Jingle: UI entry point and lots of small changes.
This commit is contained in:
		
							parent
							
								
									9b378d625a
								
							
						
					
					
						commit
						459c73f961
					
				
					 6 changed files with 171 additions and 45 deletions
				
			
		| 
						 | 
				
			
			@ -65,6 +65,15 @@
 | 
			
		|||
    </widget>
 | 
			
		||||
  </child>
 | 
			
		||||
 | 
			
		||||
  <child>
 | 
			
		||||
    <widget class="GtkMenuItem" id="start_voip_menuitem">
 | 
			
		||||
      <property name="visible">True</property>
 | 
			
		||||
      <property name="label" translatable="yes">Start _Voice chat</property>
 | 
			
		||||
      <property name="use_underline">True</property>
 | 
			
		||||
      <signal name="activate" handler="_on_start_voip_menuitem_activate" last_modification_time="Tue, 03 Jan 2006 04:26:46 GMT"/>
 | 
			
		||||
    </widget>
 | 
			
		||||
  </child>
 | 
			
		||||
 | 
			
		||||
  <child>
 | 
			
		||||
    <widget class="GtkImageMenuItem" id="add_to_roster_menuitem">
 | 
			
		||||
      <property name="visible">True</property>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1191,6 +1191,10 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
		gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
 | 
			
		||||
			widget.get_active())
 | 
			
		||||
 | 
			
		||||
	def _on_start_voip_menuitem_activate(self, *things):
 | 
			
		||||
		print 'Start VoiP'
 | 
			
		||||
		gajim.connections[self.account].startVoiP(self.contact.jid)
 | 
			
		||||
 | 
			
		||||
	def _update_gpg(self):
 | 
			
		||||
		tb = self.xml.get_widget('gpg_togglebutton')
 | 
			
		||||
		# we can do gpg
 | 
			
		||||
| 
						 | 
				
			
			@ -1533,6 +1537,7 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
		
 | 
			
		||||
		history_menuitem = xml.get_widget('history_menuitem')
 | 
			
		||||
		toggle_gpg_menuitem = xml.get_widget('toggle_gpg_menuitem')
 | 
			
		||||
		start_voip_menuitem = xml.get_widget('start_voip_menuitem')
 | 
			
		||||
		add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem')
 | 
			
		||||
		send_file_menuitem = xml.get_widget('send_file_menuitem')
 | 
			
		||||
		information_menuitem = xml.get_widget('information_menuitem')
 | 
			
		||||
| 
						 | 
				
			
			@ -1583,6 +1588,9 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
		id = toggle_gpg_menuitem.connect('activate', 
 | 
			
		||||
			self._on_toggle_gpg_menuitem_activate)
 | 
			
		||||
		self.handlers[id] = toggle_gpg_menuitem 
 | 
			
		||||
		id = start_voip_menuitem.connect('activate',
 | 
			
		||||
			self._on_start_voip_menuitem_activate)
 | 
			
		||||
		self.handlers[id] = start_voip_menuitem
 | 
			
		||||
		id = information_menuitem.connect('activate', 
 | 
			
		||||
			self._on_contact_information_menuitem_activate)
 | 
			
		||||
		self.handlers[id] = information_menuitem
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ from common import exceptions
 | 
			
		|||
from common.commands import ConnectionCommands
 | 
			
		||||
from common.pubsub import ConnectionPubSub
 | 
			
		||||
from common.caps import ConnectionCaps
 | 
			
		||||
from common.jingle import ConnectionJingle
 | 
			
		||||
 | 
			
		||||
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
 | 
			
		||||
	'invisible', 'error']
 | 
			
		||||
