summaryrefslogtreecommitdiff
path: root/src/browser-extension
diff options
context:
space:
mode:
authorMathias Hasselmann <hasselmm@gnome.org>2010-01-10 00:43:02 +0100
committerMathias Hasselmann <hasselmm@gnome.org>2010-01-10 00:43:03 +0100
commit9f8ee8d8bb0fde950650560d77f79aec1e81512a (patch)
treed1a7196906915b84255d4a037542355908f03b39 /src/browser-extension
parentbcea784a38f6bb23b51c83066eff1c5e222279ee (diff)
Add browser extension for accessing FacebookHEADmaster
Add a browser extension which provides a D-Bus interface for accessing Faceboook without violating their terms of service.
Diffstat (limited to 'src/browser-extension')
-rw-r--r--src/browser-extension/tgBrowserService.cpp176
-rw-r--r--src/browser-extension/tgBrowserService.h63
-rw-r--r--src/browser-extension/tgChannelProxy.cpp349
-rw-r--r--src/browser-extension/tgChannelProxy.h68
-rw-r--r--src/browser-extension/tgDBusService.cpp45
-rw-r--r--src/browser-extension/tgDBusService.h37
-rw-r--r--src/browser-extension/tgModule.cpp45
7 files changed, 783 insertions, 0 deletions
diff --git a/src/browser-extension/tgBrowserService.cpp b/src/browser-extension/tgBrowserService.cpp
new file mode 100644
index 0000000..7180059
--- /dev/null
+++ b/src/browser-extension/tgBrowserService.cpp
@@ -0,0 +1,176 @@
+#include "config.h"
+#include "tgBrowserService.h"
+
+#include "nsAppShellCID.h"
+#include "nsIAppStartup.h"
+#include "nsXPFEComponentsCID.h"
+#include "tgChannelProxy.h"
+
+NS_IMPL_ISUPPORTS1(tgBrowserService, nsISupports);
+
+tgBrowserService::tgBrowserService()
+{
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+ NS_INIT_ISUPPORTS();
+}
+
+tgBrowserService::~tgBrowserService()
+{
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+}
+
+NS_IMETHODIMP
+tgBrowserService::Init()
+{
+ nsresult rv;
+
+ shell = do_GetService (NS_APPSHELLSERVICE_CONTRACTID, &rv);
+fprintf(stderr, "%s:%d: shell=%p, rv=%x\n", __func__, __LINE__, shell.get(), rv);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIAppStartup> startup;
+ startup = do_GetService (NS_APPSTARTUP_CONTRACTID, &rv);
+fprintf(stderr, "%s:%d: startup=%p, rv=%x\n", __func__, __LINE__, startup.get(), rv);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = startup->CreateHiddenWindow();
+fprintf(stderr, "%s:%d: rv=%x\n", __func__, __LINE__, rv);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ io = do_GetIOService (&rv);
+fprintf(stderr, "%s:%d: io=%p, rv=%x\n", __func__, __LINE__, io.get(), rv);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ DBusConnection *session = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+fprintf(stderr, "%s:%d: session=%p\n", __func__, __LINE__, session);
+
+ if (NULL == session)
+ return NS_ERROR_FAILURE;
+
+ if (-1 == dbus_bus_request_name(session,
+ TG_BROWSER_SERVICE_DBUS_NAME,
+ DBUS_NAME_FLAG_ALLOW_REPLACEMENT |
+ DBUS_NAME_FLAG_REPLACE_EXISTING,
+ NULL))
+ return NS_ERROR_FAILURE;
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+
+ rv = Register(session);
+ NS_ENSURE_SUCCESS (rv, rv);
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+tgBrowserService::GetObjectPath(nsCString & aObjectPath)
+{
+ aObjectPath.AssignLiteral(TG_BROWSER_SERVICE_DBUS_PATH);
+ return NS_OK;
+}
+
+DBusMessage *
+tgBrowserService::OnMethodCall(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+ const nsCString interface(dbus_message_get_interface(aMessage));
+ const nsCString member(dbus_message_get_member(aMessage));
+fprintf(stderr, "%s:%d: %s::%s\n", __func__, __LINE__, interface.BeginReading(), member.BeginReading());
+
+ if (interface == DBUS_INTERFACE_INTROSPECTABLE)
+ {
+ if (member == "Introspect")
+ return OnIntrospect(aConnection, aMessage);
+ }
+
+ if (interface == TG_BROWSER_SERVICE_DBUS_INTERFACE)
+ {
+ if (member == "NewChannel")
+ return OnNewChannel(aConnection, aMessage);
+ if (member == "NewWindow")
+ return OnNewWindow(aConnection, aMessage);
+ }
+
+ return NULL;
+}
+
+DBusMessage *
+tgBrowserService::OnIntrospect(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+ static const char interfaceDescription[] =
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node name=\"" TG_BROWSER_SERVICE_DBUS_PATH "\">\n"
+ " <interface name=\"" TG_BROWSER_SERVICE_DBUS_INTERFACE "\">\n"
+ " <method name=\"NewChannel\">\n"
+ " <arg name=\"uri\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"proxy_path\" type=\"o\" direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ "</node>\n";
+
+ DBusMessage * reply = dbus_message_new_method_return(aMessage);
+ const char *vInterfaceDescription = interfaceDescription;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &vInterfaceDescription,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+DBusMessage *
+tgBrowserService::OnNewChannel(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+ nsCOMPtr<nsIChannel> channel;
+ const char *uri;
+ nsresult rv;
+
+ if (!dbus_message_get_args(aMessage, NULL, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID))
+ return NULL;
+
+fprintf(stderr, "%s:%d: uri=%s\n", __func__, __LINE__, uri);
+ rv = io->NewChannel(nsCAutoString(uri), nsnull, nsnull, getter_AddRefs(channel));
+
+ if (NS_FAILED(rv))
+ return dbus_message_new_error_printf(aMessage, DBUS_ERROR_FAILED,
+ "nsIIOService::NewChannel() failed (rv=%x)", rv);
+
+ nsCOMPtr<tgChannelProxy> proxy(new tgChannelProxy);
+ rv = proxy->Init(channel, aConnection);
+
+ if (NS_FAILED(rv))
+ return dbus_message_new_error_printf(aMessage, DBUS_ERROR_FAILED,
+ "tgChannelProxy::Init() failed (rv=%x)", rv);
+
+ nsCString proxyPath;
+ rv = proxy->GetObjectPath(proxyPath);
+
+ if (NS_FAILED(rv))
+ return dbus_message_new_error_printf(aMessage, DBUS_ERROR_FAILED,
+ "tgChannelProxy::GetObjectPath() failed (rv=%x)", rv);
+
+ DBusMessage * reply = dbus_message_new_method_return(aMessage);
+ const char *vProxyPath = proxyPath.BeginReading();
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_OBJECT_PATH, &vProxyPath,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+DBusMessage*
+tgBrowserService::OnNewWindow(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+ return NULL;
+}
+
diff --git a/src/browser-extension/tgBrowserService.h b/src/browser-extension/tgBrowserService.h
new file mode 100644
index 0000000..f753806
--- /dev/null
+++ b/src/browser-extension/tgBrowserService.h
@@ -0,0 +1,63 @@
+/* telepathy-gruschler - A Telepathy connection manager for social networks.
+ * Copyright (C) 2009 Mathias Hasselmann
+ *
+ * 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 __TG_BROWSER_SERVICE_H__
+#define __TG_BROWSER_SERVICE_H__
+
+#include "nsIAppShellService.h"
+#include "nsNetUtil.h"
+#include "tgDBusService.h"
+
+#define TG_BROWSER_SERVICE_CONTRACTID "@freedesktop.org/telepathy-gruschler/BrowserService;1"
+#define TG_BROWSER_SERVICE_CLASSNAME "Telepathy Gruschler Browser Service"
+#define TG_BROWSER_SERVICE_CID { 0x76a9731d, 0xf28e, 0x4998, { 0x8b, 0x2f, 0x3f, 0x69, 0x74, 0xe7, 0x61, 0x89 } }
+
+#define TG_BROWSER_SERVICE_DBUS_NAME "org.freedesktop.Telepathy.Gruschler.BrowserService"
+#define TG_BROWSER_SERVICE_DBUS_PATH "/org/freedesktop/Telepathy/Gruschler/BrowserService"
+#define TG_BROWSER_SERVICE_DBUS_INTERFACE "org.freedesktop.Telepathy.Gruschler.BrowserService"
+
+class tgBrowserService:
+ public nsISupports,
+ public tgDBusService
+{
+ NS_DECL_ISUPPORTS;
+
+public:
+ tgBrowserService();
+
+private:
+ ~tgBrowserService();
+
+public:
+ NS_METHOD Init();
+ NS_IMETHOD GetObjectPath(nsCString & aObjectPath);
+
+protected:
+ virtual DBusMessage * OnMethodCall(DBusConnection * aConnection, DBusMessage * aMessage);
+
+private:
+ DBusMessage * OnIntrospect(DBusConnection * aConnection, DBusMessage * aMessage);
+ DBusMessage * OnNewChannel(DBusConnection * aConnection, DBusMessage * aMessage);
+ DBusMessage * OnNewWindow(DBusConnection * aConnection, DBusMessage * aMessage);
+
+private:
+ nsCOMPtr<nsIIOService> io;
+ nsCOMPtr<nsIAppShellService> shell;
+};
+
+#endif /* __TG_BROWSER_SERVICE_H__ */
+
diff --git a/src/browser-extension/tgChannelProxy.cpp b/src/browser-extension/tgChannelProxy.cpp
new file mode 100644
index 0000000..5b5381f
--- /dev/null
+++ b/src/browser-extension/tgChannelProxy.cpp
@@ -0,0 +1,349 @@
+#include "config.h"
+#include "tgChannelProxy.h"
+
+#include "nsIInputStream.h"
+#include "nsServiceManagerUtils.h"
+
+#include <plstr.h>
+#include <stdio.h>
+
+NS_IMPL_ISUPPORTS1(tgChannelProxy, nsIStreamListener);
+
+int tgChannelProxy::lastId = 0;
+
+class DBusMessagePtr
+{
+public:
+ DBusMessagePtr(DBusMessage * aMessage = NULL): message(aMessage) {}
+ virtual ~DBusMessagePtr() { assign(NULL); }
+
+ void operator=(DBusMessage * rhs) { assign(rhs); }
+ operator DBusMessage *() const { return get(); }
+
+ void
+ assign(DBusMessage * other)
+ {
+ if (other)
+ dbus_message_ref (other);
+ if (message)
+ dbus_message_unref (message);
+
+ message = other;
+ }
+
+ DBusMessage *
+ forget()
+ {
+ DBusMessage * tmp = message;
+ message = NULL;
+ return tmp;
+ }
+
+ DBusMessage *
+ get() const
+ {
+ return message;
+ }
+
+private:
+ DBusMessage * message;
+};
+
+tgChannelProxy::tgChannelProxy():
+ connection(NULL)
+{
+ NS_INIT_ISUPPORTS();
+}
+
+NS_METHOD
+tgChannelProxy::Init(nsIChannel * aChannel,
+ DBusConnection * aConnection)
+{
+ if (NULL == aChannel)
+ return NS_ERROR_INVALID_ARG;
+ if (NULL == aConnection)
+ return NS_ERROR_INVALID_ARG;
+
+ nsresult rv;
+
+ rv = Register(aConnection);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ timer = do_GetService(NS_TIMER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // FIXME: figure out why the callback is not called
+ rv = timer->InitWithFuncCallback(OnProxyTimeout, this, 15000, nsITimer::TYPE_ONE_SHOT);
+
+ AddRef(); // borrow a reference until the channel was used
+ channel = aChannel; // remember the channel we use
+ connection = dbus_connection_ref(aConnection);
+
+ return NS_OK;
+}
+
+tgChannelProxy::~tgChannelProxy()
+{
+ if (connection)
+ {
+ if (objectPath.Length() > 0)
+ dbus_connection_unregister_object_path(connection, objectPath.BeginReading());
+
+ dbus_connection_unref(connection);
+ }
+}
+
+NS_IMETHODIMP
+tgChannelProxy::OnStartRequest(nsIRequest * aRequest,
+ nsISupports * aContext)
+{
+ nsCString requestName;
+ nsresult rv;
+
+ channel = NULL;
+
+ rv = aRequest->GetName(requestName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ const char *vRequestName = requestName.BeginReading();
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(objectPath.BeginReading(),
+ TG_CHANNEL_PROXY_DBUS_INTERFACE,
+ "RequestStarted");
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &vRequestName,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send(connection, message, NULL))
+ rv = NS_ERROR_FAILURE;
+ else
+ rv = NS_OK;
+
+ dbus_message_unref(message);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+tgChannelProxy::OnStopRequest(nsIRequest * aRequest,
+ nsISupports * aContext,
+ nsresult aStatusCode)
+{
+ nsCString requestName;
+ nsresult rv;
+
+ rv = aRequest->GetName(requestName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ const char *vRequestName = requestName.BeginReading();
+ dbus_uint32_t vStatusCode = aStatusCode;
+
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(objectPath.BeginReading(),
+ TG_CHANNEL_PROXY_DBUS_INTERFACE,
+ "RequestStopped");
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &vRequestName,
+ DBUS_TYPE_UINT32, &vStatusCode,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send(connection, message, NULL))
+ rv = NS_ERROR_FAILURE;
+ else
+ rv = NS_OK;
+
+ dbus_message_unref(message);
+ channel = NULL; // FIXME: check error handling
+
+ return rv;
+}
+
+NS_IMETHODIMP
+tgChannelProxy::OnDataAvailable(nsIRequest * aRequest,
+ nsISupports * aContext,
+ nsIInputStream * aInputStream,
+ PRUint32 aOffset,
+ PRUint32 aCount)
+{
+ nsCString requestName;
+ nsresult rv;
+
+ rv = aRequest->GetName(requestName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ char buffer[aCount];
+ const char *vRequestName = requestName.BeginReading();
+ const char *vBuffer = buffer;
+ rv = NS_OK;
+
+ while (aCount > 0)
+ {
+ PRUint32 bytesRead;
+
+ rv = aInputStream->Read(buffer, aCount, &bytesRead);
+ NS_ENSURE_SUCCESS(rv, rv);
+ aCount -= bytesRead;
+
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(objectPath.BeginReading(),
+ TG_CHANNEL_PROXY_DBUS_INTERFACE,
+ "DataAvailable");
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &vRequestName,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &vBuffer, bytesRead,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send(connection, message, NULL))
+ {
+ dbus_message_unref(message);
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
+
+ dbus_message_unref(message);
+ rv = NS_OK;
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+tgChannelProxy::GetObjectPath(nsCString & aObjectPath)
+{
+ if (0 == objectPath.Length())
+ {
+ objectPath.Assign(TG_CHANNEL_PROXY_DBUS_PATH);
+ objectPath.AppendInt(++lastId);
+ }
+
+ aObjectPath.Assign(objectPath);
+ return NS_OK;
+}
+
+DBusMessage *
+tgChannelProxy::OnMethodCall(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+ const nsCString interface(dbus_message_get_interface(aMessage));
+ const nsCString member(dbus_message_get_member(aMessage));
+
+ if (interface == DBUS_INTERFACE_INTROSPECTABLE)
+ {
+ if (member == "Introspect")
+ return OnIntrospect(aConnection, aMessage);
+ }
+
+ if (interface == TG_CHANNEL_PROXY_DBUS_INTERFACE)
+ {
+ if (member == "Open")
+ return OnOpen(aConnection, aMessage);
+ }
+
+ return NULL;
+}
+
+DBusMessage *
+tgChannelProxy::OnIntrospect(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+ nsCString interfaceDescription;
+
+ interfaceDescription.AppendLiteral(
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node name=\"");
+ interfaceDescription.Append(objectPath);
+
+ interfaceDescription.AppendLiteral(
+ "\">\n"
+ " <interface name=\"" TG_CHANNEL_PROXY_DBUS_INTERFACE "\">\n"
+ " <method name=\"Open\"/>\n"
+ " <signal name=\"RequestStarted\">\n"
+ " <arg name=\"request_name\" type=\"s\"/>\n"
+ " </signal>\n"
+ " <signal name=\"RequestStopped\">\n"
+ " <arg name=\"request_name\" type=\"s\"/>\n"
+ " <arg name=\"status_code\" type=\"i\"/>\n"
+ " </signal>\n"
+ " <signal name=\"DataAvailable\">\n"
+ " <arg name=\"request_name\" type=\"s\"/>\n"
+ " <arg name=\"data\" type=\"ay\"/>\n"
+ " </signal>\n"
+ " </interface>\n"
+ " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ "</node>\n");
+
+ DBusMessage * reply = dbus_message_new_method_return(aMessage);
+ const char *vInterfaceDescription = interfaceDescription.BeginReading();
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &vInterfaceDescription,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+DBusMessage *
+tgChannelProxy::OnOpen(DBusConnection * aConnection,
+ DBusMessage * aMessage)
+{
+ if (!timer)
+ return dbus_message_new_error_printf(aMessage, DBUS_ERROR_FAILED,
+ "This channel proxy is expired");
+
+ nsresult rv = channel->AsyncOpen(this, nsnull);
+
+ if (NS_FAILED (rv))
+ return dbus_message_new_error_printf(aMessage, DBUS_ERROR_FAILED,
+ "nsIChannel::AsyncOpen() failed (rv=%x)", rv);
+
+ timer = NULL; // discard the timer
+ //Release(); // give back borrowed reference
+ //TODO: call channel->removeObserver() at some point?
+
+ return dbus_message_new_method_return (aMessage);
+}
+
+void
+tgChannelProxy::OnProxyTimeout(nsITimer * aTimer,
+ void * aClosure)
+{
+ tgChannelProxy *proxy = static_cast<tgChannelProxy*>(aClosure);
+
+ if (proxy->timer)
+ {
+ proxy->timer = NULL; // discard the timer
+ proxy->Release(); // give back borrowed reference
+ }
+}
+
+
+/*
+To create an HTTP POST, a few additional steps are required after the nsIChannel is created.
+
+First, a nsIInputStream instance is created, after which the setData method is called. The first argument is the POST data as a string, while the second argument is the length of that data. In this case, the data is URL encoded, meaning that the string should look like this: foo=bar&baz=eek.
+
+var inputStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
+ .createInstance(Components.interfaces.nsIStringInputStream);
+inputStream.setData(postData, postData.length);
+
+Next, the nsIChannel is QIed to an nsIUploadChannel. Its setUploadStream method is called, passing in the nsIInputStream and the type (in this case, "application/x-www-form-urlencoded"):
+
+var uploadChannel = gChannel.QueryInterface(Components.interfaces.nsIUploadChannel);
+uploadChannel.setUploadStream(inputStream, "application/x-www-form-urlencoded", -1);
+
+Due to a bug, calling setUploadStream will reset the nsIHttpChannel to be a PUT request, so now the request type is set to POST:
+
+// order important - setUploadStream resets to PUT
+httpChannel.requestMethod = "POST";
+
+*/
diff --git a/src/browser-extension/tgChannelProxy.h b/src/browser-extension/tgChannelProxy.h
new file mode 100644
index 0000000..98a7bec
--- /dev/null
+++ b/src/browser-extension/tgChannelProxy.h
@@ -0,0 +1,68 @@
+/* telepathy-gruschler - A Telepathy connection manager for social networks.
+ * Copyright (C) 2009 Mathias Hasselmann
+ *
+ * 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 __TG_CHANNEL_PROXY_H__
+#define __TG_CHANNEL_PROXY_H__
+
+#include "nsCOMPtr.h"
+#include "nsIChannel.h"
+#include "nsIStreamListener.h"
+#include "nsITimer.h"
+#include "tgDBusService.h"
+
+#define TG_CHANNEL_PROXY_DBUS_PATH "/org/freedesktop/Telepathy/Gruschler/ChannelProxy/"
+#define TG_CHANNEL_PROXY_DBUS_INTERFACE "org.freedesktop.Telepathy.Gruschler.ChannelProxy"
+
+class tgChannelProxy:
+ public nsIStreamListener,
+ public tgDBusService
+{
+ NS_DECL_ISUPPORTS;
+ NS_DECL_NSIREQUESTOBSERVER;
+ NS_DECL_NSISTREAMLISTENER;
+
+public:
+ tgChannelProxy();
+
+private:
+ ~tgChannelProxy();
+
+public:
+ NS_METHOD Init(nsIChannel * aChannel, DBusConnection * aConnection);
+ NS_IMETHOD GetObjectPath(nsCString & aObjectPath);
+
+protected:
+ virtual DBusMessage * OnMethodCall(DBusConnection * aConnection, DBusMessage * aMessage);
+
+private:
+ static void OnProxyTimeout(nsITimer *aTimer, void * aClosure);
+
+ DBusMessage * OnIntrospect(DBusConnection * aConnection, DBusMessage * aMessage);
+ DBusMessage * OnOpen(DBusConnection * aConnection, DBusMessage * aMessage);
+
+private:
+ nsCOMPtr<nsIChannel> channel;
+ nsCOMPtr<nsITimer> timer;
+
+ DBusConnection * connection;
+ nsCString objectPath;
+ static int lastId;
+
+};
+
+#endif /* __CHANNEL_PROXY_H__ */
+
diff --git a/src/browser-extension/tgDBusService.cpp b/src/browser-extension/tgDBusService.cpp
new file mode 100644
index 0000000..d0ba80a
--- /dev/null
+++ b/src/browser-extension/tgDBusService.cpp
@@ -0,0 +1,45 @@
+#include "config.h"
+#include "tgDBusService.h"
+
+#include <stdio.h>
+
+NS_IMETHODIMP
+tgDBusService::Register(DBusConnection * aConnection)
+{
+ const DBusObjectPathVTable vtable = { NULL, OnDBusMessage, NULL, };
+ nsCString objectPath;
+ nsresult rv;
+
+ rv = GetObjectPath(objectPath);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!dbus_connection_register_object_path(aConnection,
+ objectPath.BeginReading(),
+ &vtable, this))
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+
+DBusHandlerResult
+tgDBusService::OnDBusMessage(DBusConnection * aConnection,
+ DBusMessage * aMessage,
+ void * aData)
+{
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+ tgDBusService * service = static_cast<tgDBusService*>(aData);
+ DBusMessage *reply = NULL;
+
+ if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(aMessage))
+ reply = service->OnMethodCall(aConnection, aMessage);
+
+ if (NULL == reply)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ dbus_connection_send(aConnection, reply, NULL);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
diff --git a/src/browser-extension/tgDBusService.h b/src/browser-extension/tgDBusService.h
new file mode 100644
index 0000000..65a43c8
--- /dev/null
+++ b/src/browser-extension/tgDBusService.h
@@ -0,0 +1,37 @@
+/* telepathy-gruschler - A Telepathy connection manager for social networks.
+ * Copyright (C) 2010 Mathias Hasselmann
+ *
+ * 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 __TG_DBUS_SERVICE_H__
+#define __TG_DBUS_SERVICE_H__
+
+#include <dbus/dbus.h>
+#include "nsStringAPI.h"
+
+class tgDBusService
+{
+public:
+ NS_IMETHOD GetObjectPath(nsCString & aObjectPath) = 0;
+
+protected:
+ NS_METHOD Register(DBusConnection * aConnection);
+ virtual DBusMessage * OnMethodCall(DBusConnection * aConnection, DBusMessage * aMessage) = 0;
+
+private:
+ static DBusHandlerResult OnDBusMessage(DBusConnection * aConnection, DBusMessage * aMessage, void * aData);
+};
+
+#endif /* __TG_DBUS_SERVICE_H__ */
diff --git a/src/browser-extension/tgModule.cpp b/src/browser-extension/tgModule.cpp
new file mode 100644
index 0000000..29f2da6
--- /dev/null
+++ b/src/browser-extension/tgModule.cpp
@@ -0,0 +1,45 @@
+#include "config.h"
+
+#include "nsIGenericFactory.h"
+#include "nsICategoryManager.h"
+#include "nsServiceManagerUtils.h"
+
+#include "tgBrowserService.h"
+
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(tgBrowserService, Init);
+
+static NS_METHOD
+tgBrowserServiceRegistration(nsIComponentManager *aCompMgr,
+ nsIFile *aPath,
+ const char *registryLocation,
+ const char *componentType,
+ const nsModuleComponentInfo *info)
+{
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+ nsCOMPtr<nsICategoryManager> catman;
+ nsresult rv;
+
+ catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = catman->AddCategoryEntry(NS_XPCOM_STARTUP_CATEGORY,
+ TG_BROWSER_SERVICE_CLASSNAME,
+ TG_BROWSER_SERVICE_CONTRACTID,
+ PR_TRUE, PR_TRUE, nsnull);
+
+ return rv;
+}
+
+static nsModuleComponentInfo components[] = {
+ { TG_BROWSER_SERVICE_CLASSNAME,
+ TG_BROWSER_SERVICE_CID,
+ TG_BROWSER_SERVICE_CONTRACTID,
+ tgBrowserServiceConstructor,
+ tgBrowserServiceRegistration,
+ },
+};
+
+NS_IMPL_NSGETMODULE("tgModule", components);
+