changeset 23769:60f5abc6cf0c

propagate from branch 'im.pidgin.pidgin' (head 7f8e027e1591ade622baf58a9dac216e7122c1ac) to branch 'im.pidgin.pidgin.vv' (head 9fd950ff4de5331c13cd762cb755741046bdd576)
author Evan Schoenberg <evan.s@dreskin.net>
date Sat, 29 Dec 2007 06:34:59 +0000
parents 18628d7aba30 (current diff) f0e32b734ef7 (diff)
children b20e24fcae47
files configure.ac finch/Makefile.am finch/gntaccount.c finch/gntdebug.c finch/gntft.c finch/gntnotify.c finch/gntplugin.c finch/gntpounce.c finch/gntrequest.c finch/gntstatus.c finch/gntui.c finch/libgnt/Makefile.am libpurple/Makefile.am libpurple/plugins/Makefile.am libpurple/protocols/bonjour/Makefile.am libpurple/protocols/bonjour/bonjour.c libpurple/protocols/bonjour/mdns_howl.c libpurple/protocols/gg/gg.c libpurple/protocols/irc/irc.c libpurple/protocols/jabber/.todo libpurple/protocols/jabber/Makefile.am libpurple/protocols/jabber/disco.c libpurple/protocols/jabber/google.c libpurple/protocols/jabber/google.h libpurple/protocols/jabber/iq.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.h libpurple/protocols/jabber/libxmpp.c libpurple/protocols/jabber/presence.c libpurple/protocols/msn/Makefile.am libpurple/protocols/msn/msn-utils.c libpurple/protocols/msn/msn-utils.h libpurple/protocols/msn/msn.c libpurple/protocols/myspace/Makefile.am libpurple/protocols/myspace/myspace.c libpurple/protocols/novell/novell.c libpurple/protocols/null/nullprpl.c libpurple/protocols/oscar/.todo libpurple/protocols/oscar/libaim.c libpurple/protocols/oscar/libicq.c libpurple/protocols/qq/qq.c libpurple/protocols/sametime/sametime.c libpurple/protocols/silc/silc.c libpurple/protocols/silc10/silc.c libpurple/protocols/simple/simple.c libpurple/protocols/yahoo/yahoo.c libpurple/protocols/zephyr/zephyr.c libpurple/prpl.h pidgin/Makefile.am pidgin/gtkconv.c pidgin/gtkconv.h pidgin/pixmaps/animations/16/Makefile.am pidgin/pixmaps/animations/16/Makefile.mingw pidgin/pixmaps/animations/Makefile.am pidgin/pixmaps/animations/Makefile.mingw pidgin/pixmaps/buddy_icons/Makefile.am pidgin/pixmaps/buddy_icons/Makefile.mingw pidgin/pixmaps/dialogs/16/Makefile.am pidgin/pixmaps/dialogs/16/Makefile.mingw pidgin/pixmaps/dialogs/16/scalable/Makefile.am pidgin/pixmaps/dialogs/64/Makefile.am pidgin/pixmaps/dialogs/64/Makefile.mingw pidgin/pixmaps/dialogs/64/scalable/Makefile.am pidgin/pixmaps/dialogs/Makefile.am pidgin/pixmaps/dialogs/Makefile.mingw pidgin/pixmaps/emblems/16/Makefile.am pidgin/pixmaps/emblems/16/Makefile.mingw pidgin/pixmaps/emblems/16/scalable/Makefile.am pidgin/pixmaps/emblems/Makefile.am pidgin/pixmaps/emblems/Makefile.mingw pidgin/pixmaps/emotes/Makefile.am pidgin/pixmaps/emotes/Makefile.mingw pidgin/pixmaps/emotes/default/24/scalable/Makefile.am pidgin/pixmaps/emotes/default/Makefile.am pidgin/pixmaps/emotes/default/Makefile.mingw pidgin/pixmaps/icons/16/Makefile.am pidgin/pixmaps/icons/16/Makefile.mingw pidgin/pixmaps/icons/16/pidgin.png pidgin/pixmaps/icons/16/scalable/Makefile.am pidgin/pixmaps/icons/16/scalable/pidgin.svg pidgin/pixmaps/icons/22/Makefile.am pidgin/pixmaps/icons/22/pidgin.png pidgin/pixmaps/icons/22/scalable/Makefile.am pidgin/pixmaps/icons/22/scalable/pidgin.svg pidgin/pixmaps/icons/24/Makefile.am pidgin/pixmaps/icons/24/Makefile.mingw pidgin/pixmaps/icons/24/pidgin.png pidgin/pixmaps/icons/24/scalable/Makefile.am pidgin/pixmaps/icons/24/scalable/pidgin.svg pidgin/pixmaps/icons/32/Makefile.am pidgin/pixmaps/icons/32/Makefile.mingw pidgin/pixmaps/icons/32/pidgin.png pidgin/pixmaps/icons/32/scalable/Makefile.am pidgin/pixmaps/icons/32/scalable/pidgin.svg pidgin/pixmaps/icons/48/Makefile.am pidgin/pixmaps/icons/48/Makefile.mingw pidgin/pixmaps/icons/48/pidgin.png pidgin/pixmaps/icons/48/scalable/Makefile.am pidgin/pixmaps/icons/48/scalable/pidgin.svg pidgin/pixmaps/icons/Makefile.am pidgin/pixmaps/icons/Makefile.mingw pidgin/pixmaps/protocols/16/Makefile.am pidgin/pixmaps/protocols/16/Makefile.mingw pidgin/pixmaps/protocols/16/scalable/Makefile.am pidgin/pixmaps/protocols/22/Makefile.am pidgin/pixmaps/protocols/22/Makefile.mingw pidgin/pixmaps/protocols/22/scalable/Makefile.am pidgin/pixmaps/protocols/48/Makefile.am pidgin/pixmaps/protocols/48/Makefile.mingw pidgin/pixmaps/protocols/48/scalable/Makefile.am pidgin/pixmaps/protocols/Makefile.am pidgin/pixmaps/protocols/Makefile.mingw pidgin/pixmaps/status/11/Makefile.am pidgin/pixmaps/status/11/Makefile.mingw pidgin/pixmaps/status/11/rtl/Makefile.am pidgin/pixmaps/status/11/rtl/Makefile.mingw pidgin/pixmaps/status/11/scalable/Makefile.am pidgin/pixmaps/status/16/Makefile.am pidgin/pixmaps/status/16/Makefile.mingw pidgin/pixmaps/status/16/rtl/Makefile.am pidgin/pixmaps/status/16/rtl/Makefile.mingw pidgin/pixmaps/status/16/scalable/Makefile.am pidgin/pixmaps/status/22/Makefile.am pidgin/pixmaps/status/22/Makefile.mingw pidgin/pixmaps/status/22/rtl/Makefile.am pidgin/pixmaps/status/22/rtl/Makefile.mingw pidgin/pixmaps/status/22/scalable/Makefile.am pidgin/pixmaps/status/32/Makefile.am pidgin/pixmaps/status/32/Makefile.mingw pidgin/pixmaps/status/32/rtl/Makefile.am pidgin/pixmaps/status/32/rtl/Makefile.mingw pidgin/pixmaps/status/32/scalable/Makefile.am pidgin/pixmaps/status/48/Makefile.am pidgin/pixmaps/status/48/Makefile.mingw pidgin/pixmaps/status/48/rtl/Makefile.am pidgin/pixmaps/status/48/rtl/Makefile.mingw pidgin/pixmaps/status/Makefile.am pidgin/pixmaps/status/Makefile.mingw pidgin/pixmaps/toolbar/16/Makefile.am pidgin/pixmaps/toolbar/16/Makefile.mingw pidgin/pixmaps/toolbar/16/scalable/Makefile.am pidgin/pixmaps/toolbar/22/Makefile.am pidgin/pixmaps/toolbar/22/Makefile.mingw pidgin/pixmaps/toolbar/22/scalable/Makefile.am pidgin/pixmaps/toolbar/Makefile.am pidgin/pixmaps/toolbar/Makefile.mingw pidgin/pixmaps/tray/16/Makefile.am pidgin/pixmaps/tray/16/Makefile.mingw pidgin/pixmaps/tray/16/scalable/Makefile.am pidgin/pixmaps/tray/22/Makefile.am pidgin/pixmaps/tray/22/Makefile.mingw pidgin/pixmaps/tray/22/scalable/Makefile.am pidgin/pixmaps/tray/32/Makefile.am pidgin/pixmaps/tray/32/Makefile.mingw pidgin/pixmaps/tray/48/Makefile.am pidgin/pixmaps/tray/48/Makefile.mingw pidgin/pixmaps/tray/Makefile.am pidgin/pixmaps/tray/Makefile.mingw pidgin/plugins/gevolution/Makefile.am po/sr@Latn.po share/Makefile.am share/Makefile.mingw
diffstat 73 files changed, 1775 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Fri Dec 28 17:14:52 2007 +0000
+++ b/configure.ac	Sat Dec 29 06:34:59 2007 +0000
@@ -673,6 +673,23 @@
 fi
 
 dnl #######################################################################
