user32/tests: Fix a test failure on Win95.
[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     LPWININETHTTPREQW lpwhr;
66     LPWININETHTTPSESSIONW lpwhs = NULL;
67     LPWININETAPPINFOW hIC = NULL;
68     LPWSTR p;
69
70     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
71     if (NULL == lpwhr)
72         return FALSE;
73
74     lpwhs = lpwhr->lpHttpSession;
75     if (NULL == lpwhs)
76         return FALSE;
77
78     hIC = lpwhs->lpAppInfo;
79     if (NULL == hIC)
80         return FALSE;
81
82     lstrcpynW(szBuf, hIC->lpszProxy, sz);
83
84     /* FIXME: perhaps it would be better to use InternetCrackUrl here */
85     p = strchrW(szBuf, ':');
86     if (p)
87         *p = 0;
88
89     return TRUE;
90 }
91
92 /***********************************************************************
93  *         WININET_GetAuthRealm
94  *
95  *  Determine the name of the (basic) Authentication realm
96  */
97 static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz )
98 {
99     LPWSTR p, q;
100     DWORD index;
101     static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 };
102
103     /* extract the Realm from the proxy response and show it */
104     index = 0;
105     if( !HttpQueryInfoW( hRequest, HTTP_QUERY_PROXY_AUTHENTICATE,
106                          szBuf, &sz, &index) )
107         return FALSE;
108
109     /*
110      * FIXME: maybe we should check that we're
111      * dealing with 'Basic' Authentication
112      */
113     p = strchrW( szBuf, ' ' );
114     if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) )
115     {
116         ERR("proxy response wrong? (%s)\n", debugstr_w(szBuf));
117         return FALSE;
118     }
119
120
121     /* remove quotes */
122     p += 7;
123     if( *p == '"' )
124     {
125         p++;
126         q = strrchrW( p, '"' );
127         if( q )
128             *q = 0;
129     }
130     strcpyW( szBuf, p );
131
132     return TRUE;
133 }
134
135 /***********************************************************************
136  *         WININET_GetSetPassword
137  */
138 static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, 
139                                     LPCWSTR szRealm, BOOL bSet )
140 {
141     WCHAR szResource[0x80], szUserPass[0x40];
142     LPWSTR p;
143     HWND hUserItem, hPassItem;
144     DWORD r, dwMagic = 19;
145     UINT r_len, u_len;
146     WORD sz;
147     static const WCHAR szColon[] = { ':',0 };
148     static const WCHAR szbs[] = { '/', 0 };
149
150     hUserItem = GetDlgItem( hdlg, IDC_USERNAME );
151     hPassItem = GetDlgItem( hdlg, IDC_PASSWORD );
152
153     /* now try fetch the username and password */
154     lstrcpyW( szResource, szServer);
155     lstrcatW( szResource, szbs);
156     lstrcatW( szResource, szRealm);
157
158     /*
159      * WNetCachePassword is only concerned with the length
160      * of the data stored (which we tell it) and it does
161      * not use strlen() internally so we can add WCHAR data
162      * instead of ASCII data and get it back the same way.
163      */
164     if( bSet )
165     {
166         szUserPass[0] = 0;
167         GetWindowTextW( hUserItem, szUserPass, 
168                         (sizeof szUserPass-1)/sizeof(WCHAR) );
169         lstrcatW(szUserPass, szColon);
170         u_len = strlenW( szUserPass );
171         GetWindowTextW( hPassItem, szUserPass+u_len, 
172                         (sizeof szUserPass)/sizeof(WCHAR)-u_len );
173
174         r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR);
175         u_len = (strlenW( szUserPass ) + 1)*sizeof(WCHAR);
176         r = WNetCachePassword( (CHAR*)szResource, r_len,
177                                (CHAR*)szUserPass, u_len, dwMagic, 0 );
178
179         return ( r == WN_SUCCESS );
180     }
181
182     sz = sizeof szUserPass;
183     r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR);
184     r = WNetGetCachedPassword( (CHAR*)szResource, r_len,
185                                (CHAR*)szUserPass, &sz, dwMagic );
186     if( r != WN_SUCCESS )
187         return FALSE;
188
189     p = strchrW( szUserPass, ':' );
190     if( p )
191     {
192         *p = 0;
193         SetWindowTextW( hUserItem, szUserPass );
194         SetWindowTextW( hPassItem, p+1 );
195     }
196
197     return TRUE;
198 }
199
200 /***********************************************************************
201  *         WININET_SetProxyAuthorization
202  */
203 static BOOL WININET_SetProxyAuthorization( HINTERNET hRequest,
204                                          LPWSTR username, LPWSTR password )
205 {
206     LPWININETHTTPREQW lpwhr;
207     LPWININETHTTPSESSIONW lpwhs;
208     LPWININETAPPINFOW hIC;
209     LPWSTR p;
210
211     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
212     if( !lpwhr )
213         return FALSE;
214         
215     lpwhs = lpwhr->lpHttpSession;
216     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
217     {
218         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
219         return FALSE;
220     }
221
222     hIC = lpwhs->lpAppInfo;
223
224     p = HeapAlloc( GetProcessHeap(), 0, (strlenW( username ) + 1)*sizeof(WCHAR) );
225     if( !p )
226         return FALSE;
227     
228     lstrcpyW( p, username );
229     hIC->lpszProxyUsername = p;
230
231     p = HeapAlloc( GetProcessHeap(), 0, (strlenW( password ) + 1)*sizeof(WCHAR) );
232     if( !p )
233         return FALSE;
234     
235     lstrcpyW( p, password );
236     hIC->lpszProxyPassword = p;
237
238     return TRUE;
239 }
240
241 /***********************************************************************
242  *         WININET_ProxyPasswordDialog
243  */
244 static INT_PTR WINAPI WININET_ProxyPasswordDialog(
245     HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
246 {
247     HWND hitem;
248     struct WININET_ErrorDlgParams *params;
249     WCHAR szRealm[0x80], szServer[0x80];
250
251     if( uMsg == WM_INITDIALOG )
252     {
253         TRACE("WM_INITDIALOG (%08lx)\n", lParam);
254
255         /* save the parameter list */
256         params = (struct WININET_ErrorDlgParams*) lParam;
257         SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam );
258
259         /* extract the Realm from the proxy response and show it */
260         if( WININET_GetAuthRealm( params->hRequest,
261                                   szRealm, sizeof szRealm/sizeof(WCHAR)) )
262         {
263             hitem = GetDlgItem( hdlg, IDC_REALM );
264             SetWindowTextW( hitem, szRealm );
265         }
266
267         /* extract the name of the proxy server */
268         if( WININET_GetProxyServer( params->hRequest, 
269                                     szServer, sizeof szServer/sizeof(WCHAR)) )
270         {
271             hitem = GetDlgItem( hdlg, IDC_PROXY );
272             SetWindowTextW( hitem, szServer );
273         }
274
275         WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE );
276
277         return TRUE;
278     }
279
280     params = (struct WININET_ErrorDlgParams*)
281                  GetWindowLongPtrW( hdlg, GWLP_USERDATA );
282
283     switch( uMsg )
284     {
285     case WM_COMMAND:
286         if( wParam == IDOK )
287         {
288             WCHAR username[0x20], password[0x20];
289
290             username[0] = 0;
291             hitem = GetDlgItem( hdlg, IDC_USERNAME );
292             if( hitem )
293                 GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) );
294             
295             password[0] = 0;
296             hitem = GetDlgItem( hdlg, IDC_PASSWORD );
297             if( hitem )
298                 GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) );
299
300             hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD );
301             if( hitem &&
302                 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) &&
303                 WININET_GetAuthRealm( params->hRequest,
304                                   szRealm, sizeof szRealm/sizeof(WCHAR)) &&
305                 WININET_GetProxyServer( params->hRequest, 
306                                     szServer, sizeof szServer/sizeof(WCHAR)) )
307             {
308                 WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE );
309             }
310             WININET_SetProxyAuthorization( params->hRequest, username, password );
311
312             EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY );
313             return TRUE;
314         }
315         if( wParam == IDCANCEL )
316         {
317             EndDialog( hdlg, 0 );
318             return TRUE;
319         }
320         break;
321     }
322     return FALSE;
323 }
324
325 /***********************************************************************
326  *         WININET_GetConnectionStatus
327  */
328 static INT WININET_GetConnectionStatus( HINTERNET hRequest )
329 {
330     WCHAR szStatus[0x20];
331     DWORD sz, index, dwStatus;
332
333     TRACE("%p\n", hRequest );
334
335     sz = sizeof szStatus;
336     index = 0;
337     if( !HttpQueryInfoW( hRequest, HTTP_QUERY_STATUS_CODE,
338                     szStatus, &sz, &index))
339         return -1;
340     dwStatus = atoiW( szStatus );
341
342     TRACE("request %p status = %d\n", hRequest, dwStatus );
343
344     return dwStatus;
345 }
346
347
348 /***********************************************************************
349  *         InternetErrorDlg
350  */
351 DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest,
352                  DWORD dwError, DWORD dwFlags, LPVOID* lppvData)
353 {
354     struct WININET_ErrorDlgParams params;
355     HMODULE hwininet = GetModuleHandleA( "wininet.dll" );
356     INT dwStatus;
357
358     TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData);
359
360     params.hWnd = hWnd;
361     params.hRequest = hRequest;
362     params.dwError = dwError;
363     params.dwFlags = dwFlags;
364     params.lppvData = lppvData;
365
366     switch( dwError )
367     {
368     case ERROR_SUCCESS:
369         if( !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) )
370             return 0;
371         dwStatus = WININET_GetConnectionStatus( hRequest );
372         if( HTTP_STATUS_PROXY_AUTH_REQ != dwStatus )
373             return ERROR_SUCCESS;
374         return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ),
375                     hWnd, WININET_ProxyPasswordDialog, (LPARAM) &params );
376
377     case ERROR_INTERNET_INCORRECT_PASSWORD:
378         return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ),
379                     hWnd, WININET_ProxyPasswordDialog, (LPARAM) &params );
380
381     case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
382     case ERROR_INTERNET_INVALID_CA:
383     case ERROR_INTERNET_POST_IS_NON_SECURE:
384     case ERROR_INTERNET_SEC_CERT_CN_INVALID:
385     case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
386         FIXME("Need to display dialog for error %d\n", dwError);
387         return ERROR_SUCCESS;
388     }
389     return ERROR_INVALID_PARAMETER;
390 }