From: Steven Luo Date: Mon, 14 Dec 2009 11:27:51 +0000 (-0800) Subject: Merge documentation updates from 2.2 into c-implementation X-Git-Tag: v3.0rc1~21 X-Git-Url: http://git.maemo.org/git/?p=browser-switch;a=commitdiff_plain;h=62cd99eefeeb67d5b52444a8768645cfe76b04b6;hp=ab465ec2a9b021123bbc8c77c6cc4883f5809406 Merge documentation updates from 2.2 into c-implementation --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8974eb2 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +CC = gcc +CFLAGS = -Wall -Os -mcpu=arm1136jf-s -mthumb +CPPFLAGS = `pkg-config --cflags dbus-glib-1` +LDFLAGS = `pkg-config --libs dbus-glib-1` +PREFIX = /usr/local + +APP = browser-switchboard +obj = main.o launcher.o dbus-server-bindings.o + +all: $(APP) + +$(APP): dbus-server-glue.h $(obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(APP) $(obj) + +dbus-server-glue.h: + dbus-binding-tool --mode=glib-server --prefix="osso_browser" \ + dbus-server-glue.xml > dbus-server-glue.h + +strip: $(APP) + strip $(APP) + +install: all + mkdir -p $(DESTDIR)$(PREFIX)/bin + install -c -m 0755 browser-switchboard $(DESTDIR)$(PREFIX)/bin + install -c -m 0644 com.nokia.osso_browser.service $(DESTDIR)$(PREFIX)/share/dbus-1/services + install -c -m 0755 browser $(DESTDIR)$(PREFIX)/bin + +clean: + rm -f $(APP) *.o dbus-server-glue.h + +.PHONY: strip install diff --git a/browser-switchboard b/browser-switchboard deleted file mode 100755 index e922cee..0000000 --- a/browser-switchboard +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/python -# browser-switchboard -# version 2.2 by steven676 and xiojason - -# simple python-dbus service that proxies osso_browser events to Tear -# based on code from http://paste.lisp.org/display/45824 - -# Copyright (C) 2009 Jason Simpson -# Copyright (C) 2009 Steven Luo - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# On Maemo systems, a copy of the GPL can be found in -# /usr/share/common-licenses/GPL . - - -import os -import gobject -import dbus -import dbus.service -import dbus.glib - -# Set default configuration values -# These can be overriden by the config file $HOME/.config/browser-switchboard -def setconfigdefaults(): - global continuous_mode, default_browser, other_browser_cmd - - # continuous_mode: 0 -- close after handling a request; 1 -- run - # continuously in the background - continuous_mode = 0 - # default_browser: "tear", "microb", "fennec", "midori", or "other" - # empty string is handled specially -- see below - default_browser = "" - # If default browser is "other", what program to run (%s will be replaced - # by URI) - other_browser_cmd = "" - -class BrowserLauncher: - def LaunchTear(self, uri): - # We should be able to just call the D-Bus service to open Tear ... - # but if Tear's not open, that causes D-Bus to start Tear and then - # pass it the OpenAddress call, which results in two browser windows. - # Properly fixing this probably requires Tear to provide a D-Bus method - # that opens an address in an existing window, but for now work around - # by just opening Tear via the command line if it's not running. - if os.system("pidof tear > /dev/null") == 0: - dbus.SessionBus().get_object('com.nokia.tear', '/com/nokia/tear').OpenAddress(uri, dbus_interface='com.nokia.Tear') - if continuous_mode == 0: - quit() - else: - if continuous_mode: - if os.fork() != 0: - # parent process doesn't need to do anything - return - # child process - os.setsid() - os.execl('/usr/bin/tear', '/usr/bin/tear', uri) - - def LaunchMicroB(self, uri): - if os.system("pidof /usr/sbin/browserd > /dev/null") != 0: - kill_browserd = 1 - os.system("/usr/sbin/browserd -d") - else: - kill_browserd = 0 - dbus.SessionBus().release_name("com.nokia.osso_browser") - if uri == "new_window": - # exec maemo-invoker directly instead of relying on the - # /usr/bin/browser symlink, since /usr/bin/browser may have been - # replaced with a shell script calling us via D-Bus - os.spawnl(os.P_WAIT, '/usr/bin/maemo-invoker', '/usr/bin/browser') - else: - os.spawnl(os.P_WAIT, '/usr/bin/maemo-invoker', '/usr/bin/browser', '--url', uri) - if kill_browserd: - os.system("kill `pidof /usr/sbin/browserd`") - if continuous_mode: - dbus.SessionBus().request_name("com.nokia.osso_browser") - else: - quit() - - def LaunchOtherBrowser(self, uri): - if uri == "new_window": - uri = "" - try: - # URI must be quoted and quotes in the URI must be URL-escaped - # to prevent the shell from interpreting any part of the URI - command = other_browser_cmd % "'%s'" % uri.replace("'", "%27") - except TypeError: - # Couldn't substitute URI in, just launch the browser - print "other_browser_cmd should have a %s placeholder for the URI" - command = other_browser_cmd - import subprocess - subprocess.Popen(command, shell=True) - if continuous_mode == 0: - quit() - - def UpdateDefaultBrowser(self): - global other_browser_cmd - if default_browser == "tear": - self.LaunchBrowser = self.LaunchTear - elif default_browser == "microb": - self.LaunchBrowser = self.LaunchMicroB - elif default_browser == "fennec": - # Cheat and reuse LaunchOtherBrowser, since we don't appear to - # need to do anything special - # TODO: does Fennec have a D-Bus API or signaling mechanism? - # Invoking the fennec binary appears to be somewhat expensive - other_browser_cmd = "fennec '%s'" - self.LaunchBrowser = self.LaunchOtherBrowser - elif default_browser == "midori": - other_browser_cmd = "midori '%s'" - self.LaunchBrowser = self.LaunchOtherBrowser - elif default_browser == "other": - if other_browser_cmd != "": - self.LaunchBrowser = self.LaunchOtherBrowser - else: - print "default_browser is 'other', but no other_browser_cmd set -- using default" - self.LaunchBrowser = self.LaunchTear - elif default_browser == "": - # If default_browser is empty, use Tear as the default if - # installed, otherwise use MicroB - if os.access("/usr/bin/tear", os.X_OK): - self.LaunchBrowser = self.LaunchTear - else: - self.LaunchBrowser = self.LaunchMicroB - else: - print "Unknown default_browser %s, using default" % default_browser - self.LaunchBrowser = self.LaunchTear - - def __init__(self): - self.UpdateDefaultBrowser() - -class ProxyBrowserService(dbus.service.Object): - def __init__(self): - bus_name = dbus.service.BusName('com.nokia.osso_browser', bus=dbus.SessionBus()) - dbus.service.Object.__init__(self, bus_name, '/com/nokia/osso_browser') - dbus.service.Object.__init__(self, bus_name, '/com/nokia/osso_browser/request') - - def OpenAddress(self, uri): - print uri - - if uri[0] == '/': - print "prefixing apparent local path with file://" - uri = "file://" + uri - - launcher.LaunchBrowser(uri) - - @dbus.service.method(dbus_interface='com.nokia.osso_browser', in_signature='s') - def load_url(self, uri): - print "load_url" - self.OpenAddress(uri) - - @dbus.service.method(dbus_interface='com.nokia.osso_browser', in_signature='s') - def mime_open(self, uri): - print "mime_open" - self.OpenAddress(uri) - - @dbus.service.method(dbus_interface='com.nokia.osso_browser', in_signature='s') - def open_new_window(self, uri): - print "open_new_window" - self.OpenAddress(uri) - - @dbus.service.method(dbus_interface='com.nokia.osso_browser') - def top_application(self): - print "top_application" - launcher.LaunchMicroB("new_window") - - # This method is an "undocumented", non-standard extension to the - # osso_browser D-Bus API, intended solely to allow a wrapper script - # replacing /usr/bin/browser to implement --url - @dbus.service.method(dbus_interface='com.nokia.osso_browser') - def switchboard_launch_microb(self, uri="new_window"): - print "switchboard_launch_microb" - launcher.LaunchMicroB(uri) - -def readconfigfile(signalnum=None, frame=None): - # reset configuration to defaults - setconfigdefaults() - - # read configuration from the config file, if available - try: - execfile(os.getenv("HOME", "/home/user") + "/.config/browser-switchboard", globals()) - except: - # Try the legacy config file location - try: - execfile(os.getenv("HOME", "/home/user") + "/.config/browser-proxy", globals()) - except: - # No valid config file available - pass - launcher.UpdateDefaultBrowser() - -setconfigdefaults() - -launcher = BrowserLauncher() -pbrowser = ProxyBrowserService() - -readconfigfile() - -if continuous_mode: - import signal - def waitforzombies(signalnum, frame): - try: - while os.waitpid(-1, os.WNOHANG) != (0, 0): - continue - except OSError: - pass - signal.signal(signal.SIGCHLD, waitforzombies) - signal.signal(signal.SIGHUP, readconfigfile) - -loop = gobject.MainLoop() -loop.run() diff --git a/browser-switchboard.h b/browser-switchboard.h new file mode 100644 index 0000000..726a553 --- /dev/null +++ b/browser-switchboard.h @@ -0,0 +1,34 @@ +/* + * browser-switchboard.h -- definitions common to all of browser-switchboard + * + * Copyright (C) 2009 Steven Luo + * Derived from a Python implementation by Jason Simpson and Steven Luo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef _BROWSER_SWITCHBOARD_H +#define _BROWSER_SWITCHBOARD_H 1 + +struct swb_context { + int continuous_mode; + void (*default_browser_launcher)(struct swb_context *, char *); + char *other_browser_cmd; + DBusGConnection *session_bus; + DBusGProxy *dbus_proxy; +}; + +#endif /* _BROWSER_SWITCHBOARD_H */ diff --git a/dbus-server-bindings.c b/dbus-server-bindings.c new file mode 100644 index 0000000..b29b1ab --- /dev/null +++ b/dbus-server-bindings.c @@ -0,0 +1,143 @@ +/* + * dbus-server-bindings.c -- osso_browser D-Bus interface implementation + * + * Copyright (C) 2009 Steven Luo + * Derived from a Python implementation by Jason Simpson and Steven Luo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include +#include +#include +#include + +#include "browser-switchboard.h" +#include "launcher.h" +#include "dbus-server-bindings.h" + +extern struct swb_context ctx; + +G_DEFINE_TYPE(OssoBrowser, osso_browser, G_TYPE_OBJECT); +static void osso_browser_init(OssoBrowser *obj) +{ +} + +static void osso_browser_class_init(OssoBrowserClass *klass) +{ +} + +#include "dbus-server-glue.h" + + +static void open_address(const char *uri) { + char *new_uri; + size_t new_uri_len; + + if (!uri) + /* Not much to do in this case ... */ + return; + + if (uri[0] == '/') { + new_uri_len = strlen("file://") + strlen(uri) + 1; + if (!(new_uri = calloc(new_uri_len, sizeof(char)))) + exit(1); + snprintf(new_uri, new_uri_len, "%s%s", "file://", uri); + + launch_browser(&ctx, new_uri); + /* If launch_browser didn't exec something in this process, + we need to clean up after ourselves */ + free(new_uri); + } else { + printf("open_address '%s'\n", uri); + launch_browser(&ctx, (char *)uri); + } +} + + +/* + * The com.nokia.osso_browser D-Bus interface + */ +gboolean osso_browser_load_url(OssoBrowser *obj, + const char *uri, GError **error) { + open_address(uri); + return TRUE; +} + +gboolean osso_browser_mime_open(OssoBrowser *obj, + const char *uri, GError **error) { + open_address(uri); + return TRUE; +} + +gboolean osso_browser_open_new_window(OssoBrowser *obj, + const char *uri, GError **error) { + open_address(uri); + return TRUE; +} + +gboolean osso_browser_top_application(OssoBrowser *obj, + GError **error) { + launch_microb(&ctx, "new_window"); + return TRUE; +} + +/* This is a "undocumented", non-standard extension to the API, ONLY + for use by /usr/bin/browser wrapper to implement --url */ +gboolean osso_browser_switchboard_launch_microb(OssoBrowser *obj, + const char *uri, GError **error) { + launch_microb(&ctx, (char *)uri); + return TRUE; +} + + +/* Register the name com.nokia.osso_browser on the D-Bus session bus */ +void dbus_request_osso_browser_name(struct swb_context *ctx) { + GError *error = NULL; + guint result; + + if (!ctx || !ctx->dbus_proxy) + return; + + if (!dbus_g_proxy_call(ctx->dbus_proxy, "RequestName", &error, + G_TYPE_STRING, "com.nokia.osso_browser", + G_TYPE_UINT, DBUS_NAME_FLAG_REPLACE_EXISTING|DBUS_NAME_FLAG_DO_NOT_QUEUE, + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID)) { + printf("Couldn't acquire name com.nokia.osso_browser\n"); + exit(1); + } + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + printf("Couldn't acquire name com.nokia.osso_browser\n"); + exit(1); + } +} + +/* Release the name com.nokia.osso_browser on the D-Bus session bus */ +void dbus_release_osso_browser_name(struct swb_context *ctx) { + GError *error = NULL; + guint result; + + if (!ctx || !ctx->dbus_proxy) + return; + + dbus_g_proxy_call(ctx->dbus_proxy, "ReleaseName", &error, + G_TYPE_STRING, "com.nokia.osso_browser", + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID); +} diff --git a/dbus-server-bindings.h b/dbus-server-bindings.h new file mode 100644 index 0000000..232ac5d --- /dev/null +++ b/dbus-server-bindings.h @@ -0,0 +1,54 @@ +/* + * dbus-server-bindings.h -- definitions for the osso_browser interface + * + * Copyright (C) 2009 Steven Luo + * Derived from a Python implementation by Jason Simpson and Steven Luo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef _DBUS_SERVER_BINDINGS_H +#define _DBUS_SERVER_BINDINGS_H 1 + +#include "browser-switchboard.h" + +GType osso_browser_get_type(void); +#define OSSO_BROWSER_TYPE (osso_browser_get_type()) +typedef struct _OssoBrowser { + GObject parent; +} OssoBrowser; +typedef struct _OssoBrowserClass { + GObjectClass parent; +} OssoBrowserClass; + +/* The com.nokia.osso_browser D-Bus interface */ +gboolean osso_browser_load_url(OssoBrowser *obj, + const char *uri, GError **error); +gboolean osso_browser_mime_open(OssoBrowser *obj, + const char *uri, GError **error); +gboolean osso_browser_open_new_window(OssoBrowser *obj, + const char *uri, GError **error); +gboolean osso_browser_top_application(OssoBrowser *obj, GError **error); +/* This is an "undocumented", non-standard extension; DO NOT USE */ +gboolean osso_browser_switchboard_launch_microb(OssoBrowser *obj, + const char *uri, GError **error); + +void dbus_request_osso_browser_name(struct swb_context *ctx); +void dbus_release_osso_browser_name(struct swb_context *ctx); + +const DBusGObjectInfo dbus_glib_osso_browser_object_info; + +#endif /* _DBUS_SERVER_BINDINGS_H */ diff --git a/dbus-server-glue.xml b/dbus-server-glue.xml new file mode 100644 index 0000000..1fd3062 --- /dev/null +++ b/dbus-server-glue.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/launcher.c b/launcher.c new file mode 100644 index 0000000..24dff0a --- /dev/null +++ b/launcher.c @@ -0,0 +1,237 @@ +/* + * launcher.c -- functions for launching web browsers for browser-switchboard + * + * Copyright (C) 2009 Steven Luo + * Derived from a Python implementation by Jason Simpson and Steven Luo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "browser-switchboard.h" +#include "launcher.h" +#include "dbus-server-bindings.h" + +#define LAUNCH_DEFAULT_BROWSER launch_tear + +static void launch_tear(struct swb_context *ctx, char *uri) { + int status; + static DBusGProxy *tear_proxy = NULL; + GError *error = NULL; + pid_t pid; + + if (!uri) + uri = "new_window"; + + printf("launch_tear with uri '%s'\n", uri); + + status = system("pidof tear > /dev/null"); + if (WIFEXITED(status) && !WEXITSTATUS(status)) { + if (!tear_proxy) + tear_proxy = dbus_g_proxy_new_for_name(ctx->session_bus, + "com.nokia.tear", "/com/nokia/tear", + "com.nokia.Tear"); + dbus_g_proxy_call(tear_proxy, "OpenAddress", &error, + G_TYPE_STRING, uri, G_TYPE_INVALID); + if (!ctx->continuous_mode) + exit(0); + } else { + if (ctx->continuous_mode) { + if ((pid = fork()) != 0) { + /* Parent process or error in fork() */ + printf("child: %d\n", (int)pid); + return; + } + /* Child process */ + setsid(); + } + execl("/usr/bin/tear", "/usr/bin/tear", uri, (char *)NULL); + } +} + +void launch_microb(struct swb_context *ctx, char *uri) { + int kill_browserd = 0; + int status; + pid_t pid; + + if (!uri) + uri = "new_window"; + + status = system("pidof /usr/sbin/browserd > /dev/null"); + if (WIFEXITED(status) && WEXITSTATUS(status)) { + kill_browserd = 1; + system("/usr/sbin/browserd -d"); + } + + dbus_release_osso_browser_name(ctx); + + if ((pid = fork()) == -1) { + perror("fork"); + exit(1); + } + if (pid > 0) { + /* Parent process */ + waitpid(pid, &status, 0); + } else { + /* Child process */ + if (!strcmp(uri, "new_window")) { + execl("/usr/bin/maemo-invoker", + "browser", (char *)NULL); + } else { + execl("/usr/bin/maemo-invoker", + "browser", "--url", uri, (char *)NULL); + } + } + + if (kill_browserd) + system("kill `pidof /usr/sbin/browserd`"); + + if (!ctx || !ctx->continuous_mode) + exit(0); + + dbus_request_osso_browser_name(ctx); +} + +static void launch_other_browser(struct swb_context *ctx, char *uri) { + char *command; + char *quoted_uri, *quote; + + size_t cmdlen, urilen; + size_t quoted_uri_size; + size_t offset; + + if (!uri || !strcmp(uri, "new_window")) + uri = ""; + urilen = strlen(uri); + if (urilen > 0) { + /* Quote the URI */ + /* urilen+3 = length of URI + 2x \' + \0 */ + if (!(quoted_uri = calloc(urilen+3, sizeof(char)))) + exit(1); + snprintf(quoted_uri, urilen+3, "'%s'", uri); + + /* If there are any 's in the original URI, URL-escape them + (replace them with %27) */ + quoted_uri_size = urilen + 3; + quote = quoted_uri + 1; + while ((quote = strchr(quote, '\'')) && + (offset = quote-quoted_uri) < strlen(quoted_uri)-1) { + /* Check to make sure we don't shrink the memory area + as a result of integer overflow */ + if (quoted_uri_size+2 <= quoted_uri_size) + exit(1); + + /* Grow the memory area; + 2 = strlen("%27")-strlen("'") */ + if (!(quoted_uri = realloc(quoted_uri, + quoted_uri_size+2))) + exit(1); + quoted_uri_size = quoted_uri_size + 2; + + /* Recalculate the location of the ' character -- + realloc() may have moved the string in memory */ + quote = quoted_uri + offset; + + /* Move the string after the ', including the \0, + over two chars */ + memmove(quote+3, quote+1, strlen(quote)); + memcpy(quote, "%27", 3); + quote = quote + 3; + } + urilen = strlen(quoted_uri); + } else + quoted_uri = uri; + + cmdlen = strlen(ctx->other_browser_cmd); + + /* cmdlen+urilen+1 is normally two bytes longer than we need (uri will + replace "%s"), but is needed in the case other_browser_cmd has no %s + and urilen < 2 */ + if (!(command = calloc(cmdlen+urilen+1, sizeof(char)))) + exit(1); + snprintf(command, cmdlen+urilen+1, ctx->other_browser_cmd, quoted_uri); + printf("command: '%s'\n", command); + + if (ctx->continuous_mode) { + if (fork() != 0) { + /* Parent process or error in fork() */ + if (urilen > 0) + free(quoted_uri); + free(command); + return; + } + /* Child process */ + setsid(); + } + execl("/bin/sh", "/bin/sh", "-c", command, (char *)NULL); +} + +static void use_other_browser_cmd(struct swb_context *ctx, char *cmd) { + size_t len = strlen(cmd); + + free(ctx->other_browser_cmd); + ctx->other_browser_cmd = calloc(len+1, sizeof(char)); + if (!ctx->other_browser_cmd) { + printf("malloc failed!\n"); + ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER; + } else { + ctx->other_browser_cmd = strncpy(ctx->other_browser_cmd, + cmd, len+1); + ctx->default_browser_launcher = launch_other_browser; + } +} + +void update_default_browser(struct swb_context *ctx, char *default_browser) { + if (!ctx) + return; + + if (!default_browser) { + ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER; + return; + } + + if (!strcmp(default_browser, "tear")) + ctx->default_browser_launcher = launch_tear; + else if (!strcmp(default_browser, "microb")) + ctx->default_browser_launcher = launch_microb; + else if (!strcmp(default_browser, "fennec")) + use_other_browser_cmd(ctx, "fennec %s"); + else if (!strcmp(default_browser, "midori")) + use_other_browser_cmd(ctx, "midori %s"); + else if (!strcmp(default_browser, "other")) { + if (ctx->other_browser_cmd) + ctx->default_browser_launcher = launch_other_browser; + else { + printf("default_browser is 'other', but no other_browser_cmd set -- using default\n"); + ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER; + } + } else { + printf("Unknown default_browser %s, using default", default_browser); + ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER; + } +} + +void launch_browser(struct swb_context *ctx, char *uri) { + if (ctx && ctx->default_browser_launcher) + ctx->default_browser_launcher(ctx, uri); +} diff --git a/launcher.h b/launcher.h new file mode 100644 index 0000000..c3ad5b9 --- /dev/null +++ b/launcher.h @@ -0,0 +1,32 @@ +/* + * launcher.h -- definitions for the browser launching functions + * + * Copyright (C) 2009 Steven Luo + * Derived from a Python implementation by Jason Simpson and Steven Luo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef _LAUNCHER_H +#define _LAUNCHER_H 1 + +#include "browser-switchboard.h" + +void launch_microb(struct swb_context *ctx, char *uri); +void launch_browser(struct swb_context *ctx, char *uri); +void update_default_browser(struct swb_context *ctx, char *default_browser); + +#endif /* _LAUNCHER_H */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..73ca570 --- /dev/null +++ b/main.c @@ -0,0 +1,221 @@ +/* + * main.c -- config file parsing and main loop for browser-switchboard + * + * Copyright (C) 2009 Steven Luo + * Derived from a Python implementation by Jason Simpson and Steven Luo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "browser-switchboard.h" +#include "launcher.h" +#include "dbus-server-bindings.h" + +#define DEFAULT_HOMEDIR "/home/user" +#define CONFIGFILE_LOC "/.config/browser-switchboard" +#define MAXLINE 1024 + +struct swb_context ctx; + +static void set_config_defaults(struct swb_context *ctx) { + if (!ctx) + return; + free(ctx->other_browser_cmd); + ctx->continuous_mode = 0; + ctx->default_browser_launcher = NULL; + ctx->other_browser_cmd = NULL; +} + +static void waitforzombies(int signalnum) { + while (waitpid(-1, NULL, WNOHANG) > 0) + printf("Waited for a zombie\n"); +} + +static void read_config(int signalnum) { + char *homedir, *configfile; + size_t len; + char buf[MAXLINE]; + char *key, *value; + char *default_browser = NULL; + FILE *fp; + regex_t re_ignore, re_config1, re_config2; + regmatch_t substrs[3]; + + set_config_defaults(&ctx); + + if (!(homedir = getenv("HOME"))) + homedir = DEFAULT_HOMEDIR; + len = strlen(homedir) + strlen(CONFIGFILE_LOC) + 1; + if (!(configfile = calloc(len, sizeof(char)))) + goto out_noopen; + snprintf(configfile, len, "%s%s", homedir, CONFIGFILE_LOC); + + if (!(fp = fopen(configfile, "r"))) + goto out_noopen; + + /* compile regex matching blank lines or comments */ + if (regcomp(&re_ignore, "^[[:space:]]*(#|$)", REG_EXTENDED|REG_NOSUB)) + goto out_nore; + /* compile regex matching foo = "bar", with arbitrary whitespace at + beginning and end of line and surrounding the = */ + if (regcomp(&re_config1, + "^[[:space:]]*([^=[:space:]]+)[[:space:]]*=[[:space:]]*\"(.*)\"[[:space:]]*$", + REG_EXTENDED)) { + regfree(&re_ignore); + goto out_nore; + } + /* compile regex matching foo = bar, with arbitrary whitespace at + beginning of line and surrounding the = */ + if (regcomp(&re_config2, + "^[[:space:]]*([^=[:space:]]+)[[:space:]]*=[[:space:]]*(.*)$", + REG_EXTENDED|REG_NEWLINE)) { + regfree(&re_ignore); + regfree(&re_config1); + goto out_nore; + } + + /* Read in the config file one line at a time and parse it + XXX doesn't deal with lines longer than MAXLINE */ + while (fgets(buf, MAXLINE, fp)) { + /* skip blank lines and comments */ + if (!regexec(&re_ignore, buf, 0, NULL, 0)) + continue; + + /* Find the substrings corresponding to the key and value + If the line doesn't match our idea of a config file entry, + skip it */ + if (regexec(&re_config1, buf, 3, substrs, 0) && + regexec(&re_config2, buf, 3, substrs, 0)) + continue; + if (substrs[1].rm_so == -1 || substrs[2].rm_so == -1) + continue; + + /* copy the config value into a new string */ + len = substrs[2].rm_eo - substrs[2].rm_so; + if (!(value = calloc(len+1, sizeof(char)))) + goto out; + strncpy(value, buf+substrs[2].rm_so, len); + /* calloc() zeroes the memory, so string is automatically + null terminated */ + + /* make key point to a null-terminated string holding the + config key */ + key = buf + substrs[1].rm_so; + buf[substrs[1].rm_eo] = '\0'; + + if (!strcmp(key, "continuous_mode")) { + ctx.continuous_mode = atoi(value); + free(value); + } else if (!strcmp(key, "default_browser")) { + if (!default_browser) + default_browser = value; + } else if (!strcmp(key, "other_browser_cmd")) { + if (!ctx.other_browser_cmd) + ctx.other_browser_cmd = value; + } else { + /* Don't need this line's contents */ + free(value); + } + value = NULL; + } + + printf("continuous_mode: %d\n", ctx.continuous_mode); + printf("default_browser: '%s'\n", default_browser?default_browser:"NULL"); + printf("other_browser_cmd: '%s'\n", ctx.other_browser_cmd?ctx.other_browser_cmd:"NULL"); + +out: + regfree(&re_ignore); + regfree(&re_config1); + regfree(&re_config2); +out_nore: + fclose(fp); +out_noopen: + update_default_browser(&ctx, default_browser); + free(configfile); + free(default_browser); + return; +} + +int main() { + OssoBrowser *obj_osso_browser, *obj_osso_browser_req; + GMainLoop *mainloop; + GError *error = NULL; + + read_config(0); + + if (ctx.continuous_mode) { + struct sigaction act; + act.sa_flags = SA_RESTART; + sigemptyset(&(act.sa_mask)); + + act.sa_handler = waitforzombies; + if (sigaction(SIGCHLD, &act, NULL) == -1) { + printf("Installing signal handler failed\n"); + return 1; + } + + act.sa_handler = read_config; + if (sigaction(SIGHUP, &act, NULL) == -1) { + printf("Installing signal handler failed\n"); + return 1; + } + } + + g_type_init(); + + dbus_g_object_type_install_info(OSSO_BROWSER_TYPE, + &dbus_glib_osso_browser_object_info); + + ctx.session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); + if (!ctx.session_bus) { + printf("Couldn't get a D-Bus bus connection\n"); + return 1; + } + ctx.dbus_proxy = dbus_g_proxy_new_for_name(ctx.session_bus, + "org.freedesktop.DBus", "/org/freedesktop/DBus", + "org.freedesktop.DBus"); + if (!ctx.dbus_proxy) { + printf("Couldn't get an org.freedesktop.DBus proxy\n"); + return 1; + } + + dbus_request_osso_browser_name(&ctx); + + obj_osso_browser = g_object_new(OSSO_BROWSER_TYPE, NULL); + obj_osso_browser_req = g_object_new(OSSO_BROWSER_TYPE, NULL); + dbus_g_connection_register_g_object(ctx.session_bus, + "/com/nokia/osso_browser", G_OBJECT(obj_osso_browser)); + dbus_g_connection_register_g_object(ctx.session_bus, + "/com/nokia/osso_browser/request", + G_OBJECT(obj_osso_browser_req)); + + mainloop = g_main_loop_new(NULL, FALSE); + printf("Starting main loop\n"); + g_main_loop_run(mainloop); + printf("Main loop completed\n"); + + return 0; +}