+
+#ifdef FREMANTLE
+/* 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);
+}
+
+/* Check to see whether MicroB is ready to handle D-Bus requests yet
+ See the comments in microb_start_dbus_watch_* 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 new is not an empty string, then the name has been acquired, and
+ MicroB should be ready to handle our request */
+ if (strlen(new) > 0) {
+ log_msg("MicroB ready\n");
+ microb_started = 1;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+/* Set up the D-Bus eavesdropping we'll use to watch for MicroB acquiring the
+ com.nokia.osso_browser D-Bus name.
+
+ Ideas for how to do this monitoring derived from the dbus-monitor code
+ (tools/dbus-monitor.c in the D-Bus codebase). */
+DBusConnection *microb_start_dbus_watch_init(void) {
+ DBusConnection *conn;
+ DBusError dbus_error;
+ DBusHandleMessageFunction filter_func = check_microb_started;
+
+ dbus_error_init(&dbus_error);
+
+ conn = dbus_bus_get_private(DBUS_BUS_SESSION, &dbus_error);
+ if (!conn) {
+ log_msg("Failed to open connection to session bus: %s\n",
+ dbus_error.message);
+ dbus_error_free(&dbus_error);
+ return NULL;
+ }
+
+ dbus_bus_add_match(conn,
+ "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);
+ return NULL;
+ }
+ if (!dbus_connection_add_filter(conn, filter_func, NULL, NULL)) {
+ log_msg("Failed to set up watch filter!\n");
+ return NULL;
+ }
+
+ return conn;
+}
+
+/* Wait for MicroB to acquire the com.nokia.osso_browser D-Bus name
+ Blocks until name is acquired, then returns */
+void microb_start_dbus_watch_wait(DBusConnection *conn) {
+ microb_started = 0;
+ log_msg("Waiting for MicroB to start\n");
+ while (!microb_started &&
+ dbus_connection_read_write_dispatch(conn, -1));
+}
+
+/* Tear down the D-Bus watch for acquiring com.nokia.osso-browser */
+void microb_start_dbus_watch_remove(DBusConnection *conn) {
+ DBusError dbus_error;
+ DBusHandleMessageFunction filter_func = check_microb_started;
+
+ dbus_error_init(&dbus_error);
+
+ dbus_connection_remove_filter(conn, filter_func, NULL);
+ dbus_bus_remove_match(conn,
+ "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(conn);
+ dbus_connection_unref(conn);
+}
+
+/* Start a new MicroB browser process if one isn't already running */
+pid_t launch_microb_start_browser_process(DBusConnection *conn, int fd) {
+ pid_t pid;
+ int status;
+
+ status = system("pidof browser > /dev/null");
+ if (WIFEXITED(status) && !WEXITSTATUS(status)) {
+ /* MicroB browser already running */
+ return 0;
+ }
+
+ if ((pid = fork()) == -1) {
+ log_perror(errno, "fork");
+ return -1;
+ }
+
+ if (!pid) {
+ /* Child process */
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+ if (fd != -1)
+ 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);
+
+ /* If we get here, exec() failed */
+ exit(1);
+ }
+
+ return pid;
+}
+
+/* Open a MicroB window using the D-Bus interface
+ It's assumed that we have already released the D-Bus name and that it's been
+ ensured that MicroB has acquired com.nokia.osso_browser (otherwise this will
+ cause D-Bus to try forever to launch another browser-switchboard) */
+
+#define LAUNCH_MICROB_BOOKMARK_WIN_OK 0x1
+
+int launch_microb_open_window(struct swb_context *ctx, char *uri,
+ int flags) {
+ DBusGProxy *g_proxy;
+ GError *gerror = NULL;
+
+ 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");
+ return 0;
+ }
+
+ if (!strcmp(uri, "new_window")) {
+ if (flags & LAUNCH_MICROB_BOOKMARK_WIN_OK) {
+ 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);
+ g_error_free(gerror);
+ return 0;
+ }
+
+ return 1;
+ } else {
+ /* 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 */
+ uri = "about:blank";
+ }
+ }
+ if (!dbus_g_proxy_call(g_proxy, "open_new_window",
+ &gerror,
+ G_TYPE_STRING, uri,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+ log_msg("Opening window failed: %s\n", gerror->message);
+ g_error_free(gerror);
+ return 0;
+ }
+
+ g_object_unref(g_proxy);
+ return 1;
+}
+
+/* Launch Fremantle MicroB and kill it when the session is finished */
+void launch_microb_fremantle_with_kill(struct swb_context *ctx, char *uri) {