SDP_SERVER_SVCLASS_ID		= 0x1000
BROWSE_GRP_DESC_SVCLASS_ID	= 0x1001
PUBLIC_BROWSE_GROUP		= 0x1002
SERIAL_PORT_SVCLASS_ID		= 0x1101
LAN_ACCESS_SVCLASS_ID		= 0x1102
DIALUP_NET_SVCLASS_ID		= 0x1103
IRMC_SYNC_SVCLASS_ID		= 0x1104
OBEX_OBJPUSH_SVCLASS_ID		= 0x1105
OBEX_FILETRANS_SVCLASS_ID	= 0x1106
IRMC_SYNC_CMD_SVCLASS_ID	= 0x1107
HEADSET_SVCLASS_ID		= 0x1108
CORDLESS_TELEPHONY_SVCLASS_ID	= 0x1109
AUDIO_SOURCE_SVCLASS_ID		= 0x110a
AUDIO_SINK_SVCLASS_ID		= 0x110b
AV_REMOTE_TARGET_SVCLASS_ID	= 0x110c
ADVANCED_AUDIO_SVCLASS_ID	= 0x110d
AV_REMOTE_SVCLASS_ID		= 0x110e
VIDEO_CONF_SVCLASS_ID		= 0x110f
INTERCOM_SVCLASS_ID		= 0x1110
FAX_SVCLASS_ID			= 0x1111
HEADSET_AGW_SVCLASS_ID		= 0x1112
WAP_SVCLASS_ID			= 0x1113
WAP_CLIENT_SVCLASS_ID		= 0x1114
PANU_SVCLASS_ID			= 0x1115
NAP_SVCLASS_ID			= 0x1116
GN_SVCLASS_ID			= 0x1117
DIRECT_PRINTING_SVCLASS_ID	= 0x1118
REFERENCE_PRINTING_SVCLASS_ID	= 0x1119
IMAGING_SVCLASS_ID		= 0x111a
IMAGING_RESPONDER_SVCLASS_ID	= 0x111b
IMAGING_ARCHIVE_SVCLASS_ID	= 0x111c
IMAGING_REFOBJS_SVCLASS_ID	= 0x111d
HANDSFREE_SVCLASS_ID		= 0x111e
HANDSFREE_AGW_SVCLASS_ID	= 0x111f
DIRECT_PRT_REFOBJS_SVCLASS_ID	= 0x1120
REFLECTED_UI_SVCLASS_ID		= 0x1121
BASIC_PRINTING_SVCLASS_ID	= 0x1122
PRINTING_STATUS_SVCLASS_ID	= 0x1123
HID_SVCLASS_ID			= 0x1124
HCR_SVCLASS_ID			= 0x1125
HCR_PRINT_SVCLASS_ID		= 0x1126
HCR_SCAN_SVCLASS_ID		= 0x1127
CIP_SVCLASS_ID			= 0x1128
VIDEO_CONF_GW_SVCLASS_ID	= 0x1129
UDI_MT_SVCLASS_ID		= 0x112a
UDI_TA_SVCLASS_ID		= 0x112b
AV_SVCLASS_ID			= 0x112c
SAP_SVCLASS_ID			= 0x112d
PBAP_PCE_SVCLASS_ID		= 0x112e
PBAP_PSE_SVCLASS_ID		= 0x112f
PBAP_SVCLASS_ID			= 0x1130
PNP_INFO_SVCLASS_ID		= 0x1200
GENERIC_NETWORKING_SVCLASS_ID	= 0x1201
GENERIC_FILETRANS_SVCLASS_ID	= 0x1202
GENERIC_AUDIO_SVCLASS_ID	= 0x1203
GENERIC_TELEPHONY_SVCLASS_ID	= 0x1204
UPNP_SVCLASS_ID			= 0x1205
UPNP_IP_SVCLASS_ID		= 0x1206
UPNP_PAN_SVCLASS_ID		= 0x1300
UPNP_LAP_SVCLASS_ID		= 0x1301
UPNP_L2CAP_SVCLASS_ID		= 0x1302
VIDEO_SOURCE_SVCLASS_ID		= 0x1303
VIDEO_SINK_SVCLASS_ID		= 0x1304
VIDEO_DISTRIBUTION_SVCLASS_ID	= 0x1305
MDP_SVCLASS_ID			= 0x1400
MDP_SOURCE_SVCLASS_ID		= 0x1401
MDP_SINK_SVCLASS_ID		= 0x1402
APPLE_AGENT_SVCLASS_ID		= 0x2112

