X-Git-Url: https://code.delx.au/pymsnt/blobdiff_plain/85e6c0f55bd0d46cad7f94d15b52c7b64dc94c08..0d4d29aca86231be18b7ad579d2eb7dd6e25430f:/src/legacy/glue.py diff --git a/src/legacy/glue.py b/src/legacy/glue.py index a809f8e..176932f 100644 --- a/src/legacy/glue.py +++ b/src/legacy/glue.py @@ -1,36 +1,41 @@ # Copyright 2004-2005 James Bunton # Licensed for distribution under the GPL version 2, check COPYING for details +import os.path import utils from twisted.internet import task -if utils.checkTwisted(): - from twisted.xish.domish import Element -else: - from tlib.domish import Element -from tlib import msn, msnp2p +from tlib.xmlw import Element +from tlib import msn from debug import LogEvent, INFO, WARN, ERROR -import sha +import disco import groupchat +import ft import avatar -import msnw import config import lang -name = "MSN Transport" # The name of the transport url = "http://msn-transport.jabberstudio.org" -version = "0.10.1" # The transport version +version = "0.11-dev" # The transport version mangle = True # XDB '@' -> '%' mangling id = "msn" # The transport identifier -# Load the default avatar -f = open("src/legacy/defaultJabberAvatar.png") +# Load the default avatars +f = open(os.path.join("data", "defaultJabberAvatar.png"), "rb") defaultJabberAvatarData = f.read() f.close() +f = open(os.path.join("data", "defaultMSNAvatar.png"), "rb") +defaultAvatarData = f.read() +f.close() +defaultAvatar = avatar.AvatarCache().setAvatar(defaultAvatarData) + + +def reloadConfig(): + msn.MSNConnection.GETALLAVATARS = config.getAllAvatars def isGroupJID(jid): """ Returns True if the JID passed is a valid groupchat JID (for MSN, does not contain '%') """ @@ -84,19 +89,21 @@ def startStats(statistics): def updateStats(statistics): stats = statistics.stats - stats["AvatarCount"] = msnp2p.MSNP2P_Avatar.TRANSFER_COUNT - stats["FailedAvatarCount"] = msnp2p.MSNP2P_Avatar.ERROR_COUNT + # FIXME + #stats["AvatarCount"] = msnp2p.MSNP2P_Avatar.TRANSFER_COUNT + #stats["FailedAvatarCount"] = msnp2p.MSNP2P_Avatar.ERROR_COUNT -def msn2jid(msnid): +def msn2jid(msnid, withResource): """ Converts a MSN passport into a JID representation to be used with the transport """ - return msnid.replace('@', '%') + "@" + config.jid + return msnid.replace('@', '%') + "@" + config.jid + (withResource and "/msn" or "") -translateAccount = msn2jid # Marks this as the function to be used in jabber:iq:gateway (Service ID Translation) +# Marks this as the function to be used in jabber:iq:gateway (Service ID Translation) +translateAccount = lambda a: msn2jid(a, False) def jid2msn(jid): """ Converts a JID representation of a MSN passport into the original MSN passport """ - return unicode(jid[:jid.find('@')].replace('%', '@')) + return unicode(jid[:jid.find('@')].replace('%', '@')).split("/")[0] def presence2state(show, ptype): @@ -131,32 +138,67 @@ def state2presence(state): return (None, "unavailable") +def getGroupNames(msnContact, msnContactList): + """ Gets a list of groups that this contact is in """ + groups = [] + for groupGUID in msnContact.groups: + try: + groups.append(msnContactList.groups[groupGUID]) + except KeyError: + pass + return groups + +def msnlist2jabsub(lists): + """ Converts MSN contact lists ORed together into the corresponding Jabber subscription state """ + if lists & msn.FORWARD_LIST and lists & msn.REVERSE_LIST: + return "both" + elif lists & msn.REVERSE_LIST: + return "from" + elif lists & msn.FORWARD_LIST: + return "to" + else: + return "none" + + +def jabsub2msnlist(sub): + """ Converts a Jabber subscription state into the corresponding MSN contact lists ORed together """ + if sub == "to": + return msn.FORWARD_LIST + elif sub == "from": + return msn.REVERSE_LIST + elif sub == "both": + return (msn.FORWARD_LIST | msn.REVERSE_LIST) + else: + return 0 + + + # This class handles groupchats with the legacy protocol class LegacyGroupchat(groupchat.BaseGroupchat): - def __init__(self, session, resource, ID=None, existing=False, switchboardSession=None): + def __init__(self, session, resource=None, ID=None, switchboardSession=None): """ Possible entry points for groupchat - User starts an empty switchboard session by sending presence to a blank room - An existing switchboard session is joined by another MSN user - User invited to an existing switchboard session with more than one user """ groupchat.BaseGroupchat.__init__(self, session, resource, ID) - if not existing: - self.switchboardSession = msnw.GroupchatSwitchboardSession(self, makeSwitchboard=True) - else: + if switchboardSession: self.switchboardSession = switchboardSession + else: + self.switchboardSession = msn.MultiSwitchboardSession(self.session.legacycon) + self.switchboardSession.groupchat = self - assert(self.switchboardSession != None) - LogEvent(INFO, self.roomJID()) def removeMe(self): - self.switchboardSession.removeMe() - self.switchboardSession = None + if self.switchboardSession.transport: + self.switchboardSession.transport.loseConnection() + self.switchboardSession.groupchat = None + del self.switchboardSession groupchat.BaseGroupchat.removeMe(self) LogEvent(INFO, self.roomJID()) - utils.mutilateMe(self) def sendLegacyMessage(self, message, noerror): LogEvent(INFO, self.roomJID()) @@ -166,13 +208,19 @@ class LegacyGroupchat(groupchat.BaseGroupchat): LogEvent(INFO, self.roomJID()) userHandle = jid2msn(contactJID) self.switchboardSession.inviteUser(userHandle) + + def gotMessage(self, userHandle, text): + LogEvent(INFO, self.roomJID()) + self.messageReceived(userHandle, text) # This class handles most interaction with the legacy protocol -class LegacyConnection(msnw.MSNConnection): +class LegacyConnection(msn.MSNConnection): """ A glue class that connects to the legacy network """ def __init__(self, username, password, session): + self.jabberID = session.jabberID + self.session = session self.listSynced = False self.initialListVersion = 0 @@ -182,7 +230,7 @@ class LegacyConnection(msnw.MSNConnection): self.remoteNick = "" # Init the MSN bits - msnw.MSNConnection.__init__(self, username, password) + msn.MSNConnection.__init__(self, username, password, self.jabberID) # User typing notification stuff self.userTyping = dict() # Indexed by contact MSN ID, stores whether the user is typing to this contact @@ -192,30 +240,32 @@ class LegacyConnection(msnw.MSNConnection): self.userTypingSend = task.LoopingCall(self.sendTypingNotifications) self.userTypingSend.start(5.0) - import legacylist # Is in here to prevent an ImportError loop - self.legacyList = legacylist.LegacyList(self.session) + self.legacyList = LegacyList(self.session) - LogEvent(INFO, self.session.jabberID) + LogEvent(INFO, self.jabberID) def removeMe(self): - LogEvent(INFO, self.session.jabberID) + LogEvent(INFO, self.jabberID) self.userTypingSend.stop() - msnw.MSNConnection.removeMe(self) self.legacyList.removeMe() self.legacyList = None self.session = None - - utils.mutilateMe(self) + self.logOut() - def jidRes(self, resource): - to = self.session.jabberID - if resource: - to += "/" + resource - return to + # Implemented from baseproto + def sendShowStatus(self, jid=None): + if not self.session: return + source = config.jid + if not jid: + jid = self.jabberID + self.session.sendPresence(to=jid, fro=source, show=self.remoteShow, status=self.remoteStatus, nickname=self.remoteNick) + def resourceOffline(self, resource): + pass + def highestResource(self): """ Returns highest priority resource """ return self.session.highestResource() @@ -225,45 +275,39 @@ class LegacyConnection(msnw.MSNConnection): if self.userTyping.has_key(dest): del self.userTyping[dest] try: - msnw.MSNConnection.sendMessage(self, dest, resource, body, noerror) + msn.MSNConnection.sendMessage(self, dest, body, noerror) self.session.pytrans.statistics.stats["MessageCount"] += 1 except: self.failedMessage(dest, body) raise - def msnAlert(self, text, actionurl, subscrurl): - if not self.session: return - - el = Element((None, "message")) - el.attributes["to"] = self.session.jabberID - el.attributes["from"] = config.jid - el.attributes["type"] = "headline" - body = el.addElement("body") - body.addContent(text) - - x = el.addElement("x") - x.attributes["xmlns"] = "jabber:x:oob" - x.addElement("desc").addContent("More information on this notice.") - x.addElement("url").addContent(actionurl) - - x = el.addElement("x") - x.attributes["xmlns"] = "jabber:x:oob" - x.addElement("desc").addContent("Manage subscriptions to alerts.") - x.addElement("url").addContent(subscrurl) + def sendFile(self, dest, ftSend): + dest = jid2msn(dest) + def continueSendFile1((msnFileSend, d)): + def continueSendFile2((success, )): + if success: + ftSend.accept(msnFileSend) + else: + sendFileFail() + d.addCallbacks(continueSendFile2, sendFileFail) + + def sendFileFail(): + ftSend.reject() - self.session.pytrans.send(el) + d = msn.MSNConnection.sendFile(self, dest, ftSend.filename, ftSend.filesize) + d.addCallbacks(continueSendFile1, sendFileFail) def setStatus(self, nickname, show, status): statusCode = presence2state(show, None) - msnw.MSNConnection.changeStatus(self, statusCode, nickname, status) + msn.MSNConnection.changeStatus(self, statusCode, nickname, status) def updateAvatar(self, av=None): global defaultJabberAvatarData if av: - msnw.MSNConnection.changeAvatar(self, av.getImageData()) + msn.MSNConnection.changeAvatar(self, av.getImageData()) else: - msnw.MSNConnection.changeAvatar(self, defaultJabberAvatarData) + msn.MSNConnection.changeAvatar(self, defaultJabberAvatarData) def sendTypingNotifications(self): if not self.session: return @@ -274,20 +318,11 @@ class LegacyConnection(msnw.MSNConnection): self.sendTypingToContact(contact) # Send any typing notification messages from contacts to the user - for contact, resource in self.contactTyping.keys(): - self.contactTyping[(contact, resource)] += 1 - if self.contactTyping[(contact, resource)] >= 3: - self.session.sendTypingNotification(self.jidRes(resource), msn2jid(contact), False) - del self.contactTyping[(contact, resource)] - - def gotContactTyping(self, contact, resource): - if not self.session: return - # Check if the contact has only just started typing - if not self.contactTyping.has_key((contact, resource)): - self.session.sendTypingNotification(self.jidRes(resource), msn2jid(contact), True) - - # Reset the counter - self.contactTyping[(contact, resource)] = 0 + for contact in self.contactTyping.keys(): + self.contactTyping[contact] += 1 + if self.contactTyping[contact] >= 3: + self.session.sendTypingNotification(self.jabberID, msn2jid(contact, True), False) + del self.contactTyping[contact] def userTypingNotification(self, dest, resource, composing): if not self.session: return @@ -296,51 +331,123 @@ class LegacyConnection(msnw.MSNConnection): if composing: # Make it instant self.sendTypingToContact(dest) + + + # Implement callbacks from msn.MSNConnection + def connectionFailed(self, reason): + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).msnConnectFailed % reason + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=text) + self.session.removeMe() + + def loginFailed(self, reason): + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).msnLoginFailure % (self.session.username) + self.session.sendErrorMessage(to=self.jabberID, fro=config.jid, etype="auth", condition="not-authorized", explanation=text, body="Login Failure") + self.session.removeMe() + + def connectionLost(self, reason): + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).msnDisconnected % reason + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=text) + self.session.removeMe() # Tear down the session + + def multipleLogin(self): + LogEvent(INFO, self.jabberID) + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=lang.get(self.session.lang).msnMultipleLogin) + self.session.removeMe() + + def serverGoingDown(self): + LogEvent(INFO, self.jabberID) + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=lang.get(self.session.lang).msnMaintenance) + + def accountNotVerified(self): + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).msnNotVerified % (self.session.username) + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=text) + + def userMapping(self, passport, jid): + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).userMapping % (passport, jid) + self.session.sendMessage(to=self.jabberID, fro=msn2jid(passport, True), body=text) + + def loggedIn(self): + LogEvent(INFO, self.jabberID) + self.session.ready = True + def listSynchronized(self): - if not self.session: return - self.session.sendPresence(to=self.session.jabberID, fro=config.jid) + LogEvent(INFO, self.jabberID) + self.session.sendPresence(to=self.jabberID, fro=config.jid) self.legacyList.syncJabberLegacyLists() self.listSynced = True #self.legacyList.flushSubscriptionBuffer() - def gotMessage(self, remoteUser, resource, text): - if not self.session: return - source = msn2jid(remoteUser) - self.session.sendMessage(self.jidRes(resource), fro=source, body=text, mtype="chat") + def ourStatusChanged(self, statusCode, screenName, personal): + # Send out a new presence packet to the Jabber user so that the transport icon changes + LogEvent(INFO, self.jabberID) + self.remoteShow, ptype = state2presence(statusCode) + self.remoteStatus = personal + self.remoteNick = screenName + self.sendShowStatus() + + def gotMessage(self, remoteUser, text): + LogEvent(INFO, self.jabberID) + source = msn2jid(remoteUser, True) + if self.contactTyping.has_key(remoteUser): + del self.contactTyping[remoteUser] + self.session.sendMessage(self.jabberID, fro=source, body=text, mtype="chat") self.session.pytrans.statistics.stats["MessageCount"] += 1 - def avatarHashChanged(self, userHandle, hash): - if not self.session: return - av = self.session.pytrans.avatarCache.getAvatar(hash) - if av: - msnContact = self.getContacts().getContact(userHandle) - msnContact.msnobjGot = True - jid = msn2jid(userHandle) - c = self.session.contactList.findContact(jid) - if not c: return - c.updateAvatar(av) - else: - self.requestAvatar(userHandle) + def gotGroupchat(self, msnGroupchat, userHandle): + LogEvent(INFO, self.jabberID) + msnGroupchat.groupchat = LegacyGroupchat(self.session, switchboardSession=msnGroupchat) + msnGroupchat.groupchat.sendUserInvite(msn2jid(userHandle, True)) - def gotAvatarImage(self, userHandle, imageData): - if not self.session: return - jid = msn2jid(userHandle) + def gotContactTyping(self, contact): + LogEvent(INFO, self.jabberID) + # Check if the contact has only just started typing + if not self.contactTyping.has_key(contact): + self.session.sendTypingNotification(self.jabberID, msn2jid(contact, True), True) + + # Reset the counter + self.contactTyping[contact] = 0 + + def failedMessage(self, remoteUser, message): + LogEvent(INFO, self.jabberID) + self.session.pytrans.statistics.stats["FailedMessageCount"] += 1 + fro = msn2jid(remoteUser, True) + self.session.sendErrorMessage(to=self.jabberID, fro=fro, etype="wait", condition="recipient-unavailable", explanation=lang.get(self.session.lang).msnFailedMessage, body=message) + + def contactAvatarChanged(self, userHandle, hash): + LogEvent(INFO, self.jabberID) + jid = msn2jid(userHandle, False) c = self.session.contactList.findContact(jid) if not c: return - av = self.session.pytrans.avatarCache.setAvatar(imageData) - c.updateAvatar(av) - - def loggedIn(self): - if not self.session: return - LogEvent(INFO, self.session.jabberID) - self.session.ready = True + + if hash: + # New avatar + av = self.session.pytrans.avatarCache.getAvatar(hash) + if av: + msnContact = self.getContacts().getContact(userHandle) + msnContact.msnobjGot = True + c.updateAvatar(av) + else: + def updateAvatarCB((imageData,)): + av = self.session.pytrans.avatarCache.setAvatar(imageData) + c.updateAvatar(av) + d = self.sendAvatarRequest(userHandle) + if d: + d.addCallback(updateAvatarCB) + else: + # They've turned off their avatar + global defaultAvatar + c.updateAvatar(defaultAvatar) def contactStatusChanged(self, remoteUser): - if not (self.session and self.getContacts()): return - LogEvent(INFO, self.session.jabberID) + LogEvent(INFO, self.jabberID) msnContact = self.getContacts().getContact(remoteUser) - c = self.session.contactList.findContact(msn2jid(remoteUser)) + c = self.session.contactList.findContact(msn2jid(remoteUser, False)) if not (c and msnContact): return show, ptype = state2presence(msnContact.status) @@ -350,87 +457,197 @@ class LegacyConnection(msnw.MSNConnection): c.updateNickname(screenName, push=False) c.updatePresence(show, status, ptype, force=True) - def ourStatusChanged(self, statusCode): - # Send out a new presence packet to the Jabber user so that the MSN-t icon changes - if not self.session: return - LogEvent(INFO, self.session.jabberID) - self.remoteShow, ptype = state2presence(statusCode) - self.sendShowStatus() - - def ourPersonalChanged(self, statusMessage): - if not self.session: return - LogEvent(INFO, self.session.jabberID) - self.remoteStatus = statusMessage - self.sendShowStatus() - - def ourNickChanged(self, nick): - if not self.session: return - LogEvent(INFO, self.session.jabberID) - self.remoteNick = nick - self.sendShowStatus() - - def sendShowStatus(self): - if not self.session: return - source = config.jid - to = self.session.jabberID - self.session.sendPresence(to=to, fro=source, show=self.remoteShow, status=self.remoteStatus, nickname=self.remoteNick) - - def userMapping(self, passport, jid): - if not self.session: return - text = lang.get(self.session.lang).userMapping % (passport, jid) - self.session.sendMessage(to=self.session.jabberID, fro=msn2jid(passport), body=text) + def gotFileReceive(self, fileReceive): + LogEvent(INFO, self.jabberID) + # FIXME + ft.FTReceive(self.session, msn2jid(fileReceive.userHandle, True), fileReceive) - def userAddedMe(self, userHandle): - if not self.session: return - self.session.contactList.getContact(msn2jid(userHandle)).contactRequestsAuth() + def contactAddedMe(self, userHandle): + LogEvent(INFO, self.jabberID) + self.session.contactList.getContact(msn2jid(userHandle, False)).contactRequestsAuth() - def userRemovedMe(self, userHandle): - if not self.session: return - c = self.session.contactList.getContact(msn2jid(userHandle)) + def contactRemovedMe(self, userHandle): + LogEvent(INFO, self.jabberID) + c = self.session.contactList.getContact(msn2jid(userHandle, True)) c.contactDerequestsAuth() c.contactRemovesAuth() - def serverGoingDown(self): - if not self.session: return - self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=lang.get(self.session.lang).msnMaintenance) + def gotInitialEmailNotification(self, inboxunread, foldersunread): + if config.mailNotifications: + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).msnInitialMail % (inboxunread, foldersunread) + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=text, mtype="headline") + + def gotRealtimeEmailNotification(self, mailfrom, fromaddr, subject): + if config.mailNotifications: + LogEvent(INFO, self.jabberID) + text = lang.get(self.session.lang).msnRealtimeMail % (mailfrom, fromaddr, subject) + self.session.sendMessage(to=self.jabberID, fro=config.jid, body=text, mtype="headline") + + def gotMSNAlert(self, text, actionurl, subscrurl): + LogEvent(INFO, self.jabberID) + + el = Element((None, "message")) + el.attributes["to"] = self.jabberID + el.attributes["from"] = config.jid + el.attributes["type"] = "headline" + body = el.addElement("body") + body.addContent(text) + + x = el.addElement("x") + x.attributes["xmlns"] = "jabber:x:oob" + x.addElement("desc").addContent("More information on this notice.") + x.addElement("url").addContent(actionurl) + + x = el.addElement("x") + x.attributes["xmlns"] = "jabber:x:oob" + x.addElement("desc").addContent("Manage subscriptions to alerts.") + x.addElement("url").addContent(subscrurl) + + self.session.pytrans.send(el) - def multipleLogin(self): - if not self.session: return - self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=lang.get(self.session.lang).msnMultipleLogin) - self.session.removeMe() + def gotAvatarImageData(self, userHandle, imageData): + LogEvent(INFO, self.jabberID) + av = self.session.pytrans.avatarCache.setAvatar(imageData) + jid = msn2jid(userHandle, False) + c = self.session.contactList.findContact(jid) + c.updateAvatar(av) - def accountNotVerified(self): - if not self.session: return - text = lang.get(self.session.lang).msnNotVerified % (self.session.username) - self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text) - def loginFailure(self, message): - if not self.session: return - text = lang.get(self.session.lang).msnLoginFailure % (self.session.username) - self.session.sendErrorMessage(to=self.session.jabberID, fro=config.jid, etype="auth", condition="not-authorized", explanation=text, body="Login Failure") - self.session.removeMe() + + +class LegacyList: + def __init__(self, session): + self.jabberID = session.jabberID + self.session = session + self.subscriptionBuffer = [] - def failedMessage(self, remoteUser, message): - if not self.session: return - self.session.pytrans.statistics.stats["FailedMessageCount"] += 1 - fro = msn2jid(remoteUser) - self.session.sendErrorMessage(to=self.session.jabberID, fro=fro, etype="wait", condition="recipient-unavailable", explanation=lang.get(self.session.lang).msnFailedMessage, body=message) + def removeMe(self): + self.subscriptionBuffer = None + self.session = None + + def addContact(self, jid): + LogEvent(INFO, self.jabberID) + userHandle = jid2msn(jid) + self.session.legacycon.addContact(msn.FORWARD_LIST, userHandle) + self.session.contactList.getContact(jid).contactGrantsAuth() - def initialEmailNotification(self, inboxunread, foldersunread): - if not self.session: return - text = lang.get(self.session.lang).msnInitialMail % (inboxunread, foldersunread) - self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text, mtype="headline") + def removeContact(self, jid): + LogEvent(INFO, self.jabberID) + jid = jid2msn(jid) + self.session.legacycon.remContact(msn.FORWARD_LIST, jid) - def realtimeEmailNotification(self, mailfrom, fromaddr, subject): - if not self.session: return - text = lang.get(self.session.lang).msnRealtimeMail % (mailfrom, fromaddr, subject) - self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text, mtype="headline") - - def connectionLost(self, reason): - if not self.session: return + + def authContact(self, jid): LogEvent(INFO, self.jabberID) - text = lang.get(self.session.lang).msnDisconnected % ("Error") # FIXME, a better error would be nice =P - self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text) - self.session.removeMe() # Tear down the session + jid = jid2msn(jid) + d = self.session.legacycon.remContact(msn.PENDING_LIST, jid) + if d: + self.session.legacycon.addContact(msn.REVERSE_LIST, jid) + self.session.legacycon.remContact(msn.BLOCK_LIST, jid) + self.session.legacycon.addContact(msn.ALLOW_LIST, jid) + + def deauthContact(self, jid): + LogEvent(INFO, self.jabberID) + jid = jid2msn(jid) + self.session.legacycon.remContact(msn.ALLOW_LIST, jid) + self.session.legacycon.remContact(msn.PENDING_LIST, jid) + self.session.legacycon.addContact(msn.BLOCK_LIST, jid) + + + + def syncJabberLegacyLists(self): + """ Synchronises the MSN contact list on server with the Jabber contact list """ + + global defaultAvatar + + # We have to make an MSNContactList from the XDB data, then compare it with the one the server sent + # Any subscription changes must be sent to the client, as well as changed in the XDB + LogEvent(INFO, self.jabberID, "Start.") + result = self.session.pytrans.xdb.request(self.jabberID, disco.IQROSTER) + oldContactList = msn.MSNContactList() + if result: + for item in result.elements(): + user = item.getAttribute("jid") + sub = item.getAttribute("subscription") + lists = item.getAttribute("lists") + if not lists: + lists = jabsub2msnlist(sub) # Backwards compatible + lists = int(lists) + contact = msn.MSNContact(userHandle=user, screenName="", lists=lists) + oldContactList.addContact(contact) + + newXDB = Element((None, "query")) + newXDB.attributes["xmlns"] = disco.IQROSTER + + contactList = self.session.legacycon.getContacts() + + + # Convienence functions + def addedToList(num): + return (not (oldLists & num) and (lists & num)) + def removedFromList(num): + return ((oldLists & num) and not (lists & num)) + + for contact in contactList.contacts.values(): + # Compare with the XDB entry + oldContact = oldContactList.getContact(contact.userHandle) + if oldContact == None: + oldLists = 0 + else: + oldLists = oldContact.lists + lists = contact.lists + + # Create the Jabber representation of the + # contact base on the old list data and then + # sync it with current + jabContact = self.session.contactList.createContact(msn2jid(contact.userHandle, False), msnlist2jabsub(oldLists)) + jabContact.updateAvatar(defaultAvatar, push=False) + + if addedToList(msn.FORWARD_LIST): + jabContact.syncGroups(getGroupNames(contact, contactList), push=False) + jabContact.syncContactGrantedAuth() + if removedFromList(msn.FORWARD_LIST): + jabContact.syncContactRemovedAuth() + + if addedToList(msn.ALLOW_LIST): + jabContact.syncUserGrantedAuth() + + if addedToList(msn.BLOCK_LIST) or removedFromList(msn.ALLOW_LIST): + jabContact.syncUserRemovedAuth() + + if (not (lists & msn.ALLOW_LIST) and not (lists & msn.BLOCK_LIST) and (lists & msn.REVERSE_LIST)) or (lists & msn.PENDING_LIST): + jabContact.contactRequestsAuth() + + if removedFromList(msn.REVERSE_LIST): + jabContact.contactDerequestsAuth() + + jabContact.syncRoster() + + item = newXDB.addElement("item") + item.attributes["jid"] = contact.userHandle + item.attributes["subscription"] = msnlist2jabsub(lists) + item.attributes["lists"] = str(lists) + + # Update the XDB + self.session.pytrans.xdb.set(self.jabberID, disco.IQROSTER, newXDB) + LogEvent(INFO, self.jabberID, "End.") + + def saveLegacyList(self): + contactList = self.session.legacycon.getContacts() + if not contactList: return + + newXDB = Element((None, "query")) + newXDB.attributes["xmlns"] = disco.IQROSTER + + for contact in contactList.contacts.values(): + item = newXDB.addElement("item") + item.attributes["jid"] = contact.userHandle + item.attributes["subscription"] = msnlist2jabsub(contact.lists) # Backwards compat + item.attributes["lists"] = str(contact.lists) + + self.session.pytrans.xdb.set(self.jabberID, disco.IQROSTER, newXDB) + LogEvent(INFO, self.jabberID, "Finished saving list.") +