]> code.delx.au - pymsnt/blobdiff - src/jabw.py
Fix sendRosterImport with ejabberd (trim the resources when sending)
[pymsnt] / src / jabw.py
index fa7f4f44cda807a45b795cdc2fece7fc027733ff..031aaf9857e6d5ab08c73b6654a1cf661d61dd87 100644 (file)
@@ -1,19 +1,16 @@
-# Copyright 2004 James Bunton <james@delx.cjb.net>
+# Copyright 2004-2005 James Bunton <james@delx.cjb.net>
 # Licensed for distribution under the GPL version 2, check COPYING for details
 
 import utils
-if(utils.checkTwisted()):
-       from twisted.xish.domish import Element
-       from twisted.words.protocols.jabber import jid
-else:
-       from tlib.domish import Element
-       from tlib.jabber import jid
-import debug
+from twisted.words.xish.domish import Element
+from twisted.words.protocols.jabber.jid import internJID
+from debug import LogEvent, INFO, WARN, ERROR
+import disco
 
 
 def sendMessage(pytrans, to, fro, body, mtype=None, delay=None):
        """ Sends a Jabber message """
-       debug.log("jabw: Sending a Jabber message \"%s\" \"%s\" \"%s\" \"%s\"" % (to, fro, utils.latin1(body), mtype))
+       LogEvent(INFO)
        el = Element((None, "message"))
        el.attributes["to"] = to
        el.attributes["from"] = fro
@@ -23,23 +20,23 @@ def sendMessage(pytrans, to, fro, body, mtype=None, delay=None):
        
        if(delay):
                x = el.addElement("x")
-               x.attributes["xmlns"] = "jabber:x:delay"
+               x.attributes["xmlns"] = disco.XDELAY
                x.attributes["from"] = fro
                x.attributes["stamp"] = delay
        
        b = el.addElement("body")
        b.addContent(body)
        x = el.addElement("x")
-       x.attributes["xmlns"] = "jabber:x:event"
+       x.attributes["xmlns"] = disco.XEVENT
        composing = x.addElement("composing")
        pytrans.send(el)
 
-def sendPresence(pytrans, to, fro, show=None, status=None, priority=None, ptype=None):
+def sendPresence(pytrans, to, fro, show=None, status=None, priority=None, ptype=None, avatarHash=None, nickname=None, payload=[]):
        # Strip the resource off any presence subscribes (as per XMPP RFC 3921 Section 5.1.6)
        # Makes eJabberd behave :)
-       if(ptype == "subscribe"):
-               (user,host,res) = jid.parse(to)
-               to = "%s@%s" % (user, host)
+       if ptype in ("subscribe", "subscribed", "unsubscribe", "unsubscribed"):
+               to = internJID(to).userhost()
+               fro = internJID(fro).userhost()
        
        el = Element((None, "presence"))
        el.attributes["to"] = to
