# 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, 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 = msn.GroupchatSwitchboardSession(self, makeSwitchboard=True)
- else:
+ if switchboardSession:
self.switchboardSession = switchboardSession
+ else:
+ self.switchboardSession = msn.MultiSwitchboardSession(self)
- assert(self.switchboardSession != None)
-
LogEvent(INFO, self.roomJID())
def removeMe(self):
- self.switchboardSession.removeMe()
- self.switchboardSession = None
+ del self.switchboardSession
groupchat.BaseGroupchat.removeMe(self)
LogEvent(INFO, self.roomJID())
LogEvent(INFO, self.roomJID())
userHandle = jid2msn(contactJID)
self.switchboardSession.inviteUser(userHandle)
+
+ def gotMessage(self, userHandle, text)
+ LogEvent(INFO, self.roomJID())
+ self.messageReceived(userHandle, text)
self.legacyList = None
self.session = None
+ 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)
+
+
+
+ # Implemented from baseproto
def resourceOffline(self, resource):
pass
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)
-
- self.session.pytrans.send(el)
-
def setStatus(self, nickname, show, status):
statusCode = presence2state(show, None)
msn.MSNConnection.changeStatus(self, statusCode, nickname, status)
self.session.sendTypingNotification(self.session.jabberID, msn2jid(contact), False)
del self.contactTyping[contact]
- def gotContactTyping(self, contact):
- if not self.session: return
- # Check if the contact has only just started typing
- if not self.contactTyping.has_key(contact):
- self.session.sendTypingNotification(self.session.jabberID, msn2jid(contact), True)
-
- # Reset the counter
- self.contactTyping[contact] = 0
-
def userTypingNotification(self, dest, resource, composing):
if not self.session: return
dest = jid2msn(dest)
if composing: # Make it instant
self.sendTypingToContact(dest)
+
+
+ # Implement callbacks from msn.MSNConnection
+ def connectionFailed(self, reason):
+ LogEvent(INFO, self.session.jabberID)
+ text = lang.get(self.session.lang).msnConnectFailed % reason
+ self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text)
+ self.session.removeMe()
+
+ def loginFailed(self, reason):
+ LogEvent(INFO, self.session.jabberID)
+ 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()
+
+ def connectionLost(self, reason):
+ LogEvent(INFO, self.session.jabberID)
+ text = lang.get(self.session.lang).msnDisconnected % reason
+ self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text)
+ self.session.removeMe() # Tear down the session
+
+ def multipleLogin(self):
+ LogEvent(INFO, self.session.jabberID)
+ self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=lang.get(self.session.lang).msnMultipleLogin)
+ self.session.removeMe()
+
+ def serverGoingDown(self):
+ LogEvent(INFO, self.session.jabberID)
+ self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=lang.get(self.session.lang).msnMaintenance)
+
+ def accountNotVerified(self):
+ LogEvent(INFO, self.session.jabberID)
+ text = lang.get(self.session.lang).msnNotVerified % (self.session.username)
+ self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text)
+
+ def userMapping(self, passport, jid):
+ LogEvent(INFO, self.session.jabberID)
+ text = lang.get(self.session.lang).userMapping % (passport, jid)
+ self.session.sendMessage(to=self.session.jabberID, fro=msn2jid(passport), body=text)
+
+ def loggedIn(self):
+ LogEvent(INFO, self.session.jabberID)
+ self.session.ready = True
+
def listSynchronized(self):
- if not self.session: return
+ LogEvent(INFO, self.session.jabberID)
self.session.sendPresence(to=self.session.jabberID, fro=config.jid)
self.legacyList.syncJabberLegacyLists()
self.listSynced = True
#self.legacyList.flushSubscriptionBuffer()
+ 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.session.jabberID)
+ self.remoteShow, ptype = state2presence(statusCode)
+ self.remoteStatus = personal
+ self.remoteNick = screenName
+ self._sendShowStatus()
+
def gotMessage(self, remoteUser, text):
- if not self.session: return
+ LogEvent(INFO, self.session.jabberID)
source = msn2jid(remoteUser)
self.session.sendMessage(self.session.jabberID, fro=source, body=text, mtype="chat")
self.session.pytrans.statistics.stats["MessageCount"] += 1
- def avatarHashChanged(self, userHandle, hash):
- if not self.session: return
+ def gotGroupchat(self, msnGroupchat):
+ LogEvent(INFO, self.session.jabberID)
+ msnGroupchat.groupchat = LegacyGroupchat(self.session, switchboardSession=msnGroupchat)
+
+ def gotContactTyping(self, contact):
+ LogEvent(INFO, self.session.jabberID)
+ # Check if the contact has only just started typing
+ if not self.contactTyping.has_key(contact):
+ self.session.sendTypingNotification(self.session.jabberID, msn2jid(contact), True)
- if not hash:
- # They've turned off their avatar
- c = self.session.contactList.findContact(jid)
- if not c: return
- c.updateAvatar(av)
- else:
+ # Reset the counter
+ self.contactTyping[contact] = 0
+
+ def failedMessage(self, remoteUser, message):
+ LogEvent(INFO, self.session.jabberID)
+ 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 contactAvatarChanged(self, userHandle, hash):
+ LogEvent(INFO, self.session.jabberID)
+ c = self.session.contactList.findContact(jid)
+ if not c: return
+
+ if hash:
# New avatar
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 gotAvatarImage(self, userHandle, imageData):
- if not self.session: return
- jid = msn2jid(userHandle)
- c = self.session.contactList.findContact(jid)
- if not c: return
- av = self.session.pytrans.avatarCache.setAvatar(imageData)
- c.updateAvatar(av)
-
- def gotSendRequest(self, fileReceive):
- if not self.session: return
- LogEvent(INFO, self.session.jabberID)
- ft.FTReceive(self.session, msn2jid(fileReceive.userHandle), fileReceive)
-
- def loggedIn(self):
- if not self.session: return
- LogEvent(INFO, self.session.jabberID)
- self.session.ready = True
+ def updateAvatar((imageData,)):
+ av = self.session.pytrans.avatarCache.setAvatar(imageData)
+ c.updateAvatar(av)
+ self.sendAvatarRequest(userHandle).addCallback(updateAvatar)
+ else:
+ # They've turned off their avatar
+ global defaultAvatar
+ c.updateAvatar(defaultAvatar)
- def contactStatusChanged(self, remoteUser, statusCode, screenName):
- if not (self.session and self.getContacts()): return
+ def contactStatusChanged(self, remoteUser):
LogEvent(INFO, self.session.jabberID)
msnContact = self.getContacts().getContact(remoteUser)
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
+ def gotFileReceive(self, fileReceive):
LogEvent(INFO, self.session.jabberID)
- self.remoteShow, ptype = state2presence(statusCode)
- self.sendShowStatus()
+ pass # FIXME
- def ourPersonalChanged(self, statusMessage):
- if not self.session: return
+ def contactAddedMe(self, userHandle):
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 userAddedMe(self, userHandle):
- if not self.session: return
self.session.contactList.getContact(msn2jid(userHandle)).contactRequestsAuth()
- def userRemovedMe(self, userHandle):
- if not self.session: return
+ def contactRemovedMe(self, userHandle):
+ LogEvent(INFO, self.session.jabberID)
c = self.session.contactList.getContact(msn2jid(userHandle))
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 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 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()
-
- 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 initialEmailNotification(self, inboxunread, foldersunread):
- if not self.session: return
+ def gotInitialEmailNotification(self, inboxunread, foldersunread):
+ LogEvent(INFO, self.session.jabberID)
text = lang.get(self.session.lang).msnInitialMail % (inboxunread, foldersunread)
self.session.sendMessage(to=self.session.jabberID, fro=config.jid, body=text, mtype="headline")
- def realtimeEmailNotification(self, mailfrom, fromaddr, subject):
- if not self.session: return
+ def gotRealtimeEmailNotification(self, mailfrom, fromaddr, subject):
+ LogEvent(INFO, self.session.jabberID)
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 gotMSNAlert(self, text, actionurl, subscrurl):
LogEvent(INFO, self.session.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
+
+ 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)
+
+ self.session.pytrans.send(el)
+
+
class LegacyList:
def sendTypingToContact(self, userHandle):
"""
- Sends typing notification to a contact.
+ Sends typing notification to a contact. Should send every 5secs.
@param userHandle: the contact to notify of our typing.
"""
def connectionFailed(self, reason=''):
""" Called when the connection to the server failed. """
+ def loginFailed(self, reason=''):
+ """ Called when the account could not be logged in. """
+
def connectionLost(self, reason=''):
""" Called when we are disconnected. """
def gotMessage(self, userHandle, text):
""" Called when a contact sends us a message """
- def gotGroupchat(self, groupchat):
+ def gotGroupchat(self, msnGroupchat):
""" Called when a conversation with more than one contact begins.
- The overriding method is expected to set groupchat.groupchat to an object
+ The overriding method is expected to set msnGroupchat.groupchat to an object
that implements the following methods:
contactJoined(userHandle)
contactLeft(userHandle)
gotMessage(userHandle, text)
- The object received as 'groupchat' is an instance of MultiSwitchboardSession.
+ The object received as 'msnGroupchat' is an instance of MultiSwitchboardSession.
"""
def gotContactTyping(self, userHandle):
- """ Called when a contact sends typing notification """
+ """ Called when a contact sends typing notification.
+ Will be called once every 5 seconds. """
def failedMessage(self, userHandle, text):
""" Called when a message we sent has been bounced back. """
""" Called when we receive a changed avatar hash for a contact.
You should call sendAvatarRequest(). """
- def contactStatusChanged(self, userHandle, statusCode, screenName):
+ def contactStatusChanged(self, userHandle):
""" Called when we receive status information for a contact. """
- def contactPersonalChanged(self, personal):
- """ Called when we receive a new personal message for a contact. """
-
def gotFileReceive(self, fileReceive):
""" Called when a contact sends the user a file.
Call accept(fileHandle) or reject() on the object. """
def contactRemovedMe(self, userHandle):
""" Called when a contact removes the user from their list. """
+
+ def gotInitialEmailNotification(self, inboxunread, foldersunread):
+ """ Received at login to tell about the user's Hotmail status """
+
+ def gotRealtimeEmailNotification(self, mailfrom, fromaddr, subject):
+ """ Received in realtime whenever an email comes into the hotmail account """
+
+ def gotMSNAlert(self, body, action, subscr):
+ """ An MSN Alert (http://alerts.msn.com) was received. Body is the
+ text of the alert. 'action' is a url for more information,
+ 'subscr' is a url to modify your your alerts subscriptions. """
class SavedEvents:
class NotificationClient(msn.NotificationClient):
def loginFailure(self, message):
- self.factory.msncon.connectionFailed(message)
+ self.factory.msncon.loginFailed(message)
def loggedIn(self, userHandle, verified):
LogEvent(INFO, self.factory.msncon.ident)
def gotContactStatus(self, userHandle, statusCode, screenName):
LogEvent(INFO, self.factory.msncon.ident)
- self.factory.msncon.contactStatusChanged(userHandle, statusCode, screenName)
+ self.factory.msncon.contactStatusChanged(userHandle)
def contactStatusChanged(self, userHandle, statusCode, screenName):
LogEvent(INFO, self.factory.msncon.ident)
- self.factory.msncon.contactStatusChanged(userHandle, statusCode, screenName)
+ self.factory.msncon.contactStatusChanged(userHandle)
- def contactOffline(self, userHandle):
+ def contactPersonalChanged(self, userHandle, personal):
LogEvent(INFO, self.factory.msncon.ident)
- self.factory.msncon.contactStatusChanged(userHandle, msn.STATUS_OFFLINE, "")
+ self.factory.msncon.contactStatusChanged(userHandle)
+ def contactOffline(self, userHandle):
+ LogEvent(INFO, self.factory.msncon.ident)
+ self.factory.msncon.contactStatusChanged(userHandle)
+
def gotSwitchboardInvitation(self, sessionID, host, port, key, userHandle, screenName):
LogEvent(INFO, self.factory.msncon.ident)
sb = self.factory.msncon.switchboardSessions.get(userHandle)
-def switchToMulti(switchboardSession, msncon, userHandle):
- LogEvent(INFO, switchboardSession.ident)
- switchboardSession.__class__ = MultiSwitchboardSession
- del switchboardSession.remoteUser
- switchboardSession.userJoined(userHandle)
- msncon.gotGroupchat(switchboardSession)
- if not switchboardSession.groupchat:
- raise Exception("YouNeedAGroupchat-WeHaveAProblemError") # FIXME
-
-
class SwitchboardSessionBase(msn.SwitchboardClient):
def __init__(self, msncon):
msn.SwitchboardClient.__init__(self)
LogEvent(INFO, self.ident)
msn.SwitchboardClient.inviteUser(userHandle)
else:
- self.funcBuffer.append(lamba: msn.SwitchboardClient.inviteUser(userHandle))
+ self.funcBuffer.append(lambda: msn.SwitchboardClient.inviteUser(userHandle))
def gotMessage(self, message):
self.groupchat.gotMessage(message.userHandle, message.getMessage())
self.timeout.cancel()
self.timeout = None
self.flushBuffer()
+
+ def _switchToMulti(self):
+ LogEvent(INFO, self.ident)
+ del self.switchboardSessions[self.remoteUser]
+ self.__class__ = MultiSwitchboardSession
+ del self.remoteUser
+ self.msncon.gotGroupchat(switchboardSession)
+ if not self.groupchat:
+ LogEvent(ERROR, self.ident)
+ raise Exception("YouNeedAGroupchat-WeHaveAProblemError") # FIXME
def failedMessage(self, text):
self.msncon.failedMessage(self.remoteUser, text)
self._ready()
if userHandle != self.remoteUser:
# Another user has joined, so we now have three participants.
- switchToMulti(self, msncon, userHandle)
+ self.switchToMulti(self)
+ self.userJoined(userHandle)
def userLeft(self, userHandle):
def wait():