+dnl # Check for Farsight
+dnl #######################################################################
+AC_ARG_ENABLE(farsight,
+	[AC_HELP_STRING([--disable-vv], [compile without voice and video support])],
+	enable_farsight="$enableval", enable_farsight="yes")
+if test "x$enable_farsight" != "xno"; then
+	PKG_CHECK_MODULES(FARSIGHT, [farsight-0.1], [
+		AC_DEFINE(USE_FARSIGHT, 1, [Use Farsight for voice and video])
+		AC_SUBST(FARSIGHT_CFLAGS)
+		AC_SUBST(FARSIGHT_LIBS)
+	], [
+		AC_MSG_RESULT(no)
+		enable_farsight="no"
+	])
+fi
+
+dnl #######################################################################
 dnl # Check for Meanwhile headers (for Sametime)
 dnl #######################################################################
 PKG_CHECK_MODULES(MEANWHILE, [meanwhile >= 1.0.0 meanwhile < 2.0.0], [
@@ -2274,6 +2291,7 @@
 echo Protocols to link statically.. : $STATIC_PRPLS
 echo
 echo Build with GStreamer support.. : $enable_gst
+echo Build with voice and video.... : $enable_farsight
 echo Build with D-Bus support...... : $enable_dbus
 if test "x$enable_dbus" = "xyes" ; then
 	eval eval echo D-Bus services directory...... : $DBUS_SERVICES_DIR
--- a/finch/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -65,6 +65,7 @@
 	$(INTLLIBS) \
 	$(GLIB_LIBS) \
 	$(LIBXML_LIBS) \
+	$(FARSIGHT_LIBS) \
 	$(GNT_LIBS) \
 	$(GSTREAMER_LIBS) \
 	./libgnt/libgnt.la \
@@ -84,5 +85,6 @@
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(LIBXML_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GSTREAMER_CFLAGS) \
 	$(GNT_CFLAGS)
--- a/finch/gntaccount.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntaccount.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,6 +23,13 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#include <account.h>
+#include <accountopt.h>
+#include <connection.h>
+#include <notify.h>
+#include <plugin.h>
+#include <request.h>
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -37,13 +44,6 @@
 
 #include "finch.h"
 
-#include <account.h>
-#include <accountopt.h>
-#include <connection.h>
-#include <notify.h>
-#include <plugin.h>
-#include <request.h>
-
 #include "gntaccount.h"
 #include "gntblist.h"
 
--- a/finch/gntdebug.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntdebug.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,6 +23,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#include "util.h"
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -36,7 +38,6 @@
 #include "gntdebug.h"
 #include "finch.h"
 #include "notify.h"
-#include "util.h"
 
 #include <stdio.h>
 #include <string.h>
--- a/finch/gntft.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntft.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,19 +23,19 @@
  * 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 "debug.h"
+#include "notify.h"
+#include "ft.h"
+#include "prpl.h"
+#include "util.h"
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
 #include <gntcheckbox.h>
 #include <gntlabel.h>
 #include <gnttree.h>
-#include "internal.h"
-
-#include "debug.h"
-#include "notify.h"
-#include "ft.h"
-#include "prpl.h"
-#include "util.h"
 
 #include "gntft.h"
 #include "prefs.h"
--- a/finch/gntnotify.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntnotify.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,6 +23,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#include <util.h>
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -32,7 +34,6 @@
 
 #include "finch.h"
 
-#include <util.h>
 
 #include "gntnotify.h"
 
--- a/finch/gntplugin.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntplugin.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,6 +23,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#include "notify.h"
+#include "request.h"
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -34,8 +37,6 @@
 #include "finch.h"
 
 #include "debug.h"
-#include "notify.h"
-#include "request.h"
 
 #include "gntplugin.h"
 #include "gntrequest.h"
--- a/finch/gntpounce.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntpounce.c	Sat Dec 29 06:34:59 2007 +0000
@@ -24,6 +24,16 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  *
  */
+#include "internal.h"
+#include "account.h"
+#include "conversation.h"
+#include "debug.h"
+#include "notify.h"
+#include "prpl.h"
+#include "request.h"
+#include "server.h"
+#include "util.h"
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -35,18 +45,8 @@
 #include <gnttree.h>
 #include <gntutils.h>
 
-#include "internal.h"
 #include "finch.h"
 
-#include "account.h"
-#include "conversation.h"
-#include "debug.h"
-#include "notify.h"
-#include "prpl.h"
-#include "request.h"
-#include "server.h"
-#include "util.h"
-
 #include "gntpounce.h"
 
 
--- a/finch/gntrequest.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntrequest.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,6 +23,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+
+#include "util.h"
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -36,7 +39,6 @@
 
 #include "finch.h"
 #include "gntrequest.h"
-#include "util.h"
 
 typedef struct
 {
--- a/finch/gntstatus.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntstatus.c	Sat Dec 29 06:34:59 2007 +0000
@@ -23,6 +23,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+
+#include <notify.h>
+#include <request.h>
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -35,9 +39,6 @@
 
 #include "finch.h"
 
-#include <notify.h>
-#include <request.h>
-
 #include "gntstatus.h"
 
 static struct
--- a/finch/gntui.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/gntui.c	Sat Dec 29 06:34:59 2007 +0000
@@ -19,9 +19,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#include <prefs.h>
 #include "internal.h"
 
-#include "gntui.h"
 
 #include "gntaccount.h"
 #include "gntblist.h"
@@ -38,7 +38,7 @@
 #include "gntstatus.h"
 #include "gntsound.h"
 
-#include <prefs.h>
+#include "gntui.h"
 
 void gnt_ui_init()
 {
--- a/finch/libgnt/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/libgnt/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -89,6 +89,7 @@
 
 AM_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GNT_CFLAGS) \
 	$(DEBUG_CFLAGS) \
 	$(LIBXML_CFLAGS) \
--- a/finch/libgnt/wms/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/libgnt/wms/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -34,5 +34,6 @@
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(GNT_CFLAGS) \
-	$(PLUGIN_CFLAGS)
+	$(PLUGIN_CFLAGS) \
+	$(FARSIGHT_CFLAGS) 
 
--- a/finch/libgnt/wms/s.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/libgnt/wms/s.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2,6 +2,7 @@
 #include <sys/types.h>
 
 #include "internal.h"
+#include "blist.h"
 
 #include "gnt.h"
 #include "gntbox.h"
@@ -11,7 +12,6 @@
 #include "gntwindow.h"
 #include "gntlabel.h"
 
-#include "blist.h"
 
 #define TYPE_S				(s_get_gtype())
 
--- a/finch/plugins/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/finch/plugins/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -37,7 +37,8 @@
 	-I$(top_srcdir) \
 	-I$(top_srcdir)/finch \
 	-I$(top_srcdir)/finch/libgnt \
-	$(DEBUG_CFLAGS) \
+	$(DEBUG_CFLAGS) \	
+	$(FARSIGHT_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(GNT_CFLAGS) \
 	$(PLUGIN_CFLAGS)
--- a/libpurple/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -51,6 +51,8 @@
 	idle.c \
 	imgstore.c \
 	log.c \
+	media.c \
+	mediamanager.c \
 	mime.c \
 	nat-pmp.c \
 	network.c \
@@ -103,6 +105,8 @@
 	idle.h \
 	imgstore.h \
 	log.h \
+	media.h \
+	mediamanager.h \
 	mime.h \
 	nat-pmp.h \
 	network.h \
@@ -246,6 +250,7 @@
 	$(LIBXML_LIBS) \
 	$(LIBNM_LIBS) \
 	$(INTLLIBS) \
+	$(FARSIGHT_LIBS) \
 	-lm
 
 AM_CPPFLAGS = \
@@ -258,4 +263,5 @@
 	$(DEBUG_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(LIBXML_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(LIBNM_CFLAGS)
--- a/libpurple/example/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/example/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -7,7 +7,8 @@
 	$(DBUS_LIBS) \
 	$(INTLLIBS) \
 	$(GLIB_LIBS) \
-	$(LIBXML_LIBS) \
+	$(LIBXML_LIBS) \	
+	$(FARSIGHT_LIBS) \
 	$(top_builddir)/libpurple/libpurple.la
 
 AM_CPPFLAGS = \
@@ -22,4 +23,5 @@
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(LIBXML_CFLAGS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media.c	Sat Dec 29 06:34:59 2007 +0000
@@ -0,0 +1,457 @@
+/**
+ * @file media.c Media API
+ * @ingroup core
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+
+#include "internal.h"
+
+#include "connection.h"
+#include "media.h"
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+
+struct _PurpleMediaPrivate
+{
+	FarsightSession *farsight_session;
+
+	char *name;
+	PurpleConnection *connection;
+	GstElement *audio_src;
+	GstElement *audio_sink;
+	GstElement *video_src;
+	GstElement *video_sink;
+
+	FarsightStream *audio_stream;
+	FarsightStream *video_stream;
+};
+
+#define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate))
+
+static void purple_media_class_init (PurpleMediaClass *klass);
+static void purple_media_init (PurpleMedia *media);
+static void purple_media_finalize (GObject *object);
+static void purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static GObjectClass *parent_class = NULL;
+
+
+
+enum {
+	READY,
+	ACCEPTED,
+	HANGUP,
+	REJECT,
+	GOT_HANGUP,
+	LAST_SIGNAL
+};
+static guint purple_media_signals[LAST_SIGNAL] = {0};
+
+enum {
+	PROP_0,
+	PROP_FARSIGHT_SESSION,
+	PROP_NAME,
+	PROP_CONNECTION,
+	PROP_AUDIO_SRC,
+	PROP_AUDIO_SINK,
+	PROP_VIDEO_SRC,
+	PROP_VIDEO_SINK,
+	PROP_VIDEO_STREAM,
+	PROP_AUDIO_STREAM
+};
+
+GType
+purple_media_get_type()
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleMediaClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) purple_media_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleMedia),
+			0,
+			(GInstanceInitFunc) purple_media_init
+		};
+		type = g_type_register_static(G_TYPE_OBJECT, "PurpleMedia", &info, 0);
+	}
+	return type;
+}
+
+
+static void
+purple_media_class_init (PurpleMediaClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+	
+	gobject_class->finalize = purple_media_finalize;
+	gobject_class->set_property = purple_media_set_property;
+	gobject_class->get_property = purple_media_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_FARSIGHT_SESSION,
+			g_param_spec_object("farsight-session",
+			"Farsight session",
+			"The FarsightSession associated with this media.",
+			FARSIGHT_TYPE_SESSION,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_NAME,
+			g_param_spec_string("screenname",
+			"Screenname",
+			"The screenname of the remote user",
+			NULL,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_CONNECTION,
+			g_param_spec_pointer("connection",
+			"Connection",
+			"The PurpleConnection associated with this session",
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_AUDIO_SRC,
+			g_param_spec_object("audio-src",
+			"Audio source",
+			"The GstElement used to source audio",
+			GST_TYPE_ELEMENT,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_AUDIO_SINK,
+			g_param_spec_object("audio-sink",
+			"Audio sink",
+			"The GstElement used to sink audio",
+			GST_TYPE_ELEMENT,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_VIDEO_SRC,
+			g_param_spec_object("video-src",
+			"Video source",
+			"The GstElement used to source video",
+			GST_TYPE_ELEMENT,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_VIDEO_SINK,
+			g_param_spec_object("video-sink",
+			"Audio source",
+			"The GstElement used to sink video",
+			GST_TYPE_ELEMENT,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_VIDEO_STREAM,
+			g_param_spec_object("video-stream",
+			"Video stream",
+			"The FarsightStream used for video",
+			FARSIGHT_TYPE_STREAM,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_AUDIO_STREAM,
+			g_param_spec_object("audio-stream",
+			"Audio stream",
+			"The FarsightStream used for audio",
+			FARSIGHT_TYPE_STREAM,
+			G_PARAM_READWRITE));
+
+	purple_media_signals[READY] = g_signal_new("ready", G_TYPE_FROM_CLASS(klass),
+				 	 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE, 0);
+	purple_media_signals[ACCEPTED] = g_signal_new("accepted", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE, 0);
+	purple_media_signals[HANGUP] = g_signal_new("hangup", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE, 0);
+	purple_media_signals[REJECT] = g_signal_new("reject", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE, 0);
+	purple_media_signals[GOT_HANGUP] = g_signal_new("got-hangup", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE, 0);
+
+	g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
+}
+
+
+static void
+purple_media_init (PurpleMedia *media)
+{
+	media->priv = PURPLE_MEDIA_GET_PRIVATE(media);
+	memset(media->priv, 0, sizeof(media->priv));	
+}
+
+static void
+purple_media_finalize (GObject *media)
+{
+	parent_class->finalize(media);
+}
+
+static void
+purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	PurpleMedia *media;
+	g_return_if_fail(PURPLE_IS_MEDIA(object));
+	
+	media = PURPLE_MEDIA(object);
+
+	switch (prop_id) {
+		case PROP_FARSIGHT_SESSION:
+			if (media->priv->farsight_session)
+				g_object_unref(media->priv->farsight_session);
+			media->priv->farsight_session = g_value_get_object(value);
+			g_object_ref(media->priv->farsight_session);
+			break;
+		case PROP_NAME:
+			g_free(media->priv->name);
+			media->priv->name = g_value_dup_string(value);
+			break;
+		case PROP_CONNECTION:
+			media->priv->connection = g_value_get_pointer(value);
+			break;
+		case PROP_AUDIO_SRC:
+			if (media->priv->audio_src)
+				gst_object_unref(media->priv->audio_src);
+			media->priv->audio_src = g_value_get_object(value);
+			gst_object_ref(media->priv->audio_src);
+			break;
+		case PROP_AUDIO_SINK:
+			if (media->priv->audio_sink)
+				gst_object_unref(media->priv->audio_sink);
+			media->priv->audio_sink = g_value_get_object(value);
+			gst_object_ref(media->priv->audio_sink);
+			break;
+		case PROP_VIDEO_SRC:
+			if (media->priv->video_src)
+				gst_object_unref(media->priv->video_src);
+			media->priv->video_src = g_value_get_object(value);
+			gst_object_ref(media->priv->video_src);
+			break;
+		case PROP_VIDEO_SINK:
+			if (media->priv->video_sink)
+				gst_object_unref(media->priv->video_sink);
+			media->priv->video_sink = g_value_get_object(value);
+			gst_object_ref(media->priv->video_sink);
+			break;
+		case PROP_VIDEO_STREAM:
+			if (media->priv->video_stream)
+				g_object_unref(media->priv->video_stream);
+			media->priv->video_stream = g_value_get_object(value);
+			gst_object_ref(media->priv->video_stream);
+			break;
+		case PROP_AUDIO_STREAM:
+			if (media->priv->audio_stream)
+				g_object_unref(media->priv->audio_stream);
+			media->priv->audio_stream = g_value_get_object(value);
+			gst_object_ref(media->priv->audio_stream);
+			break;
+
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	PurpleMedia *media;
+	g_return_if_fail(PURPLE_IS_MEDIA(object));
+	
+	media = PURPLE_MEDIA(object);
+
+	switch (prop_id) {
+		case PROP_FARSIGHT_SESSION:
+			g_value_set_object(value, media->priv->farsight_session);
+			break;
+		case PROP_NAME:
+			g_value_set_string(value, media->priv->name);
+			break;
+		case PROP_CONNECTION:
+			g_value_set_pointer(value, media->priv->connection);
+			break;
+		case PROP_AUDIO_SRC:
+			g_value_set_object(value, media->priv->audio_src);
+			break;
+		case PROP_AUDIO_SINK:
+			g_value_set_object(value, media->priv->audio_sink);
+			break;
+		case PROP_VIDEO_SRC:
+			g_value_set_object(value, media->priv->video_src);
+			break;
+		case PROP_VIDEO_SINK:
+			g_value_set_object(value, media->priv->video_sink);
+			break;
+		case PROP_VIDEO_STREAM:
+			g_value_set_object(value, media->priv->video_stream);
+			break;
+		case PROP_AUDIO_STREAM:
+			g_value_set_object(value, media->priv->audio_stream);
+			break;
+
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
+			break;
+	}
+
+}
+
+void 
+purple_media_get_elements(PurpleMedia *media, GstElement **audio_src, GstElement **audio_sink,
+                                                  GstElement **video_src, GstElement **video_sink)
+{
+	 if (audio_src) 
+		g_object_get(G_OBJECT(media), "audio-src", *audio_src, NULL);
+	 if (audio_sink) 
+		g_object_get(G_OBJECT(media), "audio-sink", *audio_sink, NULL);
+	 if (video_src) 
+		g_object_get(G_OBJECT(media), "video-src", *video_src, NULL);
+	 if (video_sink) 
+		g_object_get(G_OBJECT(media), "video-sink", *video_sink, NULL);
+
+}
+
+void 
+purple_media_set_audio_src(PurpleMedia *media, GstElement *audio_src)
+{
+	g_object_set(G_OBJECT(media), "audio-src", audio_src, NULL);
+}
+
+void 
+purple_media_set_audio_sink(PurpleMedia *media, GstElement *audio_sink)
+{
+	g_object_set(G_OBJECT(media), "audio-sink", audio_sink, NULL);
+}
+
+void 
+purple_media_set_video_src(PurpleMedia *media, GstElement *video_src)
+{
+	g_object_set(G_OBJECT(media), "video-src", video_src, NULL);
+}
+
+void 
+purple_media_set_video_sink(PurpleMedia *media, GstElement *video_sink)
+{
+	g_object_set(G_OBJECT(media), "video-sink", video_sink, NULL);
+}
+
+GstElement *
+purple_media_get_audio_src(PurpleMedia *media)
+{
+	GstElement *ret;
+	g_object_get(G_OBJECT(media), "audio-src", &ret, NULL);
+	return ret;
+}
+
+GstElement *
+purple_media_get_audio_sink(PurpleMedia *media)
+{
+	GstElement *ret;
+	g_object_get(G_OBJECT(media), "audio-sink", &ret, NULL);
+	return ret;
+}
+
+GstElement *
+purple_media_get_video_src(PurpleMedia *media)
+{
+	GstElement *ret;
+	g_object_get(G_OBJECT(media), "video-src", &ret, NULL);
+	return ret;
+}
+
+GstElement *
+purple_media_get_video_sink(PurpleMedia *media)
+{
+	GstElement *ret;
+	g_object_get(G_OBJECT(media), "video-sink", &ret, NULL);
+	return ret;
+}
+
+GstElement *
+purple_media_get_audio_pipeline(PurpleMedia *media)
+{
+	FarsightStream *stream;
+	g_object_get(G_OBJECT(media), "audio-stream", &stream, NULL);
+printf("stream: %d\n\n\n", stream);
+GstElement *l = farsight_stream_get_pipeline(stream);
+printf("Element: %d\n", l);
+	return farsight_stream_get_pipeline(stream);
+}
+
+PurpleConnection *
+purple_media_get_connection(PurpleMedia *media)
+{
+	PurpleConnection *gc;
+	g_object_get(G_OBJECT(media), "connection", &gc, NULL);
+	return gc;
+}
+
+const char *
+purple_media_get_screenname(PurpleMedia *media)
+{
+	const char *ret;
+	g_object_get(G_OBJECT(media), "screenname", &ret, NULL);
+	return ret;
+}
+
+void
+purple_media_ready(PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[READY], 0);
+}
+
+void
+purple_media_accept(PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[ACCEPTED], 0);
+}
+
+void
+purple_media_hangup(PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[HANGUP], 0);
+}
+
+void
+purple_media_reject(PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[REJECT], 0);
+}
+
+void
+purple_media_got_hangup(PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[GOT_HANGUP], 0);
+}
+
+#endif  /* USE_FARSIGHT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media.h	Sat Dec 29 06:34:59 2007 +0000
@@ -0,0 +1,101 @@
+/**
+ * @file media.h Media API
+ * @ingroup core
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MEDIA_H_
+#define __MEDIA_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "connection.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA            (purple_media_get_type())
+#define PURPLE_MEDIA(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA, PurpleMedia))
+#define PURPLE_MEDIA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA, PurpleMediaClass))
+#define PURPLE_IS_MEDIA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA))
+#define PURPLE_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA))
+#define PURPLE_MEDIA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA, PurpleMediaClass))
+
+typedef struct _PurpleMedia PurpleMedia;
+typedef struct _PurpleMediaClass PurpleMediaClass;
+typedef struct _PurpleMediaPrivate PurpleMediaPrivate;
+
+typedef enum {
+	PURPLE_MEDIA_RECV_AUDIO = 1 << 0,
+	PURPLE_MEDIA_SEND_AUDIO = 1 << 1,
+	PURPLE_MEDIA_RECV_VIDEO = 1 << 2,
+	PURPLE_MEDIA_SEND_VIDEO = 1 << 3,
+} PurpleMediaStreamType;
+
+struct _PurpleMediaClass
+{
+	GObjectClass parent_class;
+};
+
+struct _PurpleMedia
+{
+	GObject parent;
+	PurpleMediaPrivate *priv;
+};
+
+GType purple_media_get_type();
+
+void purple_media_get_elements(PurpleMedia *media, GstElement **audio_src, GstElement **audio_sink,
+						  GstElement **video_src, GstElement **video_sink);
+
+void purple_media_set_audio_src(PurpleMedia *media, GstElement *video_src);
+void purple_media_set_audio_sink(PurpleMedia *media, GstElement *video_src);
+void purple_media_set_video_src(PurpleMedia *media, GstElement *video_src);
+void purple_media_set_video_sink(PurpleMedia *media, GstElement *video_src);
+
+GstElement *purple_media_get_audio_src(PurpleMedia *media);
+GstElement *purple_media_get_audio_sink(PurpleMedia *media);
+GstElement *purple_media_get_video_src(PurpleMedia *media);
+GstElement *purple_media_get_video_sink(PurpleMedia *media);
+
+GstElement *purple_media_get_audio_pipeline(PurpleMedia *media);
+
+PurpleConnection *purple_media_get_connection(PurpleMedia *media);
+const char *purple_media_get_screenname(PurpleMedia *media);
+void purple_media_ready(PurpleMedia *media);
+void purple_media_accept(PurpleMedia *media);
+void purple_media_reject(PurpleMedia *media);
+void purple_media_hangup(PurpleMedia *media);
+void purple_media_got_hangup(PurpleMedia *media);
+G_END_DECLS
+
+#endif  /* USE_FARSIGHT */
+
+
+#endif  /* __MEDIA_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/mediamanager.c	Sat Dec 29 06:34:59 2007 +0000
@@ -0,0 +1,146 @@
+/**
+ * @file mediamanager.c Media Manager API
+ * @ingroup core
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "internal.h"
+
+#include "connection.h"
+#include "mediamanager.h"
+#include "media.h"
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+
+struct _PurpleMediaManagerPrivate
+{
+	GList *medias;
+};
+
+#define PURPLE_MEDIA_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerPrivate))
+
+static void purple_media_manager_class_init (PurpleMediaManagerClass *klass);
+static void purple_media_manager_init (PurpleMediaManager *media);
+static void purple_media_manager_finalize (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+
+
+enum {
+	INIT_MEDIA,
+	LAST_SIGNAL
+};
+static guint purple_media_manager_signals[LAST_SIGNAL] = {0};
+
+enum {
+	PROP_0,
+	PROP_FARSIGHT_SESSION,
+	PROP_NAME,
+	PROP_CONNECTION,
+	PROP_MIC_ELEMENT,
+	PROP_SPEAKER_ELEMENT,
+};
+
+GType
+purple_media_manager_get_type()
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleMediaManagerClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) purple_media_manager_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleMediaManager),
+			0,
+			(GInstanceInitFunc) purple_media_manager_init
+		};
+		type = g_type_register_static(G_TYPE_OBJECT, "PurpleMediaManager", &info, 0);
+	}
+	return type;
+}
+
+
+static void
+purple_media_manager_class_init (PurpleMediaManagerClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+	
+	gobject_class->finalize = purple_media_manager_finalize;
+
+	purple_media_manager_signals[INIT_MEDIA] = g_signal_new ("init-media",
+		G_TYPE_FROM_CLASS (klass),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__OBJECT,
+		G_TYPE_NONE, 1, PURPLE_TYPE_MEDIA);
+	g_type_class_add_private(klass, sizeof(PurpleMediaManagerPrivate));
+}
+
+static void
+purple_media_manager_init (PurpleMediaManager *media)
+{
+	media->priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media);
+	media->priv->medias = NULL;
+}
+
+static void
+purple_media_manager_finalize (GObject *media)
+{
+	parent_class->finalize(media);
+}
+
+PurpleMediaManager *
+purple_media_manager_get()
+{
+	static PurpleMediaManager *manager = NULL;
+
+	if (manager == NULL)
+		manager = PURPLE_MEDIA_MANAGER(g_object_new(purple_media_manager_get_type(), NULL));
+	return manager;
+}
+
+PurpleMedia*
+purple_media_manager_create_media(PurpleMediaManager *manager, 
+				  PurpleConnection *gc,
+				  const char *screenname,
+				  FarsightStream *audio_stream,
+				  FarsightStream *video_stream)
+{
+	PurpleMedia *media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
+					  "screenname", screenname,
+					  "connection", gc, 
+					  "audio-stream", audio_stream,
+					  "video-stream", video_stream, NULL));
+	manager->priv->medias = g_list_append(manager->priv->medias, media);
+	g_signal_emit(manager, purple_media_manager_signals[INIT_MEDIA], 0, media);
+	return media;
+}
+
+#endif  /* USE_FARSIGHT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/mediamanager.h	Sat Dec 29 06:34:59 2007 +0000
@@ -0,0 +1,80 @@
+/**
+ * @file mediamanager.h Media Manager API
+ * @ingroup core
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MEDIA_MANAGER_H_
+#define __MEDIA_MANAGER_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "connection.h"
+#include "media.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA_MANAGER            (purple_media_manager_get_type())
+#define PURPLE_MEDIA_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManager))
+#define PURPLE_MEDIA_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerClass))
+#define PURPLE_IS_MEDIA_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_MANAGER))
+#define PURPLE_IS_MEDIA_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_MANAGER))
+#define PURPLE_MEDIA_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerClass))
+
+typedef struct _PurpleMediaManager PurpleMediaManager;
+typedef struct _PurpleMediaManagerClass PurpleMediaManagerClass;
+typedef struct _PurpleMediaManagerPrivate PurpleMediaManagerPrivate;
+
+struct _PurpleMediaManagerClass
+{
+	GObjectClass parent_class;
+};
+
+struct _PurpleMediaManager
+{
+	GObject parent;
+	PurpleMediaManagerPrivate *priv;
+};
+
+GType purple_media_manager_get_type(void);
+PurpleMediaManager *purple_media_manager_get(void);
+
+PurpleMedia *purple_media_manager_create_media(PurpleMediaManager *manager,
+					       PurpleConnection *gc,
+					       const char *screenname,
+					       FarsightStream *audio_stream,
+					       FarsightStream *video_stream);
+
+G_END_DECLS
+
+#endif  /* USE_FARSIGHT */
+
+
+#endif  /* __MEDIA_MANAGER_H_ */
--- a/libpurple/plugins/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/plugins/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -140,6 +140,7 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(PLUGIN_CFLAGS) \
 	$(DBUS_CFLAGS)
--- a/libpurple/plugins/perl/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/plugins/perl/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -5,7 +5,7 @@
 plugin_LTLIBRARIES = perl.la
 
 perl_la_LDFLAGS = -module -avoid-version
-perl_la_LIBADD = $(GLIB_LIBS) $(PERL_LIBS)
+perl_la_LIBADD = $(GLIB_LIBS) $(PERL_LIBS) $(FARSIGHT_LIBS)
 perl_la_SOURCES = \
 	perl.c \
 	perl-common.c \
@@ -159,4 +159,5 @@
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(PLUGIN_CFLAGS) \
-	$(PERL_CFLAGS)
+	$(PERL_CFLAGS) \
+	$(FARSIGHT_CFLAGS)
--- a/libpurple/plugins/ssl/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/plugins/ssl/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -31,6 +31,7 @@
 	-I$(top_builddir)/libpurple \
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(PLUGIN_CFLAGS)
 
 ssl_gnutls_la_CFLAGS = $(AM_CPPFLAGS) $(GNUTLS_CFLAGS)
--- a/libpurple/plugins/tcl/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/plugins/tcl/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -7,7 +7,7 @@
 tcl_la_SOURCES = tcl.c tcl_glib.c tcl_glib.h tcl_cmds.c tcl_signals.c tcl_purple.h \
                  tcl_ref.c tcl_cmd.c
 
-tcl_la_LIBADD = $(GLIB_LIBS) $(TCL_LIBS) $(TK_LIBS)
+tcl_la_LIBADD = $(GLIB_LIBS) $(TCL_LIBS) $(TK_LIBS) $(FARSIGHT_LIBS)
 
 EXTRA_DIST = signal-test.tcl Makefile.mingw
 
@@ -18,5 +18,6 @@
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(PLUGIN_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(TK_CFLAGS) \
 	$(TCL_CFLAGS)
--- a/libpurple/protocols/bonjour/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/bonjour/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -51,5 +51,12 @@
 	$(GLIB_CFLAGS) \
 	$(DEBUG_CFLAGS) \
 	$(LIBXML_CFLAGS) \
-	$(AVAHI_CFLAGS)
+	$(FARSIGHT_CFLAGS)
+if MDNS_AVAHI
+  AM_CPPFLAGS += $(AVAHI_CFLAGS)
+else
+if MDNS_HOWL
+    AM_CPPFLAGS += $(HOWL_CFLAGS)
+endif
+endif
 
--- a/libpurple/protocols/bonjour/bonjour.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Sat Dec 29 06:34:59 2007 +0000
@@ -487,7 +487,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+	sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/gg/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/gg/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -75,5 +75,6 @@
 	-I$(top_builddir)/libpurple \
 	$(INTGG_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
 
--- a/libpurple/protocols/gg/gg.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/gg/gg.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2152,7 +2152,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 /* }}} */
 
--- a/libpurple/protocols/irc/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/irc/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -32,4 +32,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/irc/irc.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/irc/irc.c	Sat Dec 29 06:34:59 2007 +0000
@@ -953,7 +953,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static void _init_plugin(PurplePlugin *plugin)
--- a/libpurple/protocols/jabber/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -82,4 +82,5 @@
 	-I$(top_builddir)/libpurple \
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(LIBXML_CFLAGS)
--- a/libpurple/protocols/jabber/disco.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/disco.c	Sat Dec 29 06:34:59 2007 +0000
@@ -142,6 +142,15 @@
 						SUPPORT_FEATURE(feat->namespace);
 				}
 			}
+		} else if (node && !strcmp(node, CAPS0115_NODE "#voice-v1")) {
+			SUPPORT_FEATURE("http://www.google.com/session");
+			SUPPORT_FEATURE("http://www.google.com/transport/p2p");
+			SUPPORT_FEATURE("http://www.google.com/transport/raw-udp");
+			SUPPORT_FEATURE("http://www.google.com/session/phone");
+			SUPPORT_FEATURE("http://www.xmpp.org/extensions/xep-0166.html");
+			SUPPORT_FEATURE("http://www.xmpp.org/extensions/xep-0180.html");
+			SUPPORT_FEATURE("http://www.xmpp.org/extensions/xep-0167.html");
+			SUPPORT_FEATURE("http://www.xmpp.org/extensions/xep-0177.html");
 		} else {
 			const char *ext = NULL;
 			unsigned pos;
--- a/libpurple/protocols/jabber/google.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/google.c	Sat Dec 29 06:34:59 2007 +0000
@@ -18,8 +18,11 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include <farsight/farsight-transport.h>
+
 #include "internal.h"
 #include "debug.h"
+#include "mediamanager.h"
 #include "util.h"
 #include "privacy.h"
 
@@ -29,6 +32,366 @@
 #include "presence.h"
 #include "iq.h"
 
+typedef struct {
+	char *id;
+	char *initiator;
+} GoogleSessionId;
+
+typedef enum {
+	UNINIT,
+	SENT_INITIATE,
+	RECEIVED_INITIATE,
+	IN_PRORESS,
+	TERMINATED
+} GoogleSessionState;
+
+typedef struct {
+	GoogleSessionId id;
+	GoogleSessionState state;
+	PurpleMedia *media;
+	FarsightStream *stream;
+	JabberStream *js; 
+	char *remote_jid;
+} GoogleSession;
+
+GHashTable *sessions = NULL;
+
+static guint 
+google_session_id_hash(gconstpointer key) 
+{
+	GoogleSessionId *id = (GoogleSessionId*)key;
+	
+	guint id_hash = g_str_hash(id->id);
+	guint init_hash = g_str_hash(id->initiator);
+
+	return 23 * id_hash + init_hash;
+}
+
+static gboolean 
+google_session_id_equal(gconstpointer a, gconstpointer b)
+{
+	GoogleSessionId *c = (GoogleSessionId*)a;
+	GoogleSessionId *d = (GoogleSessionId*)b;
+	
+	return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator);
+}
+
+static void
+google_session_destroy(GoogleSession *session)
+{
+	g_hash_table_remove(sessions, &(session->id));
+	g_free(session->id.id);
+	g_free(session->id.initiator);
+	g_free(session->remote_jid);
+	g_object_unref(session->media);
+	g_object_unref(session->stream);
+	g_free(session);
+}
+
+static xmlnode *
+google_session_create_xmlnode(GoogleSession *session, const char *type)
+{
+	xmlnode *node = xmlnode_new("session");
+	xmlnode_set_namespace(node, "http://www.google.com/session");
+	xmlnode_set_attrib(node, "id", session->id.id);
+	xmlnode_set_attrib(node, "initiator", session->id.initiator);
+	xmlnode_set_attrib(node, "type", type);
+	return node;
+}
+
+static void
+google_session_send_accept(GoogleSession *session)
+{
+	xmlnode *sess, *desc, *payload;
+	GList *codecs = farsight_stream_get_codec_intersection(session->stream);
+	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+	sess = google_session_create_xmlnode(session, "accept");
+	xmlnode_insert_child(iq->node, sess);
+	desc = xmlnode_new_child(sess, "description");
+	xmlnode_set_namespace(desc, "http://www.google.com/session/phone");
+
+	for (;codecs; codecs = codecs->next) {
+		FarsightCodec *codec = (FarsightCodec*)codecs->data;
+		char id[8], clockrate[10];
+		payload = xmlnode_new_child(desc, "payload-type");
+		g_snprintf(id, sizeof(id), "%d", codec->id);
+		g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate);
+		xmlnode_set_attrib(payload, "name", codec->encoding_name);
+		xmlnode_set_attrib(payload, "id", id);
+		xmlnode_set_attrib(payload, "clockrate", clockrate);
+	}
+
+	jabber_iq_send(iq);
+	farsight_stream_start(session->stream);
+}
+
+static void
+google_session_send_terminate(GoogleSession *session)
+{
+	xmlnode *sess;
+	GList *codecs = farsight_stream_get_codec_intersection(session->stream);
+	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+	sess = google_session_create_xmlnode(session, "terminate");
+	xmlnode_insert_child(iq->node, sess);
+	
+	jabber_iq_send(iq);
+	farsight_stream_stop(session->stream);
+	google_session_destroy(session);
+}
+
+static void
+google_session_send_reject(GoogleSession *session)
+{
+	xmlnode *sess;
+	GList *codecs = farsight_stream_get_codec_intersection(session->stream);
+	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+	sess = google_session_create_xmlnode(session, "reject");
+	xmlnode_insert_child(iq->node, sess);
+	
+	jabber_iq_send(iq);
+	farsight_stream_stop(session->stream);
+	google_session_destroy(session);
+}
+
+
+static void 
+google_session_candidates_prepared (FarsightStream *stream, gchar *candidate_id, GoogleSession *session)
+{
+	JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+	GList *candidates = farsight_stream_get_native_candidate_list(stream);
+	FarsightTransportInfo *transport;
+	xmlnode *sess;
+	xmlnode *candidate;
+	sess = google_session_create_xmlnode(session, "candidates");
+	xmlnode_insert_child(iq->node, sess);
+	xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+	
+	for (;candidates;candidates = candidates->next) {
+		transport = (FarsightTransportInfo*)(candidates->data);
+		char port[8];
+		char pref[8];
+
+		if (!strcmp(transport->ip, "127.0.0.1"))
+			continue;
+	
+		candidate = xmlnode_new("candidate");
+
+		g_snprintf(port, sizeof(port), "%d", transport->port);
+		g_snprintf(pref, sizeof(pref), "%f", transport->preference);
+
+		xmlnode_set_attrib(candidate, "address", transport->ip);
+		xmlnode_set_attrib(candidate, "port", port);
+		xmlnode_set_attrib(candidate, "name", "rtp");
+		xmlnode_set_attrib(candidate, "username", transport->username);
+		xmlnode_set_attrib(candidate, "password", transport->password);
+		xmlnode_set_attrib(candidate, "preference", pref);
+		xmlnode_set_attrib(candidate, "protocol", transport->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? "udp" : "tcp");
+		xmlnode_set_attrib(candidate, "type", transport->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? "local" :
+						      transport->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? "stun" :
+					       	      transport->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? "relay" : NULL);
+		xmlnode_set_attrib(candidate, "generation", "0");
+		xmlnode_set_attrib(candidate, "network", "0");
+		xmlnode_insert_child(sess, candidate);
+		
+	}
+	jabber_iq_send(iq);
+}
+
+static void
+google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+{
+	PurpleMedia *media;
+	JabberIq *result;
+	FarsightSession *fs;
+	GList *codecs = NULL;
+	xmlnode *desc_element, *codec_element;
+	FarsightCodec *codec;
+	const char *id, *encoding_name,  *clock_rate;
+	int res;
+	
+
+	if (session->state != UNINIT) {
+		purple_debug_error("jabber", "Received initiate for active session.\n");
+		return FALSE;
+	}
+
+	fs = farsight_session_factory_make("rtp");
+	if (!fs) {
+		purple_debug_error("jabber", "Farsight's rtp plugin not installed");
+		return FALSE;
+	}
+	session->stream = farsight_session_create_stream(fs, FARSIGHT_MEDIA_TYPE_AUDIO, FARSIGHT_STREAM_DIRECTION_BOTH);
+
+	g_object_set(G_OBJECT(session->stream), "transmitter", "libjingle", NULL);
+	
+	desc_element = xmlnode_get_child(sess, "description");
+	
+	for (codec_element = xmlnode_get_child(desc_element, "payload-type"); 
+	     codec_element; 
+	     codec_element = xmlnode_get_next_twin(codec_element)) {
+		encoding_name = xmlnode_get_attrib(codec_element, "name");
+		id = xmlnode_get_attrib(codec_element, "id");
+		clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
+
+		codec = g_new0(FarsightCodec, 1);
+		farsight_codec_init(codec, atoi(id), encoding_name, FARSIGHT_MEDIA_TYPE_AUDIO, clock_rate ? atoi(clock_rate) : 0);
+		codecs = g_list_append(codecs, codec);
+	}
+
+	session->media = media = purple_media_manager_create_media(purple_media_manager_get(), js->gc, session->remote_jid, session->stream, NULL);
+
+	g_signal_connect_swapped(G_OBJECT(media), "accepted", G_CALLBACK(google_session_send_accept), session);
+	g_signal_connect_swapped(G_OBJECT(media), "reject", G_CALLBACK(google_session_send_reject), session);
+	g_signal_connect_swapped(G_OBJECT(media), "hangup", G_CALLBACK(google_session_send_terminate), session);
+
+	
+	GstElement *e = purple_media_get_audio_src(media);
+	farsight_stream_set_source(session->stream, e);	
+	
+	e = purple_media_get_audio_sink(media);
+	farsight_stream_set_sink(session->stream, e);
+	
+	farsight_stream_prepare_transports(session->stream);
+	res = farsight_stream_set_remote_codecs(session->stream, codecs);
+	
+	purple_media_ready(media);
+
+	farsight_codec_list_destroy(codecs);
+	g_signal_connect(G_OBJECT(session->stream), "new-native-candidate", G_CALLBACK(google_session_candidates_prepared), session);
+	result = jabber_iq_new(js, JABBER_IQ_RESULT);
+	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+	xmlnode_set_attrib(result->node, "to", session->remote_jid);
+	jabber_iq_send(result);
+}
+
+static void 
+google_session_handle_candidates(JabberStream  *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+{
+	JabberIq *result;
+	GList *list = NULL;
+	xmlnode *cand;
+	static int name = 0;
+	char n[4];	
+	
+	for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) {
+		FarsightTransportInfo *info = g_new0(FarsightTransportInfo, 1);
+		g_snprintf(n, sizeof(n), "S%d", name++);
+		info->ip = xmlnode_get_attrib(cand, "address");
+		info->port = atoi(xmlnode_get_attrib(cand, "port"));
+		info->proto = !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ? FARSIGHT_NETWORK_PROTOCOL_UDP : FARSIGHT_NETWORK_PROTOCOL_TCP;
+		info->preference = atof(xmlnode_get_attrib(cand, "preference"));
+		info->type = !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? FARSIGHT_CANDIDATE_TYPE_LOCAL :
+			     !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ? FARSIGHT_CANDIDATE_TYPE_DERIVED :
+			     !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ? FARSIGHT_CANDIDATE_TYPE_RELAY : FARSIGHT_CANDIDATE_TYPE_LOCAL;
+		info->candidate_id = n;
+		info->username = xmlnode_get_attrib(cand, "username");
+		info->password = xmlnode_get_attrib(cand, "password");
+		list = g_list_append(list, info);
+	}
+
+	farsight_stream_add_remote_candidate(session->stream, list);
+	g_list_foreach(list, g_free, NULL);
+	g_list_free(list);
+
+	result = jabber_iq_new(js, JABBER_IQ_RESULT);
+	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+	xmlnode_set_attrib(result->node, "to", session->remote_jid);
+	jabber_iq_send(result);
+}
+
+static void
+google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+{
+	farsight_stream_stop(session->stream);
+	purple_media_got_hangup(session->media);
+	
+	google_session_destroy(session);
+}
+
+static void
+google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+{
+	farsight_stream_stop(session->stream);
+	purple_media_got_hangup(session->media);
+
+	google_session_destroy(session);
+}
+
+static void
+google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *packet)
+{
+	xmlnode *sess = xmlnode_get_child(packet, "session");	
+	const char *type = xmlnode_get_attrib(sess, "type");
+
+	if (!strcmp(type, "initiate")) {
+		google_session_handle_initiate(js, session, packet, sess);
+	} else if (!strcmp(type, "accept")) {
+	} else if (!strcmp(type, "reject")) {
+		google_session_handle_reject(js, session, packet, sess);
+	} else if (!strcmp(type, "terminate")) {
+		google_session_handle_terminate(js, session, packet, sess);
+	} else if (!strcmp(type, "candidates")) {
+		google_session_handle_candidates(js, session, packet, sess);
+	}
+}
+
+void
+jabber_google_session_parse(JabberStream *js, xmlnode *packet)
+{
+	GoogleSession *session;
+	GoogleSessionId id;
+	JabberIq *result;
+
+	xmlnode *session_node;
+	xmlnode *desc_node;
+
+	if (strcmp(xmlnode_get_attrib(packet, "type"), "set"))
+		return;
+
+	session_node = xmlnode_get_child(packet, "session");
+	if (!session_node)
+		return;
+
+	id.id = xmlnode_get_attrib(session_node, "id");
+	if (!id.id)
+		return;
+
+	id.initiator = xmlnode_get_attrib(session_node, "initiator");
+	if (!id.initiator)
+		return;
+
+	if (sessions == NULL)
+		sessions = g_hash_table_new(google_session_id_hash, google_session_id_equal);
+	session = (GoogleSession*)g_hash_table_lookup(sessions, &id);
+
+	if (session) {
+		google_session_parse_iq(js, session, packet);
+		return;
+	}
+
+	/* If the session doesn't exist, this has to be an initiate message */
+	if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate"))
+		return;
+	desc_node = xmlnode_get_child(session_node, "description");
+	if (!desc_node)
+		return;
+	session = g_new0(GoogleSession, 1);
+	session->id.id = g_strdup(id.id);
+	session->id.initiator = g_strdup(id.initiator);
+	session->state = UNINIT;
+	session->js = js;
+	session->remote_jid = g_strdup(session->id.initiator);
+	g_hash_table_insert(sessions, &(session->id), session);
+
+	google_session_parse_iq(js, session, packet);
+}
+
 static void
 jabber_gmail_parse(JabberStream *js, xmlnode *packet, gpointer nul)
 {
--- a/libpurple/protocols/jabber/google.h	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/google.h	Sat Dec 29 06:34:59 2007 +0000
@@ -45,6 +45,7 @@
 
 char *jabber_google_format_to_html(const char *text);
 
+void jabber_google_session_parse(JabberStream *js, xmlnode *node);
 
 
 #endif   /* _PURPLE_GOOGLE_H_ */
--- a/libpurple/protocols/jabber/iq.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/iq.c	Sat Dec 29 06:34:59 2007 +0000
@@ -337,6 +337,11 @@
 			return;
 		}
 	}
+	
+	if (xmlnode_get_child_with_namespace(packet, "session", "http://www.google.com/session")) {
+		jabber_google_session_parse(js, packet);
+		return;
+	}
 
 	if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) {
 		jabber_si_parse(js, packet);
--- a/libpurple/protocols/jabber/jabber.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2320,6 +2320,11 @@
 	return TRUE;
 }
 
+PurpleMedia *jabber_media_initiate(PurpleConnection *gc, const char *who, PurpleMediaStreamType type)
+{
+	return NULL;
+}
+
 void jabber_register_commands(void)
 {
 	purple_cmd_register("config", "", PURPLE_CMD_P_PRPL,
--- a/libpurple/protocols/jabber/jabber.h	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Sat Dec 29 06:34:59 2007 +0000
@@ -259,5 +259,5 @@
 GList *jabber_actions(PurplePlugin *plugin, gpointer context);
 void jabber_register_commands(void);
 void jabber_init_plugin(PurplePlugin *plugin);
-
+PurpleMedia *jabber_media_initiate(PurpleConnection *gc, const char *who, PurpleMediaStreamType type);
 #endif /* _PURPLE_JABBER_H_ */
--- a/libpurple/protocols/jabber/libxmpp.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Sat Dec 29 06:34:59 2007 +0000
@@ -118,6 +118,10 @@
 
 	/* padding */
 	NULL
+	NULL,
+	NULL,
+	jabber_media_initiate,          /* initiate_media */
+	sizeof(PurplePluginProtocolInfo)
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
--- a/libpurple/protocols/jabber/presence.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Sat Dec 29 06:34:59 2007 +0000
@@ -265,6 +265,10 @@
 	xmlnode_set_namespace(c, "http://jabber.org/protocol/caps");
 	xmlnode_set_attrib(c, "node", CAPS0115_NODE);
 	xmlnode_set_attrib(c, "ver", VERSION);
+#ifdef USE_FARSIGHT
+	/* Make sure this is 'voice-v1', or you won't be able to talk to Google Talk */
+	xmlnode_set_attrib(c, "ext", "voice-v1");
+#endif
 	
 	if(js != NULL) {
 		/* add the extensions */
--- a/libpurple/protocols/msn/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/msn/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -95,4 +95,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
-	$(DEBUG_CFLAGS)
+	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS)
--- a/libpurple/protocols/msn/msn.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2286,7 +2286,7 @@
 	msn_attention_types,                    /* attention_types */
 
 	/* padding */
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/myspace/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/myspace/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -40,4 +40,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/myspace/myspace.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2990,7 +2990,7 @@
 	NULL,                  /* unregister_user */
 	msim_send_attention,   /* send_attention */
 	msim_attention_types,  /* attention_types */
-	NULL                /* _purple_reserved4 */
+        sizeof(PurplePluginProtocolInfo)
 };
 
 
--- a/libpurple/protocols/novell/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/novell/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -54,4 +54,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GLIB_CFLAGS)
--- a/libpurple/protocols/novell/novell.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/novell/novell.c	Sat Dec 29 06:34:59 2007 +0000
@@ -3516,7 +3516,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/protocols/null/nullprpl.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/null/nullprpl.c	Sat Dec 29 06:34:59 2007 +0000
@@ -1125,7 +1125,7 @@
   NULL,                                /* padding... */
   NULL,
   NULL,
-  NULL,
+  sizeof(PurpleProtocolPluginInfo)
 };
 
 static void nullprpl_init(PurplePlugin *plugin)
--- a/libpurple/protocols/oscar/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/oscar/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -76,4 +76,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/oscar/libaim.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/oscar/libaim.c	Sat Dec 29 06:34:59 2007 +0000
@@ -97,7 +97,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/oscar/libicq.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/oscar/libicq.c	Sat Dec 29 06:34:59 2007 +0000
@@ -97,7 +97,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/qq/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/qq/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -94,4 +94,5 @@
 	-I$(top_builddir)/libpurple \
 	-DQQ_BUDDY_ICON_DIR=\"$(datadir)/pixmaps/purple/buddy_icons/qq\" \
 	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GLIB_CFLAGS)
--- a/libpurple/protocols/qq/qq.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/qq/qq.c	Sat Dec 29 06:34:59 2007 +0000
@@ -742,7 +742,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 
--- a/libpurple/protocols/sametime/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/sametime/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -32,7 +32,7 @@
 
 
 AM_CFLAGS = \
-	$(GLIB_CFLAGS) $(MEANWHILE_CFLAGS) \
+	$(GLIB_CFLAGS) $(MEANWHILE_CFLAGS) $(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS) \
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple
--- a/libpurple/protocols/sametime/sametime.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Sat Dec 29 06:34:59 2007 +0000
@@ -5178,7 +5178,8 @@
   .new_xfer                  = mw_prpl_new_xfer,
   .offline_message           = NULL,
   .whiteboard_prpl_ops       = NULL,
-  .send_raw                  = NULL
+  .send_raw                  = NULL,
+  .struct_size               = sizeof(PurplePluginProtocolInfo)
 };
 
 
