Mercurial > hg
comparison mcabber/src/xmpp_muc.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 void decline_invitation(event_muc_invitation *invitation, char *reason) | |
4 { | |
5 // cut and paste from xmpp_room_invite | |
6 LmMessage *m; | |
7 LmMessageNode *x, *y; | |
8 | |
9 if (!invitation) return; | |
10 if (!invitation->to || !invitation->from) return; | |
11 | |
12 m = lm_message_new(invitation->to, LM_MESSAGE_TYPE_MESSAGE); | |
13 | |
14 x = lm_message_node_add_child(m->node, "x", NULL); | |
15 lm_message_node_set_attribute(x, "xmlns", | |
16 "http://jabber.org/protocol/muc#user"); | |
17 | |
18 y = lm_message_node_add_child(x, "decline", NULL); | |
19 lm_message_node_set_attribute(y, "to", invitation->from); | |
20 | |
21 if (reason) | |
22 lm_message_node_add_child(y, "reason", reason); | |
23 | |
24 lm_connection_send(lconnection, m, NULL); | |
25 lm_message_unref(m); | |
26 } | |
27 | |
28 static int evscallback_invitation(eviqs *evp, guint evcontext) | |
29 { | |
30 event_muc_invitation *invitation = evp->data; | |
31 | |
32 // Sanity check | |
33 if (!invitation) { | |
34 // Shouldn't happen. | |
35 scr_LogPrint(LPRINT_LOGNORM, "Error in evs callback."); | |
36 return 0; | |
37 } | |
38 | |
39 if (evcontext == EVS_CONTEXT_TIMEOUT) { | |
40 scr_LogPrint(LPRINT_LOGNORM, "Event %s timed out, cancelled.", evp->id); | |
41 goto evscallback_invitation_free; | |
42 } | |
43 if (evcontext == EVS_CONTEXT_CANCEL) { | |
44 scr_LogPrint(LPRINT_LOGNORM, "Event %s cancelled.", evp->id); | |
45 goto evscallback_invitation_free; | |
46 } | |
47 if (!(evcontext & EVS_CONTEXT_USER)) | |
48 goto evscallback_invitation_free; | |
49 // Ok, let's work now. | |
50 // evcontext: 0, 1 == reject, accept | |
51 | |
52 if (evcontext & ~EVS_CONTEXT_USER) { | |
53 char *nickname = default_muc_nickname(invitation->to); | |
54 xmpp_room_join(invitation->to, nickname, invitation->passwd); | |
55 g_free(nickname); | |
56 } else { | |
57 scr_LogPrint(LPRINT_LOGNORM, "Invitation to %s refused.", invitation->to); | |
58 decline_invitation(invitation, NULL); | |
59 } | |
60 | |
61 evscallback_invitation_free: | |
62 g_free(invitation->to); | |
63 g_free(invitation->from); | |
64 g_free(invitation->passwd); | |
65 g_free(invitation->reason); | |
66 g_free(invitation); | |
67 evp->data = NULL; | |
68 return 0; | |
69 } | |
70 | |
71 // Join a MUC room | |
72 void xmpp_room_join(const char *room, const char *nickname, const char *passwd) | |
73 { | |
74 LmMessage *x; | |
75 LmMessageNode *y; | |
76 gchar *roomid; | |
77 GSList *room_elt; | |
78 | |
79 if (!lm_connection_is_authenticated(lconnection) || !room) return; | |
80 if (!nickname) return; | |
81 | |
82 roomid = g_strdup_printf("%s/%s", room, nickname); | |
83 if (check_jid_syntax(roomid)) { | |
84 scr_LogPrint(LPRINT_NORMAL, "<%s/%s> is not a valid Jabber room", room, | |
85 nickname); | |
86 g_free(roomid); | |
87 return; | |
88 } | |
89 | |
90 room_elt = roster_find(room, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_ROOM); | |
91 // Add room if it doesn't already exist | |
92 if (!room_elt) { | |
93 room_elt = roster_add_user(room, NULL, NULL, ROSTER_TYPE_ROOM, | |
94 sub_none, -1); | |
95 } else { | |
96 // Make sure this is a room (it can be a conversion user->room) | |
97 buddy_settype(room_elt->data, ROSTER_TYPE_ROOM); | |
98 } | |
99 // If insideroom is TRUE, this is a nickname change and we don't care here | |
100 if (!buddy_getinsideroom(room_elt->data)) { | |
101 // We're trying to enter a room | |
102 buddy_setnickname(room_elt->data, nickname); | |
103 } | |
104 | |
105 // Send the XML request | |
106 x = lm_message_new(roomid, LM_MESSAGE_TYPE_PRESENCE); | |
107 | |
108 x = lm_message_new_presence(mystatus, roomid, mystatusmsg); | |
109 y = lm_message_node_add_child(x->node, "x", NULL); | |
110 lm_message_node_set_attribute(y, "xmlns", "http://jabber.org/protocol/muc"); | |
111 if (passwd) | |
112 lm_message_node_add_child(y, "password", passwd); | |
113 | |
114 lm_connection_send(lconnection, x, NULL); | |
115 lm_message_unref(x); | |
116 g_free(roomid); | |
117 } | |
118 | |
119 // Invite a user to a MUC room | |
120 // room syntax: "room@server" | |
121 // reason can be null. | |
122 void xmpp_room_invite(const char *room, const char *fjid, const char *reason) | |
123 { | |
124 LmMessage *msg; | |
125 LmMessageNode *x, *y; | |
126 | |
127 if (!lm_connection_is_authenticated(lconnection) || !room || !fjid) return; | |
128 | |
129 msg = lm_message_new(room, LM_MESSAGE_TYPE_MESSAGE); | |
130 | |
131 x = lm_message_node_add_child(msg->node, "x", NULL); | |
132 lm_message_node_set_attribute(x, "xmlns", | |
133 "http://jabber.org/protocol/muc#user"); | |
134 | |
135 y = lm_message_node_add_child(x, "invite", NULL); | |
136 lm_message_node_set_attribute(y, "to", fjid); | |
137 | |
138 if (reason) | |
139 lm_message_node_add_child(y, "reason", reason); | |
140 | |
141 lm_connection_send(lconnection, msg, NULL); | |
142 lm_message_unref(msg); | |
143 } | |
144 | |
145 int xmpp_room_setattrib(const char *roomid, const char *fjid, | |
146 const char *nick, struct role_affil ra, | |
147 const char *reason) | |
148 { | |
149 LmMessage *iq; | |
150 LmMessageNode *query, *x; | |
151 | |
152 if (!lm_connection_is_authenticated(lconnection) || !roomid) return 1; | |
153 if (!fjid && !nick) return 1; | |
154 | |
155 if (check_jid_syntax((char*)roomid)) { | |
156 scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", roomid); | |
157 return 1; | |
158 } | |
159 if (fjid && check_jid_syntax((char*)fjid)) { | |
160 scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", fjid); | |
161 return 1; | |
162 } | |
163 | |
164 if (ra.type == type_affil && ra.val.affil == affil_outcast && !fjid) | |
165 return 1; // Shouldn't happen (jid mandatory when banning) | |
166 | |
167 iq = lm_message_new_with_sub_type(roomid, LM_MESSAGE_TYPE_IQ, | |
168 LM_MESSAGE_SUB_TYPE_SET); | |
169 query = lm_message_node_add_child(iq->node, "query", NULL); | |
170 lm_message_node_set_attribute(query, "xmlns", | |
171 "http://jabber.org/protocol/muc#admin"); | |
172 x = lm_message_node_add_child(query, "item", NULL); | |
173 | |
174 if (fjid) { | |
175 lm_message_node_set_attribute(x, "jid", fjid); | |
176 } else { // nickname | |
177 lm_message_node_set_attribute(x, "nick", nick); | |
178 } | |
179 | |
180 if (ra.type == type_affil) | |
181 lm_message_node_set_attribute(x, "affiliation", straffil[ra.val.affil]); | |
182 else if (ra.type == type_role) | |
183 lm_message_node_set_attribute(x, "role", strrole[ra.val.role]); | |
184 | |
185 if (reason) | |
186 lm_message_node_add_child(x, "reason", reason); | |
187 | |
188 lm_connection_send(lconnection, iq, NULL); | |
189 lm_message_unref(iq); | |
190 | |
191 return 0; | |
192 } | |
193 | |
194 // Unlock a MUC room | |
195 // room syntax: "room@server" | |
196 void xmpp_room_unlock(const char *room) | |
197 { | |
198 LmMessageNode *y, *z; | |
199 LmMessage *iq; | |
200 | |
201 if (!lm_connection_is_authenticated(lconnection) || !room) return; | |
202 | |
203 iq = lm_message_new_with_sub_type(room, LM_MESSAGE_TYPE_IQ, | |
204 LM_MESSAGE_SUB_TYPE_SET); | |
205 lm_message_node_set_attribute(iq->node, "xmlns", | |
206 "http://jabber.org/protocol/muc#owner"); | |
207 | |
208 | |
209 y = lm_message_node_add_child(iq->node, "query", NULL); | |
210 z = lm_message_node_add_child(y, "x", NULL); | |
211 lm_message_node_set_attribute(z, "xmlns", "jabber:x:data"); | |
212 lm_message_node_set_attribute(z, "type", "submit"); | |
213 | |
214 lm_connection_send(lconnection, iq, NULL); | |
215 lm_message_unref(iq); | |
216 } | |
217 | |
218 // Destroy a MUC room | |
219 // room syntax: "room@server" | |
220 void xmpp_room_destroy(const char *room, const char *venue, const char *reason) | |
221 { | |
222 LmMessage *iq; | |
223 LmMessageNode *query, *x; | |
224 | |
225 if (!lm_connection_is_authenticated(lconnection) || !room) return; | |
226 | |
227 iq = lm_message_new_with_sub_type(room, LM_MESSAGE_TYPE_IQ, | |
228 LM_MESSAGE_SUB_TYPE_SET); | |
229 query = lm_message_node_add_child(iq->node, "query", NULL); | |
230 lm_message_node_set_attribute(query, "xmlns", | |
231 "http://jabber.org/protocol/muc#owner"); | |
232 x = lm_message_node_add_child(query, "destroy", NULL); | |
233 | |
234 if (venue && *venue) | |
235 lm_message_node_set_attribute(x, "jid", venue); | |
236 | |
237 if (reason) | |
238 lm_message_node_add_child(x, "reason", reason); | |
239 | |
240 lm_connection_send(lconnection, iq, NULL); | |
241 lm_message_unref(iq); | |
242 } | |
243 | |
244 // muc_get_item_info(...) | |
245 // Get room member's information from xmlndata. | |
246 // The variables must be initialized before calling this function, | |
247 // because they are not touched if the relevant information is missing. | |
248 static void muc_get_item_info(const char *from, LmMessageNode *xmldata, | |
249 enum imrole *mbrole, enum imaffiliation *mbaffil, | |
250 const char **mbjid, const char **mbnick, | |
251 const char **actorjid, const char **reason) | |
252 { | |
253 LmMessageNode *y, *z; | |
254 const char *p; | |
255 | |
256 y = lm_message_node_find_child(xmldata, "item"); | |
257 if (!y) | |
258 return; | |
259 | |
260 p = lm_message_node_get_attribute(y, "affiliation"); | |
261 if (p) { | |
262 if (!strcmp(p, "owner")) *mbaffil = affil_owner; | |
263 else if (!strcmp(p, "admin")) *mbaffil = affil_admin; | |
264 else if (!strcmp(p, "member")) *mbaffil = affil_member; | |
265 else if (!strcmp(p, "outcast")) *mbaffil = affil_outcast; | |
266 else if (!strcmp(p, "none")) *mbaffil = affil_none; | |
267 else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown affiliation \"%s\"", | |
268 from, p); | |
269 } | |
270 p = lm_message_node_get_attribute(y, "role"); | |
271 if (p) { | |
272 if (!strcmp(p, "moderator")) *mbrole = role_moderator; | |
273 else if (!strcmp(p, "participant")) *mbrole = role_participant; | |
274 else if (!strcmp(p, "visitor")) *mbrole = role_visitor; | |
275 else if (!strcmp(p, "none")) *mbrole = role_none; | |
276 else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown role \"%s\"", | |
277 from, p); | |
278 } | |
279 *mbjid = lm_message_node_get_attribute(y, "jid"); | |
280 *mbnick = lm_message_node_get_attribute(y, "nick"); | |
281 // For kick/ban, there can be actor and reason tags | |
282 *reason = lm_message_node_get_child_value(y, "reason"); | |
283 z = lm_message_node_find_child(y, "actor"); | |
284 if (z) | |
285 *actorjid = lm_message_node_get_attribute(z, "jid"); | |
286 } | |
287 | |
288 // muc_handle_join(...) | |
289 // Handle a join event in a MUC room. | |
290 // This function will return the new_member value TRUE if somebody else joins | |
291 // the room (and FALSE if _we_ are joining the room). | |
292 static bool muc_handle_join(const GSList *room_elt, const char *rname, | |
293 const char *roomjid, const char *ournick, | |
294 enum room_printstatus printstatus, | |
295 time_t usttime, int log_muc_conf) | |
296 { | |
297 bool new_member = FALSE; // True if somebody else joins the room (not us) | |
298 gchar *mbuf; | |
299 | |
300 if (!buddy_getinsideroom(room_elt->data)) { | |
301 // We weren't inside the room yet. Now we are. | |
302 // However, this could be a presence packet from another room member | |
303 | |
304 buddy_setinsideroom(room_elt->data, TRUE); | |
305 // Set the message flag unless we're already in the room buffer window | |
306 scr_setmsgflag_if_needed(roomjid, FALSE); | |
307 // Add a message to the tracelog file | |
308 mbuf = g_strdup_printf("You have joined %s as \"%s\"", roomjid, ournick); | |
309 scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); | |
310 g_free(mbuf); | |
311 mbuf = g_strdup_printf("You have joined as \"%s\"", ournick); | |
312 | |
313 // The 1st presence message could be for another room member | |
314 if (strcmp(ournick, rname)) { | |
315 // Display current mbuf and create a new message for the member | |
316 // Note: the usttime timestamp is related to the other member, | |
317 // so we use 0 here. | |
318 scr_WriteIncomingMessage(roomjid, mbuf, 0, | |
319 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
320 if (log_muc_conf) | |
321 hlog_write_message(roomjid, 0, -1, mbuf); | |
322 g_free(mbuf); | |
323 if (printstatus != status_none) | |
324 mbuf = g_strdup_printf("%s has joined", rname); | |
325 else | |
326 mbuf = NULL; | |
327 new_member = TRUE; | |
328 } | |
329 } else { | |
330 mbuf = NULL; | |
331 if (strcmp(ournick, rname)) { | |
332 if (printstatus != status_none) | |
333 mbuf = g_strdup_printf("%s has joined", rname); | |
334 new_member = TRUE; | |
335 } | |
336 } | |
337 | |
338 if (mbuf) { | |
339 guint msgflags = HBB_PREFIX_INFO; | |
340 if (!settings_opt_get_int("muc_flag_joins")) | |
341 msgflags |= HBB_PREFIX_NOFLAG; | |
342 scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0); | |
343 if (log_muc_conf) | |
344 hlog_write_message(roomjid, 0, -1, mbuf); | |
345 g_free(mbuf); | |
346 } | |
347 | |
348 return new_member; | |
349 } | |
350 | |
351 static void handle_muc_presence(const char *from, LmMessageNode *xmldata, | |
352 const char *roomjid, const char *rname, | |
353 enum imstatus ust, const char *ustmsg, | |
354 time_t usttime, char bpprio) | |
355 { | |
356 LmMessageNode *y; | |
357 const char *p; | |
358 char *mbuf; | |
359 const char *ournick; | |
360 enum imrole mbrole = role_none; | |
361 enum imaffiliation mbaffil = affil_none; | |
362 enum room_printstatus printstatus; | |
363 enum room_autowhois autowhois; | |
364 const char *mbjid = NULL, *mbnick = NULL; | |
365 const char *actorjid = NULL, *reason = NULL; | |
366 bool new_member = FALSE; // True if somebody else joins the room (not us) | |
367 guint statuscode = 0; | |
368 guint nickchange = 0; | |
369 GSList *room_elt; | |
370 int log_muc_conf; | |
371 guint msgflags; | |
372 | |
373 log_muc_conf = settings_opt_get_int("log_muc_conf"); | |
374 | |
375 room_elt = roster_find(roomjid, jidsearch, 0); | |
376 if (!room_elt) { | |
377 // Add room if it doesn't already exist | |
378 // It shouldn't happen, there is probably something wrong (server or | |
379 // network issue?) | |
380 room_elt = roster_add_user(roomjid, NULL, NULL, ROSTER_TYPE_ROOM, | |
381 sub_none, -1); | |
382 scr_LogPrint(LPRINT_LOGNORM, "Strange MUC presence message"); | |
383 } else { | |
384 // Make sure this is a room (it can be a conversion user->room) | |
385 buddy_settype(room_elt->data, ROSTER_TYPE_ROOM); | |
386 } | |
387 | |
388 // Get room member's information | |
389 muc_get_item_info(from, xmldata, &mbrole, &mbaffil, &mbjid, &mbnick, | |
390 &actorjid, &reason); | |
391 | |
392 // Get our room nickname | |
393 ournick = buddy_getnickname(room_elt->data); | |
394 | |
395 if (!ournick) { | |
396 // It shouldn't happen, probably a server issue | |
397 mbuf = g_strdup_printf("Unexpected groupchat packet!"); | |
398 | |
399 scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); | |
400 scr_WriteIncomingMessage(roomjid, mbuf, 0, HBB_PREFIX_INFO, 0); | |
401 g_free(mbuf); | |
402 // Send back an unavailable packet | |
403 xmpp_setstatus(offline, roomjid, "", TRUE); | |
404 scr_DrawRoster(); | |
405 return; | |
406 } | |
407 | |
408 // Get the status code | |
409 // 201: a room has been created | |
410 // 301: the user has been banned from the room | |
411 // 303: new room nickname | |
412 // 307: the user has been kicked from the room | |
413 // 321,322,332: the user has been removed from the room | |
414 y = lm_message_node_find_child(xmldata, "status"); | |
415 if (y) { | |
416 p = lm_message_node_get_attribute(y, "code"); | |
417 if (p) | |
418 statuscode = atoi(p); | |
419 } | |
420 | |
421 // Get the room's "print_status" settings | |
422 printstatus = buddy_getprintstatus(room_elt->data); | |
423 if (printstatus == status_default) { | |
424 printstatus = (guint) settings_opt_get_int("muc_print_status"); | |
425 if (printstatus > 3) | |
426 printstatus = status_default; | |
427 } | |
428 | |
429 // A new room has been created; accept MUC default config | |
430 if (statuscode == 201) | |
431 xmpp_room_unlock(roomjid); | |
432 | |
433 // Check for nickname change | |
434 if (statuscode == 303 && mbnick) { | |
435 mbuf = g_strdup_printf("%s is now known as %s", rname, mbnick); | |
436 scr_WriteIncomingMessage(roomjid, mbuf, usttime, | |
437 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
438 if (log_muc_conf) | |
439 hlog_write_message(roomjid, 0, -1, mbuf); | |
440 g_free(mbuf); | |
441 buddy_resource_setname(room_elt->data, rname, mbnick); | |
442 // Maybe it's _our_ nickname... | |
443 if (ournick && !strcmp(rname, ournick)) | |
444 buddy_setnickname(room_elt->data, mbnick); | |
445 nickchange = TRUE; | |
446 } | |
447 | |
448 // Check for departure/arrival | |
449 if (!mbnick && ust == offline) { | |
450 // Somebody is leaving | |
451 enum { leave=0, kick, ban } how = leave; | |
452 bool we_left = FALSE; | |
453 | |
454 if (statuscode == 307) | |
455 how = kick; | |
456 else if (statuscode == 301) | |
457 how = ban; | |
458 | |
459 // If this is a leave, check if it is ourself | |
460 if (ournick && !strcmp(rname, ournick)) { | |
461 we_left = TRUE; // _We_ have left! (kicked, banned, etc.) | |
462 buddy_setinsideroom(room_elt->data, FALSE); | |
463 buddy_setnickname(room_elt->data, NULL); | |
464 buddy_del_all_resources(room_elt->data); | |
465 buddy_settopic(room_elt->data, NULL); | |
466 scr_UpdateChatStatus(FALSE); | |
467 update_roster = TRUE; | |
468 } | |
469 | |
470 // The message depends on _who_ left, and _how_ | |
471 if (how) { | |
472 gchar *mbuf_end; | |
473 // Forced leave | |
474 if (actorjid) { | |
475 mbuf_end = g_strdup_printf("%s from %s by <%s>.\nReason: %s", | |
476 (how == ban ? "banned" : "kicked"), | |
477 roomjid, actorjid, reason); | |
478 } else { | |
479 mbuf_end = g_strdup_printf("%s from %s.", | |
480 (how == ban ? "banned" : "kicked"), | |
481 roomjid); | |
482 } | |
483 if (we_left) | |
484 mbuf = g_strdup_printf("You have been %s", mbuf_end); | |
485 else | |
486 mbuf = g_strdup_printf("%s has been %s", rname, mbuf_end); | |
487 | |
488 g_free(mbuf_end); | |
489 } else { | |
490 // Natural leave | |
491 if (we_left) { | |
492 LmMessageNode *destroynode = lm_message_node_find_child(xmldata, | |
493 "destroy"); | |
494 if (destroynode) { | |
495 if ((reason = lm_message_node_get_child_value(destroynode, | |
496 "reason"))) { | |
497 mbuf = g_strdup_printf("You have left %s, " | |
498 "the room has been destroyed: %s", | |
499 roomjid, reason); | |
500 } else { | |
501 mbuf = g_strdup_printf("You have left %s, " | |
502 "the room has been destroyed", roomjid); | |
503 } | |
504 } else { | |
505 mbuf = g_strdup_printf("You have left %s", roomjid); | |
506 } | |
507 } else { | |
508 if (ust != offline) { | |
509 // This can happen when a network failure occurs, | |
510 // this isn't an official leave but the user isn't there anymore. | |
511 mbuf = g_strdup_printf("%s has disappeared!", rname); | |
512 ust = offline; | |
513 } else { | |
514 if (ustmsg) | |
515 mbuf = g_strdup_printf("%s has left: %s", rname, ustmsg); | |
516 else | |
517 mbuf = g_strdup_printf("%s has left", rname); | |
518 } | |
519 } | |
520 } | |
521 | |
522 // Display the mbuf message if we're concerned | |
523 // or if the print_status isn't set to none. | |
524 if (we_left || printstatus != status_none) { | |
525 msgflags = HBB_PREFIX_INFO; | |
526 if (!we_left && settings_opt_get_int("muc_flag_joins") != 2) | |
527 msgflags |= HBB_PREFIX_NOFLAG; | |
528 scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0); | |
529 } | |
530 | |
531 if (log_muc_conf) | |
532 hlog_write_message(roomjid, 0, -1, mbuf); | |
533 | |
534 if (we_left) { | |
535 scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); | |
536 g_free(mbuf); | |
537 return; | |
538 } | |
539 g_free(mbuf); | |
540 } else if (buddy_getstatus(room_elt->data, rname) == offline && | |
541 ust != offline) { | |
542 // Somebody is joining | |
543 new_member = muc_handle_join(room_elt, rname, roomjid, ournick, | |
544 printstatus, usttime, log_muc_conf); | |
545 } else { | |
546 // This is a simple member status change | |
547 | |
548 if (printstatus == status_all && !nickchange) { | |
549 mbuf = g_strdup_printf("Member status has changed: %s [%c] %s", rname, | |
550 imstatus2char[ust], ((ustmsg) ? ustmsg : "")); | |
551 scr_WriteIncomingMessage(roomjid, mbuf, usttime, | |
552 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
553 g_free(mbuf); | |
554 } | |
555 } | |
556 | |
557 // Sanity check, shouldn't happen... | |
558 if (!rname) | |
559 return; | |
560 | |
561 // Update room member status | |
562 roster_setstatus(roomjid, rname, bpprio, ust, ustmsg, usttime, | |
563 mbrole, mbaffil, mbjid); | |
564 | |
565 autowhois = buddy_getautowhois(room_elt->data); | |
566 if (autowhois == autowhois_default) | |
567 autowhois = (settings_opt_get_int("muc_auto_whois") ? | |
568 autowhois_on : autowhois_off); | |
569 | |
570 if (new_member && autowhois == autowhois_on) { | |
571 // FIXME: This will fail for some UTF-8 nicknames. | |
572 gchar *joiner_nick = from_utf8(rname); | |
573 cmd_room_whois(room_elt->data, joiner_nick, FALSE); | |
574 g_free(joiner_nick); | |
575 } | |
576 | |
577 scr_DrawRoster(); | |
578 } | |
579 | |
580 static void roompresence(gpointer room, void *presencedata) | |
581 { | |
582 const char *bjid; | |
583 const char *nickname; | |
584 char *to; | |
585 struct T_presence *pres = presencedata; | |
586 | |
587 if (!buddy_getinsideroom(room)) | |
588 return; | |
589 | |
590 bjid = buddy_getjid(room); | |
591 if (!bjid) return; | |
592 nickname = buddy_getnickname(room); | |
593 if (!nickname) return; | |
594 | |
595 to = g_strdup_printf("%s/%s", bjid, nickname); | |
596 xmpp_setstatus(pres->st, to, pres->msg, TRUE); | |
597 g_free(to); | |
598 } | |
599 | |
600 // got_invite(from, to, reason, passwd) | |
601 // This function should be called when receiving an invitation from user | |
602 // "from", to enter the room "to". Optional reason and room password can | |
603 // be provided. | |
604 static void got_invite(const char* from, const char *to, const char* reason, | |
605 const char* passwd) | |
606 { | |
607 eviqs *evn; | |
608 event_muc_invitation *invitation; | |
609 GString *sbuf; | |
610 char *barejid; | |
611 GSList *room_elt; | |
612 | |
613 sbuf = g_string_new(""); | |
614 if (reason) { | |
615 g_string_printf(sbuf, | |
616 "Received an invitation to <%s>, from <%s>, reason: %s", | |
617 to, from, reason); | |
618 } else { | |
619 g_string_printf(sbuf, "Received an invitation to <%s>, from <%s>", | |
620 to, from); | |
621 } | |
622 | |
623 barejid = jidtodisp(from); | |
624 scr_WriteIncomingMessage(barejid, sbuf->str, 0, HBB_PREFIX_INFO, 0); | |
625 scr_LogPrint(LPRINT_LOGNORM, "%s", sbuf->str); | |
626 | |
627 evn = evs_new(EVS_TYPE_INVITATION, EVS_MAX_TIMEOUT); | |
628 if (evn) { | |
629 evn->callback = &evscallback_invitation; | |
630 invitation = g_new(event_muc_invitation, 1); | |
631 invitation->to = g_strdup(to); | |
632 invitation->from = g_strdup(from); | |
633 invitation->passwd = g_strdup(passwd); | |
634 invitation->reason = g_strdup(reason); | |
635 evn->data = invitation; | |
636 evn->desc = g_strdup_printf("<%s> invites you to %s ", from, to); | |
637 g_string_printf(sbuf, "Please use /event %s accept|reject", evn->id); | |
638 } else { | |
639 g_string_printf(sbuf, "Unable to create a new event!"); | |
640 } | |
641 scr_WriteIncomingMessage(barejid, sbuf->str, 0, HBB_PREFIX_INFO, 0); | |
642 scr_LogPrint(LPRINT_LOGNORM, "%s", sbuf->str); | |
643 g_string_free(sbuf, TRUE); | |
644 g_free(barejid); | |
645 | |
646 // Make sure the MUC room barejid is a room in the roster | |
647 barejid = jidtodisp(to); | |
648 room_elt = roster_find(barejid, jidsearch, 0); | |
649 if (room_elt) | |
650 buddy_settype(room_elt->data, ROSTER_TYPE_ROOM); | |
651 | |
652 g_free(barejid); | |
653 } | |
654 | |
655 | |
656 // Specific MUC message handling (for example invitation processing) | |
657 static void got_muc_message(const char *from, LmMessageNode *x) | |
658 { | |
659 LmMessageNode *invite = lm_message_node_get_child(x, "invite"); | |
660 if (invite) | |
661 { | |
662 const char *invite_from; | |
663 const char *reason = NULL; | |
664 const char *password = NULL; | |
665 | |
666 invite_from = lm_message_node_get_attribute(invite, "from"); | |
667 reason = lm_message_node_get_child_value(invite, "reason"); | |
668 password = lm_message_node_get_child_value(invite, "password"); | |
669 if (invite_from) | |
670 got_invite(invite_from, from, reason, password); | |
671 } | |
672 // TODO | |
673 // handle status code = 100 ( not anonymous ) | |
674 // handle status code = 170 ( changement de config ) | |
675 // 10.2.1 Notification of Configuration Changes | |
676 // declined invitation | |
677 } | |
678 |