~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/programs/winebrowser/main.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * winebrowser - winelib app to launch native OS browser or mail client.
  3  *
  4  * Copyright (C) 2004 Chris Morgan
  5  * Copyright (C) 2005 Hans Leidekker
  6  *
  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.
 11  *
 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.
 16  *
 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
 20  *
 21  * NOTES:
 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.
 26  *
 27  *  The application to launch is chosen from a default set or, if set,
 28  *  taken from a registry key.
 29  *  
 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:
 34  *
 35  *   mailto:[E-MAIL]?subject=[TOPIC]&cc=[E-MAIL]&bcc=[E-MAIL]&body=[TEXT]
 36  */
 37 
 38 #define WIN32_LEAN_AND_MEAN
 39 
 40 #include "config.h"
 41 #include "wine/port.h"
 42 #include "wine/debug.h"
 43 #include "wine/unicode.h"
 44 
 45 #include <windows.h>
 46 #include <shlwapi.h>
 47 #include <ddeml.h>
 48 #include <stdio.h>
 49 #include <stdlib.h>
 50 #include <errno.h>
 51 
 52 WINE_DEFAULT_DEBUG_CHANNEL(winebrowser);
 53 
 54 typedef LPSTR (*wine_get_unix_file_name_t)(LPCWSTR unixname);
 55 
 56 static const WCHAR browser_key[] =
 57     {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
 58      'W','i','n','e','B','r','o','w','s','e','r',0};
 59 
 60 static char *strdup_unixcp( const WCHAR *str )
 61 {
 62     char *ret;
 63     int len = WideCharToMultiByte( CP_UNIXCP, 0, str, -1, NULL, 0, NULL, NULL );
 64     if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
 65         WideCharToMultiByte( CP_UNIXCP, 0, str, -1, ret, len, NULL, NULL );
 66     return ret;
 67 }
 68 
 69 static WCHAR *strdupW( const WCHAR *src )
 70 {
 71     WCHAR *dst;
 72     if (!src) return NULL;
 73     if ((dst = HeapAlloc( GetProcessHeap(), 0, (strlenW( src ) + 1) * sizeof(WCHAR) )))
 74         strcpyW( dst, src );
 75     return dst;
 76 }
 77 
 78 /* try to launch a unix app from a comma separated string of app names */
 79 static int launch_app( WCHAR *candidates, const WCHAR *argv1 )
 80 {
 81     char *app, *applist, *cmdline;
 82     const char *argv_new[3];
 83 
 84     if (!(applist = strdup_unixcp( candidates ))) return 1;
 85     if (!(cmdline = strdup_unixcp( argv1 )))
 86     {
 87         HeapFree( GetProcessHeap(), 0, applist );
 88         return 1;
 89     }
 90     app = strtok( applist, "," );
 91     while (app)
 92     {
 93         WINE_TRACE( "Considering: %s\n", wine_dbgstr_a(app) );
 94         WINE_TRACE( "argv[1]: %s\n", wine_dbgstr_a(cmdline) );
 95 
 96         argv_new[0] = app;
 97         argv_new[1] = cmdline;
 98         argv_new[2] = NULL;
 99 
100         spawnvp( _P_OVERLAY, app, argv_new );  /* only returns on error */
101         app = strtok( NULL, "," );  /* grab the next app */
102     }
103     WINE_ERR( "could not find a suitable app to run\n" );
104 
105     HeapFree( GetProcessHeap(), 0, applist );
106     HeapFree( GetProcessHeap(), 0, cmdline );
107     return 1;
108 }
109 
110 static int open_http_url( const WCHAR *url )
111 {
112 #ifdef __APPLE__
113     static const WCHAR defaultbrowsers[] =
114         { '/', 'u', 's', 'r', '/', 'b', 'i', 'n', '/', 'o', 'p', 'e', 'n', 0 };
115 #else
116     static const WCHAR defaultbrowsers[] =
117         {'x','d','g','-','o','p','e','n',',','f','i','r','e','f','o','x',',',
118          'k','o','n','q','u','e','r','o','r',',','m','o','z','i','l','l','a',',',
119          'n','e','t','s','c','a','p','e',',','g','a','l','e','o','n',',',
120          'o','p','e','r','a',',','d','i','l','l','o',0};
121 #endif
122     static const WCHAR browsersW[] =
123         {'B','r','o','w','s','e','r','s',0};
124 
125     WCHAR browsers[256];
126     DWORD length, type;
127     HKEY key;
128     LONG r;
129 
130     length = sizeof(browsers);
131     /* @@ Wine registry key: HKCU\Software\Wine\WineBrowser */
132     if  (!(r = RegOpenKeyW( HKEY_CURRENT_USER, browser_key, &key )))
133     {
134         r = RegQueryValueExW( key, browsersW, 0, &type, (LPBYTE)browsers, &length );
135         RegCloseKey( key );
136     }
137     if (r != ERROR_SUCCESS)
138         strcpyW( browsers, defaultbrowsers );
139 
140     return launch_app( browsers, url );
141 }
142 
143 static int open_mailto_url( const WCHAR *url )
144 {
145 #ifdef __APPLE__
146     static const WCHAR defaultmailers[] =
147         { '/', 'u', 's', 'r', '/', 'b', 'i', 'n', '/', 'o', 'p', 'e', 'n', 0 };
148 #else
149     static const WCHAR defaultmailers[] =
150         {'x','d','g','-','e','m','a','i','l',',',
151          'm','o','z','i','l','l','a','-','t','h','u','n','d','e','r','b','i','r','d',',',
152          't','h','u','n','d','e','r','b','i','r','d',',',
153          'e','v','o','l','u','t','i','o','n',0};
154 #endif
155     static const WCHAR mailersW[] =
156         {'M','a','i','l','e','r','s',0};
157 
158     WCHAR mailers[256];
159     DWORD length, type;
160     HKEY key;
161     LONG r;
162 
163     length = sizeof(mailers);
164     /* @@ Wine registry key: HKCU\Software\Wine\WineBrowser */
165     if (!(r = RegOpenKeyW( HKEY_CURRENT_USER, browser_key, &key )))
166     {
167         r = RegQueryValueExW( key, mailersW, 0, &type, (LPBYTE)mailers, &length );
168         RegCloseKey( key );
169     }
170     if (r != ERROR_SUCCESS)
171         strcpyW( mailers, defaultmailers );
172 
173     return launch_app( mailers, url );
174 }
175 
176 /*****************************************************************************
177  * DDE helper functions.
178  */
179 
180 static WCHAR *ddeString = NULL;
181 static HSZ hszTopic = 0, hszReturn = 0;
182 static DWORD ddeInst = 0;
183 
184 /* Dde callback, save the execute or request string for processing */
185 static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv,
186                                 HSZ hsz1, HSZ hsz2, HDDEDATA hData,
187                                 ULONG_PTR dwData1, ULONG_PTR dwData2)
188 {
189     DWORD size = 0, ret = 0;
190 
191     WINE_TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
192                uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
193 
194     switch (uType)
195     {
196         case XTYP_CONNECT:
197             if (!DdeCmpStringHandles(hsz1, hszTopic))
198                 return (HDDEDATA)TRUE;
199             return (HDDEDATA)FALSE;
200 
201         case XTYP_EXECUTE:
202         {
203             char *buffer = NULL;
204 
205             if (!(size = DdeGetData(hData, NULL, 0, 0)))
206                 WINE_ERR("DdeGetData returned zero size of execute string\n");
207             else if (!(buffer = HeapAlloc(GetProcessHeap(), 0, size)))
208                 WINE_ERR("Out of memory\n");
209             else if (DdeGetData(hData, (LPBYTE)buffer, size, 0) != size)
210                 WINE_WARN("DdeGetData did not return %d bytes\n", size);
211             else
212             {
213                 int len = MultiByteToWideChar(CP_ACP, 0, buffer, -1, NULL, 0);
214                 if (!(ddeString = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
215                     WINE_ERR("Out of memory\n");
216                 else
217                     MultiByteToWideChar(CP_ACP, 0, buffer, -1, ddeString, len);
218             }
219             HeapFree(GetProcessHeap(), 0, buffer);
220             DdeFreeDataHandle(hData);
221             return (HDDEDATA)DDE_FACK;
222         }
223         case XTYP_REQUEST:
224             ret = -3; /* error */
225             if (!(size = DdeQueryStringW(ddeInst, hsz2, NULL, 0, CP_WINUNICODE)))
226                 WINE_ERR("DdeQueryString returned zero size of request string\n");
227             else if (!(ddeString = HeapAlloc(GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR))))
228                 WINE_ERR("Out of memory\n");
229             else if (DdeQueryStringW(ddeInst, hsz2, ddeString, size + 1, CP_WINUNICODE) != size)
230                 WINE_WARN("DdeQueryString did not return %d characters\n", size);
231             else
232                 ret = -2; /* acknowledgment */
233             return DdeCreateDataHandle(ddeInst, (LPBYTE)&ret, sizeof(ret), 0,
234                                        hszReturn, CF_TEXT, 0);
235 
236         default:
237             return NULL;
238     }
239 }
240 
241 static WCHAR *get_url_from_dde(void)
242 {
243     static const WCHAR szApplication[] = {'I','E','x','p','l','o','r','e',0};
244     static const WCHAR szTopic[] = {'W','W','W','_','O','p','e','n','U','R','L',0};
245     static const WCHAR szReturn[] = {'R','e','t','u','r','n',0};
246 
247     HSZ hszApplication = 0;
248     UINT_PTR timer = 0;
249     int rc;
250     WCHAR *ret = NULL;
251 
252     rc = DdeInitializeW(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | CBF_FAIL_POKES, 0);
253     if (rc != DMLERR_NO_ERROR)
254     {
255         WINE_ERR("Unable to initialize DDE, DdeInitialize returned %d\n", rc);
256         goto done;
257     }
258 
259     hszApplication = DdeCreateStringHandleW(ddeInst, szApplication, CP_WINUNICODE);
260     if (!hszApplication)
261     {
262         WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
263         goto done;
264     }
265 
266     hszTopic = DdeCreateStringHandleW(ddeInst, szTopic, CP_WINUNICODE);
267     if (!hszTopic)
268     {
269         WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
270         goto done;
271     }
272 
273     hszReturn = DdeCreateStringHandleW(ddeInst, szReturn, CP_WINUNICODE);
274     if (!hszReturn)
275     {
276         WINE_ERR("Unable to initialize DDE, DdeCreateStringHandle failed\n");
277         goto done;
278     }
279 
280     if (!DdeNameService(ddeInst, hszApplication, 0, DNS_REGISTER))
281     {
282         WINE_ERR("Unable to initialize DDE, DdeNameService failed\n");
283         goto done;
284     }
285 
286     timer = SetTimer(NULL, 0, 5000, NULL);
287     if (!timer)
288     {
289         WINE_ERR("SetTimer failed to create timer\n");
290         goto done;
291     }
292 
293     while (!ddeString)
294     {
295         MSG msg;
296         if (!GetMessageW(&msg, NULL, 0, 0)) break;
297         if (msg.message == WM_TIMER) break;
298         DispatchMessageW(&msg);
299     }
300 
301     if (ddeString)
302     {
303         if (*ddeString == '"')
304         {
305             WCHAR *endquote = strchrW(ddeString + 1, '"');
306             if (!endquote)
307             {
308                 WINE_ERR("Unable to retrieve URL from string %s\n", wine_dbgstr_w(ddeString));
309                 goto done;
310             }
311             *endquote = 0;
312             ret = ddeString+1;
313         }
314         else
315             ret = ddeString;
316     }
317 
318 done:
319     if (timer) KillTimer(NULL, timer);
320     if (ddeInst)
321     {
322         if (hszTopic && hszApplication) DdeNameService(ddeInst, hszApplication, 0, DNS_UNREGISTER);
323         if (hszReturn) DdeFreeStringHandle(ddeInst, hszReturn);
324         if (hszTopic) DdeFreeStringHandle(ddeInst, hszTopic);
325         if (hszApplication) DdeFreeStringHandle(ddeInst, hszApplication);
326         DdeUninitialize(ddeInst);
327     }
328     return ret;
329 }
330 
331 /*****************************************************************************
332  * Main entry point. This is a console application so we have a wmain() not a
333  * winmain().
334  */
335 int wmain(int argc, WCHAR *argv[])
336 {
337     static const WCHAR nohomeW[] = {'-','n','o','h','o','m','e',0};
338     static const WCHAR mailtoW[] = {'m','a','i','l','t','o',':',0};
339     static const WCHAR fileW[] = {'f','i','l','e',':',0};
340 
341     WCHAR *p, *filenameW = NULL, *fileurlW = NULL, *url = argv[1];
342     wine_get_unix_file_name_t wine_get_unix_file_name_ptr;
343     int ret = 1;
344 
345     /* DDE used only if -nohome is specified; avoids delay in printing usage info
346      * when no parameters are passed */
347     if (url && !strcmpiW( url, nohomeW ))
348         url = argc > 2 ? argv[2] : get_url_from_dde();
349 
350     if (!url)
351     {
352         WINE_ERR( "Usage: winebrowser URL\n" );
353         goto done;
354     }
355 
356     /* handle an RFC1738 file URL */
357     if (!strncmpiW( url, fileW, 5 ))
358     {
359         DWORD len = strlenW( url ) + 1;
360 
361         if (UrlUnescapeW( url, NULL, &len, URL_UNESCAPE_INPLACE ) != S_OK)
362         {
363             WINE_ERR( "unescaping URL failed: %s\n", wine_dbgstr_w(url) );
364             goto done;
365         }
366 
367         /* look for a Windows path after 'file:' */
368         p = url + 5;
369         while (*p)
370         {
371             if (isalphaW( p[0] ) && (p[1] == ':' || p[1] == '|')) break;
372             p++;
373         }
374         if (!*p)
375         {
376             WINE_ERR( "no valid Windows path in: %s\n", wine_dbgstr_w(url) );
377             goto done;
378         }
379 
380         if (p[1] == '|') p[1] = ':';
381         url = p;
382  
383         while (*p)
384         {
385             if (*p == '/') *p = '\\';
386             p++;
387         }
388     }
389 
390     /* check if the argument is a local file */
391     wine_get_unix_file_name_ptr = (wine_get_unix_file_name_t)
392         GetProcAddress( GetModuleHandleA( "KERNEL32" ), "wine_get_unix_file_name" );
393 
394     if (wine_get_unix_file_name_ptr == NULL)
395     {
396         WINE_ERR( "cannot get the address of 'wine_get_unix_file_name'\n" );
397     }
398     else
399     {
400         char *unixpath;
401         WCHAR c = 0;
402 
403         if (!(filenameW = strdupW( url ))) goto done;
404         if ((p = strchrW( filenameW, '?' )) || (p = strchrW( filenameW, '#' )))
405         {
406             c = *p;
407             *p = 0;
408         }
409 
410         if ((unixpath = wine_get_unix_file_name_ptr( filenameW )))
411         {
412             struct stat dummy;
413             if (stat( unixpath, &dummy ) >= 0)
414             {
415                 static const WCHAR schemeW[] = {'f','i','l','e',':','/','/',0};
416                 int len, len_scheme;
417 
418                 len = len_scheme = strlenW( schemeW );
419                 len += MultiByteToWideChar( CP_UNIXCP, 0, unixpath, -1, NULL, 0 );
420                 if (p)
421                 {
422                     *p = c;
423                     len += strlenW( p );
424                 }
425 
426                 if (!(fileurlW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto done;
427 
428                 strcpyW( fileurlW, schemeW );
429                 MultiByteToWideChar( CP_UNIXCP, 0, unixpath, -1, fileurlW + len_scheme, len - len_scheme );
430                 if (p) strcatW( fileurlW, p );
431 
432                 ret = open_http_url( fileurlW );
433                 goto done;
434             }
435         }
436     }
437 
438     if (!strncmpiW( url, mailtoW, 7 ))
439         ret = open_mailto_url( url );
440     else
441         /* let the browser decide how to handle the given url */
442         ret = open_http_url( url );
443 
444 done:
445     HeapFree(GetProcessHeap(), 0, ddeString);
446     HeapFree( GetProcessHeap(), 0, filenameW );
447     HeapFree( GetProcessHeap(), 0, fileurlW );
448     return ret;
449 }
450 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.