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 *ddeString
= NULL
;
129 static HSZ hszTopic
= 0, hszReturn
= 0;
130 static DWORD ddeInst
= 0;
132 /* Dde callback, save the execute or request string for processing */
133 static HDDEDATA CALLBACK
ddeCb(UINT uType
, UINT uFmt
, HCONV hConv
,
134 HSZ hsz1
, HSZ hsz2
, HDDEDATA hData
,
135 ULONG_PTR dwData1
, ULONG_PTR dwData2
)
137 DWORD size
= 0, ret
= 0;
139 WINE_TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
140 uType
, uFmt
, hConv
, hsz1
, hsz2
, hData
, dwData1
, dwData2
);
145 if (!DdeCmpStringHandles(hsz1
, hszTopic
))
146 return (HDDEDATA
)TRUE
;
147 return (HDDEDATA
)FALSE
;
150 if (!(size
= DdeGetData(hData
, NULL
, 0, 0)))
151 WINE_ERR("DdeGetData returned zero size of execute string\n");
152 else if (!(ddeString
= HeapAlloc(GetProcessHeap(), 0, size
)))
153 WINE_ERR("Out of memory\n");
154 else if (DdeGetData(hData
, (LPBYTE
)ddeString
, size
, 0) != size
)
155 WINE_WARN("DdeGetData did not return %d bytes\n", size
);
156 DdeFreeDataHandle(hData
);
157 return (HDDEDATA
)DDE_FACK
;
160 ret
= -3; /* error */
161 if (!(size
= DdeQueryString(ddeInst
, hsz2
, NULL
, 0, CP_WINANSI
)))
162 WINE_ERR("DdeQueryString returned zero size of request string\n");
163 else if (!(ddeString
= HeapAlloc(GetProcessHeap(), 0, size
+1)))
164 WINE_ERR("Out of memory\n");
165 else if (DdeQueryString(ddeInst
, hsz2
, ddeString
, size
+1, CP_WINANSI
) != size
)
166 WINE_WARN("DdeQueryString did not return %d bytes\n", size
);
168 ret
= -2; /* acknowledgment */
169 return DdeCreateDataHandle(ddeInst
, (LPBYTE
)&ret
, sizeof(ret
), 0,
170 hszReturn
, CF_TEXT
, 0);
177 static char *get_url_from_dde(void)
179 static const char szApplication
[] = "IExplore";
180 static const char szTopic
[] = "WWW_OpenURL";
181 static const char szReturn
[] = "Return";
183 HSZ hszApplication
= 0;
188 rc
= DdeInitializeA(&ddeInst
, ddeCb
, CBF_SKIP_ALLNOTIFICATIONS
| CBF_FAIL_ADVISES
|
190 if (rc
!= DMLERR_NO_ERROR
)
192 WINE_ERR("Unable to initialize DDE, DdeInitialize returned %d\n", rc
);
196 hszApplication
= DdeCreateStringHandleA(ddeInst
, szApplication
, CP_WINANSI
);
199 WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
203 hszTopic
= DdeCreateStringHandleA(ddeInst
, szTopic
, CP_WINANSI
);
206 WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
210 hszReturn
= DdeCreateStringHandleA(ddeInst
, szReturn
, CP_WINANSI
);
213 WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
217 if (!DdeNameService(ddeInst
, hszApplication
, 0, DNS_REGISTER
))
219 WINE_ERR("Unable to initialize DDE, DdeNameService failed\n");
223 timer
= SetTimer(NULL
, 0, 5000, NULL
);
226 WINE_ERR("SetTimer failed to create timer\n");
233 if (!GetMessage(&msg
, NULL
, 0, 0)) break;
234 if (msg
.message
== WM_TIMER
) break;
235 DispatchMessage(&msg
);
240 if (*ddeString
== '"')
242 char *endquote
= strchr(ddeString
+1, '"');
245 WINE_ERR("Unabled to retrieve URL from string '%s'\n", ddeString
);
256 if (timer
) KillTimer(NULL
, timer
);
259 if (hszTopic
&& hszApplication
) DdeNameService(ddeInst
, hszApplication
, 0, DNS_UNREGISTER
);
260 if (hszReturn
) DdeFreeStringHandle(ddeInst
, hszReturn
);
261 if (hszTopic
) DdeFreeStringHandle(ddeInst
, hszTopic
);
262 if (hszApplication
) DdeFreeStringHandle(ddeInst
, hszApplication
);
263 DdeUninitialize(ddeInst
);
268 /*****************************************************************************
269 * Main entry point. This is a console application so we have a main() not a
272 int main(int argc
, char *argv
[])
275 wine_get_unix_file_name_t wine_get_unix_file_name_ptr
;
278 /* DDE used only if -nohome is specified; avoids delay in printing usage info
279 * when no parameters are passed */
280 if (url
&& !strcasecmp( url
, "-nohome" ))
281 url
= argc
> 2 ? argv
[2] : get_url_from_dde();
285 fprintf( stderr
, "Usage: winebrowser URL\n" );
289 /* handle an RFC1738 file URL */
290 if (!strncasecmp( url
, "file:", 5 ))
293 DWORD len
= lstrlenA( url
) + 1;
295 if (UrlUnescapeA( url
, NULL
, &len
, URL_UNESCAPE_INPLACE
) != S_OK
)
297 fprintf( stderr
, "winebrowser: unescaping URL failed: %s\n", url
);
301 /* look for a Windows path after 'file:' */
305 if (isalpha( p
[0] ) && (p
[1] == ':' || p
[1] == '|')) break;
310 fprintf( stderr
, "winebrowser: no valid Windows path in: %s\n", url
);
314 if (p
[1] == '|') p
[1] = ':';
319 if (*p
== '/') *p
= '\\';
324 /* check if the argument is a local file */
325 wine_get_unix_file_name_ptr
= (wine_get_unix_file_name_t
)
326 GetProcAddress( GetModuleHandle( "KERNEL32" ), "wine_get_unix_file_name" );
328 if (wine_get_unix_file_name_ptr
== NULL
)
330 WINE_ERR( "cannot get the address of 'wine_get_unix_file_name'\n" );
335 WCHAR unixpathW
[MAX_PATH
];
337 MultiByteToWideChar( CP_UNIXCP
, 0, url
, -1, unixpathW
, MAX_PATH
);
338 if ((unixpath
= wine_get_unix_file_name_ptr( unixpathW
)))
342 if (stat( unixpath
, &dummy
) >= 0)
344 ret
= open_http_url( unixpath
);
350 if (!strncasecmp( url
, "mailto:", 7 ))
351 ret
= open_mailto_url( url
);
353 /* let the browser decide how to handle the given url */
354 ret
= open_http_url( url
);
357 HeapFree(GetProcessHeap(), 0, ddeString
);