Пример #1
0
void jabber_gmail_init(JabberStream *js) {
	JabberIq *iq;
	PurpleXmlNode *usersetting, *mailnotifications;

	if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
		return;

	/*
	 * Quoting https://developers.google.com/talk/jep_extensions/usersettings:
	 * To ensure better compatibility with other clients, rather than
	 * setting this value to "false" to turn off notifications, it is
	 * recommended that a client set this to "true" and filter incoming
	 * email notifications itself.
	 */
	iq = jabber_iq_new(js, JABBER_IQ_SET);
	usersetting = purple_xmlnode_new_child(iq->node, "usersetting");
	purple_xmlnode_set_namespace(usersetting, "google:setting");
	mailnotifications = purple_xmlnode_new_child(usersetting, "mailnotifications");
	purple_xmlnode_set_attrib(mailnotifications, "value", "true");
	jabber_iq_send(iq);

	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
	jabber_iq_send(iq);
}
Пример #2
0
static PurpleXmlNode *
jingle_add_jingle_packet(JingleSession *session,
			 JabberIq *iq, JingleActionType action)
{
	PurpleXmlNode *jingle = iq ?
			purple_xmlnode_new_child(iq->node, "jingle") :
			purple_xmlnode_new("jingle");
	gchar *local_jid = jingle_session_get_local_jid(session);
	gchar *remote_jid = jingle_session_get_remote_jid(session);
	gchar *sid = jingle_session_get_sid(session);

	purple_xmlnode_set_namespace(jingle, JINGLE);
	purple_xmlnode_set_attrib(jingle, "action", jingle_get_action_name(action));

	if (jingle_session_is_initiator(session)) {
		purple_xmlnode_set_attrib(jingle, "initiator", local_jid);
		purple_xmlnode_set_attrib(jingle, "responder", remote_jid);
	} else {
		purple_xmlnode_set_attrib(jingle, "initiator", remote_jid);
		purple_xmlnode_set_attrib(jingle, "responder", local_jid);
	}

	purple_xmlnode_set_attrib(jingle, "sid", sid);

	g_free(local_jid);
	g_free(remote_jid);
	g_free(sid);

	return jingle;
}
static PurpleXmlNode *
google_session_create_xmlnode(GoogleSession *session, const char *type)
{
	PurpleXmlNode *node = purple_xmlnode_new("session");
	purple_xmlnode_set_namespace(node, NS_GOOGLE_SESSION);
	purple_xmlnode_set_attrib(node, "id", session->id.id);
	purple_xmlnode_set_attrib(node, "initiator", session->id.initiator);
	purple_xmlnode_set_attrib(node, "type", type);
	return node;
}
static JabberSaslState
digest_md5_start(JabberStream *js, PurpleXmlNode *packet, PurpleXmlNode **response,
                 char **error)
{
	PurpleXmlNode *auth = purple_xmlnode_new("auth");
	purple_xmlnode_set_namespace(auth, NS_XMPP_SASL);
	purple_xmlnode_set_attrib(auth, "mechanism", "DIGEST-MD5");

	*response = auth;
	return JABBER_SASL_STATE_CONTINUE;
}
Пример #5
0
JabberIq *jabber_iq_new_query(JabberStream *js, JabberIqType type,
		const char *xmlns)
{
	JabberIq *iq = jabber_iq_new(js, type);
	PurpleXmlNode *query;

	query = purple_xmlnode_new_child(iq->node, "query");
	purple_xmlnode_set_namespace(query, xmlns);

	return iq;
}
Пример #6
0
void purple_xmlnode_strip_prefixes(PurpleXmlNode *node)
{
    PurpleXmlNode *child;
    const char *prefix;

    g_return_if_fail(node != NULL);

    for (child = node->child; child; child = child->next) {
        if (child->type == PURPLE_XMLNODE_TYPE_TAG)
            purple_xmlnode_strip_prefixes(child);
    }

    prefix = purple_xmlnode_get_prefix(node);
    if (prefix) {
        const char *ns = purple_xmlnode_get_prefix_namespace(node, prefix);
        purple_xmlnode_set_namespace(node, ns);
        purple_xmlnode_set_prefix(node, NULL);
    } else {
        purple_xmlnode_set_namespace(node, purple_xmlnode_get_default_namespace(node));
    }
}
Пример #7
0
static void
xep_ft_si_result(PurpleXfer *xfer, const char *to)
{
	PurpleXmlNode *si_node, *feature, *field, *value, *x;
	XepIq *iq;
	XepXfer *xf;
	BonjourData *bd;

	if(!to || !xfer)
		return;
	xf = purple_xfer_get_protocol_data(xfer);
	if(!xf)
		return;

	bd = xf->data;

	purple_debug_info("bonjour", "xep file transfer stream initialization result.\n");
	iq = xep_iq_new(bd, XEP_IQ_RESULT, to, bonjour_get_jid(bd->jabber_data->account), xf->iq_id);
	if(iq == NULL)
		return;

	si_node = purple_xmlnode_new_child(iq->node, "si");
	purple_xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si");
	/*purple_xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer");*/

	feature = purple_xmlnode_new_child(si_node, "feature");
	purple_xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");

	x = purple_xmlnode_new_child(feature, "x");
	purple_xmlnode_set_namespace(x, "jabber:x:data");
	purple_xmlnode_set_attrib(x, "type", "submit");

	field = purple_xmlnode_new_child(x, "field");
	purple_xmlnode_set_attrib(field, "var", "stream-method");

	value = purple_xmlnode_new_child(field, "value");
	purple_xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);

	xep_iq_send_and_free(iq);
}
Пример #8
0
static void
xep_ft_si_reject(BonjourData *bd, const char *id, const char *to, const char *error_code, const char *error_type)
{
	PurpleXmlNode *error_node;
	XepIq *iq;

	g_return_if_fail(error_code != NULL);
	g_return_if_fail(error_type != NULL);

	if(!to || !id) {
		purple_debug_info("bonjour", "xep file transfer stream initialization error.\n");
		return;
	}

	iq = xep_iq_new(bd, XEP_IQ_ERROR, to, bonjour_get_jid(bd->jabber_data->account), id);
	if(iq == NULL)
		return;

	error_node = purple_xmlnode_new_child(iq->node, "error");
	purple_xmlnode_set_attrib(error_node, "code", error_code);
	purple_xmlnode_set_attrib(error_node, "type", error_type);

	/* TODO: Make this better */
	if (!strcmp(error_code, "403")) {
		PurpleXmlNode *tmp_node = purple_xmlnode_new_child(error_node, "forbidden");
		purple_xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");

		tmp_node = purple_xmlnode_new_child(error_node, "text");
		purple_xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
		purple_xmlnode_insert_data(tmp_node, "Offer Declined", -1);
	} else if (!strcmp(error_code, "404")) {
		PurpleXmlNode *tmp_node = purple_xmlnode_new_child(error_node, "item-not-found");
		purple_xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
	}

	xep_iq_send_and_free(iq);
}
Пример #9
0
static void
purple_xmlnode_parser_element_start_libxml(void *user_data,
        const xmlChar *element_name, const xmlChar *prefix, const xmlChar *xmlns,
        int nb_namespaces, const xmlChar **namespaces,
        int nb_attributes, int nb_defaulted, const xmlChar **attributes)
{
    struct _xmlnode_parser_data *xpd = user_data;
    PurpleXmlNode *node;
    int i, j;

    if(!element_name || xpd->error) {
        return;
    } else {
        if(xpd->current)
            node = purple_xmlnode_new_child(xpd->current, (const char*) element_name);
        else
            node = purple_xmlnode_new((const char *) element_name);

        purple_xmlnode_set_namespace(node, (const char *) xmlns);
        purple_xmlnode_set_prefix(node, (const char *)prefix);

        if (nb_namespaces != 0) {
            node->namespace_map = g_hash_table_new_full(
                                      g_str_hash, g_str_equal, g_free, g_free);

            for (i = 0, j = 0; i < nb_namespaces; i++, j += 2) {
                const char *key = (const char *)namespaces[j];
                const char *val = (const char *)namespaces[j + 1];
                g_hash_table_insert(node->namespace_map,
                                    g_strdup(key ? key : ""), g_strdup(val ? val : ""));
            }
        }

        for(i=0; i < nb_attributes * 5; i+=5) {
            const char *name = (const char *)attributes[i];
            const char *prefix = (const char *)attributes[i+1];
            char *txt;
            int attrib_len = attributes[i+4] - attributes[i+3];
            char *attrib = g_strndup((const char *)attributes[i+3], attrib_len);
            txt = attrib;
            attrib = purple_unescape_text(txt);
            g_free(txt);
            purple_xmlnode_set_attrib_full(node, name, NULL, prefix, attrib);
            g_free(attrib);
        }

        xpd->current = node;
    }
}
Пример #10
0
static void do_nick_set(JabberStream *js, const char *nick) {
	PurpleXmlNode *publish, *nicknode;

	publish = purple_xmlnode_new("publish");
	purple_xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/nick");
	nicknode = purple_xmlnode_new_child(purple_xmlnode_new_child(publish, "item"), "nick");
	purple_xmlnode_set_namespace(nicknode, "http://jabber.org/protocol/nick");

	if(nick && nick[0] != '\0')
		purple_xmlnode_insert_data(nicknode, nick, -1);

	jabber_pep_publish(js, publish);
	/* publish is freed by jabber_pep_publish -> jabber_iq_send -> jabber_iq_free
		(yay for well-defined memory management rules) */
}
Пример #11
0
static void
bonjour_bytestreams_listen(int sock, gpointer data)
{
	PurpleXfer *xfer = data;
	XepXfer *xf;
	XepIq *iq;
	PurpleXmlNode *query, *streamhost;
	gchar *port;
	GSList *local_ips;
	BonjourData *bd;

	purple_debug_info("bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock);
	if (sock < 0 || xfer == NULL) {
		/*purple_xfer_cancel_local(xfer);*/
		return;
	}

	purple_xfer_set_watcher(xfer, purple_input_add(sock, PURPLE_INPUT_READ,
					 bonjour_sock5_request_cb, xfer));
	xf = purple_xfer_get_protocol_data(xfer);
	xf->listen_data = NULL;

	bd = xf->data;

	iq = xep_iq_new(bd, XEP_IQ_SET, purple_xfer_get_remote_user(xfer), bonjour_get_jid(bd->jabber_data->account), xf->sid);

	query = purple_xmlnode_new_child(iq->node, "query");
	purple_xmlnode_set_namespace(query, "http://jabber.org/protocol/bytestreams");
	purple_xmlnode_set_attrib(query, "sid", xf->sid);
	purple_xmlnode_set_attrib(query, "mode", "tcp");

	purple_xfer_set_local_port(xfer, purple_network_get_port_from_fd(sock));

	local_ips = bonjour_jabber_get_local_ips(sock);

	port = g_strdup_printf("%hu", purple_xfer_get_local_port(xfer));
	while(local_ips) {
		streamhost = purple_xmlnode_new_child(query, "streamhost");
		purple_xmlnode_set_attrib(streamhost, "jid", xf->sid);
		purple_xmlnode_set_attrib(streamhost, "host", local_ips->data);
		purple_xmlnode_set_attrib(streamhost, "port", port);
		g_free(local_ips->data);
		local_ips = g_slist_delete_link(local_ips, local_ips);
	}
	g_free(port);

	xep_iq_send_and_free(iq);
}
Пример #12
0
static void
jabber_ibb_send_error_response(JabberStream *js, const char *to, const char *id)
{
	JabberIq *result = jabber_iq_new(js, JABBER_IQ_ERROR);
	PurpleXmlNode *error = purple_xmlnode_new("error");
	PurpleXmlNode *item_not_found = purple_xmlnode_new("item-not-found");

	purple_xmlnode_set_namespace(item_not_found, NS_XMPP_STANZAS);
	purple_xmlnode_set_attrib(error, "code", "440");
	purple_xmlnode_set_attrib(error, "type", "cancel");
	jabber_iq_set_id(result, id);
	purple_xmlnode_set_attrib(result->node, "to", to);
	purple_xmlnode_insert_child(error, item_not_found);
	purple_xmlnode_insert_child(result->node, error);

	jabber_iq_send(result);
}
Пример #13
0
static void
jabber_bosh_connection_recv(PurpleHttpConnection *http_conn,
	PurpleHttpResponse *response, gpointer _bosh_conn)
{
	PurpleJabberBOSHConnection *bosh_conn = _bosh_conn;
	PurpleXmlNode *node, *child;

	if (purple_debug_is_verbose() && purple_debug_is_unsafe()) {
		purple_debug_misc("jabber-bosh", "received: %s\n",
			purple_http_response_get_data(response, NULL));
	}

	node = jabber_bosh_connection_parse(bosh_conn, response);
	if (node == NULL)
		return;

	child = node->child;
	while (child != NULL) {
		/* jabber_process_packet might free child */
		PurpleXmlNode *next = child->next;
		const gchar *xmlns;

		if (child->type != PURPLE_XMLNODE_TYPE_TAG) {
			child = next;
			continue;
		}

		/* Workaround for non-compliant servers that don't stamp
		 * the right xmlns on these packets. See #11315.
		 */
		xmlns = purple_xmlnode_get_namespace(child);
		if ((xmlns == NULL || g_strcmp0(xmlns, NS_BOSH) == 0) &&
			(g_strcmp0(child->name, "iq") == 0 ||
			g_strcmp0(child->name, "message") == 0 ||
			g_strcmp0(child->name, "presence") == 0))
		{
			purple_xmlnode_set_namespace(child, NS_XMPP_CLIENT);
		}

		jabber_process_packet(bosh_conn->js, &child);

		child = next;
	}

	jabber_bosh_connection_send(bosh_conn, NULL);
}
Пример #14
0
void
jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data,
                             gsize size)
{
	JabberIBBSessionState state = jabber_ibb_session_get_state(sess);

	purple_debug_info("jabber", "sending data block of %" G_GSIZE_FORMAT " bytes on IBB stream\n",
		size);

	if (state != JABBER_IBB_SESSION_OPENED) {
		purple_debug_error("jabber",
			"trying to send data on a non-open IBB session\n");
	} else if (size > jabber_ibb_session_get_max_data_size(sess)) {
		purple_debug_error("jabber",
			"trying to send a too large packet in the IBB session\n");
	} else {
		JabberIq *set = jabber_iq_new(jabber_ibb_session_get_js(sess),
			JABBER_IQ_SET);
		PurpleXmlNode *data_element = purple_xmlnode_new("data");
		char *base64 = purple_base64_encode(data, size);
		char seq[10];
		g_snprintf(seq, sizeof(seq), "%u", jabber_ibb_session_get_send_seq(sess));

		purple_xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
		purple_xmlnode_set_namespace(data_element, NS_IBB);
		purple_xmlnode_set_attrib(data_element, "sid", jabber_ibb_session_get_sid(sess));
		purple_xmlnode_set_attrib(data_element, "seq", seq);
		purple_xmlnode_insert_data(data_element, base64, -1);

		purple_xmlnode_insert_child(set->node, data_element);

		purple_debug_info("jabber",
			"IBB: setting send <iq/> callback for session %p %s\n", sess,
			sess->sid);
		jabber_iq_set_callback(set, jabber_ibb_session_send_acknowledge_cb, sess);
		sess->last_iq_id = g_strdup(purple_xmlnode_get_attrib(set->node, "id"));
		purple_debug_info("jabber", "IBB: set sess->last_iq_id: %s\n",
			sess->last_iq_id);
		jabber_iq_send(set);

		g_free(base64);
		(sess->send_seq)++;
	}
}
Пример #15
0
static void
bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message)
{
	PurpleXfer *xfer = data;
	XepXfer *xf = purple_xfer_get_protocol_data(xfer);
	XepIq *iq;
	PurpleXmlNode *q_node, *tmp_node;
	BonjourData *bd;
	gboolean ret = FALSE;

	xf->proxy_connection = NULL;

	if(source < 0) {
		purple_debug_error("bonjour", "Error connecting via SOCKS5 to %s - %s\n",
			xf->proxy_host, error_message ? error_message : "(null)");

		tmp_node = purple_xmlnode_get_next_twin(xf->streamhost);
		ret = __xep_bytestreams_parse(xf->pb, xfer, tmp_node, xf->iq_id);

		if (!ret) {
			xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), "404", "cancel");
			/* Cancel the connection */
			purple_xfer_cancel_local(xfer);
		}
		return;
	}

	purple_debug_info("bonjour", "Connected successfully via SOCKS5, starting transfer.\n");

	bd = xf->data;

	/* Here, start the file transfer.*/

	/* Notify Initiator of Connection */
	iq = xep_iq_new(bd, XEP_IQ_RESULT, purple_xfer_get_remote_user(xfer), bonjour_get_jid(bd->jabber_data->account), xf->iq_id);
	q_node = purple_xmlnode_new_child(iq->node, "query");
	purple_xmlnode_set_namespace(q_node, "http://jabber.org/protocol/bytestreams");
	tmp_node = purple_xmlnode_new_child(q_node, "streamhost-used");
	purple_xmlnode_set_attrib(tmp_node, "jid", xf->jid);
	xep_iq_send_and_free(iq);

	purple_xfer_start(xfer, source, NULL, -1);
}
Пример #16
0
void
jabber_ibb_session_close(JabberIBBSession *sess)
{
	JabberIBBSessionState state = jabber_ibb_session_get_state(sess);

	if (state != JABBER_IBB_SESSION_OPENED && state != JABBER_IBB_SESSION_ERROR) {
		purple_debug_error("jabber",
			"jabber_ibb_session_close called on a session that has not been"
			"opened\n");
	} else {
		JabberIq *set = jabber_iq_new(jabber_ibb_session_get_js(sess),
			JABBER_IQ_SET);
		PurpleXmlNode *close = purple_xmlnode_new("close");

		purple_xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
		purple_xmlnode_set_namespace(close, NS_IBB);
		purple_xmlnode_set_attrib(close, "sid", jabber_ibb_session_get_sid(sess));
		purple_xmlnode_insert_child(set->node, close);
		jabber_iq_send(set);
		sess->state = JABBER_IBB_SESSION_CLOSED;
	}
}
Пример #17
0
static void jabber_time_parse(JabberStream *js, const char *from,
                              JabberIqType type, const char *id,
                              PurpleXmlNode *child)
{
	JabberIq *iq;
	time_t now_t;
	struct tm *tm;

	time(&now_t);

	if(type == JABBER_IQ_GET) {
		PurpleXmlNode *tzo, *utc;
		const char *date, *tz;

		iq = jabber_iq_new(js, JABBER_IQ_RESULT);
		jabber_iq_set_id(iq, id);
		if (from)
			purple_xmlnode_set_attrib(iq->node, "to", from);

		child = purple_xmlnode_new_child(iq->node, child->name);
		purple_xmlnode_set_namespace(child, NS_ENTITY_TIME);

		/* <tzo>-06:00</tzo> */
		tm = localtime(&now_t);
		tz = purple_get_tzoff_str(tm, TRUE);
		tzo = purple_xmlnode_new_child(child, "tzo");
		purple_xmlnode_insert_data(tzo, tz, -1);

		/* <utc>2006-12-19T17:58:35Z</utc> */
		tm = gmtime(&now_t);
		date = purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm);
		utc = purple_xmlnode_new_child(child, "utc");
		purple_xmlnode_insert_data(utc, date, -1);

		jabber_iq_send(iq);
	} else {
		/* TODO: Errors */
	}
}
Пример #18
0
void
jabber_ibb_session_open(JabberIBBSession *sess)
{
	if (jabber_ibb_session_get_state(sess) != JABBER_IBB_SESSION_NOT_OPENED) {
		purple_debug_error("jabber",
			"jabber_ibb_session called on an already open stream\n");
	} else {
		JabberIq *set = jabber_iq_new(sess->js, JABBER_IQ_SET);
		PurpleXmlNode *open = purple_xmlnode_new("open");
		gchar block_size[10];

		purple_xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
		purple_xmlnode_set_namespace(open, NS_IBB);
		purple_xmlnode_set_attrib(open, "sid", jabber_ibb_session_get_sid(sess));
		g_snprintf(block_size, sizeof(block_size), "%" G_GSIZE_FORMAT,
			jabber_ibb_session_get_block_size(sess));
		purple_xmlnode_set_attrib(open, "block-size", block_size);
		purple_xmlnode_insert_child(set->node, open);

		jabber_iq_set_callback(set, jabber_ibb_session_opened_cb, sess);

		jabber_iq_send(set);
	}
}
Пример #19
0
gboolean
jabber_mood_set(JabberStream *js, const char *mood, const char *text)
{
	const PurpleMood *target_mood = NULL;
	PurpleXmlNode *publish, *moodnode;

	if (mood && *mood) {
		target_mood = find_mood_by_name(mood);
		/* Mood specified, but is invalid --
		 * fail so that the command can handle this.
		 */
		if (!target_mood)
			return FALSE;
	}

	publish = purple_xmlnode_new("publish");
	purple_xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/mood");
	moodnode = purple_xmlnode_new_child(purple_xmlnode_new_child(publish, "item"), "mood");
	purple_xmlnode_set_namespace(moodnode, "http://jabber.org/protocol/mood");

	if (target_mood) {
		/* If target_mood is not NULL, then
		 * target_mood->mood == mood, and is a valid element name.
		 */
	    purple_xmlnode_new_child(moodnode, mood);

		/* Only set text when setting a mood */
		if (text && *text) {
			PurpleXmlNode *textnode = purple_xmlnode_new_child(moodnode, "text");
			purple_xmlnode_insert_data(textnode, text, -1);
		}
	}

	jabber_pep_publish(js, publish);
	return TRUE;
}
Пример #20
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);
}
Пример #21
0
static JabberSaslState
scram_start(JabberStream *js, PurpleXmlNode *mechanisms, PurpleXmlNode **out, char **error)
{
	PurpleXmlNode *reply;
	JabberScramData *data;
	guint64 cnonce;
#ifdef CHANNEL_BINDING
	gboolean binding_supported = TRUE;
#endif
	gchar *dec_out, *enc_out;
	gchar *prepped_node, *tmp;
	gchar *prepped_pass;

	prepped_node = jabber_saslprep(js->user->node);
	if (!prepped_node) {
		*error = g_strdup(_("Unable to canonicalize username"));
		return JABBER_SASL_STATE_FAIL;
	}

	tmp = escape_username(prepped_node);
	g_free(prepped_node);
	prepped_node = tmp;

	prepped_pass = jabber_saslprep(purple_connection_get_password(js->gc));
	if (!prepped_pass) {
		g_free(prepped_node);
		*error = g_strdup(_("Unable to canonicalize password"));
		return JABBER_SASL_STATE_FAIL;
	}

	data = js->auth_mech_data = g_new0(JabberScramData, 1);
	data->hash = mech_to_hash(js->auth_mech->name);
	data->password = prepped_pass;

#ifdef CHANNEL_BINDING
	if (strstr(js->auth_mech_name, "-PLUS"))
		data->channel_binding = TRUE;
#endif
	cnonce = ((guint64)g_random_int() << 32) | g_random_int();
	data->cnonce = purple_base64_encode((guchar *)&cnonce, sizeof(cnonce));

	data->auth_message = g_string_new(NULL);
	g_string_printf(data->auth_message, "n=%s,r=%s",
			prepped_node, data->cnonce);
	g_free(prepped_node);

	data->step = 1;

	reply = purple_xmlnode_new("auth");
	purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
	purple_xmlnode_set_attrib(reply, "mechanism", js->auth_mech->name);

	/* TODO: Channel binding */
	dec_out = g_strdup_printf("%c,,%s", 'n', data->auth_message->str);
	enc_out = purple_base64_encode((guchar *)dec_out, strlen(dec_out));
	purple_debug_misc("jabber", "initial SCRAM message '%s'\n", dec_out);

	purple_xmlnode_insert_data(reply, enc_out, -1);

	g_free(enc_out);
	g_free(dec_out);

	*out = reply;
	return JABBER_SASL_STATE_CONTINUE;
}
Пример #22
0
static void
xep_ft_si_offer(PurpleXfer *xfer, const gchar *to)
{
	PurpleXmlNode *si_node, *feature, *field, *file, *x;
	XepIq *iq;
	XepXfer *xf = purple_xfer_get_protocol_data(xfer);
	BonjourData *bd = NULL;
	char buf[32];

	if(!xf)
		return;

	bd = xf->data;
	if(!bd)
		return;

	purple_debug_info("bonjour", "xep file transfer stream initialization offer-id=%d.\n", next_id);

	/* Assign stream id. */
	g_free(xf->iq_id);
	xf->iq_id = g_strdup_printf("%u", next_id++);
	iq = xep_iq_new(xf->data, XEP_IQ_SET, to, bonjour_get_jid(bd->jabber_data->account), xf->iq_id);
	if(iq == NULL)
		return;

	/*Construct Stream initialization offer message.*/
	si_node = purple_xmlnode_new_child(iq->node, "si");
	purple_xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si");
	purple_xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer");
	g_free(xf->sid);
	xf->sid = g_strdup(xf->iq_id);
	purple_xmlnode_set_attrib(si_node, "id", xf->sid);

	file = purple_xmlnode_new_child(si_node, "file");
	purple_xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer");
	purple_xmlnode_set_attrib(file, "name", purple_xfer_get_filename(xfer));
	g_snprintf(buf, sizeof(buf), "%" G_GOFFSET_FORMAT, purple_xfer_get_size(xfer));
	purple_xmlnode_set_attrib(file, "size", buf);

	feature = purple_xmlnode_new_child(si_node, "feature");
	purple_xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");

	x = purple_xmlnode_new_child(feature, "x");
	purple_xmlnode_set_namespace(x, "jabber:x:data");
	purple_xmlnode_set_attrib(x, "type", "form");

	field = purple_xmlnode_new_child(x, "field");
	purple_xmlnode_set_attrib(field, "var", "stream-method");
	purple_xmlnode_set_attrib(field, "type", "list-single");

	if (xf->mode & XEP_BYTESTREAMS) {
		PurpleXmlNode *option = purple_xmlnode_new_child(field, "option");
		PurpleXmlNode *value = purple_xmlnode_new_child(option, "value");
		purple_xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
	}
	if (xf->mode & XEP_IBB) {
		PurpleXmlNode *option = purple_xmlnode_new_child(field, "option");
		PurpleXmlNode *value = purple_xmlnode_new_child(option, "value");
		purple_xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
	}

	xep_iq_send_and_free(iq);
}
Пример #23
0
static JabberSaslState
scram_handle_challenge(JabberStream *js, PurpleXmlNode *challenge, PurpleXmlNode **out, char **error)
{
	JabberScramData *data = js->auth_mech_data;
	PurpleXmlNode *reply;
	gchar *enc_in, *dec_in = NULL;
	gchar *enc_out = NULL, *dec_out = NULL;
	gsize len;
	JabberSaslState state = JABBER_SASL_STATE_FAIL;

	enc_in = purple_xmlnode_get_data(challenge);
	if (!enc_in || *enc_in == '\0') {
		reply = purple_xmlnode_new("abort");
		purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		data->step = -1;
		*error = g_strdup(_("Invalid challenge from server"));
		goto out;
	}

	dec_in = (gchar *)purple_base64_decode(enc_in, &len);
	if (!dec_in || len != strlen(dec_in)) {
		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
		reply = purple_xmlnode_new("abort");
		purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		data->step = -1;
		*error = g_strdup(_("Malicious challenge from server"));
		goto out;
	}

	purple_debug_misc("jabber", "decoded challenge: %s\n", dec_in);

	if (!jabber_scram_feed_parser(data, dec_in, &dec_out)) {
		reply = purple_xmlnode_new("abort");
		purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		data->step = -1;
		*error = g_strdup(_("Invalid challenge from server"));
		goto out;
	}

	data->step += 1;

	reply = purple_xmlnode_new("response");
	purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);

	purple_debug_misc("jabber", "decoded response: %s\n", dec_out ? dec_out : "(null)");
	if (dec_out) {
		enc_out = purple_base64_encode((guchar *)dec_out, strlen(dec_out));
		purple_xmlnode_insert_data(reply, enc_out, -1);
	}

	state = JABBER_SASL_STATE_CONTINUE;

