""" Called whenever PyTransport wants to send a message to a remote user """
pass
+ def sendFile(self, dest, fileSend):
+ """ Called whenever PyTransport wants to send a file to a remote user. Call accept(fileObj), or reject(). """
+
def setStatus(self, nickname, show, status):
""" Called whenever PyTransport needs to change the status on the legacy service
'nickname' is the Jabber nickname, 'show' is a Jabber status description, and status
import random
import sys
+
+###########
+# Sending #
+###########
+
+class FTSend:
+ """ For file transfers going from Jabber to MSN. """
+ def __init__(self, startTransfer, filename, filesize):
+ self.startTransfer = startTransfer
+ self.filename = filename
+ self.filesize = filesize
+
+ def accept(self, legacyFileSend):
+ self.startTransfer(legacyFileSend)
+
+ def reject(self):
+ del self.startTransfer
+
+
+try:
+ from twisted.web import http
+except ImportError:
+ try:
+ from twisted.protocols import http
+ except ImportError:
+ print "Couldn't find http.HTTPClient. If you're using Twisted 2.0, make sure that you've installed twisted.web"
+ raise
+
+class OOBSendConnector(http.HTTPClient):
+ def connectionMade(self):
+ self.sendCommand("GET", self.factory.path.encode("utf-8"))
+ self.sendHeader("Host", (self.factory.host + ":" + str(self.factory.port)).encode("utf-8"))
+ self.endHeaders()
+ self.first = True
+
+ def handleResponsePart(self, data):
+ self.factory.consumer.write(data)
+
+ def handleResponseEnd(self):
+ # This is called once before writing is finished, and once when the
+ # connection closes. We only consumer.close() on the second.
+ if self.first:
+ self.first = False
+ else:
+ self.factory.consumer.close()
+ self.factory.consumer = None
+
+
+
+
+
+#############
+# Receiving #
+#############
+
class FTReceive:
- """ Manager for file transfers going from MSN to Jabber. """
+ """ For file transfers going from MSN to Jabber. """
"""
Plan of action for this class:
from debug import LogEvent, INFO, WARN, ERROR
-class Connector:
+class OOBReceiveConnector:
def __init__(self, ftReceive, ftHttpPush):
self.ftReceive, self.ftHttpPush = ftReceive, ftHttpPush
self.ftReceive.legacyftp.accept(self)
self.ftHttpPush.finish()
self.ftReceive.error()
-class FileTransferOOB(resource.Resource):
+class FileTransferOOBReceive(resource.Resource):
def __init__(self, port):
LogEvent(INFO)
self.isLeaf = True
file = self.files[filename]
request.setHeader("Content-Length", str(file.legacyftp.filesize))
request.setHeader("Content-Disposition", "attachment; filename=\"%s\"" % file.legacyftp.filename.encode("utf-8"))
- Connector(file, request)
+ OOBReceiveConnector(file, request)
del self.files[filename]
return server.NOT_DONE_YET
else:
self.failedMessage(dest, body)
raise
+ 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()
+
+ d = msn.MSNConnection.sendFile(self, dest, ftSend.filename, ftSend.filesize)
+ d.addCallbacks(continueSendFile1, sendFileFail)
+
def setStatus(self, nickname, show, status):
statusCode = presence2state(show, None)
msn.MSNConnection.changeStatus(self, statusCode, nickname, status)
self.iqAvatarFactor = misciq.IqAvatarFactory(self)
self.connectUsers = misciq.ConnectUsers(self)
if config.ftJabberPort: self.ftSOCKS5 = ft.Proxy65(int(config.ftJabberPort))
- if config.ftOOBPort: self.ftOOB = ft.FileTransferOOB(int(config.ftOOBPort))
+ if config.ftOOBPort:
+ self.ftOOBReceive = ft.FileTransferOOBReceive(int(config.ftOOBPort))
+ self.ftOOBSend = misciq.FileTransferOOBSend(self)
self.statistics = misciq.Statistics(self)
self.startTime = int(time.time())
# Licensed for distribution under the GPL version 2, check COPYING for details
import utils
-from twisted.internet import reactor, task
+from twisted.internet import reactor, task, protocol
from tlib.xmlw import Element, jid
from debug import LogEvent, INFO, WARN, ERROR
import jabw
import disco
import config
import lang
+import ft
import base64
-import sys
+import sys, urllib
class ConnectUsers:
self.pytrans.send(iq)
+class FileTransferOOBSend:
+ def __init__(self, pytrans):
+ self.pytrans = pytrans
+ self.pytrans.discovery.addFeature(disco.IQOOB, self.incomingOOB, "USER")
+
+ def incomingOOB(self, el):
+ errOut = lambda: self.pytrans.discovery.sendIqError(to=el.getAttribute("from"), fro=el.getAttribute("to"), ID=el.getAttribute("id"), xmlns=disco.IQOOB, etype="cancel", condition="feature-not-implemented")
+ if el.attributes["type"] != "set":
+ return errOut()
+ for child in el.elements():
+ if child.name == "query":
+ query = child
+ break
+ else:
+ return errOut()
+ for child in query.elements():
+ if child.name == "url":
+ url = child.__str__()
+ break
+ else:
+ return errOut()
+
+ froj = jid.intern(el.getAttribute("from"))
+ toj = jid.intern(el.getAttribute("to"))
+ session = self.pytrans.sessions.get(froj.userhost(), None)
+ if not session:
+ return errOut()
+
+ res = utils.getURLBits(url, "http")
+ if not res:
+ return errOut()
+ host, port, path, filename = res
+
+
+ def sendResult():
+ iq = Element((None, "iq"))
+ iq.attributes["to"] = froj.full()
+ iq.attributes["from"] = to.full()
+ iq.attributes["type"] = "result"
+ iq.addElement("query").attributes["xmlns"] = "jabber:iq:oob"
+ self.pytrans.send(iq)
+
+ def startTransfer(consumer):
+ factory = protocol.ClientFactory()
+ factory.protocol = ft.OOBSendConnector
+ factory.path = path
+ factory.host = host
+ factory.port = port
+ factory.consumer = consumer
+ reactor.connectTCP(host, port, factory)
+ session.legacycon.sendFile(toj.userhost(), ft.FTSend(startTransfer, filename, 1024))
+
+
+class Socks5FileTransfer:
+ def __init__(self, pytrans):
+ self.pytrans = pytrans
+ self.pytrans.discovery.addFeature(disco.SI, self.incomingSI, "USER")
+ self.pytrans.discovery.addFeature(disco.S5B, self.incomingS5B, "USER")
+
+ def incomingSI(self, el):
+ pass
+
+ def incomingS5B(self, el):
+ pass
@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()
return sha.new("%s%s%s" % (sid, initiator, target)).hexdigest()
+import urllib
+import os.path
+def getURLBits(url, assumedType=None):
+ type, rest = urllib.splittype(url)
+ if assumedType and type != assumedType:
+ return
+ hostport, path = urllib.splithost(rest)
+ host, port = urllib.splitnport(hostport, 80)
+ filename = os.path.basename(path)
+ return host, port, path, filename
+
+
try:
import Image
import StringIO