--- a/libpurple/protocols/silc/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/silc/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -25,7 +25,7 @@
 noinst_LIBRARIES =
 
 libsilcpurple_la_SOURCES = $(SILCSOURCES)
-libsilcpurple_la_LIBADD  = $(GLIB_LIBS) $(SILC_LIBS)
+libsilcpurple_la_LIBADD  = $(GLIB_LIBS) $(SILC_LIBS) $(FARSIGHT_LIBS)
 
 endif
 
@@ -33,4 +33,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/silc/silc.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/silc/silc.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2035,7 +2035,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static void
--- a/libpurple/protocols/silc10/silc.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/silc10/silc.c	Sat Dec 29 06:34:59 2007 +0000
@@ -1835,7 +1835,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurpleProtocolPluginInfo)
 };
 
 static void
--- a/libpurple/protocols/simple/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/simple/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -33,4 +33,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/simple/simple.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/simple/simple.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2036,7 +2036,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 
--- a/libpurple/protocols/yahoo/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/yahoo/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -53,4 +53,5 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/yahoo/yahoo.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Sat Dec 29 06:34:59 2007 +0000
@@ -4350,7 +4350,7 @@
 	yahoo_attention_types,
 
 	/* padding */
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/zephyr/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/zephyr/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -106,5 +106,6 @@
 	-I$(top_srcdir)/libpurple/protocols \
 	-DCONFDIR=\"$(confdir)\" \
 	$(GLIB_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(KRB4_CFLAGS) \
 	$(DEBUG_CFLAGS)