| 
						 | 
				
			
			@ -1174,12 +1175,13 @@ class ConnectionVcard:
 | 
			
		|||
			#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
 | 
			
		||||
			self.dispatch('VCARD', vcard)
 | 
			
		||||
 | 
			
		||||
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps):
 | 
			
		||||
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps, ConnectionJingle):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		ConnectionVcard.__init__(self)
 | 
			
		||||
		ConnectionBytestream.__init__(self)
 | 
			
		||||
		ConnectionCommands.__init__(self)
 | 
			
		||||
		ConnectionPubSub.__init__(self)
 | 
			
		||||
		ConnectionJingle.__init__(self)
 | 
			
		||||
		self.gmail_url=None
 | 
			
		||||
		# List of IDs we are waiting answers for {id: (type_of_request, data), }
 | 
			
		||||
		self.awaiting_answers = {}
 | 
			
		||||
| 
						 | 
				
			
			@ -2099,6 +2101,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
 | 
			
		|||
		con.RegisterHandler('iq', self._search_fields_received, 'result',
 | 
			
		||||
			common.xmpp.NS_SEARCH)
 | 
			
		||||
		con.RegisterHandler('iq', self._PubSubCB, 'result')
 | 
			
		||||
		con.RegisterHandler('iq', self._JingleCB, 'result')
 | 
			
		||||
		con.RegisterHandler('iq', self._JingleCB, 'error')
 | 
			
		||||
		con.RegisterHandler('iq', self._JingleCB, 'set',
 | 
			
		||||
			common.xmpp.NS_JINGLE)
 | 
			
		||||
		con.RegisterHandler('iq', self._ErrorCB, 'error')
 | 
			
		||||
		con.RegisterHandler('iq', self._IqCB)
 | 
			
		||||
		con.RegisterHandler('iq', self._StanzaArrivedCB)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,19 +12,24 @@
 | 
			
		|||
##
 | 
			
		||||
''' Handles the jingle signalling protocol. '''
 | 
			
		||||
 | 
			
		||||
import gajim
 | 
			
		||||
import xmpp
 | 
			
		||||
 | 
			
		||||
import meta
 | 
			
		||||
 | 
			
		||||
class JingleStates(object):
 | 
			
		||||
	''' States in which jingle session may exist. '''
 | 
			
		||||
	ended=0
 | 
			
		||||
	pending=1
 | 
			
		||||
	active=2
 | 
			
		||||
 | 
			
		||||
class WrongState(exception): pass
 | 
			
		||||
class NoCommonCodec(exception): pass
 | 
			
		||||
class Exception(object): pass
 | 
			
		||||
class WrongState(Exception): pass
 | 
			
		||||
class NoCommonCodec(Exception): pass
 | 
			
		||||
 | 
			
		||||
