+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
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:'
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,
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).
`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:
%.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)
install -c -m 0644 $(APP).desktop $(DESTDIR)$(PREFIX)/share/applications/hildon-control-panel
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 install install-plugin app util diablo-hildon-app diablo-plugin fremantle-hildon-app fremantle-plugin
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+
+#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);
+}
#endif /* HILDON_CP_APPLET */
#endif /* HILDON */
-#include "configfile.h"
+#include "config.h"
#define CONTINUOUS_MODE_DEFAULT 0
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)" },
+ { "opera", "Opera Mobile" },
{ "midori", "Midori" },
{ "other", "Other" },
{ NULL, NULL },
};
-char *logger_name = NULL;
+struct swb_config orig_cfg;
struct config_widgets {
#if defined(HILDON) && defined(FREMANTLE)
}
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) {
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 */
#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;
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");
/* Event found, stop looking */
break;
memset(buf, '\0', 256);
- }
+ }
inotify_rm_watch(fd, inot_wd);
close(fd);
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) {
#include <stdlib.h>
#include <string.h>
#include <signal.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dbus/dbus-glib.h>
#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;
}