24 #include <string.h> |
24 #include <string.h> |
25 |
25 |
26 #include "commands.h" |
26 #include "commands.h" |
27 #include "logprint.h" |
27 #include "logprint.h" |
28 #include "utils.h" |
28 #include "utils.h" |
|
29 #include "hooks.h" |
29 #include "xmpp.h" |
30 #include "xmpp.h" |
30 #include "compl.h" |
31 #include "compl.h" |
31 #include "xmpp_defines.h" |
32 #include "xmpp_defines.h" |
32 #include "screen.h" |
33 #include "screen.h" |
33 #include "hbuf.h" |
34 #include "hbuf.h" |
34 |
35 |
35 static guint disco_cid = 0; |
36 #include "disco.h" |
36 static LmMessageHandler *disco_info_reply_handler = NULL; |
37 |
37 static LmMessageHandler *disco_items_reply_handler = NULL; |
38 // |
38 |
39 // private types |
39 static LmHandlerResult disco_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata) |
40 // |
40 { |
41 |
41 gboolean info_request = handler == disco_info_reply_handler ? TRUE : FALSE; |
42 // lm message handler userdata |
|
43 typedef struct { |
|
44 disco_info_handler_t handler; |
|
45 gpointer data; |
|
46 GDestroyNotify notify; |
|
47 } disco_info_reply_handler_t; |
|
48 |
|
49 // lm message handler userdata |
|
50 typedef struct { |
|
51 disco_items_handler_t handler; |
|
52 gpointer data; |
|
53 GDestroyNotify notify; |
|
54 } disco_items_reply_handler_t; |
|
55 |
|
56 // user request disco handler userdata (common for info and items) |
|
57 typedef struct { |
|
58 gchar *jid; |
|
59 gchar *node; |
|
60 } disco_handler_t; |
|
61 |
|
62 // |
|
63 // globals |
|
64 // |
|
65 |
|
66 static guint disco_cid = 0; |
|
67 static GSList *reply_handlers = NULL; |
|
68 |
|
69 // |
|
70 // destroyers |
|
71 // |
|
72 |
|
73 static void disco_info_reply_handler_destroy_notify (gpointer data) |
|
74 { |
|
75 disco_info_reply_handler_t *cb = data; |
|
76 if (cb -> notify) |
|
77 cb -> notify (cb -> data); |
|
78 g_free (cb); |
|
79 return; |
|
80 } |
|
81 |
|
82 static void disco_items_reply_handler_destroy_notify (gpointer data) |
|
83 { |
|
84 disco_items_reply_handler_t *cb = data; |
|
85 if (cb -> notify) |
|
86 cb -> notify (cb -> data); |
|
87 g_free (cb); |
|
88 return; |
|
89 } |
|
90 |
|
91 static void disco_handler_destroy_notify (gpointer data) |
|
92 { |
|
93 disco_handler_t *cb = data; |
|
94 g_free (cb -> jid); |
|
95 g_free (cb -> node); |
|
96 g_free (cb); |
|
97 return; |
|
98 } |
|
99 |
|
100 // |
|
101 // lm reply handlers |
|
102 // |
|
103 |
|
104 static LmHandlerResult disco_info_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata) |
|
105 { |
|
106 disco_info_reply_handler_t *cb = udata; |
|
107 |
|
108 reply_handlers = g_slist_remove (reply_handlers, handler); |
42 |
109 |
43 switch (lm_message_get_sub_type (message)) { |
110 switch (lm_message_get_sub_type (message)) { |
44 case LM_MESSAGE_SUB_TYPE_RESULT: |
111 case LM_MESSAGE_SUB_TYPE_RESULT: |
45 |
112 |
46 { |
113 { |
47 LmMessageNode *node = lm_message_get_node (message); |
114 LmMessageNode *node = lm_message_get_node (message); |
48 const gchar *from = lm_message_node_get_attribute (node, "from"); |
115 const gchar *from = lm_message_node_get_attribute (node, "from"); |
49 GString *info; |
116 GSList *identities = NULL; |
|
117 GSList *features = NULL; |
50 |
118 |
51 node = lm_message_node_get_child (node, "query"); |
119 node = lm_message_node_get_child (node, "query"); |
52 |
120 |
53 // check xmlns |
121 // check xmlns |
54 if (!node || strcmp (lm_message_node_get_attribute (node, "xmlns"), info_request ? NS_DISCO_INFO : NS_DISCO_ITEMS)) |
122 if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_INFO)) |
55 break; |
123 break; |
56 |
124 |
57 { // header for user message |
125 // parse request results |
58 const gchar *rnode = lm_message_node_get_attribute (node, "node"); |
126 if (node->children) |
59 |
127 for (node = node->children; node; node = node->next) |
60 // create user message string |
128 if (!strcasecmp (node->name, "identity")) { |
61 info = g_string_new (NULL); |
129 disco_identity_t *identity = g_new (disco_identity_t, 1); |
62 g_string_printf (info, "Service discovery %s results for %s", info_request ? "info" : "items", from); |
130 |
63 if (rnode) |
131 identity -> category = lm_message_node_get_attribute (node, "category"); |
64 g_string_append_printf (info, " (%s):", rnode); |
132 identity -> type = lm_message_node_get_attribute (node, "type"); |
65 else |
133 identity -> name = lm_message_node_get_attribute (node, "name"); |
66 g_string_append (info, ":"); |
134 identity -> reserved = NULL; |
|
135 |
|
136 identities = g_slist_append (identities, identity); |
|
137 } else if (!strcasecmp (node->name, "feature")) |
|
138 features = g_slist_insert_sorted (features, (gpointer) lm_message_node_get_attribute (node, "var"), (GCompareFunc) g_strcmp0); |
|
139 |
|
140 // call handler |
|
141 cb -> handler (identities, features, cb -> data); |
|
142 |
|
143 { // free resources |
|
144 GSList *iel; |
|
145 |
|
146 for (iel = identities; iel; iel = iel -> next) |
|
147 g_free (iel -> data); |
|
148 |
|
149 g_slist_free (identities); |
|
150 g_slist_free (features); |
67 } |
151 } |
68 |
|
69 if (node->children) { |
|
70 // parse request results |
|
71 if (info_request) { // info |
|
72 GString *identities = g_string_new (NULL); |
|
73 GString *features = g_string_new (NULL); |
|
74 |
|
75 for (node = node->children; node; node = node->next) { |
|
76 if (!strcasecmp (node->name, "identity")) { |
|
77 const gchar *category = lm_message_node_get_attribute (node, "category"); |
|
78 const gchar *type = lm_message_node_get_attribute (node, "type"); |
|
79 const gchar *name = lm_message_node_get_attribute (node, "name"); |
|
80 |
|
81 g_string_append_printf (identities, "\n [%s (%s)] %s", category ? category : "none", type ? type : "none", name ? name : ""); |
|
82 |
|
83 } else if (!strcasecmp (node->name, "feature")) { |
|
84 const gchar *var = lm_message_node_get_attribute (node, "var"); |
|
85 |
|
86 g_string_append_printf (features, "\n [%s]", var ? var : "none"); |
|
87 } |
|
88 } |
|
89 |
|
90 if (identities->len) |
|
91 g_string_append_printf (info, "\n Identities:%s", identities->str); |
|
92 if (features->len) |
|
93 g_string_append_printf (info, "\n Features:%s", features->str); |
|
94 |
|
95 g_string_free (identities, TRUE); |
|
96 g_string_free (features, TRUE); |
|
97 |
|
98 } else { // items |
|
99 for (node = node->children; node; node = node->next) { |
|
100 const gchar *name = lm_message_node_get_attribute (node, "name"); |
|
101 const gchar *jid = lm_message_node_get_attribute (node, "jid"); |
|
102 const gchar *inode = lm_message_node_get_attribute (node, "node"); |
|
103 |
|
104 if (inode) |
|
105 g_string_append_printf (info, "\n [%s (%s)] %s", jid ? jid : "none", inode, name ? name : ""); |
|
106 else |
|
107 g_string_append_printf (info, "\n [%s] %s", jid ? jid : "none", name ? name : ""); |
|
108 } |
|
109 } |
|
110 } else |
|
111 g_string_append (info, "\n Empty result."); |
|
112 |
|
113 { // print to buddy's buffer |
|
114 gchar *jid = jidtodisp (from); |
|
115 |
|
116 // XXX check for message size? conference server lists may be huge... |
|
117 scr_WriteIncomingMessage (jid, info->str, 0, HBB_PREFIX_INFO, 0); // NO conversion from utf-8 |
|
118 |
|
119 g_free (jid); |
|
120 } |
|
121 |
|
122 g_string_free (info, TRUE); |
|
123 } |
152 } |
124 |
153 |
125 break; |
154 break; |
126 |
155 |
127 case LM_MESSAGE_SUB_TYPE_ERROR: |
156 case LM_MESSAGE_SUB_TYPE_ERROR: |
137 if (node->children) |
166 if (node->children) |
138 reason = node->children->name; |
167 reason = node->children->name; |
139 else |
168 else |
140 reason = "undefined"; |
169 reason = "undefined"; |
141 |
170 |
142 { // print to buddy's buffer |
171 // XXX: we need to inform user, but do we really need to print this on every possible error? |
143 gchar *jid = jidtodisp (from); |
172 scr_LogPrint (LPRINT_LOGNORM, "disco: Service info discovery for %s failed: %s - %s", from, type, reason); |
144 gchar *mesg = g_strdup_printf ("Service %s discovery for %s failed: %s - %s", info_request ? "info" : "items", from, type, reason); |
173 |
145 |
174 cb -> handler (NULL, NULL, cb -> data); |
146 scr_WriteIncomingMessage (jid, mesg, 0, HBB_PREFIX_INFO, 0); |
|
147 |
|
148 g_free (mesg); |
|
149 g_free (jid); |
|
150 } |
|
151 } |
175 } |
152 |
176 |
153 break; |
177 break; |
154 |
178 |
155 default: |
179 default: |
156 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
180 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
|
181 } |
|
182 |
|
183 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
|
184 } |
|
185 |
|
186 static LmHandlerResult disco_items_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata) |
|
187 { |
|
188 disco_items_reply_handler_t *cb = udata; |
|
189 |
|
190 reply_handlers = g_slist_remove (reply_handlers, handler); |
|
191 |
|
192 switch (lm_message_get_sub_type (message)) { |
|
193 case LM_MESSAGE_SUB_TYPE_RESULT: |
|
194 |
|
195 { |
|
196 LmMessageNode *node = lm_message_get_node (message); |
|
197 const gchar *from = lm_message_node_get_attribute (node, "from"); |
|
198 GSList *items = NULL; |
|
199 |
|
200 node = lm_message_node_get_child (node, "query"); |
|
201 |
|
202 // check xmlns |
|
203 if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_ITEMS)) |
|
204 break; |
|
205 |
|
206 // parse request results |
|
207 if (node->children) |
|
208 for (node = node->children; node; node = node->next) |
|
209 if (!strcasecmp (node->name, "item")) { |
|
210 disco_item_t *item = g_new (disco_item_t, 1); |
|
211 |
|
212 item -> name = lm_message_node_get_attribute (node, "name"); |
|
213 item -> jid = lm_message_node_get_attribute (node, "jid"); |
|
214 item -> node = lm_message_node_get_attribute (node, "node"); |
|
215 |
|
216 items = g_slist_append (items, item); |
|
217 } |
|
218 |
|
219 // call handler |
|
220 cb -> handler (items, cb -> data); |
|
221 |
|
222 { // free resources |
|
223 GSList *iel; |
|
224 |
|
225 for (iel = items; iel; iel = iel -> next) |
|
226 g_free (iel -> data); |
|
227 |
|
228 g_slist_free (items); |
|
229 } |
|
230 } |
|
231 |
157 break; |
232 break; |
|
233 |
|
234 case LM_MESSAGE_SUB_TYPE_ERROR: |
|
235 |
|
236 { |
|
237 LmMessageNode *node = lm_message_get_node (message); |
|
238 const gchar *from = lm_message_node_get_attribute (node, "from"); |
|
239 const gchar *type; |
|
240 const gchar *reason; |
|
241 |
|
242 node = lm_message_node_get_child (node, "error"); |
|
243 type = lm_message_node_get_attribute (node, "type"); |
|
244 if (node->children) |
|
245 reason = node->children->name; |
|
246 else |
|
247 reason = "undefined"; |
|
248 |
|
249 // XXX: we need to inform user, but do we really need to print this on every possible error? |
|
250 scr_LogPrint (LPRINT_LOGNORM, "disco: Service items discovery for %s failed: %s - %s", from, type, reason); |
|
251 |
|
252 cb -> handler (NULL, cb -> data); |
|
253 } |
|
254 |
|
255 break; |
|
256 |
|
257 default: |
|
258 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
158 } |
259 } |
159 |
260 |
160 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
261 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
161 } |
262 } |
|
263 |
|
264 // |
|
265 // disco requests sending |
|
266 // |
|
267 |
|
268 static void disco_features_cb (gconstpointer data, gpointer userdata) |
|
269 { |
|
270 const gchar *feature = data; |
|
271 GSList **features = userdata; |
|
272 *features = g_slist_insert_sorted (*features, (gpointer) feature, (GCompareFunc) g_strcmp0); |
|
273 return; |
|
274 } |
|
275 |
|
276 void disco_info_request (const gchar *jid, const gchar *dnode, disco_info_handler_t handler, gpointer userdata, GDestroyNotify notify) |
|
277 { |
|
278 if (!handler) { |
|
279 if (notify) |
|
280 notify (userdata); |
|
281 return; |
|
282 } |
|
283 |
|
284 if (0 && !dnode) { // FIXME: no way to get identity(ies) from caps |
|
285 gchar *bjid = jidtodisp (jid); |
|
286 GSList *buddy = roster_find (bjid, jidsearch, ROSTER_TYPE_USER | ROSTER_TYPE_ROOM | ROSTER_TYPE_AGENT); |
|
287 const gchar *resource = strchr (jid, JID_RESOURCE_SEPARATOR); |
|
288 |
|
289 g_free (bjid); |
|
290 |
|
291 if (buddy) { |
|
292 const gchar *hash = buddy_resource_getcaps (BUDDATA(buddy), resource); // ?? will it all work? |
|
293 if (hash) { // cached result |
|
294 GSList *identities = NULL; |
|
295 GSList *features = NULL; |
|
296 caps_foreach_feature (hash, disco_features_cb, &features); |
|
297 handler (identities, features, userdata); |
|
298 if (notify) |
|
299 notify (userdata); |
|
300 return; |
|
301 } |
|
302 } |
|
303 } |
|
304 |
|
305 { // send request |
|
306 LmMessage *request; |
|
307 LmMessageNode *node; |
|
308 GError *error = NULL; |
|
309 |
|
310 request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
|
311 node = lm_message_get_node (request); |
|
312 node = lm_message_node_add_child (node, "query", NULL); |
|
313 lm_message_node_set_attribute (node, "xmlns", NS_DISCO_INFO); |
|
314 if (dnode) |
|
315 lm_message_node_set_attribute (node, "node", dnode); |
|
316 |
|
317 { |
|
318 disco_info_reply_handler_t *cb = g_new (disco_info_reply_handler_t, 1); |
|
319 LmMessageHandler *lhandler = lm_message_handler_new (disco_info_reply_handler, cb, disco_info_reply_handler_destroy_notify); |
|
320 |
|
321 cb -> handler = handler; |
|
322 cb -> data = userdata; |
|
323 cb -> notify = notify; |
|
324 |
|
325 reply_handlers = g_slist_append (reply_handlers, lhandler); |
|
326 |
|
327 lm_connection_send_with_reply (lconnection, request, lhandler, &error); |
|
328 |
|
329 if (error) { |
|
330 scr_LogPrint (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
|
331 g_error_free (error); |
|
332 } |
|
333 |
|
334 lm_message_handler_unref (lhandler); |
|
335 } |
|
336 |
|
337 lm_message_unref (request); |
|
338 } |
|
339 |
|
340 return; |
|
341 } |
|
342 |
|
343 void disco_items_request (const gchar *jid, const gchar *dnode, disco_items_handler_t handler, gpointer userdata, GDestroyNotify notify) |
|
344 { |
|
345 if (!handler) { |
|
346 if (notify) |
|
347 notify (userdata); |
|
348 return; |
|
349 } |
|
350 |
|
351 { // send request |
|
352 LmMessage *request; |
|
353 LmMessageNode *node; |
|
354 GError *error = NULL; |
|
355 |
|
356 request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
|
357 node = lm_message_get_node (request); |
|
358 node = lm_message_node_add_child (node, "query", NULL); |
|
359 lm_message_node_set_attribute (node, "xmlns", NS_DISCO_ITEMS); |
|
360 if (dnode) |
|
361 lm_message_node_set_attribute (node, "node", dnode); |
|
362 |
|
363 { |
|
364 disco_items_reply_handler_t *cb = g_new (disco_items_reply_handler_t, 1); |
|
365 LmMessageHandler *lhandler = lm_message_handler_new (disco_items_reply_handler, cb, disco_items_reply_handler_destroy_notify); |
|
366 |
|
367 cb -> handler = handler; |
|
368 cb -> data = userdata; |
|
369 cb -> notify = notify; |
|
370 |
|
371 reply_handlers = g_slist_append (reply_handlers, lhandler); |
|
372 |
|
373 lm_connection_send_with_reply (lconnection, request, lhandler, &error); |
|
374 |
|
375 if (error) { |
|
376 scr_LogPrint (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
|
377 g_error_free (error); |
|
378 } |
|
379 |
|
380 lm_message_handler_unref (lhandler); |
|
381 } |
|
382 |
|
383 lm_message_unref (request); |
|
384 } |
|
385 |
|
386 return; |
|
387 } |
|
388 |
|
389 // |
|
390 // user requests handlers (print results) |
|
391 // |
|
392 |
|
393 static void disco_info_handler (GSList *identities, GSList *features, gpointer udata) |
|
394 { |
|
395 disco_handler_t *cb = udata; |
|
396 GString *info = g_string_new ("Service discovery info results for "); |
|
397 |
|
398 g_string_append (info, cb -> jid); |
|
399 if (cb -> node) |
|
400 g_string_append_printf (info, " (%s):", cb -> node); |
|
401 else |
|
402 g_string_append_c (info, ':'); |
|
403 |
|
404 { |
|
405 GString *tmp = g_string_new (NULL); |
|
406 GSList *el; |
|
407 |
|
408 // compose identities part |
|
409 for (el = identities; el; el = el -> next) { |
|
410 disco_identity_t *identity = el -> data; |
|
411 g_string_append_printf (tmp, "\n [%s (%s)] %s", |
|
412 identity -> category ? identity -> category : "none", |
|
413 identity -> type ? identity -> type : "none", |
|
414 identity -> name ? identity -> name : ""); |
|
415 } |
|
416 |
|
417 if (tmp -> len) { |
|
418 g_string_append_printf (info, "\n Identities:%s", tmp -> str); |
|
419 g_string_truncate (info, 0); |
|
420 } |
|
421 |
|
422 // compose features part |
|
423 for (el = features; el; el = el -> next) { |
|
424 gchar *feature = el -> data; |
|
425 g_string_append_printf (tmp, "\n [%s]", feature ? feature : "none"); |
|
426 } |
|
427 |
|
428 if (tmp -> len) |
|
429 g_string_append_printf (info, "\n Features:%s", tmp -> str); |
|
430 |
|
431 g_string_free (tmp, TRUE); |
|
432 } |
|
433 |
|
434 { // print to buddy's buffer |
|
435 gchar *bjid = jidtodisp (cb -> jid); |
|
436 |
|
437 scr_WriteIncomingMessage (bjid, info -> str, 0, HBB_PREFIX_INFO, 0); // NO conversion from utf-8 |
|
438 |
|
439 g_free (bjid); |
|
440 } |
|
441 |
|
442 g_string_free (info, TRUE); |
|
443 |
|
444 return; |
|
445 } |
|
446 |
|
447 static void disco_items_handler (GSList *items, gpointer udata) |
|
448 { |
|
449 disco_handler_t *cb = udata; |
|
450 GString *info = g_string_new ("Service discovery items results for "); |
|
451 |
|
452 g_string_append (info, cb -> jid); |
|
453 if (cb -> node) |
|
454 g_string_append_printf (info, " (%s):", cb -> node); |
|
455 else |
|
456 g_string_append_c (info, ':'); |
|
457 |
|
458 { |
|
459 GSList *el; |
|
460 |
|
461 // add items info |
|
462 for (el = items; el; el = el -> next) { |
|
463 disco_item_t *item = el -> data; |
|
464 if (item -> node) |
|
465 g_string_append_printf (info, "\n [%s (%s)] %s", |
|
466 item -> jid ? item -> jid : "none", item -> node, |
|
467 item -> name ? item -> name : ""); |
|
468 else |
|
469 g_string_append_printf (info, "\n [%s] %s", |
|
470 item -> jid ? item -> jid : "none", |
|
471 item -> name ? item -> name : ""); |
|
472 } |
|
473 } |
|
474 |
|
475 { // print to buddy's buffer |
|
476 gchar *bjid = jidtodisp (cb -> jid); |
|
477 |
|
478 scr_WriteIncomingMessage (bjid, info -> str, 0, HBB_PREFIX_INFO, 0); // NO conversion from utf-8 |
|
479 |
|
480 g_free (bjid); |
|
481 } |
|
482 |
|
483 g_string_free (info, TRUE); |
|
484 |
|
485 return; |
|
486 } |
|
487 |
|
488 // |
|
489 // command |
|
490 // |
162 |
491 |
163 static void do_disco (char *arg) |
492 static void do_disco (char *arg) |
164 { |
493 { |
165 char **args = split_arg (arg, 3, 0); |
494 char **args = split_arg (arg, 3, 0); |
166 int info = -1; |
495 int info = -1; |
195 if (args[2]) |
522 if (args[2]) |
196 dnode = to_utf8 (args[2]); |
523 dnode = to_utf8 (args[2]); |
197 } |
524 } |
198 // XXX send to all resources/current resource? |
525 // XXX send to all resources/current resource? |
199 |
526 |
200 { // create message |
|
201 LmMessageNode *node; |
|
202 |
|
203 request = lm_message_new_with_sub_type (to ? to : CURRENT_JID, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
|
204 node = lm_message_get_node (request); |
|
205 node = lm_message_node_add_child (node, "query", NULL); |
|
206 lm_message_node_set_attribute (node, "xmlns", info ? NS_DISCO_INFO : NS_DISCO_ITEMS); |
|
207 if (dnode) |
|
208 lm_message_node_set_attribute (node, "node", dnode); |
|
209 } |
|
210 |
|
211 { |
527 { |
212 GError *error = NULL; |
528 disco_handler_t *cb = g_new (disco_handler_t, 1); |
213 |
529 |
214 lm_connection_send_with_reply (lconnection, request, info ? disco_info_reply_handler : disco_items_reply_handler, &error); |
530 cb -> jid = to ? to : g_strdup (CURRENT_JID); |
215 |
531 cb -> node = dnode; |
216 if (error) { |
532 |
217 scr_LogPrint (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
533 if (info) |
218 g_error_free (error); |
534 disco_info_request (cb -> jid, cb -> node, disco_info_handler, cb, disco_handler_destroy_notify); |
219 } |
535 else |
220 } |
536 disco_items_request (cb -> jid, cb -> node, disco_items_handler, cb, disco_handler_destroy_notify); |
221 |
537 } |
222 lm_message_unref (request); |
|
223 if (dnode) |
|
224 g_free (dnode); |
|
225 if (to) |
|
226 g_free (to); |
|
227 } |
538 } |
228 |
539 |
229 free_arg_lst (args); |
540 free_arg_lst (args); |
|
541 return; |
|
542 } |
|
543 |
|
544 // |
|
545 // module mechanics |
|
546 // |
|
547 |
|
548 static void disco_unregister_handlers (void) |
|
549 { |
|
550 GSList *hel; |
|
551 |
|
552 for (hel = reply_handlers; hel; hel = hel -> next) { |
|
553 LmMessageHandler *handler = hel -> data; |
|
554 lm_message_handler_invalidate (handler); |
|
555 } |
|
556 |
|
557 g_slist_free (reply_handlers); |
|
558 reply_handlers = NULL; |
|
559 |
|
560 return; |
|
561 } |
|
562 |
|
563 static void disco_hh (guint32 htype, hk_arg_t *args, gpointer ignore) |
|
564 { |
|
565 hk_arg_t *arg; |
|
566 |
|
567 for (arg = args; arg->name; ++arg) |
|
568 if (!strcmp (arg->name, "hook")) { |
|
569 if (!strcmp (arg->value, "hook-pre-disconnect")) |
|
570 disco_unregister_handlers (); |
|
571 return; |
|
572 } |
|
573 |
|
574 return; |
230 } |
575 } |
231 |
576 |
232 const gchar *g_module_check_init(GModule *module) |
577 const gchar *g_module_check_init(GModule *module) |
233 { |
578 { |
234 // create handlers |
|
235 disco_info_reply_handler = lm_message_handler_new (disco_handler, NULL, NULL); |
|
236 disco_items_reply_handler = lm_message_handler_new (disco_handler, NULL, NULL); |
|
237 |
|
238 // completion |
579 // completion |
239 disco_cid = compl_new_category (); |
580 disco_cid = compl_new_category (); |
240 if (disco_cid) { |
581 if (disco_cid) { |
241 compl_add_category_word (disco_cid, "info"); |
582 compl_add_category_word (disco_cid, "info"); |
242 compl_add_category_word (disco_cid, "items"); |
583 compl_add_category_word (disco_cid, "items"); |
243 } |
584 } |
244 |
585 |
|
586 // hook handler |
|
587 hk_add_handler (disco_hh, HOOK_INTERNAL, NULL); |
|
588 |
245 // command |
589 // command |
246 cmd_add ("disco", "", disco_cid, COMPL_JID, do_disco, NULL); |
590 cmd_add ("disco", "", disco_cid, COMPL_JID, do_disco, NULL); |
247 |
591 |
248 return NULL; |
592 return NULL; |
249 } |
593 } |