class JingleSession(object):
 | 
			
		||||
	''' This represents one jingle session. '''
 | 
			
		||||
	__metaclass__=meta.VerboseClassType
 | 
			
		||||
	def __init__(self, con, weinitiate, jid):
 | 
			
		||||
		''' con -- connection object,
 | 
			
		||||
		    weinitiate -- boolean, are we the initiator?
 | 
			
		||||
| 
						 | 
				
			
			@ -32,48 +37,59 @@ class JingleSession(object):
 | 
			
		|||
		self.contents={}	# negotiated contents
 | 
			
		||||
		self.connection=con	# connection to use
 | 
			
		||||
		# our full jid
 | 
			
		||||
		self.ourjid=gajim.get_full_jid_from_account(self.connection.name)
 | 
			
		||||
		self.jid=jid		# jid we connect to
 | 
			
		||||
		self.ourjid=gajim.get_jid_from_account(self.connection.name)+'/'+con.server_resource
 | 
			
		||||
		self.peerjid=jid	# jid we connect to
 | 
			
		||||
		# jid we use as the initiator
 | 
			
		||||
		self.initiator=weinitiate and self.ourjid or self.jid
 | 
			
		||||
		self.initiator=weinitiate and self.ourjid or self.peerjid
 | 
			
		||||
		# jid we use as the responder
 | 
			
		||||
		self.responder=weinitiate and self.jid or self.ourjid
 | 
			
		||||
		self.responder=weinitiate and self.peerjid or self.ourjid
 | 
			
		||||
		# are we an initiator?
 | 
			
		||||
		self.weinitiate=weinitiate
 | 
			
		||||
		# what state is session in? (one from JingleStates)
 | 
			
		||||
		self.state=JingleStates.ended
 | 
			
		||||
		self.sid=con.getAnID()	# sessionid
 | 
			
		||||
		self.sid=con.connection.getAnID()	# sessionid
 | 
			
		||||
 | 
			
		||||
		# callbacks to call on proper contents
 | 
			
		||||
		# use .prepend() to add new callbacks
 | 
			
		||||
		self.callbacks=dict((key, [self.__defaultCB]) for key in
 | 
			
		||||
			('content-accept', 'content-add', 'content-modify',
 | 
			
		||||
			('content-add', 'content-modify',
 | 
			
		||||
			 'content-remove', 'session-accept', 'session-info',
 | 
			
		||||
			 'session-initiate', 'session-terminate',
 | 
			
		||||
			 'transport-info'))
 | 
			
		||||
		self.callbacks['iq-result']=[]
 | 
			
		||||
		self.callbacks['iq-error']=[]
 | 
			
		||||
 | 
			
		||||
		self.callbacks['content-accept']=[self.__contentAcceptCB, self.__defaultCB]
 | 
			
		||||
 | 
			
		||||
	''' Middle-level functions to manage contents. Handle local content
 | 
			
		||||
	cache and send change notifications. '''
 | 
			
		||||
	def addContent(self, name, description, transport, profile=None):
 | 
			
		||||
	def addContent(self, name, content, initiator='we'):
 | 
			
		||||
		''' Add new content to session. If the session is active,
 | 
			
		||||
		this will send proper stanza to update session. 
 | 
			
		||||
		The protocol prohibits changing that when pending.'''
 | 
			
		||||
		The protocol prohibits changing that when pending.
 | 
			
		||||
		Initiator must be one of ('we', 'peer', 'initiator', 'responder')'''
 | 
			
		||||
		if self.state==JingleStates.pending:
 | 
			
		||||
			raise WrongState
 | 
			
		||||
 | 
			
		||||
		content={'creator': 'initiator',
 | 
			
		||||
			'name': name,
 | 
			
		||||
			'description': description,
 | 
			
		||||
			'transport': transport}
 | 
			
		||||
		if profile is not None:
 | 
			
		||||
			content['profile']=profile
 | 
			
		||||
		self.contents[('initiator', name)]=content
 | 
			
		||||
		if (initiator=='we' and self.weinitiate) or (initiator=='peer' and not self.weinitiate):
 | 
			
		||||
			initiator='initiator'
 | 
			
		||||
		elif (initiator=='peer' and self.weinitiate) or (initiator=='we' and not self.weinitiate):
 | 
			
		||||
			initiator='responder'
 | 
			
		||||
		content.creator = initiator
 | 
			
		||||
		content.name = name
 | 
			
		||||
		self.contents[(initiator,name)]=content
 | 
			
		||||
 | 
			
		||||
		if self.state==JingleStates.active:
 | 
			
		||||
			pass # TODO: send proper stanza, shouldn't be needed now
 | 
			
		||||
 | 
			
		||||
	def removeContent(self, creator, name):
 | 
			
		||||
		''' We do not need this now '''
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def modifyContent(self, creator, name, *someother):
 | 
			
		||||
		''' We do not need this now '''
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	''' Middle-level function to do stanza exchange. '''
 | 
			
		||||
	def startSession(self):
 | 
			
		||||
		''' Start session. '''
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +108,7 @@ class JingleSession(object):
 | 
			
		|||
		if error:
 | 
			
		||||
			# it's an iq-error stanza
 | 
			
		||||
			callables = 'iq-error'
 | 
			
		||||
		else if jingle:
 | 
			
		||||
		elif jingle:
 | 
			
		||||
			# it's a jingle action
 | 
			
		||||
			action = jingle.getAttr('action')
 | 
			
		||||
			callables = action
 | 
			
		||||
