void jabber_ibb_session_destroy(JabberIBBSession *sess) { purple_debug_info("jabber", "IBB: destroying session %p %s\n", sess, sess->sid); if (jabber_ibb_session_get_state(sess) == JABBER_IBB_SESSION_OPENED) { jabber_ibb_session_close(sess); } if (sess->last_iq_id) { purple_debug_info("jabber", "IBB: removing callback for <iq/> %s\n", sess->last_iq_id); jabber_iq_remove_callback_by_id(jabber_ibb_session_get_js(sess), sess->last_iq_id); g_free(sess->last_iq_id); sess->last_iq_id = NULL; } g_hash_table_remove(jabber_ibb_sessions, sess->sid); g_free(sess->id); g_free(sess->sid); g_free(sess->who); g_free(sess); }
void jabber_iq_parse(JabberStream *js, xmlnode *packet) { JabberCallbackData *jcd; xmlnode *query, *error, *x; const char *xmlns; const char *type, *id, *from; JabberIqHandler *jih; query = xmlnode_get_child(packet, "query"); type = xmlnode_get_attrib(packet, "type"); from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); if(type == NULL || !(!strcmp(type, "get") || !strcmp(type, "set") || !strcmp(type, "result") || !strcmp(type, "error"))) { purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n", type ? type : "(null)"); return; } /* All IQs must have an ID, so send an error for a set/get that doesn't */ if(!id || !*id) { if(!strcmp(type, "set") || !strcmp(type, "get")) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode_free(iq->node); iq->node = xmlnode_copy(packet); xmlnode_set_attrib(iq->node, "to", from); xmlnode_remove_attrib(iq->node, "from"); xmlnode_set_attrib(iq->node, "type", "error"); /* This id is clearly not useful, but we must put something there for a valid stanza */ iq->id = jabber_get_next_id(js); xmlnode_set_attrib(iq->node, "id", iq->id); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "type", "modify"); x = xmlnode_new_child(error, "bad-request"); xmlnode_set_namespace(x, "urn:ietf:params:xml:ns:xmpp-stanzas"); jabber_iq_send(iq); } else purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", type); return; } /* First, lets see if a special callback got registered */ if(!strcmp(type, "result") || !strcmp(type, "error")) { if(id && *id && (jcd = g_hash_table_lookup(js->iq_callbacks, id))) { jcd->callback(js, packet, jcd->data); jabber_iq_remove_callback_by_id(js, id); return; } } /* Apparently not, so lets see if we have a pre-defined handler */ if(query && (xmlns = xmlnode_get_namespace(query))) { if((jih = g_hash_table_lookup(iq_handlers, xmlns))) { jih(js, packet); return; } } if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) { jabber_si_parse(js, packet); return; } if(xmlnode_get_child_with_namespace(packet, "new-mail", "google:mail:notify")) { jabber_gmail_poke(js, packet); return; } purple_debug_info("jabber", "jabber_iq_parse\n"); if(xmlnode_get_child_with_namespace(packet, "ping", "urn:xmpp:ping")) { jabber_ping_parse(js, packet); return; } if (xmlnode_get_child_with_namespace(packet, "data", XEP_0231_NAMESPACE)) { jabber_data_parse(js, packet); return; } /* If we get here, send the default error reply mandated by XMPP-CORE */ if(!strcmp(type, "set") || !strcmp(type, "get")) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode_free(iq->node); iq->node = xmlnode_copy(packet); xmlnode_set_attrib(iq->node, "to", from); xmlnode_remove_attrib(iq->node, "from"); xmlnode_set_attrib(iq->node, "type", "error"); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "type", "cancel"); xmlnode_set_attrib(error, "code", "501"); x = xmlnode_new_child(error, "feature-not-implemented"); xmlnode_set_namespace(x, "urn:ietf:params:xml:ns:xmpp-stanzas"); jabber_iq_send(iq); } }
void jabber_iq_parse(JabberStream *js, PurpleXmlNode *packet) { JabberIqCallbackData *jcd; PurpleXmlNode *child, *error, *x; const char *xmlns; const char *iq_type, *id, *from; JabberIqType type = JABBER_IQ_NONE; gboolean signal_return; JabberID *from_id; from = purple_xmlnode_get_attrib(packet, "from"); id = purple_xmlnode_get_attrib(packet, "id"); iq_type = purple_xmlnode_get_attrib(packet, "type"); /* * Ensure the 'from' attribute is valid. No point in handling a stanza * of which we don't understand where it came from. */ from_id = jabber_id_new(from); if (from && !from_id) { purple_debug_error("jabber", "Received an iq with an invalid from: %s\n", from); return; } /* * child will be either the first tag child or NULL if there is no child. * Historically, we used just the 'query' subchild, but newer XEPs use * differently named children. Grabbing the first child is (for the time * being) sufficient. */ for (child = packet->child; child; child = child->next) { if (child->type == PURPLE_XMLNODE_TYPE_TAG) break; } if (iq_type) { if (!strcmp(iq_type, "get")) type = JABBER_IQ_GET; else if (!strcmp(iq_type, "set")) type = JABBER_IQ_SET; else if (!strcmp(iq_type, "result")) type = JABBER_IQ_RESULT; else if (!strcmp(iq_type, "error")) type = JABBER_IQ_ERROR; } if (type == JABBER_IQ_NONE) { purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n", iq_type ? iq_type : "(null)"); jabber_id_free(from_id); return; } /* All IQs must have an ID, so send an error for a set/get that doesn't */ if(!id || !*id) { if(type == JABBER_IQ_SET || type == JABBER_IQ_GET) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); purple_xmlnode_free(iq->node); iq->node = purple_xmlnode_copy(packet); if (from) { purple_xmlnode_set_attrib(iq->node, "to", from); purple_xmlnode_remove_attrib(iq->node, "from"); } purple_xmlnode_set_attrib(iq->node, "type", "error"); /* This id is clearly not useful, but we must put something there for a valid stanza */ iq->id = jabber_get_next_id(js); purple_xmlnode_set_attrib(iq->node, "id", iq->id); error = purple_xmlnode_new_child(iq->node, "error"); purple_xmlnode_set_attrib(error, "type", "modify"); x = purple_xmlnode_new_child(error, "bad-request"); purple_xmlnode_set_namespace(x, NS_XMPP_STANZAS); jabber_iq_send(iq); } else purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", iq_type); jabber_id_free(from_id); return; } signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-receiving-iq", js->gc, iq_type, id, from, packet)); if (signal_return) { jabber_id_free(from_id); return; } /* First, lets see if a special callback got registered */ if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) { jcd = g_hash_table_lookup(js->iq_callbacks, id); if (jcd) { if (does_reply_from_match_request_to(js, jcd->to, from_id)) { jcd->callback(js, from, type, id, packet, jcd->data); jabber_iq_remove_callback_by_id(js, id); jabber_id_free(from_id); return; } else { char *expected_to; if (jcd->to) { expected_to = jabber_id_get_full_jid(jcd->to); } else { expected_to = jabber_id_get_bare_jid(js->user); } purple_debug_error("jabber", "Got a result iq with id %s from %s instead of expected %s!\n", id, from ? from : "(null)", expected_to); g_free(expected_to); } } } /* * Apparently not, so let's see if we have a pre-defined handler * or if an outside plugin is interested. */ if(child && (xmlns = purple_xmlnode_get_namespace(child))) { char *key = g_strdup_printf("%s %s", child->name, xmlns); JabberIqHandler *jih = g_hash_table_lookup(iq_handlers, key); int signal_ref = GPOINTER_TO_INT(g_hash_table_lookup(signal_iq_handlers, key)); g_free(key); if (signal_ref > 0) { signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-watched-iq", js->gc, iq_type, id, from, child)); if (signal_return) { jabber_id_free(from_id); return; } } if(jih) { jih(js, from, type, id, child); jabber_id_free(from_id); return; } } purple_debug_misc("jabber", "Unhandled IQ with id %s\n", id); /* If we get here, send the default error reply mandated by XMPP-CORE */ if(type == JABBER_IQ_SET || type == JABBER_IQ_GET) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); purple_xmlnode_free(iq->node); iq->node = purple_xmlnode_copy(packet); if (from) { purple_xmlnode_set_attrib(iq->node, "to", from); purple_xmlnode_remove_attrib(iq->node, "from"); } purple_xmlnode_set_attrib(iq->node, "type", "error"); error = purple_xmlnode_new_child(iq->node, "error"); purple_xmlnode_set_attrib(error, "type", "cancel"); purple_xmlnode_set_attrib(error, "code", "501"); x = purple_xmlnode_new_child(error, "feature-not-implemented"); purple_xmlnode_set_namespace(x, NS_XMPP_STANZAS); jabber_iq_send(iq); } jabber_id_free(from_id); }