out:
	g_free(enc_in);
	g_free(dec_in);
	g_free(enc_out);
	g_free(dec_out);

	*out = reply;
	return state;
}
static JabberSaslState
digest_md5_handle_challenge(JabberStream *js, PurpleXmlNode *packet,
                            PurpleXmlNode **response, char **msg)
{
	PurpleXmlNode *reply = NULL;
	char *enc_in = purple_xmlnode_get_data(packet);
	char *dec_in;
	char *enc_out;
	GHashTable *parts;
	JabberSaslState state = JABBER_SASL_STATE_CONTINUE;

	if (!enc_in) {
		*msg = g_strdup(_("Invalid response from server"));
		return JABBER_SASL_STATE_FAIL;
	}

	dec_in = (char *)purple_base64_decode(enc_in, NULL);
	purple_debug_misc("jabber", "decoded challenge (%"
			G_GSIZE_FORMAT "): %s\n",
			strlen(dec_in),
			dec_in);

	parts = jabber_auth_digest_md5_parse(dec_in);

	if (g_hash_table_lookup(parts, "rspauth")) {
		char *rspauth = g_hash_table_lookup(parts, "rspauth");
		char *expected_rspauth = js->auth_mech_data;

		if (rspauth && purple_strequal(rspauth, expected_rspauth)) {
			reply = purple_xmlnode_new("response");
			purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		} else {
			*msg = g_strdup(_("Invalid challenge from server"));
			state = JABBER_SASL_STATE_FAIL;
		}
		g_free(js->auth_mech_data);
		js->auth_mech_data = NULL;
	} else {
		/* assemble a response, and send it */
		/* see RFC 2831 */
		char *realm;
		char *nonce;

		/* Make sure the auth string contains everything that should be there.
		   This isn't everything in RFC2831, but it is what we need. */

		nonce = g_hash_table_lookup(parts, "nonce");

		/* we're actually supposed to prompt the user for a realm if
		 * the server doesn't send one, but that really complicates things,
		 * so i'm not gonna worry about it until is poses a problem to
		 * someone, or I get really bored */
		realm = g_hash_table_lookup(parts, "realm");
		if(!realm)
			realm = js->user->domain;

		if (nonce == NULL || realm == NULL) {
			*msg = g_strdup(_("Invalid challenge from server"));
			state = JABBER_SASL_STATE_FAIL;
		} else {
			GString *response = g_string_new("");
			char *a2;
			char *auth_resp;
			char *cnonce;

			cnonce = g_strdup_printf("%x%u%x", g_random_int(), (int)time(NULL),
					g_random_int());

			a2 = g_strdup_printf("AUTHENTICATE:xmpp/%s", realm);
			auth_resp = generate_response_value(js->user,
					purple_connection_get_password(js->gc), nonce, cnonce, a2, realm);
			g_free(a2);

			a2 = g_strdup_printf(":xmpp/%s", realm);
			js->auth_mech_data = generate_response_value(js->user,
					purple_connection_get_password(js->gc), nonce, cnonce, a2, realm);
			g_free(a2);

			g_string_append_printf(response, "username=\"%s\"", js->user->node);
			g_string_append_printf(response, ",realm=\"%s\"", realm);
			g_string_append_printf(response, ",nonce=\"%s\"", nonce);
			g_string_append_printf(response, ",cnonce=\"%s\"", cnonce);
			g_string_append_printf(response, ",nc=00000001");
			g_string_append_printf(response, ",qop=auth");
			g_string_append_printf(response, ",digest-uri=\"xmpp/%s\"", realm);
			g_string_append_printf(response, ",response=%s", auth_resp);
			g_string_append_printf(response, ",charset=utf-8");

			g_free(auth_resp);
			g_free(cnonce);

			enc_out = purple_base64_encode((guchar *)response->str, response->len);

			purple_debug_misc("jabber", "decoded response (%"
					G_GSIZE_FORMAT "): %s\n",
					response->len, response->str);

			reply = purple_xmlnode_new("response");
			purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
			purple_xmlnode_insert_data(reply, enc_out, -1);

			g_free(enc_out);

			g_string_free(response, TRUE);
		}
	}

	g_free(enc_in);
	g_free(dec_in);
	g_hash_table_destroy(parts);

	*response = reply;
	return state;
}
Пример #25
0
static void
google_session_ready(GoogleSession *session)
{
	PurpleMedia *media =
		((GoogleAVSessionData *)session->session_data)->media;
	gboolean video =
		((GoogleAVSessionData *)session->session_data)->video;
	if (purple_media_codecs_ready(media, NULL) &&
			purple_media_candidates_prepared(media, NULL, NULL)) {
		gchar *me = g_strdup_printf("%s@%s/%s",
				session->js->user->node,
				session->js->user->domain,
				session->js->user->resource);
		JabberIq *iq;
		PurpleXmlNode *sess, *desc, *payload;
		GList *codecs, *iter;
		gboolean is_initiator = !strcmp(session->id.initiator, me);

		if (!is_initiator &&
				!purple_media_accepted(media, NULL, NULL)) {
			g_free(me);
			return;
		}

		iq = jabber_iq_new(session->js, JABBER_IQ_SET);

		if (is_initiator) {
			purple_xmlnode_set_attrib(iq->node, "to", session->remote_jid);
			purple_xmlnode_set_attrib(iq->node, "from", session->id.initiator);
			sess = google_session_create_xmlnode(session, "initiate");
		} else {
			google_session_send_candidates(media,
					"google-voice", session->remote_jid,
					session);
			google_session_send_candidates(media,
					"google-video", session->remote_jid,
					session);
			purple_xmlnode_set_attrib(iq->node, "to", session->remote_jid);
			purple_xmlnode_set_attrib(iq->node, "from", me);
			sess = google_session_create_xmlnode(session, "accept");
		}
		purple_xmlnode_insert_child(iq->node, sess);
		desc = purple_xmlnode_new_child(sess, "description");
		if (video)
			purple_xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO);
		else
			purple_xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE);

		codecs = purple_media_get_codecs(media, "google-video");

		for (iter = codecs; iter; iter = g_list_next(iter)) {
			PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
			gchar *id = g_strdup_printf("%d",
					purple_media_codec_get_id(codec));
			gchar *encoding_name =
					purple_media_codec_get_encoding_name(codec);
			payload = purple_xmlnode_new_child(desc, "payload-type");
			purple_xmlnode_set_attrib(payload, "id", id);
			purple_xmlnode_set_attrib(payload, "name", encoding_name);
			purple_xmlnode_set_attrib(payload, "width", "320");
			purple_xmlnode_set_attrib(payload, "height", "200");
			purple_xmlnode_set_attrib(payload, "framerate", "30");
			g_free(encoding_name);
			g_free(id);
		}
		purple_media_codec_list_free(codecs);

		codecs = purple_media_get_codecs(media, "google-voice");

		for (iter = codecs; iter; iter = g_list_next(iter)) {
			PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
			gchar *id = g_strdup_printf("%d",
					purple_media_codec_get_id(codec));
			gchar *encoding_name =
					purple_media_codec_get_encoding_name(codec);
			gchar *clock_rate = g_strdup_printf("%d",
					purple_media_codec_get_clock_rate(codec));
			payload = purple_xmlnode_new_child(desc, "payload-type");
			if (video)
				purple_xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE);
			purple_xmlnode_set_attrib(payload, "id", id);
			/*
			 * Hack to make Gmail accept speex as the codec.
			 * It shouldn't have to be case sensitive.
			 */
			if (purple_strequal(encoding_name, "SPEEX"))
				purple_xmlnode_set_attrib(payload, "name", "speex");
			else
				purple_xmlnode_set_attrib(payload, "name", encoding_name);
			purple_xmlnode_set_attrib(payload, "clockrate", clock_rate);
			g_free(clock_rate);
			g_free(encoding_name);
			g_free(id);
		}
		purple_media_codec_list_free(codecs);

		jabber_iq_send(iq);

		if (is_initiator) {
			google_session_send_candidates(media,
					"google-voice", session->remote_jid,
					session);
			google_session_send_candidates(media,
					"google-video", session->remote_jid,
					session);
		}

		g_signal_handlers_disconnect_by_func(G_OBJECT(media),
				G_CALLBACK(google_session_ready), session);
	}
}