]> code.delx.au - pymsnt/blobdiff - src/misciq.py
Fixed default ft limit.
[pymsnt] / src / misciq.py
index 732912054b56053ab7bb742fe7c2e1dcb0c409e3..a565755251c1b3bc86e33d5b0ad5b7ed86f582f1 100644 (file)
@@ -2,7 +2,7 @@
 # Licensed for distribution under the GPL version 2, check COPYING for details
 
 import utils
 # 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, error
 from tlib.xmlw import Element, jid
 from debug import LogEvent, INFO, WARN, ERROR
 import jabw
 from tlib.xmlw import Element, jid
 from debug import LogEvent, INFO, WARN, ERROR
 import jabw
@@ -10,8 +10,9 @@ import legacy
 import disco
 import config
 import lang
 import disco
 import config
 import lang
+import ft
 import base64
 import base64
-import sys
+import sys, urllib
 
 
 class ConnectUsers:
 
 
 class ConnectUsers:
@@ -48,7 +49,7 @@ class ConnectUsers:
                command.attributes["status"] = "completed"
 
                x = command.addElement("x")
                command.attributes["status"] = "completed"
 
                x = command.addElement("x")
-               x.attributes["xmlns"] = "jabber:x:data"
+               x.attributes["xmlns"] = disco.XDATA
                x.attributes["type"] = "result"
 
                title = x.addElement("title")
                x.attributes["type"] = "result"
 
                title = x.addElement("title")
@@ -92,7 +93,7 @@ class Statistics:
                command.attributes["status"] = "completed"
 
                x = command.addElement("x")
                command.attributes["status"] = "completed"
 
                x = command.addElement("x")
-               x.attributes["xmlns"] = "jabber:x:data"
+               x.attributes["xmlns"] = disco.XDATA
                x.attributes["type"] = "result"
 
                title = x.addElement("title")
                x.attributes["type"] = "result"
 
                title = x.addElement("title")
@@ -455,4 +456,222 @@ class VersionTeller:
                self.pytrans.send(iq)
 
 
                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):
