wininet: Make module handle scope global.
[wine] / dlls / wininet / dialogs.c
1 /*
2  * Wininet
3  *
4  * Copyright 2003 Mike McCormack for CodeWeavers Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #if defined(__MINGW32__) || defined (_MSC_VER)
25 #include <ws2tcpip.h>
26 #endif
27
28 #include <stdarg.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winreg.h"
34 #include "wininet.h"
35 #include "winnetwk.h"
36 #include "wine/debug.h"
37 #include "winerror.h"
38 #define NO_SHLWAPI_STREAM
39 #include "shlwapi.h"
40
41 #include "internet.h"
42
43 #include "wine/unicode.h"
44
45 #include "resource.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
48
49 struct WININET_ErrorDlgParams
50 {
51     HWND       hWnd;
52     HINTERNET  hRequest;
53     DWORD      dwError;
54     DWORD      dwFlags;
55     LPVOID*    lppvData;
56 };
57
58 /***********************************************************************
59  *         WININET_GetProxyServer
60  *
61  *  Determine the name of the proxy server the request is using
62  */
63 static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz )
64 {
65     http_request_t *lpwhr;
66     http_session_t *lpwhs = NULL;
67     appinfo_t *hIC = NULL;
68     BOOL ret = FALSE;
69     LPWSTR p;
70
71     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
72     if (NULL == lpwhr)
73         return FALSE;
74
75     lpwhs = lpwhr->lpHttpSession;
76     if (NULL == lpwhs)
77         goto done;
78
79     hIC = lpwhs->lpAppInfo;
80     if (NULL == hIC)
81         goto done;
82
83     lstrcpynW(szBuf, hIC->lpszProxy, sz);
84
85     /* FIXME: perhaps it would be better to use InternetCrackUrl here */
86     p = strchrW(szBuf, ':');
87     if (p)
88         *p = 0;
89
90     ret = TRUE;
91
92 done:
93     WININET_Release( &lpwhr->hdr );
94     return ret;
95 }
96
97 /***********************************************************************
98  *         WININET_GetServer
99  *
100  *  Determine the name of the web server
101  */
102 static BOOL WININET_GetServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz )
103 {
104     http_request_t *lpwhr;
105     http_session_t *lpwhs = NULL;
106     BOOL ret = FALSE;
107
108     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
109     if (NULL == lpwhr)
110         return FALSE;
111
112     lpwhs = lpwhr->lpHttpSession;
113     if (NULL == lpwhs)
114         goto done;
115
116     lstrcpynW(szBuf, lpwhs->lpszHostName, sz);
117
118     ret = TRUE;
119
120 done:
121     WININET_Release( &lpwhr->hdr );
122     return ret;
123 }
124
125 /***********************************************************************
126  *         WININET_GetAuthRealm
127  *
128  *  Determine the name of the (basic) Authentication realm
129  */
130 static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz, BOOL proxy )
131 {
132     LPWSTR p, q;
133     DWORD index, query;
134     static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 };
135
136     if (proxy)
137         query = HTTP_QUERY_PROXY_AUTHENTICATE;
138     else
139         query = HTTP_QUERY_WWW_AUTHENTICATE;
140
141     /* extract the Realm from the response and show it */
142     index = 0;
143     if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) )
144         return FALSE;
145
146     /*
147      * FIXME: maybe we should check that we're
148      * dealing with 'Basic' Authentication
149      */
150     p = strchrW( szBuf, ' ' );
151     if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) )
152     {
153         ERR("response wrong? (%s)\n", debugstr_w(szBuf));
154         return FALSE;
155     }
156
157     /* remove quotes */
158     p += 7;
159     if( *p == '"' )
160     {
161         p++;
162         q = strrchrW( p, '"' );
163         if( q )
164             *q = 0;
165     }
166     strcpyW( szBuf, p );
167
168     return TRUE;
169 }
170
171 /***********************************************************************
172  *         WININET_GetSetPassword
173  */
174 static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, 
175                                     LPCWSTR szRealm, BOOL bSet )
176 {
177     WCHAR szResource[0x80], szUserPass[0x40];
178     LPWSTR p;
179     HWND hUserItem, hPassItem;
180     DWORD r, dwMagic = 19;
181     UINT r_len, u_len;
182     WORD sz;
183     static const WCHAR szColon[] = { ':',0 };
184     static const WCHAR szbs[] = { '/', 0 };
185
186     hUserItem = GetDlgItem( hdlg, IDC_USERNAME );
187     hPassItem = GetDlgItem( hdlg, IDC_PASSWORD );
188
189     /* now try fetch the username and password */
190     lstrcpyW( szResource, szServer);
191     lstrcatW( szResource, szbs);
192     lstrcatW( szResource, szRealm);
193
194     /*
195      * WNetCachePassword is only concerned with the length
196      * of the data stored (which we tell it) and it does
197      * not use strlen() internally so we can add WCHAR data
198      * instead of ASCII data and get it back the same way.
199      */
200     if( bSet )
201     {
202         szUserPass[0] = 0;
203         GetWindowTextW( hUserItem, szUserPass, 
204                         (sizeof szUserPass-1)/sizeof(WCHAR) );
205         lstrcatW(szUserPass, szColon);
206         u_len = strlenW( szUserPass );
207         GetWindowTextW( hPassItem, szUserPass+u_len, 
208                         (sizeof szUserPass)/sizeof(WCHAR)-u_len );
209
210         r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR);
211         u_len = (strlenW( szUserPass ) + 1)*sizeof(WCHAR);
212         r = WNetCachePassword( (CHAR*)szResource, r_len,
213                                (CHAR*)szUserPass, u_len, dwMagic, 0 );
214
215         return ( r == WN_SUCCESS );
216     }
217
218     sz = sizeof szUserPass;
219     r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR);
220     r = WNetGetCachedPassword( (CHAR*)szResource, r_len,
221                                (CHAR*)szUserPass, &sz, dwMagic );
222     if( r != WN_SUCCESS )
223         return FALSE;
224
225     p = strchrW( szUserPass, ':' );
226     if( p )
227     {
228         *p = 0;
229         SetWindowTextW( hUserItem, szUserPass );
230         SetWindowTextW( hPassItem, p+1 );
231     }
232
233     return TRUE;
234 }
235
236 /***********************************************************************
237  *         WININET_SetAuthorization
238  */
239 static BOOL WININET_SetAuthorization( HINTERNET hRequest, LPWSTR username,
240                                       LPWSTR password, BOOL proxy )
241 {
242     http_request_t *lpwhr;
243     http_session_t *lpwhs;
244     BOOL ret = FALSE;
245     LPWSTR p, q;
246
247     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
248     if( !lpwhr )
249         return FALSE;
250
251     lpwhs = lpwhr->lpHttpSession;
252     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
253     {
254         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
255         goto done;
256     }
257
258     p = heap_strdupW(username);
259     if( !p )
260         goto done;
261
262     q = heap_strdupW(password);
263     if( !q )
264     {
265         HeapFree(GetProcessHeap(), 0, username);
266         goto done;
267     }
268
269     if (proxy)
270     {
271         appinfo_t *hIC = lpwhs->lpAppInfo;
272
273         HeapFree(GetProcessHeap(), 0, hIC->lpszProxyUsername);
274         hIC->lpszProxyUsername = p;
275
276         HeapFree(GetProcessHeap(), 0, hIC->lpszProxyPassword);
277         hIC->lpszProxyPassword = q;
278     }
279     else
280     {
281         HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
282         lpwhs->lpszUserName = p;
283
284         HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
285         lpwhs->lpszPassword = q;
286     }
287
288     ret = TRUE;
289
290 done:
291     WININET_Release( &lpwhr->hdr );
292     return ret;
293 }
294
295 /***********************************************************************
296  *         WININET_ProxyPasswordDialog
297  */
298 static INT_PTR WINAPI WININET_ProxyPasswordDialog(
299     HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
300 {
301     HWND hitem;
302     struct WININET_ErrorDlgParams *params;
303     WCHAR szRealm[0x80], szServer[0x80];
304
305     if( uMsg == WM_INITDIALOG )
306     {
307         TRACE("WM_INITDIALOG (%08lx)\n", lParam);
308
309         /* save the parameter list */
310         params = (struct WININET_ErrorDlgParams*) lParam;
311         SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam );
312
313         /* extract the Realm from the proxy response and show it */
314         if( WININET_GetAuthRealm( params->hRequest,
315                                   szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) )
316         {
317             hitem = GetDlgItem( hdlg, IDC_REALM );
318             SetWindowTextW( hitem, szRealm );
319         }
320
321         /* extract the name of the proxy server */
322         if( WININET_GetProxyServer( params->hRequest, 
323                                     szServer, sizeof szServer/sizeof(WCHAR)) )
324         {
325             hitem = GetDlgItem( hdlg, IDC_PROXY );
326             SetWindowTextW( hitem, szServer );
327         }
328
329         WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE );
330
331         return TRUE;
332     }
333
334     params = (struct WININET_ErrorDlgParams*)
335                  GetWindowLongPtrW( hdlg, GWLP_USERDATA );
336
337     switch( uMsg )
338     {
339     case WM_COMMAND:
340         if( wParam == IDOK )
341         {
342             WCHAR username[0x20], password[0x20];
343
344             username[0] = 0;
345             hitem = GetDlgItem( hdlg, IDC_USERNAME );
346             if( hitem )
347                 GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) );
348             
349             password[0] = 0;
350             hitem = GetDlgItem( hdlg, IDC_PASSWORD );
351             if( hitem )
352                 GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) );
353
354             hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD );
355             if( hitem &&
356                 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) &&
357                 WININET_GetAuthRealm( params->hRequest,
358                                   szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) &&
359                 WININET_GetProxyServer( params->hRequest, 
360                                     szServer, sizeof szServer/sizeof(WCHAR)) )
361             {
362                 WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE );
363             }
364             WININET_SetAuthorization( params->hRequest, username, password, TRUE );
365
366             EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY );
367             return TRUE;
368         }
369         if( wParam == IDCANCEL )
370         {
371             EndDialog( hdlg, 0 );
372             return TRUE;
373         }
374         break;
375     }
376     return FALSE;
377 }
378
379 /***********************************************************************
380  *         WININET_PasswordDialog
381  */
382 static INT_PTR WINAPI WININET_PasswordDialog(
383     HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
384 {
385     HWND hitem;
386     struct WININET_ErrorDlgParams *params;
387     WCHAR szRealm[0x80], szServer[0x80];
388
389     if( uMsg == WM_INITDIALOG )
390     {
391         TRACE("WM_INITDIALOG (%08lx)\n", lParam);
392
393         /* save the parameter list */
394         params = (struct WININET_ErrorDlgParams*) lParam;
395         SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam );
396
397         /* extract the Realm from the response and show it */
398         if( WININET_GetAuthRealm( params->hRequest,
399                                   szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) )
400         {
401             hitem = GetDlgItem( hdlg, IDC_REALM );
402             SetWindowTextW( hitem, szRealm );
403         }
404
405         /* extract the name of the server */
406         if( WININET_GetServer( params->hRequest,
407                                szServer, sizeof szServer/sizeof(WCHAR)) )
408         {
409             hitem = GetDlgItem( hdlg, IDC_SERVER );
410             SetWindowTextW( hitem, szServer );
411         }
412
413         WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE );
414
415         return TRUE;
416     }
417
418     params = (struct WININET_ErrorDlgParams*)
419                  GetWindowLongPtrW( hdlg, GWLP_USERDATA );
420
421     switch( uMsg )
422     {
423     case WM_COMMAND:
424         if( wParam == IDOK )
425         {
426             WCHAR username[0x20], password[0x20];
427
428             username[0] = 0;
429             hitem = GetDlgItem( hdlg, IDC_USERNAME );
430             if( hitem )
431                 GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) );
432
433             password[0] = 0;
434             hitem = GetDlgItem( hdlg, IDC_PASSWORD );
435             if( hitem )
436                 GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) );
437
438             hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD );
439             if( hitem &&
440                 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) &&
441                 WININET_GetAuthRealm( params->hRequest,
442                                   szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) &&
443                 WININET_GetServer( params->hRequest,
444                                    szServer, sizeof szServer/sizeof(WCHAR)) )
445             {
446                 WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE );
447             }
448             WININET_SetAuthorization( params->hRequest, username, password, FALSE );
449
450             EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY );
451             return TRUE;
452         }
453         if( wParam == IDCANCEL )
454         {
455             EndDialog( hdlg, 0 );
456             return TRUE;
457         }
458         break;
459     }
460     return FALSE;
461 }
462
463 /***********************************************************************
464  *         WININET_GetConnectionStatus
465  */
466 static INT WININET_GetConnectionStatus( HINTERNET hRequest )
467 {
468     WCHAR szStatus[0x20];
469     DWORD sz, index, dwStatus;
470
471     TRACE("%p\n", hRequest );
472
473     sz = sizeof szStatus;
474     index = 0;
475     if( !HttpQueryInfoW( hRequest, HTTP_QUERY_STATUS_CODE,
476                     szStatus, &sz, &index))
477         return -1;
478     dwStatus = atoiW( szStatus );
479
480     TRACE("request %p status = %d\n", hRequest, dwStatus );
481
482     return dwStatus;
483 }
484
485
486 /***********************************************************************
487  *         InternetErrorDlg
488  */
489 DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest,
490                  DWORD dwError, DWORD dwFlags, LPVOID* lppvData)
491 {
492     struct WININET_ErrorDlgParams params;
493     INT dwStatus;
494
495     TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData);
496
497     params.hWnd = hWnd;
498     params.hRequest = hRequest;
499     params.dwError = dwError;
500     params.dwFlags = dwFlags;
501     params.lppvData = lppvData;
502
503     switch( dwError )
504     {
505     case ERROR_SUCCESS:
506     case ERROR_INTERNET_INCORRECT_PASSWORD:
507         if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) )
508             return 0;
509
510         dwStatus = WININET_GetConnectionStatus( hRequest );
511         switch (dwStatus)
512         {
513         case HTTP_STATUS_PROXY_AUTH_REQ:
514             return DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ),
515                                     hWnd, WININET_ProxyPasswordDialog, (LPARAM) &params );
516         case HTTP_STATUS_DENIED:
517             return DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ),
518                                     hWnd, WININET_PasswordDialog, (LPARAM) &params );
519         default:
520             WARN("unhandled status %u\n", dwStatus);
521             return 0;
522         }
523
524     case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
525     case ERROR_INTERNET_INVALID_CA:
526     case ERROR_INTERNET_POST_IS_NON_SECURE:
527     case ERROR_INTERNET_SEC_CERT_CN_INVALID:
528     case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
529         FIXME("Need to display dialog for error %d\n", dwError);
530         return ERROR_SUCCESS;
531     }
532     return ERROR_INVALID_PARAMETER;
533 }