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