| 
						 | 
				
			
			@ -115,11 +131,20 @@ class JingleSession(object):
 | 
			
		|||
		self.connection.send(response)
 | 
			
		||||
		raise xmpp.NodeProcessed
 | 
			
		||||
 | 
			
		||||
	def __contentAcceptCB(self, stanza, jingle, error):
 | 
			
		||||
		''' Called when we get content-accept stanza or equivalent one
 | 
			
		||||
		(like session-accept).'''
 | 
			
		||||
		# check which contents are accepted, call their callbacks
 | 
			
		||||
		for content in jingle.iterTags('content'):
 | 
			
		||||
			creator = content['creator']
 | 
			
		||||
			name = content['name']
 | 
			
		||||
			
 | 
			
		||||
 | 
			
		||||
	''' Methods that make/send proper pieces of XML. They check if the session
 | 
			
		||||
	is in appropriate state. '''
 | 
			
		||||
	def makeJingle(self, action):
 | 
			
		||||
	def __makeJingle(self, action):
 | 
			
		||||
		stanza = xmpp.Iq(typ='set', to=xmpp.JID(self.jid))
 | 
			
		||||
		jingle = stanza.addChild('jingle', attrs=
 | 
			
		||||
		jingle = stanza.addChild('jingle', attrs={
 | 
			
		||||
			'xmlns': 'http://www.xmpp.org/extensions/xep-0166.html#ns',
 | 
			
		||||
			'action': action,
 | 
			
		||||
			'initiator': self.initiator,
 | 
			
		||||
| 
						 | 
				
			
			@ -127,21 +152,18 @@ class JingleSession(object):
 | 
			
		|||
			'sid': self.sid})
 | 
			
		||||
		return stanza, jingle
 | 
			
		||||
 | 
			
		||||
	def appendContent(self, jingle, content, full=True):
 | 
			
		||||
	def __appendContent(self, jingle, content, full=True):
 | 
			
		||||
		''' Append <content/> element to <jingle/> element,
 | 
			
		||||
		with (full=True) or without (full=False) <content/>
 | 
			
		||||
		children. '''
 | 
			
		||||
		c=jingle.addChild('content', attrs={
 | 
			
		||||
			'creator': content['creator'],
 | 
			
		||||
			'name': content['name']})
 | 
			
		||||
		if 'profile' in content:
 | 
			
		||||
			c['profile']=content['profile']
 | 
			
		||||
		if full:
 | 
			
		||||
			c.addChild(node=content['description'])
 | 
			
		||||
			c.addChild(node=content['transport'])
 | 
			
		||||
			jingle.addChild(node=content.toXML())
 | 
			
		||||
		else:
 | 
			
		||||
			jingle.addChild('content',
 | 
			
		||||
				attrs={'name': content.name, 'creator': content.creator})
 | 
			
		||||
		return c
 | 
			
		||||
 | 
			
		||||
	def appendContents(self, jingle, full=True):
 | 
			
		||||
	def __appendContents(self, jingle, full=True):
 | 
			
		||||
		''' Append all <content/> elements to <jingle/>.'''
 | 
			
		||||
		# TODO: integrate with __appendContent?
 | 
			
		||||
		# TODO: parameters 'name', 'content'?
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +172,9 @@ class JingleSession(object):
 | 
			
		|||
 | 
			
		||||
	def __sessionInitiate(self):
 | 
			
		||||
		assert self.state==JingleStates.ended
 | 
			
		||||
		stanza, jingle = self.__makeJingle('session-initiate')
 | 
			
		||||
		self.__appendContents(jingle)
 | 
			
		||||
		self.connection.send(jingle)
 | 
			
		||||
 | 
			
		||||
	def __sessionAccept(self):
 | 
			
		||||
		assert self.state==JingleStates.pending
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +222,7 @@ class JingleSession(object):
 | 
			
		|||
		self.sid = jingle['sid']
 | 
			
		||||
		for element in jingle.iterTags('content'):
 | 
			
		||||
			content={'creator': 'initiator',
 | 
			
		||||
				'name': element['name']
 | 
			
		||||
				'name': element['name'],
 | 
			
		||||
				'description': element.getTag('description'),
 | 
			
		||||
				'transport': element.getTag('transport')}
 | 
			
		||||
			if element.has_attr('profile'):
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +232,7 @@ class JingleSession(object):
 | 
			
		|||
	def sessionTerminateCB(self, stanza): pass
 | 
			
		||||
 | 
			
		||||
class JingleAudioSession(object):
 | 
			
		||||
	__metaclass__=meta.VerboseClassType
 | 
			
		||||
	class Codec(object):
 | 
			
		||||
		''' This class keeps description of a single codec. '''
 | 
			
		||||
		def __init__(self, name, id=None, **params):
 | 
			
		||||
| 
						 | 
				
			
			@ -232,15 +258,15 @@ class JingleAudioSession(object):
 | 
			
		|||
				attrs=self.attrs,
 | 
			
		||||
				payload=(xmpp.Node('parameter', {'name': k, 'value': v}) for k,v in self.params))
 | 
			
		||||
 | 
			
		||||
	def __init__(self, con, weinitiate, jid):
 | 
			
		||||
		JingleSession.__init__(self, con, weinitiate, jid)
 | 
			
		||||
		if weinitiate:
 | 
			
		||||
			pass #add voice content
 | 
			
		||||
		self.callbacks['session-initiate'].prepend(
 | 
			
		||||
	def __init__(self, content):
 | 
			
		||||
		self.content = content
 | 
			
		||||
 | 
			
		||||
		self.initiator_codecs=[]
 | 
			
		||||
		self.responder_codecs=[]
 | 
			
		||||
 | 
			
		||||
	def sessionInitiateCB(self, stanza, ourcontent):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	''' "Negotiation" of codecs... simply presenting what *we* can do, nothing more... '''
 | 
			
		||||
	def getOurCodecs(self, other=None):
 | 
			
		||||
		''' Get a list of codecs we support. Try to get them in the same
 | 
			
		||||
| 
						 | 
				
			
			@ -282,16 +308,46 @@ class JingleAudioSession(object):
 | 
			
		|||
			xmlns=xmpp.NS_JINGLE_AUDIO,
 | 
			
		||||
			payload=(codec.toXML() for codec in codecs))
 | 
			
		||||
 | 
			
		||||
	def toXML(self):
 | 
			
		||||
		if not self.initiator_codecs:
 | 
			
		||||
			# we are the initiator, so just send our codecs
 | 
			
		||||
			self.initiator_codecs = self.getOurCodecs()
 | 
			
		||||
			return self.__codecsList(self.initiator_codecs)
 | 
			
		||||
		else:
 | 
			
		||||
			# we are the responder, we SHOULD adjust our codec list
 | 
			
		||||
			self.responder_codecs = self.getOurCodecs(self.initiator_codecs)
 | 
			
		||||
			return self.__codecsList(self.responder_codecs)
 | 
			
		||||
 | 
			
		||||
class JingleICEUDPSession(object):
 | 
			
		||||
	def __init__(self, con, weinitiate, jid):
 | 
			
		||||
	__metaclass__=meta.VerboseClassType
 | 
			
		||||
	def __init__(self, content):
 | 
			
		||||
		self.content = content
 | 
			
		||||
 | 
			
		||||
	def _sessionInitiateCB(self):
 | 
			
		||||
		''' Called when we initiate the session. '''
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
class JingleVoiP(JingleSession):
 | 
			
		||||
	def toXML(self):
 | 
			
		||||
		''' ICE-UDP doesn't send much in its transport stanza... '''
 | 
			
		||||
		return xmpp.Node('transport', xmlns=xmpp.JINGLE_ICE_UDP)
 | 
			
		||||
 | 
			
		||||
class JingleVoiP(object):
 | 
			
		||||
	''' Jingle VoiP sessions consist of audio content transported
 | 
			
		||||
	over an ICE UDP protocol. '''
 | 
			
		||||
	def __init__(*data):
 | 
			
		||||
		JingleAudioSession.__init__(*data)
 | 
			
		||||
		JingleICEUDPSession.__init__(*data)
 | 
			
		||||
	__metaclass__=meta.VerboseClassType
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.audio = JingleAudioSession(self)
 | 
			
		||||
		self.transport = JingleICEUDPSession(self)
 | 
			
		||||
 | 
			
		||||
	def toXML(self):
 | 
			
		||||
		''' Return proper XML for <content/> element. '''
 | 
			
		||||
		return xmpp.Node('content',
 | 
			
		||||
			attrs={'name': self.name, 'creator': self.creator, 'profile': 'RTP/AVP'},
 | 
			
		||||
			childs=[self.audio.toXML(), self.transport.toXML()])
 | 
			
		||||
 | 
			
		||||
	def _sessionInitiateCB(self):
 | 
			
		||||
		''' Called when we initiate the session. '''
 | 
			
		||||
		self.transport._sessionInitiateCB()
 | 
			
		||||
 | 
			
		||||
class ConnectionJingle(object):
 | 
			
		||||
	''' This object depends on that it is a part of Connection class. '''
 | 
			
		||||
| 
						 | 
				
			
			@ -307,13 +363,13 @@ class ConnectionJingle(object):
 | 
			
		|||
		''' Add a jingle session to a jingle stanza dispatcher
 | 
			
		||||
		jingle - a JingleSession object.
 | 
			
		||||
		'''
 | 
			
		||||
		self.__sessions[(jingle.jid, jingle.sid)]=jingle
 | 
			
		||||
		self.__sessions[(jingle.peerjid, jingle.sid)]=jingle
 | 
			
		||||
 | 
			
		||||
	def deleteJingle(self, jingle):
 | 
			
		||||
		''' Remove a jingle session from a jingle stanza dispatcher '''
 | 
			
		||||
		del self.__session[(jingle.jid, jingle.sid)]
 | 
			
		||||
		del self.__session[(jingle.peerjid, jingle.sid)]
 | 
			
		||||
 | 
			
		||||
	def _jingleCB(self, con, stanza):
 | 
			
		||||
	def _JingleCB(self, con, stanza):
 | 
			
		||||
		''' The jingle stanza dispatcher.
 | 
			
		||||
		Route jingle stanza to proper JingleSession object,
 | 
			
		||||
		or create one if it is a new session.
 | 
			
		||||
| 
						 | 
				
			
			@ -330,6 +386,7 @@ class ConnectionJingle(object):
 | 
			
		|||
			raise xmpp.NodeProcessed
 | 
			
		||||
 | 
			
		||||
		jingle = stanza.getTag('jingle')
 | 
			
		||||
		if not jingle: return
 | 
			
		||||
		sid = jingle.getAttr('sid')
 | 
			
		||||
 | 
			
		||||
		# do we need to create a new jingle object
 | 
			
		||||
| 
						 | 
				
			
			@ -341,5 +398,11 @@ class ConnectionJingle(object):
 | 
			
		|||
		# we already have such session in dispatcher...
 | 
			
		||||
		return self.__sessions[(jid, sid)].stanzaCB(stanza)
 | 
			
		||||
 | 
			
		||||
	def addJingleIqCallback(jid, id, jingle):
 | 
			
		||||
	def addJingleIqCallback(self, jid, id, jingle):
 | 
			
		||||
		self.__iq_responses[(jid, id)]=jingle
 | 
			
		||||
 | 
			
		||||
	def startVoiP(self, jid):
 | 
			
		||||
		jingle = JingleSession(self, weinitiate=True, jid=jid)
 | 
			
		||||
		self.addJingle(jingle)
 | 
			
		||||
		jingle.addContent('voice', JingleVoiP())
 | 
			
		||||
		jingle.startSession()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										36
									
								
								src/common/meta.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/common/meta.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
#!/usr/bin/python
 | 
			
		||||
 | 
			
		||||
import types
 | 
			
		||||
 | 
			
		||||
class VerboseClassType(type):
 | 
			
		||||
	indent = ''
 | 
			
		||||
 | 
			
		||||
	def __init__(cls, name, bases, dict):
 | 
			
		||||
		super(VerboseClassType, cls).__init__(cls, name, bases, dict)
 | 
			
		||||
		new = {}
 | 
			
		||||
		print 'Initializing new class %s:' % cls
 | 
			
		||||
		for fname, fun in dict.iteritems():
 | 
			
		||||
			wrap = hasattr(fun, '__call__')
 | 
			
		||||
			print '%s%s is %s, we %s wrap it.' % \
 | 
			
		||||
				(cls.__class__.indent, fname, fun, wrap and 'will' or "won't")
 | 
			
		||||
			if not wrap: continue
 | 
			
		||||
			setattr(cls, fname, cls.wrap(name, fname, fun))
 | 
			
		||||
 | 
			
		||||
	def wrap(cls, name, fname, fun):
 | 
			
		||||
		def verbose(*a, **b):
 | 
			
		||||
			args = ', '.join(map(repr, a)+map(lambda x:'%s=%r'%x, b.iteritems()))
 | 
			
		||||
			print '%s%s.%s(%s):' % (cls.__class__.indent, name, fname, args)
 | 
			
		||||
			cls.__class__.indent += '|   '
 | 
			
		||||
			r = fun(*a, **b)
 | 
			
		||||
			cls.__class__.indent = cls.__class__.indent[:-4]
 | 
			
		||||
			print '%s+=%r' % (cls.__class__.indent, r)
 | 
			
		||||
			return r
 | 
			
		||||
		verbose.__name__ = fname
 | 
			
		||||
		return verbose
 | 
			
		||||
 | 
			
		||||
def nested_property(f):
 | 
			
		||||
	ret = f()
 | 
			
		||||
	p = {}
 | 
			
		||||
	for v in ('fget', 'fset', 'fdel', 'doc'):
 | 
			
		||||
		if v in ret: p[v]=ret[v]
 | 
			
		||||
	return property(**p)
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +55,10 @@ NS_HTTP_BIND    ='http://jabber.org/protocol/httpbind'                  # XEP-01
 | 
			
		|||
NS_IBB          ='http://jabber.org/protocol/ibb'
 | 
			
		||||
NS_INVISIBLE    ='presence-invisible'                                   # Jabberd2
 | 
			
		||||
NS_IQ           ='iq'                                                   # Jabberd2
 | 
			
		||||
NS_JINGLE	='http://www.xmpp.org/extensions/xep-0166.html#ns'	# XEP-0166
 | 
			
		||||
NS_JINGLE_AUDIO	='http://www.xmpp.org/extensions/xep-0167.html#ns'	# XEP-0167
 | 
			
		||||
NS_JINGLE_RAW_UDP='http://www.xmpp.org/extensions/xep-0177.html#ns'	# XEP-0177
 | 
			
		||||
NS_JINGLE_ICE_UDP='http://www.xmpp.org/extensions/xep-0176.html#ns-udp'	# XEP-0176
 | 
			
		||||
NS_LAST         ='jabber:iq:last'
 | 
			
		||||
NS_MESSAGE      ='message'                                              # Jabberd2
 | 
			
		||||
NS_MOOD         ='http://jabber.org/protocol/mood'                      # XEP-0107
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue