From: Steven Luo Date: Sun, 30 May 2010 10:19:24 +0000 (-0700) Subject: Merge commit 'diablo-package-3.3b1-1' into fremantle-package X-Git-Tag: fremantle-package-3.3b1-1fremantle1~2 X-Git-Url: http://git.maemo.org/git/?p=browser-switch;a=commitdiff_plain;h=007f12d8930bbef0998dc0d26806dbef0d7947b5;hp=505d6b3f7068e8eb1eab2cf094e69fe9341a941f Merge commit 'diablo-package-3.3b1-1' into fremantle-package --- diff --git a/Changelog b/Changelog index 4eb2902..120ab03 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,13 @@ +version 3.3: +* add support for Opera Mobile +* fall back to the built-in default if the user's configured default browser + isn't installed +* introduce a command-line config utility; this is mainly intended to give + browser vendors a way to set their browser as the default +* provide a description for users who don't know what MicroB is; thanks + Emanuele Cassioli for pointing out the need +* major rewrite of configuration loading/saving code + 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 diff --git a/Makefile b/Makefile index 65bb61e..e6e1bb8 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ 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 log.o +obj = main.o launcher.o dbus-server-bindings.o config.o configfile.o log.o all: @echo 'Usage:' diff --git a/README b/README index d7e51d8..2f36e77 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ BROWSER SWITCHBOARD -version 3.2 +version 3.3b1 Browser Switchboard is a program which allows you to choose which browser to use as the default browser. It supports MicroB, Tear, @@ -15,7 +15,9 @@ page on garage.maemo.org: https://garage.maemo.org/frs/?group_id=1159 Quick Start: 1. Download the binary package: browser-switchboard_X.Y-Z_all.deb (where X.Y-Z is the version number, of course). -2. Install the package using the Application Manager (open the +2. If you're using a Maemo 5 device, make sure all your MicroB browser +windows are closed. +3. Install the package using the Application Manager (open the Application Manager, then select Application->Install from file in the menu). diff --git a/config-ui/Makefile b/config-ui/Makefile index 8bc3749..bb7ad98 100644 --- a/config-ui/Makefile +++ b/config-ui/Makefile @@ -11,23 +11,27 @@ LDFLAGS_PLUGIN = -shared $(LDFLAGS_HILDON) \ `pkg-config --libs libosso` `pkg-config --libs hildon-control-panel` PREFIX = /usr -other_obj = ../configfile.o +other_obj = ../configfile.o ../config.o save-config.o APP = browser-switchboard-cp +UTIL = browser-switchboard-config app_obj = $(APP).app.o $(other_obj) +util_obj = $(UTIL).o $(other_obj) HILDON_APP = $(APP)-hildon happ_obj = $(APP).happ.o $(other_obj) PLUGIN = lib$(APP).so -plugin_obj = $(APP).plugin.o ../configfile.plugin.o +plugin_obj = $(APP).plugin.o ../configfile.plugin.o ../config.plugin.o save-config.plugin.o all: @echo 'Usage:' @echo ' make app -- build standalone GTK+ application' + @echo ' make util -- build command-line configuration utility' @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) +util: $(UTIL) diablo-hildon-app: $(HILDON_APP) diablo-plugin: $(PLUGIN) fremantle-hildon-app: @@ -41,6 +45,9 @@ $(APP): $(app_obj) %.app.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< +$(UTIL): $(util_obj) + $(CC) $(CFLAGS) -o $(UTIL) $(util_obj) $(LDFLAGS) + $(HILDON_APP): $(happ_obj) $(CC) $(CFLAGS) -o $(HILDON_APP) $(happ_obj) \ $(LDFLAGS) $(LDFLAGS_HILDON) @@ -57,18 +64,23 @@ $(PLUGIN): $(plugin_obj) $(CC) $(CFLAGS) $(CFLAGS_PLUGIN) $(CPPFLAGS) $(CPPFLAGS_PLUGIN) \ -c -o $@ $< -strip: strip-plugin +strip: strip-plugin strip-util strip-plugin: $(PLUGIN) strip $(PLUGIN) +strip-util: $(UTIL) + strip ($UTIL) -install: install-plugin +install: install-plugin install-util 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 +install-util: $(UTIL) + mkdir -p $(DESTDIR)$(PREFIX)/bin + install -c -m 0755 $(UTIL) $(DESTDIR)$(PREFIX)/bin clean: - rm -f $(APP) $(HILDON_APP) $(PLUGIN) $(app_obj) $(happ_obj) $(plugin_obj) + rm -f $(APP) $(UTIL) $(HILDON_APP) $(PLUGIN) $(app_obj) $(util_obj) $(happ_obj) $(plugin_obj) -.PHONY: strip strip-plugin install install-plugin app diablo-hildon-app diablo-plugin fremantle-hildon-app fremantle-plugin +.PHONY: strip strip-plugin strip-util install install-plugin install-util app util diablo-hildon-app diablo-plugin fremantle-hildon-app fremantle-plugin diff --git a/config-ui/browser-switchboard-config.c b/config-ui/browser-switchboard-config.c new file mode 100644 index 0000000..ec1e509 --- /dev/null +++ b/config-ui/browser-switchboard-config.c @@ -0,0 +1,199 @@ +/* + * browser-switchboard-config.c -- command-line configuration utility for + * Browser Switchboard + * + * Copyright (C) 2009-2010 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, 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 "config.h" + +extern struct swb_config_option swb_config_options[]; + +static int get_config_value(char *name) { + struct swb_config cfg; + struct swb_config_option *optinfo; + ptrdiff_t i; + int retval = 1; + + swb_config_init(&cfg); + + if (!swb_config_load(&cfg)) + return 1; + + for (optinfo = swb_config_options; optinfo->name; ++optinfo) { + if (strcmp(name, optinfo->name)) + continue; + + i = optinfo - swb_config_options; + switch (optinfo->type) { + case SWB_CONFIG_OPT_STRING: + if (*(char **)cfg.entries[i]) + printf("%s\n", *(char **)cfg.entries[i]); + break; + case SWB_CONFIG_OPT_INT: + printf("%d\n", *(int *)cfg.entries[i]); + break; + default: + break; + } + retval = 0; + break; + } + + swb_config_free(&cfg); + + return retval; +} + +static int set_config_value(char *name, char *value) { + struct swb_config cfg; + struct swb_config_option *optinfo; + ptrdiff_t i; + int retval = 1; + + swb_config_init(&cfg); + + if (!swb_config_load(&cfg)) + return 1; + + for (optinfo = swb_config_options; optinfo->name; ++optinfo) { + if (strcmp(name, optinfo->name)) + continue; + + i = optinfo - swb_config_options; + switch (optinfo->type) { + case SWB_CONFIG_OPT_STRING: + /* Free any existing string */ + if (cfg.flags & optinfo->set_mask) + free(*(char **)cfg.entries[i]); + + if (strlen(value) == 0) { + /* If the new value is empty, clear the config + setting */ + *(char **)cfg.entries[i] = NULL; + cfg.flags &= ~optinfo->set_mask; + } else { + /* Make a copy of the string -- it's not safe + to free value, which comes from argv */ + if (!(*(char **)cfg.entries[i] = + strdup(value))) + exit(1); + cfg.flags |= optinfo->set_mask; + } + break; + case SWB_CONFIG_OPT_INT: + if (strlen(value) == 0) { + /* If the new value is empty, clear the config + setting */ + cfg.flags &= ~optinfo->set_mask; + } else { + *(int *)cfg.entries[i] = atoi(value); + cfg.flags |= optinfo->set_mask; + } + break; + } + retval = 0; + break; + } + + if (!retval) + if (!swb_config_save(&cfg)) + retval = 1; + + swb_config_free(&cfg); + + /* Try to send SIGHUP to any running browser-switchboard process + This causes it to reread config files if in continuous_mode, or + die so that the config will be reloaded on next start otherwise */ + system("kill -HUP `pidof browser-switchboard` > /dev/null 2>&1"); + + return retval; +} + +void usage(void) { + printf("Usage:\n"); + printf(" browser-switchboard-config -b -- Display default browser\n"); + printf(" browser-switchboard-config -c -- Display command used when default browser is \"other\"\n"); + printf(" browser-switchboard-config -m -- Display continuous mode setting\n"); + printf(" browser-switchboard-config -o option -- Display value of option\n"); + printf("\n"); + printf(" browser-switchboard-config -s [-b|-c|-m|-o option] value -- Set the selected option to value\n"); + printf("\n"); + printf(" browser-switchboard-config -h -- Show this message\n"); +} + +int main(int argc, char **argv) { + int opt, done = 0; + int set = 0; + char *selected_opt = NULL; + + while (!done && (opt = getopt(argc, argv, "hsbcmo:")) != -1) { + switch (opt) { + case 'h': + usage(); + exit(0); + break; + case 's': + set = 1; + break; + case 'b': + selected_opt = "default_browser"; + done = 1; + break; + case 'c': + selected_opt = "other_browser_cmd"; + done = 1; + break; + case 'm': + selected_opt = "continuous_mode"; + done = 1; + break; + case 'o': + selected_opt = optarg; + done = 1; + break; + default: + usage(); + exit(1); + break; + } + } + + if (!selected_opt) { + printf("Must specify one of -b, -c, -m, -o\n"); + usage(); + exit(1); + } + + if (set) { + if (optind >= argc) { + printf("Value to set config option to not provided\n"); + usage(); + exit(1); + } + return set_config_value(selected_opt, argv[optind]); + } else + return get_config_value(selected_opt); +} diff --git a/config-ui/browser-switchboard-cp.c b/config-ui/browser-switchboard-cp.c index c34778b..b11fd2c 100644 --- a/config-ui/browser-switchboard-cp.c +++ b/config-ui/browser-switchboard-cp.c @@ -51,7 +51,7 @@ #endif /* HILDON_CP_APPLET */ #endif /* HILDON */ -#include "configfile.h" +#include "config.h" #define CONTINUOUS_MODE_DEFAULT 0 @@ -64,7 +64,7 @@ struct browser_entry { char *displayname; }; struct browser_entry browsers[] = { - { "microb", "MicroB" }, /* First entry is the default! */ + { "microb", "MicroB (stock browser)" }, /* First entry is the default! */ { "tear", "Tear" }, { "fennec", "Mobile Firefox (Fennec)" }, { "midori", "Midori" }, @@ -72,7 +72,7 @@ struct browser_entry browsers[] = { { NULL, NULL }, }; -char *logger_name = NULL; +struct swb_config orig_cfg; struct config_widgets { #if defined(HILDON) && defined(FREMANTLE) @@ -151,170 +151,40 @@ static inline void set_other_browser_cmd(char *cmd) { } static void load_config(void) { - FILE *fp; - int continuous_mode_seen = 0; - int default_browser_seen = 0; - int other_browser_cmd_seen = 0; - struct swb_config_line line; - - if (!(fp = open_config_file())) - return; - - /* Parse the config file - TODO: should we handle errors differently than EOF? */ - if (!parse_config_file_begin()) - goto out; - while (!parse_config_file_line(fp, &line)) { - if (line.parsed) { - if (!strcmp(line.key, "continuous_mode")) { - if (!continuous_mode_seen) { - 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); - } - parse_config_file_end(); - -out: - fclose(fp); - return; + swb_config_init(&orig_cfg); + + swb_config_load(&orig_cfg); + + set_continuous_mode(orig_cfg.continuous_mode); + set_default_browser(orig_cfg.default_browser); + if (orig_cfg.other_browser_cmd) + set_other_browser_cmd(orig_cfg.other_browser_cmd); } static void save_config(void) { - FILE *fp = NULL, *tmpfp = NULL; - char *homedir, *tempfile, *newfile; - size_t len; - int continuous_mode_seen = 0; - int default_browser_seen = 0; - int other_browser_cmd_seen = 0; - struct swb_config_line line; - - /* If CONFIGFILE_DIR doesn't exist already, try to create it */ - if (!(homedir = getenv("HOME"))) - homedir = DEFAULT_HOMEDIR; - len = strlen(homedir) + strlen(CONFIGFILE_DIR) + 1; - if (!(newfile = calloc(len, sizeof(char)))) - return; - snprintf(newfile, len, "%s%s", homedir, CONFIGFILE_DIR); - if (access(newfile, F_OK) == -1 && errno == ENOENT) { - mkdir(newfile, 0750); + struct swb_config new_cfg; + + swb_config_copy(&new_cfg, &orig_cfg); + + if (get_continuous_mode() != orig_cfg.continuous_mode) { + new_cfg.continuous_mode = get_continuous_mode(); + new_cfg.flags |= SWB_CONFIG_CONTINUOUS_MODE_SET; } - free(newfile); - - /* Put together the path to the new config file and the tempfile */ - len = strlen(homedir) + strlen(CONFIGFILE_LOC) + 1; - if (!(newfile = calloc(len, sizeof(char)))) - return; - /* 4 = strlen(".tmp") */ - if (!(tempfile = calloc(len+4, sizeof(char)))) { - free(newfile); - return; + if (strcmp(get_default_browser(), orig_cfg.default_browser)) { + new_cfg.default_browser = get_default_browser(); + new_cfg.flags |= SWB_CONFIG_DEFAULT_BROWSER_SET; } - snprintf(newfile, len, "%s%s", homedir, CONFIGFILE_LOC); - snprintf(tempfile, len+4, "%s%s", newfile, ".tmp"); - - /* Open the temporary file for writing */ - if (!(tmpfp = fopen(tempfile, "w"))) - /* TODO: report the error somehow? */ - goto out; - - /* Open the old config file, if it exists */ - if ((fp = open_config_file()) && parse_config_file_begin()) { - /* Copy the old config file over to the new one line by line, - replacing old config values with new ones - TODO: should we handle errors differently than EOF? */ - while (!parse_config_file_line(fp, &line)) { - if (line.parsed) { - /* Is a config line, print the new value here */ - if (!strcmp(line.key, "continuous_mode")) { - if (!continuous_mode_seen) { - fprintf(tmpfp, "%s = %d\n", - line.key, - get_continuous_mode()); - continuous_mode_seen = 1; - } - } else if (!strcmp(line.key, - "default_browser")) { - if (!default_browser_seen) { - fprintf(tmpfp, "%s = \"%s\"\n", - line.key, - get_default_browser()); - default_browser_seen = 1; - } - } else if (!strcmp(line.key, - "other_browser_cmd")) { - if (!other_browser_cmd_seen && - strlen(get_other_browser_cmd())>0) { - fprintf(tmpfp, "%s = \"%s\"\n", - line.key, - 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 */ - fprintf(tmpfp, "%s\n", line.key); - } - free(line.key); - free(line.value); - } - parse_config_file_end(); + if (strlen(get_other_browser_cmd()) == 0) { + new_cfg.other_browser_cmd = NULL; + new_cfg.flags &= ~SWB_CONFIG_OTHER_BROWSER_CMD_SET; + } else if (!(orig_cfg.other_browser_cmd && + !strcmp(get_other_browser_cmd(), + orig_cfg.other_browser_cmd))) { + new_cfg.other_browser_cmd = get_other_browser_cmd(); + new_cfg.flags |= SWB_CONFIG_OTHER_BROWSER_CMD_SET; } - /* If we haven't written them yet, write out the new config values */ - if (!continuous_mode_seen) - fprintf(tmpfp, "%s = %d\n", - "continuous_mode", get_continuous_mode()); - if (!default_browser_seen) - fprintf(tmpfp, "%s = \"%s\"\n", - "default_browser", get_default_browser()); - 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); - tmpfp = NULL; - rename(tempfile, newfile); - -out: - free(newfile); - free(tempfile); - if (tmpfp) - fclose(tmpfp); - if (fp) - fclose(fp); - return; + swb_config_save(&new_cfg); } static void do_reconfig(void) { diff --git a/config-ui/save-config.c b/config-ui/save-config.c new file mode 100644 index 0000000..4415b99 --- /dev/null +++ b/config-ui/save-config.c @@ -0,0 +1,147 @@ +/* + * save-config.c -- functions to save a Browser Switchboard configuration + * + * 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 + * 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 "configfile.h" +#include "config.h" + +extern struct swb_config_option swb_config_options[]; + +/* Outputs a config file line for the named option to a file descriptor */ +static void swb_config_output_option(FILE *fp, unsigned int *oldcfg_seen, + struct swb_config *cfg, char *name) { + struct swb_config_option *opt; + ptrdiff_t i; + + for (opt = swb_config_options; opt->name; ++opt) { + if (strcmp(opt->name, name)) + continue; + + i = opt - swb_config_options; + if (!(*oldcfg_seen & opt->set_mask) && + (cfg->flags & opt->set_mask)) { + switch (opt->type) { + case SWB_CONFIG_OPT_STRING: + fprintf(fp, "%s = \"%s\"\n", + opt->name, + *(char **)cfg->entries[i]); + *oldcfg_seen |= opt->set_mask; + break; + case SWB_CONFIG_OPT_INT: + fprintf(fp, "%s = %d\n", + opt->name, + *(int *)cfg->entries[i]); + *oldcfg_seen |= opt->set_mask; + break; + } + } + break; + } +} + +/* Save the settings in the provided swb_config struct to the config file + Returns true on success, false otherwise */ +int swb_config_save(struct swb_config *cfg) { + FILE *fp = NULL, *tmpfp = NULL; + char *homedir, *tempfile, *newfile; + size_t len; + int retval = 1; + struct swb_config_line line; + unsigned int oldcfg_seen = 0; + int i; + + /* If CONFIGFILE_DIR doesn't exist already, try to create it */ + if (!(homedir = getenv("HOME"))) + homedir = DEFAULT_HOMEDIR; + len = strlen(homedir) + strlen(CONFIGFILE_DIR) + 1; + if (!(newfile = calloc(len, sizeof(char)))) + return 0; + snprintf(newfile, len, "%s%s", homedir, CONFIGFILE_DIR); + if (access(newfile, F_OK) == -1 && errno == ENOENT) { + mkdir(newfile, 0750); + } + free(newfile); + + /* Put together the path to the new config file and the tempfile */ + len = strlen(homedir) + strlen(CONFIGFILE_LOC) + 1; + if (!(newfile = calloc(len, sizeof(char)))) + return 0; + /* 4 = strlen(".tmp") */ + if (!(tempfile = calloc(len+4, sizeof(char)))) { + free(newfile); + return 0; + } + snprintf(newfile, len, "%s%s", homedir, CONFIGFILE_LOC); + snprintf(tempfile, len+4, "%s%s", newfile, ".tmp"); + + /* Open the temporary file for writing */ + if (!(tmpfp = fopen(tempfile, "w"))) { + retval = 0; + goto out; + } + + /* Open the old config file, if it exists */ + if ((fp = open_config_file()) && parse_config_file_begin()) { + /* Copy the old config file over to the new one line by line, + replacing old config values with new ones + TODO: should we handle errors differently than EOF? */ + while (!parse_config_file_line(fp, &line)) { + if (line.parsed) { + /* Is a config line, print the new value here */ + swb_config_output_option(tmpfp, &oldcfg_seen, + cfg, line.key); + } else { + /* Just copy the old line over */ + fprintf(tmpfp, "%s\n", line.key); + } + free(line.key); + free(line.value); + } + parse_config_file_end(); + } + + /* If we haven't written them yet, write out any new config values */ + for (i = 0; swb_config_options[i].name; ++i) + swb_config_output_option(tmpfp, &oldcfg_seen, cfg, + swb_config_options[i].name); + + /* Replace the old config file with the new one */ + fclose(tmpfp); + tmpfp = NULL; + rename(tempfile, newfile); + +out: + free(newfile); + free(tempfile); + if (tmpfp) + fclose(tmpfp); + if (fp) + fclose(fp); + return retval; +} diff --git a/config.c b/config.c new file mode 100644 index 0000000..8928a3d --- /dev/null +++ b/config.c @@ -0,0 +1,161 @@ +/* + * config.c -- configuration functions for Browser Switchboard + * + * 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 + * 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 "configfile.h" +#include "config.h" + +/* The Browser Switchboard config file options */ +struct swb_config_option swb_config_options[] = { + { "continuous_mode", SWB_CONFIG_OPT_INT, SWB_CONFIG_CONTINUOUS_MODE_SET }, + { "default_browser", SWB_CONFIG_OPT_STRING, SWB_CONFIG_DEFAULT_BROWSER_SET }, + { "other_browser_cmd", SWB_CONFIG_OPT_STRING, SWB_CONFIG_OTHER_BROWSER_CMD_SET }, + { "logging", SWB_CONFIG_OPT_STRING, SWB_CONFIG_LOGGING_SET }, + { NULL, 0, 0 }, +}; + +/* Browser Switchboard configuration defaults */ +static struct swb_config swb_config_defaults = { + .flags = SWB_CONFIG_INITIALIZED, + .continuous_mode = 0, + .default_browser = "microb", + .other_browser_cmd = NULL, + .logging = "stdout", +}; + + +/* Copy the contents of an swb_config struct + The entries[] array means that the standard copy will not work */ +void swb_config_copy(struct swb_config *dst, struct swb_config *src) { + if (!dst || !src) + return; + + dst->entries[0] = &(dst->continuous_mode); + dst->entries[1] = &(dst->default_browser); + dst->entries[2] = &(dst->other_browser_cmd); + dst->entries[3] = &(dst->logging); + + dst->flags = src->flags; + + dst->continuous_mode = src->continuous_mode; + dst->default_browser = src->default_browser; + dst->other_browser_cmd = src->other_browser_cmd; + dst->logging = src->logging; +} + +/* Initialize a swb_config struct with configuration defaults */ +void swb_config_init(struct swb_config *cfg) { + swb_config_copy(cfg, &swb_config_defaults); +} + +/* Free all heap memory used in an swb_config struct + This MUST NOT be done if any of the strings are being used elsewhere! */ +void swb_config_free(struct swb_config *cfg) { + int i; + + if (!cfg) + return; + if (!(cfg->flags & SWB_CONFIG_INITIALIZED)) + return; + + for (i = 0; swb_config_options[i].name; ++i) { + if (cfg->flags & swb_config_options[i].set_mask) { + switch (swb_config_options[i].type) { + case SWB_CONFIG_OPT_STRING: + free(*(char **)cfg->entries[i]); + *(char **)cfg->entries[i] = NULL; + break; + default: + break; + } + } + } + + cfg->flags = 0; +} + +/* Load a value into the part of a struct swb_config indicated by name */ +static int swb_config_load_option(struct swb_config *cfg, + char *name, char *value) { + struct swb_config_option *opt; + ptrdiff_t i; + int retval = 0; + + for (opt = swb_config_options; opt->name; ++opt) { + if (strcmp(name, opt->name)) + continue; + + if (!(cfg->flags & opt->set_mask)) { + i = opt - swb_config_options; + switch (opt->type) { + case SWB_CONFIG_OPT_STRING: + *(char **)cfg->entries[i] = value; + break; + case SWB_CONFIG_OPT_INT: + *(int *)cfg->entries[i] = atoi(value); + free(value); + break; + } + cfg->flags |= opt->set_mask; + } + retval = 1; + break; + } + + if (!retval) + free(value); + + return retval; +} + +/* Read the config file and load settings into the provided swb_config struct + Caller is responsible for freeing allocated strings with free() + Returns true on success, false otherwise */ +int swb_config_load(struct swb_config *cfg) { + FILE *fp; + struct swb_config_line line; + + if (!cfg || !(cfg->flags & SWB_CONFIG_INITIALIZED)) + return 0; + + if (!(fp = open_config_file())) + goto out_noopen; + + /* Parse the config file + TODO: should we handle errors differently than EOF? */ + if (!parse_config_file_begin()) + goto out; + while (!parse_config_file_line(fp, &line)) { + if (line.parsed) + swb_config_load_option(cfg, line.key, line.value); + free(line.key); + } + parse_config_file_end(); + +out: + fclose(fp); +out_noopen: + return 1; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..858aec5 --- /dev/null +++ b/config.h @@ -0,0 +1,61 @@ +/* + * config.h -- definitions for Browser Switchboard configuration + * + * 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 + * 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 _CONFIG_H +#define _CONFIG_H + +#define SWB_CONFIG_INITIALIZED 0x01 +#define SWB_CONFIG_CONTINUOUS_MODE_SET 0x02 +#define SWB_CONFIG_DEFAULT_BROWSER_SET 0x04 +#define SWB_CONFIG_OTHER_BROWSER_CMD_SET 0x08 +#define SWB_CONFIG_LOGGING_SET 0x10 + +struct swb_config { + unsigned int flags; + /* Array of pointers to the elements of the struct, in the order given + in swb_config_options[] */ + void *entries[4]; + + int continuous_mode; + char *default_browser; + char *other_browser_cmd; + char *logging; +}; + +struct swb_config_option { + char *name; + enum { + SWB_CONFIG_OPT_STRING, + SWB_CONFIG_OPT_INT + } type; + int set_mask; +}; + +void swb_config_copy(struct swb_config *dst, struct swb_config *src); +void swb_config_init(struct swb_config *cfg); +void swb_config_free(struct swb_config *cfg); + +int swb_config_load(struct swb_config *cfg); + +int swb_config_save(struct swb_config *cfg); + +#endif /* _CONFIG_H */ diff --git a/debian/changelog b/debian/changelog index c9e8ca7..28645e3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,22 @@ +browser-switchboard (3.3~b1-1) extras-devel; urgency=low + + * New "upstream" development release. + * Upstream changes: + - add support for Opera Mobile + - fall back to the built-in default if the user's configured default + browser isn't installed + - introduce a command-line config utility; this is mainly intended to give + browser vendors a way to set their browser as the default + - provide a description for users who don't know what MicroB is; thanks + Emanuele Cassioli for pointing out the need + - major rewrite of configuration loading/saving code + * Cherry-pick addb0ed9... ("Add command-line utility to Makefile install + target"). + * Packaging changes: + - Build and install the new command-line config utility. + + -- Steven Luo Sun, 30 May 2010 02:52:31 -0700 + browser-switchboard (3.2-2fremantle1) extras-devel; urgency=low * Beta release for Fremantle. @@ -10,6 +29,7 @@ browser-switchboard (3.2-2fremantle1) extras-devel; urgency=low browser-switchboard (3.2-2) extras-devel; urgency=low * Cherry-pick ebfd6218... ("Add preliminary support for Opera Mobile"). + * Update package description to mention Opera Mobile. -- Steven Luo Fri, 28 May 2010 01:35:22 -0700 diff --git a/debian/rules b/debian/rules index 358cfd6..4eb9973 100755 --- a/debian/rules +++ b/debian/rules @@ -28,7 +28,7 @@ build-stamp: configure-stamp dh_testdir make EXTRA_CFLAGS="$(EXTRA_CFLAGS)" fremantle - make -C config-ui EXTRA_CFLAGS="$(EXTRA_CFLAGS)" fremantle-plugin + make -C config-ui EXTRA_CFLAGS="$(EXTRA_CFLAGS)" fremantle-plugin util touch $@ diff --git a/launcher.c b/launcher.c index 77f2ded..fe57eb9 100644 --- a/launcher.c +++ b/launcher.c @@ -47,7 +47,12 @@ #include "dbus-server-bindings.h" #include "log.h" -#define LAUNCH_DEFAULT_BROWSER launch_microb +struct browser_launcher { + char *name; + void (*launcher)(struct swb_context *, char *); + char *other_browser_cmd; + char *binary; +}; #ifdef FREMANTLE static int microb_started = 0; @@ -134,7 +139,7 @@ static void launch_tear(struct swb_context *ctx, char *uri) { if (!tear_proxy) { if (!(tear_proxy = dbus_g_proxy_new_for_name( ctx->session_bus, - "com.nokia.tear", + "com.nokia.tear", "/com/nokia/tear", "com.nokia.Tear"))) { log_msg("Failed to create proxy for com.nokia.Tear D-Bus interface\n"); @@ -386,7 +391,7 @@ void launch_microb(struct swb_context *ctx, char *uri) { /* Event found, stop looking */ break; memset(buf, '\0', 256); - } + } inotify_rm_watch(fd, inot_wd); close(fd); @@ -595,57 +600,83 @@ static void launch_other_browser(struct swb_context *ctx, char *uri) { execl("/bin/sh", "/bin/sh", "-c", command, (char *)NULL); } -/* 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); - ctx->other_browser_cmd = calloc(len+1, sizeof(char)); - if (!ctx->other_browser_cmd) { - log_msg("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; + +/* The list of known browsers and how to launch them */ +static struct browser_launcher browser_launchers[] = { + { "microb", launch_microb, NULL, NULL }, /* First entry is the default! */ + { "tear", launch_tear, NULL, "/usr/bin/tear" }, + { "fennec", NULL, "fennec %s", "/usr/bin/fennec" }, + { "opera", NULL, "opera %s", "/usr/bin/opera" }, + { "midori", NULL, "midori %s", "/usr/bin/midori" }, + { NULL, NULL, NULL, NULL }, +}; + +static void use_launcher_as_default(struct swb_context *ctx, + struct browser_launcher *browser) { + if (!ctx || !browser) + return; + + if (browser->launcher) + ctx->default_browser_launcher = browser->launcher; + else if (browser->other_browser_cmd) { + free(ctx->other_browser_cmd); + + /* Make a copy of the string constant so that + ctx->other_browser_cmd is safe to free() */ + ctx->other_browser_cmd = strdup(browser->other_browser_cmd); + if (!ctx->other_browser_cmd) { + log_msg("malloc failed!\n"); + /* Ideally, we'd configure the built-in default here -- + but it's possible we could be called in that path */ + exit(1); + } else + ctx->default_browser_launcher = launch_other_browser; } + + return; } void update_default_browser(struct swb_context *ctx, char *default_browser) { + struct browser_launcher *browser; + if (!ctx) return; - if (!default_browser) { + /* Configure the built-in default to start -- that way, we can + handle errors by just returning */ + use_launcher_as_default(ctx, &browser_launchers[0]); + + if (!default_browser) /* No default_browser configured -- use built-in default */ - 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")) - /* 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"); - else if (!strcmp(default_browser, "other")) { + /* Go through the list of known browser launchers and use one if + it matches */ + for (browser = browser_launchers; browser->name; ++browser) + if (!strcmp(default_browser, browser->name)) { + /* Make sure the user's choice is installed on the + system */ + if (browser->binary && access(browser->binary, X_OK)) { + log_msg("%s appears not to be installed\n", + default_browser); + } else { + use_launcher_as_default(ctx, browser); + return; + } + } + + /* Deal with default_browser = "other" */ + if (!strcmp(default_browser, "other")) { if (ctx->other_browser_cmd) ctx->default_browser_launcher = launch_other_browser; - else { + else log_msg("default_browser is 'other', but no other_browser_cmd set -- using default\n"); - ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER; - } - } else { - log_msg("Unknown default_browser %s, using default", - default_browser); - ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER; + return; } + + /* Unknown value of default_browser */ + log_msg("Unknown default_browser %s, using default\n", default_browser); + return; } void launch_browser(struct swb_context *ctx, char *uri) { diff --git a/main.c b/main.c index 093b535..40823e3 100644 --- a/main.c +++ b/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -30,82 +31,42 @@ #include "browser-switchboard.h" #include "launcher.h" #include "dbus-server-bindings.h" -#include "configfile.h" +#include "config.h" #include "log.h" 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) 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, *logger_name = NULL; - - set_config_defaults(&ctx); - - if (!(fp = open_config_file())) - goto out_noopen; - - /* Parse the config file - TODO: should we handle errors differently than EOF? */ - if (!parse_config_file_begin()) - goto out; - while (!parse_config_file_line(fp, &line)) { - if (line.parsed) { - if (!strcmp(line.key, "continuous_mode")) { - if (!continuous_mode_seen) { - ctx.continuous_mode = atoi(line.value); - continuous_mode_seen = 1; - } - free(line.value); - } else if (!strcmp(line.key, "default_browser")) { - if (!default_browser) - default_browser = line.value; - } 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); - } - } - free(line.key); - } - parse_config_file_end(); + struct swb_config cfg; -out: - fclose(fp); -out_noopen: - log_config(logger_name); - update_default_browser(&ctx, default_browser); + swb_config_init(&cfg); + + swb_config_load(&cfg); + + log_config(cfg.logging); + ctx.continuous_mode = cfg.continuous_mode; + free(ctx.other_browser_cmd); + if (cfg.other_browser_cmd) { + if (!(ctx.other_browser_cmd = strdup(cfg.other_browser_cmd))) { + log_perror(errno, "Failed to set other_browser_cmd"); + exit(1); + } + } else + ctx.other_browser_cmd = NULL; + update_default_browser(&ctx, cfg.default_browser); - log_msg("continuous_mode: %d\n", ctx.continuous_mode); - log_msg("default_browser: '%s'\n", - default_browser?default_browser:"NULL"); + log_msg("continuous_mode: %d\n", cfg.continuous_mode); + log_msg("default_browser: '%s'\n", cfg.default_browser); 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"); + cfg.other_browser_cmd?cfg.other_browser_cmd:"NULL"); + log_msg("logging: '%s'\n", cfg.logging); - free(logger_name); - free(default_browser); + swb_config_free(&cfg); return; }