b6c9ea432ec6c0afa93be76e3b9617da2ba34b4e
[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",
57                                 &error,
58                                 G_TYPE_STRING, uri,
59                                 G_TYPE_INVALID);
60                 if (!ctx->continuous_mode)
61                         exit(0);
62         } else {
63                 if (ctx->continuous_mode) {
64                         if ((pid = fork()) != 0) {
65                                 /* Parent process or error in fork() */
66                                 printf("child: %d\n", (int)pid);
67                                 return;
68                         }
69                         /* Child process */
70                         setsid();
71                 }
72                 execl("/usr/bin/tear", "/usr/bin/tear", uri, (char *)NULL);
73         }
74 }
75
76 void launch_microb(struct swb_context * ctx, char * uri) {
77         int kill_browserd = 0;
78         int status;
79         pid_t pid;
80
81         if (!uri)
82                 uri = "new_window";
83
84         status = system("pidof /usr/sbin/browserd > /dev/null");
85         if (!WIFEXITED(status))
86                 exit(1);
87         if (WEXITSTATUS(status)) {
88                 kill_browserd = 1;
89                 system("/usr/sbin/browserd -d");
90         }
91
92         dbus_release_osso_browser_name(ctx);
93
94         if ((pid = fork()) == -1) {
95                 perror("fork");
96                 exit(1);
97         }
98         if (pid > 0) {
99                 /* Parent process */
100                 waitpid(pid, &status, 0);
101         } else {
102                 /* Child process */
103                 if (!strcmp(uri, "new_window")) {
104                         execl("/usr/bin/maemo-invoker",
105                                        "browser", (char *)NULL);
106                 } else {
107                         execl("/usr/bin/maemo-invoker",
108                                         "browser", "--url", uri, (char *)NULL);
109                 }
110         }
111
112         if (kill_browserd)
113                 system("kill `pidof /usr/sbin/browserd`");
114
115         if (!ctx || !ctx->continuous_mode) 
116                 exit(0);
117
118         dbus_request_osso_browser_name(ctx);
119 }
120
121 static void launch_other_browser(struct swb_context * ctx, char * uri) {
122         char * command;
123         char * quoted_uri;
124         size_t cmdlen, urilen;
125
126         if (!uri || !strcmp(uri, "new_window"))
127                 uri = "";
128         urilen = strlen(uri);
129         if (urilen > 0) {
130                 char * quote;
131
132                 /* Quote the URI */
133                 /* urilen+3 = length of URI + 2x \' + \0 */
134                 if (!(quoted_uri = calloc(urilen+3, sizeof(char))))
135                         exit(1);
136                 strncpy(quoted_uri+1, uri, urilen);
137                 quoted_uri[0] = quoted_uri[urilen+1] = '\'';
138                 /* calloc zeroes the memory, so string is automatically
139                    null terminated */
140
141                 /* If there are any 's in the original URI, URL-escape them
142                    (replace them with %27) */
143                 quote = quoted_uri + 1;
144                 while ((quote = strchr(quote, '\'')) &&
145                                 (quote-quoted_uri) < strlen(quoted_uri)-1) {
146                         /* 3 = strlen("%27")-strlen("'") + \0 */
147                         if (!(quoted_uri = realloc(quoted_uri,
148                                                         strlen(quoted_uri)+3)))
149                                 exit(1);
150                         /* Move the string after the ', including the \0,
151                            over two chars */
152                         memmove(quote+3, quote+1, strlen(quote)+1);
153                         memcpy(quote, "%27", 3);
154                         quote = quote + 3;
155                 }
156                 urilen = strlen(quoted_uri);
157         } else
158                 quoted_uri = uri;
159
160         cmdlen = strlen(ctx->other_browser_cmd);
161
162         /* cmdlen+urilen+1 is normally two bytes longer than we need (uri will
163            replace "%s"), but is needed in the case other_browser_cmd has no %s
164            and urilen < 2 */
165         if (!(command = calloc(cmdlen+urilen+1, sizeof(char))))
166                 exit(1);
167         snprintf(command, cmdlen+urilen+1, ctx->other_browser_cmd, quoted_uri);
168         printf("command: '%s'\n", command);
169
170         if (ctx->continuous_mode) {
171                 if (fork() != 0) {
172                         /* Parent process or error in fork() */
173                         if (urilen > 0)
174                                 free(quoted_uri);
175                         free(command);  
176                         return;
177                 }
178                 /* Child process */
179                 setsid();
180         }
181         execl("/bin/sh", "/bin/sh", "-c", command, (char *)NULL);
182 }
183
184 static void use_other_browser_cmd(struct swb_context * ctx, char * cmd) {
185         size_t len = strlen(cmd);
186
187         free(ctx->other_browser_cmd);
188         ctx->other_browser_cmd = calloc(len+1, sizeof(char));
189         if (!ctx->other_browser_cmd) {
190                 printf("malloc failed!\n");
191                 ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
192         } else {
193                 ctx->other_browser_cmd = strncpy(ctx->other_browser_cmd,
194                                 cmd, len);
195                 ctx->other_browser_cmd[len] = '\0';
196                 ctx->default_browser_launcher = launch_other_browser;
197         }
198 }
199
200 void update_default_browser(struct swb_context * ctx, char * default_browser) {
201         if (!ctx)
202                 return;
203
204         if (!default_browser) {
205                 ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
206                 return;
207         }
208
209         if (!strcmp(default_browser, "tear"))
210                 ctx->default_browser_launcher = launch_tear;
211         else if (!strcmp(default_browser, "microb"))
212                 ctx->default_browser_launcher = launch_microb;
213         else if (!strcmp(default_browser, "fennec"))
214                 use_other_browser_cmd(ctx, "fennec %s");
215         else if (!strcmp(default_browser, "midori"))
216                 use_other_browser_cmd(ctx, "midori %s");
217         else if (!strcmp(default_browser, "other")) {
218                 if (ctx->other_browser_cmd)
219                         ctx->default_browser_launcher = launch_other_browser;
220                 else {
221                         printf("default_browser is 'other', but no other_browser_cmd set -- using default\n");
222                         ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
223                 }
224         } else {
225                 printf("Unknown default_browser %s, using default", default_browser);
226                 ctx->default_browser_launcher = LAUNCH_DEFAULT_BROWSER;
227         }
228 }
229
230 void launch_browser(struct swb_context * ctx, char * uri) {
231         if (ctx && ctx->default_browser_launcher)
232                 ctx->default_browser_launcher(ctx, uri);
233 }