pidgin.vv.yahoo.voice: bad95bf7: Initial commit of Yahoo Voice code. It c...

maiku at pidgin.im maiku at pidgin.im
Wed Aug 19 22:10:38 EDT 2009


-----------------------------------------------------------------
Revision: bad95bf79c54addda84101885ba9fc4b2f17c12d
Ancestor: 68bb82df03e74d8e33d5c334880a9b5bbab6a5d8
Author: maiku at pidgin.im
Date: 2009-08-20T02:04:54
Branch: im.pidgin.pidgin.vv.yahoo.voice
URL: http://d.pidgin.im/viewmtn/revision/info/bad95bf79c54addda84101885ba9fc4b2f17c12d

Added files:
        libpurple/protocols/yahoo/yahoo_sip.c
        libpurple/protocols/yahoo/yahoo_sip.h
Modified files:
        configure.ac libpurple/protocols/yahoo/Makefile.am
        libpurple/protocols/yahoo/libymsg.c
        libpurple/protocols/yahoo/libymsg.h

ChangeLog: 

Initial commit of Yahoo Voice code. It connects to and disconnects from the
Yahoo SIP server when connecting to and disconnecting from a Yahoo account.

libsofia-sip-ua and libsofia-sip-ua-glib are required to run this.

-------------- next part --------------
============================================================
--- libpurple/protocols/yahoo/yahoo_sip.c	e7371b3954a1b79de94601ab7b89f2bae32a39dc
+++ libpurple/protocols/yahoo/yahoo_sip.c	e7371b3954a1b79de94601ab7b89f2bae32a39dc
@@ -0,0 +1,222 @@
+/**
+ * @file yahoo_sip.c The Yahoo! protocol plugin SIP 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 "internal.h"
+
+#include "cipher.h"
+#include "debug.h"
+
+#include "yahoo_sip.h"
+#include "libymsg.h"
+
+#include <glib.h>
+#include <sofia-sip/nua.h>
+#include <sofia-sip/su_glib.h>
+#include <sofia-sip/sip_header.h>
+
+/* This is the y64 alphabet... it's like base64, but has a . and a _ */
+static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
+
+/* This is taken from Sylpheed by Hiroyuki Yamamoto.  We have our own tobase64 function
+ * in util.c, but it has a bug I don't feel like finding right now ;) */
+static void to_y64(char *out, const unsigned char *in, gsize inlen)
+     /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
+{
+	for (; inlen >= 3; inlen -= 3)
+		{
+			*out++ = base64digits[in[0] >> 2];
+			*out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+			*out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+			*out++ = base64digits[in[2] & 0x3f];
+			in += 3;
+		}
+	if (inlen > 0)
+		{
+			unsigned char fragment;
+
+			*out++ = base64digits[in[0] >> 2];
+			fragment = (in[0] << 4) & 0x30;
+			if (inlen > 1)
+				fragment |= in[1] >> 4;
+			*out++ = base64digits[fragment];
+			*out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
+			*out++ = '-';
+		}
+	*out = '\0';
+}
+
+static gboolean
+send_yahooref(gpointer nh)
+{
+	nua_method(nh, NUTAG_METHOD("YAHOOREF"), TAG_END());
+	return TRUE;
+}
+
+static void
+event_callback(nua_event_t event, int status, const gchar *phrase, nua_t *nua,
+		nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic,
+		const sip_t *sip, tagi_t tags[])
+{
+	purple_debug_info("yahoo", "sofia-sip: event %s status %d %s\n",
+			nua_event_name(event), status, phrase);
+	if (event == nua_r_register && status == 401) {
+		PurpleAccount *account = magic;
+		PurpleConnection *pc = purple_account_get_connection(account);
+		YahooData *yd = pc->proto_data;
+		const sip_www_authenticate_t *wa = sip->sip_www_authenticate;
+		const gchar *method = NULL, *realm = NULL, *nonce = NULL;
+		gchar *auth, *cookie;
+		PurpleCipher *cipher;
+		PurpleCipherContext *context;
+		gchar *to_hash, response[25];
+		guchar digest[16];
+
+		if (!wa) {
+			purple_debug_error("yahoo", "sip www authenticate "
+					"structure is NULL\n");
+			return;
+		}
+
+		realm = msg_params_find(wa->au_params, "realm=");
+		method = wa->au_scheme;
+		nonce = msg_params_find(wa->au_params, "nonce=");
+		if (!realm || !method || !nonce) {
+			purple_debug_error("yahoo", "sip: unable to retrieve "
+					"authentication parameters\n");
+			return;
+		}
+
+		cipher = purple_ciphers_find_cipher("md5");
+		context = purple_cipher_context_new(cipher, NULL);
+		to_hash = g_strdup_printf("%s\"%s\"", yd->cookie_crumb, nonce);
+		purple_cipher_context_append(context, (const guchar*)to_hash,
+				strlen(to_hash));
+		g_free(to_hash);
+		purple_cipher_context_digest(context, sizeof(digest),
+				digest, NULL);
+		purple_cipher_context_destroy(context);
+		to_y64(response, digest, 16);
+
+		auth = g_strdup_printf("%s:%s:%s:%s", method, realm,
+				purple_account_get_username(account),
+				purple_connection_get_password(pc));
+		/*
+		 * Should this be used instead?
+		 * "Y-Cookie: Y=%s; path=/; domain=.yahoo.com; T=%s; path=/;"
+		 * " domain=.yahoo.com; AT=2; CRUMB=%s"
+		 */
+		cookie = g_strdup_printf("Y-Cookie: Y=%s; T=%s; AT=2; CRUMB=%s",
+				yd->cookie_y, yd->cookie_t, response);
+
+		nua_authenticate(nh, NUTAG_AUTH(auth),
+				SIPTAG_HEADER_STR(cookie),
+				SIPTAG_HEADER_STR("Y-User-Agent: intl=us; "
+				"os-version=w-2-5-1; internet-connection=lan; "
+				"cpu-speed=2390; pstn-call-enable=true; "
+				"appid=9.0.0.2034"),
+				TAG_END());
+
+		g_free(auth);
+		g_free(cookie);
+	} else if (event == nua_r_register && status == 200) {
+		nua_subscribe(nh, 
+				SIPTAG_EVENT_STR("billing"),
+				TAG_END());
+		purple_timeout_add_seconds(60, send_yahooref, nh);
+	} else if (event == nua_r_unregister && status == 200) {
+		nua_shutdown(nua);
+	} else if (event == nua_r_shutdown && status == 200) {
+		nua_destroy(nua);
+	}
+}
+
+void
+yahoo_sip_init(PurpleAccount *account)
+{
+	PurpleConnection *pc = purple_account_get_connection(account);
+	YahooData *yd = purple_connection_get_protocol_data(pc);
+	GSource *gsource;
+	su_root_t *sofia_event_loop;
+	su_timer_t *timer;
+	gchar *sip_str;
+
+	purple_debug_info("yahoo", "Starting Sofia-SIP\n");
+
+	sofia_event_loop = su_glib_root_create(NULL);
+
+	gsource = su_glib_root_gsource(sofia_event_loop);
+	g_source_attach(gsource, g_main_context_default());
+
+	timer = su_timer_create(su_root_task(sofia_event_loop), 200L);
+
+
+	yd->nua = nua_create(sofia_event_loop, event_callback, account,
+			NUTAG_URL("sip:*:*;transport=tcp"),
+			NUTAG_M_PARAMS("transport=tcp"),
+			NUTAG_MEDIA_ENABLE(1),
+#if 0
+			/*
+			 * This is supposed to stop it from sending an OPTIONS
+			 * message, but it doesn't...
+			 */
+			NUTAG_OUTBOUND("no-options-keepalive"),
+			NUTAG_KEEPALIVE(0),
+#endif
+			TAG_END());
+
+	/* XXX: Use the real address here or resolve it */
+	sip_str = g_strdup_printf("sip:%s at 68.142.233.179:443;transport=tcp",
+			purple_url_encode(purple_account_get_username(account)));
+	yd->nh = nua_handle(yd->nua, NULL,
+			SIPTAG_TO_STR(sip_str),
+			TAG_END());
+	g_free(sip_str);
+
+	nua_register(yd->nh,
+#if 0
+			/* Possibly needed for actual invitations? */
+			NUTAG_M_DISPLAY("1"),
+			NUTAG_M_USERNAME("line-1"),
+			NUTAG_M_PARAMS("user=phone"),
+			NUTAG_M_FEATURES("audio"),
+			NUTAG_CALLEE_CAPS(0),
+#endif
+			TAG_END());
+}
+
+void
+yahoo_sip_uninit(PurpleAccount *account)
+{
+	PurpleConnection *pc = purple_account_get_connection(account);
+	YahooData *yd = purple_connection_get_protocol_data(pc);
+
+	/*
+	 * XXX: These don't always finish when shutting down.
+	 * I don't know if that's a problem or not...
+	 */
+	if (nua_handle_has_registrations(yd->nh) == 1)
+		nua_unregister(yd->nh, TAG_NULL());
+	else
+		nua_shutdown(yd->nua);
+}
============================================================
--- libpurple/protocols/yahoo/yahoo_sip.h	c0d485a2bc5210d9db0424c227a898f66475d1f7
+++ libpurple/protocols/yahoo/yahoo_sip.h	c0d485a2bc5210d9db0424c227a898f66475d1f7
@@ -0,0 +1,33 @@
+/**
+ * @file yahoo_sip.h The Yahoo! protocol plugin SIP 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 _YAHOO_SIP_H_
+#define _YAHOO_SIP_H_
+
+#include "account.h"
+
+void yahoo_sip_init(PurpleAccount *account);
+void yahoo_sip_uninit(PurpleAccount *account);
+
+#endif  /* _YAHOO_SIP_H_ */
============================================================
--- configure.ac	25d35a51d820754c8e2468e3058657dcf4cd4c8b
+++ configure.ac	c5324dfaaca8f124dd55bd725cf7716f87f913b9
@@ -797,6 +797,21 @@ if test "x$enable_vv" != "xno"; then
 if test "x$enable_vv" != "xno"; then
 	if test "x$enable_gstreamer" != "xno" -a "x$enable_gstinterfaces" != "xno" -a "x$enable_farsight" != "xno"; then
 		AC_DEFINE(USE_VV, 1, [Use voice and video])