uuid_names = {}
uuid_names[0x0001] = "SDP"
uuid_names[0x0002] = "UDP"
uuid_names[0x0003] = "RFCOMM"
uuid_names[0x0004] = "TCP"
uuid_names[0x0005] = "TCS-BIN"
uuid_names[0x0006] = "TCS-AT"
uuid_names[0x0008] = "OBEX"
uuid_names[0x0009] = "IP"
uuid_names[0x000a] = "FTP"
uuid_names[0x000c] = "HTTP"
uuid_names[0x000e] = "WSP"
uuid_names[0x000f] = "BNEP"
uuid_names[0x0010] = "UPnP/ESDP"
uuid_names[0x0011] = "HIDP"
uuid_names[0x0012] = "Hardcopy Control Channel"
uuid_names[0x0014] = "Hardcopy Data Channel"
uuid_names[0x0016] = "Hardcopy Notification"
uuid_names[0x0017] = "AVCTP"
uuid_names[0x0019] = "AVDTP"
uuid_names[0x001b] = "CMTP"
uuid_names[0x001d] = "UDI_C-Plane"
uuid_names[0x0100] = "L2CAP"
uuid_names[0x1000] = "ServiceDiscoveryServerServiceClassID",
uuid_names[0x1001] = "BrowseGroupDescriptorServiceClassID"
uuid_names[0x1002] = "Public Browse Group"
uuid_names[0x1101] = "Serial Port"
uuid_names[0x1102] = "LAN Access Using PPP"
uuid_names[0x1103] = _("Dialup Networking (DUN)")
uuid_names[0x1104] = "IrMC Sync"
uuid_names[0x1105] = "OBEX Object Push"
uuid_names[0x1106] = "OBEX File Transfer"
uuid_names[0x1107] = "IrMC Sync Command"
uuid_names[0x1108] = "Headset"
uuid_names[0x1109] = "Cordless Telephony"
uuid_names[0x110a] = _("Audio Source")
uuid_names[0x110b] = _("Audio Sink")
uuid_names[0x110c] = "Remote Control Target"
uuid_names[0x110d] = "Advanced Audio"
uuid_names[0x110e] = "Remote Control"
uuid_names[0x110f] = "Video Conferencing"
uuid_names[0x1110] = "Intercom"
uuid_names[0x1111] = "Fax"
uuid_names[0x1112] = "Headset Audio Gateway"
uuid_names[0x1113] = "WAP"
uuid_names[0x1114] = "WAP Client"
uuid_names[0x1115] = "PANU"
uuid_names[0x1116] = _("Network Access Point")
uuid_names[0x1117] = _("Group Network")
uuid_names[0x1118] = "DirectPrinting (BPP)"
uuid_names[0x1119] = "ReferencePrinting (BPP)"
uuid_names[0x111a] = "Imaging (BIP)"
uuid_names[0x111b] = "ImagingResponder (BIP)"
uuid_names[0x111c] = "ImagingAutomaticArchive (BIP)"
uuid_names[0x111d] = "ImagingReferencedObjects (BIP)"
uuid_names[0x111e] = "Handsfree"
uuid_names[0x111f] = "Handsfree Audio Gateway"
uuid_names[0x1120] = "DirectPrintingReferenceObjectsService (BPP)"
uuid_names[0x1121] = "ReflectedUI (BPP)"
uuid_names[0x1122] = "Basic Printing (BPP)"
uuid_names[0x1123] = "Printing Status (BPP)"
uuid_names[0x1124] = "Human Interface Device Service (HID)"
uuid_names[0x1125] = "HardcopyCableReplacement (HCR)"
uuid_names[0x1126] = "HCR_Print (HCR)"
uuid_names[0x1127] = "HCR_Scan (HCR)"
uuid_names[0x1128] = "Common ISDN Access (CIP)"
uuid_names[0x1129] = "VideoConferencingGW (VCP)"
uuid_names[0x112a] = "UDI-MT"
uuid_names[0x112b] = "UDI-TA"
uuid_names[0x112c] = "Audio/Video"
uuid_names[0x112d] = "SIM Access (SAP)"
uuid_names[0x112e] = "Phonebook Access (PBAP) - PCE"
uuid_names[0x112f] = "Phonebook Access (PBAP) - PSE"
uuid_names[0x1130] = "Phonebook Access (PBAP)"
uuid_names[0x1200] = "PnP Information"
uuid_names[0x1201] = "Generic Networking"
uuid_names[0x1202] = "Generic FileTransfer"
uuid_names[0x1203] = "Generic Audio"
uuid_names[0x1204] = "Generi cTelephony"
uuid_names[0x1303] = "Video Source"
uuid_names[0x1304] = "Video Sink"
uuid_names[0x1305] = "Video Distribution"
uuid_names[0x1400] = "MDP"
uuid_names[0x1401] = "MDPSource"
uuid_names[0x1402] = "MDPSink"
uuid_names[0x2112] = "AppleAgent"

