from twisted.internet.protocol import ClientFactory
# System imports
-import math, base64, binascii, math
+import math, base64, binascii
# Local imports
from debug import LogEvent, INFO, WARN, ERROR
from tlib.msn import msn
-MAXMESSAGESIZE = 1400
-SWITCHBOARDTIMEOUT = 30.0*60.0
-GETALLAVATARS = False
-
"""
All interaction should be with the MSNConnection and MultiSwitchboardSession classes.
class MSNConnection:
""" Manages all the Twisted factories, etc """
+ MAXMESSAGESIZE = 1400
+ SWITCHBOARDTIMEOUT = 30.0*60.0
+ GETALLAVATARS = False
+
def __init__(self, username, password, ident):
""" Connects to the MSN servers.
@param username: the MSN passport to connect with.
self.password = password
self.ident = ident
self.timeout = None
+ self.notificationFactory = None
self.notificationClient = None
self.connect()
LogEvent(INFO, self.ident)
def _getNotificationReferral(self):
def timeout():
- if not d.called: d.errback()
+ if not d.called:
+ d.errback()
+ self.logOut() # Clean up everything
self.timeout = reactor.callLater(30, timeout)
dispatchFactory = msn.DispatchFactory()
dispatchFactory.userHandle = self.username
LogEvent(INFO, self.ident)
if not self.notificationClient: return
- if GETALLAVATARS:
+ if MSNConnection.GETALLAVATARS:
self._ensureSwitchboardSession(userHandle)
sb = self.switchboardSessions.get(userHandle)
if sb: return sb.sendAvatarRequest()
@return: A Deferred, which will fire with an argument of:
(fileSend, d) A FileSend object and a Deferred.
- The Deferred will pass one argument in a tuple,
+ The new Deferred will pass one argument in a tuple,
whether or not the transfer is accepted. If you
receive a True, then you can call write() on the
fileSend object to send your file. Call close()
changeCount[0] += 1
if changeCount[0] == 3:
self.ourStatusChanged(statusCode, screenName, personal)
- del changeCount
LogEvent(INFO, self.ident)
self.notificationClient.changeStatus(statusCode.encode("utf-8")).addCallback(cb)
self.notificationClient.changeScreenName(screenName.encode("utf-8")).addCallback(cb)
def logOut(self):
""" Shuts down the whole connection. Don't try to call any
- other methods after this one. """
+ other methods after this one. Except maybe connect() """
if self.notificationClient:
self.notificationClient.logOut()
for c in self.connectors:
if self.notificationFactory:
self.notificationFactory.msncon = None
self.connectors = []
+ for sbs in self.switchboardSessions.values():
+ if hasattr(sbs, "transport") and sbs.transport:
+ sbs.transport.loseConnection()
self.switchboardSessions = {}
LogEvent(INFO, self.ident)
class SavedEvents:
def __init__(self):
- self.nickname = ""
+ self.screenName = ""
self.statusCode = ""
self.personal = ""
self.avatarImageData = ""
def send(self, msncon):
if self.avatarImageData:
msncon.notificationClient.changeAvatar(self.avatarImageData, push=False)
- if self.nickname or self.statusCode or self.personal:
- msncon.changeStatus(self.statusCode, self.nickname, self.personal)
+ if self.screenName or self.statusCode or self.personal:
+ msncon.changeStatus(self.statusCode, self.screenName, self.personal)
for listType, userHandle in self.addContacts:
msncon.addContact(listType, userHandle)
for listType, userHandle in self.remContacts:
if not noerror:
self.failedMessage(text)
- if len(text) < MAXMESSAGESIZE:
+ if len(text) < MSNConnection.MAXMESSAGESIZE:
message = msn.MSNMessage(message=str(text.replace("\n", "\r\n").encode("utf-8")))
message.setHeader("Content-Type", "text/plain; charset=UTF-8")
message.ack = msn.MSNMessage.MESSAGE_NACK
d.addCallback(failedMessage)
else:
- chunks = int(math.ceil(len(text) / float(MAXMESSAGESIZE)))
+ chunks = int(math.ceil(len(text) / float(MSNConnection.MAXMESSAGESIZE)))
chunk = 0
guid = msn.random_guid()
while chunk < chunks:
- offset = chunk * MAXMESSAGESIZE
- text = message[offset : offset + MAXMESSAGESIZE]
+ offset = chunk * MSNConnection.MAXMESSAGESIZE
+ text = message[offset : offset + MSNConnection.MAXMESSAGESIZE]
message = msn.MSNMessage(message=str(text.replace("\n", "\r\n").encode("utf-8")))
message.ack = msn.MSNMessage.MESSAGE_NACK
if chunk == 0:
self.timeout = None
def __del__(self):
+ if self.timeout:
+ self.timeout.cancel()
+ self.timeout = None
for message, noerror in self.messageBuffer:
if not noerror:
- self.failedMessage(self.remoteUser, message)
+ self.failedMessage(message)
def _ready(self):
LogEvent(INFO, self.ident)
LogEvent(INFO, self.ident)
if not self.reply:
def failCB(arg=None):
+ if not (self.msncon and self.msncon.switchboardSessions.has_key(self.remoteUser)):
+ return
LogEvent(INFO, self.ident, "User has not joined after 30 seconds.")
del self.msncon.switchboardSessions[self.remoteUser]
+ self.timeout = None
d = self.inviteUser(self.remoteUser)
d.addErrback(failCB)
self.timeout = reactor.callLater(30.0, failCB)
def userLeft(self, userHandle):
def wait():
if userHandle == self.remoteUser:
- del self.msncon.switchboardSessions[self.remoteUser]
+ if self.msncon and self.msncon.switchboardSessions.has_key(self.remoteUser):
+ del self.msncon.switchboardSessions[self.remoteUser]
reactor.callLater(0, wait) # Make sure this is handled after everything else
def gotMessage(self, message):
text = message.getMessage()
self.msncon.gotMessage(self.remoteUser, text)
except:
- self.msncon.gotMessage("A message was lost.")
+ self.msncon.gotMessage(self.remoteUser, "A message was lost.")
raise
elif "text/x-clientcaps" == cTypes[0]:
if message.hasHeader("JabberID"):
jid = message.getHeader("JabberID")
- self.switchboardSession.msncon.userMapping(message.userHandle, jid)
+ self.msncon.userMapping(message.userHandle, jid)
else:
LogEvent(INFO, self.ident, "Discarding unknown message type.")