예제 #1
0
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);
}
예제 #2
0
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;
}
예제 #3
0
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;
    }
}
예제 #4
0
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;
}
예제 #5
0
파일: roster.c 프로젝트: Distrotech/pidgin
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;
}
예제 #6
0
파일: smiley.c 프로젝트: Distrotech/pidgin
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);
}
예제 #7
0
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);
}
예제 #8
0
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);
	}
}
예제 #9
0
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");
}
예제 #10
0
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;
    }
}
예제 #11
0
void jabber_iq_free(JabberIq *iq)
{
	g_return_if_fail(iq != NULL);

	g_free(iq->id);
	purple_xmlnode_free(iq->node);
	g_free(iq);
}
예제 #12
0
/**
 * 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);
}
예제 #14
0
/* 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);
    }
}
예제 #15
0
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);
}
예제 #16
0
파일: roster.c 프로젝트: Distrotech/pidgin
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);
}
예제 #17
0
파일: smiley.c 프로젝트: Distrotech/pidgin
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);
}
예제 #18
0
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);
}
예제 #19
0
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);
}
예제 #20
0
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);
}
예제 #21
0
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;
}
예제 #22
0
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);
}
예제 #23
0
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);
}
예제 #24
0
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);
}