--- a/libpurple/protocols/zephyr/zephyr.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Sat Dec 29 06:34:59 2007 +0000
@@ -2926,7 +2926,7 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+        sizeof(PurplePluginProtocolInfo)
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/prpl.h	Fri Dec 28 17:14:52 2007 +0000
+++ b/libpurple/prpl.h	Sat Dec 29 06:34:59 2007 +0000
@@ -64,6 +64,7 @@
 #include "conversation.h"
 #include "ft.h"
 #include "imgstore.h"
+#include "media.h"
 #include "notify.h"
 #include "proxy.h"
 #include "plugin.h"
@@ -399,8 +400,20 @@
 	GList *(*get_attention_types)(PurpleAccount *acct);
 
 	void (*_purple_reserved4)(void);
+	GList *(*attention_types)(PurpleAccount *acct);
+#ifdef USE_FARSIGHT
+	PurpleMedia  *(*initiate_media)(PurpleConnection *conn, const char *who, PurpleMediaStreamType type);
+#else
+	void (*initiate_media)(void)
+#endif
+	/* Make sure you do not try to dereference anything past struct_size! */
+	int struct_size;
 };
 
+#define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
+	((G_STRUCT_OFFSET(PurpleProtocolPluginInfo, member) < prpl->struct_size) && \
+	 prpl->member != NULL)
+
 #define PURPLE_IS_PROTOCOL_PLUGIN(plugin) \
 	((plugin)->info->type == PURPLE_PLUGIN_PROTOCOL)
 
