Jingle: UI entry point and lots of small changes.
This commit is contained in:
parent
9b378d625a
commit
459c73f961
|
@ -65,6 +65,15 @@
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</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>
|
<child>
|
||||||
<widget class="GtkImageMenuItem" id="add_to_roster_menuitem">
|
<widget class="GtkImageMenuItem" id="add_to_roster_menuitem">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
|
@ -1191,6 +1191,10 @@ class ChatControl(ChatControlBase):
|
||||||
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
|
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
|
||||||
widget.get_active())
|
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):
|
def _update_gpg(self):
|
||||||
tb = self.xml.get_widget('gpg_togglebutton')
|
tb = self.xml.get_widget('gpg_togglebutton')
|
||||||
# we can do gpg
|
# we can do gpg
|
||||||
|
@ -1533,6 +1537,7 @@ class ChatControl(ChatControlBase):
|
||||||
|
|
||||||
history_menuitem = xml.get_widget('history_menuitem')
|
history_menuitem = xml.get_widget('history_menuitem')
|
||||||
toggle_gpg_menuitem = xml.get_widget('toggle_gpg_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')
|
add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem')
|
||||||
send_file_menuitem = xml.get_widget('send_file_menuitem')
|
send_file_menuitem = xml.get_widget('send_file_menuitem')
|
||||||
information_menuitem = xml.get_widget('information_menuitem')
|
information_menuitem = xml.get_widget('information_menuitem')
|
||||||
|
@ -1583,6 +1588,9 @@ class ChatControl(ChatControlBase):
|
||||||
id = toggle_gpg_menuitem.connect('activate',
|
id = toggle_gpg_menuitem.connect('activate',
|
||||||
self._on_toggle_gpg_menuitem_activate)
|
self._on_toggle_gpg_menuitem_activate)
|
||||||
self.handlers[id] = toggle_gpg_menuitem
|
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',
|
id = information_menuitem.connect('activate',
|
||||||
self._on_contact_information_menuitem_activate)
|
self._on_contact_information_menuitem_activate)
|
||||||
self.handlers[id] = information_menuitem
|
self.handlers[id] = information_menuitem
|
||||||
|
|
|
@ -38,6 +38,7 @@ from common import exceptions
|
||||||
from common.commands import ConnectionCommands
|
from common.commands import ConnectionCommands
|
||||||
from common.pubsub import ConnectionPubSub
|
from common.pubsub import ConnectionPubSub
|
||||||
from common.caps import ConnectionCaps
|
from common.caps import ConnectionCaps
|
||||||
|
from common.jingle import ConnectionJingle
|
||||||
|
|
||||||
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
||||||
'invisible', 'error']
|
'invisible', 'error']
|
||||||
|
@ -1174,12 +1175,13 @@ class ConnectionVcard:
|
||||||
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
|
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
|
||||||
self.dispatch('VCARD', vcard)
|
self.dispatch('VCARD', vcard)
|
||||||
|
|
||||||
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps):
|
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps, ConnectionJingle):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
ConnectionVcard.__init__(self)
|
ConnectionVcard.__init__(self)
|
||||||
ConnectionBytestream.__init__(self)
|
ConnectionBytestream.__init__(self)
|
||||||
ConnectionCommands.__init__(self)
|
ConnectionCommands.__init__(self)
|
||||||
ConnectionPubSub.__init__(self)
|
ConnectionPubSub.__init__(self)
|
||||||
|
ConnectionJingle.__init__(self)
|
||||||
self.gmail_url=None
|
self.gmail_url=None
|
||||||
# List of IDs we are waiting answers for {id: (type_of_request, data), }
|
# List of IDs we are waiting answers for {id: (type_of_request, data), }
|
||||||
self.awaiting_answers = {}
|
self.awaiting_answers = {}
|
||||||
|
@ -2099,6 +2101,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
con.RegisterHandler('iq', self._search_fields_received, 'result',
|
con.RegisterHandler('iq', self._search_fields_received, 'result',
|
||||||
common.xmpp.NS_SEARCH)
|
common.xmpp.NS_SEARCH)
|
||||||
con.RegisterHandler('iq', self._PubSubCB, 'result')
|
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._ErrorCB, 'error')
|
||||||
con.RegisterHandler('iq', self._IqCB)
|
con.RegisterHandler('iq', self._IqCB)
|
||||||
con.RegisterHandler('iq', self._StanzaArrivedCB)
|
con.RegisterHandler('iq', self._StanzaArrivedCB)
|
||||||
|
|
|
@ -12,19 +12,24 @@
|
||||||
##
|
##
|
||||||
''' Handles the jingle signalling protocol. '''
|
''' Handles the jingle signalling protocol. '''
|
||||||
|
|
||||||
|
import gajim
|
||||||
import xmpp
|
import xmpp
|
||||||
|
|
||||||
|
import meta
|
||||||
|
|
||||||
class JingleStates(object):
|
class JingleStates(object):
|
||||||
''' States in which jingle session may exist. '''
|
''' States in which jingle session may exist. '''
|
||||||
ended=0
|
ended=0
|
||||||
pending=1
|
pending=1
|
||||||
active=2
|
active=2
|
||||||
|
|
||||||
class WrongState(exception): pass
|
class Exception(object): pass
|
||||||
class NoCommonCodec(exception): pass
|
class WrongState(Exception): pass
|
||||||
|
class NoCommonCodec(Exception): pass
|
||||||
|
|
||||||
class JingleSession(object):
|
class JingleSession(object):
|
||||||
''' This represents one jingle session. '''
|
''' This represents one jingle session. '''
|
||||||
|
__metaclass__=meta.VerboseClassType
|
||||||
def __init__(self, con, weinitiate, jid):
|
def __init__(self, con, weinitiate, jid):
|
||||||
''' con -- connection object,
|
''' con -- connection object,
|
||||||
weinitiate -- boolean, are we the initiator?
|
weinitiate -- boolean, are we the initiator?
|
||||||
|
@ -32,48 +37,59 @@ class JingleSession(object):
|
||||||
self.contents={} # negotiated contents
|
self.contents={} # negotiated contents
|
||||||
self.connection=con # connection to use
|
self.connection=con # connection to use
|
||||||
# our full jid
|
# our full jid
|
||||||
self.ourjid=gajim.get_full_jid_from_account(self.connection.name)
|
self.ourjid=gajim.get_jid_from_account(self.connection.name)+'/'+con.server_resource
|
||||||
self.jid=jid # jid we connect to
|
self.peerjid=jid # jid we connect to
|
||||||
# jid we use as the initiator
|
# 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
|
# 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?
|
# are we an initiator?
|
||||||
self.weinitiate=weinitiate
|
self.weinitiate=weinitiate
|
||||||
# what state is session in? (one from JingleStates)
|
# what state is session in? (one from JingleStates)
|
||||||
self.state=JingleStates.ended
|
self.state=JingleStates.ended
|
||||||
self.sid=con.getAnID() # sessionid
|
self.sid=con.connection.getAnID() # sessionid
|
||||||
|
|
||||||
# callbacks to call on proper contents
|
# callbacks to call on proper contents
|
||||||
# use .prepend() to add new callbacks
|
# use .prepend() to add new callbacks
|
||||||
self.callbacks=dict((key, [self.__defaultCB]) for key in
|
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',
|
'content-remove', 'session-accept', 'session-info',
|
||||||
'session-initiate', 'session-terminate',
|
'session-initiate', 'session-terminate',
|
||||||
'transport-info'))
|
'transport-info'))
|
||||||
self.callbacks['iq-result']=[]
|
self.callbacks['iq-result']=[]
|
||||||
self.callbacks['iq-error']=[]
|
self.callbacks['iq-error']=[]
|
||||||
|
|
||||||
|
self.callbacks['content-accept']=[self.__contentAcceptCB, self.__defaultCB]
|
||||||
|
|
||||||
''' Middle-level functions to manage contents. Handle local content
|
''' Middle-level functions to manage contents. Handle local content
|
||||||
cache and send change notifications. '''
|
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,
|
''' Add new content to session. If the session is active,
|
||||||
this will send proper stanza to update session.
|
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:
|
if self.state==JingleStates.pending:
|
||||||
raise WrongState
|
raise WrongState
|
||||||
|
|
||||||
content={'creator': 'initiator',
|
if (initiator=='we' and self.weinitiate) or (initiator=='peer' and not self.weinitiate):
|
||||||
'name': name,
|
initiator='initiator'
|
||||||
'description': description,
|
elif (initiator=='peer' and self.weinitiate) or (initiator=='we' and not self.weinitiate):
|
||||||
'transport': transport}
|
initiator='responder'
|
||||||
if profile is not None:
|
content.creator = initiator
|
||||||
content['profile']=profile
|
content.name = name
|
||||||
self.contents[('initiator', name)]=content
|
self.contents[(initiator,name)]=content
|
||||||
|
|
||||||
if self.state==JingleStates.active:
|
if self.state==JingleStates.active:
|
||||||
pass # TODO: send proper stanza, shouldn't be needed now
|
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. '''
|
''' Middle-level function to do stanza exchange. '''
|
||||||
def startSession(self):
|
def startSession(self):
|
||||||
''' Start session. '''
|
''' Start session. '''
|
||||||
|
@ -92,7 +108,7 @@ class JingleSession(object):
|
||||||
if error:
|
if error:
|
||||||
# it's an iq-error stanza
|
# it's an iq-error stanza
|
||||||
callables = 'iq-error'
|
callables = 'iq-error'
|
||||||
else if jingle:
|
elif jingle:
|
||||||
# it's a jingle action
|
# it's a jingle action
|
||||||
action = jingle.getAttr('action')
|
action = jingle.getAttr('action')
|
||||||
callables = action
|
callables = action
|
||||||
|
@ -115,11 +131,20 @@ class JingleSession(object):
|
||||||
self.connection.send(response)
|
self.connection.send(response)
|
||||||
raise xmpp.NodeProcessed
|
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
|
''' Methods that make/send proper pieces of XML. They check if the session
|
||||||
is in appropriate state. '''
|
is in appropriate state. '''
|
||||||
def makeJingle(self, action):
|
def __makeJingle(self, action):
|
||||||
stanza = xmpp.Iq(typ='set', to=xmpp.JID(self.jid))
|
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',
|
'xmlns': 'http://www.xmpp.org/extensions/xep-0166.html#ns',
|
||||||
'action': action,
|
'action': action,
|
||||||
'initiator': self.initiator,
|
'initiator': self.initiator,
|
||||||
|
@ -127,21 +152,18 @@ class JingleSession(object):
|
||||||
'sid': self.sid})
|
'sid': self.sid})
|
||||||
return stanza, jingle
|
return stanza, jingle
|
||||||
|
|
||||||
def appendContent(self, jingle, content, full=True):
|
def __appendContent(self, jingle, content, full=True):
|
||||||
''' Append <content/> element to <jingle/> element,
|
''' Append <content/> element to <jingle/> element,
|
||||||
with (full=True) or without (full=False) <content/>
|
with (full=True) or without (full=False) <content/>
|
||||||
children. '''
|
children. '''
|
||||||
c=jingle.addChild('content', attrs={
|
|
||||||
'creator': content['creator'],
|
|
||||||
'name': content['name']})
|
|
||||||
if 'profile' in content:
|
|
||||||
c['profile']=content['profile']
|
|
||||||
if full:
|
if full:
|
||||||
c.addChild(node=content['description'])
|
jingle.addChild(node=content.toXML())
|
||||||
c.addChild(node=content['transport'])
|
else:
|
||||||
|
jingle.addChild('content',
|
||||||
|
attrs={'name': content.name, 'creator': content.creator})
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def appendContents(self, jingle, full=True):
|
def __appendContents(self, jingle, full=True):
|
||||||
''' Append all <content/> elements to <jingle/>.'''
|
''' Append all <content/> elements to <jingle/>.'''
|
||||||
# TODO: integrate with __appendContent?
|
# TODO: integrate with __appendContent?
|
||||||
# TODO: parameters 'name', 'content'?
|
# TODO: parameters 'name', 'content'?
|
||||||
|
@ -150,6 +172,9 @@ class JingleSession(object):
|
||||||
|
|
||||||
def __sessionInitiate(self):
|
def __sessionInitiate(self):
|
||||||
assert self.state==JingleStates.ended
|
assert self.state==JingleStates.ended
|
||||||
|
stanza, jingle = self.__makeJingle('session-initiate')
|
||||||
|
self.__appendContents(jingle)
|
||||||
|
self.connection.send(jingle)
|
||||||
|
|
||||||
def __sessionAccept(self):
|
def __sessionAccept(self):
|
||||||
assert self.state==JingleStates.pending
|
assert self.state==JingleStates.pending
|
||||||
|
@ -197,7 +222,7 @@ class JingleSession(object):
|
||||||
self.sid = jingle['sid']
|
self.sid = jingle['sid']
|
||||||
for element in jingle.iterTags('content'):
|
for element in jingle.iterTags('content'):
|
||||||
content={'creator': 'initiator',
|
content={'creator': 'initiator',
|
||||||
'name': element['name']
|
'name': element['name'],
|
||||||
'description': element.getTag('description'),
|
'description': element.getTag('description'),
|
||||||
'transport': element.getTag('transport')}
|
'transport': element.getTag('transport')}
|
||||||
if element.has_attr('profile'):
|
if element.has_attr('profile'):
|
||||||
|
@ -207,6 +232,7 @@ class JingleSession(object):
|
||||||
def sessionTerminateCB(self, stanza): pass
|
def sessionTerminateCB(self, stanza): pass
|
||||||
|
|
||||||
class JingleAudioSession(object):
|
class JingleAudioSession(object):
|
||||||
|
__metaclass__=meta.VerboseClassType
|
||||||
class Codec(object):
|
class Codec(object):
|
||||||
''' This class keeps description of a single codec. '''
|
''' This class keeps description of a single codec. '''
|
||||||
def __init__(self, name, id=None, **params):
|
def __init__(self, name, id=None, **params):
|
||||||
|
@ -232,15 +258,15 @@ class JingleAudioSession(object):
|
||||||
attrs=self.attrs,
|
attrs=self.attrs,
|
||||||
payload=(xmpp.Node('parameter', {'name': k, 'value': v}) for k,v in self.params))
|
payload=(xmpp.Node('parameter', {'name': k, 'value': v}) for k,v in self.params))
|
||||||
|
|
||||||
def __init__(self, con, weinitiate, jid):
|
def __init__(self, content):
|
||||||
JingleSession.__init__(self, con, weinitiate, jid)
|
self.content = content
|
||||||
if weinitiate:
|
|
||||||
pass #add voice content
|
|
||||||
self.callbacks['session-initiate'].prepend(
|
|
||||||
|
|
||||||
self.initiator_codecs=[]
|
self.initiator_codecs=[]
|
||||||
self.responder_codecs=[]
|
self.responder_codecs=[]
|
||||||
|
|
||||||
|
def sessionInitiateCB(self, stanza, ourcontent):
|
||||||
|
pass
|
||||||
|
|
||||||
''' "Negotiation" of codecs... simply presenting what *we* can do, nothing more... '''
|
''' "Negotiation" of codecs... simply presenting what *we* can do, nothing more... '''
|
||||||
def getOurCodecs(self, other=None):
|
def getOurCodecs(self, other=None):
|
||||||
''' Get a list of codecs we support. Try to get them in the same
|
''' 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,
|
xmlns=xmpp.NS_JINGLE_AUDIO,
|
||||||
payload=(codec.toXML() for codec in codecs))
|
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):
|
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
|
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
|
''' Jingle VoiP sessions consist of audio content transported
|
||||||
over an ICE UDP protocol. '''
|
over an ICE UDP protocol. '''
|
||||||
def __init__(*data):
|
__metaclass__=meta.VerboseClassType
|
||||||
JingleAudioSession.__init__(*data)
|
def __init__(self):
|
||||||
JingleICEUDPSession.__init__(*data)
|
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):
|
class ConnectionJingle(object):
|
||||||
''' This object depends on that it is a part of Connection class. '''
|
''' 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
|
''' Add a jingle session to a jingle stanza dispatcher
|
||||||
jingle - a JingleSession object.
|
jingle - a JingleSession object.
|
||||||
'''
|
'''
|
||||||
self.__sessions[(jingle.jid, jingle.sid)]=jingle
|
self.__sessions[(jingle.peerjid, jingle.sid)]=jingle
|
||||||
|
|
||||||
def deleteJingle(self, jingle):
|
def deleteJingle(self, jingle):
|
||||||
''' Remove a jingle session from a jingle stanza dispatcher '''
|
''' 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.
|
''' The jingle stanza dispatcher.
|
||||||
Route jingle stanza to proper JingleSession object,
|
Route jingle stanza to proper JingleSession object,
|
||||||
or create one if it is a new session.
|
or create one if it is a new session.
|
||||||
|
@ -330,6 +386,7 @@ class ConnectionJingle(object):
|
||||||
raise xmpp.NodeProcessed
|
raise xmpp.NodeProcessed
|
||||||
|
|
||||||
jingle = stanza.getTag('jingle')
|
jingle = stanza.getTag('jingle')
|
||||||
|
if not jingle: return
|
||||||
sid = jingle.getAttr('sid')
|
sid = jingle.getAttr('sid')
|
||||||
|
|
||||||
# do we need to create a new jingle object
|
# do we need to create a new jingle object
|
||||||
|
@ -341,5 +398,11 @@ class ConnectionJingle(object):
|
||||||
# we already have such session in dispatcher...
|
# we already have such session in dispatcher...
|
||||||
return self.__sessions[(jid, sid)].stanzaCB(stanza)
|
return self.__sessions[(jid, sid)].stanzaCB(stanza)
|
||||||
|
|
||||||
def addJingleIqCallback(jid, id, jingle):
|
def addJingleIqCallback(self, jid, id, jingle):
|
||||||
self.__iq_responses[(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()
|
||||||
|
|
|
@ -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_IBB ='http://jabber.org/protocol/ibb'
|
||||||
NS_INVISIBLE ='presence-invisible' # Jabberd2
|
NS_INVISIBLE ='presence-invisible' # Jabberd2
|
||||||
NS_IQ ='iq' # 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_LAST ='jabber:iq:last'
|
||||||
NS_MESSAGE ='message' # Jabberd2
|
NS_MESSAGE ='message' # Jabberd2
|
||||||
NS_MOOD ='http://jabber.org/protocol/mood' # XEP-0107
|
NS_MOOD ='http://jabber.org/protocol/mood' # XEP-0107
|
||||||
|
|
Loading…
Reference in New Issue