--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/src/xmpp_muc.c Sun Oct 11 15:38:32 2009 +0200
@@ -0,0 +1,678 @@
+/* See xmpp.c file for copyright and license details. */
+
+static void decline_invitation(event_muc_invitation *invitation, char *reason)
+{
+ // cut and paste from xmpp_room_invite
+ LmMessage *m;
+ LmMessageNode *x, *y;
+
+ if (!invitation) return;
+ if (!invitation->to || !invitation->from) return;
+
+ m = lm_message_new(invitation->to, LM_MESSAGE_TYPE_MESSAGE);
+
+ x = lm_message_node_add_child(m->node, "x", NULL);
+ lm_message_node_set_attribute(x, "xmlns",
+ "http://jabber.org/protocol/muc#user");
+
+ y = lm_message_node_add_child(x, "decline", NULL);
+ lm_message_node_set_attribute(y, "to", invitation->from);
+
+ if (reason)
+ lm_message_node_add_child(y, "reason", reason);
+
+ lm_connection_send(lconnection, m, NULL);
+ lm_message_unref(m);
+}
+
+static int evscallback_invitation(eviqs *evp, guint evcontext)
+{
+ event_muc_invitation *invitation = evp->data;
+
+ // Sanity check
+ if (!invitation) {
+ // Shouldn't happen.
+ scr_LogPrint(LPRINT_LOGNORM, "Error in evs callback.");
+ return 0;
+ }
+
+ if (evcontext == EVS_CONTEXT_TIMEOUT) {
+ scr_LogPrint(LPRINT_LOGNORM, "Event %s timed out, cancelled.", evp->id);
+ goto evscallback_invitation_free;
+ }
+ if (evcontext == EVS_CONTEXT_CANCEL) {
+ scr_LogPrint(LPRINT_LOGNORM, "Event %s cancelled.", evp->id);
+ goto evscallback_invitation_free;
+ }
+ if (!(evcontext & EVS_CONTEXT_USER))
+ goto evscallback_invitation_free;
+ // Ok, let's work now.
+ // evcontext: 0, 1 == reject, accept
+
+ if (evcontext & ~EVS_CONTEXT_USER) {
+ char *nickname = default_muc_nickname(invitation->to);
+ xmpp_room_join(invitation->to, nickname, invitation->passwd);
+ g_free(nickname);
+ } else {
+ scr_LogPrint(LPRINT_LOGNORM, "Invitation to %s refused.", invitation->to);
+ decline_invitation(invitation, NULL);
+ }
+
+evscallback_invitation_free:
+ g_free(invitation->to);
+ g_free(invitation->from);
+ g_free(invitation->passwd);
+ g_free(invitation->reason);
+ g_free(invitation);
+ evp->data = NULL;
+ return 0;
+}
+
+// Join a MUC room
+void xmpp_room_join(const char *room, const char *nickname, const char *passwd)
+{
+ LmMessage *x;
+ LmMessageNode *y;
+ gchar *roomid;
+ GSList *room_elt;
+
+ if (!lm_connection_is_authenticated(lconnection) || !room) return;
+ if (!nickname) return;
+
+ roomid = g_strdup_printf("%s/%s", room, nickname);
+ if (check_jid_syntax(roomid)) {
+ scr_LogPrint(LPRINT_NORMAL, "<%s/%s> is not a valid Jabber room", room,
+ nickname);
+ g_free(roomid);
+ return;
+ }
+
+ room_elt = roster_find(room, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_ROOM);
+ // Add room if it doesn't already exist
+ if (!room_elt) {
+ room_elt = roster_add_user(room, NULL, NULL, ROSTER_TYPE_ROOM,
+ sub_none, -1);
+ } else {
+ // Make sure this is a room (it can be a conversion user->room)
+ buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
+ }
+ // If insideroom is TRUE, this is a nickname change and we don't care here
+ if (!buddy_getinsideroom(room_elt->data)) {
+ // We're trying to enter a room
+ buddy_setnickname(room_elt->data, nickname);
+ }
+
+ // Send the XML request
+ x = lm_message_new(roomid, LM_MESSAGE_TYPE_PRESENCE);
+
+ x = lm_message_new_presence(mystatus, roomid, mystatusmsg);
+ y = lm_message_node_add_child(x->node, "x", NULL);
+ lm_message_node_set_attribute(y, "xmlns", "http://jabber.org/protocol/muc");
+ if (passwd)
+ lm_message_node_add_child(y, "password", passwd);
+
+ lm_connection_send(lconnection, x, NULL);
+ lm_message_unref(x);
+ g_free(roomid);
+}
+
+// Invite a user to a MUC room
+// room syntax: "room@server"
+// reason can be null.
+void xmpp_room_invite(const char *room, const char *fjid, const char *reason)
+{
+ LmMessage *msg;
+ LmMessageNode *x, *y;
+
+ if (!lm_connection_is_authenticated(lconnection) || !room || !fjid) return;
+
+ msg = lm_message_new(room, LM_MESSAGE_TYPE_MESSAGE);
+
+ x = lm_message_node_add_child(msg->node, "x", NULL);
+ lm_message_node_set_attribute(x, "xmlns",
+ "http://jabber.org/protocol/muc#user");
+
+ y = lm_message_node_add_child(x, "invite", NULL);
+ lm_message_node_set_attribute(y, "to", fjid);
+
+ if (reason)
+ lm_message_node_add_child(y, "reason", reason);
+
+ lm_connection_send(lconnection, msg, NULL);
+ lm_message_unref(msg);
+}
+
+int xmpp_room_setattrib(const char *roomid, const char *fjid,
+ const char *nick, struct role_affil ra,
+ const char *reason)
+{
+ LmMessage *iq;
+ LmMessageNode *query, *x;
+
+ if (!lm_connection_is_authenticated(lconnection) || !roomid) return 1;
+ if (!fjid && !nick) return 1;
+
+ if (check_jid_syntax((char*)roomid)) {
+ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", roomid);
+ return 1;
+ }
+ if (fjid && check_jid_syntax((char*)fjid)) {
+ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", fjid);
+ return 1;
+ }
+
+ if (ra.type == type_affil && ra.val.affil == affil_outcast && !fjid)
+ return 1; // Shouldn't happen (jid mandatory when banning)
+
+ iq = lm_message_new_with_sub_type(roomid, LM_MESSAGE_TYPE_IQ,
+ LM_MESSAGE_SUB_TYPE_SET);
+ query = lm_message_node_add_child(iq->node, "query", NULL);
+ lm_message_node_set_attribute(query, "xmlns",
+ "http://jabber.org/protocol/muc#admin");
+ x = lm_message_node_add_child(query, "item", NULL);
+
+ if (fjid) {
+ lm_message_node_set_attribute(x, "jid", fjid);
+ } else { // nickname
+ lm_message_node_set_attribute(x, "nick", nick);
+ }
+
+ if (ra.type == type_affil)
+ lm_message_node_set_attribute(x, "affiliation", straffil[ra.val.affil]);
+ else if (ra.type == type_role)
+ lm_message_node_set_attribute(x, "role", strrole[ra.val.role]);
+
+ if (reason)
+ lm_message_node_add_child(x, "reason", reason);
+
+ lm_connection_send(lconnection, iq, NULL);
+ lm_message_unref(iq);
+
+ return 0;
+}
+
+// Unlock a MUC room
+// room syntax: "room@server"
+void xmpp_room_unlock(const char *room)
+{
+ LmMessageNode *y, *z;
+ LmMessage *iq;
+
+ if (!lm_connection_is_authenticated(lconnection) || !room) return;
+
+ iq = lm_message_new_with_sub_type(room, LM_MESSAGE_TYPE_IQ,
+ LM_MESSAGE_SUB_TYPE_SET);
+ lm_message_node_set_attribute(iq->node, "xmlns",
+ "http://jabber.org/protocol/muc#owner");
+
+
+ y = lm_message_node_add_child(iq->node, "query", NULL);
+ z = lm_message_node_add_child(y, "x", NULL);
+ lm_message_node_set_attribute(z, "xmlns", "jabber:x:data");
+ lm_message_node_set_attribute(z, "type", "submit");
+
+ lm_connection_send(lconnection, iq, NULL);
+ lm_message_unref(iq);
+}
+
+// Destroy a MUC room
+// room syntax: "room@server"
+void xmpp_room_destroy(const char *room, const char *venue, const char *reason)
+{
+ LmMessage *iq;
+ LmMessageNode *query, *x;
+
+ if (!lm_connection_is_authenticated(lconnection) || !room) return;
+
+ iq = lm_message_new_with_sub_type(room, LM_MESSAGE_TYPE_IQ,
+ LM_MESSAGE_SUB_TYPE_SET);
+ query = lm_message_node_add_child(iq->node, "query", NULL);
+ lm_message_node_set_attribute(query, "xmlns",
+ "http://jabber.org/protocol/muc#owner");
+ x = lm_message_node_add_child(query, "destroy", NULL);
+
+ if (venue && *venue)
+ lm_message_node_set_attribute(x, "jid", venue);
+
+ if (reason)
+ lm_message_node_add_child(x, "reason", reason);
+
+ lm_connection_send(lconnection, iq, NULL);
+ lm_message_unref(iq);
+}
+
+// muc_get_item_info(...)
+// Get room member's information from xmlndata.
+// The variables must be initialized before calling this function,
+// because they are not touched if the relevant information is missing.
+static void muc_get_item_info(const char *from, LmMessageNode *xmldata,
+ enum imrole *mbrole, enum imaffiliation *mbaffil,
+ const char **mbjid, const char **mbnick,
+ const char **actorjid, const char **reason)
+{
+ LmMessageNode *y, *z;
+ const char *p;
+
+ y = lm_message_node_find_child(xmldata, "item");
+ if (!y)
+ return;
+
+ p = lm_message_node_get_attribute(y, "affiliation");
+ if (p) {
+ if (!strcmp(p, "owner")) *mbaffil = affil_owner;
+ else if (!strcmp(p, "admin")) *mbaffil = affil_admin;
+ else if (!strcmp(p, "member")) *mbaffil = affil_member;
+ else if (!strcmp(p, "outcast")) *mbaffil = affil_outcast;
+ else if (!strcmp(p, "none")) *mbaffil = affil_none;
+ else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown affiliation \"%s\"",
+ from, p);
+ }
+ p = lm_message_node_get_attribute(y, "role");
+ if (p) {
+ if (!strcmp(p, "moderator")) *mbrole = role_moderator;
+ else if (!strcmp(p, "participant")) *mbrole = role_participant;
+ else if (!strcmp(p, "visitor")) *mbrole = role_visitor;
+ else if (!strcmp(p, "none")) *mbrole = role_none;
+ else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown role \"%s\"",
+ from, p);
+ }
+ *mbjid = lm_message_node_get_attribute(y, "jid");
+ *mbnick = lm_message_node_get_attribute(y, "nick");
+ // For kick/ban, there can be actor and reason tags
+ *reason = lm_message_node_get_child_value(y, "reason");
+ z = lm_message_node_find_child(y, "actor");
+ if (z)
+ *actorjid = lm_message_node_get_attribute(z, "jid");
+}
+
+// muc_handle_join(...)
+// Handle a join event in a MUC room.
+// This function will return the new_member value TRUE if somebody else joins
+// the room (and FALSE if _we_ are joining the room).
+static bool muc_handle_join(const GSList *room_elt, const char *rname,
+ const char *roomjid, const char *ournick,
+ enum room_printstatus printstatus,
+ time_t usttime, int log_muc_conf)
+{
+ bool new_member = FALSE; // True if somebody else joins the room (not us)
+ gchar *mbuf;
+
+ if (!buddy_getinsideroom(room_elt->data)) {
+ // We weren't inside the room yet. Now we are.
+ // However, this could be a presence packet from another room member
+
+ buddy_setinsideroom(room_elt->data, TRUE);
+ // Set the message flag unless we're already in the room buffer window
+ scr_setmsgflag_if_needed(roomjid, FALSE);
+ // Add a message to the tracelog file
+ mbuf = g_strdup_printf("You have joined %s as \"%s\"", roomjid, ournick);
+ scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
+ g_free(mbuf);
+ mbuf = g_strdup_printf("You have joined as \"%s\"", ournick);
+
+ // The 1st presence message could be for another room member
+ if (strcmp(ournick, rname)) {
+ // Display current mbuf and create a new message for the member
+ // Note: the usttime timestamp is related to the other member,
+ // so we use 0 here.
+ scr_WriteIncomingMessage(roomjid, mbuf, 0,
+ HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
+ if (log_muc_conf)
+ hlog_write_message(roomjid, 0, -1, mbuf);
+ g_free(mbuf);
+ if (printstatus != status_none)
+ mbuf = g_strdup_printf("%s has joined", rname);
+ else
+ mbuf = NULL;
+ new_member = TRUE;
+ }
+ } else {
+ mbuf = NULL;
+ if (strcmp(ournick, rname)) {
+ if (printstatus != status_none)
+ mbuf = g_strdup_printf("%s has joined", rname);
+ new_member = TRUE;
+ }
+ }
+
+ if (mbuf) {
+ guint msgflags = HBB_PREFIX_INFO;
+ if (!settings_opt_get_int("muc_flag_joins"))
+ msgflags |= HBB_PREFIX_NOFLAG;
+ scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0);
+ if (log_muc_conf)
+ hlog_write_message(roomjid, 0, -1, mbuf);
+ g_free(mbuf);
+ }
+
+ return new_member;
+}
+
+static void handle_muc_presence(const char *from, LmMessageNode *xmldata,
+ const char *roomjid, const char *rname,
+ enum imstatus ust, const char *ustmsg,
+ time_t usttime, char bpprio)
+{
+ LmMessageNode *y;
+ const char *p;
+ char *mbuf;
+ const char *ournick;
+ enum imrole mbrole = role_none;
+ enum imaffiliation mbaffil = affil_none;
+ enum room_printstatus printstatus;
+ enum room_autowhois autowhois;
+ const char *mbjid = NULL, *mbnick = NULL;
+ const char *actorjid = NULL, *reason = NULL;
+ bool new_member = FALSE; // True if somebody else joins the room (not us)
+ guint statuscode = 0;
+ guint nickchange = 0;
+ GSList *room_elt;
+ int log_muc_conf;
+ guint msgflags;
+
+ log_muc_conf = settings_opt_get_int("log_muc_conf");
+
+ room_elt = roster_find(roomjid, jidsearch, 0);
+ if (!room_elt) {
+ // Add room if it doesn't already exist
+ // It shouldn't happen, there is probably something wrong (server or
+ // network issue?)
+ room_elt = roster_add_user(roomjid, NULL, NULL, ROSTER_TYPE_ROOM,
+ sub_none, -1);
+ scr_LogPrint(LPRINT_LOGNORM, "Strange MUC presence message");
+ } else {
+ // Make sure this is a room (it can be a conversion user->room)
+ buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
+ }
+
+ // Get room member's information
+ muc_get_item_info(from, xmldata, &mbrole, &mbaffil, &mbjid, &mbnick,
+ &actorjid, &reason);
+
+ // Get our room nickname
+ ournick = buddy_getnickname(room_elt->data);
+
+ if (!ournick) {
+ // It shouldn't happen, probably a server issue
+ mbuf = g_strdup_printf("Unexpected groupchat packet!");
+
+ scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
+ scr_WriteIncomingMessage(roomjid, mbuf, 0, HBB_PREFIX_INFO, 0);
+ g_free(mbuf);
+ // Send back an unavailable packet
+ xmpp_setstatus(offline, roomjid, "", TRUE);
+ scr_DrawRoster();
+ return;
+ }
+
+ // Get the status code
+ // 201: a room has been created
+ // 301: the user has been banned from the room
+ // 303: new room nickname
+ // 307: the user has been kicked from the room
+ // 321,322,332: the user has been removed from the room
+ y = lm_message_node_find_child(xmldata, "status");
+ if (y) {
+ p = lm_message_node_get_attribute(y, "code");
+ if (p)
+ statuscode = atoi(p);
+ }
+
+ // Get the room's "print_status" settings
+ printstatus = buddy_getprintstatus(room_elt->data);
+ if (printstatus == status_default) {
+ printstatus = (guint) settings_opt_get_int("muc_print_status");
+ if (printstatus > 3)
+ printstatus = status_default;
+ }
+
+ // A new room has been created; accept MUC default config
+ if (statuscode == 201)
+ xmpp_room_unlock(roomjid);
+
+ // Check for nickname change
+ if (statuscode == 303 && mbnick) {
+ mbuf = g_strdup_printf("%s is now known as %s", rname, mbnick);
+ scr_WriteIncomingMessage(roomjid, mbuf, usttime,
+ HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
+ if (log_muc_conf)
+ hlog_write_message(roomjid, 0, -1, mbuf);
+ g_free(mbuf);
+ buddy_resource_setname(room_elt->data, rname, mbnick);
+ // Maybe it's _our_ nickname...
+ if (ournick && !strcmp(rname, ournick))
+ buddy_setnickname(room_elt->data, mbnick);
+ nickchange = TRUE;
+ }
+
+ // Check for departure/arrival
+ if (!mbnick && ust == offline) {
+ // Somebody is leaving
+ enum { leave=0, kick, ban } how = leave;
+ bool we_left = FALSE;
+
+ if (statuscode == 307)
+ how = kick;
+ else if (statuscode == 301)
+ how = ban;
+
+ // If this is a leave, check if it is ourself
+ if (ournick && !strcmp(rname, ournick)) {
+ we_left = TRUE; // _We_ have left! (kicked, banned, etc.)
+ buddy_setinsideroom(room_elt->data, FALSE);
+ buddy_setnickname(room_elt->data, NULL);
+ buddy_del_all_resources(room_elt->data);
+ buddy_settopic(room_elt->data, NULL);
+ scr_UpdateChatStatus(FALSE);
+ update_roster = TRUE;
+ }
+
+ // The message depends on _who_ left, and _how_
+ if (how) {
+ gchar *mbuf_end;
+ // Forced leave
+ if (actorjid) {
+ mbuf_end = g_strdup_printf("%s from %s by <%s>.\nReason: %s",
+ (how == ban ? "banned" : "kicked"),
+ roomjid, actorjid, reason);
+ } else {
+ mbuf_end = g_strdup_printf("%s from %s.",
+ (how == ban ? "banned" : "kicked"),
+ roomjid);
+ }
+ if (we_left)
+ mbuf = g_strdup_printf("You have been %s", mbuf_end);
+ else
+ mbuf = g_strdup_printf("%s has been %s", rname, mbuf_end);
+
+ g_free(mbuf_end);
+ } else {
+ // Natural leave
+ if (we_left) {
+ LmMessageNode *destroynode = lm_message_node_find_child(xmldata,
+ "destroy");
+ if (destroynode) {
+ if ((reason = lm_message_node_get_child_value(destroynode,
+ "reason"))) {
+ mbuf = g_strdup_printf("You have left %s, "
+ "the room has been destroyed: %s",
+ roomjid, reason);
+ } else {
+ mbuf = g_strdup_printf("You have left %s, "
+ "the room has been destroyed", roomjid);
+ }
+ } else {
+ mbuf = g_strdup_printf("You have left %s", roomjid);
+ }
+ } else {
+ if (ust != offline) {
+ // This can happen when a network failure occurs,
+ // this isn't an official leave but the user isn't there anymore.
+ mbuf = g_strdup_printf("%s has disappeared!", rname);
+ ust = offline;
+ } else {
+ if (ustmsg)
+ mbuf = g_strdup_printf("%s has left: %s", rname, ustmsg);
+ else
+ mbuf = g_strdup_printf("%s has left", rname);
+ }
+ }
+ }
+
+ // Display the mbuf message if we're concerned
+ // or if the print_status isn't set to none.
+ if (we_left || printstatus != status_none) {
+ msgflags = HBB_PREFIX_INFO;
+ if (!we_left && settings_opt_get_int("muc_flag_joins") != 2)
+ msgflags |= HBB_PREFIX_NOFLAG;
+ scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0);
+ }
+
+ if (log_muc_conf)
+ hlog_write_message(roomjid, 0, -1, mbuf);
+
+ if (we_left) {
+ scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
+ g_free(mbuf);
+ return;
+ }
+ g_free(mbuf);
+ } else if (buddy_getstatus(room_elt->data, rname) == offline &&
+ ust != offline) {
+ // Somebody is joining
+ new_member = muc_handle_join(room_elt, rname, roomjid, ournick,
+ printstatus, usttime, log_muc_conf);
+ } else {
+ // This is a simple member status change
+
+ if (printstatus == status_all && !nickchange) {
+ mbuf = g_strdup_printf("Member status has changed: %s [%c] %s", rname,
+ imstatus2char[ust], ((ustmsg) ? ustmsg : ""));
+ scr_WriteIncomingMessage(roomjid, mbuf, usttime,
+ HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
+ g_free(mbuf);
+ }
+ }
+
+ // Sanity check, shouldn't happen...
+ if (!rname)
+ return;
+
+ // Update room member status
+ roster_setstatus(roomjid, rname, bpprio, ust, ustmsg, usttime,
+ mbrole, mbaffil, mbjid);
+
+ autowhois = buddy_getautowhois(room_elt->data);
+ if (autowhois == autowhois_default)
+ autowhois = (settings_opt_get_int("muc_auto_whois") ?
+ autowhois_on : autowhois_off);
+
+ if (new_member && autowhois == autowhois_on) {
+ // FIXME: This will fail for some UTF-8 nicknames.
+ gchar *joiner_nick = from_utf8(rname);
+ cmd_room_whois(room_elt->data, joiner_nick, FALSE);
+ g_free(joiner_nick);
+ }
+
+ scr_DrawRoster();
+}
+
+static void roompresence(gpointer room, void *presencedata)
+{
+ const char *bjid;
+ const char *nickname;
+ char *to;
+ struct T_presence *pres = presencedata;
+
+ if (!buddy_getinsideroom(room))
+ return;
+
+ bjid = buddy_getjid(room);
+ if (!bjid) return;
+ nickname = buddy_getnickname(room);
+ if (!nickname) return;
+
+ to = g_strdup_printf("%s/%s", bjid, nickname);
+ xmpp_setstatus(pres->st, to, pres->msg, TRUE);
+ g_free(to);
+}
+
+// got_invite(from, to, reason, passwd)
+// This function should be called when receiving an invitation from user
+// "from", to enter the room "to". Optional reason and room password can
+// be provided.
+static void got_invite(const char* from, const char *to, const char* reason,
+ const char* passwd)
+{
+ eviqs *evn;
+ event_muc_invitation *invitation;
+ GString *sbuf;
+ char *barejid;
+ GSList *room_elt;
+
+ sbuf = g_string_new("");
+ if (reason) {
+ g_string_printf(sbuf,
+ "Received an invitation to <%s>, from <%s>, reason: %s",
+ to, from, reason);
+ } else {
+ g_string_printf(sbuf, "Received an invitation to <%s>, from <%s>",
+ to, from);
+ }
+
+ barejid = jidtodisp(from);
+ scr_WriteIncomingMessage(barejid, sbuf->str, 0, HBB_PREFIX_INFO, 0);
+ scr_LogPrint(LPRINT_LOGNORM, "%s", sbuf->str);
+
+ evn = evs_new(EVS_TYPE_INVITATION, EVS_MAX_TIMEOUT);
+ if (evn) {
+ evn->callback = &evscallback_invitation;
+ invitation = g_new(event_muc_invitation, 1);
+ invitation->to = g_strdup(to);
+ invitation->from = g_strdup(from);
+ invitation->passwd = g_strdup(passwd);
+ invitation->reason = g_strdup(reason);
+ evn->data = invitation;
+ evn->desc = g_strdup_printf("<%s> invites you to %s ", from, to);
+ g_string_printf(sbuf, "Please use /event %s accept|reject", evn->id);
+ } else {
+ g_string_printf(sbuf, "Unable to create a new event!");
+ }
+ scr_WriteIncomingMessage(barejid, sbuf->str, 0, HBB_PREFIX_INFO, 0);
+ scr_LogPrint(LPRINT_LOGNORM, "%s", sbuf->str);
+ g_string_free(sbuf, TRUE);
+ g_free(barejid);
+
+ // Make sure the MUC room barejid is a room in the roster
+ barejid = jidtodisp(to);
+ room_elt = roster_find(barejid, jidsearch, 0);
+ if (room_elt)
+ buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
+
+ g_free(barejid);
+}
+
+
+// Specific MUC message handling (for example invitation processing)
+static void got_muc_message(const char *from, LmMessageNode *x)
+{
+ LmMessageNode *invite = lm_message_node_get_child(x, "invite");
+ if (invite)
+ {
+ const char *invite_from;
+ const char *reason = NULL;
+ const char *password = NULL;
+
+ invite_from = lm_message_node_get_attribute(invite, "from");
+ reason = lm_message_node_get_child_value(invite, "reason");
+ password = lm_message_node_get_child_value(invite, "password");
+ if (invite_from)
+ got_invite(invite_from, from, reason, password);
+ }
+ // TODO
+ // handle status code = 100 ( not anonymous )
+ // handle status code = 170 ( changement de config )
+ // 10.2.1 Notification of Configuration Changes
+ // declined invitation
+}
+