comparison mcabber/mcabber/xmpp_muc.c @ 1668:41c26b7d2890

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