pidgin.vv.msn.webcam: 1deb79e2: Initial commit of msn webcam code. Suppo...

maiku at pidgin.im maiku at pidgin.im
Tue Aug 25 04:45:46 EDT 2009


-----------------------------------------------------------------
Revision: 1deb79e27c3967647d508217efaaa277fc229713
Ancestor: cf52f515f41f2668c92606c9ad852fb55460da9c
Author: maiku at pidgin.im
Date: 2009-08-25T08:42:33
Branch: im.pidgin.pidgin.vv.msn.webcam
URL: http://d.pidgin.im/viewmtn/revision/info/1deb79e27c3967647d508217efaaa277fc229713

Added files:
        libpurple/protocols/msn/webcam.c
        libpurple/protocols/msn/webcam.h
Modified files:
        libpurple/protocols/msn/Makefile.am
        libpurple/protocols/msn/Makefile.mingw
        libpurple/protocols/msn/msn.c libpurple/protocols/msn/slp.c
        libpurple/protocols/msn/slpcall.c
        libpurple/protocols/msn/slpcall.h
        libpurple/protocols/msn/slplink.c

ChangeLog: 

Initial commit of msn webcam code. Supports initiating and requesting the
remote webcam only. It can't receive any invitations. It requires a
prerelease of gst-plugins-bad (0.10.14) and a version of Farsight2 with the
fsmsnconference plugin in order to work.

