Make "make install" install the /usr/bin/browser wrapper and dbus service too
[browser-switch] / launcher.c
1 /*
2  * launcher.c -- functions for launching web browsers for browser-switchboard
3  *
4  * Copyright (C) 2009 Steven Luo
5  * Derived from a Python implementation by Jason Simpson and Steven Luo
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <dbus/dbus-glib.h>
30
31 #include "browser-switchboard.h"
32 #include "launcher.h"
33 #include "dbus-server-bindings.h"
34
35 #define LAUNCH_DEFAULT_BROWSER launch_tear
36
37 static void launch_tear(struct swb_context *ctx, char *uri) {
38         int status;
39         static DBusGProxy *tear_proxy = NULL;
40         GError *error = NULL;
41         pid_t pid;
42
43         if (!uri)
44                 uri = "new_window";
45
46         printf("launch_tear with uri '%s'\n", uri);
47
48         status = system("pidof tear > /dev/null");
49         if (!WIFEXITED(status))
50                 exit(1);
51         if (!WEXITSTATUS(status)) {
52                 if (!tear_proxy)
53                         tear_proxy = dbus_g_proxy_new_for_name(ctx->session_bus,
54                                         "com.nokia.tear", "/com/nokia/tear",
55                                         "com.nokia.Tear");
56                 dbus_g_proxy_call(tear_proxy, "OpenAddress", &error,
57                                   G_TYPE_STRING, uri, G_TYPE_INVALID);
58                 if (!ctx->continuous_mode)
59                         exit(0);
60         } else {
61                 if (ctx->continuous_mode) {
62                         if ((pid = fork()) != 0) {
63                                 /* Parent process or error in fork() */
64                                 printf("child: %d\n", (int)pid);
65                                 return;
66                         }
67                         /* Child process */
68                         setsid();
69                 }
70                 execl("/usr/bin/tear", "/usr/bin/tear", uri, (char *)NULL);
71         }
72 }
73
74 void launch_microb(struct swb_context *ctx, char *uri) {
75         int kill_browserd = 0;
76         int status;
77         pid_t pid;
78
79         if (!uri)
80                 uri = "new_window";
81
82         status = system("pidof /usr/sbin/browserd > /dev/null");
83         if (!WIFEXITED(status))
84                 exit(1);
85         if (WEXITSTATUS(status)) {
86                 kill_browserd = 1;
87                 system("/usr/sbin/browserd -d");
88         }
89
90         dbus_release_osso_browser_name(ctx);
91
92         if ((pid = fork()) == -1) {
93                 perror("fork");
94                 exit(1);
95         }
96         if (pid > 0) {
97                 /* Parent process */
98                 waitpid(pid, &status, 0);
99         } else {
100                 /* Child process */
101                 if (!strcmp(uri, "new_window")) {
102                         execl("/usr/bin/maemo-invoker",
103                               "browser", (char *)NULL);
104                 } else {
105                         execl("/usr/bin/maemo-invoker",
106                               "browser", "--url", uri, (char *)NULL);
107                 }
108         }
109
110         if (kill_browserd)
111                 system("kill `pidof /usr/sbin/browserd`");
112
113         if (!ctx || !ctx->continuous_mode) 
114                 exit(0);
115
116         dbus_request_osso_browser_name(ctx);
117 }
118
119 static void launch_other_browser(struct swb_context *ctx, char *uri) {
120         char *command;
121         char *quoted_uri, *quote;
122
123         size_t cmdlen, urilen;
124         size_t quoted_uri_size;
125         size_t offset;
126
127         if (!uri || !strcmp(uri, "new_window"))
128                 uri = "";
129         urilen = strlen(uri);
130         if (urilen > 0) {
131                 /* Quote the URI */
132                 /* urilen+3 = length of URI + 2x \' + \0 */
133                 if (!(quoted_uri = calloc(urilen+3, sizeof(char))))
134                         exit(1);
135                 snprintf(quoted_uri, urilen+3, "'%s'", uri);
136
137                 /* If there are any 's in the original URI, URL-escape them
138                    (replace them with %27) */
139                 quoted_uri_size = urilen + 3;
140                 quote = quoted_uri + 1;
141                 while ((quote = strchr(quote, '\'')) &&
142                        (offset = quote-quoted_uri) < strlen(quoted_uri)-1) {
143                         /* Check to make sure we don't shrink the memory area
144                            as a result of integer overflow */
145                         if (quoted_uri_size+2 <= quoted_uri_size)
146                                 exit(1);
147
148                         /* Grow the memory area;
149                            2 = strlen("%27")-strlen("'") */
150                         if (!(quoted_uri = realloc(quoted_uri,
151                                                    quoted_uri_size+2)))
152                                 exit(1);
153                         quoted_uri_size = quoted_uri_size + 2;
154
155                         /* Recalculate the location of the ' character --
156                            realloc() may have moved the string in memory */
157                         quote = quoted_uri + offset;
158
159                         /* Move the string after the ', including the \0,
160                            over two chars */
161                         memmove(quote+3, quote+1, strlen(quote)+1);
162                         memcpy(quote, "%27", 3);
163                         quote = quote + 3;
164                 }
165                 urilen = strlen(quoted_uri);
166         } else
167                 quoted_uri = uri;
168
169         cmdlen = strlen(ctx->other_browser_cmd);
170
171         /* cmdlen+urilen+1 is normally two bytes longer than we need (uri will
172            replace "%s"), but is needed in the case other_browser_cmd has no %s
173            and urilen < 2 */
174         if (!(command = calloc(cmdlen+urilen+1, sizeof(char))))
175                 exit(1);
176         snprintf(command, cmdlen+urilen+1, ctx->other_browser_cmd, quoted_uri);
177         printf("command: '%s'\n", command);
178
179         if (ctx->continuous_mode) {
180                 if (fork() != 0) {
181                         /* Parent process or error in fork() */
182                         if (urilen > 0)
183                                 free(quoted_uri);
184                         free(command);  
185                         return;
186                 }
187                 /* Child process */
188                 setsid();
189         }
190         execl("/bin/sh", "/bin/sh", "-c", command, (char *)NULL);
191 }
192
193 static void use_other_browser_cmd(struct swb_context *ctx, char *cmd) {
194         size_t len = strlen(cmd);
195
196         free(ctx->other_browser_cmd);
197         ctx->other_browser_cmd = calloc(len+1, sizeof(char));
198         if (!ctx->other_browser_cmd) {
199                 printf("malloc failed!\n");
200                 ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
201         } else {
202                 ctx->other_browser_cmd = strncpy(ctx->other_browser_cmd,
203                                                  cmd, len+1);
204                 ctx->default_browser_launcher = launch_other_browser;
205         }
206 }
207
208 void update_default_browser(struct swb_context *ctx, char *default_browser) {
209         if (!ctx)
210                 return;
211
212         if (!default_browser) {
213                 ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
214                 return;
215         }
216
217         if (!strcmp(default_browser, "tear"))
218                 ctx->default_browser_launcher = launch_tear;
219         else if (!strcmp(default_browser, "microb"))
220                 ctx->default_browser_launcher = launch_microb;
221         else if (!strcmp(default_browser, "fennec"))
222                 use_other_browser_cmd(ctx, "fennec %s");
223         else if (!strcmp(default_browser, "midori"))
224                 use_other_browser_cmd(ctx, "midori %s");
225         else if (!strcmp(default_browser, "other")) {
226                 if (ctx->other_browser_cmd)
227                         ctx->default_browser_launcher = launch_other_browser;
228                 else {
229                         printf("default_browser is 'other', but no other_browser_cmd set -- using default\n");
230                         ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
231                 }
232         } else {
233                 printf("Unknown default_browser %s, using default", default_browser);
234                 ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
235         }
236 }
237
238 void launch_browser(struct swb_context *ctx, char *uri) {
239         if (ctx && ctx->default_browser_launcher)
240                 ctx->default_browser_launcher(ctx, uri);
241 }