Mercurial > hg
comparison mcabber/src/xmpp_iq.c @ 1598:a087125d8fc8
Replace libjabber with loudmouth
author | franky |
---|---|
date | Sun, 11 Oct 2009 15:38:32 +0200 |
parents | mcabber/src/jabglue.c@1802b926e3fa |
children | dcd5d4c75199 |
comparison
equal
deleted
inserted
replaced
1597:4f59a414217e | 1598:a087125d8fc8 |
---|---|
1 /* See xmpp.c file for copyright and license details. */ | |
2 | |
3 static LmHandlerResult handle_iq_command_set_status(LmMessageHandler *h, | |
4 LmConnection *c, | |
5 LmMessage *m, | |
6 gpointer ud); | |
7 | |
8 static LmHandlerResult handle_iq_command_leave_groupchats(LmMessageHandler *h, | |
9 LmConnection *c, | |
10 LmMessage *m, | |
11 gpointer ud); | |
12 | |
13 inline double seconds_since_last_use(void); | |
14 | |
15 struct adhoc_command { | |
16 char *name; | |
17 char *description; | |
18 bool only_for_self; | |
19 LmHandleMessageFunction callback; | |
20 }; | |
21 | |
22 const struct adhoc_command adhoc_command_list[] = { | |
23 { "http://jabber.org/protocol/rc#set-status", | |
24 "Change client status", | |
25 1, | |
26 &handle_iq_command_set_status }, | |
27 { "http://jabber.org/protocol/rc#leave-groupchats", | |
28 "Leave groupchat(s)", | |
29 1, | |
30 &handle_iq_command_leave_groupchats }, | |
31 { NULL, NULL, 0, NULL }, | |
32 }; | |
33 | |
34 struct adhoc_status { | |
35 char *name; // the name used by adhoc | |
36 char *description; | |
37 char *status; // the string, used by setstus | |
38 }; | |
39 // It has to match imstatus of roster.h! | |
40 const struct adhoc_status adhoc_status_list[] = { | |
41 {"offline", "Offline", "offline"}, | |
42 {"online", "Online", "avail"}, | |
43 {"chat", "Chat", "free"}, | |
44 {"dnd", "Do not disturb", "dnd"}, | |
45 {"xd", "Extended away", "notavail"}, | |
46 {"away", "Away", "away"}, | |
47 {"invisible", "Invisible", "invisible"}, | |
48 {NULL, NULL, NULL}, | |
49 }; | |
50 | |
51 static char *generate_session_id(char *prefix) | |
52 { | |
53 char *result; | |
54 static int counter = 0; | |
55 counter++; | |
56 // TODO better use timestamp? | |
57 result = g_strdup_printf("%s-%i", prefix, counter); | |
58 return result; | |
59 } | |
60 | |
61 static LmMessage *lm_message_new_iq_error(LmMessage *m, guint error) | |
62 { | |
63 LmMessage *r; | |
64 LmMessageNode *err; | |
65 int i; | |
66 | |
67 for (i = 0; xmpp_errors[i].code; ++i) | |
68 if (xmpp_errors[i].code == error) | |
69 break; | |
70 g_return_val_if_fail(xmpp_errors[i].code > 0, NULL); | |
71 | |
72 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_ERROR); | |
73 err = lm_message_node_add_child(r->node, "error", NULL); | |
74 lm_message_node_set_attribute(err, "code", xmpp_errors[i].code_str); | |
75 lm_message_node_set_attribute(err, "type", xmpp_errors[i].type); | |
76 lm_message_node_set_attribute | |
77 (lm_message_node_add_child(err, | |
78 xmpp_errors[i].condition, NULL), | |
79 "xmlns", NS_XMPP_STANZAS); | |
80 | |
81 return r; | |
82 } | |
83 | |
84 static void send_iq_error(LmConnection *c, LmMessage *m, guint error) | |
85 { | |
86 LmMessage *r; | |
87 r = lm_message_new_iq_error(m, error); | |
88 lm_connection_send(c, r, NULL); | |
89 lm_message_unref(r); | |
90 } | |
91 | |
92 static void lm_message_node_add_dataform_result(LmMessageNode *node, | |
93 const char *message) | |
94 { | |
95 LmMessageNode *x, *field; | |
96 | |
97 x = lm_message_node_add_child(node, "x", NULL); | |
98 lm_message_node_set_attributes(x, | |
99 "type", "result", | |
100 "xmlns", "jabber:x:data", | |
101 NULL); | |
102 field = lm_message_node_add_child(x, "field", NULL); | |
103 lm_message_node_set_attributes(field, | |
104 "type", "text-single", | |
105 "var", "message", | |
106 NULL); | |
107 lm_message_node_add_child(field, "value", message); | |
108 } | |
109 | |
110 static LmHandlerResult handle_iq_commands_list(LmMessageHandler *h, | |
111 LmConnection *c, | |
112 LmMessage *m, gpointer ud) | |
113 { | |
114 LmMessage *iq; | |
115 LmMessageNode *query; | |
116 const char *requester_jid; | |
117 const struct adhoc_command *command; | |
118 const char *node; | |
119 gboolean from_self; | |
120 | |
121 iq = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
122 query = lm_message_node_add_child(iq->node, "query", NULL); | |
123 node = lm_message_node_get_attribute | |
124 (lm_message_node_get_child(m->node, "query"), | |
125 "node"); | |
126 if (node) | |
127 lm_message_node_set_attribute(query, "node", node); | |
128 | |
129 requester_jid = lm_message_get_from(m); | |
130 from_self = jid_equal(lm_connection_get_jid(c), requester_jid); | |
131 | |
132 for (command = adhoc_command_list ; command->name ; command++) { | |
133 if (!command->only_for_self || from_self) { | |
134 lm_message_node_set_attributes | |
135 (lm_message_node_add_child(query, "item", NULL), | |
136 "node", command->name, | |
137 "name", command->description, | |
138 "jid", lm_connection_get_jid(c), | |
139 NULL); | |
140 } | |
141 } | |
142 | |
143 lm_connection_send(c, iq, NULL); | |
144 lm_message_unref(iq); | |
145 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
146 } | |
147 | |
148 static LmHandlerResult handle_iq_command_set_status(LmMessageHandler *h, | |
149 LmConnection *c, | |
150 LmMessage *m, gpointer ud) | |
151 { | |
152 const char *action, *node; | |
153 char *sessionid; | |
154 LmMessage *iq; | |
155 LmMessageNode *command, *x, *y; | |
156 const struct adhoc_status *s; | |
157 | |
158 x = lm_message_node_get_child(m->node, "command"); | |
159 action = lm_message_node_get_attribute(x, "action"); | |
160 node = lm_message_node_get_attribute(x, "node"); | |
161 sessionid = (char *)lm_message_node_get_attribute(x, "sessionid"); | |
162 | |
163 iq = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
164 command = lm_message_node_add_child(iq->node, "command", NULL); | |
165 lm_message_node_set_attribute(command, "node", node); | |
166 lm_message_node_set_attribute(command, "xmlns", NS_COMMANDS); | |
167 | |
168 if (!sessionid) { | |
169 sessionid = generate_session_id("set-status"); | |
170 lm_message_node_set_attribute(command, "sessionid", sessionid); | |
171 g_free(sessionid); | |
172 sessionid = NULL; | |
173 lm_message_node_set_attribute(command, "status", "executing"); | |
174 | |
175 x = lm_message_node_add_child(command, "x", NULL); | |
176 lm_message_node_set_attribute(x, "type", "form"); | |
177 lm_message_node_set_attribute(x, "xmlns", "jabber:x:data"); | |
178 | |
179 lm_message_node_add_child(x, "title", "Change Status"); | |
180 | |
181 lm_message_node_add_child(x, "instructions", | |
182 "Choose the status and status message"); | |
183 | |
184 // TODO see if factorisation is possible | |
185 y = lm_message_node_add_child(x, "field", NULL); | |
186 lm_message_node_set_attribute(y, "type", "hidden"); | |
187 lm_message_node_set_attribute(y, "var", "FORM_TYPE"); | |
188 | |
189 lm_message_node_add_child(y, "value", "http://jabber.org/protocol/rc"); | |
190 | |
191 y = lm_message_node_add_child(x, "field", NULL); | |
192 lm_message_node_set_attributes(y, | |
193 "type", "list-single", | |
194 "var", "status", | |
195 "label", "Status", | |
196 NULL); | |
197 lm_message_node_add_child(y, "required", NULL); | |
198 | |
199 // XXX: ugly | |
200 lm_message_node_add_child(y, "value", | |
201 adhoc_status_list[xmpp_getstatus()].name); | |
202 for (s = adhoc_status_list; s->name; s++) { | |
203 LmMessageNode *option = lm_message_node_add_child(y, "option", NULL); | |
204 lm_message_node_add_child(option, "value", s->name); | |
205 lm_message_node_set_attribute(option, "label", s->description); | |
206 } | |
207 // TODO add priority ? | |
208 // I do not think this is useful, user should not have to care of the | |
209 // priority like gossip and gajim do (misc) | |
210 lm_message_node_set_attributes | |
211 (lm_message_node_add_child(x, "field", NULL), | |
212 "type", "text-multi", | |
213 "var", "status-message", | |
214 "label", "Message", | |
215 NULL); | |
216 } else if (action && !strcmp(action, "cancel")) { | |
217 lm_message_node_set_attribute(command, "status", "canceled"); | |
218 } else { // (if sessionid and not canceled) | |
219 y = lm_message_node_find_xmlns(x, "jabber:x:data"); //x?xmlns=jabber:x:data | |
220 if (y) { | |
221 const char *value=NULL, *message=NULL; | |
222 LmMessageNode *fields, *field; | |
223 field = fields = lm_message_node_get_child(y, "field"); //field?var=status | |
224 while (field && strcmp("status", | |
225 lm_message_node_get_attribute(field, "var"))) | |
226 field = field->next; | |
227 field = lm_message_node_get_child(field, "value"); | |
228 if (field) | |
229 value = lm_message_node_get_value(field); | |
230 field = fields; //field?var=status-message | |
231 while (field && strcmp("status-message", | |
232 lm_message_node_get_attribute(field, "var"))) | |
233 field = field->next; | |
234 field = lm_message_node_get_child(field, "value"); | |
235 if (field) | |
236 message = lm_message_node_get_value(field); | |
237 if (value) { | |
238 for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++); | |
239 if (s->name) { | |
240 char *status = g_strdup_printf("%s %s", s->status, | |
241 message ? message : ""); | |
242 cmd_setstatus(NULL, status); | |
243 g_free(status); | |
244 lm_message_node_set_attribute(command, "status", "completed"); | |
245 lm_message_node_add_dataform_result(command, | |
246 "Status has been changed"); | |
247 } | |
248 } | |
249 } | |
250 } | |
251 if (sessionid) | |
252 lm_message_node_set_attribute(command, "sessionid", sessionid); | |
253 lm_connection_send(c, iq, NULL); | |
254 lm_message_unref(iq); | |
255 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
256 } | |
257 | |
258 static void _callback_foreach_buddy_groupchat(gpointer rosterdata, void *param) | |
259 { | |
260 LmMessageNode *field, *value, *option; | |
261 const char *room_jid, *nickname; | |
262 char *desc; | |
263 | |
264 room_jid = buddy_getjid(rosterdata); | |
265 if (!room_jid) return; | |
266 nickname = buddy_getnickname(rosterdata); | |
267 if (!nickname) return; | |
268 field = param; | |
269 | |
270 option = lm_message_node_add_child(field, "option", NULL); | |
271 value = lm_message_node_add_child(option, "value", room_jid); | |
272 desc = g_strdup_printf("%s on %s", nickname, room_jid); | |
273 lm_message_node_set_attribute(option, "label", desc); | |
274 g_free(desc); | |
275 } | |
276 | |
277 static LmHandlerResult handle_iq_command_leave_groupchats(LmMessageHandler *h, | |
278 LmConnection *c, | |
279 LmMessage *m, | |
280 gpointer ud) | |
281 { | |
282 const char *action, *node; | |
283 char *sessionid; | |
284 LmMessage *iq; | |
285 LmMessageNode *command, *x; | |
286 | |
287 x = lm_message_node_get_child(m->node, "command"); | |
288 action = lm_message_node_get_attribute(x, "action"); | |
289 node = lm_message_node_get_attribute(x, "node"); | |
290 sessionid = (char*)lm_message_node_get_attribute(x, "sessionid"); | |
291 | |
292 iq = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
293 command = lm_message_node_add_child(iq->node, "command", NULL); | |
294 lm_message_node_set_attributes(command, | |
295 "node", node, | |
296 "xmlns", NS_COMMANDS, | |
297 NULL); | |
298 | |
299 if (!sessionid) { | |
300 LmMessageNode *field; | |
301 | |
302 sessionid = generate_session_id("leave-groupchats"); | |
303 lm_message_node_set_attribute(command, "sessionid", sessionid); | |
304 g_free(sessionid); | |
305 sessionid = NULL; | |
306 lm_message_node_set_attribute(command, "status", "executing"); | |
307 | |
308 x = lm_message_node_add_child(command, "x", NULL); | |
309 lm_message_node_set_attributes(x, | |
310 "type", "form", | |
311 "xmlns", "jabber:x:data", | |
312 NULL); | |
313 | |
314 lm_message_node_add_child(x, "title", "Leave groupchat(s)"); | |
315 | |
316 lm_message_node_add_child(x, "instructions", | |
317 "What groupchats do you want to leave?"); | |
318 | |
319 field = lm_message_node_add_child(x, "field", NULL); | |
320 lm_message_node_set_attributes(field, | |
321 "type", "hidden", | |
322 "var", "FORM_TYPE", | |
323 NULL); | |
324 | |
325 lm_message_node_add_child(field, "value", | |
326 "http://jabber.org/protocol/rc"); | |
327 | |
328 field = lm_message_node_add_child(x, "field", NULL); | |
329 lm_message_node_set_attributes(field, | |
330 "type", "list-multi", | |
331 "var", "groupchats", | |
332 "label", "Groupchats: ", | |
333 NULL); | |
334 lm_message_node_add_child(field, "required", NULL); | |
335 | |
336 foreach_buddy(ROSTER_TYPE_ROOM, &_callback_foreach_buddy_groupchat, field); | |
337 //TODO: return an error if we are not connected to groupchats | |
338 } else if (action && !strcmp(action, "cancel")) { | |
339 lm_message_node_set_attribute(command, "status", "canceled"); | |
340 } else { // (if sessionid and not canceled) | |
341 LmMessageNode *form = lm_message_node_find_xmlns(x, "jabber:x:data");//TODO | |
342 if (form) { | |
343 LmMessageNode *field; | |
344 | |
345 lm_message_node_set_attribute(command, "status", "completed"); | |
346 //TODO: implement sth. like "field?var=groupchats" in xmlnode... | |
347 field = lm_message_node_get_child(form, "field"); | |
348 while (field && strcmp("groupchats", | |
349 lm_message_node_get_attribute(field, "var"))) | |
350 field = field->next; | |
351 | |
352 for (x = field->children ; x ; x = x->next) | |
353 { | |
354 LmMessageNode *to_leave = lm_message_node_get_child(x, "value"); | |
355 if (to_leave) { | |
356 GList* b = buddy_search_jid(lm_message_node_get_value(to_leave)); | |
357 if (b) | |
358 cmd_room_leave(b->data, "Requested by remote command"); | |
359 } | |
360 } | |
361 lm_message_node_add_dataform_result(command, | |
362 "Groupchats have been left"); | |
363 } | |
364 } | |
365 if (sessionid) | |
366 lm_message_node_set_attribute(command, "sessionid", sessionid); | |
367 lm_connection_send(c, iq, NULL); | |
368 lm_message_unref(iq); | |
369 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
370 } | |
371 | |
372 static LmHandlerResult handle_iq_commands(LmMessageHandler *h, | |
373 LmConnection *c, | |
374 LmMessage *m, gpointer ud) | |
375 { | |
376 const char *requester_jid = NULL; | |
377 LmMessageNode *cmd; | |
378 const struct adhoc_command *command; | |
379 | |
380 // mcabber has only partial XEP-0146 support... | |
381 if (LM_MESSAGE_SUB_TYPE_SET != lm_message_get_sub_type(m)) | |
382 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; | |
383 | |
384 requester_jid = lm_message_get_from(m); | |
385 | |
386 cmd = lm_message_node_get_child(m->node, "command"); | |
387 if (jid_equal(lm_connection_get_jid(c), requester_jid)) { | |
388 const char *action, *node; | |
389 action = lm_message_node_get_attribute(cmd, "action"); | |
390 node = lm_message_node_get_attribute(cmd, "node"); | |
391 // action can be NULL, in which case it seems to take the default, | |
392 // ie execute | |
393 if (!action || !strcmp(action, "execute") || !strcmp(action, "cancel") | |
394 || !strcmp(action, "next") || !strcmp(action, "complete")) { | |
395 for (command = adhoc_command_list; command->name; command++) { | |
396 if (!strcmp(node, command->name)) | |
397 command->callback(h, c, m, ud); | |
398 } | |
399 // "prev" action will get there, as we do not implement it, | |
400 // and do not authorize it | |
401 } else { | |
402 LmMessage *r; | |
403 LmMessageNode *err; | |
404 r = lm_message_new_iq_error(m, XMPP_ERROR_BAD_REQUEST); | |
405 err = lm_message_node_get_child(r->node, "error"); | |
406 lm_message_node_set_attribute | |
407 (lm_message_node_add_child(err, "malformed-action", NULL), | |
408 "xmlns", NS_COMMANDS); | |
409 lm_connection_send(c, r, NULL); | |
410 lm_message_unref(r); | |
411 } | |
412 } else { | |
413 send_iq_error(c, m, XMPP_ERROR_FORBIDDEN); | |
414 } | |
415 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
416 } | |
417 | |
418 | |
419 static LmHandlerResult handle_iq_disco_items(LmMessageHandler *h, | |
420 LmConnection *c, | |
421 LmMessage *m, gpointer ud) | |
422 { | |
423 LmMessageNode *query; | |
424 const char *node; | |
425 query = lm_message_node_get_child(m->node, "query"); | |
426 node = lm_message_node_get_attribute(query, "node"); | |
427 if (node) { | |
428 if (!strcmp(node, NS_COMMANDS)) { | |
429 return handle_iq_commands_list(NULL, c, m, ud); | |
430 } else { | |
431 send_iq_error(c, m, XMPP_ERROR_NOT_IMPLEMENTED); | |
432 } | |
433 } else { | |
434 // not sure about this one | |
435 send_iq_error(c, m, XMPP_ERROR_NOT_IMPLEMENTED); | |
436 } | |
437 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
438 } | |
439 | |
440 | |
441 // disco_info_set_ext(ansquery, ext) | |
442 // Add features attributes to ansquery for extension ext. | |
443 static void disco_info_set_ext(LmMessageNode *ansquery, const char *ext) | |
444 { | |
445 char *nodename = g_strdup_printf("%s#%s", MCABBER_CAPS_NODE, ext); | |
446 lm_message_node_set_attribute(ansquery, "node", nodename); | |
447 g_free(nodename); | |
448 if (!strcasecmp(ext, "csn")) { | |
449 // I guess it's ok to send this even if it's not compiled in. | |
450 lm_message_node_set_attribute(lm_message_node_add_child(ansquery, | |
451 "feature", NULL), | |
452 "var", NS_CHATSTATES); | |
453 } | |
454 if (!strcasecmp(ext, "iql")) { | |
455 // I guess it's ok to send this even if it's not compiled in. | |
456 lm_message_node_set_attribute(lm_message_node_add_child(ansquery, | |
457 "feature", NULL), | |
458 "var", NS_LAST); | |
459 } | |
460 } | |
461 | |
462 // disco_info_set_default(ansquery, entitycaps) | |
463 // Add features attributes to ansquery. If entitycaps is TRUE, assume | |
464 // that we're answering an Entity Caps request (if not, the request was | |
465 // a basic discovery query). | |
466 // Please change the entity version string if you modify mcabber disco | |
467 // source code, so that it doesn't conflict with the upstream client. | |
468 static void disco_info_set_default(LmMessageNode *ansquery, guint entitycaps) | |
469 { | |
470 LmMessageNode *y; | |
471 char *eversion; | |
472 | |
473 eversion = g_strdup_printf("%s#%s", MCABBER_CAPS_NODE, entity_version()); | |
474 lm_message_node_set_attribute(ansquery, "node", eversion); | |
475 g_free(eversion); | |
476 | |
477 y = lm_message_node_add_child(ansquery, "identity", NULL); | |
478 | |
479 lm_message_node_set_attributes(y, | |
480 "category", "client", | |
481 "type", "pc", | |
482 "name", PACKAGE_NAME, | |
483 NULL); | |
484 | |
485 lm_message_node_set_attribute | |
486 (lm_message_node_add_child(ansquery, "feature", NULL), | |
487 "var", NS_DISCO_INFO); | |
488 lm_message_node_set_attribute | |
489 (lm_message_node_add_child(ansquery, "feature", NULL), | |
490 "var", NS_MUC); | |
491 #ifdef JEP0085 | |
492 // Advertise ChatStates only if we're not using Entity Capabilities | |
493 if (!entitycaps) | |
494 lm_message_node_set_attribute | |
495 (lm_message_node_add_child(ansquery, "feature", NULL), | |
496 "var", NS_CHATSTATES); | |
497 #endif | |
498 lm_message_node_set_attribute | |
499 (lm_message_node_add_child(ansquery, "feature", NULL), | |
500 "var", NS_TIME); | |
501 lm_message_node_set_attribute | |
502 (lm_message_node_add_child(ansquery, "feature", NULL), | |
503 "var", NS_XMPP_TIME); | |
504 lm_message_node_set_attribute | |
505 (lm_message_node_add_child(ansquery, "feature", NULL), | |
506 "var", NS_VERSION); | |
507 lm_message_node_set_attribute | |
508 (lm_message_node_add_child(ansquery, "feature", NULL), | |
509 "var", NS_PING); | |
510 lm_message_node_set_attribute | |
511 (lm_message_node_add_child(ansquery, "feature", NULL), | |
512 "var", NS_COMMANDS); | |
513 if (!entitycaps) | |
514 lm_message_node_set_attribute | |
515 (lm_message_node_add_child(ansquery, "feature", NULL), | |
516 "var", NS_LAST); | |
517 } | |
518 | |
519 static LmHandlerResult handle_iq_disco_info(LmMessageHandler *h, | |
520 LmConnection *c, | |
521 LmMessage *m, gpointer ud) | |
522 { | |
523 LmMessage *r; | |
524 LmMessageNode *query, *tmp; | |
525 const char *node = NULL; | |
526 | |
527 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
528 query = lm_message_node_add_child(r->node, "query", NULL); | |
529 lm_message_node_set_attribute(query, "xmlns", NS_DISCO_INFO); | |
530 tmp = lm_message_node_find_child(m->node, "query"); | |
531 if (tmp) | |
532 node = lm_message_node_get_attribute(tmp, "node"); | |
533 if (node && startswith(node, MCABBER_CAPS_NODE "#", FALSE)) { | |
534 const char *param = node+strlen(MCABBER_CAPS_NODE)+1; | |
535 if (!strcmp(param, entity_version())) | |
536 disco_info_set_default(query, TRUE); // client#version | |
537 else | |
538 disco_info_set_ext(query, param); // client#extension | |
539 } else { | |
540 // Basic discovery request | |
541 disco_info_set_default(query, FALSE); | |
542 } | |
543 | |
544 lm_connection_send(c, r, NULL); | |
545 lm_message_unref(r); | |
546 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
547 } | |
548 | |
549 static LmHandlerResult handle_iq_roster(LmMessageHandler *h, LmConnection *c, | |
550 LmMessage *m, gpointer ud) | |
551 { | |
552 LmMessageNode *y; | |
553 const char *fjid, *name, *group, *sub, *ask; | |
554 char *cleanalias; | |
555 enum subscr esub; | |
556 int need_refresh = FALSE; | |
557 guint roster_type; | |
558 | |
559 for (y = lm_message_node_find_child(lm_message_node_find_xmlns | |
560 (m->node, NS_ROSTER), | |
561 "item"); | |
562 y; | |
563 y = y->next) { | |
564 char *name_tmp = NULL; | |
565 | |
566 fjid = lm_message_node_get_attribute(y, "jid"); | |
567 name = lm_message_node_get_attribute(y, "name"); | |
568 sub = lm_message_node_get_attribute(y, "subscription"); | |
569 ask = lm_message_node_get_attribute(y, "ask"); | |
570 | |
571 if (lm_message_node_find_child(y, "group")) | |
572 group = lm_message_node_get_value(lm_message_node_find_child(y, "group")); | |
573 else | |
574 group = NULL; | |
575 | |
576 if (!fjid) | |
577 continue; | |
578 | |
579 cleanalias = jidtodisp(fjid); | |
580 | |
581 esub = sub_none; | |
582 if (sub) { | |
583 if (!strcmp(sub, "to")) esub = sub_to; | |
584 else if (!strcmp(sub, "from")) esub = sub_from; | |
585 else if (!strcmp(sub, "both")) esub = sub_both; | |
586 else if (!strcmp(sub, "remove")) esub = sub_remove; | |
587 } | |
588 | |
589 if (esub == sub_remove) { | |
590 roster_del_user(cleanalias); | |
591 scr_LogPrint(LPRINT_LOGNORM, "Buddy <%s> has been removed " | |
592 "from the roster", cleanalias); | |
593 g_free(cleanalias); | |
594 need_refresh = TRUE; | |
595 continue; | |
596 } | |
597 | |
598 if (ask && !strcmp(ask, "subscribe")) | |
599 esub |= sub_pending; | |
600 | |
601 if (!name) { | |
602 if (!settings_opt_get_int("roster_hide_domain")) { | |
603 name = cleanalias; | |
604 } else { | |
605 char *p; | |
606 name = name_tmp = g_strdup(cleanalias); | |
607 p = strchr(name_tmp, JID_DOMAIN_SEPARATOR); | |
608 if (p) *p = '\0'; | |
609 } | |
610 } | |
611 | |
612 // Tricky... :-\ My guess is that if there is no JID_DOMAIN_SEPARATOR, | |
613 // this is an agent. | |
614 if (strchr(cleanalias, JID_DOMAIN_SEPARATOR)) | |
615 roster_type = ROSTER_TYPE_USER; | |
616 else | |
617 roster_type = ROSTER_TYPE_AGENT; | |
618 | |
619 roster_add_user(cleanalias, name, group, roster_type, esub, 1); | |
620 | |
621 g_free(name_tmp); | |
622 g_free(cleanalias); | |
623 } | |
624 | |
625 buddylist_build(); | |
626 update_roster = TRUE; | |
627 if (need_refresh) | |
628 scr_UpdateBuddyWindow(); | |
629 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
630 } | |
631 | |
632 static LmHandlerResult handle_iq_ping(LmMessageHandler *h, LmConnection *c, | |
633 LmMessage *m, gpointer ud) | |
634 { | |
635 LmMessage *r; | |
636 | |
637 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
638 lm_connection_send(c, r, NULL); | |
639 lm_message_unref(r); | |
640 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
641 } | |
642 | |
643 double seconds_since_last_use(void) | |
644 { | |
645 return difftime(time(NULL), iqlast); | |
646 } | |
647 | |
648 static LmHandlerResult handle_iq_last(LmMessageHandler *h, LmConnection *c, | |
649 LmMessage *m, gpointer ud) | |
650 { | |
651 LmMessage *r; | |
652 LmMessageNode *query; | |
653 char *seconds; | |
654 | |
655 if (!settings_opt_get_int("iq_hide_requests")) { | |
656 scr_LogPrint(LPRINT_LOGNORM, "Received an IQ last time request from <%s>", | |
657 lm_message_get_from(m)); | |
658 } | |
659 | |
660 if (settings_opt_get_int("iq_last_disable") || | |
661 (settings_opt_get_int("iq_last_disable_when_notavail") && | |
662 xmpp_getstatus() == notavail)) | |
663 { | |
664 send_iq_error(c, m, XMPP_ERROR_SERVICE_UNAVAILABLE); | |
665 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
666 } | |
667 | |
668 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
669 query = lm_message_node_add_child(r->node, "query", NULL); | |
670 seconds = g_strdup_printf("%.0f", seconds_since_last_use()); | |
671 lm_message_node_set_attribute(query, "seconds", seconds); | |
672 g_free(seconds); | |
673 | |
674 lm_connection_send(c, r, NULL); | |
675 lm_message_unref(r); | |
676 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
677 } | |
678 | |
679 static LmHandlerResult handle_iq_version(LmMessageHandler *h, LmConnection *c, | |
680 LmMessage *m, gpointer ud) | |
681 { | |
682 LmMessage *r; | |
683 LmMessageNode *query; | |
684 char *os = NULL; | |
685 char *ver = mcabber_version(); | |
686 | |
687 if (!settings_opt_get_int("iq_hide_requests")) { | |
688 scr_LogPrint(LPRINT_LOGNORM, "Received an IQ version request from <%s>", | |
689 lm_message_get_from(m)); | |
690 } | |
691 if (!settings_opt_get_int("iq_version_hide_os")) { | |
692 struct utsname osinfo; | |
693 uname(&osinfo); | |
694 os = g_strdup_printf("%s %s %s", osinfo.sysname, osinfo.release, | |
695 osinfo.machine); | |
696 } | |
697 | |
698 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
699 | |
700 query = lm_message_node_add_child(r->node, "query", NULL); | |
701 | |
702 lm_message_node_add_child(query, "name", PACKAGE_NAME); | |
703 lm_message_node_add_child(query, "version", ver); | |
704 if (os) { | |
705 lm_message_node_add_child(query, "os", os); | |
706 g_free(os); | |
707 } | |
708 | |
709 g_free(ver); | |
710 lm_connection_send(c, r, NULL); | |
711 lm_message_unref(r); | |
712 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
713 } | |
714 | |
715 // This function borrows some code from the Pidgin project | |
716 static LmHandlerResult handle_iq_time(LmMessageHandler *h, LmConnection *c, | |
717 LmMessage *m, gpointer ud) | |
718 { | |
719 LmMessage *r; | |
720 LmMessageNode *query; | |
721 char *buf, *utf8_buf; | |
722 time_t now_t; | |
723 struct tm *now; | |
724 | |
725 time(&now_t); | |
726 | |
727 if (!settings_opt_get_int("iq_hide_requests")) { | |
728 scr_LogPrint(LPRINT_LOGNORM, "Received an IQ time request from <%s>", | |
729 lm_message_get_from(m)); | |
730 } | |
731 | |
732 buf = g_new0(char, 512); | |
733 | |
734 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
735 query = lm_message_node_add_child(r->node, "query", NULL); | |
736 | |
737 now = gmtime(&now_t); | |
738 | |
739 strftime(buf, 512, "%Y%m%dT%T", now); | |
740 lm_message_node_add_child(query, "utc", buf); | |
741 | |
742 now = localtime(&now_t); | |
743 | |
744 strftime(buf, 512, "%Z", now); | |
745 if ((utf8_buf = to_utf8(buf))) { | |
746 lm_message_node_add_child(query, "tz", utf8_buf); | |
747 g_free(utf8_buf); | |
748 } | |
749 | |
750 strftime(buf, 512, "%d %b %Y %T", now); | |
751 if ((utf8_buf = to_utf8(buf))) { | |
752 lm_message_node_add_child(query, "display", utf8_buf); | |
753 g_free(utf8_buf); | |
754 } | |
755 | |
756 lm_connection_send(c, r, NULL); | |
757 lm_message_unref(r); | |
758 g_free(buf); | |
759 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
760 } | |
761 | |
762 // This function borrows some code from the Pidgin project | |
763 static LmHandlerResult handle_iq_time202(LmMessageHandler *h, LmConnection *c, | |
764 LmMessage *m, gpointer ud) | |
765 { | |
766 LmMessage *r; | |
767 LmMessageNode *query; | |
768 char *buf, *utf8_buf; | |
769 time_t now_t; | |
770 struct tm *now; | |
771 char const *sign; | |
772 int diff = 0; | |
773 | |
774 time(&now_t); | |
775 | |
776 if (!settings_opt_get_int("iq_hide_requests")) { | |
777 scr_LogPrint(LPRINT_LOGNORM, "Received an IQ time request from <%s>", | |
778 lm_message_get_from(m)); | |
779 } | |
780 | |
781 buf = g_new0(char, 512); | |
782 | |
783 r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); | |
784 query = lm_message_node_add_child(r->node, "time", NULL); | |
785 lm_message_node_set_attribute(query, "xmlns", NS_XMPP_TIME); | |
786 | |
787 now = localtime(&now_t); | |
788 | |
789 if (now->tm_isdst >= 0) { | |
790 #if defined HAVE_TM_GMTOFF | |
791 diff = now->tm_gmtoff; | |
792 #elif defined HAVE_TIMEZONE | |
793 tzset(); | |
794 diff = -timezone; | |
795 #endif | |
796 } | |
797 | |
798 if (diff < 0) { | |
799 sign = "-"; | |
800 diff = -diff; | |
801 } else { | |
802 sign = "+"; | |
803 } | |
804 diff /= 60; | |
805 snprintf(buf, 512, "%c%02d:%02d", *sign, diff / 60, diff % 60); | |
806 if ((utf8_buf = to_utf8(buf))) { | |
807 lm_message_node_add_child(query, "tzo", utf8_buf); | |
808 g_free(utf8_buf); | |
809 } | |
810 | |
811 now = gmtime(&now_t); | |
812 | |
813 strftime(buf, 512, "%Y-%m-%dT%TZ", now); | |
814 lm_message_node_add_child(query, "utc", buf); | |
815 | |
816 lm_connection_send(c, r, NULL); | |
817 lm_message_unref(r); | |
818 g_free(buf); | |
819 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | |
820 } |