+               ID = el.getAttribute("id")
+               def errOut():
+                       self.pytrans.discovery.sendIqError(to=el.getAttribute("from"), fro=el.getAttribute("to"), ID=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"] = toj.full()
+                       iq.attributes["type"] = "result"
+                       if ID:
+                               iq.attributes["id"] = ID
+                       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
+                       factory.finished = sendResult
+                       reactor.connectTCP(host, port, factory)
+
+               def doSendFile(length):
+                       ft.FTSend(session, toj.userhost(), startTransfer, errOut, filename, length)
+
+               # Make a HEAD request to grab the length of data first
+               factory = protocol.ClientFactory()
+               factory.protocol = ft.OOBHeaderHelper
+               factory.path = path
+               factory.host = host
+               factory.port = port
+               factory.gotLength = doSendFile
+               reactor.connectTCP(host, port, factory)
+
+
+
+class Socks5FileTransfer:
+       def __init__(self, pytrans):
+               self.pytrans = pytrans
+               self.pytrans.discovery.addFeature(disco.SI, self.incomingSI, "USER")
+               self.pytrans.discovery.addFeature(disco.FT, lambda: None, "USER")
+               self.pytrans.discovery.addFeature(disco.S5B, self.incomingS5B, "USER")
+               self.sessions = {}
+       
+       def incomingSI(self, el):
+               ID = el.getAttribute("id")
+               def errOut():
+                       self.pytrans.discovery.sendIqError(to=el.getAttribute("from"), fro=el.getAttribute("to"), ID=ID, xmlns=disco.SI, etype="cancel", condition="bad-request")
+
+               toj = jid.intern(el.getAttribute("to"))
+               froj = jid.intern(el.getAttribute("from"))
+               session = self.pytrans.sessions.get(froj.userhost(), None)
+               if not session:
+                       return errOut()
+
+               si = el.si
+               if not (si and si.getAttribute("profile") == disco.FT):
+                       return errOut()
+               file = si.file
+               if not (file and file.defaultUri == disco.FT):
+                       return errOut()
+               try:
+                       sid = si["id"]
+                       filename = file["name"]
+                       filesize = int(file["size"])
+               except KeyError:
+                       return errOut()
+               except ValueError:
+                       return errOut()
+
+               # Check that we can use socks5 bytestreams
+               feature = si.feature
+               if not (feature and feature.defaultUri == disco.FEATURE_NEG):
+                       return errOut()
+               x = feature.x
+               if not (x and x.defaultUri == disco.XDATA):
+                       return errOut()
+               field = x.field
+               if not (field and field.getAttribute("var") == "stream-method"):
+                       return errOut()
+               for option in field.elements():
+                       value = option.value
+                       if not value:
+                               continue
+                       value = value.__str__()
+                       if value == disco.S5B:
+                               break
+               else:
+                       return errOut() # Socks5 bytestreams not supported :(
+
+
+               def startTransfer(consumer):
+                       iq = Element((None, "iq"))
+                       iq["type"] = "result"
+                       iq["to"] = froj.full()
+                       iq["from"] = toj.full()
+                       iq["id"] = ID
+                       si = iq.addElement("si")
+                       si["xmlns"] = disco.SI
+                       feature = si.addElement("feature")
+                       feature["xmlns"] = disco.FEATURE_NEG
+                       x = feature.addElement("x")
+                       x["xmlns"] = disco.XDATA
+                       x["type"] = "submit"
+                       field = x.addElement("field")
+                       field["var"] = "stream-method"
+                       value = field.addElement("value")
+                       value.addContent(disco.S5B)
+                       self.pytrans.send(iq)
+                       self.sessions[(froj.full(), sid)] = consumer
+
+               ft.FTSend(session, toj.userhost(), startTransfer, errOut, filename, filesize)
+       
+       def incomingS5B(self, el):
+               ID = el.getAttribute("id")
+               def errOut():
+                       self.pytrans.discovery.sendIqError(to=el.getAttribute("from"), fro=el.getAttribute("to"), ID=ID, xmlns=disco.S5B, etype="cancel", condition="item-not-found")
+
+               if el.getAttribute("type") != "set":
+                       return errOut()
+
+               toj = jid.intern(el.getAttribute("to"))
+               froj = jid.intern(el.getAttribute("from"))
+
+               query = el.query
+               if not (query and query.getAttribute("mode") == "tcp"):
+                       return errOut()
+               sid = query.getAttribute("sid")
+               consumer = self.sessions.pop((froj.full(), sid), None)
+               if not consumer:
+                       return errOut()
+               streamhosts = []
+               for streamhost in query.elements():
+                       if streamhost.name == "streamhost":
+                               try:
+                                       JID = streamhost["jid"]
+                                       host = streamhost["host"]
+                                       port = int(streamhost["port"])
+                               except ValueError:
+                                       return errOut()
+                               except KeyError:
+                                       continue
+                               streamhosts.append((JID, host, port))
+
+
+               def gotStreamhost(host):
+                       for streamhost in streamhosts:
+                               if streamhost[1] == host:
+                                       jid = streamhost[0]
+                                       break
+                       else:
+                               LogEvent(WARN)
+                               return errOut()
+
+                       for connector in factory.connectors:
+                               # Stop any other connections
+                               try:
+                                       connector.stopConnecting()
+                               except error.NotConnectingError:
+                                       pass
+
+                       iq = Element((None, "iq"))
+                       iq["type"] = "result"
+                       iq["from"] = toj.full()
+                       iq["to"] = froj.full()
+                       iq["id"] = ID
+                       query = iq.addElement("query")
+                       query["xmlns"] = disco.S5B
+                       streamhost = query.addElement("streamhost-used")
+                       streamhost["jid"] = jid
+                       self.pytrans.send(iq)
+
+
+               # Try the streamhosts
+               factory = protocol.ClientFactory()
+               factory.protocol = ft.JEP65ConnectionSend
+               factory.consumer = consumer
+               factory.hash = utils.socks5Hash(sid, froj.full(), toj.full())
+               factory.madeConnection = gotStreamhost
+               factory.connectors = []
+               for streamhost in streamhosts:
+                       factory.connectors.append(reactor.connectTCP(streamhost[1], streamhost[2], factory))
+