annotate src/plugins/plugin_xep_0096.py @ 297:c5554e2939dd

plugin XEP 0277: author for in request + author, updated management for out request - a workaround is now used to parse "nick" tag (Jappix behaviour) - author and updated can now be used in data when sendind microblog. Is no author is given, user jid is used, if no updated is given, current timestamp is used
author Goffi <goffi@goffi.org>
date Fri, 18 Feb 2011 22:32:02 +0100
parents 7c79d4a8c9e6
children f964dcec1611
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
goffi@necton2
parents:
diff changeset
1 #!/usr/bin/python
goffi@necton2
parents:
diff changeset
2 # -*- coding: utf-8 -*-
goffi@necton2
parents:
diff changeset
3
goffi@necton2
parents:
diff changeset
4 """
goffi@necton2
parents:
diff changeset
5 SAT plugin for managing xep-0096
228
b1794cbb88e5 2011 copyright upgrade
Goffi <goffi@goffi.org>
parents: 223
diff changeset
6 Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org)
0
goffi@necton2
parents:
diff changeset
7
goffi@necton2
parents:
diff changeset
8 This program is free software: you can redistribute it and/or modify
goffi@necton2
parents:
diff changeset
9 it under the terms of the GNU General Public License as published by
goffi@necton2
parents:
diff changeset
10 the Free Software Foundation, either version 3 of the License, or
goffi@necton2
parents:
diff changeset
11 (at your option) any later version.
goffi@necton2
parents:
diff changeset
12
goffi@necton2
parents:
diff changeset
13 This program is distributed in the hope that it will be useful,
goffi@necton2
parents:
diff changeset
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
goffi@necton2
parents:
diff changeset
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
goffi@necton2
parents:
diff changeset
16 GNU General Public License for more details.
goffi@necton2
parents:
diff changeset
17
goffi@necton2
parents:
diff changeset
18 You should have received a copy of the GNU General Public License
goffi@necton2
parents:
diff changeset
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
goffi@necton2
parents:
diff changeset
20 """
goffi@necton2
parents:
diff changeset
21
goffi@necton2
parents:
diff changeset
22 from logging import debug, info, error
goffi@necton2
parents:
diff changeset
23 from twisted.words.xish import domish
goffi@necton2
parents:
diff changeset
24 from twisted.internet import protocol
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
25 from twisted.words.protocols.jabber import client, jid
39
2e3411a6baad Wix: external server management in gateways manager, SàT: bug fixes in gateway management
Goffi <goffi@goffi.org>
parents: 22
diff changeset
26 from twisted.words.protocols.jabber import error as jab_error
0
goffi@necton2
parents:
diff changeset
27 import os.path
goffi@necton2
parents:
diff changeset
28 from twisted.internet import reactor #FIXME best way ???
1
a06a151fc31f Disconnect first draft
Goffi <goffi@goffi.org>
parents: 0
diff changeset
29 import pdb
0
goffi@necton2
parents:
diff changeset
30
15
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
31 from zope.interface import implements
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
32
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
33 try:
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
34 from twisted.words.protocols.xmlstream import XMPPHandler
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
35 except ImportError:
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
36 from wokkel.subprotocols import XMPPHandler
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
37
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
38 from wokkel import disco, iwokkel
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
39
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
40 IQ_SET = '/iq[@type="set"]'
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
41 NS_SI = 'http://jabber.org/protocol/si'
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
42 SI_REQUEST = IQ_SET + '/si[@xmlns="' + NS_SI + '"]'
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
43
0
goffi@necton2
parents:
diff changeset
44 PLUGIN_INFO = {
goffi@necton2
parents:
diff changeset
45 "name": "XEP 0096 Plugin",
291
7c79d4a8c9e6 plugins: fixed bad import names
Goffi <goffi@goffi.org>
parents: 228
diff changeset
46 "import_name": "XEP-0096",
0
goffi@necton2
parents:
diff changeset
47 "type": "XEP",
48
4392f1fdb064 plugins improvement
Goffi <goffi@goffi.org>
parents: 39
diff changeset
48 "protocols": ["XEP-0096"],
291
7c79d4a8c9e6 plugins: fixed bad import names
Goffi <goffi@goffi.org>
parents: 228
diff changeset
49 "dependencies": ["XEP-0065"],
0
goffi@necton2
parents:
diff changeset
50 "main": "XEP_0096",
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
51 "handler": "yes",
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
52 "description": _("""Implementation of SI File Transfert""")
0
goffi@necton2
parents:
diff changeset
53 }
goffi@necton2
parents:
diff changeset
54
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
55 class XEP_0096():
19
f2a745ca0fbc refactoring: using xml params part III (parameters import)
Goffi <goffi@goffi.org>
parents: 15
diff changeset
56
0
goffi@necton2
parents:
diff changeset
57 def __init__(self, host):
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
58 info(_("Plugin XEP_0096 initialization"))
0
goffi@necton2
parents:
diff changeset
59 self.host = host
goffi@necton2
parents:
diff changeset
60 self._waiting_for_approval = {}
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
61 host.bridge.addMethod("sendFile", ".communication", in_sign='sss', out_sign='s', method=self.sendFile)
0
goffi@necton2
parents:
diff changeset
62
72
f271fff3a713 MUC implementation: first draft
Goffi <goffi@goffi.org>
parents: 69
diff changeset
63 def getHandler(self, profile):
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
64 return XEP_0096_handler(self)
15
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
65
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
66 def xep_96(self, IQ, profile):
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
67 info (_("XEP-0096 management"))
15
218ec9984fa5 wokkel integration part III + memory saved again
Goffi <goffi@goffi.org>
parents: 8
diff changeset
68 IQ.handled=True
0
goffi@necton2
parents:
diff changeset
69 SI_elem = IQ.firstChildElement()
goffi@necton2
parents:
diff changeset
70 debug(SI_elem.toXml())
goffi@necton2
parents:
diff changeset
71 filename = ""
goffi@necton2
parents:
diff changeset
72 file_size = ""
goffi@necton2
parents:
diff changeset
73 for element in SI_elem.elements():
goffi@necton2
parents:
diff changeset
74 if element.name == "file":
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
75 info (_("File proposed: name=[%(name)s] size=%(size)s") % {'name':element['name'], 'size':element['size']})
0
goffi@necton2
parents:
diff changeset
76 filename = element["name"]
goffi@necton2
parents:
diff changeset
77 file_size = element["size"]
goffi@necton2
parents:
diff changeset
78 elif element.name == "feature":
goffi@necton2
parents:
diff changeset
79 from_jid = IQ["from"]
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
80 self._waiting_for_approval[IQ["id"]] = (element, from_jid, file_size, profile)
0
goffi@necton2
parents:
diff changeset
81 data={ "filename":filename, "from":from_jid, "size":file_size }
goffi@necton2
parents:
diff changeset
82 self.host.askConfirmation(IQ["id"], "FILE_TRANSFERT", data, self.confirmationCB)
goffi@necton2
parents:
diff changeset
83
goffi@necton2
parents:
diff changeset
84 def confirmationCB(self, id, accepted, data):
goffi@necton2
parents:
diff changeset
85 """Called on confirmation answer"""
goffi@necton2
parents:
diff changeset
86 if accepted:
goffi@necton2
parents:
diff changeset
87 data['size'] = self._waiting_for_approval[id][2]
291
7c79d4a8c9e6 plugins: fixed bad import names
Goffi <goffi@goffi.org>
parents: 228
diff changeset
88 self.host.plugins["XEP-0065"].setData(data, id)
0
goffi@necton2
parents:
diff changeset
89 self.approved(id)
goffi@necton2
parents:
diff changeset
90 else:
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
91 debug (_("Transfert [%s] refused"), id)
0
goffi@necton2
parents:
diff changeset
92 del(self._waiting_for_approval[id])
goffi@necton2
parents:
diff changeset
93
goffi@necton2
parents:
diff changeset
94 def approved(self, id):
goffi@necton2
parents:
diff changeset
95 """must be called when a file transfert has be accepted by client"""
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
96 debug (_("Transfert [%s] accepted"), id)
0
goffi@necton2
parents:
diff changeset
97
goffi@necton2
parents:
diff changeset
98 if ( not self._waiting_for_approval.has_key(id) ):
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
99 error (_("Approved unknow id !"))
0
goffi@necton2
parents:
diff changeset
100 #TODO: manage this (maybe approved by several frontends)
goffi@necton2
parents:
diff changeset
101 else:
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
102 element, from_id, size, profile = self._waiting_for_approval[id]
0
goffi@necton2
parents:
diff changeset
103 del(self._waiting_for_approval[id])
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
104 self.negociate(element, id, from_id, profile)
0
goffi@necton2
parents:
diff changeset
105
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
106 def negociate(self, feat_elem, id, to_jid, profile):
0
goffi@necton2
parents:
diff changeset
107 #TODO: put this in a plugin
goffi@necton2
parents:
diff changeset
108 #FIXME: over ultra mega ugly, need to be generic
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
109 client = self.host.getClient(profile)
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
110 assert(client)
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
111 info (_("Feature negociation"))
0
goffi@necton2
parents:
diff changeset
112 data = feat_elem.firstChildElement()
goffi@necton2
parents:
diff changeset
113 field = data.firstChildElement()
goffi@necton2
parents:
diff changeset
114 #FIXME: several options ! Q&D code for test only
goffi@necton2
parents:
diff changeset
115 option = field.firstChildElement()
goffi@necton2
parents:
diff changeset
116 value = option.firstChildElement()
goffi@necton2
parents:
diff changeset
117 if unicode(value) == "http://jabber.org/protocol/bytestreams":
goffi@necton2
parents:
diff changeset
118 #ugly, as usual, need to be entirely rewritten (just for test !)
goffi@necton2
parents:
diff changeset
119 result = domish.Element(('', 'iq'))
goffi@necton2
parents:
diff changeset
120 result['type'] = 'result'
goffi@necton2
parents:
diff changeset
121 result['id'] = id
goffi@necton2
parents:
diff changeset
122 result['to'] = to_jid
goffi@necton2
parents:
diff changeset
123 si = result.addElement('si', 'http://jabber.org/protocol/si')
goffi@necton2
parents:
diff changeset
124 file = si.addElement('file', 'http://jabber.org/protocol/si/profile/file-transfer')
goffi@necton2
parents:
diff changeset
125 feature = si.addElement('feature', 'http://jabber.org/protocol/feature-neg')
goffi@necton2
parents:
diff changeset
126 x = feature.addElement('x', 'jabber:x:data')
goffi@necton2
parents:
diff changeset
127 x['type'] = 'submit'
goffi@necton2
parents:
diff changeset
128 field = x.addElement('field')
goffi@necton2
parents:
diff changeset
129 field['var'] = 'stream-method'
goffi@necton2
parents:
diff changeset
130 value = field.addElement('value')
goffi@necton2
parents:
diff changeset
131 value.addContent('http://jabber.org/protocol/bytestreams')
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
132 client.xmlstream.send(result)
0
goffi@necton2
parents:
diff changeset
133
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
134 def fileCB(self, answer, xmlstream, current_jid):
0
goffi@necton2
parents:
diff changeset
135 if answer['type']=="result": #FIXME FIXME FIXME ugly ugly ugly ! and temp FIXME FIXME FIXME
goffi@necton2
parents:
diff changeset
136 info("SENDING UGLY ANSWER")
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
137 offer=client.IQ(xmlstream,'set')
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
138 offer["from"]=current_jid.full()
0
goffi@necton2
parents:
diff changeset
139 offer["to"]=answer['from']
goffi@necton2
parents:
diff changeset
140 query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams')
goffi@necton2
parents:
diff changeset
141 query['mode']='tcp'
goffi@necton2
parents:
diff changeset
142 streamhost=query.addElement('streamhost')
22
bb72c29f3432 added action cb mechanism for buttons. Tested with a temporary new user registration button.
Goffi <goffi@goffi.org>
parents: 19
diff changeset
143 streamhost['host']=self.host.memory.getParamA("IP", "File Transfert")
bb72c29f3432 added action cb mechanism for buttons. Tested with a temporary new user registration button.
Goffi <goffi@goffi.org>
parents: 19
diff changeset
144 streamhost['port']=self.host.memory.getParamA("Port", "File Transfert")
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
145 streamhost['jid']=current_jid.full()
0
goffi@necton2
parents:
diff changeset
146 offer.send()
goffi@necton2
parents:
diff changeset
147
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
148 def sendFile(self, to, filepath, profile_key='@DEFAULT@'):
0
goffi@necton2
parents:
diff changeset
149 """send a file using XEP-0096
goffi@necton2
parents:
diff changeset
150 Return an unique id to identify the transfert
goffi@necton2
parents:
diff changeset
151 """
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
152 current_jid, xmlstream = self.host.getJidNStream(profile_key)
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
153 if not xmlstream:
69
86f1f7f6d332 i18n first draft
Goffi <goffi@goffi.org>
parents: 64
diff changeset
154 error (_('Asking for an non-existant or not connected profile'))
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
155 return ""
0
goffi@necton2
parents:
diff changeset
156 debug ("sendfile (%s) to %s", filepath, to )
goffi@necton2
parents:
diff changeset
157 print type(filepath), type(to)
goffi@necton2
parents:
diff changeset
158
goffi@necton2
parents:
diff changeset
159 statinfo = os.stat(filepath)
goffi@necton2
parents:
diff changeset
160
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
161 offer=client.IQ(xmlstream,'set')
0
goffi@necton2
parents:
diff changeset
162 debug ("Transfert ID: %s", offer["id"])
goffi@necton2
parents:
diff changeset
163
291
7c79d4a8c9e6 plugins: fixed bad import names
Goffi <goffi@goffi.org>
parents: 228
diff changeset
164 self.host.plugins["XEP-0065"].sendFile(offer["id"], filepath, str(statinfo.st_size))
0
goffi@necton2
parents:
diff changeset
165
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
166 offer["from"]=current_jid.full()
0
goffi@necton2
parents:
diff changeset
167 offer["to"]=jid.JID(to).full()
goffi@necton2
parents:
diff changeset
168 si=offer.addElement('si','http://jabber.org/protocol/si')
goffi@necton2
parents:
diff changeset
169 si["mime-type"]='text/plain'
goffi@necton2
parents:
diff changeset
170 si["profile"]='http://jabber.org/protocol/si/profile/file-transfer'
8
4b05308d45f9 fixed bad namespace
Goffi <goffi@goffi.org>
parents: 7
diff changeset
171 file = si.addElement('file', 'http://jabber.org/protocol/si/profile/file-transfer')
0
goffi@necton2
parents:
diff changeset
172 file['name']=os.path.basename(filepath)
goffi@necton2
parents:
diff changeset
173 file['size']=str(statinfo.st_size)
goffi@necton2
parents:
diff changeset
174
goffi@necton2
parents:
diff changeset
175 ###
goffi@necton2
parents:
diff changeset
176 # FIXME: Ugly temporary hard coded implementation of XEP-0020 & XEP-0004,
goffi@necton2
parents:
diff changeset
177 # Need to be recoded elsewhere in a more generic way
goffi@necton2
parents:
diff changeset
178 ###
goffi@necton2
parents:
diff changeset
179
goffi@necton2
parents:
diff changeset
180 feature=si.addElement('feature', "http://jabber.org/protocol/feature-neg")
goffi@necton2
parents:
diff changeset
181 x=feature.addElement('x', "jabber:x:data")
goffi@necton2
parents:
diff changeset
182 x['type']='form'
goffi@necton2
parents:
diff changeset
183 field=x.addElement('field')
goffi@necton2
parents:
diff changeset
184 field['type']='list-single'
goffi@necton2
parents:
diff changeset
185 field['var']='stream-method'
goffi@necton2
parents:
diff changeset
186 option = field.addElement('option')
goffi@necton2
parents:
diff changeset
187 value = option.addElement('value', content='http://jabber.org/protocol/bytestreams')
goffi@necton2
parents:
diff changeset
188
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
189 offer.addCallback(self.fileCB, current_jid = current_jid, xmlstream = xmlstream)
0
goffi@necton2
parents:
diff changeset
190 offer.send()
goffi@necton2
parents:
diff changeset
191 return offer["id"] #XXX: using IQ id as file transfert id seems OK as IQ id are required
goffi@necton2
parents:
diff changeset
192
64
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
193 class XEP_0096_handler(XMPPHandler):
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
194 implements(iwokkel.IDisco)
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
195
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
196 def __init__(self, plugin_parent):
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
197 self.plugin_parent = plugin_parent
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
198 self.host = plugin_parent.host
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
199
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
200 def connectionInitialized(self):
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
201 self.xmlstream.addObserver(SI_REQUEST, self.plugin_parent.xep_96, profile = self.parent.profile)
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
202
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
203 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
204 return [disco.DiscoFeature(NS_SI)]
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
205
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
206 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
207 return []
d46f849664aa SàT: multi-profile, plugins updated
Goffi <goffi@goffi.org>
parents: 57
diff changeset
208