+		PKG_CHECK_MODULES(SOFIASIP, [sofia-sip-ua], [
+			AC_DEFINE(USE_SOFIASIP, 1, [Use Sofia-SIP for SIP voice and video])
+			AC_SUBST(SOFIASIP_CFLAGS)
+			AC_SUBST(SOFIASIP_LIBS)
+			
+			PKG_CHECK_MODULES(SOFIASIPGLIB, [sofia-sip-ua-glib], [
+				AC_DEFINE(USE_SOFIASIPGLIB, 1, [Use GLib utils for Sofia-SIP for SIP voice and video])
+				AC_SUBST(SOFIASIPGLIB_CFLAGS)
+				AC_SUBST(SOFIASIPGLIB_LIBS)
+			], [
+				enable_sofiasip="no"
+			])
+		], [
+			enable_sofiasip="no"
+		])
 	else
 		enable_vv="no"
 		if test "x$force_vv" = "xyes"; then
============================================================
--- libpurple/protocols/yahoo/Makefile.am	e9d9993f55ec5505a065b7892b98df4be11a6288
+++ libpurple/protocols/yahoo/Makefile.am	e10f377addb9008955e3875562a763c4d6443d92
@@ -22,6 +22,8 @@ YAHOOSOURCES = \
 	yahoo_picture.c \
 	yahoo_picture.h \
 	yahoo_profile.c \
