Mercurial > libervia-backend
annotate plugins/plugin_xep_0065.py @ 40:6f0699ba0329
plugin XEP-0077: minor log fix
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 19 Dec 2009 18:13:04 +1100 |
parents | 3e24753b9e0b |
children | 4392f1fdb064 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/python |
2 #-*- coding: utf-8 -*- | |
3 """ | |
4 SAT plugin for managing xep-0065 | |
5 | |
6 Copyright (C) | |
7 2002-2004 Dave Smith (dizzyd@jabber.org) | |
8 2007-2008 Fabio Forno (xmpp:ff@jabber.bluendo.com) | |
9 2009 Jérôme Poisson (goffi@goffi.org) | |
10 | |
11 This program is free software: you can redistribute it and/or modify | |
12 it under the terms of the GNU General Public License as published by | |
13 the Free Software Foundation, either version 3 of the License, or | |
14 (at your option) any later version. | |
15 | |
16 This program is distributed in the hope that it will be useful, | |
17 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 GNU General Public License for more details. | |
20 | |
21 You should have received a copy of the GNU General Public License | |
22 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
23 | |
24 -- | |
25 | |
26 This program is based on proxy65 (http://code.google.com/p/proxy65), | |
27 originaly written by David Smith and modified by Fabio Forno. | |
28 It is sublicensed under GPL v3 (or any later version) as allowed by the original | |
29 license. | |
30 | |
31 -- | |
32 | |
33 Here is a copy of the original license: | |
34 | |
35 Copyright (C) | |
36 2002-2004 Dave Smith (dizzyd@jabber.org) | |
37 2007-2008 Fabio Forno (xmpp:ff@jabber.bluendo.com) | |
38 | |
39 Permission is hereby granted, free of charge, to any person obtaining a copy | |
40 of this software and associated documentation files (the "Software"), to deal | |
41 in the Software without restriction, including without limitation the rights | |
42 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
43 copies of the Software, and to permit persons to whom the Software is | |
44 furnished to do so, subject to the following conditions: | |
45 | |
46 The above copyright notice and this permission notice shall be included in | |
47 all copies or substantial portions of the Software. | |
48 | |
49 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
50 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
51 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
52 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
53 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
54 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
55 THE SOFTWARE. | |
56 """ | |
57 | |
58 from logging import debug, info, error | |
59 from twisted.internet import protocol, reactor | |
60 from twisted.protocols.basic import FileSender | |
61 from twisted.words.xish import domish | |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
62 from twisted.web.client import getPage |
0 | 63 import struct |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
64 import urllib |
0 | 65 import hashlib, pdb |
66 | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
67 from zope.interface import implements |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
68 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
69 try: |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
70 from twisted.words.protocols.xmlstream import XMPPHandler |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
71 except ImportError: |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
72 from wokkel.subprotocols import XMPPHandler |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
73 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
74 from wokkel import disco, iwokkel |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
75 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
76 IQ_SET = '/iq[@type="set"]' |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
77 NS_BS = 'http://jabber.org/protocol/bytestreams' |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
78 BS_REQUEST = IQ_SET + '/query[@xmlns="' + NS_BS + '"]' |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
79 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
80 |
0 | 81 |
82 PLUGIN_INFO = { | |
83 "name": "XEP 0065 Plugin", | |
84 "import_name": "XEP_0065", | |
85 "type": "XEP", | |
86 "main": "XEP_0065", | |
9 | 87 "description": """Implementation of SOCKS5 Bytestreams""" |
0 | 88 } |
89 | |
90 STATE_INITIAL = 0 | |
91 STATE_AUTH = 1 | |
92 STATE_REQUEST = 2 | |
93 STATE_READY = 3 | |
94 STATE_AUTH_USERPASS = 4 | |
95 STATE_TARGET_INITIAL = 5 | |
96 STATE_TARGET_AUTH = 6 | |
97 STATE_TARGET_REQUEST = 7 | |
98 STATE_TARGET_READY = 8 | |
99 STATE_LAST = 9 | |
100 | |
101 STATE_CONNECT_PENDING = STATE_LAST + 1 | |
102 | |
103 SOCKS5_VER = 0x05 | |
104 | |
105 ADDR_IPV4 = 0x01 | |
106 ADDR_DOMAINNAME = 0x03 | |
107 ADDR_IPV6 = 0x04 | |
108 | |
109 CMD_CONNECT = 0x01 | |
110 CMD_BIND = 0x02 | |
111 CMD_UDPASSOC = 0x03 | |
112 | |
113 AUTHMECH_ANON = 0x00 | |
114 AUTHMECH_USERPASS = 0x02 | |
115 AUTHMECH_INVALID = 0xFF | |
116 | |
117 REPLY_SUCCESS = 0x00 | |
118 REPLY_GENERAL_FAILUR = 0x01 | |
119 REPLY_CONN_NOT_ALLOWED = 0x02 | |
120 REPLY_NETWORK_UNREACHABLE = 0x03 | |
121 REPLY_HOST_UNREACHABLE = 0x04 | |
122 REPLY_CONN_REFUSED = 0x05 | |
123 REPLY_TTL_EXPIRED = 0x06 | |
124 REPLY_CMD_NOT_SUPPORTED = 0x07 | |
125 REPLY_ADDR_NOT_SUPPORTED = 0x08 | |
126 | |
127 | |
128 | |
129 | |
130 | |
131 class SOCKSv5(protocol.Protocol, FileSender): | |
132 def __init__(self): | |
133 debug("Protocol init") | |
134 self.state = STATE_INITIAL | |
135 self.buf = "" | |
136 self.supportedAuthMechs = [ AUTHMECH_ANON ] | |
137 self.supportedAddrs = [ ADDR_DOMAINNAME ] | |
138 self.enabledCommands = [ CMD_CONNECT ] | |
139 self.peersock = None | |
140 self.addressType = 0 | |
141 self.requestType = 0 | |
142 self.activeConns = {} | |
143 self.pendingConns = {} | |
144 self.transfered = 0 #nb of bytes already copied | |
145 | |
146 def _startNegotiation(self): | |
147 debug("_startNegotiation") | |
148 self.state = STATE_TARGET_AUTH | |
149 self.transport.write(struct.pack('!3B', SOCKS5_VER, 1, AUTHMECH_ANON)) | |
150 | |
151 def _parseNegotiation(self): | |
152 debug("_parseNegotiation") | |
153 try: | |
154 # Parse out data | |
155 ver, nmethod = struct.unpack('!BB', self.buf[:2]) | |
156 methods = struct.unpack('%dB' % nmethod, self.buf[2:nmethod+2]) | |
157 | |
158 # Ensure version is correct | |
159 if ver != 5: | |
160 self.transport.write(struct.pack('!BB', SOCKS5_VER, AUTHMECH_INVALID)) | |
161 self.transport.loseConnection() | |
162 return | |
163 | |
164 # Trim off front of the buffer | |
165 self.buf = self.buf[nmethod+2:] | |
166 | |
167 # Check for supported auth mechs | |
168 for m in self.supportedAuthMechs: | |
169 if m in methods: | |
170 # Update internal state, according to selected method | |
171 if m == AUTHMECH_ANON: | |
172 self.state = STATE_REQUEST | |
173 elif m == AUTHMECH_USERPASS: | |
174 self.state = STATE_AUTH_USERPASS | |
175 # Complete negotiation w/ this method | |
176 self.transport.write(struct.pack('!BB', SOCKS5_VER, m)) | |
177 return | |
178 | |
179 # No supported mechs found, notify client and close the connection | |
180 self.transport.write(struct.pack('!BB', SOCKS5_VER, AUTHMECH_INVALID)) | |
181 self.transport.loseConnection() | |
182 except struct.error: | |
183 pass | |
184 | |
185 def _parseUserPass(self): | |
186 debug("_parseUserPass") | |
187 try: | |
188 # Parse out data | |
189 ver, ulen = struct.unpack('BB', self.buf[:2]) | |
190 uname, = struct.unpack('%ds' % ulen, self.buf[2:ulen + 2]) | |
191 plen, = struct.unpack('B', self.buf[ulen + 2]) | |
192 password, = struct.unpack('%ds' % plen, self.buf[ulen + 3:ulen + 3 + plen]) | |
193 # Trim off fron of the buffer | |
194 self.buf = self.buf[3 + ulen + plen:] | |
195 # Fire event to authenticate user | |
196 if self.authenticateUserPass(uname, password): | |
197 # Signal success | |
198 self.state = STATE_REQUEST | |
199 self.transport.write(struct.pack('!BB', SOCKS5_VER, 0x00)) | |
200 else: | |
201 # Signal failure | |
202 self.transport.write(struct.pack('!BB', SOCKS5_VER, 0x01)) | |
203 self.transport.loseConnection() | |
204 except struct.error: | |
205 pass | |
206 | |
207 def sendErrorReply(self, errorcode): | |
208 debug("sendErrorReply") | |
209 # Any other address types are not supported | |
210 result = struct.pack('!BBBBIH', SOCKS5_VER, errorcode, 0, 1, 0, 0) | |
211 self.transport.write(result) | |
212 self.transport.loseConnection() | |
213 | |
214 def addConnection(self, address, connection): | |
215 info("Adding connection: %s, %s", address, connection) | |
216 olist = self.pendingConns.get(address, []) | |
217 if len(olist) <= 1: | |
218 olist.append(connection) | |
219 self.pendingConns[address] = olist | |
220 return True | |
221 else: | |
222 return False | |
223 | |
224 def removePendingConnection(self, address, connection): | |
225 olist = self.pendingConns[address] | |
226 if len(olist) == 1: | |
227 del self.pendingConns[address] | |
228 else: | |
229 olist.remove(connection) | |
230 self.pendingConns[address] = olist | |
231 | |
232 def removeActiveConnection(self, address): | |
233 del self.activeConns[address] | |
234 | |
235 def _parseRequest(self): | |
236 debug("_parseRequest") | |
237 try: | |
238 # Parse out data and trim buffer accordingly | |
239 ver, cmd, rsvd, self.addressType = struct.unpack('!BBBB', self.buf[:4]) | |
240 | |
241 # Ensure we actually support the requested address type | |
242 if self.addressType not in self.supportedAddrs: | |
243 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
244 return | |
245 | |
246 # Deal with addresses | |
247 if self.addressType == ADDR_IPV4: | |
248 addr, port = struct.unpack('!IH', self.buf[4:10]) | |
249 self.buf = self.buf[10:] | |
250 elif self.addressType == ADDR_DOMAINNAME: | |
251 nlen = ord(self.buf[4]) | |
252 addr, port = struct.unpack('!%dsH' % nlen, self.buf[5:]) | |
253 self.buf = self.buf[7 + len(addr):] | |
254 else: | |
255 # Any other address types are not supported | |
256 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
257 return | |
258 | |
259 # Ensure command is supported | |
260 if cmd not in self.enabledCommands: | |
261 # Send a not supported error | |
262 self.sendErrorReply(REPLY_CMD_NOT_SUPPORTED) | |
263 return | |
264 | |
265 # Process the command | |
266 if cmd == CMD_CONNECT: | |
267 self.connectRequested(addr, port) | |
268 elif cmd == CMD_BIND: | |
269 self.bindRequested(addr, port) | |
270 else: | |
271 # Any other command is not supported | |
272 self.sendErrorReply(REPLY_CMD_NOT_SUPPORTED) | |
273 | |
274 except struct.error, why: | |
275 return None | |
276 | |
277 def _makeRequest(self): | |
278 debug("_makeRequest") | |
279 self.state = STATE_TARGET_REQUEST | |
280 sha1 = hashlib.sha1(self.sid + self.initiator_jid + self.target_jid).hexdigest() | |
281 request = struct.pack('!5B%dsH' % len(sha1), SOCKS5_VER, CMD_CONNECT, 0, ADDR_DOMAINNAME, len(sha1), sha1, 0) | |
282 self.transport.write(request) | |
283 | |
284 def _parseRequestReply(self): | |
285 debug("_parseRequestReply") | |
286 try: | |
287 ver, rep, rsvd, self.addressType = struct.unpack('!BBBB', self.buf[:4]) | |
288 # Ensure we actually support the requested address type | |
289 if self.addressType not in self.supportedAddrs: | |
290 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
291 return | |
292 | |
293 # Deal with addresses | |
294 if self.addressType == ADDR_IPV4: | |
295 addr, port = struct.unpack('!IH', self.buf[4:10]) | |
296 self.buf = self.buf[10:] | |
297 elif self.addressType == ADDR_DOMAINNAME: | |
298 nlen = ord(self.buf[4]) | |
299 addr, port = struct.unpack('!%dsH' % nlen, self.buf[5:]) | |
300 self.buf = self.buf[7 + len(addr):] | |
301 else: | |
302 # Any other address types are not supported | |
303 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
304 return | |
305 | |
306 # Ensure reply is OK | |
307 if rep != REPLY_SUCCESS: | |
308 self.loseConnection() | |
309 return | |
310 | |
311 debug("Saving file in %s.", self.data["dest_path"]) | |
312 self.dest_file = open(self.data["dest_path"], 'w') | |
313 self.state = STATE_TARGET_READY | |
314 self.activateCB(self.target_jid, self.initiator_jid, self.sid, self.IQ_id) | |
315 | |
316 | |
317 except struct.error, why: | |
318 return None | |
319 | |
320 def connectionMade(self): | |
321 debug("connectionMade (mode = %s)" % self.mode) | |
322 self.host.registerProgressCB(self.transfert_id, self.getProgress) | |
323 | |
324 if self.mode == "target": | |
325 self.state = STATE_TARGET_INITIAL | |
326 self._startNegotiation() | |
327 | |
328 def connectRequested(self, addr, port): | |
329 debug(("connectRequested")) | |
330 # Check for special connect to the namespace -- this signifies that the client | |
331 # is just checking to ensure it can connect to the streamhost | |
332 if addr == "http://jabber.org/protocol/bytestreams": | |
333 self.connectCompleted(addr, 0) | |
334 self.transport.loseConnection() | |
335 return | |
336 | |
337 # Save addr, for cleanup | |
338 self.addr = addr | |
339 | |
340 # Check to see if the requested address is already | |
341 # activated -- send an error if so | |
342 if addr in self.activeConns: | |
343 self.sendErrorReply(socks5.REPLY_CONN_NOT_ALLOWED) | |
344 return | |
345 | |
346 # Add this address to the pending connections | |
347 if self.addConnection(addr, self): | |
348 self.connectCompleted(addr, 0) | |
349 self.transport.stopReading() | |
350 else: | |
351 self.sendErrorReply(socks5.REPLY_CONN_REFUSED) | |
352 | |
353 def getProgress(self, data): | |
354 """Fill data with position of current transfert""" | |
355 data["size"] = self.filesize | |
356 try: | |
357 data["position"] = str(self.dest_file.tell()) | |
358 except (ValueError, AttributeError): | |
359 data["position"] = "" | |
360 | |
361 def fileTransfered(self, d): | |
362 info("File transfer completed, closing connection") | |
363 self.transport.loseConnection() | |
364 | |
365 def updateTransfered(self, data): | |
366 self.transfered+=len(data) | |
367 return data | |
368 | |
369 def connectCompleted(self, remotehost, remoteport): | |
370 debug("connectCompleted") | |
371 if self.addressType == ADDR_IPV4: | |
372 result = struct.pack('!BBBBIH', SOCKS5_VER, REPLY_SUCCESS, 0, 1, remotehost, remoteport) | |
373 elif self.addressType == ADDR_DOMAINNAME: | |
374 result = struct.pack('!BBBBB%dsH' % len(remotehost), SOCKS5_VER, REPLY_SUCCESS, 0, | |
375 ADDR_DOMAINNAME, len(remotehost), remotehost, remoteport) | |
376 self.transport.write(result) | |
377 self.state = STATE_READY | |
378 self.dest_file=open(self.filepath) | |
379 d=self.beginFileTransfer(self.dest_file, self.transport, self.updateTransfered) | |
380 d.addCallback(self.fileTransfered) | |
381 | |
382 def bindRequested(self, addr, port): | |
383 pass | |
384 | |
385 def authenticateUserPass(self, user, passwd): | |
386 debug("User/pass: %s/%s", user, passwd) | |
387 return True | |
388 | |
389 def dataReceived(self, buf): | |
390 if self.state == STATE_TARGET_READY: | |
391 self.dest_file.write(buf) | |
392 self.transfered+=len(buf) | |
393 return | |
394 | |
395 self.buf = self.buf + buf | |
396 if self.state == STATE_INITIAL: | |
397 self._parseNegotiation() | |
398 if self.state == STATE_AUTH_USERPASS: | |
399 self._parseUserPass() | |
400 if self.state == STATE_REQUEST: | |
401 self._parseRequest() | |
402 if self.state == STATE_TARGET_AUTH: | |
403 ver, method = struct.unpack('!BB', buf) | |
404 self.buf = self.buf[2:] | |
405 if ver!=SOCKS5_VER or method!=AUTHMECH_ANON: | |
406 self.transport.loseConnection() | |
407 else: | |
408 self._makeRequest() | |
409 if self.state == STATE_TARGET_REQUEST: | |
410 self._parseRequestReply() | |
411 | |
412 | |
413 def clientConnectionLost(self, reason): | |
414 debug("clientConnectionLost") | |
415 self.transport.loseConnection() | |
416 | |
417 def connectionLost(self, reason): | |
418 debug("connectionLost") | |
419 self.host.removeProgressCB(self.transfert_id) | |
420 if self.state == STATE_CONNECT_PENDING: | |
421 self.removePendingConnection(self.addr, self) | |
422 else: | |
423 self.transport.unregisterProducer() | |
424 if self.peersock != None: | |
425 self.peersock.peersock = None | |
426 self.peersock.transport.unregisterProducer() | |
427 self.peersock = None | |
428 self.removeActiveConnection(self.addr) | |
429 | |
430 class Socks5ServerFactory(protocol.ServerFactory): | |
431 protocol = SOCKSv5 | |
432 protocol.mode = "initiator" #FIXME: Q&D way, fix it | |
433 | |
434 | |
435 def startedConnecting(self, connector): | |
436 debug ("Socks 5 server connection started") | |
437 | |
438 def clientConnectionLost(self, connector, reason): | |
439 debug ("Socks 5 server connection lost (reason: %s)", reason) | |
440 | |
441 class Socks5ClientFactory(protocol.ClientFactory): | |
442 protocol = SOCKSv5 | |
443 protocol.mode = "target" #FIXME: Q&D way, fix it | |
444 | |
445 def startedConnecting(self, connector): | |
446 debug ("Socks 5 client connection started") | |
447 | |
448 def clientConnectionLost(self, connector, reason): | |
449 debug ("Socks 5 client connection lost (reason: %s)", reason) | |
450 | |
451 | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
452 class XEP_0065(XMPPHandler): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
453 implements(iwokkel.IDisco) |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
454 |
19
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
455 params = """ |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
456 <params> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
457 <category name="File Transfert"> |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
458 <param name="IP" value='0.0.0.0' default_cb='yes' type="string" /> |
19
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
459 <param name="Port" value="28915" type="string" /> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
460 </category> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
461 </params> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
462 """ |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
463 |
0 | 464 def __init__(self, host): |
465 info("Plugin XEP_0065 initialization") | |
466 self.host = host | |
467 debug("registering") | |
468 self.server_factory = Socks5ServerFactory() | |
469 self.server_factory.protocol.host = self.host #needed for progress CB | |
470 self.client_factory = Socks5ClientFactory() | |
21
633c5ed65701
parameters: new button type (not finished)
Goffi <goffi@goffi.org>
parents:
20
diff
changeset
|
471 |
633c5ed65701
parameters: new button type (not finished)
Goffi <goffi@goffi.org>
parents:
20
diff
changeset
|
472 #parameters |
38 | 473 host.memory.importParams(XEP_0065.params) |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
474 host.memory.setDefault("IP", "File Transfert", self.getExternalIP) |
21
633c5ed65701
parameters: new button type (not finished)
Goffi <goffi@goffi.org>
parents:
20
diff
changeset
|
475 |
22
bb72c29f3432
added action cb mechanism for buttons. Tested with a temporary new user registration button.
Goffi <goffi@goffi.org>
parents:
21
diff
changeset
|
476 port = int(self.host.memory.getParamA("Port", "File Transfert")) |
0 | 477 info("Launching Socks5 Stream server on port %d", port) |
478 reactor.listenTCP(port, self.server_factory) | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
479 |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
480 def getExternalIP(self): |
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
481 """Return IP visible from outside, by asking to a website""" |
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
482 return getPage("http://www.goffi.org/sat_tools/get_ip.php") |
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
483 |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
484 def connectionInitialized(self): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
485 self.xmlstream.addObserver(BS_REQUEST, self.getFile) |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
486 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
487 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
488 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
489 return [disco.DiscoFeature(NS_BS)] |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
490 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
491 def getDiscoItems(self, requestor, target, nodeIdentifier=''): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
492 return [] |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
493 |
0 | 494 |
495 def setData(self, data, id): | |
496 self.data = data | |
497 self.transfert_id = id | |
498 | |
499 def sendFile(self, id, filepath, size): | |
500 #lauching socks5 initiator | |
8 | 501 debug("Launching socks5 initiator") |
0 | 502 self.server_factory.protocol.mode = "initiator" |
503 self.server_factory.protocol.filepath = filepath | |
504 self.server_factory.protocol.filesize = size | |
505 self.server_factory.protocol.transfert_id = id | |
506 | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
507 def getFile(self, iq): |
0 | 508 """Get file using byte stream""" |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
509 iq.handled = True |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
510 SI_elem = iq.firstChildElement() |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
511 IQ_id = iq['id'] |
0 | 512 for element in SI_elem.elements(): |
513 if element.name == "streamhost": | |
514 info ("Stream proposed: host=[%s] port=[%s]", element['host'], element['port']) | |
515 factory = self.client_factory | |
516 self.server_factory.protocol.mode = "target" | |
517 factory.protocol.host = self.host #needed for progress CB | |
518 factory.protocol.data = self.data | |
519 factory.protocol.transfert_id = self.transfert_id | |
520 factory.protocol.filesize = self.data["size"] | |
521 factory.protocol.sid = SI_elem['sid'] | |
522 factory.protocol.initiator_jid = element['jid'] | |
523 factory.protocol.target_jid = self.host.me.full() | |
524 factory.protocol.IQ_id = IQ_id | |
525 factory.protocol.activateCB = self.activateStream | |
526 reactor.connectTCP(element['host'], int(element['port']), factory) | |
527 | |
528 def activateStream(self, from_jid, to_jid, sid, IQ_id): | |
529 debug("activating stream") | |
530 result = domish.Element(('', 'iq')) | |
531 result['type'] = 'result' | |
532 result['id'] = IQ_id | |
533 result['from'] = from_jid | |
534 result['to'] = to_jid | |
535 query = result.addElement('query', 'http://jabber.org/protocol/bytestreams') | |
536 query['sid'] = sid | |
537 streamhost = query.addElement('streamhost-used') | |
538 streamhost['jid'] = to_jid #FIXME: use real streamhost | |
539 self.host.xmlstream.send(result) | |
540 |