Merge commit 'v3.2' into test-branch
authorSteven Luo <steven+maemo@steven676.net>
Mon, 22 Feb 2010 10:03:38 +0000 (02:03 -0800)
committerSteven Luo <steven+maemo@steven676.net>
Mon, 22 Feb 2010 10:03:38 +0000 (02:03 -0800)
13 files changed:
Changelog
Makefile
README
browser
config-ui/Makefile
config-ui/browser-switchboard-cp.c
dbus-server-bindings.c
launcher.c
log.c [new file with mode: 0644]
log.h [new file with mode: 0644]
main.c
microb [new file with mode: 0755]
microb.desktop [new file with mode: 0644]

index 02456b9..4eb2902 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,23 @@
+version 3.2:
+* make the "Web" menu entry and /usr/bin/browser open the default browser, and
+  provide a new "MicroB" menu entry and /usr/bin/microb script for launching
+  MicroB; the previous behavior was counterintuitive and difficult to discover
+* Fremantle: fix launching and closing MicroB on Fremantle; thanks Faheem
+  Pervez and Uwe Kaminski for extensive testing
+* Fremantle: force the Ovi Store bookmark to open in MicroB, since Ovi Store
+  doesn't load in other browsers; thanks ToJa92 of t.m.o for reporting
+* add ability to send debug output to syslog and new config setting ("logging")
+  to control where debug output goes; thanks Faheem Pervez for the suggestion
+* close stdin/stdout/stderr in child processes before the exec(), to make debug
+  output on stdout less noisy
+* fix some abuses of the D-Bus API in launcher.c:launch_tear()
+* make sure a running browserd is detected correctly on all devices so that we
+  don't try to launch another one; thanks Faheem Pervez for reporting
+* ensure that only one browser-switchboard is active at any time
+* update build system; we now have "diablo" and "fremantle" targets that build
+  binaries for the selected OS release
+* link binaries with -Wl,--as-needed to eliminate unnecessary dependencies
+
 version 3.1:
 * add a new, more finger-friendly GUI for Fremantle, based on work by
   Faheem Pervez (build UI with EXTRA_CPPFLAGS=-DFREMANTLE)
index 33a52b8..65bb61e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,25 @@
 CC = gcc
 CFLAGS = -Wall -Os $(EXTRA_CFLAGS)
 CPPFLAGS = `pkg-config --cflags dbus-glib-1` $(EXTRA_CPPFLAGS)
-LDFLAGS = `pkg-config --libs dbus-glib-1` $(EXTRA_LDFLAGS)
+LDFLAGS = -Wl,--as-needed `pkg-config --libs dbus-glib-1` $(EXTRA_LDFLAGS)
 PREFIX = /usr
 
 APP = browser-switchboard
-obj = main.o launcher.o dbus-server-bindings.o configfile.o
+obj = main.o launcher.o dbus-server-bindings.o configfile.o log.o
+
+all:
+       @echo 'Usage:'
+       @echo '    make diablo -- build for Diablo'
+       @echo '    make fremantle -- build for Fremantle'
+diablo: $(APP)
+fremantle:
+       @$(MAKE) \
+           EXTRA_CPPFLAGS='-DFREMANTLE `pkg-config --cflags dbus-1` $(EXTRA_CPPFLAGS)' \
+           EXTRA_LDFLAGS='`pkg-config --libs dbus-1` $(EXTRA_LDFLAGS)' $(APP)
 
-all: $(APP)
 
 $(APP): dbus-server-glue.h $(obj)
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $(APP) $(obj)
+       $(CC) $(CFLAGS) -o $(APP) $(obj) $(LDFLAGS)
 
 dbus-server-glue.h:
        dbus-binding-tool --mode=glib-server --prefix="osso_browser" \
@@ -19,14 +28,17 @@ dbus-server-glue.h:
 strip: $(APP)
        strip $(APP)
 
-install: all
+install: $(APP)
        mkdir -p $(DESTDIR)$(PREFIX)/bin
        mkdir -p $(DESTDIR)$(PREFIX)/share/dbus-1/services