+	yahoo_sip.h \
+	yahoo_sip.c \
 	ycht.c \
 	ycht.h
 
@@ -43,7 +45,9 @@ libymsg_la_SOURCES = $(YAHOOSOURCES)
 pkg_LTLIBRARIES     = libymsg.la libyahoo.la libyahoojp.la
 
 libymsg_la_SOURCES = $(YAHOOSOURCES)
-libymsg_la_LIBADD  = $(GLIB_LIBS)
+libymsg_la_LIBADD  = $(GLIB_LIBS) \
+		$(SOFIASIP_LIBS) \
+		$(SOFIASIPGLIB_LIBS)
 
 libyahoo_la_SOURCES = libyahoo.c
 libyahoo_la_LIBADD = libymsg.la
@@ -57,4 +61,6 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(SOFIASIP_CFLAGS) \
+	$(SOFIASIPGLIB_CFLAGS) \
 	$(DEBUG_CFLAGS)
============================================================
--- libpurple/protocols/yahoo/libymsg.c	e15c747098a033957affc608406029519a9efc6d
+++ libpurple/protocols/yahoo/libymsg.c	9a094aced8948ca727f018c2acb7802c09638aa3
@@ -49,6 +49,7 @@
 #include "yahoo_friend.h"
 #include "yahoo_packet.h"
 #include "yahoo_picture.h"
+#include "yahoo_sip.h"
 #include "ycht.h"
 
 /* #define YAHOO_DEBUG */
