// 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 (!xmpp_is_online() || !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_presence(mystatus, roomid, mystatusmsg); xmpp_insert_entity_capabilities(x->node, mystatus); // Entity Caps (XEP-0115) y = lm_message_node_add_child(x->node, "x", NULL); lm_message_node_set_attribute(y, "xmlns", NS_MUC); if (passwd) lm_message_node_add_child(y, "password", passwd); lm_connection_send(lconnection, x, NULL); lm_message_unref(x); g_free(roomid); }
static void storage_bookmarks_parse_conference(LmMessageNode *node) { const char *fjid, *name, *autojoin; const char *pstatus, *awhois, *fjoins, *group; char *bjid; GSList *room_elt; fjid = lm_message_node_get_attribute(node, "jid"); if (!fjid) return; name = lm_message_node_get_attribute(node, "name"); autojoin = lm_message_node_get_attribute(node, "autojoin"); awhois = lm_message_node_get_attribute(node, "autowhois"); pstatus = lm_message_node_get_child_value(node, "print_status"); fjoins = lm_message_node_get_child_value(node, "flag_joins"); group = lm_message_node_get_child_value(node, "group"); bjid = jidtodisp(fjid); // Bare jid // Make sure this is a room (it can be a conversion user->room) room_elt = roster_find(bjid, jidsearch, 0); if (!room_elt) { room_elt = roster_add_user(bjid, name, group, ROSTER_TYPE_ROOM, sub_none, -1); } else { buddy_settype(room_elt->data, ROSTER_TYPE_ROOM); /* // If the name is available, should we use it? // I don't think so, it would be confusing because this item is already // in the roster. if (name) buddy_setname(room_elt->data, name); // The same question for roster group. if (group) buddy_setgroup(room_elt->data, group); */ } // Set the print_status and auto_whois values if (pstatus) { enum room_printstatus i; for (i = status_none; i <= status_all; i++) if (!strcasecmp(pstatus, strprintstatus[i])) break; if (i <= status_all) buddy_setprintstatus(room_elt->data, i); } if (awhois) { enum room_autowhois i = autowhois_default; if (!g_strcmp0(awhois, "1") || !(g_strcmp0(awhois, "true"))) i = autowhois_on; else if (!g_strcmp0(awhois, "0") || !(g_strcmp0(awhois, "false"))) i = autowhois_off; if (i != autowhois_default) buddy_setautowhois(room_elt->data, i); } if (fjoins) { enum room_flagjoins i; for (i = flagjoins_none; i <= flagjoins_all; i++) if (!strcasecmp(fjoins, strflagjoins[i])) break; if (i <= flagjoins_all) buddy_setflagjoins(room_elt->data, i); } // Is autojoin set? // If it is, we'll look up for more information (nick? password?) and // try to join the room. if (autojoin && !g_strcmp0(autojoin, "1")) { const char *nick, *passwd; char *tmpnick = NULL; nick = lm_message_node_get_child_value(node, "nick"); passwd = lm_message_node_get_child_value(node, "password"); if (!nick || !*nick) nick = tmpnick = default_muc_nickname(NULL); // Let's join now scr_LogPrint(LPRINT_LOGNORM, "Auto-join bookmark <%s>", bjid); xmpp_room_join(bjid, nick, passwd); g_free(tmpnick); } g_free(bjid); buddylist_build(); update_roster = TRUE; }
LmHandlerResult handle_iq_roster(LmMessageHandler *h, LmConnection *c, LmMessage *m, gpointer ud) { LmMessageNode *y; const char *fjid, *name, *group, *sub, *ask; char *cleanalias; enum subscr esub; int need_refresh = FALSE; guint roster_type; y = lm_message_node_find_child(lm_message_node_find_xmlns(m->node, NS_ROSTER), "item"); for ( ; y; y = y->next) { char *name_tmp = NULL; fjid = lm_message_node_get_attribute(y, "jid"); name = lm_message_node_get_attribute(y, "name"); sub = lm_message_node_get_attribute(y, "subscription"); ask = lm_message_node_get_attribute(y, "ask"); if (lm_message_node_find_child(y, "group")) group = lm_message_node_get_value(lm_message_node_find_child(y, "group")); else group = NULL; if (!fjid) continue; cleanalias = jidtodisp(fjid); esub = sub_none; if (sub) { if (!strcmp(sub, "to")) esub = sub_to; else if (!strcmp(sub, "from")) esub = sub_from; else if (!strcmp(sub, "both")) esub = sub_both; else if (!strcmp(sub, "remove")) esub = sub_remove; } if (esub == sub_remove) { roster_del_user(cleanalias); scr_LogPrint(LPRINT_LOGNORM, "Buddy <%s> has been removed " "from the roster", cleanalias); g_free(cleanalias); need_refresh = TRUE; continue; } if (ask && !strcmp(ask, "subscribe")) esub |= sub_pending; if (!name) { if (!settings_opt_get_int("roster_hide_domain")) { name = cleanalias; } else { char *p; name = name_tmp = g_strdup(cleanalias); p = strchr(name_tmp, JID_DOMAIN_SEPARATOR); if (p) *p = '\0'; } } // Tricky... :-\ My guess is that if there is no JID_DOMAIN_SEPARATOR, // this is an agent. if (strchr(cleanalias, JID_DOMAIN_SEPARATOR)) roster_type = ROSTER_TYPE_USER; else roster_type = ROSTER_TYPE_AGENT; roster_add_user(cleanalias, name, group, roster_type, esub, 1); g_free(name_tmp); g_free(cleanalias); } // Acknowledge IQ message if (lm_message_get_sub_type(m) == LM_MESSAGE_SUB_TYPE_SET) { LmMessage *result; result = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); lm_connection_send(c, result, NULL); lm_message_unref(result); } buddylist_build(); update_roster = TRUE; if (need_refresh) scr_update_buddy_window(); return LM_HANDLER_RESULT_REMOVE_MESSAGE; }
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) { char *mbuf; const char *ournick; enum imrole mbrole = role_none; enum imaffiliation mbaffil = affil_none; enum room_printstatus printstatus; enum room_autowhois autowhois; enum room_flagjoins flagjoins; const char *mbjid = NULL, *mbnick = NULL; const char *reason = NULL; char *actor = NULL; bool new_member = FALSE; // True if somebody else joins the room (not us) bool our_presence = FALSE; // True if this presence is from us (i.e. bears // code 110) 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, &actor, &reason); // Get our room nickname ournick = buddy_getnickname(room_elt->data); if (!ournick) { // It shouldn't happen, probably a server issue const gchar msg[] = "Unexpected groupchat packet!"; scr_LogPrint(LPRINT_LOGNORM, msg); scr_WriteIncomingMessage(roomjid, msg, 0, HBB_PREFIX_INFO, 0); // Send back an unavailable packet xmpp_setstatus(offline, roomjid, "", TRUE); scr_draw_roster(); return; } #define SETSTATUSCODE(VALUE) \ { \ if (G_UNLIKELY(statuscode)) \ scr_LogPrint(LPRINT_DEBUG, "handle_muc_presence: WARNING: " \ "replacing status code %u with %u.", statuscode, VALUE); \ statuscode = VALUE; \ } { // Get the status code LmMessageNode *node; for (node = xmldata -> children; node; node = node -> next) { if (!g_strcmp0(node -> name, "status")) { const char *codestr = lm_message_node_get_attribute(node, "code"); if (codestr) { const char *mesg = NULL; switch (atoi(codestr)) { // initial case 100: mesg = "The room is not anonymous."; break; case 110: // It is our presence our_presence = TRUE; break; // initial case 170: mesg = "The room is logged."; break; // initial case 201: // Room created SETSTATUSCODE(201); break; // initial case 210: // Your nick change (on join) // FIXME: print nick mesg = "The room has changed your nick!"; buddy_setnickname(room_elt->data, rname); ournick = rname; break; case 301: // User banned SETSTATUSCODE(301); break; case 303: // Nick change SETSTATUSCODE(303); break; case 307: // User kicked SETSTATUSCODE(307); break; // XXX (next three) case 321: mesg = "User leaves room due to affilation change."; break; case 322: mesg = "User leaves room, as room is only for members now."; break; case 332: mesg = "User leaves room due to system shutdown."; break; default: scr_LogPrint(LPRINT_DEBUG, "handle_muc_presence: Unknown MUC status code: %s.", codestr); break; } if (mesg) { scr_WriteIncomingMessage(roomjid, mesg, usttime, HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); if (log_muc_conf) hlog_write_message(roomjid, 0, -1, mesg); } } } } } #undef SETSTATUSCODE if (!our_presence) if (ournick && !strcmp(ournick, rname)) our_presence = TRUE; // 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 (our_presence) buddy_setnickname(room_elt->data, mbnick); nickchange = TRUE; } autowhois = buddy_getautowhois(room_elt->data); if (autowhois == autowhois_default) autowhois = (settings_opt_get_int("muc_auto_whois") ? autowhois_on : autowhois_off); // Check for departure/arrival if (statuscode != 303 && ust == offline) { // Somebody is leaving enum { leave=0, kick, ban } how = leave; if (statuscode == 307) how = kick; else if (statuscode == 301) how = ban; // If this is a leave, check if it is ourself if (our_presence) { 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_update_chat_status(FALSE); update_roster = TRUE; } // The message depends on _who_ left, and _how_ if (how) { gchar *mbuf_end; gchar *reason_msg = NULL; // Forced leave if (actor) { mbuf_end = g_strdup_printf("%s from %s by %s", (how == ban ? "banned" : "kicked"), roomjid, actor); } else { mbuf_end = g_strdup_printf("%s from %s", (how == ban ? "banned" : "kicked"), roomjid); } if (reason) reason_msg = g_strdup_printf("\nReason: %s", reason); if (our_presence) mbuf = g_strdup_printf("You have been %s%s", mbuf_end, reason_msg ? reason_msg : ""); else mbuf = g_strdup_printf("%s has been %s%s", rname, mbuf_end, reason_msg ? reason_msg : ""); g_free(reason_msg); g_free(mbuf_end); } else { // Natural leave if (our_presence) { LmMessageNode *destroynode = lm_message_node_find_child(xmldata, "destroy"); if (destroynode) { reason = lm_message_node_get_child_value(destroynode, "reason"); if (reason && *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); } } } g_free(actor); // Display the mbuf message if we're concerned // or if the print_status isn't set to none. if (our_presence || printstatus != status_none) { msgflags = HBB_PREFIX_INFO; flagjoins = buddy_getflagjoins(room_elt->data); if (flagjoins == flagjoins_default && settings_opt_get_int("muc_flag_joins") == 2) flagjoins = flagjoins_all; if (!our_presence && flagjoins != flagjoins_all) msgflags |= HBB_PREFIX_NOFLAG; //silent message if someone else joins, and we care about noone scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0); } if (log_muc_conf) hlog_write_message(roomjid, 0, -1, mbuf); if (our_presence) { scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); g_free(mbuf); return; } g_free(mbuf); } else { enum imstatus old_ust = buddy_getstatus(room_elt->data, rname); if (old_ust == offline && ust != offline) { // Somebody is joining new_member = muc_handle_join(room_elt, rname, roomjid, ournick, printstatus, usttime, log_muc_conf, autowhois, mbjid); } else { // This is a simple member status change if (printstatus == status_all && !nickchange) { const char *old_ustmsg = buddy_getstatusmsg(room_elt->data, rname); if (old_ust != ust || g_strcmp0(old_ustmsg, ustmsg)) { mbuf = g_strdup_printf("%s [%c>%c] %s", rname, imstatus2char[old_ust], 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); if (new_member && autowhois == autowhois_on) { cmd_room_whois(room_elt->data, rname, FALSE); } scr_draw_roster(); }