import xml.dom.minidom

SDP_ATTR_RECORD_HANDLE			= 0x0000
SDP_ATTR_SVCLASS_ID_LIST		= 0x0001
SDP_ATTR_RECORD_STATE			= 0x0002
SDP_ATTR_SERVICE_ID			= 0x0003
SDP_ATTR_PROTO_DESC_LIST		= 0x0004
SDP_ATTR_BROWSE_GRP_LIST		= 0x0005
SDP_ATTR_LANG_BASE_ATTR_ID_LIST		= 0x0006
SDP_ATTR_SVCINFO_TTL			= 0x0007
SDP_ATTR_SERVICE_AVAILABILITY		= 0x0008
SDP_ATTR_PFILE_DESC_LIST		= 0x0009
SDP_ATTR_DOC_URL			= 0x000a
SDP_ATTR_CLNT_EXEC_URL			= 0x000b
SDP_ATTR_ICON_URL			= 0x000c
SDP_ATTR_ADD_PROTO_DESC_LIST		= 0x000d

SDP_PRIMARY_LANG_BASE 			= 0x0100

SDP_UUID	= 0x0001
UDP_UUID	= 0x0002
RFCOMM_UUID	= 0x0003
TCP_UUID	= 0x0004
TCS_BIN_UUID	= 0x0005
TCS_AT_UUID	= 0x0006
OBEX_UUID	= 0x0008
IP_UUID		= 0x0009
FTP_UUID	= 0x000a
HTTP_UUID	= 0x000c
WSP_UUID	= 0x000e
BNEP_UUID	= 0x000f
UPNP_UUID	= 0x0010
HIDP_UUID	= 0x0011
HCRP_CTRL_UUID	= 0x0012
HCRP_DATA_UUID	= 0x0014
HCRP_NOTE_UUID	= 0x0016
AVCTP_UUID	= 0x0017
AVDTP_UUID	= 0x0019
CMTP_UUID	= 0x001b
UDI_UUID	= 0x001d
MCAP_CTRL_UUID	= 0x001e
MCAP_DATA_UUID	= 0x001f
L2CAP_UUID	= 0x0100