@@ -742,6 +743,7 @@ static void yahoo_process_list(PurpleCon
 	}
 	/* Now that we've got the list, request aliases */
 	yahoo_fetch_aliases(gc);
+	yahoo_sip_init(account);
 }
 
 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
@@ -1676,7 +1678,6 @@ static void yahoo_auth16_stage2(PurpleUt
 		gchar **split_data = g_strsplit(ret_data, "\r\n", -1);
 		int totalelements = 0;
 		int response_no = -1;
-		char *crumb = NULL;
 		char *crypt = NULL;
 
 #if GLIB_CHECK_VERSION(2,6,0)
@@ -1686,7 +1687,7 @@ static void yahoo_auth16_stage2(PurpleUt
 #endif
 		if (totalelements >= 4) {
 			response_no = strtol(split_data[0], NULL, 10);
-			crumb = g_strdup(split_data[1] + strlen("crumb="));
+			yd->cookie_crumb = g_strdup(split_data[1] + strlen("crumb="));
 			yd->cookie_y = g_strdup(split_data[2] + strlen("Y="));
 			yd->cookie_t = g_strdup(split_data[3] + strlen("T="));
 		}
@@ -1711,7 +1712,7 @@ static void yahoo_auth16_stage2(PurpleUt
 					break;
 				default:
 					/* if we have everything we need, why not try to login irrespective of response */
-					if((crumb != NULL) && (yd->cookie_y != NULL) && (yd->cookie_t != NULL)) {
+					if((yd->cookie_crumb != NULL) && (yd->cookie_y != NULL) && (yd->cookie_t != NULL)) {
 						try_login_on_error = TRUE;
 						break;
 					}
@@ -1730,10 +1731,9 @@ static void yahoo_auth16_stage2(PurpleUt
 			}
 		}
 
-		crypt = g_strconcat(crumb, auth_data->seed, NULL);
+		crypt = g_strconcat(yd->cookie_crumb, auth_data->seed, NULL);
 		yahoo_auth16_stage3(gc, crypt);
 		g_free(crypt);
-		g_free(crumb);
 	}
 	g_free(auth_data->seed);
 	g_free(auth_data);
@@ -3465,6 +3465,8 @@ void yahoo_close(PurpleConnection *gc) {
 	YahooData *yd = (YahooData *)gc->proto_data;
 	GSList *l;
 
+	yahoo_sip_uninit(purple_connection_get_account(gc));
+
 	if (gc->inpa)
 		purple_input_remove(gc->inpa);
 
@@ -3517,6 +3519,7 @@ void yahoo_close(PurpleConnection *gc) {
 
 	g_free(yd->cookie_y);
 	g_free(yd->cookie_t);
+	g_free(yd->cookie_crumb);
 
 	if (yd->txhandler)
 		purple_input_remove(yd->txhandler);
============================================================
--- libpurple/protocols/yahoo/libymsg.h	22e537c8bea812721238661dda7ebf4fe877a8dd
+++ libpurple/protocols/yahoo/libymsg.h	f95356261bc098a01ea0d90e67f758fd05e39238
@@ -42,6 +42,7 @@
 #define YAHOO_XFER_PORT 80
 #define YAHOO_XFER_RELAY_HOST "relay.msg.yahoo.com"
 #define YAHOO_XFER_RELAY_PORT 80
+#define YAHOO_SIP_HOST "voipa.sip.yahoo.com"
 #define YAHOO_ROOMLIST_URL "http://insider.msg.yahoo.com/ycontent/"
 #define YAHOO_ROOMLIST_LOCALE "us"
 /* really we should get the list of servers from
@@ -149,6 +150,8 @@ struct _YchtConn;
 };
 
 struct _YchtConn;
+struct nua_s;
+struct nua_handle_s;
 
 typedef struct _YahooPersonalDetails {
 	char *id;
@@ -204,6 +207,7 @@ typedef struct {
 	gsize auth_written;
 	char *cookie_y;
 	char *cookie_t;
+	char *cookie_crumb;
 	int session_id;
 	gboolean jp;
 	gboolean wm; /* connected w/ web messenger method */
@@ -239,6 +243,10 @@ typedef struct {
 	int yahoo_p2p_server_watcher;
 	GHashTable *sms_carrier;	/* sms carrier data */
 	guint yahoo_p2p_server_timeout_handle;
+
+	/* SIP variables */
+	struct nua_s *nua;
+	struct nua_handle_s *nh;
 } YahooData;
 
 #define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255)


More information about the Commits mailing list