-------------- next part --------------
============================================================
--- libpurple/protocols/msn/webcam.c	ce5a585a3998500ffd8859bcbb4f847fafed7faf
+++ libpurple/protocols/msn/webcam.c	ce5a585a3998500ffd8859bcbb4f847fafed7faf
@@ -0,0 +1,536 @@
+/**
+ * @file webcam.c MSN Webcam Functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "webcam.h"
+
+#include "mediamanager.h"
+/*
+ * This one shouldn't be necessary, but fsmsnwebcam doesn't get external
+ * IP addresses correctly yet
+ */
+#include "network.h"
+
+#include "msn.h"
+#include "msnutils.h"
+#include "slp.h"
+#include "slpcall.h"
+#include "slpmsg.h"
+
+static void
+msn_webcam_session_init_cb(MsnSlpCall *slpcall)
+{
+	purple_debug_info("msn", "slpcall %p, session_id %ld\n",
+			slpcall, slpcall->session_id);
+}
+
+static void
+msn_webcam_completed_cb(MsnSlpCall *slpcall, const guchar *body,
+					  gsize size)
+{
+	purple_debug_info("msn", "completed: size: %"
+			G_GSIZE_FORMAT " %s\n", size, body);
+}
+
+static void
+msn_webcam_end_cb(MsnSlpCall *slpcall, MsnSession *session)
+{
+	purple_debug_info("msn", "webcam end; slpcall wasted %s \n",
+			slpcall->wasted ? "TRUE" : "FALSE");
+	if (slpcall->media) {
+		purple_media_set_prpl_data(slpcall->media, NULL);
+		if (slpcall->wasted == TRUE)
+			purple_media_end(slpcall->media, NULL, NULL);
+	}
+}
+
+static void
+msn_webcam_codecs_changed_cb(PurpleMedia *media, gchar *sid,
+		gchar *name, gpointer *data)
+{
+	purple_debug_info("msn", "codecs changed - sid: %s name: %s\n", sid, name);
+}
+
+static void
+msn_webcam_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
+		gchar *sid, gchar *name, MsnSlpCall *slpcall)
+{
+	purple_debug_info("msn", "state changed - state: %d sid: %s "
+			"name: %s\n", state, sid, name);
+	if (state == PURPLE_MEDIA_STATE_END) {
+		slpcall = purple_media_get_prpl_data(media);
+		if (!slpcall)
+			return;
+		slpcall->media = NULL;
+		if (purple_media_is_initiator(media, NULL, NULL) &&
+				slpcall->started == FALSE)
+		{
+			msn_slpcall_close(slpcall);
+		}
+		else
+		{
+			send_bye(slpcall, "application/x-msnmsgr-sessionclosebody");
+			msn_slplink_send_queued_slpmsgs(slpcall->slplink);
+			msn_slpcall_destroy(slpcall);
+		}
+	}
+}
+
+static void
+msn_webcam_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
+		gchar *sid, gchar *name, gboolean local, gpointer *data)
+{
+	purple_debug_info("msn", "stream-info: type: %d sid: %s name: %s local: %s\n",
+			type, sid, name, local ? "TRUE" : "FALSE");
+}
+
+static void
+msn_webcam_candidates_prepared_cb(PurpleMedia *media,
+		gchar *sid, gchar *name, gpointer *data)
+{
+	PurpleAccount *account;
+	PurpleConnection *pc;
+	MsnSession *session;
+	MsnSlpLink *slplink;
+	MsnSlpCall *slpcall;
+	GList *candidates;
+	const gchar *context = "{B8BE70DE-E2CA-4400-AE03-88FF85B9F4E8}";
+	gunichar2 *utf16_context;
+	gchar *base64_context;
+	glong written;
+
+	purple_debug_info("msn", "candidates prepared - sid: %s name: %s\n", sid, name);
+
+	account = purple_media_get_account(media);
+	pc = purple_account_get_connection(account);
+	session = pc->proto_data;
+	slplink = msn_session_get_slplink(session, name);
+	slpcall = msn_slpcall_new(slplink);
+
+	msn_slpcall_init(slpcall, MSN_SLPCALL_ANY);
+
+	slpcall->media = media;
+	slpcall->cb = msn_webcam_completed_cb;
+	slpcall->session_init_cb = msn_webcam_session_init_cb;
+	slpcall->end_cb = msn_webcam_end_cb;
+	slpcall->app_id = 4;
+	purple_media_set_prpl_data(media, slpcall);
+
+	g_signal_connect(G_OBJECT(media), "codecs-changed",
+			G_CALLBACK(msn_webcam_codecs_changed_cb), slpcall);
+	g_signal_connect(G_OBJECT(media), "state-changed",
+			G_CALLBACK(msn_webcam_state_changed_cb), slpcall);
+	g_signal_connect(G_OBJECT(media), "stream-info",
+			G_CALLBACK(msn_webcam_stream_info_cb), slpcall);
+
+	candidates = purple_media_get_local_candidates(media, sid, name);
+	if (candidates) {
+		PurpleMediaCandidate *candidate = candidates->data;
+		gchar *username = purple_media_candidate_get_username(candidate);
+		purple_debug_info("msn", "webcam session-id %s\n", username);
+		slpcall->session_id = atoi(username);
+		g_free(username);
+	} else {
+		purple_debug_error("msn", "Failed find candidates for msnwebcam\n");
+	}
+	g_list_free(candidates);
+
+	utf16_context = g_utf8_to_utf16(context, -1, NULL, &written, NULL);
+	base64_context = purple_base64_encode((guchar*)utf16_context,
+			written*sizeof(gunichar2));
+	g_free(utf16_context);
+	if (purple_media_get_session_type(media, sid) == PURPLE_MEDIA_SEND_VIDEO)
+		msn_slpcall_invite(slpcall, MSN_CAM_GUID, 4, base64_context);
+	if (purple_media_get_session_type(media, sid) == PURPLE_MEDIA_RECV_VIDEO)
+		msn_slpcall_invite(slpcall, MSN_CAM_REQUEST_GUID, 4, base64_context);
+	g_free(base64_context);
+}
+
+void
+msn_webcam_send_syn(MsnSlpCall *slpcall, const gchar *content)
+{
+	MsnSlpMessage *slpmsg;
+	gchar *body;
+	guint16 *r;
+
+	/*
+	 * The SlpCall object has a different instance here,
+	 * but aMSN doesn't include a SessionID in the SlpMsg
+	 */
+#if 0
+	glong session_id = 0;
+	char *temp;
+	temp = get_token(content, "SessionID: ", "\r\n");
+	long session_id;
+	if (temp != NULL)
+		session_id = atoi(temp);
+	g_free(temp);
+#endif
+
+	GList *iter = purple_media_manager_get_media_by_account(
+			purple_media_manager_get(),
+			slpcall->slplink->session->account);
+	for (; iter; iter = g_list_delete_link(iter, iter)) {
+		MsnSlpCall *slpcall_media =
+				purple_media_get_prpl_data(iter->data);
+		if (slpcall_media && slpcall_media->id &&
+				!strcmp(slpcall_media->id, slpcall->id)) {
+			slpcall->session_id = slpcall_media->session_id;
+			slpcall->media = slpcall_media->media;
+			break;
+		}
+	}
+	g_list_free(iter);
+
+	body = g_memdup("\x80\x00\x00\x01\x08\x00\x08\x00\x00\x00"
+			"s\x00y\x00n\x00\x00\x00", 18);
+	r = (guint16*)(body+1);
+	*r = GINT16_TO_LE(rand() % 0xFFFF0000);
+
+	slpmsg = msn_slpmsg_new(slpcall->slplink);
+	slpmsg->slpcall = slpcall;
+
+	slpmsg->session_id = slpcall->session_id;
+	msn_slpmsg_set_body(slpmsg, body, 18);
+	g_free(body);
+	msn_slplink_queue_slpmsg(slpcall->slplink, slpmsg);
+}
+
+void
+msn_webcam_send_ack(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
+{
+	MsnSlpMessage *slpmsg2;
+	gchar *body = g_memdup("\x80\xea\00\x00\x08\x00\x08\x00\x00\0"
+			"a\0c\0k\x00\x00\x00", 18);
+	slpmsg2 = msn_slpmsg_new(slplink);
+	slpmsg2->slpcall = slpmsg->slpcall;
+	slpmsg2->session_id = slpmsg->session_id;
+	msn_slpmsg_set_body(slpmsg2, body, 18);
+	g_free(body);
+	msn_slplink_queue_slpmsg(slplink, slpmsg2);
+	purple_media_stream_info(slpmsg->slpcall->media,
+			PURPLE_MEDIA_INFO_ACCEPT, "msncam-send",
+			slplink->remote_user, FALSE);
+}
+
+void
+msn_webcam_send_xml(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
+{
+	MsnSlpMessage *slpmsg2;
+	PurpleMedia *media = slpmsg->slpcall->media;
+	GList  *session_ids, *candidates = NULL;
+	xmlnode *node, *child, *tcp;
+	gchar *session_id = NULL, *rid = NULL, *port = NULL, *xml;
+	const gchar *public_ip = NULL;
+	gunichar2 *xmlutf;
+	guint count = 1;
+
+	glong written;
+	gchar *body;
+	guint32 *len;
+	gboolean is_producer = FALSE;
+
+	/* Get candidates */
+	session_ids = purple_media_get_session_ids(media);
+	if (session_ids->data != NULL) {
+		candidates = purple_media_get_local_candidates(media,
+				session_ids->data, slplink->remote_user);
+		is_producer = (strcmp(session_ids->data, "msncam-send") == 0);
+	}
+	g_list_free(session_ids);
+
+	if (candidates == NULL) {
+		purple_debug_error("msn", "Could not retrieve candidates "
+				"for msn webcam\n");
+		return;
+	} else if (g_list_length(candidates) >= 1) {
+		PurpleMediaCandidate *candidate = candidates->data;
+		port = g_strdup_printf("%d",
+				purple_media_candidate_get_port(candidate));
+		rid = purple_media_candidate_get_foundation(candidate);
+	}
+
+	session_id = g_strdup_printf("%lu", slpmsg->session_id);
+
+	/* Construct xml message */
+	node = xmlnode_new(is_producer ? "producer" : "viewer");
+	child = xmlnode_new_child(node, "version");
+	xmlnode_insert_data(child, "2.0", -1);
+	child = xmlnode_new_child(node, "rid");
+	xmlnode_insert_data(child, rid, -1);
+	child = xmlnode_new_child(node, "session");
+	xmlnode_insert_data(child, session_id, -1);
+
+	tcp = xmlnode_new_child(node, "tcp");
+	child = xmlnode_new_child(tcp, "tcpport");
+	xmlnode_insert_data(child, port, -1);
+	child = xmlnode_new_child(tcp, "tcplocalport");
+	xmlnode_insert_data(child, port, -1);
+	child = xmlnode_new_child(tcp, "tcpexternalport");
+	xmlnode_insert_data(child, port, -1);
+
+	public_ip = purple_network_get_my_ip(-1);
+	for (; candidates; candidates =
+			g_list_delete_link(candidates, candidates)) {
+		PurpleMediaCandidate *candidate = candidates->data;
+		gchar *ip = purple_media_candidate_get_ip(candidate);
+		gchar *name = g_strdup_printf("tcpipaddress%d", count);
+		child = xmlnode_new_child(tcp, name);
+		xmlnode_insert_data(child, ip, -1);
+
+		if (public_ip && !strcmp(ip, public_ip))
+			public_ip = NULL;
+
+		g_free(name);
+		g_free(ip);
+		++count;
+	}
+	if (public_ip) {
+		/*
+		 * This one shouldn't be necessary, but fsmsnwebcam doesn't
+		 * get external IP addresses correctly yet
+		 */
+		gchar *name = g_strdup_printf("tcpipaddress%d", count);
+		child = xmlnode_new_child(tcp, name);
+		xmlnode_insert_data(child, public_ip, -1);
+		g_free(name);
+	}
+
+	child = xmlnode_new_child(node, "codec");
+	child = xmlnode_new_child(node, "channelmode");
+	xmlnode_insert_data(child, "1", -1);
+	xml = xmlnode_to_str(node, NULL);
+	xmlnode_free(node);
+
+	g_free(session_id);
+	g_free(port);
+	g_free(rid);
+
+	xmlutf = g_utf8_to_utf16(xml, strlen(xml) + 1, NULL, &written, NULL);
+	g_free(xml);
+	written *= sizeof(gunichar2);
+
+	body = g_malloc(written + 10);
+	memcpy(body, "\x80\x00\x00\x00\x08\x00", 6);
+	len = (guint32*)(body+6);
+	*len = GUINT32_TO_LE((guint32)written);
+	memcpy(body + 10, xmlutf, written);
+	g_free(xmlutf);
+
+	slpmsg2 = msn_slpmsg_new(slplink);
+	slpmsg2->slpcall = slpmsg->slpcall;
+	slpmsg2->session_id = slpmsg->session_id;
+	msn_slpmsg_set_body(slpmsg2, body, written + 10);
+	g_free(body);
+	msn_slplink_queue_slpmsg(slplink, slpmsg2);
+}
+
+void
+msn_webcam_recv_xml(MsnSlpLink *slplink, MsnSlpMessage *slpmsg, const guchar *body, gsize body_len)
+{
+	MsnSlpMessage *slpmsg2;
+	glong bytes_written;
+	gchar *xml = g_utf16_to_utf8((const gunichar2*)body + 5,
+			body_len - 5, NULL, &bytes_written, NULL);
+	gchar *body_str;
+	gboolean is_producer = FALSE;
+
+	if (!strncmp(xml, "<producer>", 10))
+		is_producer = TRUE;
+
+	if (is_producer) {
+		GList *candidates = NULL;
+		guint port, local_port, external_port;
+		xmlnode *node, *childnode, *tcpnode;
+		gchar *rid, *session_id, *ip, *port_str;
+		guint count = 1;
+
+		node = xmlnode_from_str(xml, bytes_written);
+		childnode = xmlnode_get_child(node, "rid");
+		rid = xmlnode_get_data(childnode);
+		childnode = xmlnode_get_child(node, "session");
+		session_id = xmlnode_get_data(childnode);
+		tcpnode = xmlnode_get_child(node, "tcp");
+		childnode = xmlnode_get_child(tcpnode, "tcpport");
+		port_str = xmlnode_get_data(childnode);
+		port = port_str ? atoi(port_str) : -1;
+		g_free(port_str);
+		childnode = xmlnode_get_child(tcpnode, "tcplocalport");
+		port_str = xmlnode_get_data(childnode);
+		local_port = port_str ? atoi(port_str) : -1;
+		g_free(port_str);
+		childnode = xmlnode_get_child(tcpnode, "tcpexternalport");
+		port_str = xmlnode_get_data(childnode);
+		external_port = port_str ? atoi(port_str) : -1;
+		g_free(port_str);
+
+		if (rid == NULL || session_id == NULL || port == -1) {
+			purple_debug_error("msn", "Unable to parse webcam xml\n");
+			g_free(rid);
+			g_free(session_id);
+			return;
+		}
+
+		while (TRUE) {
+			gchar *name = g_strdup_printf("tcpipaddress%d", count);
+			++count;
+			childnode = xmlnode_get_child(tcpnode, name);
+			g_free(name);
+			if (childnode == NULL)
+				break;
+			ip = xmlnode_get_data(childnode);
+			if (ip == NULL)
+				continue;
+
+			candidates = g_list_prepend(candidates,
+					purple_media_candidate_new(rid, 1,
+					PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
+					PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, ip, port));
+			g_object_set(candidates->data, "username", session_id, NULL);
+
+
+			if (local_port > 0) {
+				candidates = g_list_prepend(candidates,
+						purple_media_candidate_new(rid, 1,
+						PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
+						PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+						ip, local_port));
+				g_object_set(candidates->data, "username", session_id, NULL);
+			}
+			if (external_port > 0) {
+				candidates = g_list_prepend(candidates,
+						purple_media_candidate_new(rid, 1,
+						PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
+						PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+						ip, external_port));
+				g_object_set(candidates->data, "username", session_id, NULL);
+			}
+			g_free(ip);
+		}
+
+		g_free(rid);
+		g_free(session_id);
+		xmlnode_free(node);
+
+		candidates = g_list_reverse(candidates);
+		purple_media_add_remote_candidates(slpmsg->slpcall->media,
+				"msncam-recv", slplink->remote_user, candidates);
+	} else {
+		slpmsg2 = msn_slpmsg_new(slplink);
+		slpmsg2->slpcall = slpmsg->slpcall;
+		slpmsg2->session_id = slpmsg->session_id;
+		body_str = g_memdup(
+				"\x80\xec\x00\x03\x08\x00" /* magic string */
+				"\x16\0\0\0"		/* length of following */
+				"r\0e\0c\0e\0i\0v\0e\0d\0V\0i\0e\0w\0e\0r\0D\0a\0t\0a\0\0\0", 48);
+		msn_slpmsg_set_body(slpmsg2, body_str, 48);
+		g_free(body_str);
+		msn_slplink_queue_slpmsg(slplink, slpmsg2);
+	}
+	g_free(xml);
+}
+
+void
+msn_webcam_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
+{
+	const guchar *body = slpmsg->buffer;
+	gsize body_len = slpmsg->size;
+
+	if (body_len >= 18 && !memcmp(body + 10, "s\0y\0n\0", 6)) {
+		purple_debug_info("msn", "webcam: got syn %s\n", body + 10);
+		msn_webcam_send_ack(slplink, slpmsg);
+	} else if (body_len >= 18 && !memcmp(body + 10, "a\0c\0k\0", 6)) {
+		purple_debug_info("msn", "webcam: got ack\n");
+		msn_webcam_send_xml(slplink, slpmsg);
+	} else if (body_len >= 26 &&
+			(!memcmp(body + 10, "<\0v\0i\0e\0w\0e\0r\0>\0", 16) ||
+			!memcmp(body + 10, "<\0p\0r\0o\0d\0u\0c\0e\0r\0>\0", 20))) {
+		purple_debug_info("msn", "webcam: got xml\n");
+		msn_webcam_recv_xml(slplink, slpmsg, body, body_len);
+	}
+}
+
+void
+msn_webcam_recv(MsnSlpCall *slpcall)
+{	
+	PurpleMedia *media;
+	media = purple_media_manager_create_media(purple_media_manager_get(),
+			slpcall->slplink->session->account,
+			"fsmsncamrecvconference",
+			slpcall->slplink->remote_user, FALSE);
+	purple_media_set_prpl_data(media, slpcall);
+
+	slpcall->media = media;
+	slpcall->cb = msn_webcam_completed_cb;
+	slpcall->end_cb = msn_webcam_end_cb;
+
+	/* connect callbacks */
+	g_signal_connect(G_OBJECT(media), "codecs-changed",
+			G_CALLBACK(msn_webcam_codecs_changed_cb), slpcall);
+	g_signal_connect(G_OBJECT(media), "state-changed",
+			G_CALLBACK(msn_webcam_state_changed_cb), slpcall);
+	g_signal_connect(G_OBJECT(media), "stream-info",
+			G_CALLBACK(msn_webcam_stream_info_cb), slpcall);
+
+	purple_media_add_stream(media, "msncam-send",
+			slpcall->slplink->remote_user,
+			PURPLE_MEDIA_RECV_VIDEO, FALSE, "", 0, NULL);
+}
+
+gboolean
+msn_initiate_media(PurpleAccount *account, const gchar *who, PurpleMediaSessionType type)
+{
+	PurpleMedia *media;
+
+	/* Hack until there are menu entries for this */
+	if (type == PURPLE_MEDIA_VIDEO)
+		type = PURPLE_MEDIA_SEND_VIDEO;
+	if (type == PURPLE_MEDIA_AUDIO)
+		type = PURPLE_MEDIA_RECV_VIDEO;
+
+	if (type & PURPLE_MEDIA_SEND_VIDEO) {
+		media = purple_media_manager_create_media(purple_media_manager_get(),
+				account, "fsmsncamsendconference", who, TRUE);
+		g_signal_connect(G_OBJECT(media), "candidates-prepared",
+				G_CALLBACK(msn_webcam_candidates_prepared_cb), NULL);
+		purple_media_add_stream(media, "msncam-send", who,
+				PURPLE_MEDIA_SEND_VIDEO, TRUE, "", 0, NULL);
+	}
+	if (type & PURPLE_MEDIA_RECV_VIDEO) {
+		media = purple_media_manager_create_media(purple_media_manager_get(),
+				account, "fsmsncamrecvconference", who, TRUE);
+		g_signal_connect(G_OBJECT(media), "candidates-prepared",
+				G_CALLBACK(msn_webcam_candidates_prepared_cb), NULL);
+		purple_media_add_stream(media, "msncam-recv", who,
+				PURPLE_MEDIA_RECV_VIDEO, TRUE, "", 0, NULL);
+	}
+
+	return TRUE;
+}
+
+PurpleMediaCaps
+msn_get_media_caps(PurpleAccount *account, const gchar *who)
+{
+	return PURPLE_MEDIA_CAPS_VIDEO | PURPLE_MEDIA_CAPS_AUDIO;
+}
+
============================================================
--- libpurple/protocols/msn/webcam.h	f29281d5038691636ebe1438a302d54794d88a2b
+++ libpurple/protocols/msn/webcam.h	f29281d5038691636ebe1438a302d54794d88a2b
@@ -0,0 +1,44 @@
+/**
+ * @file webcam.h MSN Webcam Functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _MSN_WEBCAM_H_
+#define _MSN_WEBCAM_H_
+#include "internal.h"
+#include "slpcall.h"
+#include "slplink.h"
+#include "slpmsg.h"
+#include "media.h"
+
+void msn_webcam_send_syn(MsnSlpCall *slpcall, const gchar *content);
+void msn_webcam_send_ack(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
+void msn_webcam_send_xml(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
+void msn_webcam_recv_xml(MsnSlpLink *slplink, MsnSlpMessage *slpmsg,
+		const guchar *body, gsize body_len);
+void msn_webcam_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
+void msn_webcam_recv(MsnSlpCall *slpcall);
+gboolean msn_initiate_media(PurpleAccount *account, const gchar *who,
+		PurpleMediaSessionType type);
+PurpleMediaCaps msn_get_media_caps(PurpleAccount *account, const gchar *who);
+
+#endif /* _MSN_WEBCAM_H_ */
============================================================
--- libpurple/protocols/msn/Makefile.am	bc0d9535367c5da381e6515af27b49fb54888e96
+++ libpurple/protocols/msn/Makefile.am	7518c72758fc40863c4c9b386521b0dcff495709
@@ -64,6 +64,8 @@ MSNSOURCES = \
 	user.h \
 	userlist.c \
 	userlist.h \
+	webcam.c \
+	webcam.h \
 	msnutils.c \
 	msnutils.h
 
============================================================
--- libpurple/protocols/msn/Makefile.mingw	2fc5eab590015d1ba8b3e3effb4896a0338d7d7a
+++ libpurple/protocols/msn/Makefile.mingw	490ec256199cc38690a1684dd47658119e515066
@@ -66,6 +66,7 @@ C_SRC =			cmdproc.c \
 			transaction.c \
 			user.c \
 			userlist.c \
+			webcam.c \
 			msnutils.c
 
 OBJECTS = $(C_SRC:%.c=%.o)
============================================================
--- libpurple/protocols/msn/msn.c	db1ea88fe86a348e57fe2dc47b8a2a790d8b27eb
+++ libpurple/protocols/msn/msn.c	632fa936c6a04c6586b497b65926ab0c9d3a4a61
@@ -47,6 +47,7 @@
 #include "notification.h"
 #include "sync.h"
 #include "slplink.h"
+#include "webcam.h"
 
 #if PHOTO_SUPPORT
 #define MAX_HTTP_BUDDYICON_BYTES (200 * 1024)
@@ -2688,8 +2689,8 @@ static PurplePluginProtocolInfo prpl_inf
 	msn_attention_types,                    /* attention_types */
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
 	msn_get_account_text_table,             /* get_account_text_table */
-	NULL,                                   /* initiate_media */
-	NULL                                    /* can_do_media */
+	msn_initiate_media,                     /* initiate_media */
+	msn_get_media_caps                      /* get_media_caps */
 };
 
 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/msn/slp.c	d4d55a95ef034912d98e641c87d391961de24a7f
+++ libpurple/protocols/msn/slp.c	ebef464d91b6515e4d8be1cebe58b1a75faba895
@@ -31,6 +31,7 @@
 #include "switchboard.h"
 
 #include "smiley.h"
+#include "webcam.h"
 
 /* ms to delay between sending buddy icon requests to the server. */
 #define BUDDY_ICON_DELAY 20
@@ -489,9 +490,10 @@ got_invite(MsnSlpCall *slpcall,
 	else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
 	{
 		/* A direct connection? */
-
+#if 0
 		char *listening, *nonce;
 		char *content;
+#endif
 
 		if (FALSE)
 		{
@@ -527,6 +529,14 @@ got_invite(MsnSlpCall *slpcall,
 				port);
 #endif
 		}
+		else if (1)
+		{
+			send_decline(slpcall, branch, "application/x-msnmsgr-session-failure-respbody",
+					NULL);
+			msn_webcam_send_syn(slpcall, content);
+			return;
+		}
+#if 0
 		else
 		{
 			listening = "false";
@@ -546,6 +556,7 @@ got_invite(MsnSlpCall *slpcall,
 
 		g_free(content);
 		g_free(nonce);
+#endif
 	}
 	else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
 	{
============================================================
--- libpurple/protocols/msn/slpcall.c	c5cffd20e8282ade7b1d83051ffa9deb5756e5b6
+++ libpurple/protocols/msn/slpcall.c	108dc85beb58837b1c9aa4d114d7119f89d6eb6b
@@ -24,6 +24,7 @@
 #include "msn.h"
 #include "msnutils.h"
 #include "slpcall.h"
+#include "webcam.h"
 
 #include "slp.h"
 
@@ -200,7 +201,7 @@ msn_slp_process_msg(MsnSlpLink *slplink,
 
 	if (slpmsg->flags == 0x0 || slpmsg->flags == 0x1000000)
 	{
-		char *body_str;
+		char *body_str = NULL;
 
 		if (slpmsg->session_id == 64)
 		{
@@ -252,6 +253,9 @@ msn_slp_process_msg(MsnSlpLink *slplink,
 			                         slplink->remote_user,
 			                         body_str);
 		}
+		else if (slpmsg->slpcall && slpmsg->slpcall->app_id == 4) {
+			msn_webcam_process_msg(slplink, slpmsg);
+		}
 		else
 		{
 			body_str = g_strndup((const char *)body, body_len);
============================================================
--- libpurple/protocols/msn/slpcall.h	13863cc3a700579662279fdb70c9fb520d5c2adf
+++ libpurple/protocols/msn/slpcall.h	726c02cc5e9eb33e9967ad5e67241c075815f438
@@ -72,6 +72,7 @@ struct _MsnSlpCall
 	char *data_info;
 
 	PurpleXfer *xfer;
+	PurpleMedia *media;
 
 	MsnSlpCb cb;
 	void (*end_cb)(MsnSlpCall *slpcall, MsnSession *session);
============================================================
--- libpurple/protocols/msn/slplink.c	a1d28636ade1b68f9bbbee806ca0ff5904635a55
+++ libpurple/protocols/msn/slplink.c	695292089ba3f2738c405cbccf9eea8948a60cd3
@@ -349,11 +349,17 @@ msn_slplink_release_slpmsg(MsnSlpLink *s
 
 	slpmsg->msg = msg = msn_message_new_msnslp();
 
-	if (slpmsg->flags == 0x0)
+	if (slpmsg->slpcall && slpmsg->slpcall->app_id == 4)
 	{
 		msg->msnslp_header.session_id = slpmsg->session_id;
 		msg->msnslp_header.ack_id = rand() % 0xFFFFFF00;
+		msg->msnslp_footer.value = slpmsg->slpcall->app_id;
 	}
+	else if (slpmsg->flags == 0x0)
+	{
+		msg->msnslp_header.session_id = slpmsg->session_id;
+		msg->msnslp_header.ack_id = rand() % 0xFFFFFF00;
+	}
 	else if (slpmsg->flags == 0x2)
 	{
 		msg->msnslp_header.session_id = slpmsg->session_id;


More information about the Commits mailing list