@@ -55,6 +52,25 @@ def sendPresence(pytrans, to, fro, show=None, status=None, priority=None, ptype=
        if(priority):
                s = el.addElement("priority")
                s.addContent(priority)
+
+       if(not ptype):
+               x = el.addElement("x")
+               x.attributes["xmlns"] = disco.XVCARDUPDATE
+               if(avatarHash):
+                       xx = el.addElement("x")
+                       xx.attributes["xmlns"] = disco.XAVATAR
+                       h = xx.addElement("hash")
+                       h.addContent(avatarHash)
+                       h = x.addElement("photo")
+                       h.addContent(avatarHash)
+               if(nickname):
+                       n = x.addElement("nickname")
+                       n.addContent(nickname)
+       
+       if(payload):
+               for p in payload:
+                       el.addChild(p)
+
        pytrans.send(el)
 
 
@@ -67,9 +83,9 @@ def sendErrorMessage(pytrans, to, fro, etype, condition, explanation, body=None)
        error.attributes["type"] = etype
        error.attributes["code"] = str(utils.errorCodeMap[condition])
        desc = error.addElement(condition)
-       desc.attributes["xmlns"] = "urn:ietf:params:xml:ns:xmpp-stanzas"
+       desc.attributes["xmlns"] = disco.XMPP_STANZAS
        text = error.addElement("text")
-       text.attributes["xmlns"] = "urn:ietf:params:xml:ns:xmpp-stanzas"
+       text.attributes["xmlns"] = disco.XMPP_STANZAS
        text.addContent(explanation)
        if(body and len(body) > 0):
                b = el.addElement("body")
@@ -91,35 +107,28 @@ class JabberConnection:
                self.typingUser = False # Whether this user can accept typing notifications
                self.messageIDs = dict() # The ID of the last message the user sent to a particular contact. Indexed by contact JID
                
-               debug.log("User: %s - JabberConnection constructed" % (self.jabberID))
+               LogEvent(INFO, self.jabberID)
        
        def removeMe(self):
                """ Cleanly deletes the object """
-               debug.log("User: %s - JabberConnection removed" % (self.jabberID))
-       
-       def checkFrom(self, el):
-               """ Checks to see that this packet was intended for this object """
-               fro = el.getAttribute("from")
-               froj = jid.JID(fro)
-               
-               return (froj.userhost() == self.jabberID) # Compare with the Jabber ID that we're looking at
+               LogEvent(INFO, self.jabberID)
        
        def sendMessage(self, to, fro, body, mtype=None, delay=None):
                """ Sends a Jabber message 
                For this message to have a <x xmlns="jabber:x:delay"/> you must pass a correctly formatted timestamp (See JEP0091)
                """
-               debug.log("User: %s - JabberConnection sending message \"%s\" \"%s\" \"%s\" \"%s\"" % (self.jabberID, to, fro, utils.latin1(body), mtype))
+               LogEvent(INFO, self.jabberID)
                sendMessage(self.pytrans, to, fro, body, mtype, delay)
        
        def sendTypingNotification(self, to, fro, typing):
                """ Sends the user the contact's current typing notification status """
                if(self.typingUser):
-                       debug.log("jabw: Sending a Jabber typing notification message \"%s\" \"%s\" \"%s\"" % (to, fro, typing))
+                       LogEvent(INFO, self.jabberID)
                        el = Element((None, "message"))
                        el.attributes["to"] = to
                        el.attributes["from"] = fro
                        x = el.addElement("x")
-                       x.attributes["xmlns"] = "jabber:x:event"
+                       x.attributes["xmlns"] = disco.XEVENT
                        if(typing):
                                composing = x.addElement("composing") 
                        id = x.addElement("id")
@@ -127,68 +136,90 @@ class JabberConnection:
                                id.addContent(self.messageIDs[fro])
                        self.pytrans.send(el)
        
+       def sendVCardRequest(self, to, fro):
+               """ Requests the the vCard of 'to'
+               Returns a Deferred which fires when the vCard has been received.
+               First argument an Element object of the vCard
+               """
+               el = Element((None, "iq"))
+               el.attributes["to"] = to
+               el.attributes["from"] = fro
+               el.attributes["type"] = "get"
+               el.attributes["id"] = self.pytrans.makeMessageID()
+               vCard = el.addElement("vCard")
+               vCard.attributes["xmlns"] = "vcard-temp"
+               return self.pytrans.discovery.sendIq(el)
+       
        def sendErrorMessage(self, to, fro, etype, condition, explanation, body=None):
-               debug.log("User: %s - JabberConnection sending error response." % (self.jabberID))
+               LogEvent(INFO, self.jabberID)
                sendErrorMessage(self.pytrans, to, fro, etype, condition, explanation, body)
        
-       def sendPresence(self, to, fro, show=None, status=None, priority=None, ptype=None):
+       def sendPresence(self, to, fro, show=None, status=None, priority=None, ptype=None, avatarHash=None, nickname=None, payload=[]):
                """ Sends a Jabber presence packet """
-               debug.log("User: %s - JabberConnection sending presence \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"" % (self.jabberID, to, fro, show, utils.latin1(status), priority, ptype))
-               sendPresence(self.pytrans, to, fro, show, status, priority, ptype)
+               LogEvent(INFO, self.jabberID)
+               sendPresence(self.pytrans, to, fro, show, status, priority, ptype, avatarHash, nickname, payload)
        
        def sendRosterImport(self, jid, ptype, sub, name="", groups=[]):
                """ Sends a special presence packet. This will work with all clients, but clients that support roster-import will give a better user experience
                IMPORTANT - Only ever use this for contacts that have already been authorised on the legacy service """
-               el = Element((None, "presence"))
-               el.attributes["to"] = self.jabberID
-               el.attributes["from"] = jid
-               el.attributes["type"] = ptype
-               r = el.addElement("x")
-               r.attributes["xmlns"] = "http://jabber.org/protocol/roster-subsync"
-               item = r.addElement("item")
+               x = Element((None, "x"))
+               x.attributes["xmlns"] = disco.SUBSYNC
+               item = x.addElement("item")
                item.attributes["subscription"] = sub
-               if(name):
+               if name:
                        item.attributes["name"] = unicode(name)
                for group in groups:
                        g = item.addElement("group")
                        g.addContent(group)
                
-               self.pytrans.send(el)
+               self.sendPresence(to=self.jabberID, fro=jid, ptype=ptype, payload=[x])
        
        def onMessage(self, el):
                """ Handles incoming message packets """
-               if(not self.checkFrom(el)): return
-               debug.log("User: %s - JabberConnection received message packet" % (self.jabberID))
+               #LogEvent(INFO, self.jabberID)
                fro = el.getAttribute("from")
-               froj = jid.JID(fro)
                to = el.getAttribute("to")
-               toj = jid.JID(to)
+               try:
+                       froj = internJID(fro)
+                       toj = internJID(to)
+               except Exception, e:
+                       LogEvent(WARN, self.jabberID)
+                       return
+
                mID = el.getAttribute("id")
-               
                mtype = el.getAttribute("type")
                body = ""
-               invite = ""
+               inviteTo = ""
+               inviteRoom = ""
                messageEvent = False
                noerror = False
                composing = None
                for child in el.elements():
                        if(child.name == "body"):
                                body = child.__str__()
-                       if(child.name == "noerror" and child.uri == "sapo:noerror"):
+                       elif(child.name == "noerror" and child.uri == "sapo:noerror"):
                                noerror = True
-                       if(child.name == "x"):
-                               if(child.uri == "jabber:x:conference"):
-                                       invite = child.getAttribute("jid") # The room the contact is being invited to
-                               if(child.uri == "jabber:x:event"):
+                       elif(child.name == "x"):
+                               if(child.uri == disco.XCONFERENCE):
+                                       inviteTo = to
+                                       inviteRoom = child.getAttribute("jid") # The room the contact is being invited to
+                               elif(child.uri == disco.MUC_USER):
+                                       for child2 in child.elements():
+                                               if(child2.name == "invite"):
+                                                       inviteTo = child2.getAttribute("to")
+                                                       break
+                                       inviteRoom = to
+                               elif(child.uri == disco.XEVENT):
                                        messageEvent = True
                                        composing = False
-                                       for deepchild in child.elements():
-                                               if(deepchild.name == "composing"):
+                                       for child2 in child.elements():
+                                               if(child2.name == "composing"):
                                                        composing = True
+                                                       break
                
-               if(invite):
-                       debug.log("User: %s - JabberConnection parsed message groupchat invite packet \"%s\" \"%s\" \"%s\" \"%s\"" % (self.jabberID, froj.userhost(), to, froj.resource, utils.latin1(invite)))
-                       self.inviteReceived(froj.userhost(), froj.resource, toj.userhost(), toj.resource, invite)
+               if(inviteTo and inviteRoom):
+                       LogEvent(INFO, self.jabberID, "Message groupchat invite packet")
+                       self.inviteReceived(source=froj.userhost(), resource=froj.resource, dest=inviteTo, destr="", roomjid=inviteRoom)
                        return
 
                # Check message event stuff
@@ -197,35 +228,35 @@ class JabberConnection:
                elif(body and not messageEvent):
                        self.typingUser = False
                elif(not body and messageEvent):
-                       debug.log("User: %s - JabberConnection parsed typing notification \"%s\" \"%s\"" % (self.jabberID, toj.userhost(), composing))
+                       LogEvent(INFO, self.jabberID, "Message typing notification packet")
                        self.typingNotificationReceived(toj.userhost(), toj.resource, composing)
                        
                        
                if(body):
-#                      body = utils.utf8(body)
                        # Save the message ID for later
                        self.messageIDs[to] = mID
-                       debug.log("User: %s - JabberConnection parsed message packet \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"" % (self.jabberID, froj.userhost(), to, froj.resource, mtype, utils.latin1(body)))
+                       LogEvent(INFO, self.jabberID, "Message packet")
                        self.messageReceived(froj.userhost(), froj.resource, toj.userhost(), toj.resource, mtype, body, noerror)
        
        def onPresence(self, el):
                """ Handles incoming presence packets """
-               if(not self.checkFrom(el)): return
-               debug.log("User: %s - JabberConnection received presence packet" % (self.jabberID))
+               #LogEvent(INFO, self.jabberID)
                fro = el.getAttribute("from")
-               froj = jid.JID(fro)
+               froj = internJID(fro)
                to = el.getAttribute("to")
-               toj = jid.JID(to)
+               toj = internJID(to)
                
                # Grab the contents of the <presence/> packet
                ptype = el.getAttribute("type")
-               if(ptype in ["subscribe", "subscribed", "unsubscribe", "unsubscribed"]):
-                       debug.log("User: %s - JabberConnection parsed subscription presence packet \"%s\" \"%s\"" % (self.jabberID, toj.userhost(), ptype))
-                       self.subscriptionReceived(toj.userhost(), ptype)
+               if ptype and (ptype.startswith("subscribe") or ptype.startswith("unsubscribe")):
+                       LogEvent(INFO, self.jabberID, "Parsed subscription presence packet")
+                       self.subscriptionReceived(fro, toj.userhost(), ptype)
                else:
                        status = None
                        show = None
                        priority = None
+                       avatarHash = ""
+                       nickname = ""
                        for child in el.elements():
                                if(child.name == "status"):
                                        status = child.__str__()
@@ -233,8 +264,22 @@ class JabberConnection:
                                        show = child.__str__()
                                elif(child.name == "priority"):
                                        priority = child.__str__()
+                               elif(child.uri == disco.XVCARDUPDATE):
+                                       avatarHash = " "
+                                       for child2 in child.elements():
+                                               if(child2.name == "photo"):
+                                                       avatarHash = child2.__str__()
+                                               elif(child2.name == "nickname"):
+                                                       nickname = child2.__str__()
+
+                       if not ptype:
+                               # available presence
+                               if(avatarHash):
+                                       self.avatarHashReceived(froj.userhost(), toj.userhost(), avatarHash)
+                               if(nickname):
+                                       self.nicknameReceived(froj.userhost(), toj.userhost(), nickname)
                        
-                       debug.log("User: %s - JabberConnection parsed presence packet \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"" % (self.jabberID, froj.userhost(), froj.resource, priority, ptype, show, utils.latin1(status)))
+                       LogEvent(INFO, self.jabberID, "Parsed presence packet")
                        self.presenceReceived(froj.userhost(), froj.resource, toj.userhost(), toj.resource, priority, ptype, show, status)
        
        
@@ -251,9 +296,16 @@ class JabberConnection:
                """ Override this method to be notified when presence is received """
                pass
        
-       def subscriptionReceived(self, source, subtype):
+       def subscriptionReceived(self, source, dest, subtype):
                """ Override this method to be notified when a subscription packet is received """
                pass
-
+       
+       def nicknameReceived(self, source, dest, nickname):
+               """ Override this method to be notified when a nickname has been received """
+               pass
+       
+       def avatarHashReceieved(self, source, dest, avatarHash):
+               """ Override this method to be notified when an avatar hash is received """
+               pass