-       install -c -m 0755 browser-switchboard $(DESTDIR)$(PREFIX)/bin
+       mkdir -p $(DESTDIR)$(PREFIX)/share/applications/hildon
+       install -c -m 0755 $(APP) $(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
+       install -c -m 0755 microb $(DESTDIR)$(PREFIX)/bin
+       install -c -m 0644 microb.desktop $(DESTDIR)$(PREFIX)/share/applications/hildon
 
 clean:
-       rm -f $(APP) *.o dbus-server-glue.h
+       rm -f $(APP) $(obj) dbus-server-glue.h
 
-.PHONY: strip install
+.PHONY: strip install diablo fremantle
diff --git a/README b/README
index 0d8f327..d7e51d8 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 BROWSER SWITCHBOARD
-version 3.1
+version 3.2
 
 Browser Switchboard is a program which allows you to choose which
 browser to use as the default browser. It supports MicroB, Tear,
@@ -23,18 +23,20 @@ You can now select the default browser by using the Browser Switchboard
 applet in the Control Panel.  Links in most applications, locally-saved
 web pages opened from the file manager, and (for Maemo 4.x) entries in
 the Web sidebar panel will open in the browser that you select as the
-default.  If you don't configure a default browser, MicroB will continue
-to be used as the default browser.
+default.  Opening the "Web" menu entry and running "browser" from the
+shell will also cause your chosen default browser to open.  If you don't
+configure a default browser, MicroB will continue to be used as the
+default browser.
 
 No matter which browser you select as the default, MicroB can always be
-opened via the Web menu entry in the applications menu (for Maemo 4.x,
-located in the Internet menu by default), or by running "browser" from
-the shell.  While MicroB is open, it will receive all links from other
-applications; closing MicroB will restore your chosen default browser.
+opened via the MicroB menu entry in the applications menu (for Maemo
+4.x, installed in the Extras menu by default), or by running "microb"
+from the shell.  While MicroB is open, it will receive all links from
+other applications; closing MicroB will restore your chosen default
+browser.
 
-Some users have reported that a restart may be necessary to ensure that
-Browser Switchboard is functioning.  If you experience trouble after
-installing the package, try rebooting your device first.
+If you experience trouble after installing the package, try rebooting
+your device.  If that fixes things, please report this as a bug.
 
 
 Configuring the Default Browser by Hand:
@@ -72,10 +74,12 @@ default_browser = "tear"
 # other_browser_cmd: If default browser is "other", what program
 # to run (%s will be replaced by URI)
 #other_browser_cmd = "some_browser %s"
+# logging: Where log output should go: "stdout", "syslog", "none"
+#logging = "stdout"
 # END SAMPLE CONFIG FILE
 
 Lines beginning with # characters are comments and are ignored by the
-script.  [Each option corresponds directly to an option or option group
+script.  [Most options correspond directly to an option or option group
 in the configuration UI.]
 
 In continuous mode, Browser Switchboard keeps running in the background
@@ -104,6 +108,14 @@ at a shell.  [In the UI, setting "Default brower" to "Other" activates
 the "Command (%s for URI)" setting, which corresponds to the value of
 other_browser_cmd.]
 
+The logging option controls where Browser Switchboard sends its debug
+logging output to.  You should not need to change this unless you're
+debugging Browser Switchboard, and there is no UI for this option.  The
+default option is "stdout", which means you won't see output unless you
+run Browser Switchboard from the shell.  "syslog" will send the output
+to the system log (assuming you have a syslogd set up on your device),
+and "none" disables debug logging entirely.
+
 
 Browser Switchboard and MicroB's browserd:
 
@@ -119,9 +131,9 @@ memory, but add a few seconds to MicroB's load time.
 Uninstalling Browser Switchboard:
 
 Remove the Browser Switchboard package using the Application Manager,
-and everything should be back to normal.  A reboot may be necessary for
-changes to take effect -- if you experience problems, try restarting
-your device first.
+and everything should be back to normal.  If you experience problems
+after uninstalling, try restarting your device first; if that fixes
+things, please report this as a bug.
 
 
 Compiling Browser Switchboard:
@@ -140,12 +152,15 @@ SDK$ cd browser-switchboard-X.Y
 
 4. Compile:
 
-SDK$ make
-SDK$ make -C config-ui
+SDK$ make diablo
+SDK$ make -C config-ui diablo-plugin
+
+(Replace "diablo" with "fremantle" and "diablo-plugin" with
+"fremantle-plugin" if compiling for Fremantle.
 
-(If you want the standalone config application instead of the Control
+If you want the standalone config application instead of the Control
 Panel plugin, do 
-SDK$ make -C config-ui hildon-app
+SDK$ make -C config-ui diablo-hildon-app
 instead.
 
 If you're using the Scratchbox2-based SDK+, you want
@@ -189,10 +204,10 @@ Source code is hosted in a Git (http://git-scm.com/) repository on
 git.maemo.org.  You can get a copy of the current development version by
 cloning the repository:
 
-$ git clone https://git.maemo.org/projects/browser-switch
+$ git clone http://git.maemo.org/projects/browser-switch
 
 or you can browse the source using gitweb
-(https://git.maemo.org/projects/browser-switch/?p=browser-switch;a=summary).
+(http://git.maemo.org/projects/browser-switch/?p=browser-switch;a=summary).
 
 
 Maintainer:
diff --git a/browser b/browser
index 334523f..a94b7cd 100755 (executable)
--- a/browser
+++ b/browser
@@ -9,11 +9,5 @@ case "$1" in
                ;;
 esac
 
-if pidof browser > /dev/null 2>&1; then
-       method=open_new_window
-else
-       method=switchboard_launch_microb
-fi
-
-dbus-send --session --type=method_call --print-reply --dest="com.nokia.osso_browser" /com/nokia/osso_browser/request com.nokia.osso_browser.$method string:${url:-"new_window"} > /dev/null 2>&1
+dbus-send --session --type=method_call --print-reply --dest="com.nokia.osso_browser" /com/nokia/osso_browser/request com.nokia.osso_browser.open_new_window string:${url:-"new_window"} > /dev/null 2>&1
 exit 0
index 42f2003..8bc3749 100644 (file)
@@ -5,7 +5,7 @@ CPPFLAGS = -I../ `pkg-config --cflags gtk+-2.0` $(EXTRA_CPPFLAGS)
 CPPFLAGS_HILDON = -DHILDON `pkg-config --cflags hildon-1`
 CPPFLAGS_PLUGIN = $(CPPFLAGS_HILDON) -DHILDON_CP_APPLET \
        `pkg-config --cflags libosso` `pkg-config --cflags hildon-control-panel`
-LDFLAGS = `pkg-config --libs gtk+-2.0` $(EXTRA_LDFLAGS)
+LDFLAGS = -Wl,--as-needed `pkg-config --libs gtk+-2.0` $(EXTRA_LDFLAGS)
 LDFLAGS_HILDON = `pkg-config --libs hildon-1`
 LDFLAGS_PLUGIN = -shared $(LDFLAGS_HILDON) \
        `pkg-config --libs libosso` `pkg-config --libs hildon-control-panel`
@@ -20,44 +20,55 @@ happ_obj = $(APP).happ.o $(other_obj)
 PLUGIN = lib$(APP).so
 plugin_obj = $(APP).plugin.o ../configfile.plugin.o
 
-all: plugin
-plugin: $(PLUGIN)
+all:
+       @echo 'Usage:'
+       @echo '    make app -- build standalone GTK+ application'
+       @echo '    make diablo-hildon-app -- build standalone Diablo Hildon application'
+       @echo '    make diablo-plugin -- build Diablo hildon-control-panel plugin'
+       @echo '    make fremantle-hildon-app -- build standalone Fremantle Hildon application'
+       @echo '    make fremantle-plugin -- build Fremantle hildon-control-panel plugin'
 app: $(APP)
-hildon-app: $(HILDON_APP)
+diablo-hildon-app: $(HILDON_APP)
+diablo-plugin: $(PLUGIN)
+fremantle-hildon-app:
+       @$(MAKE) EXTRA_CPPFLAGS='-DFREMANTLE $(EXTRA_CPPFLAGS)' $(HILDON_APP)
+fremantle-plugin:
+       @$(MAKE) EXTRA_CPPFLAGS='-DFREMANTLE $(EXTRA_CPPFLAGS)' $(PLUGIN)
 
 $(APP): $(app_obj)
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $(APP) $(app_obj)
+       $(CC) $(CFLAGS) -o $(APP) $(app_obj) $(LDFLAGS)
 
 %.app.o: %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 $(HILDON_APP): $(happ_obj)
-       $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_HILDON) \
-               -o $(HILDON_APP) $(happ_obj)
+       $(CC) $(CFLAGS) -o $(HILDON_APP) $(happ_obj) \
+               $(LDFLAGS) $(LDFLAGS_HILDON)
 
 %.happ.o: %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) $(CPPFLAGS_HILDON) -c -o $@ $<
 
 $(PLUGIN): $(plugin_obj)
-       $(CC) $(CFLAGS) $(CFLAGS_PLUGIN) $(LDFLAGS) $(LDFLAGS_PLUGIN) \
-               -o $(PLUGIN) $(plugin_obj)
+       $(CC) $(CFLAGS) $(CFLAGS_PLUGIN) -o $(PLUGIN) $(plugin_obj) \
+               $(LDFLAGS) $(LDFLAGS_PLUGIN)
+               
 
 %.plugin.o: %.c
        $(CC) $(CFLAGS) $(CFLAGS_PLUGIN) $(CPPFLAGS) $(CPPFLAGS_PLUGIN) \
                -c -o $@ $<
 
 strip: strip-plugin
-strip-plugin: plugin
+strip-plugin: $(PLUGIN)
        strip $(PLUGIN)
 
 install: install-plugin
-install-plugin: plugin
+install-plugin: $(PLUGIN)
        mkdir -p $(DESTDIR)$(PREFIX)/lib/hildon-control-panel
        mkdir -p $(DESTDIR)$(PREFIX)/share/applications/hildon-control-panel
        install -c -m 0755 $(PLUGIN) $(DESTDIR)$(PREFIX)/lib/hildon-control-panel
        install -c -m 0644 $(APP).desktop $(DESTDIR)$(PREFIX)/share/applications/hildon-control-panel
 
 clean:
-       rm -f $(APP) $(HILDON_APP) $(PLUGIN) *.o ../configfile.o
+       rm -f $(APP) $(HILDON_APP) $(PLUGIN) $(app_obj) $(happ_obj) $(plugin_obj)
 
-.PHONY: strip strip-plugin install install-plugin plugin app hildon-app
+.PHONY: strip strip-plugin install install-plugin app diablo-hildon-app diablo-plugin fremantle-hildon-app fremantle-plugin
index 13b0b48..c34778b 100644 (file)
@@ -72,6 +72,8 @@ struct browser_entry browsers[] = {
        { NULL, NULL },
 };
 
+char *logger_name = NULL;
+
 struct config_widgets {
 #if defined(HILDON) && defined(FREMANTLE)
        GtkWidget *continuous_mode_selector;
@@ -169,20 +171,25 @@ static void load_config(void) {
                                        set_continuous_mode(atoi(line.value));
                                        continuous_mode_seen = 1;
                                }
+                               free(line.value);
                        } else if (!strcmp(line.key, "default_browser")) {
                                if (!default_browser_seen) {
                                        set_default_browser(line.value);
                                        default_browser_seen = 1;
                                }
+                               free(line.value);
                        } else if (!strcmp(line.key, "other_browser_cmd")) {
                                if (!other_browser_cmd_seen) {
                                        set_other_browser_cmd(line.value);
                                        other_browser_cmd_seen = 1;
                                }
+                               free(line.value);
+                       } else if (!strcmp(line.key, "logging")) {
+                               if (!logger_name)
+                                       logger_name = line.value;
                        }
                }
                free(line.key);
-               free(line.value);
        }
        parse_config_file_end();
 
@@ -261,6 +268,15 @@ static void save_config(void) {
                                                        get_other_browser_cmd());
                                                other_browser_cmd_seen = 1;
                                        }
+                               } else if (!strcmp(line.key,
+                                                       "logging")) {
+                                       if (logger_name) {
+                                               fprintf(tmpfp, "%s = \"%s\"\n",
+                                                       line.key,
+                                                       logger_name);
+                                               free(logger_name);
+                                               logger_name = NULL;
+                                       }
                                }
                        } else {
                                /* Just copy the old line over */
@@ -282,6 +298,9 @@ static void save_config(void) {
        if (!other_browser_cmd_seen && strlen(get_other_browser_cmd()) > 0)
                fprintf(tmpfp, "%s = \"%s\"\n",
                        "other_browser_cmd", get_other_browser_cmd());
+       if (logger_name)
+               fprintf(tmpfp, "%s = \"%s\"\n",
+                       "logging", logger_name);
 
        /* Replace the old config file with the new one */
        fclose(tmpfp);
index 3875929..f20a690 100644 (file)
@@ -29,6 +29,7 @@
 #include "browser-switchboard.h"
 #include "launcher.h"
 #include "dbus-server-bindings.h"
+#include "log.h"
 
 extern struct swb_context ctx;
 
@@ -67,7 +68,7 @@ static void open_address(const char *uri) {
                /* Not much to do in this case ... */
                return;
 
-       printf("open_address '%s'\n", uri);
+       log_msg("open_address '%s'\n", uri);
        if (uri[0] == '/') {
                /* URI begins with a '/' -- assume it points to a local file
                   and prefix with "file://" */
@@ -81,6 +82,15 @@ static void open_address(const char *uri) {
                   we need to clean up after ourselves */
                free(new_uri);
        } else {
+#ifdef FREMANTLE
+               if (!strcmp(uri, "http://link.ovi.mobi/n900ovistore")) {
+                       /* Ovi Store webpage will not open correctly in
+                          any browser other than MicroB, so force the
+                          link in the provided bookmark to open in MicroB */
+                       launch_microb(&ctx, (char *)uri);
+                       return;
+               }
+#endif
                launch_browser(&ctx, (char *)uri);
        }
 }
@@ -117,12 +127,12 @@ gboolean osso_browser_top_application(OssoBrowser *obj,
                GError **error) {
        if (!ctx.continuous_mode)
                ignore_reconfig_requests();
-       launch_microb(&ctx, "new_window");
+       launch_browser(&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 */
+   for use by /usr/bin/microb wrapper */
 gboolean osso_browser_switchboard_launch_microb(OssoBrowser *obj,
                const char *uri, GError **error) {
        if (!ctx.continuous_mode)
@@ -146,11 +156,11 @@ void dbus_request_osso_browser_name(struct swb_context *ctx) {
                               G_TYPE_INVALID,
                               G_TYPE_UINT, &result,
                               G_TYPE_INVALID)) {
-               printf("Couldn't acquire name com.nokia.osso_browser\n");
+               log_msg("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");
+               log_msg("Couldn't acquire name com.nokia.osso_browser\n");
                exit(1);
        }
 }
index f738c63..77f2ded 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * launcher.c -- functions for launching web browsers for browser-switchboard
  *
- * Copyright (C) 2009 Steven Luo
+ * Copyright (C) 2009-2010 Steven Luo
  * Derived from a Python implementation by Jason Simpson and Steven Luo
  *
  * This program is free software; you can redistribute it and/or
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#include <errno.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <dbus/dbus-glib.h>
 
+#ifdef FREMANTLE
+#include <dbus/dbus.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/inotify.h>
+
+#define DEFAULT_HOMEDIR "/home/user"
+#define MICROB_PROFILE_DIR "/.mozilla/microb"
+#define MICROB_LOCKFILE "lock"
+#endif
+
 #include "browser-switchboard.h"
 #include "launcher.h"
 #include "dbus-server-bindings.h"
+#include "log.h"
 
 #define LAUNCH_DEFAULT_BROWSER launch_microb
 
+#ifdef FREMANTLE
+static int microb_started = 0;
+
+/* Check to see whether MicroB is ready to handle D-Bus requests yet
+   See the comments in launch_microb to understand how this works. */
+static DBusHandlerResult check_microb_started(DBusConnection *connection,
+                                    DBusMessage *message,
+                                    void *user_data) {
+       DBusError error;
+       char *name, *old, *new;
+
+       log_msg("Checking to see if MicroB is ready\n");
+       dbus_error_init(&error);
+       if (!dbus_message_get_args(message, &error,
+                                  DBUS_TYPE_STRING, &name,
+                                  DBUS_TYPE_STRING, &old,
+                                  DBUS_TYPE_STRING, &new,
+                                  DBUS_TYPE_INVALID)) {
+               log_msg("%s\n", error.message);
+               dbus_error_free(&error);
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       }
+       /* If old is an empty string, then the name has been acquired, and
+          MicroB should be ready to handle our request */
+       if (strlen(old) == 0) {
+               log_msg("MicroB ready\n");
+               microb_started = 1;
+       }
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+/* Get a browserd PID from the corresponding Mozilla profile lockfile */
+static pid_t get_browserd_pid(const char *lockfile) {
+       char buf[256], *tmp;
+
+       /* The lockfile is a symlink pointing to "[ipaddr]:+[pid]", so read in
+          the target of the symlink and parse it that way */
+       memset(buf, '\0', 256);
+       if (readlink(lockfile, buf, 255) == -1)
+               return -errno;
+       if (!(tmp = strstr(buf, ":+")))
+               return 0;
+       tmp += 2; /* Skip over the ":+" */
+
+       return atoi(tmp);
+}
+#endif
+
+/* Close stdin/stdout/stderr and replace with /dev/null */
+static int close_stdio(void) {
+       int fd;
+
+       if ((fd = open("/dev/null", O_RDWR)) == -1)
+               return -1;
+
+       if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1)
+               return -1;
+
+       close(fd);
+       return 0;
+}
+
 static void launch_tear(struct swb_context *ctx, char *uri) {
        int status;
        static DBusGProxy *tear_proxy = NULL;
@@ -43,7 +121,7 @@ static void launch_tear(struct swb_context *ctx, char *uri) {
        if (!uri)
                uri = "new_window";
 
-       printf("launch_tear with uri '%s'\n", uri);
+       log_msg("launch_tear with uri '%s'\n", uri);
 
        /* We should be able to just call the D-Bus service to open Tear ...
           but if Tear's not open, that cuases D-Bus to start Tear and then
@@ -53,23 +131,35 @@ static void launch_tear(struct swb_context *ctx, char *uri) {
           around by just invoking Tear with exec() if it's not running. */
        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 (!tear_proxy) {
+                       if (!(tear_proxy = dbus_g_proxy_new_for_name(
+                                               ctx->session_bus,
+                                               "com.nokia.tear",
+                                               "/com/nokia/tear",
+                                               "com.nokia.Tear"))) {
+                               log_msg("Failed to create proxy for com.nokia.Tear D-Bus interface\n");
+                               exit(1);
+                       }
+               }
+
+               if (!dbus_g_proxy_call(tear_proxy, "OpenAddress", &error,
+                                      G_TYPE_STRING, uri, G_TYPE_INVALID,
+                                      G_TYPE_INVALID)) {
+                       log_msg("Opening window failed: %s\n", error->message);
+                       exit(1);
+               }
                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);
+                               log_msg("child: %d\n", (int)pid);
                                return;
                        }
                        /* Child process */
                        setsid();
+                       close_stdio();
                }
                execl("/usr/bin/tear", "/usr/bin/tear", uri, (char *)NULL);
        }
@@ -79,31 +169,332 @@ void launch_microb(struct swb_context *ctx, char *uri) {
        int kill_browserd = 0;
        int status;
        pid_t pid;
+#ifdef FREMANTLE
+       char *homedir, *microb_profile_dir, *microb_lockfile;
+       size_t len;
+       int fd, inot_wd;
+       DBusConnection *raw_connection;
+       DBusError dbus_error;
+       DBusHandleMessageFunction filter_func;
+       DBusGProxy *g_proxy;
+       GError *gerror = NULL;
+       int bytes_read;
+       char buf[256], *pos;
+       struct inotify_event *event;
+       pid_t browserd_pid, waited_pid;
+       struct sigaction act, oldact;
+       int ignore_sigstop;
+#endif
 
        if (!uri)
                uri = "new_window";
 
-       printf("launch_microb with uri '%s'\n", uri);
+       log_msg("launch_microb with uri '%s'\n", uri);
 
        /* Launch browserd if it's not running */
-       status = system("pidof /usr/sbin/browserd > /dev/null");
+       status = system("pidof browserd > /dev/null");
        if (WIFEXITED(status) && WEXITSTATUS(status)) {
                kill_browserd = 1;
-               system("/usr/sbin/browserd -d");
+#ifdef FREMANTLE
+               system("/usr/sbin/browserd -d -b > /dev/null 2>&1");
+#else
+               system("/usr/sbin/browserd -d > /dev/null 2>&1");
+#endif
        }
 
        /* Release the osso_browser D-Bus name so that MicroB can take it */
        dbus_release_osso_browser_name(ctx);
 
+#ifdef FREMANTLE
+       /* Put together the path to the MicroB browserd lockfile */
+       if (!(homedir = getenv("HOME")))
+               homedir = DEFAULT_HOMEDIR;
+       len = strlen(homedir) + strlen(MICROB_PROFILE_DIR) + 1;
+       if (!(microb_profile_dir = calloc(len, sizeof(char)))) {
+               log_msg("calloc() failed\n");
+               exit(1);
+       }
+       snprintf(microb_profile_dir, len, "%s%s",
+                homedir, MICROB_PROFILE_DIR);
+       len = strlen(homedir) + strlen(MICROB_PROFILE_DIR) +
+             strlen("/") + strlen(MICROB_LOCKFILE) + 1;
+       if (!(microb_lockfile = calloc(len, sizeof(char)))) {
+               log_msg("calloc() failed\n");
+               exit(1);
+       }
+       snprintf(microb_lockfile, len, "%s%s/%s",
+                homedir, MICROB_PROFILE_DIR, MICROB_LOCKFILE);
+
+       /* Watch for the creation of a MicroB browserd lockfile
+          NB: The watch has to be set up here, before the browser
+          is launched, to make sure there's no race between browserd
+          starting and us creating the watch */
+       if ((fd = inotify_init()) == -1) {
+               log_perror(errno, "inotify_init");
+               exit(1);
+       }
+       if ((inot_wd = inotify_add_watch(fd, microb_profile_dir,
+                                        IN_CREATE)) == -1) {
+               log_perror(errno, "inotify_add_watch");
+               exit(1);
+       }
+       free(microb_profile_dir);
+
+       /* Set up the D-Bus eavesdropping we'll use to watch for MicroB
+          acquiring the com.nokia.osso_browser D-Bus name.  Again, this needs
+          to happen before the browser is launched, so that there's no race
+          between establishing the watch and browser startup.
+
+          Ideas for how to do this monitoring derived from the dbus-monitor
+          code (tools/dbus-monitor.c in the D-Bus codebase). */
+       dbus_error_init(&dbus_error);
+
+       raw_connection = dbus_bus_get_private(DBUS_BUS_SESSION, &dbus_error);
+       if (!raw_connection) {
+               log_msg("Failed to open connection to session bus: %s\n",
+                       dbus_error.message);
+               dbus_error_free(&dbus_error);
+               exit(1);
+       }
+
+       dbus_bus_add_match(raw_connection,
+                          "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.nokia.osso_browser'",
+                          &dbus_error);
+       if (dbus_error_is_set(&dbus_error)) {
+               log_msg("Failed to set up watch for browser UI start: %s\n",
+                       dbus_error.message);
+               dbus_error_free(&dbus_error);
+               exit(1);
+       }
+       filter_func = check_microb_started;
+       if (!dbus_connection_add_filter(raw_connection,
+                                       filter_func, NULL, NULL)) {
+               log_msg("Failed to set up watch filter!\n");
+               exit(1);
+       }
+
        if ((pid = fork()) == -1) {
-               perror("fork");
+               log_perror(errno, "fork");
                exit(1);
        }
+
        if (pid > 0) {
                /* Parent process */
+               /* Wait for our child to start the browser UI process and
+                  for it to acquire the com.nokia.osso_browser D-Bus name,
+                  then make the appropriate method call to open the browser
+                  window. */
+               microb_started = 0;
+               log_msg("Waiting for MicroB to start\n");
+               while (!microb_started &&
+                      dbus_connection_read_write_dispatch(raw_connection,
+                                                          -1));
+               dbus_connection_remove_filter(raw_connection,
+                                             filter_func, NULL);
+               dbus_bus_remove_match(raw_connection,
+                                     "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.nokia.osso_browser'",
+                                     &dbus_error);
+               if (dbus_error_is_set(&dbus_error))
+                       /* Don't really care -- about to disconnect from the
+                          bus anyhow */
+                       dbus_error_free(&dbus_error);
+               dbus_connection_close(raw_connection);
+               dbus_connection_unref(raw_connection);
+
+               /* Browser UI's started, send it the request for a new window
+                  via D-Bus */
+               g_proxy = dbus_g_proxy_new_for_name(ctx->session_bus,
+                               "com.nokia.osso_browser",
+                               "/com/nokia/osso_browser/request",
+                               "com.nokia.osso_browser");
+               if (!g_proxy) {
+                       log_msg("Couldn't get a com.nokia.osso_browser proxy\n");
+                       exit(1);
+               }
+               if (!strcmp(uri, "new_window")) {
+#if 0 /* Since we can't detect when the bookmark window closes, we'd have a
+        corner case where, if the user just closes the bookmark window
+        without opening any browser windows, we don't kill off MicroB or
+        resume handling com.nokia.osso_browser */
+                       if (!dbus_g_proxy_call(g_proxy, "top_application",
+                                              &gerror, G_TYPE_INVALID,
+                                              G_TYPE_INVALID)) {
+                               log_msg("Opening window failed: %s\n",
+                                       gerror->message);
+                               exit(1);
+                       }
+#endif
+                       if (!dbus_g_proxy_call(g_proxy, "load_url",
+                                              &gerror,
+                                              G_TYPE_STRING, "about:blank",
+                                              G_TYPE_INVALID,
+                                              G_TYPE_INVALID)) {
+                               log_msg("Opening window failed: %s\n",
+                                       gerror->message);
+                               exit(1);
+                       }
+               } else {
+                       if (!dbus_g_proxy_call(g_proxy, "load_url",
+                                              &gerror,
+                                              G_TYPE_STRING, uri,
+                                              G_TYPE_INVALID,
+                                              G_TYPE_INVALID)) {
+                               log_msg("Opening window failed: %s\n",
+                                       gerror->message);
+                               exit(1);
+                       }
+               }
+               g_object_unref(g_proxy);
+
+               /* Workaround: the browser process we started is going to want
+                  to hang around forever, hogging the com.nokia.osso_browser
+                  D-Bus interface while at it.  To fix this, we notice that
+                  when the last browser window closes, the browser UI restarts
+                  its attached browserd process.  Get the browserd process's
+                  PID and use ptrace() to watch for process termination.
+
+                  This has the problem of not being able to detect whether
+                  the bookmark window is open and/or in use, but it's the best
+                  that I can think of.  Better suggestions would be greatly
+                  appreciated. */
+
+               /* Wait for the MicroB browserd lockfile to be created */
+               log_msg("Waiting for browserd lockfile to be created\n");
+               memset(buf, '\0', 256);
+               /* read() blocks until there are events to be read */
+               while ((bytes_read = read(fd, buf, 255)) > 0) {
+                       pos = buf;
+                       /* Loop until we see the event we're looking for
+                          or until all the events are processed */
+                       while (pos && (pos-buf) < bytes_read) {
+                               event = (struct inotify_event *)pos;
+                               len = sizeof(struct inotify_event)
+                                     + event->len;
+                               if (!strcmp(MICROB_LOCKFILE,
+                                           event->name)) {
+                                       /* Lockfile created */
+                                       pos = NULL;
+                                       break;
+                               } else if ((pos-buf) + len < bytes_read)
+                                       /* More events to process */
+                                       pos += len;
+                               else
+                                       /* All events processed */
+                                       break;
+                       }
+                       if (!pos)
+                               /* Event found, stop looking */
+                               break;
+                       memset(buf, '\0', 256);
+                }
+               inotify_rm_watch(fd, inot_wd);
+               close(fd);
+
+               /* Get the PID of the browserd from the lockfile */
+               if ((browserd_pid = get_browserd_pid(microb_lockfile)) <= 0) {
+                       if (browserd_pid == 0)
+                               log_msg("Profile lockfile link lacks PID\n");
+                       else
+                               log_perror(-browserd_pid,
+                                          "readlink() on lockfile failed");
+                       exit(1);
+               }
+               free(microb_lockfile);
+
+               /* Wait for the browserd to close */
+               log_msg("Waiting for MicroB (browserd pid %d) to finish\n",
+                       browserd_pid);
+               /* Clear any existing SIGCHLD handler to prevent interference
+                  with our wait() */
+               act.sa_handler = SIG_DFL;
+               act.sa_flags = 0;
+               sigemptyset(&(act.sa_mask));
+               if (sigaction(SIGCHLD, &act, &oldact) == -1) {
+                       log_perror(errno, "clearing SIGCHLD handler failed");
+                       exit(1);
+               }
+
+               /* Trace the browserd to get a close notification */
+               ignore_sigstop = 1;
+               if (ptrace(PTRACE_ATTACH, browserd_pid, NULL, NULL) == -1) {
+                       log_perror(errno, "PTRACE_ATTACH");
+                       exit(1);
+               }
+               ptrace(PTRACE_CONT, browserd_pid, NULL, NULL);
+               while ((waited_pid = wait(&status)) > 0) {
+                       if (waited_pid != browserd_pid)
+                               /* Not interested in other processes */
+                               continue;
+                       if (WIFEXITED(status) || WIFSIGNALED(status))
+                               /* browserd exited */
+                               break;
+                       else if (WIFSTOPPED(status)) {
+                               /* browserd was sent a signal
+                                  We're responsible for making sure this
+                                  signal gets delivered */
+                               if (ignore_sigstop &&
+                                   WSTOPSIG(status) == SIGSTOP) {
+                                       /* Ignore the first SIGSTOP received
+                                          This is raised for some reason
+                                          immediately after we start tracing
+                                          the process, and won't be followed
+                                          by a SIGCONT at any point */
+                                       log_msg("Ignoring first SIGSTOP\n");
+                                       ptrace(PTRACE_CONT, browserd_pid,
+                                              NULL, NULL);
+                                       ignore_sigstop = 0;
+                                       continue;
+                               }
+                               log_msg("Forwarding signal %d to browserd\n",
+                                       WSTOPSIG(status));
+                               ptrace(PTRACE_CONT, browserd_pid,
+                                      NULL, WSTOPSIG(status));
+                       }
+               }
+
+               /* Kill off browser UI
+                  XXX: There is a race here with the restarting of the closed
+                  browserd; if that happens before we kill the browser UI, the
+                  newly started browserd may not close with the UI
+                  XXX: Hope we don't cause data loss here! */
+               log_msg("Killing MicroB\n");
+               kill(pid, SIGTERM);
                waitpid(pid, &status, 0);
+
+               /* Restore old SIGCHLD handler */
+               if (sigaction(SIGCHLD, &oldact, NULL) == -1) {
+                       log_perror(errno,
+                                  "restoring old SIGCHLD handler failed");
+                       exit(1);
+               }
        } else {
                /* Child process */
+               dbus_connection_close(raw_connection);
+               dbus_connection_unref(raw_connection);
+               close(fd);
+               close_stdio();
+
+               /* 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 */
+               /* Launch the browser in the background -- our parent will
+                  wait for it to claim the D-Bus name and then display the
+                  window using D-Bus */
+               execl("/usr/bin/maemo-invoker", "browser", (char *)NULL);
+       }
+#else /* !FREMANTLE */
+       if ((pid = fork()) == -1) {
+               log_perror(errno, "fork");
+               exit(1);
+       }
+
+       if (pid > 0) {
+               /* Parent process */
+               waitpid(pid, &status, 0);
+       } else {
+               /* Child process */
+               close_stdio();
+
                /* 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 */
@@ -115,10 +506,11 @@ void launch_microb(struct swb_context *ctx, char *uri) {
                              "browser", "--url", uri, (char *)NULL);
                }
        }
+#endif /* FREMANTLE */
 
        /* Kill off browserd if we started it */
        if (kill_browserd)
-               system("kill `pidof /usr/sbin/browserd`");
+               system("kill `pidof browserd`");
 
        if (!ctx || !ctx->continuous_mode) 
                exit(0);
@@ -137,7 +529,7 @@ static void launch_other_browser(struct swb_context *ctx, char *uri) {
        if (!uri || !strcmp(uri, "new_window"))
                uri = "";
 
-       printf("launch_other_browser with uri '%s'\n", uri);
+       log_msg("launch_other_browser with uri '%s'\n", uri);
 
        if ((urilen = strlen(uri)) > 0) {
                /* Quote the URI to prevent the shell from interpreting it */
@@ -186,7 +578,7 @@ static void launch_other_browser(struct swb_context *ctx, char *uri) {
        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);
+       log_msg("command: '%s'\n", command);
 
        if (ctx->continuous_mode) {
                if (fork() != 0) {
@@ -198,6 +590,7 @@ static void launch_other_browser(struct swb_context *ctx, char *uri) {
                }
                /* Child process */
                setsid();
+               close_stdio();
        }
        execl("/bin/sh", "/bin/sh", "-c", command, (char *)NULL);
 }
@@ -212,7 +605,7 @@ static void use_other_browser_cmd(struct swb_context *ctx, char *cmd) {
        free(ctx->other_browser_cmd);
        ctx->other_browser_cmd = calloc(len+1, sizeof(char));
        if (!ctx->other_browser_cmd) {
-               printf("malloc failed!\n");
+               log_msg("malloc failed!\n");
                ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
        } else {
                ctx->other_browser_cmd = strncpy(ctx->other_browser_cmd,
@@ -245,11 +638,12 @@ void update_default_browser(struct swb_context *ctx, char *default_browser) {
                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");
+                       log_msg("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);
+               log_msg("Unknown default_browser %s, using default",
+                       default_browser);
                ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
        }
 }
diff --git a/log.c b/log.c
new file mode 100644 (file)
index 0000000..36d0fd5
--- /dev/null
+++ b/log.c
@@ -0,0 +1,96 @@
+/*
+ * log.c -- logging functions for browser-switchboard
+ *
+ * Copyright (C) 2010 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 <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "log.h"
+
+#define DEFAULT_LOGGER LOGTO_STDOUT
+static enum {
+       LOGTO_NONE,
+       LOGTO_STDOUT,
+       LOGTO_SYSLOG,
+} logger = DEFAULT_LOGGER;
+
+/* Configure the logging target, performing any required setup for that
+   target */
+void log_config(char *logger_name) {
+       if (!logger_name) {
+               /* No logger configured, use the default log target */
+               logger = DEFAULT_LOGGER;
+               return;
+       }
+
+       if (!strcmp(logger_name, "stdout"))
+               logger = LOGTO_STDOUT;
+       else if (!strcmp(logger_name, "syslog")) {
+               /* XXX allow syslog facility to be configured? */
+               openlog("browser-switchboard", LOG_PID, LOG_USER);
+               logger = LOGTO_SYSLOG;
+       }
+       else if (!strcmp(logger_name, "none"))
+               logger = LOGTO_NONE;
+       else
+               /* Invalid logger configured, use the default log target */
+               logger = DEFAULT_LOGGER;
+
+       return;
+}
+
+/* Log output to the chosen log target */
+void log_msg(const char *format, ...) {
+       va_list ap;
+
+       if (!format)
+               return;
+
+       va_start(ap, format);
+       switch (logger) {
+               case LOGTO_NONE:
+                       break;
+               case LOGTO_SYSLOG:
+                       /* XXX allow syslog priority to be set by caller? */
+                       vsyslog(LOG_DEBUG, format, ap);
+                       break;
+               case LOGTO_STDOUT:
+               default:
+                       vprintf(format, ap);
+                       break;
+       }
+       va_end(ap);
+}
+
+/* Log strerror(errnum), with the string in prefix appended
+   Behaves like perror() except that it logs to chosen target, not stderr */
+void log_perror(int errnum, const char *prefix) {
+       char *errmsg;
+
+       if (!prefix)
+               return;
+       if (!(errmsg = strerror(errnum)))
+               return;
+
+       log_msg("%s: %s\n", prefix, errmsg);
+}
diff --git a/log.h b/log.h
new file mode 100644 (file)
index 0000000..350dbcc
--- /dev/null
+++ b/log.h
@@ -0,0 +1,30 @@
+/*
+ * log.h -- definitions for the logging functions
+ *
+ * Copyright (C) 2010 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 _LOG_H
+#define _LOG_H 1
+
+void log_config(char *logger_name);
+void log_msg(const char *format, ...);
+void log_perror(int errnum, const char *prefix);
+
+#endif /* _LOG_H */
diff --git a/main.c b/main.c
index 5296631..093b535 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
 /*
  * main.c -- config file parsing and main loop for browser-switchboard
  *
- * Copyright (C) 2009 Steven Luo
+ * Copyright (C) 2009-2010 Steven Luo
  * Derived from a Python implementation by Jason Simpson and Steven Luo
  *
  * This program is free software; you can redistribute it and/or
@@ -22,7 +22,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -32,6 +31,7 @@
 #include "launcher.h"
 #include "dbus-server-bindings.h"
 #include "configfile.h"
+#include "log.h"
 
 struct swb_context ctx;
 
@@ -46,14 +46,14 @@ static void set_config_defaults(struct swb_context *ctx) {
 
 static void waitforzombies(int signalnum) {
        while (waitpid(-1, NULL, WNOHANG) > 0)
-               printf("Waited for a zombie\n");
+               log_msg("Waited for a zombie\n");
 }
 
 static void read_config(int signalnum) {
        FILE *fp;
        int continuous_mode_seen = 0;
        struct swb_config_line line;
-       char *default_browser = NULL;
+       char *default_browser = NULL, *logger_name = NULL;
 
        set_config_defaults(&ctx);
 
@@ -78,6 +78,9 @@ static void read_config(int signalnum) {
                        } else if (!strcmp(line.key, "other_browser_cmd")) {
                                if (!ctx.other_browser_cmd)
                                        ctx.other_browser_cmd = line.value;
+                       } else if (!strcmp(line.key, "logging")) {
+                               if (!logger_name)
+                                       logger_name = line.value;
                        } else {
                                /* Don't need this line's contents */
                                free(line.value);
@@ -87,14 +90,21 @@ static void read_config(int signalnum) {
        }
        parse_config_file_end();
 
-       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:
        fclose(fp);
 out_noopen:
+       log_config(logger_name);
        update_default_browser(&ctx, default_browser);
+
+       log_msg("continuous_mode: %d\n", ctx.continuous_mode);
+       log_msg("default_browser: '%s'\n",
+               default_browser?default_browser:"NULL");
+       log_msg("other_browser_cmd: '%s'\n",
+               ctx.other_browser_cmd?ctx.other_browser_cmd:"NULL");
+       log_msg("logging: '%s'\n",
+               logger_name?logger_name:"NULL");
+
+       free(logger_name);
        free(default_browser);
        return;
 }
@@ -103,6 +113,7 @@ int main() {
        OssoBrowser *obj_osso_browser, *obj_osso_browser_req;
        GMainLoop *mainloop;
        GError *error = NULL;
+       int reqname_result;
 
        read_config(0);
 
@@ -115,14 +126,14 @@ int main() {
                /* SIGCHLD -- clean up after zombies */
                act.sa_handler = waitforzombies;
                if (sigaction(SIGCHLD, &act, NULL) == -1) {
-                       printf("Installing signal handler failed\n");
+                       log_msg("Installing signal handler failed\n");
                        return 1;
                }
 
                /* SIGHUP -- reread config file */
                act.sa_handler = read_config;
                if (sigaction(SIGHUP, &act, NULL) == -1) {
-                       printf("Installing signal handler failed\n");
+                       log_msg("Installing signal handler failed\n");
                        return 1;
                }
        }
@@ -135,14 +146,35 @@ int main() {
        /* Get a connection to the D-Bus session bus */
        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");
+               log_msg("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");
+               log_msg("Couldn't get an org.freedesktop.DBus proxy\n");
+               return 1;
+       }
+
+       /* Get the org.maemo.garage.browser-switchboard name from D-Bus, as
+          a form of locking to ensure that not more than one
+          browser-switchboard process is active at any time.  With
+          DBUS_NAME_FLAG_DO_NOT_QUEUE set and DBUS_NAME_FLAG_REPLACE_EXISTING
+          not set, getting the name succeeds if and only if no other
+          process owns the name. */
+       if (!dbus_g_proxy_call(ctx.dbus_proxy, "RequestName", &error,
+                              G_TYPE_STRING, "org.maemo.garage.browser-switchboard",
+                              G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+                              G_TYPE_INVALID,
+                              G_TYPE_UINT, &reqname_result,
+                              G_TYPE_INVALID)) {
+               log_msg("Couldn't acquire browser-switchboard lock: %s\n",
+                       error->message);
+               return 1;
+       }
+       if (reqname_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {  
+               log_msg("Another browser-switchboard already running\n");
                return 1;
        }
 
@@ -158,9 +190,9 @@ int main() {
                        G_OBJECT(obj_osso_browser_req));
 
        mainloop = g_main_loop_new(NULL, FALSE);
-       printf("Starting main loop\n");
+       log_msg("Starting main loop\n");
        g_main_loop_run(mainloop);
-       printf("Main loop completed\n");
+       log_msg("Main loop completed\n");
 
        return 0;
 }
diff --git a/microb b/microb
new file mode 100755 (executable)
index 0000000..334523f
--- /dev/null
+++ b/microb
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+case "$1" in
+       --url=* )
+               url="${1#--url=}"
+               ;;
+       --url )
+               url="$2"
+               ;;
+esac
+
+if pidof browser > /dev/null 2>&1; then
+       method=open_new_window
+else
+       method=switchboard_launch_microb
+fi
+
+dbus-send --session --type=method_call --print-reply --dest="com.nokia.osso_browser" /com/nokia/osso_browser/request com.nokia.osso_browser.$method string:${url:-"new_window"} > /dev/null 2>&1
+exit 0
diff --git a/microb.desktop b/microb.desktop
new file mode 100644 (file)
index 0000000..ecaae47
--- /dev/null
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Name=MicroB
+GenericName=Browser
+Comment=weba_ap_web_browser_thumb
+Exec=/usr/bin/microb
+Icon=qgn_list_browser
+Terminal=false
+Type=Application
+Categories=Application;Internet;
+X-HildonDesk-ShowInToolbar=true
+X-Osso-Type=application/x-executable