--- a/pidgin/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -99,6 +99,7 @@
 	gtkimhtmltoolbar.c \
 	gtklog.c \
 	gtkmain.c \
+	gtkmedia.c \
 	gtkmenutray.c \
 	gtknotify.c \
 	gtkplugin.c \
@@ -150,6 +151,7 @@
 	gtkimhtml.h \
 	gtkimhtmltoolbar.h \
 	gtklog.h \
+	gtkmedia.c \
 	gtkmenutray.h \
 	gtknickcolors.h \
 	gtknotify.h \
@@ -194,6 +196,7 @@
 	$(STARTUP_NOTIFICATION_LIBS) \
 	$(LIBXML_LIBS) \
 	$(GTK_LIBS) \
+	$(FARSIGHT_LIBS) \
 	$(top_builddir)/libpurple/libpurple.la
 
 if USE_INTERNAL_LIBGADU
@@ -218,5 +221,6 @@
 	$(GTKSPELL_CFLAGS) \
 	$(STARTUP_NOTIFICATION_CFLAGS) \
 	$(LIBXML_CFLAGS) \
-	$(INTGG_CFLAGS)
+	$(INTGG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) 
 endif  # ENABLE_GTK
--- a/pidgin/gtkconv.c	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/gtkconv.c	Sat Dec 29 06:34:59 2007 +0000
@@ -46,6 +46,7 @@
 #include "idle.h"
 #include "imgstore.h"
 #include "log.h"
