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