85 // |
86 // |
86 // globals |
87 // globals |
87 // |
88 // |
88 |
89 |
89 #ifdef MCABBER_API_HAVE_CMD_ID |
90 #ifdef MCABBER_API_HAVE_CMD_ID |
90 static gpointer disco_cmid = NULL; |
91 static gpointer disco_cmid = NULL; |
91 #endif |
92 #endif |
92 |
93 static guint disco_cid = 0; |
93 static guint disco_cid = 0; |
94 static guint disco_hid = 0; |
94 static guint disco_hid = 0; |
95 static GSList * disco_requests = NULL; |
95 static GSList *reply_handlers = NULL; |
|
96 |
96 |
97 // |
97 // |
98 // destroyers |
98 // destroyers |
99 // |
99 // |
100 |
100 |
101 static void disco_info_reply_handler_destroy_notify (gpointer data) |
101 static void disco_request_free ( disco_request_t * cb ) |
102 { |
102 { |
103 disco_info_reply_handler_t *cb = data; |
103 disco_requests = g_slist_remove ( disco_requests, cb ); |
104 if (cb -> notify) |
104 |
105 cb -> notify (cb -> data); |
105 if ( cb -> reply_handler ) { |
106 g_slice_free (disco_info_reply_handler_t, cb); |
106 lm_message_handler_invalidate ( cb -> reply_handler ); |
107 return; |
107 #ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER |
108 } |
108 if ( lconnection ) |
109 |
109 lm_connection_unregister_reply_handler ( lconnection, cb -> reply_handler ); |
110 static void disco_items_reply_handler_destroy_notify (gpointer data) |
110 #endif |
111 { |
111 } |
112 disco_items_reply_handler_t *cb = data; |
112 if ( cb -> notify ) |
113 if (cb -> notify) |
113 cb -> notify ( cb -> data ); |
114 cb -> notify (cb -> data); |
114 g_slice_free ( disco_request_t, cb ); |
115 g_slice_free (disco_items_reply_handler_t, cb); |
115 return; |
116 return; |
116 } |
117 } |
117 |
118 |
118 static void disco_handler_destroy_notify ( gpointer data ) |
119 static void disco_handler_destroy_notify (gpointer data) |
119 { |
120 { |
120 disco_handler_t * cb = data; |
121 disco_handler_t *cb = data; |
121 g_free ( cb -> jid ); |
122 g_free (cb -> jid); |
122 g_free ( cb -> node ); |
123 g_free (cb -> node); |
123 g_slice_free ( disco_handler_t, cb ); |
124 g_slice_free (disco_handler_t, cb); |
|
125 return; |
124 return; |
126 } |
125 } |
127 |
126 |
128 // |
127 // |
129 // lm reply handlers |
128 // lm reply handlers |
130 // |
129 // |
131 |
130 |
132 static LmHandlerResult disco_info_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata) |
131 static LmHandlerResult disco_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata) |
133 { |
132 { |
134 disco_info_reply_handler_t *cb = udata; |
133 disco_request_t * cb = udata; |
135 |
134 LmHandlerResult result = LM_HANDLER_RESULT_REMOVE_MESSAGE; |
136 reply_handlers = g_slist_remove (reply_handlers, handler); |
|
137 |
135 |
138 switch (lm_message_get_sub_type (message)) { |
136 switch (lm_message_get_sub_type (message)) { |
139 case LM_MESSAGE_SUB_TYPE_RESULT: |
137 case LM_MESSAGE_SUB_TYPE_RESULT: |
140 |
138 |
141 { |
139 { |
142 LmMessageNode *node = lm_message_get_node (message); |
140 LmMessageNode *node = lm_message_get_node (message); |
143 GSList *identities = NULL; |
|
144 GSList *features = NULL; |
|
145 |
141 |
146 node = lm_message_node_get_child (node, "query"); |
142 node = lm_message_node_get_child (node, "query"); |
147 |
143 |
148 // check xmlns |
144 if ( cb -> type == DISCO_INFO_REQUEST ) { |
149 if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_INFO)) |
145 |
150 break; |
146 GSList * identities = NULL; |
151 |
147 GSList * features = NULL; |
152 // parse request results |
148 |
153 if (node->children) |
149 // check xmlns |
154 for (node = node->children; node; node = node->next) |
150 if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_INFO)) |
155 if (!strcasecmp (node->name, "identity")) { |
151 break; |
156 disco_identity_t *identity = g_slice_new (disco_identity_t); |
152 |
157 |
153 // parse request results |
158 identity -> category = lm_message_node_get_attribute (node, "category"); |
154 if (node->children) |
159 identity -> type = lm_message_node_get_attribute (node, "type"); |
155 for (node = node->children; node; node = node->next) |
160 identity -> name = lm_message_node_get_attribute (node, "name"); |
156 if (!strcasecmp (node->name, "identity")) { |
161 identity -> reserved = NULL; |
157 disco_identity_t *identity = g_slice_new (disco_identity_t); |
162 |
158 |
163 identities = g_slist_append (identities, identity); |
159 identity -> category = lm_message_node_get_attribute (node, "category"); |
164 } else if (!strcasecmp (node->name, "feature")) |
160 identity -> type = lm_message_node_get_attribute (node, "type"); |
165 features = g_slist_insert_sorted (features, (gpointer) lm_message_node_get_attribute (node, "var"), (GCompareFunc) g_strcmp0); |
161 identity -> name = lm_message_node_get_attribute (node, "name"); |
166 |
162 identity -> reserved = NULL; |
167 // call handler |
163 |
168 cb -> handler (identities, features, cb -> data); |
164 identities = g_slist_append (identities, identity); |
169 |
165 } else if (!strcasecmp (node->name, "feature")) |
170 { // free resources |
166 features = g_slist_insert_sorted (features, (gpointer) lm_message_node_get_attribute (node, "var"), (GCompareFunc) g_strcmp0); |
171 GSList *iel; |
167 |
172 |
168 // call handler |
173 for (iel = identities; iel; iel = iel -> next) |
169 cb -> handler.info (identities, features, cb -> data); |
174 g_slice_free (disco_identity_t, iel -> data); |
170 |
175 |
171 { // free resources |
176 g_slist_free (identities); |
172 GSList *iel; |
177 g_slist_free (features); |
173 |
|
174 for (iel = identities; iel; iel = iel -> next) |
|
175 g_slice_free (disco_identity_t, iel -> data); |
|
176 |
|
177 g_slist_free (identities); |
|
178 g_slist_free (features); |
|
179 } |
|
180 |
|
181 } else { // items request |
|
182 |
|
183 GSList * items = NULL; |
|
184 |
|
185 // check xmlns |
|
186 if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_ITEMS)) |
|
187 break; |
|
188 |
|
189 // parse request results |
|
190 if (node->children) |
|
191 for (node = node->children; node; node = node->next) |
|
192 if (!strcasecmp (node->name, "item")) { |
|
193 disco_item_t *item = g_slice_new (disco_item_t); |
|
194 |
|
195 item -> name = lm_message_node_get_attribute (node, "name"); |
|
196 item -> jid = lm_message_node_get_attribute (node, "jid"); |
|
197 item -> node = lm_message_node_get_attribute (node, "node"); |
|
198 |
|
199 items = g_slist_append (items, item); |
|
200 } |
|
201 |
|
202 // call handler |
|
203 cb -> handler.items (items, cb -> data); |
|
204 |
|
205 { // free resources |
|
206 GSList *iel; |
|
207 |
|
208 for (iel = items; iel; iel = iel -> next) |
|
209 g_slice_free (disco_item_t, iel -> data); |
|
210 |
|
211 g_slist_free (items); |
|
212 } |
178 } |
213 } |
179 } |
214 } |
180 |
215 |
181 break; |
216 break; |
182 |
217 |
194 reason = node->children->name; |
229 reason = node->children->name; |
195 else |
230 else |
196 reason = "undefined"; |
231 reason = "undefined"; |
197 |
232 |
198 // XXX: we need to inform user, but do we really need to print this on every possible error? |
233 // XXX: we need to inform user, but do we really need to print this on every possible error? |
199 scr_log_print (LPRINT_LOGNORM, "disco: Service info discovery for %s failed: %s - %s", from, type, reason); |
234 if ( cb -> type == DISCO_INFO_REQUEST ) { |
200 |
235 |
201 cb -> handler (NULL, NULL, cb -> data); |
236 scr_log_print (LPRINT_LOGNORM, "disco: Service info discovery for %s failed: %s - %s", from, type, reason); |
|
237 cb -> handler.info (NULL, NULL, cb -> data); |
|
238 |
|
239 } else { |
|
240 |
|
241 scr_log_print (LPRINT_LOGNORM, "disco: Service items discovery for %s failed: %s - %s", from, type, reason); |
|
242 cb -> handler.items (NULL, cb -> data); |
|
243 } |
202 } |
244 } |
203 |
245 |
204 break; |
246 break; |
205 |
247 |
206 default: |
248 default: |
207 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
249 |
208 } |
250 result = LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
209 |
|
210 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
|
211 } |
|
212 |
|
213 static LmHandlerResult disco_items_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata) |
|
214 { |
|
215 disco_items_reply_handler_t *cb = udata; |
|
216 |
|
217 reply_handlers = g_slist_remove (reply_handlers, handler); |
|
218 |
|
219 switch (lm_message_get_sub_type (message)) { |
|
220 case LM_MESSAGE_SUB_TYPE_RESULT: |
|
221 |
|
222 { |
|
223 LmMessageNode *node = lm_message_get_node (message); |
|
224 GSList *items = NULL; |
|
225 |
|
226 node = lm_message_node_get_child (node, "query"); |
|
227 |
|
228 // check xmlns |
|
229 if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_ITEMS)) |
|
230 break; |
|
231 |
|
232 // parse request results |
|
233 if (node->children) |
|
234 for (node = node->children; node; node = node->next) |
|
235 if (!strcasecmp (node->name, "item")) { |
|
236 disco_item_t *item = g_slice_new (disco_item_t); |
|
237 |
|
238 item -> name = lm_message_node_get_attribute (node, "name"); |
|
239 item -> jid = lm_message_node_get_attribute (node, "jid"); |
|
240 item -> node = lm_message_node_get_attribute (node, "node"); |
|
241 |
|
242 items = g_slist_append (items, item); |
|
243 } |
|
244 |
|
245 // call handler |
|
246 cb -> handler (items, cb -> data); |
|
247 |
|
248 { // free resources |
|
249 GSList *iel; |
|
250 |
|
251 for (iel = items; iel; iel = iel -> next) |
|
252 g_slice_free (disco_item_t, iel -> data); |
|
253 |
|
254 g_slist_free (items); |
|
255 } |
|
256 } |
|
257 |
251 |
258 break; |
252 break; |
259 |
253 } |
260 case LM_MESSAGE_SUB_TYPE_ERROR: |
254 |
261 |
255 disco_request_free ( cb ); |
262 { |
256 |
263 LmMessageNode *node = lm_message_get_node (message); |
257 return result; |
264 const gchar *from = lm_message_node_get_attribute (node, "from"); |
|
265 const gchar *type; |
|
266 const gchar *reason; |
|
267 |
|
268 node = lm_message_node_get_child (node, "error"); |
|
269 type = lm_message_node_get_attribute (node, "type"); |
|
270 if (node->children) |
|
271 reason = node->children->name; |
|
272 else |
|
273 reason = "undefined"; |
|
274 |
|
275 // XXX: we need to inform user, but do we really need to print this on every possible error? |
|
276 scr_log_print (LPRINT_LOGNORM, "disco: Service items discovery for %s failed: %s - %s", from, type, reason); |
|
277 |
|
278 cb -> handler (NULL, cb -> data); |
|
279 } |
|
280 |
|
281 break; |
|
282 |
|
283 default: |
|
284 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
|
285 } |
|
286 |
|
287 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
|
288 } |
258 } |
289 |
259 |
290 // |
260 // |
291 // disco requests sending |
261 // disco requests sending |
292 // |
262 // |
331 } |
303 } |
332 } |
304 } |
333 #endif |
305 #endif |
334 |
306 |
335 { // send request |
307 { // send request |
336 LmMessage *request; |
308 LmMessage * request; |
337 LmMessageNode *node; |
309 LmMessageNode * node; |
338 LmMessageHandler *lhandler; |
310 LmMessageHandler * lhandler; |
339 GError *error = NULL; |
311 GError * error = NULL; |
|
312 disco_request_t * cb = g_slice_new ( disco_request_t ); |
340 |
313 |
341 request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
314 request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
342 node = lm_message_get_node (request); |
315 node = lm_message_get_node (request); |
343 node = lm_message_node_add_child (node, "query", NULL); |
316 node = lm_message_node_add_child (node, "query", NULL); |
344 lm_message_node_set_attribute (node, "xmlns", NS_DISCO_INFO); |
317 lm_message_node_set_attribute (node, "xmlns", NS_DISCO_INFO); |
345 if (dnode) |
318 if (dnode) |
346 lm_message_node_set_attribute (node, "node", dnode); |
319 lm_message_node_set_attribute (node, "node", dnode); |
347 |
320 |
348 { |
321 lhandler = lm_message_handler_new (disco_reply_handler, cb, NULL); |
349 disco_info_reply_handler_t *cb = g_slice_new (disco_info_reply_handler_t); |
322 |
350 |
323 cb -> reply_handler = lhandler; |
351 lhandler = lm_message_handler_new (disco_info_reply_handler, cb, disco_info_reply_handler_destroy_notify); |
324 cb -> type = DISCO_INFO_REQUEST; |
352 |
325 cb -> handler.info = handler; |
353 cb -> handler = handler; |
326 cb -> data = userdata; |
354 cb -> data = userdata; |
327 cb -> notify = notify; |
355 cb -> notify = notify; |
328 |
356 |
329 disco_requests = g_slist_append ( disco_requests, cb ); |
357 reply_handlers = g_slist_append (reply_handlers, lhandler); |
330 |
358 |
331 lm_connection_send_with_reply (lconnection, request, lhandler, &error); |
359 lm_connection_send_with_reply (lconnection, request, lhandler, &error); |
332 |
360 |
333 if (error) { |
361 if (error) { |
334 scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
362 // XXX destroy handler and return NULL? |
335 g_error_free (error); |
363 scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
336 handler ( NULL, NULL, userdata ); // XXX |
364 g_error_free (error); |
337 disco_request_free ( cb ); |
365 } |
338 cb = NULL; |
366 |
339 } |
367 lm_message_handler_unref (lhandler); |
340 |
368 } |
341 lm_message_handler_unref (lhandler); |
369 |
|
370 lm_message_unref (request); |
342 lm_message_unref (request); |
371 |
343 |
372 return lhandler; |
344 return cb; |
373 } |
345 } |
374 } |
346 } |
375 |
347 |
376 gpointer disco_items_request (const gchar *jid, const gchar *dnode, disco_items_handler_t handler, gpointer userdata, GDestroyNotify notify) |
348 gpointer disco_items_request (const gchar *jid, const gchar *dnode, disco_items_handler_t handler, gpointer userdata, GDestroyNotify notify) |
377 { |
349 { |
378 if (!handler || !xmpp_is_online ()) { |
350 if (!handler || !xmpp_is_online ()) { |
379 if (notify) |
351 if ( handler ) |
380 notify (userdata); |
352 handler ( NULL, userdata ); // XXX |
|
353 if ( notify ) |
|
354 notify ( userdata ); |
381 return NULL; |
355 return NULL; |
382 } |
356 } |
383 |
357 |
384 { // send request |
358 { // send request |
385 LmMessage *request; |
359 LmMessage * request; |
386 LmMessageNode *node; |
360 LmMessageNode * node; |
387 GError *error = NULL; |
361 LmMessageHandler * lhandler; |
388 LmMessageHandler *lhandler; |
362 GError * error = NULL; |
|
363 disco_request_t * cb = g_slice_new (disco_request_t); |
389 |
364 |
390 request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
365 request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); |
391 node = lm_message_get_node (request); |
366 node = lm_message_get_node (request); |
392 node = lm_message_node_add_child (node, "query", NULL); |
367 node = lm_message_node_add_child (node, "query", NULL); |
393 lm_message_node_set_attribute (node, "xmlns", NS_DISCO_ITEMS); |
368 lm_message_node_set_attribute (node, "xmlns", NS_DISCO_ITEMS); |
394 if (dnode) |
369 if (dnode) |
395 lm_message_node_set_attribute (node, "node", dnode); |
370 lm_message_node_set_attribute (node, "node", dnode); |
396 |
371 |
397 { |
372 lhandler = lm_message_handler_new (disco_reply_handler, cb, NULL); |
398 disco_items_reply_handler_t *cb = g_slice_new (disco_items_reply_handler_t); |
373 |
399 |
374 cb -> reply_handler = lhandler; |
400 lhandler = lm_message_handler_new (disco_items_reply_handler, cb, disco_items_reply_handler_destroy_notify); |
375 cb -> type = DISCO_ITEMS_REQUEST; |
401 |
376 cb -> handler.items = handler; |
402 cb -> handler = handler; |
377 cb -> data = userdata; |
403 cb -> data = userdata; |
378 cb -> notify = notify; |
404 cb -> notify = notify; |
379 |
405 |
380 disco_requests = g_slist_append ( disco_requests, cb ); |
406 reply_handlers = g_slist_append (reply_handlers, lhandler); |
381 |
407 |
382 lm_connection_send_with_reply (lconnection, request, lhandler, &error); |
408 lm_connection_send_with_reply (lconnection, request, lhandler, &error); |
383 |
409 |
384 if (error) { |
410 if (error) { |
385 scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
411 // XXX destroy handler and return NULL? |
386 g_error_free (error); |
412 scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message); |
387 handler ( NULL, userdata ); |
413 g_error_free (error); |
388 disco_request_free ( cb ); |
414 } |
389 cb = NULL; |
415 |
390 } |
416 lm_message_handler_unref (lhandler); |
391 |
417 } |
392 lm_message_handler_unref (lhandler); |
418 |
|
419 lm_message_unref (request); |
393 lm_message_unref (request); |
420 |
394 |
421 return lhandler; |
395 return cb; |
422 } |
396 } |
423 } |
397 } |
424 |
398 |
425 void disco_cancel_request (gpointer id) |
399 void disco_cancel_request ( gpointer id ) |
426 { |
400 { |
427 GSList *hel; |
401 if ( g_slist_find ( disco_requests, id ) ) { |
428 |
402 disco_request_t * cb = id; |
429 for (hel = reply_handlers; hel; hel = hel -> next) { |
403 disco_request_free ( cb ); |
430 if (hel -> data == id) { |
|
431 LmMessageHandler *handler = id; |
|
432 reply_handlers = g_slist_remove (reply_handlers, handler); |
|
433 lm_message_handler_invalidate (handler); |
|
434 #ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER |
|
435 if (lconnection) |
|
436 lm_connection_unregister_reply_handler (lconnection, handler); |
|
437 #endif |
|
438 return; |
|
439 } |
|
440 } |
404 } |
441 |
405 |
442 return; |
406 return; |
443 } |
407 } |
444 |
408 |