static void test_xmlnode_prefixes(void) { const char *xml_doc = "<iq type='get' xmlns='jabber:client' xmlns:ping='urn:xmpp:ping'>" "<ping:ping>" "<child1>" "<ping:child2></ping:child2>" /* xmlns='jabber:child' */ "</child1>" "</ping:ping>" "</iq>"; char *str; PurpleXmlNode *xml, *reparsed; xml = purple_xmlnode_from_str(xml_doc, -1); check_doc_structure(xml); /* Check that purple_xmlnode_from_str(purple_xmlnode_to_str(xml, NULL), -1) is idempotent. */ str = purple_xmlnode_to_str(xml, NULL); g_assert_nonnull(str); reparsed = purple_xmlnode_from_str(str, -1); g_assert_nonnull(reparsed); check_doc_structure(reparsed); g_free(str); purple_xmlnode_free(xml); purple_xmlnode_free(reparsed); }
PurpleXmlNode * purple_xmlnode_from_str(const char *str, gssize size) { struct _xmlnode_parser_data *xpd; PurpleXmlNode *ret; gsize real_size; g_return_val_if_fail(str != NULL, NULL); real_size = size < 0 ? strlen(str) : (gsize)size; xpd = g_new0(struct _xmlnode_parser_data, 1); if (xmlSAXUserParseMemory(&purple_xmlnode_parser_libxml, xpd, str, real_size) < 0) { while(xpd->current && xpd->current->parent) xpd->current = xpd->current->parent; if(xpd->current) purple_xmlnode_free(xpd->current); xpd->current = NULL; } ret = xpd->current; if (xpd->error) { ret = NULL; if (xpd->current) purple_xmlnode_free(xpd->current); } g_free(xpd); return ret; }
void purple_xmlnode_remove_attrib(PurpleXmlNode *node, const char *attr) { PurpleXmlNode *attr_node, *sibling = NULL; g_return_if_fail(node != NULL); g_return_if_fail(attr != NULL); attr_node = node->child; while (attr_node) { if(attr_node->type == PURPLE_XMLNODE_TYPE_ATTRIB && purple_strequal(attr_node->name, attr)) { if (node->lastchild == attr_node) { node->lastchild = sibling; } if (sibling == NULL) { node->child = attr_node->next; purple_xmlnode_free(attr_node); attr_node = node->child; } else { sibling->next = attr_node->next; sibling = attr_node->next; purple_xmlnode_free(attr_node); attr_node = sibling; } } else { attr_node = attr_node->next; } sibling = attr_node; } }
static gboolean msn_oim_request_helper(MsnOimRequestData *data) { MsnSession *session = data->oim->session; if (data->send) { /* The Sending of OIM's uses a different token for some reason. */ PurpleXmlNode *ticket; ticket = purple_xmlnode_get_child(data->body, "Header/Ticket"); purple_xmlnode_set_attrib(ticket, "passport", msn_nexus_get_token_str(session->nexus, MSN_AUTH_LIVE_SECURE)); } else { PurpleXmlNode *passport; PurpleXmlNode *xml_t; PurpleXmlNode *xml_p; GHashTable *token; const char *msn_t; const char *msn_p; token = msn_nexus_get_token(session->nexus, MSN_AUTH_MESSENGER_WEB); g_return_val_if_fail(token != NULL, FALSE); msn_t = g_hash_table_lookup(token, "t"); msn_p = g_hash_table_lookup(token, "p"); g_return_val_if_fail(msn_t != NULL, FALSE); g_return_val_if_fail(msn_p != NULL, FALSE); passport = purple_xmlnode_get_child(data->body, "Header/PassportCookie"); xml_t = purple_xmlnode_get_child(passport, "t"); xml_p = purple_xmlnode_get_child(passport, "p"); /* frees old token text, or the 'EMPTY' text if first time */ purple_xmlnode_free(xml_t->child); purple_xmlnode_free(xml_p->child); purple_xmlnode_insert_data(xml_t, msn_t, -1); purple_xmlnode_insert_data(xml_p, msn_p, -1); } msn_soap_service_send_message(session->soap, msn_soap_message_new(data->action, purple_xmlnode_copy(data->body)), data->host, data->url, FALSE, msn_oim_request_cb, data); return FALSE; }
static gboolean ggp_roster_send_update_contact_remove(PurpleConnection *gc, ggp_roster_change *change) { PurpleAccount *account = purple_connection_get_account(gc); ggp_roster_content *content = ggp_roster_get_rdata(gc)->content; uin_t uin = change->data.uin; PurpleBuddy *buddy; PurpleXmlNode *buddy_node; g_return_val_if_fail(change->type == GGP_ROSTER_CHANGE_CONTACT_REMOVE, FALSE); buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); if (buddy) { purple_debug_info("gg", "ggp_roster_send_update_contact_remove:" " contact %u re-added\n", uin); return TRUE; } buddy_node = g_hash_table_lookup(content->contact_nodes, GINT_TO_POINTER(uin)); if (!buddy_node) /* already removed */ return TRUE; purple_debug_info("gg", "ggp_roster_send_update_contact_remove: " "removing %u\n", uin); purple_xmlnode_free(buddy_node); g_hash_table_remove(content->contact_nodes, GINT_TO_POINTER(uin)); return TRUE; }
static void purple_smileys_load(void) { PurpleXmlNode *root_node, *profile_node; PurpleXmlNode *smileyset_node = NULL; PurpleXmlNode *smiley_node; smileys_loaded = TRUE; root_node = purple_util_read_xml_from_file(XML_FILE_NAME, _(SMILEYS_LOG_ID)); if (root_node == NULL) return; /* See the top comments above to understand why initial tag elements * are not being considered by now. */ profile_node = purple_xmlnode_get_child(root_node, XML_PROFILE_TAG); if (profile_node) smileyset_node = purple_xmlnode_get_child(profile_node, XML_SMILEY_SET_TAG); if (smileyset_node) { smiley_node = purple_xmlnode_get_child(smileyset_node, XML_SMILEY_TAG); for (; smiley_node != NULL; smiley_node = purple_xmlnode_get_next_twin(smiley_node)) { parse_smiley(smiley_node); } } purple_xmlnode_free(root_node); }
static void test_strip_prefixes(void) { const char *xml_doc = "<message xmlns='jabber:client' from='[email protected]/resource' to='*****@*****.**' type='chat' id='purple'>" "<cha:active xmlns:cha='http://jabber.org/protocol/chatstates'/>" "<body>xvlc xvlc</body>" "<im:html xmlns:im='http://jabber.org/protocol/xhtml-im'>" "<xht:body xmlns:xht='http://www.w3.org/1999/xhtml'>" "<xht:p>xvlc <xht:span style='font-weight: bold;'>xvlc</xht:span></xht:p>" "</xht:body>" "</im:html>" "</message>"; const char *out = "<message xmlns='jabber:client' from='[email protected]/resource' to='*****@*****.**' type='chat' id='purple'>" "<active xmlns:cha='http://jabber.org/protocol/chatstates' xmlns='http://jabber.org/protocol/chatstates'/>" "<body>xvlc xvlc</body>" "<html xmlns:im='http://jabber.org/protocol/xhtml-im' xmlns='http://jabber.org/protocol/xhtml-im'>" "<body xmlns:xht='http://www.w3.org/1999/xhtml' xmlns='http://www.w3.org/1999/xhtml'>" "<p>xvlc <span style='font-weight: bold;'>xvlc</span></p>" "</body>" "</html>" "</message>"; char *str; PurpleXmlNode *xml; xml = purple_xmlnode_from_str(xml_doc, -1); g_assert_nonnull(xml); purple_xmlnode_strip_prefixes(xml); str = purple_xmlnode_to_str(xml, NULL); g_assert_cmpstr(out, ==, str); g_free(str); purple_xmlnode_free(xml); }
void jabber_auth_handle_failure(JabberStream *js, PurpleXmlNode *packet) { PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; char *msg = NULL; if (js->auth_mech && js->auth_mech->handle_failure) { PurpleXmlNode *stanza = NULL; JabberSaslState state = js->auth_mech->handle_failure(js, packet, &stanza, &msg); if (state != JABBER_SASL_STATE_FAIL) { if (stanza) { jabber_send(js, stanza); purple_xmlnode_free(stanza); } return; } } if (!msg) msg = jabber_parse_error(js, packet, &reason); if (!msg) { purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Invalid response from server")); } else { purple_connection_error(js->gc, reason, msg); g_free(msg); } }
void jabber_auth_handle_challenge(JabberStream *js, PurpleXmlNode *packet) { const char *ns = purple_xmlnode_get_namespace(packet); if (!purple_strequal(ns, NS_XMPP_SASL)) { purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Invalid response from server")); return; } if (js->auth_mech && js->auth_mech->handle_challenge) { PurpleXmlNode *response = NULL; char *msg = NULL; JabberSaslState state = js->auth_mech->handle_challenge(js, packet, &response, &msg); if (state == JABBER_SASL_STATE_FAIL) { purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, msg ? msg : _("Invalid challenge from server")); } else if (response) { jabber_send(js, response); purple_xmlnode_free(response); } g_free(msg); } else purple_debug_warning("jabber", "Received unexpected (and unhandled) <challenge/>\n"); }
void purple_xmlnode_remove_attrib_with_namespace(PurpleXmlNode *node, const char *attr, const char *xmlns) { PurpleXmlNode *attr_node, *sibling = NULL; g_return_if_fail(node != NULL); g_return_if_fail(attr != NULL); for(attr_node = node->child; attr_node; attr_node = attr_node->next) { if(attr_node->type == PURPLE_XMLNODE_TYPE_ATTRIB && purple_strequal(attr, attr_node->name) && purple_strequal(xmlns, attr_node->xmlns)) { if(sibling == NULL) { node->child = attr_node->next; } else { sibling->next = attr_node->next; } if (node->lastchild == attr_node) { node->lastchild = sibling; } purple_xmlnode_free(attr_node); return; } sibling = attr_node; } }
void jabber_iq_free(JabberIq *iq) { g_return_if_fail(iq != NULL); g_free(iq->id); purple_xmlnode_free(iq->node); g_free(iq); }
/** * Frees the whole tree of an xml node * * First determines the root of the xml tree and then frees the whole tree * from there. * * @param node The node to free the tree from */ static void purple_xmlnode_free_tree(PurpleXmlNode *node) { g_return_if_fail(node != NULL); while(purple_xmlnode_get_parent(node)) node = purple_xmlnode_get_parent(node); purple_xmlnode_free(node); }
static PurpleTheme * pidgin_icon_loader_build(const gchar *theme_dir) { PurpleXmlNode *root_node = NULL, *sub_node; gchar *dir, *filename_full, *data = NULL; PidginIconTheme *theme = NULL; const gchar *name; /* Find the theme file */ g_return_val_if_fail(theme_dir != NULL, NULL); dir = g_build_filename(theme_dir, "purple", "status-icon", NULL); filename_full = g_build_filename(dir, "theme.xml", NULL); if (g_file_test(filename_full, G_FILE_TEST_IS_REGULAR)) root_node = purple_xmlnode_from_file(dir, "theme.xml", "icon themes", "icon-theme-loader"); g_free(filename_full); if (root_node == NULL) { g_free(dir); return NULL; } name = purple_xmlnode_get_attrib(root_node, "name"); if (name) { /* Parse the tree */ sub_node = purple_xmlnode_get_child(root_node, "description"); data = purple_xmlnode_get_data(sub_node); if (purple_xmlnode_get_attrib(root_node, "name") != NULL) { theme = g_object_new(PIDGIN_TYPE_STATUS_ICON_THEME, "type", "status-icon", "name", name, "author", purple_xmlnode_get_attrib(root_node, "author"), "image", purple_xmlnode_get_attrib(root_node, "image"), "directory", dir, "description", data, NULL); sub_node = purple_xmlnode_get_child(root_node, "icon"); while (sub_node) { pidgin_icon_theme_set_icon(theme, purple_xmlnode_get_attrib(sub_node, "id"), purple_xmlnode_get_attrib(sub_node, "file")); sub_node = purple_xmlnode_get_next_twin(sub_node); } } } purple_xmlnode_free(root_node); g_free(data); return PURPLE_THEME(theme); }
/* parse the oim XML data * and post it to the soap server to get the Offline Message * */ void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) { PurpleXmlNode *node; purple_debug_info("msn", "%s\n", xmlmsg); if (!strcmp(xmlmsg, "too-large")) { /* Too many OIM's to send via NS, so we need to request them via SOAP. */ msn_oim_get_metadata(oim); } else { node = purple_xmlnode_from_str(xmlmsg, -1); msn_parse_oim_xml(oim, node); purple_xmlnode_free(node); } }
void purple_xmlnode_free(PurpleXmlNode *node) { PurpleXmlNode *x, *y; g_return_if_fail(node != NULL); /* if we're part of a tree, remove ourselves from the tree first */ if(NULL != node->parent) { if(node->parent->child == node) { node->parent->child = node->next; if (node->parent->lastchild == node) node->parent->lastchild = node->next; } else { PurpleXmlNode *prev = node->parent->child; while(prev && prev->next != node) { prev = prev->next; } if(prev) { prev->next = node->next; if (node->parent->lastchild == node) node->parent->lastchild = prev; } } } /* now free our children */ x = node->child; while(x) { y = x->next; purple_xmlnode_free(x); x = y; } /* now dispose of ourselves */ g_free(node->name); g_free(node->data); g_free(node->xmlns); g_free(node->prefix); if(node->namespace_map) g_hash_table_destroy(node->namespace_map); // PURPLE_DBUS_UNREGISTER_POINTER(node); g_free(node); }
static void ggp_roster_content_free(ggp_roster_content *content) { if (content == NULL) return; if (content->xml) purple_xmlnode_free(content->xml); if (content->contact_nodes) g_hash_table_destroy(content->contact_nodes); if (content->group_nodes) g_hash_table_destroy(content->group_nodes); if (content->group_ids) g_hash_table_destroy(content->group_ids); if (content->group_names) g_hash_table_destroy(content->group_names); if (content->bots_group_id) g_free(content->bots_group_id); g_free(content); }
static void sync_smileys(void) { PurpleXmlNode *root_node; char *data; if (!smileys_loaded) { purple_debug_error(SMILEYS_LOG_ID, "Attempted to save smileys before it " "was read!\n"); return; } root_node = smileys_to_xmlnode(); data = purple_xmlnode_to_formatted_str(root_node, NULL); purple_util_write_data_to_file(XML_FILE_NAME, data, -1); g_free(data); purple_xmlnode_free(root_node); }
static void sync_pounces(void) { PurpleXmlNode *node; char *data; if (!pounces_loaded) { purple_debug_error("pounce", "Attempted to save buddy pounces before " "they were read!\n"); return; } node = pounces_to_xmlnode(); data = purple_xmlnode_to_formatted_str(node, NULL); purple_util_write_data_to_file("pounces.xml", data, -1); g_free(data); purple_xmlnode_free(node); }
static void msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response, gpointer req_data) { MsnOimRequestData *data = (MsnOimRequestData *)req_data; PurpleXmlNode *fault = NULL; PurpleXmlNode *faultcode = NULL; if (response != NULL) fault = purple_xmlnode_get_child(msn_soap_message_get_xml(response), "Body/Fault"); if (fault && (faultcode = purple_xmlnode_get_child(fault, "faultcode"))) { gchar *faultcode_str = purple_xmlnode_get_data(faultcode); gboolean need_token_update = FALSE; if (faultcode_str) { if (g_str_equal(faultcode_str, "q0:BadContextToken") || g_str_equal(faultcode_str, "AuthenticationFailed") || g_str_equal(faultcode_str, "s:AuthenticationFailed")) need_token_update = TRUE; else if (g_str_equal(faultcode_str, "q0:AuthenticationFailed") && purple_xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) need_token_update = TRUE; } if (need_token_update) { purple_debug_warning("msn", "OIM Request Error, Updating token now.\n"); msn_nexus_update_token(data->oim->session->nexus, data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, (GSourceFunc)msn_oim_request_helper, data); g_free(faultcode_str); return; } g_free(faultcode_str); } if (data->cb) data->cb(request, response, data->cb_data); purple_xmlnode_free(data->body); g_free(data); }
static void google_session_destroy(GoogleSession *session) { GoogleAVSessionData *session_data = (GoogleAVSessionData *) session->session_data; g_free(session->id.id); g_free(session->id.initiator); g_free(session->remote_jid); if (session_data->remote_audio_candidates) purple_media_candidate_list_free(session_data->remote_audio_candidates); if (session_data->remote_video_candidates) purple_media_candidate_list_free(session_data->remote_video_candidates); if (session->description) purple_xmlnode_free(session->description); g_free(session->session_data); g_free(session); }
static PurpleXmlNode * jabber_bosh_connection_parse(PurpleJabberBOSHConnection *conn, PurpleHttpResponse *response) { PurpleXmlNode *root; const gchar *data; size_t data_len; const gchar *type; g_return_val_if_fail(conn != NULL, NULL); g_return_val_if_fail(response != NULL, NULL); if (conn->is_terminating || purple_account_is_disconnecting( purple_connection_get_account(conn->js->gc))) { return NULL; } if (!purple_http_response_is_successful(response)) { purple_connection_error(conn->js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect")); return NULL; } data = purple_http_response_get_data(response, &data_len); root = purple_xmlnode_from_str(data, data_len); type = purple_xmlnode_get_attrib(root, "type"); if (g_strcmp0(type, "terminate") == 0) { purple_connection_error(conn->js->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("The BOSH " "connection manager terminated your session.")); purple_xmlnode_free(root); return NULL; } return root; }
static void jabber_bosh_connection_session_created(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer _bosh_conn) { PurpleJabberBOSHConnection *bosh_conn = _bosh_conn; PurpleXmlNode *node, *features; const gchar *sid, *ver, *inactivity_str; int inactivity = 0; bosh_conn->sc_req = NULL; if (purple_debug_is_verbose() && purple_debug_is_unsafe()) { purple_debug_misc("jabber-bosh", "received (session creation): %s\n", purple_http_response_get_data(response, NULL)); } node = jabber_bosh_connection_parse(bosh_conn, response); if (node == NULL) return; sid = purple_xmlnode_get_attrib(node, "sid"); ver = purple_xmlnode_get_attrib(node, "ver"); inactivity_str = purple_xmlnode_get_attrib(node, "inactivity"); /* requests = purple_xmlnode_get_attrib(node, "requests"); */ if (!sid) { purple_connection_error(bosh_conn->js->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("No BOSH session ID given")); purple_xmlnode_free(node); return; } if (ver == NULL) { purple_debug_info("jabber-bosh", "Missing version in BOSH initiation\n"); } else if (!jabber_bosh_version_check(ver, 1, 6)) { purple_debug_error("jabber-bosh", "Unsupported BOSH version: %s\n", ver); purple_connection_error(bosh_conn->js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unsupported version of BOSH protocol")); purple_xmlnode_free(node); return; } purple_debug_misc("jabber-bosh", "Session created for %p\n", bosh_conn); bosh_conn->sid = g_strdup(sid); if (inactivity_str) inactivity = atoi(inactivity_str); if (inactivity < 0 || inactivity > 3600) { purple_debug_warning("jabber-bosh", "Ignoring invalid " "inactivity value: %s\n", inactivity_str); inactivity = 0; } if (inactivity > 0) { inactivity -= 5; /* rounding */ if (inactivity <= 0) inactivity = 1; bosh_conn->js->max_inactivity = inactivity; if (bosh_conn->js->inactivity_timer == 0) { purple_debug_misc("jabber-bosh", "Starting inactivity " "timer for %d secs (compensating for " "rounding)\n", inactivity); jabber_stream_restart_inactivity_timer(bosh_conn->js); } } jabber_stream_set_state(bosh_conn->js, JABBER_STREAM_AUTHENTICATING); /* FIXME: Depending on receiving features might break with some hosts */ features = purple_xmlnode_get_child(node, "features"); jabber_stream_features_parse(bosh_conn->js, features); purple_xmlnode_free(node); jabber_bosh_connection_send(bosh_conn, NULL); }
void jabber_auth_start(JabberStream *js, PurpleXmlNode *packet) { GSList *mechanisms = NULL; GSList *l; PurpleXmlNode *response = NULL; PurpleXmlNode *mechs, *mechnode; JabberSaslState state; char *msg = NULL; if(js->registration) { jabber_register_start(js); return; } mechs = purple_xmlnode_get_child(packet, "mechanisms"); if(!mechs) { purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Invalid response from server")); return; } for(mechnode = purple_xmlnode_get_child(mechs, "mechanism"); mechnode; mechnode = purple_xmlnode_get_next_twin(mechnode)) { char *mech_name = purple_xmlnode_get_data(mechnode); if (mech_name && *mech_name) mechanisms = g_slist_prepend(mechanisms, mech_name); else g_free(mech_name); } for (l = auth_mechs; l; l = l->next) { JabberSaslMech *possible = l->data; /* Is this the Cyrus SASL mechanism? */ if (g_str_equal(possible->name, "*")) { js->auth_mech = possible; break; } /* Can we find this mechanism in the server's list? */ if (g_slist_find_custom(mechanisms, possible->name, (GCompareFunc)strcmp)) { js->auth_mech = possible; break; } } while (mechanisms) { g_free(mechanisms->data); mechanisms = g_slist_delete_link(mechanisms, mechanisms); } if (js->auth_mech == NULL) { /* Found no good mechanisms... */ purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, _("Server does not use any supported authentication method")); return; } state = js->auth_mech->start(js, mechs, &response, &msg); if (state == JABBER_SASL_STATE_FAIL) { purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, msg ? msg : _("Unknown Error")); } else if (response) { jabber_send(js, response); purple_xmlnode_free(response); } g_free(msg); }
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); }