+#include "mediamanager.h"
 #include "notify.h"
 #include "prpl.h"
 #include "request.h"
@@ -60,6 +61,7 @@
 #include "gtkimhtml.h"
 #include "gtkimhtmltoolbar.h"
 #include "gtklog.h"
+#include "gtkmedia.h"
 #include "gtkmenutray.h"
 #include "gtkpounce.h"
 #include "gtkprefs.h"
@@ -4598,7 +4600,8 @@
 	GtkPolicyType imhtml_sw_hscroll;
 
 	/* Setup the top part of the pane */
-	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtkconv->topvbox = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_paned_pack1(GTK_PANED(paned), vbox, TRUE, TRUE);
 	gtk_widget_show(vbox);
 
 	/* Setup the info pane */
@@ -7549,6 +7552,58 @@
 	return TRUE;
 }
 
+static void
+pidgin_gtkmedia_message_cb(PidginMedia *media, const char *msg, PurpleConversation *conv)
+{
+	purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
+}
+
+static void
+pidgin_conv_new_media_cb(PurpleMediaManager *manager, PurpleMedia *media, gpointer nul)
+{	
+	GstElement *sendbin, *src, *sendlevel;
+	GstElement *recvbin, *sink, *recvlevel;
+	GstPad *pad, *ghost;
+
+	GtkWidget *gtkmedia;
+	PurpleConversation *conv;
+	PidginConversation *gtkconv;
+
+	sendbin = gst_bin_new("sendbin");
+	src = gst_element_factory_make("alsasrc", "asrc");
+	sendlevel = gst_element_factory_make("level", "sendlevel");
+	gst_bin_add_many(GST_BIN(sendbin), src, sendlevel, NULL);
+	gst_element_link(src, sendlevel); //, gst_caps_new_simple("audio/x-raw-int", "rate", G_TYPE_INT, 8000, NULL));
+	pad = gst_element_get_pad(sendlevel, "src");
+	ghost = gst_ghost_pad_new("ghostsrc", pad);
+	gst_element_add_pad(sendbin, ghost);
+	g_object_set(G_OBJECT(sendlevel), "message", TRUE, NULL);
+
+	recvbin = gst_bin_new("pidginrecvbin");
+	sink = gst_element_factory_make("alsasink", "asink");
+	g_object_set(G_OBJECT(sink), "sync", FALSE, NULL);
+	recvlevel = gst_element_factory_make("level", "recvlevel");
+	gst_bin_add_many(GST_BIN(recvbin), sink, recvlevel, NULL);
+	gst_element_link(recvlevel, sink);
+	pad = gst_element_get_pad(recvlevel, "sink");
+	ghost = gst_ghost_pad_new("ghostsink", pad);
+	gst_element_add_pad(recvbin, ghost);
+	g_object_set(G_OBJECT(recvlevel), "message", TRUE, NULL);
+
+	purple_media_set_audio_src(media, sendbin);
+	purple_media_set_audio_sink(media, recvbin);
+
+	gtkmedia = pidgin_media_new(media, sendlevel, recvlevel);
+	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, 
+				       purple_connection_get_account(purple_media_get_connection(media)), 
+				       purple_media_get_screenname(media));
+	gtkconv = PIDGIN_CONVERSATION(conv);
+	gtk_box_pack_start(GTK_BOX(gtkconv->topvbox), gtkmedia, FALSE, FALSE, 0);
+	gtk_widget_show(gtkmedia);
+	g_signal_connect_swapped(G_OBJECT(media), "got-hangup", G_CALLBACK(gtk_widget_destroy), gtkmedia);
+	g_signal_connect(G_OBJECT(gtkmedia), "message", G_CALLBACK(pidgin_gtkmedia_message_cb), conv);
+}
+
 void *
 pidgin_conversations_get_handle(void)
 {
@@ -7645,6 +7700,8 @@
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
                                 hide_new_pref_cb, NULL);
 
