# Twisted imports
from twisted.internet import reactor, task
from twisted.internet.defer import Deferred
-from twisted.internet.protocol import ClientFactory
+from twisted.internet.protocol import ReconnectingClientFactory, ClientFactory
try:
from twisted.internet.ssl import ClientContextFactory
except ImportError:
PINGSPEED = 50.0
-DEBUGALL = False
+DEBUGALL = True
LINEDEBUG = False
MESSAGEDEBUG = False
MSNP2PDEBUG = False
def connectionMade(self):
self.sendCommand('GET', self.path)
self.sendHeader('Authorization', 'Passport1.4 OrgVerb=GET,OrgURL=http://messenger.msn.com,' +
- 'sign-in=%s,pwd=%s,%s' % (quote(self.userHandle), self.passwd,self.authData))
+ 'sign-in=%s,pwd=%s,%s' % (quote(self.userHandle), quote(self.passwd), self.authData))
self.sendHeader('Host', self.host)
self.endHeaders()
self.headers = {}
raise NotImplementedError
def sendLine(self, line):
- if LINEDEBUG: log.msg(">> " + line)
+ if LINEDEBUG: log.msg("<< " + line)
LineReceiver.sendLine(self, line)
def lineReceived(self, line):
- if LINEDEBUG: log.msg("<< " + line)
+ if LINEDEBUG: log.msg(">> " + line)
+ if not self.connected: return
if self.currentMessage:
self.currentMessage.readPos += len(line+"\r\n")
try:
if len(cmd) != 3: raise MSNProtocolError, "Invalid Command, %s" % repr(cmd)
if cmd.isdigit():
- if self.ids.has_key(params.split(' ')[0]):
- self.ids[id].errback(int(cmd))
+ id = params.split(' ')[0]
+ if id.isdigit() and self.ids.has_key(int(id)):
+ id = int(id)
+ self.ids[id][0].errback(int(cmd))
del self.ids[id]
return
else: # we received an error which doesn't map to a sent command
self.handle_UNKNOWN(cmd, params.split(' '))
def rawDataReceived(self, data):
+ if not self.connected: return
extra = ""
self.currentMessage.readPos += len(data)
diff = self.currentMessage.readPos - self.currentMessage.length
self.setLineMode(extra)
return
except Exception, e:
- log.msg("Traceback - ERROR in checkMessage: " + str(e))
self.setLineMode(extra)
- return
+ raise
self.gotMessage(m)
self.setLineMode(extra)
MSNEventBase.connectionMade(self)
self._setState('CONNECTED')
self.sendLine("VER %s %s" % (self._nextTransactionID(), MSN_PROTOCOL_VERSION))
+ self.factory.resetDelay()
def connectionLost(self, reason):
self._setState('DISCONNECTED')
def handle_OUT(self, params):
checkParamLen(len(params), 1, 'OUT')
+ self.factory.stopTrying()
if params[0] == "OTH": self.multipleLogin()
elif params[0] == "SSD": self.serverGoingDown()
else: raise MSNProtocolError, "Invalid Parameters received for OUT" # debug
if self.pingCheckTask:
self.pingCheckTask.stop()
self.pingCheckTask = None
+ self.factory.stopTrying()
self.sendLine("OUT")
self.transport.loseConnection()
-class NotificationFactory(ClientFactory):
+class NotificationFactory(ReconnectingClientFactory):
"""
Factory for the NotificationClient protocol.
This is basically responsible for keeping
(the whole URL is required)
@ivar status: The status of the client -- this is generally kept
up to date by the default command handlers
+ @ivar maxRetries: The number of times the factory will reconnect
+ if the connection dies because of a network error.
"""
contacts = None
screenName = ''
password = ''
passportServer = 'https://nexus.passport.com/rdr/pprdr.asp'
- status = 'FLN'
+ status = 'NLN'
protocol = NotificationClient
+ maxRetries = 5
class SwitchboardClient(MSNEventBase):
if not message.getHeader("P2P-Dest") == self.userHandle: return
packet = message.message
binaryFields = BinaryFields(packet=packet)
- if binaryFields[0] != 0:
+ if binaryFields[5] == BinaryFields.BYEGOT:
+ pass # Ignore the ACKs to SLP messages
+ elif binaryFields[0] != 0:
slpLink = self.slpLinks.get(binaryFields[0])
if not slpLink:
# Link has been killed. Ignore
return
if slpLink.remoteUser == message.userHandle:
slpLink.handlePacket(packet)
- if binaryFields[5] == BinaryFields.ACK or binaryFields[5] == BinaryFields.BYEGOT:
+ elif binaryFields[5] == BinaryFields.ACK:
pass # Ignore the ACKs to SLP messages
else:
slpMessage = MSNSLPMessage(packet)
"""
cTypes = [s.lstrip() for s in message.getHeader('Content-Type').split(';')]
if self._checkTyping(message, cTypes): return 0
- if 'text/x-msmsgsinvite' in cTypes:
+# if 'text/x-msmsgsinvite' in cTypes:
# header like info is sent as part of the message body.
- info = {}
- for line in message.message.split('\r\n'):
- try:
- key, val = line.split(':')
- info[key] = val.lstrip()
- except ValueError: continue
- if self._checkFileInvitation(message, info): return 0
+# info = {}
+# for line in message.message.split('\r\n'):
+# try:
+# key, val = line.split(':')
+# info[key] = val.lstrip()
+# except ValueError: continue
+# if self._checkFileInvitation(message, info): return 0
elif 'application/x-msnmsgrp2p' in cTypes:
self._handleP2PMessage(message)
return 0
def bufferClosed(data):
d.callback((data,))
buffer = StringBuffer(bufferClosed)
+ buffer.error = lambda: None
slpLink = SLPLink_AvatarReceive(remoteUser=msnContact.userHandle, switchboard=self, consumer=buffer, context=msnContact.msnobj.text)
self.slpLinks[slpLink.sessionID] = slpLink
return d
self.seqID = SeqID()
def killLink(self):
+ if MSNP2PDEBUG: log.msg("killLink")
def kill():
+ if MSNP2PDEBUG: log.msg("killLink - kill()")
if not self.switchboard: return
del self.switchboard.slpLinks[self.sessionID]
self.switchboard = None
else:
if slpMessage.status == "603":
self.acceptDeferred.callback((False,))
- # SLPLink is over due to decline, error or BYE
+ if MSNP2PDEBUG: log.msg("SLPLink is over due to decline, error or BYE")
self.killLink()
def wait_data_ack(self, packet):
self.handlePacket = lambda packet: None
def handleSLPMessage(self, slpMessage):
- self.killLink() # BYE or error
+ if MSNP2PDEBUG: log.msg("BYE or error")
+ self.killLink()
def close(self):
SLPLink_Send.close(self)
FileReceive.accept(self, consumer)
if not self.switchboard: return
self.sendSLPMessage("200", "application/x-msnmsgr-sessionreqbody", {"SessionID":self.sessionID}, branch=self.initialBranch)
+ self.handlePacket = self.wait_data # Moved here because sometimes the second INVITE seems to be skipped
def handleSLPMessage(self, slpMessage):
if slpMessage.method == "INVITE": # The second invite
"Listening" : "false",\
"Hashed-Nonce": "{00000000-0000-0000-0000-000000000000}"}
self.sendSLPMessage("200", "application/x-msnmsgr-transrespbody", data, branch=slpMessage.branch)
- self.handlePacket = self.wait_data
+# self.handlePacket = self.wait_data # Moved up
else:
- self.killLink() # It's either a BYE or an error
+ if MSNP2PDEBUG: log.msg("It's either a BYE or an error")
+ self.killLink()
# FIXME, do some error handling if it was an error
def doFinished(self):
"AppID" : 1,\
"Context" : context}
self.sendSLPMessage("INVITE", "application/x-msnmsgr-sessionreqbody", data)
+ self.handlePacket = self.wait_dataprep
def handleSLPMessage(self, slpMessage):
if slpMessage.status == "200":
- self.handlePacket = self.wait_dataprep
+ pass
+ #self.handlePacket = self.wait_dataprep # Moved upwards
else:
- # SLPLink is over due to error or BYE
+ if MSNP2PDEBUG: log.msg("SLPLink is over due to error or BYE")
self.killLink()
def doFinished(self):
301 : "Too many FND responses",
302 : "Not logged in",
+ 400 : "Message not allowed",
402 : "Error accessing contact list",
403 : "Error accessing contact list",