def parse_sdp_xml(services):
	svc_list = []	
	
	
	def get_value(typename, val):
		if "int" in typename:
			return (typename, int(val, 16))
		else:
			return (typename, val)
	
	def HandleRecord(record):
		svc_list.append(HandleAttribs(record.getElementsByTagName("attribute")))

		
	def HandleSequence(sequence):
		ls = []
		for i in sequence.childNodes:
			if i.nodeName == "sequence":
				r = HandleSequence(i)
				ls.append(r)
			else:
				if i.nodeType != i.TEXT_NODE:
					ls.append(get_value(i.nodeName, i.getAttribute("value")))
					
		return ls
		
		
	def HandleAttribs(attribs):
		attr_list = {}
		for attrib in attribs:
			id = attrib.getAttribute("id")
			id = int(id, 16)
			
			for i in attrib.childNodes:
				if i.nodeName == "sequence":
					attr_list[id] = HandleSequence(i)

				elif i.nodeType != i.TEXT_NODE:
					attr_list[id] = get_value(i.nodeName, i.getAttribute("value"))
					
		return attr_list
		
	for k, v in services.iteritems():
		try:
			dom = xml.dom.minidom.parseString(v)
			HandleRecord(dom.getElementsByTagName("record")[0])
		except Exception, e:
			dprint("Failed to parse xml sdp entry", e)
			dprint(v)
	
	return svc_list

def uuid16_to_name(uuid16):
	try:
		return uuid_names[uuid16]
	except:
		return _("Unknown")

def uuid128_to_uuid16(uuid128):
	try:
		return int('0x'+uuid128[4:8], 16)
	except:
		return 0
		
def bluez_to_friendly_name(svc):
	if svc == "audiosink":
		return uuid_names[0x110b]
	elif svc == "audiosource":
		return uuid_names[0x110a]
	else:
		raise Exception
		
from blueman.main.Config import Config
import pickle
import base64
import zlib

sdp_cache = {}
sdp_conf = Config("sdp")

def on_sdp_changed(c, key, value):
	if value and key in sdp_cache:
		s = pickle.loads(zlib.decompress(base64.b64decode(value)))
		sdp_cache[key] = s
	
sdp_conf.connect("property-changed", on_sdp_changed)

def sdp_get_cached(address):
	if not address in sdp_cache:
		
		d = sdp_conf.get(address)
		if d:
			try:
				s = pickle.loads(zlib.decompress(base64.b64decode(d)))
			except Exception, e:
				dprint(e)
				raise KeyError
				
			sdp_cache[address] = s
			return s
		else:
			raise KeyError("No sdp info for %s found" % address)
	else:
		return sdp_cache[address]
		
def sdp_get_cached_rfcomm(address):
	local_sdp = sdp_get_cached(address)
	ls = []
	for svc in local_sdp:
		channel = 0
		name = None
		uuids = None
	
		for k, v in svc.iteritems():
			if k == SDP_ATTR_PROTO_DESC_LIST:
				#print v
				for i in v:
					try:
						if i[0][0] == "uuid" and int(i[0][1], 16) == RFCOMM_UUID:
							#print "Channel", i[1][1]	
							channel = i[1][1]
					except:
						pass
					
			elif k == SDP_PRIMARY_LANG_BASE:
				name = v[1]
				if name:
					name = name.strip("\n\r ")
			
			elif k == SDP_ATTR_SVCLASS_ID_LIST:
				def m(x):
					try:
						return int(x[1], 16)
					except:
						pass
			
				uuids = map(m, v)
		ls.append((name, channel, uuids))	

	return ls

def sdp_get_serial_type(address, pattern):
	pattern = str(pattern)
	if "-" in pattern:
		return (uuid128_to_uuid16(pattern),)
	else:
		s = sdp_get_cached_rfcomm(address)
		for name, channel, uuids in s:
			if str(channel) == pattern:
				return tuple(uuids)
				
def sdp_get_serial_name(address, pattern):
	pattern = str(pattern)
	if "-" in pattern:
		return uuid16_to_name(uuid128_to_uuid16(pattern))
	else:
		try:
			s = sdp_get_cached_rfcomm(address)
		except:
			return _("Unknown")
			
		for name, channel, uuids in s:
			if str(channel) == pattern:
				if name == None:
					return _("Unknown")
				else:
					return name.strip("\n\r ")
					
def sdp_save(address, records):
	data = base64.b64encode(zlib.compress(pickle.dumps(records, pickle.HIGHEST_PROTOCOL)))
	sdp_conf.set(address, data)

