static gboolean _handle_carbons(xmpp_stanza_t *const stanza) { xmpp_stanza_t *carbons = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CARBONS); if (!carbons) { return FALSE; } char *name = xmpp_stanza_get_name(carbons); if ((g_strcmp0(name, "received") == 0) || (g_strcmp0(name, "sent")) == 0) { xmpp_stanza_t *forwarded = xmpp_stanza_get_child_by_ns(carbons, STANZA_NS_FORWARD); xmpp_stanza_t *message = xmpp_stanza_get_child_by_name(forwarded, STANZA_NAME_MESSAGE); xmpp_ctx_t *ctx = connection_get_ctx(); gchar *to = xmpp_stanza_get_attribute(message, STANZA_ATTR_TO); gchar *from = xmpp_stanza_get_attribute(message, STANZA_ATTR_FROM); // happens when receive a carbon of a self sent message if (!to) to = from; Jid *jid_from = jid_create(from); Jid *jid_to = jid_create(to); Jid *my_jid = jid_create(jabber_get_fulljid()); // check for and deal with message xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(message, STANZA_NAME_BODY); if (body) { char *message_txt = xmpp_stanza_get_text(body); if (message_txt) { // check for pgp encrypted message char *enc_message = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(message, STANZA_NS_ENCRYPTED); if (x) { enc_message = xmpp_stanza_get_text(x); } // if we are the recipient, treat as standard incoming message if(g_strcmp0(my_jid->barejid, jid_to->barejid) == 0){ sv_ev_incoming_carbon(jid_from->barejid, jid_from->resourcepart, message_txt, enc_message); // else treat as a sent message } else { sv_ev_outgoing_carbon(jid_to->barejid, message_txt, enc_message); } xmpp_free(ctx, message_txt); xmpp_free(ctx, enc_message); } } jid_destroy(jid_from); jid_destroy(jid_to); jid_destroy(my_jid); return TRUE; } return FALSE; }
static int _receipt_received_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) { xmpp_stanza_t *receipt = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); char *name = xmpp_stanza_get_name(receipt); if (g_strcmp0(name, "received") != 0) { return 1; } char *id = xmpp_stanza_get_attribute(receipt, STANZA_ATTR_ID); if (!id) { return 1; } char *fulljid = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!fulljid) { return 1; } Jid *jidp = jid_create(fulljid); sv_ev_message_receipt(jidp->barejid, id); jid_destroy(jidp); return 1; }
static int _conference_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) { xmpp_stanza_t *xns_conference = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_warning("Message received with no from attribute, ignoring"); return 1; } Jid *jidp = jid_create(from); if (!jidp) { return 1; } // XEP-0249 char *room = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_JID); if (!room) { jid_destroy(jidp); return 1; } char *reason = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_REASON); char *password = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_PASSWORD); sv_ev_room_invite(INVITE_DIRECT, jidp->barejid, room, reason, password); jid_destroy(jidp); return 1; }
void _receipt_request_handler(xmpp_stanza_t *const stanza) { if (!prefs_get_boolean(PREF_RECEIPTS_SEND)) { return; } char *id = xmpp_stanza_get_id(stanza); if (!id) { return; } xmpp_stanza_t *receipts = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); if (!receipts) { return; } char *receipts_name = xmpp_stanza_get_name(receipts); if (g_strcmp0(receipts_name, "request") != 0) { return; } gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *jid = jid_create(from); _message_send_receipt(jid->fulljid, id); jid_destroy(jid); }
static int _room_config_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (id != NULL) { log_debug("IQ room config handler fired, id: %s.", id); } else { log_debug("IQ room config handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); handle_room_configuration_form_error(from, error_message); free(error_message); return 0; } if (from == NULL) { log_warning("No from attribute for IQ config request result"); handle_room_configuration_form_error(from, "No from attribute for room cofig response."); return 0; } xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query == NULL) { log_warning("No query element found parsing room config response"); handle_room_configuration_form_error(from, "No query element found parsing room config response"); return 0; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); if (x == NULL) { log_warning("No x element found with %s namespace parsing room config response", STANZA_NS_DATA); handle_room_configuration_form_error(from, "No form configuration options available"); return 0; } char *form_type = xmpp_stanza_get_attribute(x, STANZA_ATTR_TYPE); if (g_strcmp0(form_type, "form") != 0) { log_warning("x element not of type 'form' parsing room config response"); handle_room_configuration_form_error(from, "Form not of type 'form' parsing room config response."); return 0; } DataForm *form = form_create(x); handle_room_configure(from, form); return 0; }
static int _muc_user_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *xns_muc_user = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); char *room = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!room) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0045 xmpp_stanza_t *invite = xmpp_stanza_get_child_by_name(xns_muc_user, STANZA_NAME_INVITE); if (!invite) { return 1; } char *invitor_jid = xmpp_stanza_get_attribute(invite, STANZA_ATTR_FROM); if (!invitor_jid) { log_warning("Chat room invite received with no from attribute"); return 1; } Jid *jidp = jid_create(invitor_jid); if (!jidp) { return 1; } char *invitor = jidp->barejid; char *reason = NULL; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(invite, STANZA_NAME_REASON); if (reason_st) { reason = xmpp_stanza_get_text(reason_st); } char *password = NULL; xmpp_stanza_t *password_st = xmpp_stanza_get_child_by_name(xns_muc_user, STANZA_NAME_PASSWORD); if (password_st) { password = xmpp_stanza_get_text(password_st); } sv_ev_room_invite(INVITE_MEDIATED, invitor, room, reason, password); jid_destroy(jidp); if (reason) { xmpp_free(ctx, reason); } if (password) { xmpp_free(ctx, password); } return 1; }
static int _presence_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) { log_debug("Presence stanza handler fired"); char *text = NULL; size_t text_size; xmpp_stanza_to_text(stanza, &text, &text_size); gboolean cont = plugins_on_presence_stanza_receive(text); xmpp_free(connection_get_ctx(), text); if (!cont) { return 1; } const char *type = xmpp_stanza_get_type(stanza); if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { _presence_error_handler(stanza); } if (g_strcmp0(type, STANZA_TYPE_UNAVAILABLE) == 0) { _unavailable_handler(stanza); } if (g_strcmp0(type, STANZA_TYPE_SUBSCRIBE) == 0) { _subscribe_handler(stanza); } if (g_strcmp0(type, STANZA_TYPE_SUBSCRIBED) == 0) { _subscribed_handler(stanza); } if (g_strcmp0(type, STANZA_TYPE_UNSUBSCRIBED) == 0) { _unsubscribed_handler(stanza); } xmpp_stanza_t *mucuser = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (mucuser) { _muc_user_handler(stanza); } _available_handler(stanza); return 1; }
static int _conference_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_stanza_t *xns_conference = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *room = NULL; char *invitor = NULL; char *reason = NULL; if (from == NULL) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0429 room = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_JID); if (room == NULL) { return 1; } Jid *jidp = jid_create(from); if (jidp == NULL) { return 1; } invitor = jidp->barejid; reason = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_REASON); handle_room_invite(INVITE_DIRECT, invitor, room, reason); jid_destroy(jidp); return 1; }
static int _conference_message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *x_muc = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); xmpp_stanza_t *x_groupchat = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); xmpp_stanza_t *captcha = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CAPTCHA); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *room = NULL; char *invitor = NULL; char *reason = NULL; if (from == NULL) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0045 if (x_muc != NULL) { room = from; xmpp_stanza_t *invite = xmpp_stanza_get_child_by_name(x_muc, STANZA_NAME_INVITE); if (invite == NULL) { return 1; } char *invitor_jid = xmpp_stanza_get_attribute(invite, STANZA_ATTR_FROM); if (invitor_jid == NULL) { log_warning("Chat room invite received with no from attribute"); return 1; } Jid *jidp = jid_create(invitor_jid); invitor = jidp->barejid; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(invite, STANZA_NAME_REASON); if (reason_st != NULL) { reason = xmpp_stanza_get_text(reason_st); } prof_handle_room_invite(INVITE_MEDIATED, invitor, room, reason); jid_destroy(jidp); if (reason != NULL) { xmpp_free(ctx, reason); } // XEP-0429 } else if (x_groupchat != NULL) { room = xmpp_stanza_get_attribute(x_groupchat, STANZA_ATTR_JID); if (room == NULL) { return 1; } Jid *jidp = jid_create(from); invitor = jidp->barejid; reason = xmpp_stanza_get_attribute(x_groupchat, STANZA_ATTR_REASON); prof_handle_room_invite(INVITE_DIRECT, invitor, room, reason); jid_destroy(jidp); // XEP-0158 } else if (captcha != NULL) { xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); if (body != NULL) { char *message = xmpp_stanza_get_text(body); if (message != NULL) { prof_handle_room_broadcast(from, message); xmpp_free(ctx, message); } } } return 1; }
Capabilities * caps_create(xmpp_stanza_t *query) { char *category = NULL; char *type = NULL; char *name = NULL; char *software = NULL; char *software_version = NULL; char *os = NULL; char *os_version = NULL; GSList *features = NULL; xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); if (softwareinfo != NULL) { DataForm *form = form_create(softwareinfo); FormField *formField = NULL; char *form_type = form_get_form_type_field(form); if (g_strcmp0(form_type, STANZA_DATAFORM_SOFTWARE) == 0) { GSList *field = form->fields; while (field != NULL) { formField = field->data; if (formField->values != NULL) { if (strcmp(formField->var, "software") == 0) { software = strdup(formField->values->data); } else if (strcmp(formField->var, "software_version") == 0) { software_version = strdup(formField->values->data); } else if (strcmp(formField->var, "os") == 0) { os = strdup(formField->values->data); } else if (strcmp(formField->var, "os_version") == 0) { os_version = strdup(formField->values->data); } } field = g_slist_next(field); } } form_destroy(form); } xmpp_stanza_t *child = xmpp_stanza_get_children(query); GSList *identity_stanzas = NULL; while (child != NULL) { if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) { features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var"))); } if (g_strcmp0(xmpp_stanza_get_name(child), "identity") == 0) { identity_stanzas = g_slist_append(identity_stanzas, child); } child = xmpp_stanza_get_next(child); } // find identity by locale const gchar* const *langs = g_get_language_names(); int num_langs = g_strv_length((gchar**)langs); xmpp_stanza_t *found = NULL; GSList *curr_identity = identity_stanzas; while (curr_identity) { xmpp_stanza_t *id_stanza = curr_identity->data; char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); if (stanza_lang) { int i = 0; for (i = 0; i < num_langs; i++) { if (g_strcmp0(langs[i], stanza_lang) == 0) { found = id_stanza; break; } } } if (found) { break; } curr_identity = g_slist_next(curr_identity); } // not lang match, use default with no lang if (!found) { curr_identity = identity_stanzas; while (curr_identity) { xmpp_stanza_t *id_stanza = curr_identity->data; char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); if (!stanza_lang) { found = id_stanza; break; } curr_identity = g_slist_next(curr_identity); } } // no matching lang, no identity without lang, use first if (!found) { if (identity_stanzas) { found = identity_stanzas->data; } } g_slist_free(identity_stanzas); if (found) { category = xmpp_stanza_get_attribute(found, "category"); type = xmpp_stanza_get_attribute(found, "type"); name = xmpp_stanza_get_attribute(found, "name"); } Capabilities *new_caps = malloc(sizeof(struct capabilities_t)); if (category != NULL) { new_caps->category = strdup(category); } else { new_caps->category = NULL; } if (type != NULL) { new_caps->type = strdup(type); } else { new_caps->type = NULL; } if (name != NULL) { new_caps->name = strdup(name); } else { new_caps->name = NULL; } if (software != NULL) { new_caps->software = software; } else { new_caps->software = NULL; } if (software_version != NULL) { new_caps->software_version = software_version; } else { new_caps->software_version = NULL; } if (os != NULL) { new_caps->os = os; } else { new_caps->os = NULL; } if (os_version != NULL) { new_caps->os_version = os_version; } else { new_caps->os_version = NULL; } if (features != NULL) { new_caps->features = features; } else { new_caps->features = NULL; } return new_caps; }
static int _iq_handle_discoinfo_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { log_debug("Recieved diso#info response"); const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (g_strcmp0(id, "discoinforeq") == 0) { GSList *identities = NULL; GSList *features = NULL; xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query != NULL) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); while (child != NULL) { const char *stanza_name = xmpp_stanza_get_name(child); if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); if (var != NULL) { features = g_slist_append(features, strdup(var)); } } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE); const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); if ((name != NULL) || (category != NULL) || (type != NULL)) { DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); if (name != NULL) { identity->name = strdup(name); } else { identity->name = NULL; } if (category != NULL) { identity->category = strdup(category); } else { identity->category = NULL; } if (type != NULL) { identity->type = strdup(type); } else { identity->type = NULL; } identities = g_slist_append(identities, identity); } } child = xmpp_stanza_get_next(child); } handle_disco_info(from, identities, features); g_slist_free_full(features, free); g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); } } else if ((id != NULL) && (g_str_has_prefix(id, "capsreq"))) { log_debug("Response to query: %s", id); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { return 1; } char *caps_key = NULL; // xep-0115 if (g_strcmp0(id, "capsreq") == 0) { log_debug("xep-0115 supported capabilities"); caps_key = strdup(node); // validate sha1 gchar **split = g_strsplit(node, "#", -1); char *given_sha1 = split[1]; char *generated_sha1 = caps_create_sha1_str(query); if (g_strcmp0(given_sha1, generated_sha1) != 0) { log_info("Generated sha-1 does not match given:"); log_info("Generated : %s", generated_sha1); log_info("Given : %s", given_sha1); g_free(generated_sha1); g_strfreev(split); free(caps_key); return 1; } g_free(generated_sha1); g_strfreev(split); // non supported hash, or legacy caps } else { log_debug("Unsupported hash, or legacy capabilities"); caps_key = strdup(id + 8); log_debug("Caps key: %s", caps_key); } // already cached if (caps_contains(caps_key)) { log_info("Client info already cached."); free(caps_key); return 1; } log_debug("Client info not cached"); const char *category = NULL; const char *type = NULL; const char *name = NULL; const char *software = NULL; const char *software_version = NULL; const char *os = NULL; const char *os_version = NULL; GSList *features = NULL; xmpp_stanza_t *identity = xmpp_stanza_get_child_by_name(query, "identity"); if (identity != NULL) { category = xmpp_stanza_get_attribute(identity, "category"); type = xmpp_stanza_get_attribute(identity, "type"); name = xmpp_stanza_get_attribute(identity, "name"); } xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); if (softwareinfo != NULL) { DataForm *form = stanza_create_form(softwareinfo); FormField *formField = NULL; if (g_strcmp0(form->form_type, STANZA_DATAFORM_SOFTWARE) == 0) { GSList *field = form->fields; while (field != NULL) { formField = field->data; if (formField->values != NULL) { if (strcmp(formField->var, "software") == 0) { software = formField->values->data; } else if (strcmp(formField->var, "software_version") == 0) { software_version = formField->values->data; } else if (strcmp(formField->var, "os") == 0) { os = formField->values->data; } else if (strcmp(formField->var, "os_version") == 0) { os_version = formField->values->data; } } field = g_slist_next(field); } } stanza_destroy_form(form); } xmpp_stanza_t *child = xmpp_stanza_get_children(query); while (child != NULL) { if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) { features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var"))); } child = xmpp_stanza_get_next(child); } caps_add(caps_key, category, type, name, software, software_version, os, os_version, features); free(caps_key); } return 1; }
/** Fire off all stanza handlers that match. * This function is called internally by the event loop whenever stanzas * are received from the XMPP server. * * @param conn a Strophe connection object * @param stanza a Strophe stanza object */ void handler_fire_stanza(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza) { xmpp_handlist_t *item, *prev; char *id, *ns, *name, *type; /* call id handlers */ id = xmpp_stanza_get_id(stanza); if (id) { prev = NULL; item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); while (item) { xmpp_handlist_t *next = item->next; if (item->user_handler && !conn->authenticated) { item = next; continue; } if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { /* handler is one-shot, so delete it */ if (prev) prev->next = next; else { hash_drop(conn->id_handlers, id); hash_add(conn->id_handlers, id, next); } xmpp_free(conn->ctx, item->id); xmpp_free(conn->ctx, item); item = NULL; } if (item) prev = item; item = next; } } /* call handlers */ ns = xmpp_stanza_get_ns(stanza); name = xmpp_stanza_get_name(stanza); type = xmpp_stanza_get_type(stanza); /* enable all added handlers */ for (item = conn->handlers; item; item = item->next) item->enabled = 1; prev = NULL; item = conn->handlers; while (item) { /* skip newly added handlers */ if (!item->enabled) { prev = item; item = item->next; continue; } /* don't call user handlers until authentication succeeds */ if (item->user_handler && !conn->authenticated) { prev = item; item = item->next; continue; } if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) || xmpp_stanza_get_child_by_ns(stanza, item->ns)) && (!item->name || (name && strcmp(name, item->name) == 0)) && (!item->type || (type && strcmp(type, item->type) == 0))) if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { /* handler is one-shot, so delete it */ if (prev) prev->next = item->next; else conn->handlers = item->next; if (item->ns) xmpp_free(conn->ctx, item->ns); if (item->name) xmpp_free(conn->ctx, item->name); if (item->type) xmpp_free(conn->ctx, item->type); xmpp_free(conn->ctx, item); item = NULL; } if (item) { prev = item; item = item->next; } else if (prev) item = prev->next; else item = conn->handlers; } }
static void _muc_user_occupant_handler(xmpp_stanza_t *stanza) { const char *from = xmpp_stanza_get_from(stanza); Jid *from_jid = jid_create(from); log_debug("Room presence received from %s", from_jid->fulljid); char *room = from_jid->barejid; char *nick = from_jid->resourcepart; char *status_str = stanza_get_status(stanza, NULL); const char *type = xmpp_stanza_get_type(stanza); if (g_strcmp0(type, STANZA_TYPE_UNAVAILABLE) == 0) { // handle nickname change const char *new_nick = stanza_get_new_nick(stanza); if (new_nick) { muc_occupant_nick_change_start(room, new_nick, nick); // handle left room } else { GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER); // kicked from room if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0)) { const char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_occupent_kicked(room, nick, actor, reason); free(reason); // banned from room } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0)) { const char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_occupent_banned(room, nick, actor, reason); free(reason); // normal exit } else { sv_ev_room_occupant_offline(room, nick, "offline", status_str); } g_slist_free_full(status_codes, free); } // room occupant online } else { // send disco info for capabilities, if not cached XMPPCaps *caps = stanza_parse_caps(stanza); if (caps) { log_info("Presence contains capabilities."); _handle_caps(from, caps); } stanza_free_caps(caps); const char *actor = stanza_get_actor(stanza); char *show_str = stanza_get_show(stanza, "online"); char *reason = stanza_get_reason(stanza); const char *jid = NULL; const char *role = NULL; const char *affiliation = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM); if (item) { jid = xmpp_stanza_get_attribute(item, "jid"); role = xmpp_stanza_get_attribute(item, "role"); affiliation = xmpp_stanza_get_attribute(item, "affiliation"); } } sv_ev_muc_occupant_online(room, nick, jid, role, affiliation, actor, reason, show_str, status_str); free(show_str); free(reason); } jid_destroy(from_jid); free(status_str); }
static void _muc_user_self_handler(xmpp_stanza_t *stanza) { const char *from = xmpp_stanza_get_from(stanza); Jid *from_jid = jid_create(from); log_debug("Room self presence received from %s", from_jid->fulljid); char *room = from_jid->barejid; const char *type = xmpp_stanza_get_type(stanza); if (g_strcmp0(type, STANZA_TYPE_UNAVAILABLE) == 0) { // handle nickname change const char *new_nick = stanza_get_new_nick(stanza); if (new_nick) { muc_nick_change_start(room, new_nick); // handle left room } else { GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER); // room destroyed if (stanza_room_destroyed(stanza)) { const char *new_jid = stanza_get_muc_destroy_alternative_room(stanza); char *password = stanza_get_muc_destroy_alternative_password(stanza); char *reason = stanza_get_muc_destroy_reason(stanza); sv_ev_room_destroyed(room, new_jid, password, reason); free(password); free(reason); // kicked from room } else if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0)) { const char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_kicked(room, actor, reason); free(reason); // banned from room } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0)) { const char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_banned(room, actor, reason); free(reason); // normal exit } else { sv_ev_leave_room(room); } g_slist_free_full(status_codes, free); } } else { gboolean config_required = stanza_muc_requires_config(stanza); const char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); char *nick = from_jid->resourcepart; char *show_str = stanza_get_show(stanza, "online"); char *status_str = stanza_get_status(stanza, NULL); const char *jid = NULL; const char *role = NULL; const char *affiliation = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM); if (item) { jid = xmpp_stanza_get_attribute(item, "jid"); role = xmpp_stanza_get_attribute(item, "role"); affiliation = xmpp_stanza_get_attribute(item, "affiliation"); } } sv_ev_muc_self_online(room, nick, config_required, role, affiliation, actor, reason, jid, show_str, status_str); free(show_str); free(status_str); free(reason); } jid_destroy(from_jid); }
static void _available_handler(xmpp_stanza_t *const stanza) { inp_nonblocking(TRUE); // handler still fires if error if (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_ERROR) == 0) { return; } // handler still fires if other types if ((g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_UNAVAILABLE) == 0) || (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_SUBSCRIBE) == 0) || (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_SUBSCRIBED) == 0) || (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_UNSUBSCRIBED) == 0)) { return; } // handler still fires for muc presence if (stanza_is_muc_presence(stanza)) { return; } int err = 0; XMPPPresence *xmpp_presence = stanza_parse_presence(stanza, &err); if (!xmpp_presence) { const char *from = NULL; switch(err) { case STANZA_PARSE_ERROR_NO_FROM: log_warning("Available presence handler fired with no from attribute."); break; case STANZA_PARSE_ERROR_INVALID_FROM: from = xmpp_stanza_get_from(stanza); log_warning("Available presence handler fired with invalid from attribute: %s", from); break; default: log_warning("Available presence handler fired, could not parse stanza."); break; } return; } else { char *jid = jid_fulljid_or_barejid(xmpp_presence->jid); log_debug("Presence available handler fired for: %s", jid); } xmpp_conn_t *conn = connection_get_conn(); const char *my_jid_str = xmpp_conn_get_jid(conn); Jid *my_jid = jid_create(my_jid_str); XMPPCaps *caps = stanza_parse_caps(stanza); if ((g_strcmp0(my_jid->fulljid, xmpp_presence->jid->fulljid) != 0) && caps) { log_info("Presence contains capabilities."); char *jid = jid_fulljid_or_barejid(xmpp_presence->jid); _handle_caps(jid, caps); } stanza_free_caps(caps); Resource *resource = stanza_resource_from_presence(xmpp_presence); if (g_strcmp0(xmpp_presence->jid->barejid, my_jid->barejid) == 0) { connection_add_available_resource(resource); } else { char *pgpsig = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_SIGNED); if (x) { pgpsig = xmpp_stanza_get_text(x); } sv_ev_contact_online(xmpp_presence->jid->barejid, resource, xmpp_presence->last_activity, pgpsig); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_free(ctx, pgpsig); } jid_destroy(my_jid); stanza_free_presence(xmpp_presence); }
static void _presence_error_handler(xmpp_stanza_t *const stanza) { const char *xmlns = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); if (x) { xmlns = xmpp_stanza_get_ns(x); } const char *from = xmpp_stanza_get_from(stanza); xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); // handle MUC join errors if (g_strcmp0(xmlns, STANZA_NS_MUC) == 0) { const char *error_cond = NULL; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_ns(error_stanza, STANZA_NS_STANZAS); if (reason_st) { error_cond = xmpp_stanza_get_name(reason_st); } if (error_cond == NULL) { error_cond = "unknown"; } Jid *fulljid = jid_create(from); log_info("Error joining room: %s, reason: %s", fulljid->barejid, error_cond); if (muc_active(fulljid->barejid)) { muc_leave(fulljid->barejid); } cons_show_error("Error joining room %s, reason: %s", fulljid->barejid, error_cond); jid_destroy(fulljid); return; } GString *log_msg = g_string_new("presence stanza error received"); const char *id = xmpp_stanza_get_id(stanza); if (id) { g_string_append(log_msg, " id="); g_string_append(log_msg, id); } if (from) { g_string_append(log_msg, " from="); g_string_append(log_msg, from); } const char *type = NULL; if (error_stanza) { type = xmpp_stanza_get_type(error_stanza); } if (type) { g_string_append(log_msg, " type="); g_string_append(log_msg, type); } // stanza_get_error never returns NULL char *err_msg = stanza_get_error_message(stanza); g_string_append(log_msg, " error="); g_string_append(log_msg, err_msg); log_info(log_msg->str); g_string_free(log_msg, TRUE); if (from) { ui_handle_recipient_error(from, err_msg); } else { ui_handle_error(err_msg); } free(err_msg); }
static int _chat_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) { // ignore if type not chat or absent char *type = xmpp_stanza_get_type(stanza); if (!(g_strcmp0(type, "chat") == 0 || type == NULL)) { return 1; } // check if carbon message gboolean res = _handle_carbons(stanza); if (res) { return 1; } // ignore handled namespaces xmpp_stanza_t *conf = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); xmpp_stanza_t *captcha = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CAPTCHA); if (conf || captcha) { return 1; } // some clients send the mucuser namespace with private messages // if the namespace exists, and the stanza contains a body element, assume its a private message // otherwise exit the handler xmpp_stanza_t *mucuser = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); if (mucuser && body == NULL) { return 1; } gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *jid = jid_create(from); // private message from chat room use full jid (room/nick) if (muc_active(jid->barejid)) { _private_chat_handler(stanza, jid->fulljid); jid_destroy(jid); return 1; } // standard chat message, use jid without resource xmpp_ctx_t *ctx = connection_get_ctx(); GDateTime *timestamp = stanza_get_delay(stanza); if (body) { char *message = xmpp_stanza_get_text(body); if (message) { char *enc_message = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_ENCRYPTED); if (x) { enc_message = xmpp_stanza_get_text(x); } sv_ev_incoming_message(jid->barejid, jid->resourcepart, message, enc_message, timestamp); xmpp_free(ctx, enc_message); _receipt_request_handler(stanza); xmpp_free(ctx, message); } } // handle chat sessions and states if (!timestamp && jid->resourcepart) { gboolean gone = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_GONE) != NULL; gboolean typing = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_COMPOSING) != NULL; gboolean paused = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PAUSED) != NULL; gboolean inactive = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_INACTIVE) != NULL; if (gone) { sv_ev_gone(jid->barejid, jid->resourcepart); } else if (typing) { sv_ev_typing(jid->barejid, jid->resourcepart); } else if (paused) { sv_ev_paused(jid->barejid, jid->resourcepart); } else if (inactive) { sv_ev_inactive(jid->barejid, jid->resourcepart); } else if (stanza_contains_chat_state(stanza)) { sv_ev_activity(jid->barejid, jid->resourcepart, TRUE); } else { sv_ev_activity(jid->barejid, jid->resourcepart, FALSE); } } if (timestamp) g_date_time_unref(timestamp); jid_destroy(jid); return 1; }
static int _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *id = xmpp_stanza_get_id(stanza); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); char *xmlns = NULL; if (x != NULL) { xmlns = xmpp_stanza_get_ns(x); } char *type = NULL; if (error_stanza != NULL) { type = xmpp_stanza_get_attribute(error_stanza, STANZA_ATTR_TYPE); } // handle MUC join errors if (g_strcmp0(xmlns, STANZA_NS_MUC) == 0) { Jid *fulljid = jid_create(from); char *error_cond = NULL; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_ns(error_stanza, STANZA_NS_STANZAS); if (reason_st != NULL) { error_cond = xmpp_stanza_get_name(reason_st); } if (error_cond == NULL) { error_cond = "unknown"; } log_info("Error joining room: %s, reason: %s", fulljid->barejid, error_cond); handle_room_join_error(fulljid->barejid, error_cond); return 1; } // stanza_get_error never returns NULL char *err_msg = stanza_get_error_message(stanza); GString *log_msg = g_string_new("presence stanza error received"); if (id != NULL) { g_string_append(log_msg, " id="); g_string_append(log_msg, id); } if (from != NULL) { g_string_append(log_msg, " from="); g_string_append(log_msg, from); } if (type != NULL) { g_string_append(log_msg, " type="); g_string_append(log_msg, type); } g_string_append(log_msg, " error="); g_string_append(log_msg, err_msg); log_info(log_msg->str); g_string_free(log_msg, TRUE); handle_presence_error(from, type, err_msg); free(err_msg); return 1; }