2 * winebrowser - winelib app to launch native OS browser or mail client.
4 * Copyright (C) 2004 Chris Morgan
5 * Copyright (C) 2005 Hans Leidekker
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library 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 GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Winebrowser is a winelib application that will start the appropriate
23 * native browser or mail client for a wine installation that lacks a
24 * windows browser/mail client. For example, you will be able to open
25 * urls via native mozilla if no browser has yet been installed in wine.
27 * The application to launch is chosen from a default set or, if set,
28 * taken from a registry key.
30 * The argument may be a regular Windows file name, a file URL, an
31 * URL or a mailto URL. In the first three cases the argument
32 * will be fed to a web browser. In the last case the argument is fed
33 * to a mail client. A mailto URL is composed as follows:
35 * mailto:[E-MAIL]?subject=[TOPIC]&cc=[E-MAIL]&bcc=[E-MAIL]&body=[TEXT]
38 #define WIN32_LEAN_AND_MEAN
41 #include "wine/port.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(winebrowser
);
53 typedef LPSTR (*wine_get_unix_file_name_t
)(LPCWSTR unixname
);
55 /* try to launch an app from a comma separated string of app names */
56 static int launch_app( char *candidates
, const char *argv1
)
59 const char *argv_new
[3];
61 app
= strtok( candidates
, "," );
68 WINE_TRACE( "Considering: %s\n", app
);
69 WINE_TRACE( "argv[1]: %s\n", argv1
);
71 spawnvp( _P_OVERLAY
, app
, argv_new
); /* only returns on error */
72 app
= strtok( NULL
, "," ); /* grab the next app */
74 fprintf( stderr
, "winebrowser: could not find a suitable app to run\n" );
78 static int open_http_url( const char *url
)
80 static const char *defaultbrowsers
=
81 "xdg-open,firefox,konqueror,mozilla,netscape,galeon,opera,dillo";
88 length
= sizeof(browsers
);
89 /* @@ Wine registry key: HKCU\Software\Wine\WineBrowser */
90 if (!(r
= RegOpenKey( HKEY_CURRENT_USER
, "Software\\Wine\\WineBrowser", &key
)))
92 r
= RegQueryValueExA( key
, "Browsers", 0, &type
, (LPBYTE
)browsers
, &length
);
95 if (r
!= ERROR_SUCCESS
)
96 strcpy( browsers
, defaultbrowsers
);
98 return launch_app( browsers
, url
);
101 static int open_mailto_url( const char *url
)
103 static const char *defaultmailers
=
104 "xdg-email,mozilla-thunderbird,thunderbird,evolution";
111 length
= sizeof(mailers
);
112 /* @@ Wine registry key: HKCU\Software\Wine\WineBrowser */
113 if (!(r
= RegOpenKey( HKEY_CURRENT_USER
, "Software\\Wine\\WineBrowser", &key
)))
115 r
= RegQueryValueExA( key
, "Mailers", 0, &type
, (LPBYTE
)mailers
, &length
);
118 if (r
!= ERROR_SUCCESS
)
119 strcpy( mailers
, defaultmailers
);
121 return launch_app( mailers
, url
);
124 /*****************************************************************************
125 * DDE helper functions.
128 static char *ddeExec
= NULL
;
129 static HSZ hszTopic
= 0;
131 /* Dde callback, save the execute string for processing */
132 static HDDEDATA CALLBACK
ddeCb(UINT uType
, UINT uFmt
, HCONV hConv
,
133 HSZ hsz1
, HSZ hsz2
, HDDEDATA hData
,
134 ULONG_PTR dwData1
, ULONG_PTR dwData2
)
138 WINE_TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
139 uType
, uFmt
, hConv
, hsz1
, hsz2
, hData
, dwData1
, dwData2
);
144 if (!DdeCmpStringHandles(hsz1
, hszTopic
))
145 return (HDDEDATA
)TRUE
;
146 return (HDDEDATA
)FALSE
;
149 if (!(size
= DdeGetData(hData
, NULL
, 0, 0)))
150 WINE_ERR("DdeGetData returned zero size of execute string\n");
151 else if (!(ddeExec
= HeapAlloc(GetProcessHeap(), 0, size
)))
152 WINE_ERR("Out of memory\n");
153 else if (DdeGetData(hData
, (LPBYTE
)ddeExec
, size
, 0) != size
)
154 WINE_WARN("DdeGetData did not return %d bytes\n", size
);
155 DdeFreeDataHandle(hData
);
156 return (HDDEDATA
)DDE_FACK
;
163 static char *get_url_from_dde(void)
165 static const char szApplication
[] = "IExplore";
166 static const char szTopic
[] = "WWW_OpenURL";
168 HSZ hszApplication
= 0;
174 rc
= DdeInitializeA(&ddeInst
, ddeCb
, CBF_SKIP_ALLNOTIFICATIONS
| CBF_FAIL_ADVISES
|
175 CBF_FAIL_POKES
| CBF_FAIL_REQUESTS
, 0);
176 if (rc
!= DMLERR_NO_ERROR
)
178 WINE_ERR("Unable to initialize DDE, DdeInitialize returned %d\n", rc
);
182 hszApplication
= DdeCreateStringHandleA(ddeInst
, szApplication
, CP_WINANSI
);
185 WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
189 hszTopic
= DdeCreateStringHandleA(ddeInst
, szTopic
, CP_WINANSI
);
192 WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
196 if (!DdeNameService(ddeInst
, hszApplication
, 0, DNS_REGISTER
))
198 WINE_ERR("Unable to initialize DDE, DdeNameService failed\n");
202 timer
= SetTimer(NULL
, 0, 5000, NULL
);
205 WINE_ERR("SetTimer failed to create timer\n");
212 if (!GetMessage(&msg
, NULL
, 0, 0)) break;
213 if (msg
.message
== WM_TIMER
) break;
214 DispatchMessage(&msg
);
221 char *endquote
= strchr(ddeExec
+1, '"');
224 WINE_ERR("Unabled to retrieve URL from string '%s'\n", ddeExec
);
235 if (timer
) KillTimer(NULL
, timer
);
238 if (hszTopic
&& hszApplication
) DdeNameService(ddeInst
, hszApplication
, 0, DNS_UNREGISTER
);
239 if (hszTopic
) DdeFreeStringHandle(ddeInst
, hszTopic
);
240 if (hszApplication
) DdeFreeStringHandle(ddeInst
, hszApplication
);
241 DdeUninitialize(ddeInst
);
246 /*****************************************************************************
247 * Main entry point. This is a console application so we have a main() not a
250 int main(int argc
, char *argv
[])
253 wine_get_unix_file_name_t wine_get_unix_file_name_ptr
;
256 /* DDE used only if -nohome is specified; avoids delay in printing usage info
257 * when no parameters are passed */
258 if (url
&& !strcasecmp( url
, "-nohome" ))
259 url
= argc
> 2 ? argv
[2] : get_url_from_dde();
263 fprintf( stderr
, "Usage: winebrowser URL\n" );
267 /* handle an RFC1738 file URL */
268 if (!strncasecmp( url
, "file:", 5 ))
271 DWORD len
= lstrlenA( url
) + 1;
273 if (UrlUnescapeA( url
, NULL
, &len
, URL_UNESCAPE_INPLACE
) != S_OK
)
275 fprintf( stderr
, "winebrowser: unescaping URL failed: %s\n", url
);
279 /* look for a Windows path after 'file:' */
283 if (isalpha( p
[0] ) && (p
[1] == ':' || p
[1] == '|')) break;
288 fprintf( stderr
, "winebrowser: no valid Windows path in: %s\n", url
);
292 if (p
[1] == '|') p
[1] = ':';
297 if (*p
== '/') *p
= '\\';
302 /* check if the argument is a local file */
303 wine_get_unix_file_name_ptr
= (wine_get_unix_file_name_t
)
304 GetProcAddress( GetModuleHandle( "KERNEL32" ), "wine_get_unix_file_name" );
306 if (wine_get_unix_file_name_ptr
== NULL
)
308 WINE_ERR( "cannot get the address of 'wine_get_unix_file_name'\n" );
313 WCHAR unixpathW
[MAX_PATH
];
315 MultiByteToWideChar( CP_UNIXCP
, 0, url
, -1, unixpathW
, MAX_PATH
);
316 if ((unixpath
= wine_get_unix_file_name_ptr( unixpathW
)))
320 if (stat( unixpath
, &dummy
) >= 0)
322 ret
= open_http_url( unixpath
);
328 if (!strncasecmp( url
, "mailto:", 7 ))
329 ret
= open_mailto_url( url
);
331 /* let the browser decide how to handle the given url */
332 ret
= open_http_url( url
);
335 HeapFree(GetProcessHeap(), 0, ddeExec
);