1
2
3 from pprint import pprint
4 from uuid import uuid4
5 from datetime import datetime
6
7 from xmpp import *
8 from xmpp.protocol import *
9
11 """
12 Publish-Subscribe node.
13
14 TODO: Items must retain info about its publisher. We have only implemented
15 owners and subscribes, not publishers. So publisher is always the onwer.
16 """
17
18 - def __init__(self, id, owner, type='leaf', parent=None, children=[], members={}, access_model='presence'):
19 """
20 Constructs a PSNode.
21
22 @type id: string
23 @param m: node id
24 """
25 self.id = id
26 self.owner = owner
27 self.type = type
28 self.parent = parent
29 self.children = children
30 self.members = members
31 self.access_model = access_model
32 self.item_ids = []
33 self.items_timestamp = {}
34 self.items = {}
35
37 try:
38
39 if id not in self.item_ids:
40 self.item_ids.append(id)
41 self.items[id] = content
42 self.items_timestamp[id] = datetime.utcnow().isoformat().split('.')[0] + 'Z'
43
44 except Exception,e:
45 self.DEBUG('Exception in addItem: '+str(e),"error")
46
48 return 'PSNode(%s, %s)' % (self.id, self.type)
49
52
54
55 NS = NS_PUBSUB
56
58 self.name = self._owner.servernames[0]
59 self.nodes = {}
60
61 for ns in (NS_PUBSUB, NS_PUBSUB_ERRORS, NS_PUBSUB_EVENTS, NS_PUBSUB_OWNER):
62 server.Dispatcher.RegisterHandler('iq', self.PubSubIqHandler, typ='set', ns=ns, xmlns=NS_CLIENT)
63 server.Dispatcher.RegisterHandler('iq', self.PubSubIqHandler, typ='set', ns=ns, xmlns=NS_COMPONENT_ACCEPT)
64
74
75 - def _sendItem(self, node_id, item_id, frm=None):
76
77 try:
78 node = self.nodes[node_id]
79
80
81
82 for jid in node.members.keys():
83
84 msg = Message(frm=self.name, to=jid)
85 msg.setID(str(uuid4()))
86 event_node = Node(tag='event', attrs={'xmlns':NS_PUBSUB_EVENTS})
87 items_node = Node(tag='items', attrs={'node':node_id})
88 item_node = Node(tag='item', attrs={'id':item_id, 'timestamp':node.items_timestamp[item_id]})
89 if frm is not None:
90 item_node['publisher'] = frm
91 item_node.addChild(node=node.items[item_id])
92 items_node.addChild(node=item_node)
93 event_node.addChild(node=items_node)
94 msg.addChild(node=event_node)
95 s = self._owner.getsession(jid)
96 s.send(msg)
97 except Exception,e:
98 self.DEBUG('Exception in sendItem: '+str(e),"error")
99
100
101
102
103
105 """
106 XXX: We do not validate. We just get what we want and that is enough.
107 """
108
109 try:
110
111 self.DEBUG('PubSub Iq handler called','info')
112
113
114
115
116
117 pubsub_node = stanza.getTag('pubsub')
118
119
120
121 if pubsub_node is None:
122 self.DEBUG('Bad message: %s' % stanza, 'error')
123 raise NodeProcessed
124
125
126 if pubsub_node.getTag('create') is not None:
127 create_node = pubsub_node.getTag('create')
128 node_id = create_node.getAttr('node')
129
130
131
132 if False:
133 session.send(self._getIqError(stanza, 'registration-required'))
134 raise NodeProcessed
135
136 if False:
137 session.send(self._getIqError(stanza, 'forbidden'))
138 raise NodeProcessed
139
140 if node_id in self.nodes:
141 iq = self._getIqError(stanza, 'conflict')
142 session.send(iq)
143 raise NodeProcessed
144
145 if False:
146 session.send(self._getIqError(stanza, 'not-acceptable', 'unsupported-access-model'))
147 raise NodeProcessed
148
149 self.nodes[node_id] = PSNode(id=node_id, owner=stanza.getFrom())
150
151
152
153 self.DEBUG('Creating node: %s' % create_node, 'info')
154
155 id = stanza.getAttr('id')
156 if isinstance(stanza,Protocol): stanza = Iq(node=stanza)
157
158 iq = stanza.buildReply('result')
159 if id: iq.setID(id)
160 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB})
161 pubsub_node.addChild(node=create_node)
162 iq.addChild(node=pubsub_node)
163
164
165 session.send(iq)
166
167
168 elif pubsub_node.getTag('delete') is not None:
169
170 node_id = pubsub_node.getTag('delete').getAttr('node')
171
172 if node_id is None:
173 self.DEBUG('Node is Non', 'error')
174 session.send(self._getIqError(stanza, 'item-not-found'))
175 raise NodeProcessed
176
177 if node_id not in self.nodes:
178 self.DEBUG('Node does not exists: %s' % node_id, 'error')
179 session.send(self._getIqError(stanza, 'item-not-found'))
180 raise NodeProcessed
181
182 node = self.nodes[node_id]
183
184 if not node.owner.bareMatch(stanza.getFrom()):
185 session.send(self._getIqError(stanza, 'forbidden'))
186 raise NodeProcessed
187
188
189
190 del self.nodes[node_id]
191
192
193 session.send(stanza.buildReply('result'))
194
195
196 for jid in node.members.keys():
197 msg = Message(frm=self.name, to=jid)
198 msg.setID(str(uuid4()))
199 event_node = Node(tag='event', attrs={'xmlns':NS_PUBSUB + '#event'})
200 event_node.addChild(name='delete', attrs={'node':node_id})
201 msg.addChild(node=event_node)
202 s = self._owner.getsession(jid)
203 s.send(msg)
204
205
206
207 elif pubsub_node.getTag('subscribe') is not None:
208
209
210
211
212 subscribe_node = pubsub_node.getTag('subscribe')
213 node_id = subscribe_node.getAttr('node')
214
215 jid = JID(subscribe_node.getAttr('jid'))
216
217
218 if node_id is None or jid is None:
219 self.DEBUG('No node id or jid in subscribe message.', 'error')
220 raise NodeProcessed
221
222 if node_id not in self.nodes:
223 self.DEBUG('Node does not exists: %s' % node_id, 'error')
224 session.send(self._getIqError(stanza, 'item-not-found'))
225 raise NodeProcessed
226
227 if not stanza.getFrom().bareMatch(jid):
228 session.send(self._getIqError(stanza, 'bad-request', 'invalid-jid'))
229 raise NodeProcessed
230
231 node = self.nodes[node_id]
232 access_model = node.access_model
233
234
235 if access_model == 'presence':
236 owner_roster = self._owner.DB.db[self.name][node.owner.getNode()]['roster']
237 if jid in owner_roster:
238 if owner_roster[jid.getStripped()]['subscription'] not in ('from', 'both'):
239 if owner_roster[jid.getStripped()]['status'] == 'pending_in':
240 session.send(self._getIqError(stanza, 'not-authorized', 'pending-subscription'))
241 raise NodeProcessed
242 else:
243 session.send(self._getIqError(stanza, 'not-authorized', 'presence-subscription-required'))
244 raise NodeProcessed
245 else:
246 session.send(self._getIqError(stanza, 'not-authorized', 'presence-subscription-required'))
247 raise NodeProcessed
248
249 if False:
250
251 pass
252
253 if False:
254
255 pass
256
257 if False:
258
259 pass
260
261 if False:
262
263 pass
264
265
266
267
268
269 node.members[jid] = str(uuid4())
270
271
272 iq = stanza.buildReply('result')
273 pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB})
274 pubsub_node.addChild(name='subscription', attrs={
275 'node':node_id,
276 'jid': jid,
277 'subid': node.members[jid],
278 'subscription': 'subscribed'
279 })
280 iq.addChild(node=pubsub_node)
281 session.send(iq)
282
283
284
285 elif pubsub_node.getTag('unsubscribe') is not None:
286 unsubscribe_node = pubsub_node.getTag('unsubscribe')
287 node_id = unsubscribe_node.getAttr('node')
288 jid = unsubscribe_node.getAttr('jid')
289
290 if node_id is None or jid is None:
291 self.DEBUG('No node id or jid in subscribe message.', 'error')
292 raise NodeProcessed
293
294 if node_id not in self.nodes:
295 self.DEBUG('Node does not exists: %s' % node_id, 'error')
296 session.send(self._getIqError(stanza, 'item-not-found'))
297 raise NodeProcessed
298
299
300 if not stanza.getFrom().bareMatch(JID(jid)):
301 session.send(self._getIqError(stanza, 'bad-request', 'invalid-jid'))
302 raise NodeProcessed
303
304 node = self.nodes[node_id]
305
306 if jid not in node.members:
307
308 session.send(self._getIqError(stanza, 'unexpected-request', 'not-subscribed'))
309 raise NodeProcessed
310
311 del node.members[jid]
312
313
314 session.send(stanza.buildReply('result'))
315
316
317
318 elif pubsub_node.getTag('publish') is not None:
319 publish_node = pubsub_node.getTag('publish')
320 node_id = publish_node['node']
321
322 if node_id is None:
323 self.DEBUG('No node id or jid in subscribe message.', 'error')
324 raise NodeProcessed
325
326 item_node = publish_node.getTag('item')
327
328 if item_node is None:
329 self.DEBUG('No item', 'error')
330 raise NodeProcessed
331
332 if node_id not in self.nodes:
333
334 self.nodes[node_id] = PSNode(id=node_id, owner=stanza.getFrom())
335
336 node = self.nodes[node_id]
337
338
339 if not node.owner.bareMatch(stanza.getFrom()):
340 session.send(self._getIqError(stanza, 'forbidden'))
341 raise NodeProcessed
342
343 item_id = item_node['id']
344 if item_id is None:
345 item_id = str(uuid4())
346
347
348
349
350 self.nodes[node_id].addItem(item_id, item_node.getChildren()[0])
351
352
353
354 iq = stanza.buildReply('result')
355 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB})
356 publish_node = Node(tag='publish', attrs={'node':node_id})
357 publish_node.addChild(name='item', attrs={'id':item_id})
358 pubsub_node.addChild(node=publish_node)
359 iq.addChild(node=pubsub_node)
360 session.send(iq)
361
362
363 self._sendItem(node_id, item_id, stanza.getFrom())
364
365
366
367 else:
368 self.DEBUG('Not implemented: %s' % create_node, 'info')
369
370 raise NodeProcessed
371 except NodeProcessed:
372 raise NodeProcessed
373 except Exception,e:
374 self.DEBUG("Exception in PubSub Handler: " + str(e),"error")
375