Add independent config file parsing functions
[browser-switch] / launcher.c
index b6c9ea4..6f25a28 100644 (file)
 #include "launcher.h"
 #include "dbus-server-bindings.h"
 
+#define DEFAULT_BROWSER "/usr/bin/tear"
 #define LAUNCH_DEFAULT_BROWSER launch_tear
 
-static void launch_tear(struct swb_context * ctx, char * uri) {
+static void launch_tear(struct swb_context *ctx, char *uri) {
        int status;
-       static DBusGProxy * tear_proxy = NULL;
-       GError * error = NULL;
+       static DBusGProxy *tear_proxy = NULL;
+       GError *error = NULL;
        pid_t pid;
 
        if (!uri)
@@ -45,18 +46,20 @@ static void launch_tear(struct swb_context * ctx, char * uri) {
 
        printf("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 star 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 invoking Tear with exec() if it's not running. */
        status = system("pidof tear > /dev/null");
-       if (!WIFEXITED(status))
-               exit(1);
-       if (!WEXITSTATUS(status)) {
+       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);
+               dbus_g_proxy_call(tear_proxy, "OpenAddress", &error,
+                                 G_TYPE_STRING, uri, G_TYPE_INVALID);
                if (!ctx->continuous_mode)
                        exit(0);
        } else {
@@ -73,7 +76,7 @@ static void launch_tear(struct swb_context * ctx, char * uri) {
        }
 }
 
-void launch_microb(struct swb_context * ctx, char * uri) {
+void launch_microb(struct swb_context *ctx, char *uri) {
        int kill_browserd = 0;
        int status;
        pid_t pid;
@@ -81,14 +84,16 @@ void launch_microb(struct swb_context * ctx, char * uri) {
        if (!uri)
                uri = "new_window";
 
+       printf("launch_microb with uri '%s'\n", uri);
+
+       /* Launch browserd if it's not running */
        status = system("pidof /usr/sbin/browserd > /dev/null");
-       if (!WIFEXITED(status))
-               exit(1);
-       if (WEXITSTATUS(status)) {
+       if (WIFEXITED(status) && WEXITSTATUS(status)) {
                kill_browserd = 1;
                system("/usr/sbin/browserd -d");
        }
 
+       /* Release the osso_browser D-Bus name so that MicroB can take it */
        dbus_release_osso_browser_name(ctx);
 
        if ((pid = fork()) == -1) {
@@ -100,15 +105,19 @@ void launch_microb(struct swb_context * ctx, char * uri) {
                waitpid(pid, &status, 0);
        } else {
                /* Child process */
+               /* 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 */
                if (!strcmp(uri, "new_window")) {
                        execl("/usr/bin/maemo-invoker",
-                                      "browser", (char *)NULL);
+                             "browser", (char *)NULL);
                } else {
                        execl("/usr/bin/maemo-invoker",
-                                       "browser", "--url", uri, (char *)NULL);
+                             "browser", "--url", uri, (char *)NULL);
                }
        }
 
+       /* Kill off browserd if we started it */
        if (kill_browserd)
                system("kill `pidof /usr/sbin/browserd`");
 
@@ -118,38 +127,51 @@ void launch_microb(struct swb_context * ctx, char * uri) {
        dbus_request_osso_browser_name(ctx);
 }
 
-static void launch_other_browser(struct swb_context * ctx, char * uri) {
-       char * command;
-       char * quoted_uri;
+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) {
-               char * quote;
 
-               /* Quote the URI */
+       printf("launch_other_browser with uri '%s'\n", uri);
+
+       if ((urilen = strlen(uri)) > 0) {
+               /* Quote the URI to prevent the shell from interpreting it */
                /* urilen+3 = length of URI + 2x \' + \0 */
                if (!(quoted_uri = calloc(urilen+3, sizeof(char))))
                        exit(1);
-               strncpy(quoted_uri+1, uri, urilen);
-               quoted_uri[0] = quoted_uri[urilen+1] = '\'';
-               /* calloc zeroes the memory, so string is automatically
-                  null terminated */
+               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, '\'')) &&
-                               (quote-quoted_uri) < strlen(quoted_uri)-1) {
-                       /* 3 = strlen("%27")-strlen("'") + \0 */
+                      (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,
-                                                       strlen(quoted_uri)+3)))
+                                                  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)+1);
+                       memmove(quote+3, quote+1, strlen(quote));
                        memcpy(quote, "%27", 3);
                        quote = quote + 3;
                }
@@ -181,7 +203,11 @@ static void launch_other_browser(struct swb_context * ctx, char * uri) {
        execl("/bin/sh", "/bin/sh", "-c", command, (char *)NULL);
 }
 
-static void use_other_browser_cmd(struct swb_context * ctx, char * cmd) {
+/* Use launch_other_browser as the default browser launcher, with the string
+   passed in as the other_browser_cmd
+   Resulting other_browser_cmd is always safe to free(), even if a pointer
+   to a string constant is passed in */
+static void use_other_browser_cmd(struct swb_context *ctx, char *cmd) {
        size_t len = strlen(cmd);
 
        free(ctx->other_browser_cmd);
@@ -191,18 +217,22 @@ static void use_other_browser_cmd(struct swb_context * ctx, char * cmd) {
                ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
        } else {
                ctx->other_browser_cmd = strncpy(ctx->other_browser_cmd,
-                               cmd, len);
-               ctx->other_browser_cmd[len] = '\0';
+                                                cmd, len+1);
                ctx->default_browser_launcher = launch_other_browser;
        }
 }
 
-void update_default_browser(struct swb_context * ctx, char * default_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;
+               /* No default_browser configured -- use DEFAULT_BROWSER if
+                  installed, otherwise launch MicroB */
+               if (!access(DEFAULT_BROWSER, X_OK))
+                       ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
+               else
+                       ctx->default_browser_launcher = launch_microb;
                return;
        }
 
@@ -211,6 +241,8 @@ void update_default_browser(struct swb_context * ctx, char * default_browser) {
        else if (!strcmp(default_browser, "microb"))
                ctx->default_browser_launcher = launch_microb;
        else if (!strcmp(default_browser, "fennec"))
+               /* Cheat and reuse launch_other_browser, since we don't appear
+                  to need to do anything special */
                use_other_browser_cmd(ctx, "fennec %s");
        else if (!strcmp(default_browser, "midori"))
                use_other_browser_cmd(ctx, "midori %s");
@@ -227,7 +259,7 @@ void update_default_browser(struct swb_context * ctx, char * default_browser) {
        }
 }
 
-void launch_browser(struct swb_context * ctx, char * uri) {
+void launch_browser(struct swb_context *ctx, char *uri) {
        if (ctx && ctx->default_browser_launcher)
                ctx->default_browser_launcher(ctx, uri);
 }