+	g_signal_connect(G_OBJECT(purple_media_manager_get()), "init-media",
+			 G_CALLBACK(pidgin_conv_new_media_cb), NULL);
 
 
 	/**********************************************************************
--- a/pidgin/gtkconv.h	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/gtkconv.h	Sat Dec 29 06:34:59 2007 +0000
@@ -169,6 +169,7 @@
 	GtkWidget *infopane;
 	GtkListStore *infopane_model;
 	GtkTreeIter infopane_iter;
+	GtkWidget *topvbox;
 
 	/* Used when attaching a PidginConversation to a PurpleConversation
 	 * with message history */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkmedia.c	Sat Dec 29 06:34:59 2007 +0000
@@ -0,0 +1,321 @@
+/**
+ * @file media.c Account API
+ * @ingroup core
+ *
+ * Pidgin
+ *
+ * Pidgin 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include "internal.h"
+#include "connection.h"
+#include "media.h"
+
+#include "gtkmedia.h"
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+
+struct _PidginMediaPrivate
+{
+	PurpleMedia *media;
+	GstElement *send_level;
+	GstElement *recv_level;
+
+	GtkWidget *accept;
+	GtkWidget *reject;
+	GtkWidget *hangup;
+	
+	GtkWidget *send_progress;
+	GtkWidget *recv_progress;
+};
+
+#define PIDGIN_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PIDGIN_TYPE_MEDIA, PidginMediaPrivate))
+
+static void pidgin_media_class_init (PidginMediaClass *klass);
+static void pidgin_media_init (PidginMedia *media);
+static void pidgin_media_finalize (GObject *object);
+static void pidgin_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void pidgin_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static GtkHBoxClass *parent_class = NULL;
+
+
+
+enum {
+	MESSAGE,
+	LAST_SIGNAL
+};
+static guint pidgin_media_signals[LAST_SIGNAL] = {0};
+
+enum {
+	PROP_0,
+	PROP_MEDIA,
+	PROP_SEND_LEVEL,
+	PROP_RECV_LEVEL
+};
+
+GType
+pidgin_media_get_type()
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PidginMediaClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) pidgin_media_class_init,
+			NULL,
+			NULL,
+			sizeof(PidginMedia),
+			0,
+			(GInstanceInitFunc) pidgin_media_init
+		};
+		type = g_type_register_static(GTK_TYPE_HBOX, "PidginMedia", &info, 0);
+	}
+	return type;
+}
+
+
+static void
+pidgin_media_class_init (PidginMediaClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	GtkContainerClass *container_class = (GtkContainerClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+	
+	gobject_class->finalize = pidgin_media_finalize;
+	gobject_class->set_property = pidgin_media_set_property;
+	gobject_class->get_property = pidgin_media_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_MEDIA,
+			g_param_spec_object("media",
+			"PurpleMedia",
+			"The PurpleMedia associated with this media.",
+			PURPLE_TYPE_MEDIA,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+	g_object_class_install_property(gobject_class, PROP_SEND_LEVEL,
+			g_param_spec_object("send-level",
+			"Send level",
+			"The GstElement of this media's send 'level'",
+			GST_TYPE_ELEMENT,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));	
+	g_object_class_install_property(gobject_class, PROP_RECV_LEVEL,
+			g_param_spec_object("recv-level",
+			"Receive level",
+			"The GstElement of this media's recv 'level'",
+			GST_TYPE_ELEMENT,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	pidgin_media_signals[MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass),
+					G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					g_cclosure_marshal_VOID__STRING,
+					G_TYPE_NONE, 1, G_TYPE_STRING);
+
+	g_type_class_add_private(klass, sizeof(PidginMediaPrivate));
+}
+
+
+static void
+pidgin_media_init (PidginMedia *media)
+{
+	media->priv = PIDGIN_MEDIA_GET_PRIVATE(media);
+	media->priv->hangup = gtk_button_new_with_label("Hangup");
+	media->priv->accept = gtk_button_new_with_label("Accept");
+	media->priv->reject = gtk_button_new_with_label("Reject");
+	media->priv->send_progress = gtk_progress_bar_new();	
+	media->priv->recv_progress = gtk_progress_bar_new();
+
+	gtk_widget_set_size_request(media->priv->send_progress, 70, 5);
+	gtk_widget_set_size_request(media->priv->recv_progress, 70, 5);
+	
+	gtk_box_pack_start(GTK_BOX(media), media->priv->hangup, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(media), media->priv->accept, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(media), media->priv->reject, FALSE, FALSE, 0);
+
+	gtk_box_pack_start(GTK_BOX(media), media->priv->send_progress, FALSE, FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(media), media->priv->recv_progress, FALSE, FALSE, 6);
+
+	gtk_widget_show(media->priv->send_progress);
+	gtk_widget_show(media->priv->recv_progress);
+	gtk_widget_show_all(media->priv->accept);
+	gtk_widget_show_all(media->priv->reject);
+}
+
+static void
+pidgin_media_finalize (GObject *media)
+{
+}
+
+static void
+pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg)
+{
+	g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg);
+}
+        
+static gboolean
+level_message_cb(GstBus *bus, GstMessage *message, PidginMedia *gtkmedia)
+{
+	const GstStructure *s;
+	const gchar *name;
+
+	int channels;
+	gdouble rms_db, peak_db, decay_db;
+	gdouble rms;
+	const GValue *list;
+	const GValue *value;
+		
+	GstElement *src = GST_MESSAGE_SRC(message);
+
+	if (message->type != GST_MESSAGE_ELEMENT)
+		return TRUE;
+
+	s = gst_message_get_structure(message);
+	name = gst_structure_get_name(s);
+
+	if (strcmp(name, "level"))
+		return TRUE;
+
+	list = gst_structure_get_value(s, "rms");
+
+	/* Only bother with the first channel. */
+	value = gst_value_list_get_value(list, 0);
+	rms_db = g_value_get_double(value);
+
+	if (!strcmp(gst_element_get_name(src), "sendlevel"))	
+		gtk_progress_bar_set_fraction(gtkmedia->priv->send_progress, pow(10, rms_db / 20) * 5);
+	else
+		gtk_progress_bar_set_fraction(gtkmedia->priv->recv_progress, pow(10, rms_db / 20) * 5);
+
+	return TRUE;
+}
+
+static void
+pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia)
+{
+	GstElement *element = purple_media_get_audio_pipeline(media);
+	gst_bus_add_signal_watch(gst_pipeline_get_bus(element));
+	g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", level_message_cb, gtkmedia);
+	printf("\n\nbus: %d\n", gst_pipeline_get_bus(GST_PIPELINE(element)));
+}
+
+static void
+pidgin_media_accept_cb(PurpleMedia *media, PidginMedia *gtkmedia)
+{
+	pidgin_media_emit_message(gtkmedia, _("Call in progress."));
+	gtk_widget_show(gtkmedia->priv->hangup);
+	gtk_widget_hide(gtkmedia->priv->accept);
+	gtk_widget_hide(gtkmedia->priv->reject);
+}
+
+static void
+pidgin_media_hangup_cb(PurpleMedia *media, PidginMedia *gtkmedia)
+{
+	pidgin_media_emit_message(gtkmedia, _("You have ended the call."));
+	gtk_widget_destroy(gtkmedia);
+}
+
+static void
+pidgin_media_reject_cb(PurpleMedia *media, PidginMedia *gtkmedia)
+{
+	pidgin_media_emit_message(gtkmedia, _("You have rejected the call."));
+	gtk_widget_destroy(gtkmedia);
+}
+
+static void
+pidgin_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	PidginMedia *media;
+	g_return_if_fail(PIDGIN_IS_MEDIA(object));
+	
+	media = PIDGIN_MEDIA(object);
+	switch (prop_id) {
+		case PROP_MEDIA:
+			if (media->priv->media)
+				g_object_unref(media->priv->media);
+			media->priv->media = g_value_get_object(value);
+			g_object_ref(media->priv->media);
+			g_signal_connect_swapped(G_OBJECT(media->priv->accept), "clicked", 
+				 G_CALLBACK(purple_media_accept), media->priv->media);
+			g_signal_connect_swapped(G_OBJECT(media->priv->reject), "clicked",
+				 G_CALLBACK(purple_media_reject), media->priv->media);
+			g_signal_connect_swapped(G_OBJECT(media->priv->hangup), "clicked",
+				 G_CALLBACK(purple_media_hangup), media->priv->media);
+
+			g_signal_connect(G_OBJECT(media->priv->media), "accepted",
+				G_CALLBACK(pidgin_media_accept_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media) ,"ready",
+				G_CALLBACK(pidgin_media_ready_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media), "hangup",
+				G_CALLBACK(pidgin_media_hangup_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media), "reject",
+				G_CALLBACK(pidgin_media_reject_cb), media);
+			break;
+		case PROP_SEND_LEVEL:
+			if (media->priv->send_level)
+				gst_object_unref(media->priv->send_level);
+			media->priv->send_level = g_value_get_object(value);
+			g_object_ref(media->priv->send_level);
+			break;
+		case PROP_RECV_LEVEL:
+			if (media->priv->recv_level)
+				gst_object_unref(media->priv->recv_level);
+			media->priv->recv_level = g_value_get_object(value);
+			g_object_ref(media->priv->recv_level);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+pidgin_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	PidginMedia *media;
+	g_return_if_fail(PIDGIN_IS_MEDIA(object));
+	
+	media = PIDGIN_MEDIA(object);
+	
+	switch (prop_id) {
+		case PROP_MEDIA:
+			g_value_set_object(value, media->priv->media);
+			break;
+		case PROP_SEND_LEVEL:
+			g_value_set_object(value, media->priv->send_level);
+			break;
+		case PROP_RECV_LEVEL:
+			g_value_set_object(value, media->priv->recv_level);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
+			break;
+	}
+}
+
+GtkWidget *
+pidgin_media_new(PurpleMedia *media, GstElement *sendlevel, GstElement *recvlevel)
+{
+	return GTK_WIDGET(g_object_new(pidgin_media_get_type(), "media", media, "send-level", sendlevel, "recv-level", recvlevel, NULL));
+}
+
+#endif  /* USE_FARSIGHT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkmedia.h	Sat Dec 29 06:34:59 2007 +0000
@@ -0,0 +1,74 @@
+/**
+ * @file media.h Account API
+ * @ingroup core
+ *
+ * Pidgin 
+ *
+ * Pidgin 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __GTKMEDIA_H_
+#define __GTKMEDIA_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#include "connection.h"
+
+G_BEGIN_DECLS
+
+#define PIDGIN_TYPE_MEDIA            (pidgin_media_get_type())
+#define PIDGIN_MEDIA(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PIDGIN_TYPE_MEDIA, PidginMedia))
+#define PIDGIN_MEDIA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PIDGIN_TYPE_MEDIA, PidginMediaClass))
+#define PIDGIN_IS_MEDIA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PIDGIN_TYPE_MEDIA))
+#define PIDGIN_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PIDGIN_TYPE_MEDIA))
+#define PIDGIN_MEDIA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PIDGIN_TYPE_MEDIA, PidginMediaClass))
+
+typedef struct _PidginMedia PidginMedia;
+typedef struct _PidginMediaClass PidginMediaClass;
+typedef struct _PidginMediaPrivate PidginMediaPrivate;
+
+struct _PidginMediaClass
+{
+	GtkHBoxClass parent_class;
+};
+
+struct _PidginMedia
+{
+	GtkHBox parent;
+	PidginMediaPrivate *priv;
+};
+
+GType pidgin_media_get_type();
+
+GtkWidget *pidgin_media_new(PurpleMedia *media, GstElement *send_level, GstElement *recv_level);
+
+G_END_DECLS
+
+#endif  /* USE_FARSIGHT */
+
+
+#endif  /* __GTKMEDIA_H_ */
--- a/pidgin/plugins/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/plugins/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -119,6 +119,7 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_srcdir)/pidgin \
 	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(PLUGIN_CFLAGS)
 
--- a/pidgin/plugins/gestures/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/plugins/gestures/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -23,4 +23,5 @@
 	-I$(top_builddir)/libpurple \
 	-I$(top_srcdir)/pidgin \
 	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GTK_CFLAGS)
--- a/pidgin/plugins/musicmessaging/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/plugins/musicmessaging/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -39,6 +39,7 @@
 	-I$(top_builddir)/libpurple \
 	-I$(top_srcdir)/libpurple \
 	-I$(top_srcdir)/pidgin \
-	$(DEBUG_CFLAGS) \
+	$(DEBUG_CFLAGS) \	
+	$(FARSIGHT_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(DBUS_CFLAGS)
--- a/pidgin/plugins/ticker/Makefile.am	Fri Dec 28 17:14:52 2007 +0000
+++ b/pidgin/plugins/ticker/Makefile.am	Sat Dec 29 06:34:59 2007 +0000
@@ -24,4 +24,5 @@
 	-I$(top_builddir)/libpurple \
 	-I$(top_srcdir)/pidgin \
 	$(DEBUG_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
 	$(GTK_CFLAGS)