Mercurial > libervia-backend
annotate plugins/plugin_xep_0065.py @ 48:4392f1fdb064
plugins improvement
- new protocols field in plugins info, useful to know which ones are implemented by the plugin
- XEP-0153 first implementation (vcard avatars)
- plugin vcard: avatar & nick cached, clients are noticed of updated values
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 06 Jan 2010 23:56:44 +1100 |
parents | 3e24753b9e0b |
children | a5b5fb5fc9fd |
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", | |
48 | 86 "protocols": ["XEP-0065"], |
0 | 87 "main": "XEP_0065", |
9 | 88 "description": """Implementation of SOCKS5 Bytestreams""" |
0 | 89 } |
90 | |
91 STATE_INITIAL = 0 | |
92 STATE_AUTH = 1 | |
93 STATE_REQUEST = 2 | |
94 STATE_READY = 3 | |
95 STATE_AUTH_USERPASS = 4 | |
96 STATE_TARGET_INITIAL = 5 | |
97 STATE_TARGET_AUTH = 6 | |
98 STATE_TARGET_REQUEST = 7 | |
99 STATE_TARGET_READY = 8 | |
100 STATE_LAST = 9 | |
101 | |
102 STATE_CONNECT_PENDING = STATE_LAST + 1 | |
103 | |
104 SOCKS5_VER = 0x05 | |
105 | |
106 ADDR_IPV4 = 0x01 | |
107 ADDR_DOMAINNAME = 0x03 | |
108 ADDR_IPV6 = 0x04 | |
109 | |
110 CMD_CONNECT = 0x01 | |
111 CMD_BIND = 0x02 | |
112 CMD_UDPASSOC = 0x03 | |
113 | |
114 AUTHMECH_ANON = 0x00 | |
115 AUTHMECH_USERPASS = 0x02 | |
116 AUTHMECH_INVALID = 0xFF | |
117 | |
118 REPLY_SUCCESS = 0x00 | |
119 REPLY_GENERAL_FAILUR = 0x01 | |
120 REPLY_CONN_NOT_ALLOWED = 0x02 | |
121 REPLY_NETWORK_UNREACHABLE = 0x03 | |
122 REPLY_HOST_UNREACHABLE = 0x04 | |
123 REPLY_CONN_REFUSED = 0x05 | |
124 REPLY_TTL_EXPIRED = 0x06 | |
125 REPLY_CMD_NOT_SUPPORTED = 0x07 | |
126 REPLY_ADDR_NOT_SUPPORTED = 0x08 | |
127 | |
128 | |
129 | |
130 | |
131 | |
132 class SOCKSv5(protocol.Protocol, FileSender): | |
133 def __init__(self): | |
134 debug("Protocol init") | |
135 self.state = STATE_INITIAL | |
136 self.buf = "" | |
137 self.supportedAuthMechs = [ AUTHMECH_ANON ] | |
138 self.supportedAddrs = [ ADDR_DOMAINNAME ] | |
139 self.enabledCommands = [ CMD_CONNECT ] | |
140 self.peersock = None | |
141 self.addressType = 0 | |
142 self.requestType = 0 | |
143 self.activeConns = {} | |
144 self.pendingConns = {} | |
145 self.transfered = 0 #nb of bytes already copied | |
146 | |
147 def _startNegotiation(self): | |
148 debug("_startNegotiation") | |
149 self.state = STATE_TARGET_AUTH | |
150 self.transport.write(struct.pack('!3B', SOCKS5_VER, 1, AUTHMECH_ANON)) | |
151 | |
152 def _parseNegotiation(self): | |
153 debug("_parseNegotiation") | |
154 try: | |
155 # Parse out data | |
156 ver, nmethod = struct.unpack('!BB', self.buf[:2]) | |
157 methods = struct.unpack('%dB' % nmethod, self.buf[2:nmethod+2]) | |
158 | |
159 # Ensure version is correct | |
160 if ver != 5: | |
161 self.transport.write(struct.pack('!BB', SOCKS5_VER, AUTHMECH_INVALID)) | |
162 self.transport.loseConnection() | |
163 return | |
164 | |
165 # Trim off front of the buffer | |
166 self.buf = self.buf[nmethod+2:] | |
167 | |
168 # Check for supported auth mechs | |
169 for m in self.supportedAuthMechs: | |
170 if m in methods: | |
171 # Update internal state, according to selected method | |
172 if m == AUTHMECH_ANON: | |
173 self.state = STATE_REQUEST | |
174 elif m == AUTHMECH_USERPASS: | |
175 self.state = STATE_AUTH_USERPASS | |
176 # Complete negotiation w/ this method | |
177 self.transport.write(struct.pack('!BB', SOCKS5_VER, m)) | |
178 return | |
179 | |
180 # No supported mechs found, notify client and close the connection | |
181 self.transport.write(struct.pack('!BB', SOCKS5_VER, AUTHMECH_INVALID)) | |
182 self.transport.loseConnection() | |
183 except struct.error: | |
184 pass | |
185 | |
186 def _parseUserPass(self): | |
187 debug("_parseUserPass") | |
188 try: | |
189 # Parse out data | |
190 ver, ulen = struct.unpack('BB', self.buf[:2]) | |
191 uname, = struct.unpack('%ds' % ulen, self.buf[2:ulen + 2]) | |
192 plen, = struct.unpack('B', self.buf[ulen + 2]) | |
193 password, = struct.unpack('%ds' % plen, self.buf[ulen + 3:ulen + 3 + plen]) | |
194 # Trim off fron of the buffer | |
195 self.buf = self.buf[3 + ulen + plen:] | |
196 # Fire event to authenticate user | |
197 if self.authenticateUserPass(uname, password): | |
198 # Signal success | |
199 self.state = STATE_REQUEST | |
200 self.transport.write(struct.pack('!BB', SOCKS5_VER, 0x00)) | |
201 else: | |
202 # Signal failure | |
203 self.transport.write(struct.pack('!BB', SOCKS5_VER, 0x01)) | |
204 self.transport.loseConnection() | |
205 except struct.error: | |
206 pass | |
207 | |
208 def sendErrorReply(self, errorcode): | |
209 debug("sendErrorReply") | |
210 # Any other address types are not supported | |
211 result = struct.pack('!BBBBIH', SOCKS5_VER, errorcode, 0, 1, 0, 0) | |
212 self.transport.write(result) | |
213 self.transport.loseConnection() | |
214 | |
215 def addConnection(self, address, connection): | |
216 info("Adding connection: %s, %s", address, connection) | |
217 olist = self.pendingConns.get(address, []) | |
218 if len(olist) <= 1: | |
219 olist.append(connection) | |
220 self.pendingConns[address] = olist | |
221 return True | |
222 else: | |
223 return False | |
224 | |
225 def removePendingConnection(self, address, connection): | |
226 olist = self.pendingConns[address] | |
227 if len(olist) == 1: | |
228 del self.pendingConns[address] | |
229 else: | |
230 olist.remove(connection) | |
231 self.pendingConns[address] = olist | |
232 | |
233 def removeActiveConnection(self, address): | |
234 del self.activeConns[address] | |
235 | |
236 def _parseRequest(self): | |
237 debug("_parseRequest") | |
238 try: | |
239 # Parse out data and trim buffer accordingly | |
240 ver, cmd, rsvd, self.addressType = struct.unpack('!BBBB', self.buf[:4]) | |
241 | |
242 # Ensure we actually support the requested address type | |
243 if self.addressType not in self.supportedAddrs: | |
244 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
245 return | |
246 | |
247 # Deal with addresses | |
248 if self.addressType == ADDR_IPV4: | |
249 addr, port = struct.unpack('!IH', self.buf[4:10]) | |
250 self.buf = self.buf[10:] | |
251 elif self.addressType == ADDR_DOMAINNAME: | |
252 nlen = ord(self.buf[4]) | |
253 addr, port = struct.unpack('!%dsH' % nlen, self.buf[5:]) | |
254 self.buf = self.buf[7 + len(addr):] | |
255 else: | |
256 # Any other address types are not supported | |
257 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
258 return | |
259 | |
260 # Ensure command is supported | |
261 if cmd not in self.enabledCommands: | |
262 # Send a not supported error | |
263 self.sendErrorReply(REPLY_CMD_NOT_SUPPORTED) | |
264 return | |
265 | |
266 # Process the command | |
267 if cmd == CMD_CONNECT: | |
268 self.connectRequested(addr, port) | |
269 elif cmd == CMD_BIND: | |
270 self.bindRequested(addr, port) | |
271 else: | |
272 # Any other command is not supported | |
273 self.sendErrorReply(REPLY_CMD_NOT_SUPPORTED) | |
274 | |
275 except struct.error, why: | |
276 return None | |
277 | |
278 def _makeRequest(self): | |
279 debug("_makeRequest") | |
280 self.state = STATE_TARGET_REQUEST | |
281 sha1 = hashlib.sha1(self.sid + self.initiator_jid + self.target_jid).hexdigest() | |
282 request = struct.pack('!5B%dsH' % len(sha1), SOCKS5_VER, CMD_CONNECT, 0, ADDR_DOMAINNAME, len(sha1), sha1, 0) | |
283 self.transport.write(request) | |
284 | |
285 def _parseRequestReply(self): | |
286 debug("_parseRequestReply") | |
287 try: | |
288 ver, rep, rsvd, self.addressType = struct.unpack('!BBBB', self.buf[:4]) | |
289 # Ensure we actually support the requested address type | |
290 if self.addressType not in self.supportedAddrs: | |
291 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
292 return | |
293 | |
294 # Deal with addresses | |
295 if self.addressType == ADDR_IPV4: | |
296 addr, port = struct.unpack('!IH', self.buf[4:10]) | |
297 self.buf = self.buf[10:] | |
298 elif self.addressType == ADDR_DOMAINNAME: | |
299 nlen = ord(self.buf[4]) | |
300 addr, port = struct.unpack('!%dsH' % nlen, self.buf[5:]) | |
301 self.buf = self.buf[7 + len(addr):] | |
302 else: | |
303 # Any other address types are not supported | |
304 self.sendErrorReply(REPLY_ADDR_NOT_SUPPORTED) | |
305 return | |
306 | |
307 # Ensure reply is OK | |
308 if rep != REPLY_SUCCESS: | |
309 self.loseConnection() | |
310 return | |
311 | |
312 debug("Saving file in %s.", self.data["dest_path"]) | |
313 self.dest_file = open(self.data["dest_path"], 'w') | |
314 self.state = STATE_TARGET_READY | |
315 self.activateCB(self.target_jid, self.initiator_jid, self.sid, self.IQ_id) | |
316 | |
317 | |
318 except struct.error, why: | |
319 return None | |
320 | |
321 def connectionMade(self): | |
322 debug("connectionMade (mode = %s)" % self.mode) | |
323 self.host.registerProgressCB(self.transfert_id, self.getProgress) | |
324 | |
325 if self.mode == "target": | |
326 self.state = STATE_TARGET_INITIAL | |
327 self._startNegotiation() | |
328 | |
329 def connectRequested(self, addr, port): | |
330 debug(("connectRequested")) | |
331 # Check for special connect to the namespace -- this signifies that the client | |
332 # is just checking to ensure it can connect to the streamhost | |
333 if addr == "http://jabber.org/protocol/bytestreams": | |
334 self.connectCompleted(addr, 0) | |
335 self.transport.loseConnection() | |
336 return | |
337 | |
338 # Save addr, for cleanup | |
339 self.addr = addr | |
340 | |
341 # Check to see if the requested address is already | |
342 # activated -- send an error if so | |
343 if addr in self.activeConns: | |
344 self.sendErrorReply(socks5.REPLY_CONN_NOT_ALLOWED) | |
345 return | |
346 | |
347 # Add this address to the pending connections | |
348 if self.addConnection(addr, self): | |
349 self.connectCompleted(addr, 0) | |
350 self.transport.stopReading() | |
351 else: | |
352 self.sendErrorReply(socks5.REPLY_CONN_REFUSED) | |
353 | |
354 def getProgress(self, data): | |
355 """Fill data with position of current transfert""" | |
356 data["size"] = self.filesize | |
357 try: | |
358 data["position"] = str(self.dest_file.tell()) | |
359 except (ValueError, AttributeError): | |
360 data["position"] = "" | |
361 | |
362 def fileTransfered(self, d): | |
363 info("File transfer completed, closing connection") | |
364 self.transport.loseConnection() | |
365 | |
366 def updateTransfered(self, data): | |
367 self.transfered+=len(data) | |
368 return data | |
369 | |
370 def connectCompleted(self, remotehost, remoteport): | |
371 debug("connectCompleted") | |
372 if self.addressType == ADDR_IPV4: | |
373 result = struct.pack('!BBBBIH', SOCKS5_VER, REPLY_SUCCESS, 0, 1, remotehost, remoteport) | |
374 elif self.addressType == ADDR_DOMAINNAME: | |
375 result = struct.pack('!BBBBB%dsH' % len(remotehost), SOCKS5_VER, REPLY_SUCCESS, 0, | |
376 ADDR_DOMAINNAME, len(remotehost), remotehost, remoteport) | |
377 self.transport.write(result) | |
378 self.state = STATE_READY | |
379 self.dest_file=open(self.filepath) | |
380 d=self.beginFileTransfer(self.dest_file, self.transport, self.updateTransfered) | |
381 d.addCallback(self.fileTransfered) | |
382 | |
383 def bindRequested(self, addr, port): | |
384 pass | |
385 | |
386 def authenticateUserPass(self, user, passwd): | |
387 debug("User/pass: %s/%s", user, passwd) | |
388 return True | |
389 | |
390 def dataReceived(self, buf): | |
391 if self.state == STATE_TARGET_READY: | |
392 self.dest_file.write(buf) | |
393 self.transfered+=len(buf) | |
394 return | |
395 | |
396 self.buf = self.buf + buf | |
397 if self.state == STATE_INITIAL: | |
398 self._parseNegotiation() | |
399 if self.state == STATE_AUTH_USERPASS: | |
400 self._parseUserPass() | |
401 if self.state == STATE_REQUEST: | |
402 self._parseRequest() | |
403 if self.state == STATE_TARGET_AUTH: | |
404 ver, method = struct.unpack('!BB', buf) | |
405 self.buf = self.buf[2:] | |
406 if ver!=SOCKS5_VER or method!=AUTHMECH_ANON: | |
407 self.transport.loseConnection() | |
408 else: | |
409 self._makeRequest() | |
410 if self.state == STATE_TARGET_REQUEST: | |
411 self._parseRequestReply() | |
412 | |
413 | |
414 def clientConnectionLost(self, reason): | |
415 debug("clientConnectionLost") | |
416 self.transport.loseConnection() | |
417 | |
418 def connectionLost(self, reason): | |
419 debug("connectionLost") | |
420 self.host.removeProgressCB(self.transfert_id) | |
421 if self.state == STATE_CONNECT_PENDING: | |
422 self.removePendingConnection(self.addr, self) | |
423 else: | |
424 self.transport.unregisterProducer() | |
425 if self.peersock != None: | |
426 self.peersock.peersock = None | |
427 self.peersock.transport.unregisterProducer() | |
428 self.peersock = None | |
429 self.removeActiveConnection(self.addr) | |
430 | |
431 class Socks5ServerFactory(protocol.ServerFactory): | |
432 protocol = SOCKSv5 | |
433 protocol.mode = "initiator" #FIXME: Q&D way, fix it | |
434 | |
435 | |
436 def startedConnecting(self, connector): | |
437 debug ("Socks 5 server connection started") | |
438 | |
439 def clientConnectionLost(self, connector, reason): | |
440 debug ("Socks 5 server connection lost (reason: %s)", reason) | |
441 | |
442 class Socks5ClientFactory(protocol.ClientFactory): | |
443 protocol = SOCKSv5 | |
444 protocol.mode = "target" #FIXME: Q&D way, fix it | |
445 | |
446 def startedConnecting(self, connector): | |
447 debug ("Socks 5 client connection started") | |
448 | |
449 def clientConnectionLost(self, connector, reason): | |
450 debug ("Socks 5 client connection lost (reason: %s)", reason) | |
451 | |
452 | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
453 class XEP_0065(XMPPHandler): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
454 implements(iwokkel.IDisco) |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
455 |
19
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 <params> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
458 <category name="File Transfert"> |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
459 <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
|
460 <param name="Port" value="28915" type="string" /> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
461 </category> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
462 </params> |
f2a745ca0fbc
refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
463 """ |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
464 |
0 | 465 def __init__(self, host): |
466 info("Plugin XEP_0065 initialization") | |
467 self.host = host | |
468 debug("registering") | |
469 self.server_factory = Socks5ServerFactory() | |
470 self.server_factory.protocol.host = self.host #needed for progress CB | |
471 self.client_factory = Socks5ClientFactory() | |
21
633c5ed65701
parameters: new button type (not finished)
Goffi <goffi@goffi.org>
parents:
20
diff
changeset
|
472 |
633c5ed65701
parameters: new button type (not finished)
Goffi <goffi@goffi.org>
parents:
20
diff
changeset
|
473 #parameters |
38 | 474 host.memory.importParams(XEP_0065.params) |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
475 host.memory.setDefault("IP", "File Transfert", self.getExternalIP) |
21
633c5ed65701
parameters: new button type (not finished)
Goffi <goffi@goffi.org>
parents:
20
diff
changeset
|
476 |
22
bb72c29f3432
added action cb mechanism for buttons. Tested with a temporary new user registration button.
Goffi <goffi@goffi.org>
parents:
21
diff
changeset
|
477 port = int(self.host.memory.getParamA("Port", "File Transfert")) |
0 | 478 info("Launching Socks5 Stream server on port %d", port) |
479 reactor.listenTCP(port, self.server_factory) | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
480 |
20
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
481 def getExternalIP(self): |
fc8c202cda87
refactoring: using xml params part IV (default values)
Goffi <goffi@goffi.org>
parents:
19
diff
changeset
|
482 """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
|
483 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
|
484 |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
485 def connectionInitialized(self): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
486 self.xmlstream.addObserver(BS_REQUEST, self.getFile) |
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 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
489 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
490 return [disco.DiscoFeature(NS_BS)] |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
491 |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
492 def getDiscoItems(self, requestor, target, nodeIdentifier=''): |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
493 return [] |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
494 |
0 | 495 |
496 def setData(self, data, id): | |
497 self.data = data | |
498 self.transfert_id = id | |
499 | |
500 def sendFile(self, id, filepath, size): | |
501 #lauching socks5 initiator | |
8 | 502 debug("Launching socks5 initiator") |
0 | 503 self.server_factory.protocol.mode = "initiator" |
504 self.server_factory.protocol.filepath = filepath | |
505 self.server_factory.protocol.filesize = size | |
506 self.server_factory.protocol.transfert_id = id | |
507 | |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
508 def getFile(self, iq): |
0 | 509 """Get file using byte stream""" |
15
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
510 iq.handled = True |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
511 SI_elem = iq.firstChildElement() |
218ec9984fa5
wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents:
9
diff
changeset
|
512 IQ_id = iq['id'] |
0 | 513 for element in SI_elem.elements(): |
514 if element.name == "streamhost": | |
515 info ("Stream proposed: host=[%s] port=[%s]", element['host'], element['port']) | |
516 factory = self.client_factory | |
517 self.server_factory.protocol.mode = "target" | |
518 factory.protocol.host = self.host #needed for progress CB | |
519 factory.protocol.data = self.data | |
520 factory.protocol.transfert_id = self.transfert_id | |
521 factory.protocol.filesize = self.data["size"] | |
522 factory.protocol.sid = SI_elem['sid'] | |
523 factory.protocol.initiator_jid = element['jid'] | |
524 factory.protocol.target_jid = self.host.me.full() | |
525 factory.protocol.IQ_id = IQ_id | |
526 factory.protocol.activateCB = self.activateStream | |
527 reactor.connectTCP(element['host'], int(element['port']), factory) | |
528 | |
529 def activateStream(self, from_jid, to_jid, sid, IQ_id): | |
530 debug("activating stream") | |
531 result = domish.Element(('', 'iq')) | |
532 result['type'] = 'result' | |
533 result['id'] = IQ_id | |
534 result['from'] = from_jid | |
535 result['to'] = to_jid | |
536 query = result.addElement('query', 'http://jabber.org/protocol/bytestreams') | |
537 query['sid'] = sid | |
538 streamhost = query.addElement('streamhost-used') | |
539 streamhost['jid'] = to_jid #FIXME: use real streamhost | |
540 self.host.xmlstream.send(result) | |
541 |