c1ed10ddea66876d2a5d514ff5afebc6e91f9968
[reactos.git] / reactos / dll / win32 / wininet / internet.c
1 /*
2 * Wininet
3 *
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 Jaco Greeff
7 * Copyright 2002 TransGaming Technologies Inc.
8 * Copyright 2004 Mike McCormack for CodeWeavers
9 *
10 * Ulrich Czekalla
11 * Aric Stewart
12 * David Hammerton
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29 #define WIN32_NO_STATUS
30 #define _INC_WINDOWS
31 #define COM_NO_WINDOWS_H
32
33 #include <config.h>
34 //#include "wine/port.h"
35
36 //#include <string.h>
37 //#include <stdarg.h>
38 #include <stdio.h>
39 //#include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #ifdef HAVE_POLL_H
44 #include <poll.h>
45 #endif
46 #ifdef HAVE_SYS_POLL_H
47 # include <sys/poll.h>
48 #endif
49 #ifdef HAVE_SYS_TIME_H
50 # include <sys/time.h>
51 #endif
52 //#include <stdlib.h>
53 //#include <ctype.h>
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
57 //#include <assert.h>
58
59 #include <windef.h>
60 #include <winbase.h>
61 #include <winreg.h>
62 #include <winuser.h>
63 #include <wininet.h>
64 //#include "winineti.h"
65 //#include "winnls.h"
66 #include <wine/debug.h>
67 //#include "winerror.h"
68 #define NO_SHLWAPI_STREAM
69 #include <shlwapi.h>
70
71 #if defined(__MINGW32__) || defined (_MSC_VER)
72 #include <ws2tcpip.h>
73 #endif
74
75 //#include "wine/exception.h"
76
77 #include "internet.h"
78 #include "resource.h"
79
80 //#include "wine/unicode.h"
81
82 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
83
84 #define RESPONSE_TIMEOUT 30
85
86 typedef struct
87 {
88 DWORD dwError;
89 CHAR response[MAX_REPLY_LEN];
90 } WITHREADERROR, *LPWITHREADERROR;
91
92 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
93 HMODULE WININET_hModule;
94
95 static CRITICAL_SECTION WININET_cs;
96 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
97 {
98 0, 0, &WININET_cs,
99 { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
100 0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
101 };
102 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
103
104 static object_header_t **handle_table;
105 static UINT_PTR next_handle;
106 static UINT_PTR handle_table_size;
107
108 typedef struct
109 {
110 DWORD proxyEnabled;
111 LPWSTR proxy;
112 LPWSTR proxyBypass;
113 } proxyinfo_t;
114
115 static ULONG max_conns = 2, max_1_0_conns = 4;
116 static ULONG connect_timeout = 60000;
117
118 static const WCHAR szInternetSettings[] =
119 { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
120 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
121 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
122 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
123 static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
124 static const WCHAR szProxyOverride[] = { 'P','r','o','x','y','O','v','e','r','r','i','d','e', 0 };
125
126 void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
127 {
128 UINT_PTR handle = 0, num;
129 object_header_t *ret;
130 object_header_t **p;
131 BOOL res = TRUE;
132
133 ret = heap_alloc_zero(size);
134 if(!ret)
135 return NULL;
136
137 list_init(&ret->children);
138
139 EnterCriticalSection( &WININET_cs );
140
141 if(!handle_table_size) {
142 num = 16;
143 p = heap_alloc_zero(sizeof(handle_table[0]) * num);
144 if(p) {
145 handle_table = p;
146 handle_table_size = num;
147 next_handle = 1;
148 }else {
149 res = FALSE;
150 }
151 }else if(next_handle == handle_table_size) {
152 num = handle_table_size * 2;
153 p = heap_realloc_zero(handle_table, sizeof(handle_table[0]) * num);
154 if(p) {
155 handle_table = p;
156 handle_table_size = num;
157 }else {
158 res = FALSE;
159 }
160 }
161
162 if(res) {
163 handle = next_handle;
164 if(handle_table[handle])
165 ERR("handle isn't free but should be\n");
166 handle_table[handle] = ret;
167 ret->valid_handle = TRUE;
168
169 while(handle_table[next_handle] && next_handle < handle_table_size)
170 next_handle++;
171 }
172
173 LeaveCriticalSection( &WININET_cs );
174
175 if(!res) {
176 heap_free(ret);
177 return NULL;
178 }
179
180 ret->vtbl = vtbl;
181 ret->refs = 1;
182 ret->hInternet = (HINTERNET)handle;
183
184 if(parent) {
185 ret->lpfnStatusCB = parent->lpfnStatusCB;
186 ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
187 }
188
189 return ret;
190 }
191
192 object_header_t *WININET_AddRef( object_header_t *info )
193 {
194 ULONG refs = InterlockedIncrement(&info->refs);
195 TRACE("%p -> refcount = %d\n", info, refs );
196 return info;
197 }
198
199 object_header_t *get_handle_object( HINTERNET hinternet )
200 {
201 object_header_t *info = NULL;
202 UINT_PTR handle = (UINT_PTR) hinternet;
203
204 EnterCriticalSection( &WININET_cs );
205
206 if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
207 info = WININET_AddRef(handle_table[handle]);
208
209 LeaveCriticalSection( &WININET_cs );
210
211 TRACE("handle %ld -> %p\n", handle, info);
212
213 return info;
214 }
215
216 static void invalidate_handle(object_header_t *info)
217 {
218 object_header_t *child, *next;
219
220 if(!info->valid_handle)
221 return;
222 info->valid_handle = FALSE;
223
224 /* Free all children as native does */
225 LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
226 {
227 TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
228 invalidate_handle( child );
229 }
230
231 WININET_Release(info);
232 }
233
234 BOOL WININET_Release( object_header_t *info )
235 {
236 ULONG refs = InterlockedDecrement(&info->refs);
237 TRACE( "object %p refcount = %d\n", info, refs );
238 if( !refs )
239 {
240 invalidate_handle(info);
241 if ( info->vtbl->CloseConnection )
242 {
243 TRACE( "closing connection %p\n", info);
244 info->vtbl->CloseConnection( info );
245 }
246 /* Don't send a callback if this is a session handle created with InternetOpenUrl */
247 if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
248 || !(info->dwInternalFlags & INET_OPENURL))
249 {
250 INTERNET_SendCallback(info, info->dwContext,
251 INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
252 sizeof(HINTERNET));
253 }
254 TRACE( "destroying object %p\n", info);
255 if ( info->htype != WH_HINIT )
256 list_remove( &info->entry );
257 info->vtbl->Destroy( info );
258
259 if(info->hInternet) {
260 UINT_PTR handle = (UINT_PTR)info->hInternet;
261
262 EnterCriticalSection( &WININET_cs );
263
264 handle_table[handle] = NULL;
265 if(next_handle > handle)
266 next_handle = handle;
267
268 LeaveCriticalSection( &WININET_cs );
269 }
270
271 heap_free(info);
272 }
273 return TRUE;
274 }
275
276 /***********************************************************************
277 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
278 *
279 * PARAMS
280 * hinstDLL [I] handle to the DLL's instance
281 * fdwReason [I]
282 * lpvReserved [I] reserved, must be NULL
283 *
284 * RETURNS
285 * Success: TRUE
286 * Failure: FALSE
287 */
288
289 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
290 {
291 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
292
293 switch (fdwReason) {
294 case DLL_PROCESS_ATTACH:
295
296 g_dwTlsErrIndex = TlsAlloc();
297
298 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
299 return FALSE;
300
301 #ifndef __REACTOS__
302 URLCacheContainers_CreateDefaults();
303 #endif
304
305 WININET_hModule = hinstDLL;
306 break;
307
308 case DLL_THREAD_ATTACH:
309 break;
310
311 case DLL_THREAD_DETACH:
312 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
313 {
314 heap_free(TlsGetValue(g_dwTlsErrIndex));
315 }
316 break;
317
318 case DLL_PROCESS_DETACH:
319 if (lpvReserved) break;
320 collect_connections(COLLECT_CLEANUP);
321 NETCON_unload();
322 free_urlcache();
323 free_cookie();
324
325 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
326 {
327 heap_free(TlsGetValue(g_dwTlsErrIndex));
328 TlsFree(g_dwTlsErrIndex);
329 }
330 break;
331 }
332 return TRUE;
333 }
334
335 /***********************************************************************
336 * INTERNET_SaveProxySettings
337 *
338 * Stores the proxy settings given by lpwai into the registry
339 *
340 * RETURNS
341 * ERROR_SUCCESS if no error, or error code on fail
342 */
343 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
344 {
345 HKEY key;
346 LONG ret;
347
348 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
349 return ret;
350
351 if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->proxyEnabled, sizeof(DWORD))))
352 {
353 RegCloseKey( key );
354 return ret;
355 }
356
357 if (lpwpi->proxy)
358 {
359 if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->proxy, sizeof(WCHAR) * (lstrlenW(lpwpi->proxy) + 1))))
360 {
361 RegCloseKey( key );
362 return ret;
363 }
364 }
365 else
366 {
367 if ((ret = RegDeleteValueW( key, szProxyServer )))
368 {
369 RegCloseKey( key );
370 return ret;
371 }
372 }
373
374 RegCloseKey(key);
375 return ERROR_SUCCESS;
376 }
377
378 /***********************************************************************
379 * INTERNET_FindProxyForProtocol
380 *
381 * Searches the proxy string for a proxy of the given protocol.
382 * Returns the found proxy, or the default proxy if none of the given
383 * protocol is found.
384 *
385 * PARAMETERS
386 * szProxy [In] proxy string to search
387 * proto [In] protocol to search for, e.g. "http"
388 * foundProxy [Out] found proxy
389 * foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
390 *
391 * RETURNS
392 * TRUE if a proxy is found, FALSE if not. If foundProxy is too short,
393 * *foundProxyLen is set to the required size in WCHARs, including the
394 * NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
395 */
396 BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen)
397 {
398 LPCWSTR ptr;
399 BOOL ret = FALSE;
400
401 TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
402
403 /* First, look for the specified protocol (proto=scheme://host:port) */
404 for (ptr = szProxy; !ret && ptr && *ptr; )
405 {
406 LPCWSTR end, equal;
407
408 if (!(end = strchrW(ptr, ' ')))
409 end = ptr + strlenW(ptr);
410 if ((equal = strchrW(ptr, '=')) && equal < end &&
411 equal - ptr == strlenW(proto) &&
412 !strncmpiW(proto, ptr, strlenW(proto)))
413 {
414 if (end - equal > *foundProxyLen)
415 {
416 WARN("buffer too short for %s\n",
417 debugstr_wn(equal + 1, end - equal - 1));
418 *foundProxyLen = end - equal;
419 SetLastError(ERROR_INSUFFICIENT_BUFFER);
420 }
421 else
422 {
423 memcpy(foundProxy, equal + 1, (end - equal) * sizeof(WCHAR));
424 foundProxy[end - equal] = 0;
425 ret = TRUE;
426 }
427 }
428 if (*end == ' ')
429 ptr = end + 1;
430 else
431 ptr = end;
432 }
433 if (!ret)
434 {
435 /* It wasn't found: look for no protocol */
436 for (ptr = szProxy; !ret && ptr && *ptr; )
437 {
438 LPCWSTR end;
439
440 if (!(end = strchrW(ptr, ' ')))
441 end = ptr + strlenW(ptr);
442 if (!strchrW(ptr, '='))
443 {
444 if (end - ptr + 1 > *foundProxyLen)
445 {
446 WARN("buffer too short for %s\n",
447 debugstr_wn(ptr, end - ptr));
448 *foundProxyLen = end - ptr + 1;
449 SetLastError(ERROR_INSUFFICIENT_BUFFER);
450 }
451 else
452 {
453 memcpy(foundProxy, ptr, (end - ptr) * sizeof(WCHAR));
454 foundProxy[end - ptr] = 0;
455 ret = TRUE;
456 }
457 }
458 if (*end == ' ')
459 ptr = end + 1;
460 else
461 ptr = end;
462 }
463 }
464 if (ret)
465 TRACE("found proxy for %s: %s\n", debugstr_w(proto),
466 debugstr_w(foundProxy));
467 return ret;
468 }
469
470 /***********************************************************************
471 * InternetInitializeAutoProxyDll (WININET.@)
472 *
473 * Setup the internal proxy
474 *
475 * PARAMETERS
476 * dwReserved
477 *
478 * RETURNS
479 * FALSE on failure
480 *
481 */
482 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
483 {
484 FIXME("STUB\n");
485 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
486 return FALSE;
487 }
488
489 /***********************************************************************
490 * DetectAutoProxyUrl (WININET.@)
491 *
492 * Auto detect the proxy url
493 *
494 * RETURNS
495 * FALSE on failure
496 *
497 */
498 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
499 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
500 {
501 FIXME("STUB\n");
502 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
503 return FALSE;
504 }
505
506 static void FreeProxyInfo( proxyinfo_t *lpwpi )
507 {
508 heap_free(lpwpi->proxy);
509 heap_free(lpwpi->proxyBypass);
510 }
511
512 static proxyinfo_t *global_proxy;
513
514 static void free_global_proxy( void )
515 {
516 EnterCriticalSection( &WININET_cs );
517 if (global_proxy)
518 {
519 FreeProxyInfo( global_proxy );
520 heap_free( global_proxy );
521 }
522 LeaveCriticalSection( &WININET_cs );
523 }
524
525 /***********************************************************************
526 * INTERNET_LoadProxySettings
527 *
528 * Loads proxy information from process-wide global settings, the registry,
529 * or the environment into lpwpi.
530 *
531 * The caller should call FreeProxyInfo when done with lpwpi.
532 *
533 * FIXME:
534 * The proxy may be specified in the form 'http=proxy.my.org'
535 * Presumably that means there can be ftp=ftpproxy.my.org too.
536 */
537 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
538 {
539 HKEY key;
540 DWORD type, len;
541 LPCSTR envproxy;
542 LONG ret;
543
544 EnterCriticalSection( &WININET_cs );
545 if (global_proxy)
546 {
547 lpwpi->proxyEnabled = global_proxy->proxyEnabled;
548 lpwpi->proxy = heap_strdupW( global_proxy->proxy );
549 lpwpi->proxyBypass = heap_strdupW( global_proxy->proxyBypass );
550 }
551 LeaveCriticalSection( &WININET_cs );
552
553 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
554 return ret;
555
556 len = sizeof(DWORD);
557 if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->proxyEnabled, &len ) || type != REG_DWORD)
558 {
559 lpwpi->proxyEnabled = 0;
560 if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->proxyEnabled, sizeof(DWORD) )))
561 {
562 RegCloseKey( key );
563 return ret;
564 }
565 }
566
567 if (!(envproxy = getenv( "http_proxy" )) || lpwpi->proxyEnabled)
568 {
569 TRACE("Proxy is enabled.\n");
570
571 /* figure out how much memory the proxy setting takes */
572 if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
573 {
574 LPWSTR szProxy, p;
575 static const WCHAR szHttp[] = {'h','t','t','p','=',0};
576
577 if (!(szProxy = heap_alloc(len)))
578 {
579 RegCloseKey( key );
580 return ERROR_OUTOFMEMORY;
581 }
582 RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
583
584 /* find the http proxy, and strip away everything else */
585 p = strstrW( szProxy, szHttp );
586 if (p)
587 {
588 p += lstrlenW( szHttp );
589 lstrcpyW( szProxy, p );
590 }
591 p = strchrW( szProxy, ' ' );
592 if (p) *p = 0;
593
594 lpwpi->proxy = szProxy;
595
596 TRACE("http proxy = %s\n", debugstr_w(lpwpi->proxy));
597 }
598 else
599 {
600 TRACE("No proxy server settings in registry.\n");
601 lpwpi->proxy = NULL;
602 }
603 }
604 else if (envproxy)
605 {
606 WCHAR *envproxyW;
607
608 len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
609 if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
610 return ERROR_OUTOFMEMORY;
611 MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
612
613 lpwpi->proxyEnabled = 1;
614 lpwpi->proxy = envproxyW;
615
616 TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
617 }
618
619 lpwpi->proxyBypass = NULL;
620 if (lpwpi->proxyEnabled)
621 {
622 if (!(envproxy = getenv( "no_proxy" )))
623 {
624 /* figure out how much memory the proxy setting takes */
625 if (!RegQueryValueExW( key, szProxyOverride, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
626 {
627 LPWSTR szProxy;
628
629 if (!(szProxy = heap_alloc(len)))
630 {
631 RegCloseKey( key );
632 return ERROR_OUTOFMEMORY;
633 }
634 RegQueryValueExW( key, szProxyOverride, NULL, &type, (BYTE*)szProxy, &len );
635
636 lpwpi->proxyBypass = szProxy;
637
638 TRACE("http proxy bypass = %s\n", debugstr_w(lpwpi->proxyBypass));
639 }
640 else
641 {
642 TRACE("No proxy bypass server settings in registry.\n");
643 }
644 }
645 else if (envproxy)
646 {
647 WCHAR *envproxyW;
648
649 len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
650 if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
651 return ERROR_OUTOFMEMORY;
652 MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
653
654 lpwpi->proxyBypass = envproxyW;
655
656 TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass));
657 }
658 }
659
660 RegCloseKey( key );
661
662 return ERROR_SUCCESS;
663 }
664
665 /***********************************************************************
666 * INTERNET_ConfigureProxy
667 */
668 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
669 {
670 proxyinfo_t wpi = {0};
671
672 if (INTERNET_LoadProxySettings( &wpi ))
673 return FALSE;
674
675 if (wpi.proxyEnabled)
676 {
677 WCHAR proxyurl[INTERNET_MAX_URL_LENGTH];
678 WCHAR username[INTERNET_MAX_USER_NAME_LENGTH];
679 WCHAR password[INTERNET_MAX_PASSWORD_LENGTH];
680 WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH];
681 URL_COMPONENTSW UrlComponents;
682
683 UrlComponents.dwStructSize = sizeof UrlComponents;
684 UrlComponents.dwSchemeLength = 0;
685 UrlComponents.lpszHostName = hostname;
686 UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
687 UrlComponents.lpszUserName = username;
688 UrlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
689 UrlComponents.lpszPassword = password;
690 UrlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
691 UrlComponents.dwUrlPathLength = 0;
692 UrlComponents.dwExtraInfoLength = 0;
693
694 if(InternetCrackUrlW(wpi.proxy, 0, 0, &UrlComponents))
695 {
696 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 };
697
698 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
699 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
700 sprintfW(proxyurl, szFormat, hostname, UrlComponents.nPort);
701
702 lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
703 lpwai->proxy = heap_strdupW(proxyurl);
704 lpwai->proxyBypass = heap_strdupW(wpi.proxyBypass);
705 if (UrlComponents.dwUserNameLength)
706 {
707 lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName);
708 lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword);
709 }
710
711 TRACE("http proxy = %s bypass = %s\n", debugstr_w(lpwai->proxy), debugstr_w(lpwai->proxyBypass));
712 FreeProxyInfo(&wpi);
713 return TRUE;
714 }
715 else
716 {
717 TRACE("Failed to parse proxy: %s\n", debugstr_w(wpi.proxy));
718 lpwai->proxy = NULL;
719 }
720 }
721
722 lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
723 FreeProxyInfo(&wpi);
724 return FALSE;
725 }
726
727 /***********************************************************************
728 * dump_INTERNET_FLAGS
729 *
730 * Helper function to TRACE the internet flags.
731 *
732 * RETURNS
733 * None
734 *
735 */
736 static void dump_INTERNET_FLAGS(DWORD dwFlags)
737 {
738 #define FE(x) { x, #x }
739 static const wininet_flag_info flag[] = {
740 FE(INTERNET_FLAG_RELOAD),
741 FE(INTERNET_FLAG_RAW_DATA),
742 FE(INTERNET_FLAG_EXISTING_CONNECT),
743 FE(INTERNET_FLAG_ASYNC),
744 FE(INTERNET_FLAG_PASSIVE),
745 FE(INTERNET_FLAG_NO_CACHE_WRITE),
746 FE(INTERNET_FLAG_MAKE_PERSISTENT),
747 FE(INTERNET_FLAG_FROM_CACHE),
748 FE(INTERNET_FLAG_SECURE),
749 FE(INTERNET_FLAG_KEEP_CONNECTION),
750 FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
751 FE(INTERNET_FLAG_READ_PREFETCH),
752 FE(INTERNET_FLAG_NO_COOKIES),
753 FE(INTERNET_FLAG_NO_AUTH),
754 FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
755 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
756 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
757 FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
758 FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
759 FE(INTERNET_FLAG_RESYNCHRONIZE),
760 FE(INTERNET_FLAG_HYPERLINK),
761 FE(INTERNET_FLAG_NO_UI),
762 FE(INTERNET_FLAG_PRAGMA_NOCACHE),
763 FE(INTERNET_FLAG_CACHE_ASYNC),
764 FE(INTERNET_FLAG_FORMS_SUBMIT),
765 FE(INTERNET_FLAG_NEED_FILE),
766 FE(INTERNET_FLAG_TRANSFER_ASCII),
767 FE(INTERNET_FLAG_TRANSFER_BINARY)
768 };
769 #undef FE
770 unsigned int i;
771
772 for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
773 if (flag[i].val & dwFlags) {
774 TRACE(" %s", flag[i].name);
775 dwFlags &= ~flag[i].val;
776 }
777 }
778 if (dwFlags)
779 TRACE(" Unknown flags (%08x)\n", dwFlags);
780 else
781 TRACE("\n");
782 }
783
784 /***********************************************************************
785 * INTERNET_CloseHandle (internal)
786 *
787 * Close internet handle
788 *
789 */
790 static VOID APPINFO_Destroy(object_header_t *hdr)
791 {
792 appinfo_t *lpwai = (appinfo_t*)hdr;
793
794 TRACE("%p\n",lpwai);
795
796 heap_free(lpwai->agent);
797 heap_free(lpwai->proxy);
798 heap_free(lpwai->proxyBypass);
799 heap_free(lpwai->proxyUsername);
800 heap_free(lpwai->proxyPassword);
801 #ifdef __REACTOS__
802 WSACleanup();
803 #endif
804 }
805
806 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
807 {
808 appinfo_t *ai = (appinfo_t*)hdr;
809
810 switch(option) {
811 case INTERNET_OPTION_HANDLE_TYPE:
812 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
813
814 if (*size < sizeof(ULONG))
815 return ERROR_INSUFFICIENT_BUFFER;
816
817 *size = sizeof(DWORD);
818 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
819 return ERROR_SUCCESS;
820
821 case INTERNET_OPTION_USER_AGENT: {
822 DWORD bufsize;
823
824 TRACE("INTERNET_OPTION_USER_AGENT\n");
825
826 bufsize = *size;
827
828 if (unicode) {
829 DWORD len = ai->agent ? strlenW(ai->agent) : 0;
830
831 *size = (len + 1) * sizeof(WCHAR);
832 if(!buffer || bufsize < *size)
833 return ERROR_INSUFFICIENT_BUFFER;
834
835 if (ai->agent)
836 strcpyW(buffer, ai->agent);
837 else
838 *(WCHAR *)buffer = 0;
839 /* If the buffer is copied, the returned length doesn't include
840 * the NULL terminator.
841 */
842 *size = len;
843 }else {
844 if (ai->agent)
845 *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
846 else
847 *size = 1;
848 if(!buffer || bufsize < *size)
849 return ERROR_INSUFFICIENT_BUFFER;
850
851 if (ai->agent)
852 WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
853 else
854 *(char *)buffer = 0;
855 /* If the buffer is copied, the returned length doesn't include
856 * the NULL terminator.
857 */
858 *size -= 1;
859 }
860
861 return ERROR_SUCCESS;
862 }
863
864 case INTERNET_OPTION_PROXY:
865 if(!size) return ERROR_INVALID_PARAMETER;
866 if (unicode) {
867 INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
868 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
869 LPWSTR proxy, proxy_bypass;
870
871 if (ai->proxy)
872 proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
873 if (ai->proxyBypass)
874 proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
875 if (!pi || *size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
876 {
877 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
878 return ERROR_INSUFFICIENT_BUFFER;
879 }
880 proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
881 proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
882
883 pi->dwAccessType = ai->accessType;
884 pi->lpszProxy = NULL;
885 pi->lpszProxyBypass = NULL;
886 if (ai->proxy) {
887 lstrcpyW(proxy, ai->proxy);
888 pi->lpszProxy = proxy;
889 }
890
891 if (ai->proxyBypass) {
892 lstrcpyW(proxy_bypass, ai->proxyBypass);
893 pi->lpszProxyBypass = proxy_bypass;
894 }
895
896 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
897 return ERROR_SUCCESS;
898 }else {
899 INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
900 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
901 LPSTR proxy, proxy_bypass;
902
903 if (ai->proxy)
904 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
905 if (ai->proxyBypass)
906 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
907 NULL, 0, NULL, NULL);
908 if (!pi || *size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
909 {
910 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
911 return ERROR_INSUFFICIENT_BUFFER;
912 }
913 proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
914 proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
915
916 pi->dwAccessType = ai->accessType;
917 pi->lpszProxy = NULL;
918 pi->lpszProxyBypass = NULL;
919 if (ai->proxy) {
920 WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
921 pi->lpszProxy = proxy;
922 }
923
924 if (ai->proxyBypass) {
925 WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
926 proxyBypassBytesRequired, NULL, NULL);
927 pi->lpszProxyBypass = proxy_bypass;
928 }
929
930 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
931 return ERROR_SUCCESS;
932 }
933
934 case INTERNET_OPTION_CONNECT_TIMEOUT:
935 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
936
937 if (*size < sizeof(ULONG))
938 return ERROR_INSUFFICIENT_BUFFER;
939
940 *(ULONG*)buffer = ai->connect_timeout;
941 *size = sizeof(ULONG);
942
943 return ERROR_SUCCESS;
944 }
945
946 return INET_QueryOption(hdr, option, buffer, size, unicode);
947 }
948
949 static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
950 {
951 appinfo_t *ai = (appinfo_t*)hdr;
952
953 switch(option) {
954 case INTERNET_OPTION_CONNECT_TIMEOUT:
955 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
956
957 if(size != sizeof(connect_timeout))
958 return ERROR_INTERNET_BAD_OPTION_LENGTH;
959 if(!*(ULONG*)buf)
960 return ERROR_BAD_ARGUMENTS;
961
962 ai->connect_timeout = *(ULONG*)buf;
963 return ERROR_SUCCESS;
964 case INTERNET_OPTION_USER_AGENT:
965 heap_free(ai->agent);
966 if (!(ai->agent = heap_strdupW(buf))) return ERROR_OUTOFMEMORY;
967 return ERROR_SUCCESS;
968 }
969
970 return INET_SetOption(hdr, option, buf, size);
971 }
972
973 static const object_vtbl_t APPINFOVtbl = {
974 APPINFO_Destroy,
975 NULL,
976 APPINFO_QueryOption,
977 APPINFO_SetOption,
978 NULL,
979 NULL,
980 NULL,
981 NULL
982 };
983
984
985 /***********************************************************************
986 * InternetOpenW (WININET.@)
987 *
988 * Per-application initialization of wininet
989 *
990 * RETURNS
991 * HINTERNET on success
992 * NULL on failure
993 *
994 */
995 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
996 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
997 {
998 appinfo_t *lpwai = NULL;
999 #ifdef __REACTOS__
1000 WSADATA wsaData;
1001 int error = WSAStartup(MAKEWORD(2, 2), &wsaData);
1002 if (error) ERR("WSAStartup failed: %d\n", error);
1003 #endif
1004
1005 if (TRACE_ON(wininet)) {
1006 #define FE(x) { x, #x }
1007 static const wininet_flag_info access_type[] = {
1008 FE(INTERNET_OPEN_TYPE_PRECONFIG),
1009 FE(INTERNET_OPEN_TYPE_DIRECT),
1010 FE(INTERNET_OPEN_TYPE_PROXY),
1011 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
1012 };
1013 #undef FE
1014 DWORD i;
1015 const char *access_type_str = "Unknown";
1016
1017 TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
1018 debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
1019 for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
1020 if (access_type[i].val == dwAccessType) {
1021 access_type_str = access_type[i].name;
1022 break;
1023 }
1024 }
1025 TRACE(" access type : %s\n", access_type_str);
1026 TRACE(" flags :");
1027 dump_INTERNET_FLAGS(dwFlags);
1028 }
1029
1030 /* Clear any error information */
1031 INTERNET_SetLastError(0);
1032
1033 if((dwAccessType == INTERNET_OPEN_TYPE_PROXY) && !lpszProxy) {
1034 SetLastError(ERROR_INVALID_PARAMETER);
1035 return NULL;
1036 }
1037
1038 lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
1039 if (!lpwai) {
1040 SetLastError(ERROR_OUTOFMEMORY);
1041 return NULL;
1042 }
1043
1044 lpwai->hdr.htype = WH_HINIT;
1045 lpwai->hdr.dwFlags = dwFlags;
1046 lpwai->accessType = dwAccessType;
1047 lpwai->proxyUsername = NULL;
1048 lpwai->proxyPassword = NULL;
1049 lpwai->connect_timeout = connect_timeout;
1050
1051 lpwai->agent = heap_strdupW(lpszAgent);
1052 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
1053 INTERNET_ConfigureProxy( lpwai );
1054 else if(dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1055 lpwai->proxy = heap_strdupW(lpszProxy);
1056 lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);
1057 }
1058
1059 TRACE("returning %p\n", lpwai);
1060
1061 return lpwai->hdr.hInternet;
1062 }
1063
1064
1065 /***********************************************************************
1066 * InternetOpenA (WININET.@)
1067 *
1068 * Per-application initialization of wininet
1069 *
1070 * RETURNS
1071 * HINTERNET on success
1072 * NULL on failure
1073 *
1074 */
1075 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
1076 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
1077 {
1078 WCHAR *szAgent, *szProxy, *szBypass;
1079 HINTERNET rc;
1080
1081 TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
1082 dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
1083
1084 szAgent = heap_strdupAtoW(lpszAgent);
1085 szProxy = heap_strdupAtoW(lpszProxy);
1086 szBypass = heap_strdupAtoW(lpszProxyBypass);
1087
1088 rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
1089
1090 heap_free(szAgent);
1091 heap_free(szProxy);
1092 heap_free(szBypass);
1093 return rc;
1094 }
1095
1096 /***********************************************************************
1097 * InternetGetLastResponseInfoA (WININET.@)
1098 *
1099 * Return last wininet error description on the calling thread
1100 *
1101 * RETURNS
1102 * TRUE on success of writing to buffer
1103 * FALSE on failure
1104 *
1105 */
1106 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
1107 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
1108 {
1109 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1110
1111 TRACE("\n");
1112
1113 if (lpwite)
1114 {
1115 *lpdwError = lpwite->dwError;
1116 if (lpwite->dwError)
1117 {
1118 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1119 *lpdwBufferLength = strlen(lpszBuffer);
1120 }
1121 else
1122 *lpdwBufferLength = 0;
1123 }
1124 else
1125 {
1126 *lpdwError = 0;
1127 *lpdwBufferLength = 0;
1128 }
1129
1130 return TRUE;
1131 }
1132
1133 /***********************************************************************
1134 * InternetGetLastResponseInfoW (WININET.@)
1135 *
1136 * Return last wininet error description on the calling thread
1137 *
1138 * RETURNS
1139 * TRUE on success of writing to buffer
1140 * FALSE on failure
1141 *
1142 */
1143 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
1144 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
1145 {
1146 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1147
1148 TRACE("\n");
1149
1150 if (lpwite)
1151 {
1152 *lpdwError = lpwite->dwError;
1153 if (lpwite->dwError)
1154 {
1155 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1156 *lpdwBufferLength = lstrlenW(lpszBuffer);
1157 }
1158 else
1159 *lpdwBufferLength = 0;
1160 }
1161 else
1162 {
1163 *lpdwError = 0;
1164 *lpdwBufferLength = 0;
1165 }
1166
1167 return TRUE;
1168 }
1169
1170 /***********************************************************************
1171 * InternetGetConnectedState (WININET.@)
1172 *
1173 * Return connected state
1174 *
1175 * RETURNS
1176 * TRUE if connected
1177 * if lpdwStatus is not null, return the status (off line,
1178 * modem, lan...) in it.
1179 * FALSE if not connected
1180 */
1181 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
1182 {
1183 TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
1184
1185 if (lpdwStatus) {
1186 WARN("always returning LAN connection.\n");
1187 *lpdwStatus = INTERNET_CONNECTION_LAN;
1188 }
1189 return TRUE;
1190 }
1191
1192
1193 /***********************************************************************
1194 * InternetGetConnectedStateExW (WININET.@)
1195 *
1196 * Return connected state
1197 *
1198 * PARAMS
1199 *
1200 * lpdwStatus [O] Flags specifying the status of the internet connection.
1201 * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
1202 * dwNameLen [I] Size of the buffer, in characters.
1203 * dwReserved [I] Reserved. Must be set to 0.
1204 *
1205 * RETURNS
1206 * TRUE if connected
1207 * if lpdwStatus is not null, return the status (off line,
1208 * modem, lan...) in it.
1209 * FALSE if not connected
1210 *
1211 * NOTES
1212 * If the system has no available network connections, an empty string is
1213 * stored in lpszConnectionName. If there is a LAN connection, a localized
1214 * "LAN Connection" string is stored. Presumably, if only a dial-up
1215 * connection is available then the name of the dial-up connection is
1216 * returned. Why any application, other than the "Internet Settings" CPL,
1217 * would want to use this function instead of the simpler InternetGetConnectedStateW
1218 * function is beyond me.
1219 */
1220 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
1221 DWORD dwNameLen, DWORD dwReserved)
1222 {
1223 TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1224
1225 /* Must be zero */
1226 if(dwReserved)
1227 return FALSE;
1228
1229 if (lpdwStatus) {
1230 WARN("always returning LAN connection.\n");
1231 *lpdwStatus = INTERNET_CONNECTION_LAN;
1232 }
1233 return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
1234 }
1235
1236
1237 /***********************************************************************
1238 * InternetGetConnectedStateExA (WININET.@)
1239 */
1240 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
1241 DWORD dwNameLen, DWORD dwReserved)
1242 {
1243 LPWSTR lpwszConnectionName = NULL;
1244 BOOL rc;
1245
1246 TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1247
1248 if (lpszConnectionName && dwNameLen > 0)
1249 lpwszConnectionName = heap_alloc(dwNameLen * sizeof(WCHAR));
1250
1251 rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
1252 dwReserved);
1253 if (rc && lpwszConnectionName)
1254 {
1255 WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
1256 dwNameLen, NULL, NULL);
1257 heap_free(lpwszConnectionName);
1258 }
1259 return rc;
1260 }
1261
1262
1263 /***********************************************************************
1264 * InternetConnectW (WININET.@)
1265 *
1266 * Open a ftp, gopher or http session
1267 *
1268 * RETURNS
1269 * HINTERNET a session handle on success
1270 * NULL on failure
1271 *
1272 */
1273 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
1274 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
1275 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
1276 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1277 {
1278 appinfo_t *hIC;
1279 HINTERNET rc = NULL;
1280 DWORD res = ERROR_SUCCESS;
1281
1282 TRACE("(%p, %s, %i, %s, %s, %i, %x, %lx)\n", hInternet, debugstr_w(lpszServerName),
1283 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
1284 dwService, dwFlags, dwContext);
1285
1286 if (!lpszServerName)
1287 {
1288 SetLastError(ERROR_INVALID_PARAMETER);
1289 return NULL;
1290 }
1291
1292 hIC = (appinfo_t*)get_handle_object( hInternet );
1293 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1294 {
1295 res = ERROR_INVALID_HANDLE;
1296 goto lend;
1297 }
1298
1299 switch (dwService)
1300 {
1301 case INTERNET_SERVICE_FTP:
1302 rc = FTP_Connect(hIC, lpszServerName, nServerPort,
1303 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
1304 if(!rc)
1305 res = INTERNET_GetLastError();
1306 break;
1307
1308 case INTERNET_SERVICE_HTTP:
1309 res = HTTP_Connect(hIC, lpszServerName, nServerPort,
1310 lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
1311 break;
1312
1313 case INTERNET_SERVICE_GOPHER:
1314 default:
1315 break;
1316 }
1317 lend:
1318 if( hIC )
1319 WININET_Release( &hIC->hdr );
1320
1321 TRACE("returning %p\n", rc);
1322 SetLastError(res);
1323 return rc;
1324 }
1325
1326
1327 /***********************************************************************
1328 * InternetConnectA (WININET.@)
1329 *
1330 * Open a ftp, gopher or http session
1331 *
1332 * RETURNS
1333 * HINTERNET a session handle on success
1334 * NULL on failure
1335 *
1336 */
1337 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
1338 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
1339 LPCSTR lpszUserName, LPCSTR lpszPassword,
1340 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1341 {
1342 HINTERNET rc = NULL;
1343 LPWSTR szServerName;
1344 LPWSTR szUserName;
1345 LPWSTR szPassword;
1346
1347 szServerName = heap_strdupAtoW(lpszServerName);
1348 szUserName = heap_strdupAtoW(lpszUserName);
1349 szPassword = heap_strdupAtoW(lpszPassword);
1350
1351 rc = InternetConnectW(hInternet, szServerName, nServerPort,
1352 szUserName, szPassword, dwService, dwFlags, dwContext);
1353
1354 heap_free(szServerName);
1355 heap_free(szUserName);
1356 heap_free(szPassword);
1357 return rc;
1358 }
1359
1360
1361 /***********************************************************************
1362 * InternetFindNextFileA (WININET.@)
1363 *
1364 * Continues a file search from a previous call to FindFirstFile
1365 *
1366 * RETURNS
1367 * TRUE on success
1368 * FALSE on failure
1369 *
1370 */
1371 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
1372 {
1373 BOOL ret;
1374 WIN32_FIND_DATAW fd;
1375
1376 ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
1377 if(lpvFindData)
1378 WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
1379 return ret;
1380 }
1381
1382 /***********************************************************************
1383 * InternetFindNextFileW (WININET.@)
1384 *
1385 * Continues a file search from a previous call to FindFirstFile
1386 *
1387 * RETURNS
1388 * TRUE on success
1389 * FALSE on failure
1390 *
1391 */
1392 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
1393 {
1394 object_header_t *hdr;
1395 DWORD res;
1396
1397 TRACE("\n");
1398
1399 hdr = get_handle_object(hFind);
1400 if(!hdr) {
1401 WARN("Invalid handle\n");
1402 SetLastError(ERROR_INVALID_HANDLE);
1403 return FALSE;
1404 }
1405
1406 if(hdr->vtbl->FindNextFileW) {
1407 res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1408 }else {
1409 WARN("Handle doesn't support NextFile\n");
1410 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1411 }
1412
1413 WININET_Release(hdr);
1414
1415 if(res != ERROR_SUCCESS)
1416 SetLastError(res);
1417 return res == ERROR_SUCCESS;
1418 }
1419
1420 /***********************************************************************
1421 * InternetCloseHandle (WININET.@)
1422 *
1423 * Generic close handle function
1424 *
1425 * RETURNS
1426 * TRUE on success
1427 * FALSE on failure
1428 *
1429 */
1430 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1431 {
1432 object_header_t *obj;
1433
1434 TRACE("%p\n", hInternet);
1435
1436 obj = get_handle_object( hInternet );
1437 if (!obj) {
1438 SetLastError(ERROR_INVALID_HANDLE);
1439 return FALSE;
1440 }
1441
1442 invalidate_handle(obj);
1443 WININET_Release(obj);
1444
1445 return TRUE;
1446 }
1447
1448
1449 /***********************************************************************
1450 * ConvertUrlComponentValue (Internal)
1451 *
1452 * Helper function for InternetCrackUrlA
1453 *
1454 */
1455 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1456 LPWSTR lpwszComponent, DWORD dwwComponentLen,
1457 LPCSTR lpszStart, LPCWSTR lpwszStart)
1458 {
1459 TRACE("%p %d %p %d %p %p\n", *lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
1460 if (*dwComponentLen != 0)
1461 {
1462 DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1463 if (*lppszComponent == NULL)
1464 {
1465 if (lpwszComponent)
1466 {
1467 int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL);
1468 *lppszComponent = (LPSTR)lpszStart + offset;
1469 }
1470 else
1471 *lppszComponent = NULL;
1472
1473 *dwComponentLen = nASCIILength;
1474 }
1475 else
1476 {
1477 DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1478 WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1479 (*lppszComponent)[ncpylen]=0;
1480 *dwComponentLen = ncpylen;
1481 }
1482 }
1483 }
1484
1485
1486 /***********************************************************************
1487 * InternetCrackUrlA (WININET.@)
1488 *
1489 * See InternetCrackUrlW.
1490 */
1491 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1492 LPURL_COMPONENTSA lpUrlComponents)
1493 {
1494 DWORD nLength;
1495 URL_COMPONENTSW UCW;
1496 BOOL ret = FALSE;
1497 WCHAR *lpwszUrl, *hostname = NULL, *username = NULL, *password = NULL, *path = NULL,
1498 *scheme = NULL, *extra = NULL;
1499
1500 TRACE("(%s %u %x %p)\n",
1501 lpszUrl ? debugstr_an(lpszUrl, dwUrlLength ? dwUrlLength : strlen(lpszUrl)) : "(null)",
1502 dwUrlLength, dwFlags, lpUrlComponents);
1503
1504 if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1505 lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1506 {
1507 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1508 return FALSE;
1509 }
1510
1511 if(dwUrlLength<=0)
1512 dwUrlLength=-1;
1513 nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1514
1515 /* if dwUrlLength=-1 then nLength includes null but length to
1516 InternetCrackUrlW should not include it */
1517 if (dwUrlLength == -1) nLength--;
1518
1519 lpwszUrl = heap_alloc((nLength + 1) * sizeof(WCHAR));
1520 MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength + 1);
1521 lpwszUrl[nLength] = '\0';
1522
1523 memset(&UCW,0,sizeof(UCW));
1524 UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1525 if (lpUrlComponents->dwHostNameLength)
1526 {
1527 UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
1528 if (lpUrlComponents->lpszHostName)
1529 {
1530 hostname = heap_alloc(UCW.dwHostNameLength * sizeof(WCHAR));
1531 UCW.lpszHostName = hostname;
1532 }
1533 }
1534 if (lpUrlComponents->dwUserNameLength)
1535 {
1536 UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
1537 if (lpUrlComponents->lpszUserName)
1538 {
1539 username = heap_alloc(UCW.dwUserNameLength * sizeof(WCHAR));
1540 UCW.lpszUserName = username;
1541 }
1542 }
1543 if (lpUrlComponents->dwPasswordLength)
1544 {
1545 UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
1546 if (lpUrlComponents->lpszPassword)
1547 {
1548 password = heap_alloc(UCW.dwPasswordLength * sizeof(WCHAR));
1549 UCW.lpszPassword = password;
1550 }
1551 }
1552 if (lpUrlComponents->dwUrlPathLength)
1553 {
1554 UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
1555 if (lpUrlComponents->lpszUrlPath)
1556 {
1557 path = heap_alloc(UCW.dwUrlPathLength * sizeof(WCHAR));
1558 UCW.lpszUrlPath = path;
1559 }
1560 }
1561 if (lpUrlComponents->dwSchemeLength)
1562 {
1563 UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
1564 if (lpUrlComponents->lpszScheme)
1565 {
1566 scheme = heap_alloc(UCW.dwSchemeLength * sizeof(WCHAR));
1567 UCW.lpszScheme = scheme;
1568 }
1569 }
1570 if (lpUrlComponents->dwExtraInfoLength)
1571 {
1572 UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
1573 if (lpUrlComponents->lpszExtraInfo)
1574 {
1575 extra = heap_alloc(UCW.dwExtraInfoLength * sizeof(WCHAR));
1576 UCW.lpszExtraInfo = extra;
1577 }
1578 }
1579 if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
1580 {
1581 ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1582 UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
1583 ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1584 UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
1585 ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1586 UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
1587 ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1588 UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
1589 ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1590 UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
1591 ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1592 UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
1593
1594 lpUrlComponents->nScheme = UCW.nScheme;
1595 lpUrlComponents->nPort = UCW.nPort;
1596
1597 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(lpszUrl),
1598 debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
1599 debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
1600 debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
1601 debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
1602 }
1603 heap_free(lpwszUrl);
1604 heap_free(hostname);
1605 heap_free(username);
1606 heap_free(password);
1607 heap_free(path);
1608 heap_free(scheme);
1609 heap_free(extra);
1610 return ret;
1611 }
1612
1613 static const WCHAR url_schemes[][7] =
1614 {
1615 {'f','t','p',0},
1616 {'g','o','p','h','e','r',0},
1617 {'h','t','t','p',0},
1618 {'h','t','t','p','s',0},
1619 {'f','i','l','e',0},
1620 {'n','e','w','s',0},
1621 {'m','a','i','l','t','o',0},
1622 {'r','e','s',0},
1623 };
1624
1625 /***********************************************************************
1626 * GetInternetSchemeW (internal)
1627 *
1628 * Get scheme of url
1629 *
1630 * RETURNS
1631 * scheme on success
1632 * INTERNET_SCHEME_UNKNOWN on failure
1633 *
1634 */
1635 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1636 {
1637 int i;
1638
1639 TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1640
1641 if(lpszScheme==NULL)
1642 return INTERNET_SCHEME_UNKNOWN;
1643
1644 for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1645 if (!strncmpiW(lpszScheme, url_schemes[i], nMaxCmp))
1646 return INTERNET_SCHEME_FIRST + i;
1647
1648 return INTERNET_SCHEME_UNKNOWN;
1649 }
1650
1651 /***********************************************************************
1652 * SetUrlComponentValueW (Internal)
1653 *
1654 * Helper function for InternetCrackUrlW
1655 *
1656 * PARAMS
1657 * lppszComponent [O] Holds the returned string
1658 * dwComponentLen [I] Holds the size of lppszComponent
1659 * [O] Holds the length of the string in lppszComponent without '\0'
1660 * lpszStart [I] Holds the string to copy from
1661 * len [I] Holds the length of lpszStart without '\0'
1662 *
1663 * RETURNS
1664 * TRUE on success
1665 * FALSE on failure
1666 *
1667 */
1668 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1669 {
1670 TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1671
1672 if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1673 return FALSE;
1674
1675 if (*dwComponentLen != 0 || *lppszComponent == NULL)
1676 {
1677 if (*lppszComponent == NULL)
1678 {
1679 *lppszComponent = (LPWSTR)lpszStart;
1680 *dwComponentLen = len;
1681 }
1682 else
1683 {
1684 DWORD ncpylen = min((*dwComponentLen)-1, len);
1685 memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1686 (*lppszComponent)[ncpylen] = '\0';
1687 *dwComponentLen = ncpylen;
1688 }
1689 }
1690
1691 return TRUE;
1692 }
1693
1694 /***********************************************************************
1695 * InternetCrackUrlW (WININET.@)
1696 *
1697 * Break up URL into its components
1698 *
1699 * RETURNS
1700 * TRUE on success
1701 * FALSE on failure
1702 */
1703 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1704 LPURL_COMPONENTSW lpUC)
1705 {
1706 /*
1707 * RFC 1808
1708 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1709 *
1710 */
1711 LPCWSTR lpszParam = NULL;
1712 BOOL found_colon = FALSE;
1713 LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1714 LPCWSTR lpszcp = NULL, lpszNetLoc;
1715 LPWSTR lpszUrl_decode = NULL;
1716 DWORD dwUrlLength = dwUrlLength_orig;
1717
1718 TRACE("(%s %u %x %p)\n",
1719 lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
1720 dwUrlLength, dwFlags, lpUC);
1721
1722 if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1723 {
1724 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1725 return FALSE;
1726 }
1727 if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1728
1729 if (dwFlags & ICU_DECODE)
1730 {
1731 WCHAR *url_tmp;
1732 DWORD len = dwUrlLength + 1;
1733
1734 if (!(url_tmp = heap_alloc(len * sizeof(WCHAR))))
1735 {
1736 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1737 return FALSE;
1738 }
1739 memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
1740 url_tmp[dwUrlLength] = 0;
1741 if (!(lpszUrl_decode = heap_alloc(len * sizeof(WCHAR))))
1742 {
1743 heap_free(url_tmp);
1744 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1745 return FALSE;
1746 }
1747 if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
1748 {
1749 dwUrlLength = len;
1750 lpszUrl = lpszUrl_decode;
1751 }
1752 heap_free(url_tmp);
1753 }
1754 lpszap = lpszUrl;
1755
1756 /* Determine if the URI is absolute. */
1757 while (lpszap - lpszUrl < dwUrlLength)
1758 {
1759 if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
1760 {
1761 lpszap++;
1762 continue;
1763 }
1764 if (*lpszap == ':')
1765 {
1766 found_colon = TRUE;
1767 lpszcp = lpszap;
1768 }
1769 else
1770 {
1771 lpszcp = lpszUrl; /* Relative url */
1772 }
1773
1774 break;
1775 }
1776
1777 if(!found_colon){
1778 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
1779 return 0;
1780 }
1781
1782 lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1783 lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1784
1785 /* Parse <params> */
1786 lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1787 if(!lpszParam)
1788 lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
1789
1790 SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1791 lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1792
1793
1794 /* Get scheme first. */
1795 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1796 SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1797 lpszUrl, lpszcp - lpszUrl);
1798
1799 /* Eat ':' in protocol. */
1800 lpszcp++;
1801
1802 /* double slash indicates the net_loc portion is present */
1803 if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1804 {
1805 lpszcp += 2;
1806
1807 lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1808 if (lpszParam)
1809 {
1810 if (lpszNetLoc)
1811 lpszNetLoc = min(lpszNetLoc, lpszParam);
1812 else
1813 lpszNetLoc = lpszParam;
1814 }
1815 else if (!lpszNetLoc)
1816 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1817
1818 /* Parse net-loc */
1819 if (lpszNetLoc)
1820 {
1821 LPCWSTR lpszHost;
1822 LPCWSTR lpszPort;
1823
1824 /* [<user>[<:password>]@]<host>[:<port>] */
1825 /* First find the user and password if they exist */
1826
1827 lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1828 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1829 {
1830 /* username and password not specified. */
1831 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1832 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1833 }
1834 else /* Parse out username and password */
1835 {
1836 LPCWSTR lpszUser = lpszcp;
1837 LPCWSTR lpszPasswd = lpszHost;
1838
1839 while (lpszcp < lpszHost)
1840 {
1841 if (*lpszcp == ':')
1842 lpszPasswd = lpszcp;
1843
1844 lpszcp++;
1845 }
1846
1847 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1848 lpszUser, lpszPasswd - lpszUser);
1849
1850 if (lpszPasswd != lpszHost)
1851 lpszPasswd++;
1852 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1853 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1854 lpszHost - lpszPasswd);
1855
1856 lpszcp++; /* Advance to beginning of host */
1857 }
1858
1859 /* Parse <host><:port> */
1860
1861 lpszHost = lpszcp;
1862 lpszPort = lpszNetLoc;
1863
1864 /* special case for res:// URLs: there is no port here, so the host is the
1865 entire string up to the first '/' */
1866 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1867 {
1868 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1869 lpszHost, lpszPort - lpszHost);
1870 lpszcp=lpszNetLoc;
1871 }
1872 else
1873 {
1874 while (lpszcp < lpszNetLoc)
1875 {
1876 if (*lpszcp == ':')
1877 lpszPort = lpszcp;
1878
1879 lpszcp++;
1880 }
1881
1882 /* If the scheme is "file" and the host is just one letter, it's not a host */
1883 if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
1884 {
1885 lpszcp=lpszHost;
1886 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1887 NULL, 0);
1888 }
1889 else
1890 {
1891 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1892 lpszHost, lpszPort - lpszHost);
1893 if (lpszPort != lpszNetLoc)
1894 lpUC->nPort = atoiW(++lpszPort);
1895 else switch (lpUC->nScheme)
1896 {
1897 case INTERNET_SCHEME_HTTP:
1898 lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1899 break;
1900 case INTERNET_SCHEME_HTTPS:
1901 lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1902 break;
1903 case INTERNET_SCHEME_FTP:
1904 lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1905 break;
1906 case INTERNET_SCHEME_GOPHER:
1907 lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1908 break;
1909 default:
1910 break;
1911 }
1912 }
1913 }
1914 }
1915 }
1916 else
1917 {
1918 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1919 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1920 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1921 }
1922
1923 /* Here lpszcp points to:
1924 *
1925 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1926 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1927 */
1928 if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
1929 {
1930 DWORD len;
1931
1932 /* Only truncate the parameter list if it's already been saved
1933 * in lpUC->lpszExtraInfo.
1934 */
1935 if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1936 len = lpszParam - lpszcp;
1937 else
1938 {
1939 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1940 * newlines if necessary.
1941 */
1942 LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1943 if (lpsznewline != NULL)
1944 len = lpsznewline - lpszcp;
1945 else
1946 len = dwUrlLength-(lpszcp-lpszUrl);
1947 }
1948 if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
1949 lpUC->nScheme == INTERNET_SCHEME_FILE)
1950 {
1951 WCHAR tmppath[MAX_PATH];
1952 if (*lpszcp == '/')
1953 {
1954 len = MAX_PATH;
1955 PathCreateFromUrlW(lpszUrl_orig, tmppath, &len, 0);
1956 }
1957 else
1958 {
1959 WCHAR *iter;
1960 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
1961 tmppath[len] = '\0';
1962
1963 iter = tmppath;
1964 while (*iter) {
1965 if (*iter == '/')
1966 *iter = '\\';
1967 ++iter;
1968 }
1969 }
1970 /* if ends in \. or \.. append a backslash */
1971 if (tmppath[len - 1] == '.' &&
1972 (tmppath[len - 2] == '\\' ||
1973 (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
1974 {
1975 if (len < MAX_PATH - 1)
1976 {
1977 tmppath[len] = '\\';
1978 tmppath[len+1] = '\0';
1979 ++len;
1980 }
1981 }
1982 SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1983 tmppath, len);
1984 }
1985 else
1986 SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1987 lpszcp, len);
1988 }
1989 else
1990 {
1991 if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
1992 lpUC->lpszUrlPath[0] = 0;
1993 lpUC->dwUrlPathLength = 0;
1994 }
1995
1996 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1997 debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1998 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1999 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
2000 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
2001
2002 heap_free( lpszUrl_decode );
2003 return TRUE;
2004 }
2005
2006 /***********************************************************************
2007 * InternetAttemptConnect (WININET.@)
2008 *
2009 * Attempt to make a connection to the internet
2010 *
2011 * RETURNS
2012 * ERROR_SUCCESS on success
2013 * Error value on failure
2014 *
2015 */
2016 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
2017 {
2018 FIXME("Stub\n");
2019 return ERROR_SUCCESS;
2020 }
2021
2022
2023 /***********************************************************************
2024 * convert_url_canonicalization_flags
2025 *
2026 * Helper for InternetCanonicalizeUrl
2027 *
2028 * PARAMS
2029 * dwFlags [I] Flags suitable for InternetCanonicalizeUrl
2030 *
2031 * RETURNS
2032 * Flags suitable for UrlCanonicalize
2033 */
2034 static DWORD convert_url_canonicalization_flags(DWORD dwFlags)
2035 {
2036 DWORD dwUrlFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
2037
2038 if (dwFlags & ICU_BROWSER_MODE) dwUrlFlags |= URL_BROWSER_MODE;
2039 if (dwFlags & ICU_DECODE) dwUrlFlags |= URL_UNESCAPE;
2040 if (dwFlags & ICU_ENCODE_PERCENT) dwUrlFlags |= URL_ESCAPE_PERCENT;
2041 if (dwFlags & ICU_ENCODE_SPACES_ONLY) dwUrlFlags |= URL_ESCAPE_SPACES_ONLY;
2042 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2043 if (dwFlags & ICU_NO_ENCODE) dwUrlFlags ^= URL_ESCAPE_UNSAFE;
2044 if (dwFlags & ICU_NO_META) dwUrlFlags |= URL_NO_META;
2045
2046 return dwUrlFlags;
2047 }
2048
2049 /***********************************************************************
2050 * InternetCanonicalizeUrlA (WININET.@)
2051 *
2052 * Escape unsafe characters and spaces
2053 *
2054 * RETURNS
2055 * TRUE on success
2056 * FALSE on failure
2057 *
2058 */
2059 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
2060 LPDWORD lpdwBufferLength, DWORD dwFlags)
2061 {
2062 HRESULT hr;
2063
2064 TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
2065 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2066
2067 dwFlags = convert_url_canonicalization_flags(dwFlags);
2068 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2069 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2070 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2071
2072 return hr == S_OK;
2073 }
2074
2075 /***********************************************************************
2076 * InternetCanonicalizeUrlW (WININET.@)
2077 *
2078 * Escape unsafe characters and spaces
2079 *
2080 * RETURNS
2081 * TRUE on success
2082 * FALSE on failure
2083 *
2084 */
2085 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
2086 LPDWORD lpdwBufferLength, DWORD dwFlags)
2087 {
2088 HRESULT hr;
2089
2090 TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
2091 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2092
2093 dwFlags = convert_url_canonicalization_flags(dwFlags);
2094 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2095 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2096 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2097
2098 return hr == S_OK;
2099 }
2100
2101 /* #################################################### */
2102
2103 static INTERNET_STATUS_CALLBACK set_status_callback(
2104 object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
2105 {
2106 INTERNET_STATUS_CALLBACK ret;
2107
2108 if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
2109 else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
2110
2111 ret = lpwh->lpfnStatusCB;
2112 lpwh->lpfnStatusCB = callback;
2113
2114 return ret;
2115 }
2116
2117 /***********************************************************************
2118 * InternetSetStatusCallbackA (WININET.@)
2119 *
2120 * Sets up a callback function which is called as progress is made
2121 * during an operation.
2122 *
2123 * RETURNS
2124 * Previous callback or NULL on success
2125 * INTERNET_INVALID_STATUS_CALLBACK on failure
2126 *
2127 */
2128 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
2129 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2130 {
2131 INTERNET_STATUS_CALLBACK retVal;
2132 object_header_t *lpwh;
2133
2134 TRACE("%p\n", hInternet);
2135
2136 if (!(lpwh = get_handle_object(hInternet)))
2137 return INTERNET_INVALID_STATUS_CALLBACK;
2138
2139 retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
2140
2141 WININET_Release( lpwh );
2142 return retVal;
2143 }
2144
2145 /***********************************************************************
2146 * InternetSetStatusCallbackW (WININET.@)
2147 *
2148 * Sets up a callback function which is called as progress is made
2149 * during an operation.
2150 *
2151 * RETURNS
2152 * Previous callback or NULL on success
2153 * INTERNET_INVALID_STATUS_CALLBACK on failure
2154 *
2155 */
2156 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2157 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2158 {
2159 INTERNET_STATUS_CALLBACK retVal;
2160 object_header_t *lpwh;
2161
2162 TRACE("%p\n", hInternet);
2163
2164 if (!(lpwh = get_handle_object(hInternet)))
2165 return INTERNET_INVALID_STATUS_CALLBACK;
2166
2167 retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2168
2169 WININET_Release( lpwh );
2170 return retVal;
2171 }
2172
2173 /***********************************************************************
2174 * InternetSetFilePointer (WININET.@)
2175 */
2176 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2177 PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2178 {
2179 FIXME("(%p %d %p %d %lx): stub\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
2180 return FALSE;
2181 }
2182
2183 /***********************************************************************
2184 * InternetWriteFile (WININET.@)
2185 *
2186 * Write data to an open internet file
2187 *
2188 * RETURNS
2189 * TRUE on success
2190 * FALSE on failure
2191 *
2192 */
2193 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2194 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2195 {
2196 object_header_t *lpwh;
2197 BOOL res;
2198
2199 TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2200
2201 lpwh = get_handle_object( hFile );
2202 if (!lpwh) {
2203 WARN("Invalid handle\n");
2204 SetLastError(ERROR_INVALID_HANDLE);
2205 return FALSE;
2206 }
2207
2208 if(lpwh->vtbl->WriteFile) {
2209 res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2210 }else {
2211 WARN("No Writefile method.\n");
2212 res = ERROR_INVALID_HANDLE;
2213 }
2214
2215 WININET_Release( lpwh );
2216
2217 if(res != ERROR_SUCCESS)
2218 SetLastError(res);
2219 return res == ERROR_SUCCESS;
2220 }
2221
2222
2223 /***********************************************************************
2224 * InternetReadFile (WININET.@)
2225 *
2226 * Read data from an open internet file
2227 *
2228 * RETURNS
2229 * TRUE on success
2230 * FALSE on failure
2231 *
2232 */
2233 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2234 DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2235 {
2236 object_header_t *hdr;
2237 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2238
2239 TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2240
2241 hdr = get_handle_object(hFile);
2242 if (!hdr) {
2243 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2244 return FALSE;
2245 }
2246
2247 if(hdr->vtbl->ReadFile)
2248 res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2249
2250 WININET_Release(hdr);
2251
2252 TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2253 pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2254
2255 if(res != ERROR_SUCCESS)
2256 SetLastError(res);
2257 return res == ERROR_SUCCESS;
2258 }
2259
2260 /***********************************************************************
2261 * InternetReadFileExA (WININET.@)
2262 *
2263 * Read data from an open internet file
2264 *
2265 * PARAMS
2266 * hFile [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2267 * lpBuffersOut [I/O] Buffer.
2268 * dwFlags [I] Flags. See notes.
2269 * dwContext [I] Context for callbacks.
2270 *
2271 * RETURNS
2272 * TRUE on success
2273 * FALSE on failure
2274 *
2275 * NOTES
2276 * The parameter dwFlags include zero or more of the following flags:
2277 *|IRF_ASYNC - Makes the call asynchronous.
2278 *|IRF_SYNC - Makes the call synchronous.
2279 *|IRF_USE_CONTEXT - Forces dwContext to be used.
2280 *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2281 *
2282 * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2283 *
2284 * SEE
2285 * InternetOpenUrlA(), HttpOpenRequestA()
2286 */
2287 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2288 DWORD dwFlags, DWORD_PTR dwContext)
2289 {
2290 object_header_t *hdr;
2291 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2292
2293 TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2294
2295 if (lpBuffersOut->dwStructSize != sizeof(*lpBuffersOut)) {
2296 SetLastError(ERROR_INVALID_PARAMETER);
2297 return FALSE;
2298 }
2299
2300 hdr = get_handle_object(hFile);
2301 if (!hdr) {
2302 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2303 return FALSE;
2304 }
2305
2306 if(hdr->vtbl->ReadFileEx)
2307 res = hdr->vtbl->ReadFileEx(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
2308 &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
2309
2310 WININET_Release(hdr);
2311
2312 TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2313 res, lpBuffersOut->dwBufferLength);
2314
2315 if(res != ERROR_SUCCESS)
2316 SetLastError(res);
2317 return res == ERROR_SUCCESS;
2318 }
2319
2320 /***********************************************************************
2321 * InternetReadFileExW (WININET.@)
2322 * SEE
2323 * InternetReadFileExA()
2324 */
2325 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2326 DWORD dwFlags, DWORD_PTR dwContext)
2327 {
2328 object_header_t *hdr;
2329 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2330
2331 TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
2332
2333 if (lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
2334 SetLastError(ERROR_INVALID_PARAMETER);
2335 return FALSE;
2336 }
2337
2338 hdr = get_handle_object(hFile);
2339 if (!hdr) {
2340 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2341 return FALSE;
2342 }
2343
2344 if(hdr->vtbl->ReadFileEx)
2345 res = hdr->vtbl->ReadFileEx(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
2346 dwFlags, dwContext);
2347
2348 WININET_Release(hdr);
2349
2350 TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2351 res, lpBuffer->dwBufferLength);
2352
2353 if(res != ERROR_SUCCESS)
2354 SetLastError(res);
2355 return res == ERROR_SUCCESS;
2356 }
2357
2358 static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)
2359 {
2360 /* FIXME: This function currently handles more options than it should. Options requiring
2361 * proper handles should be moved to proper functions */
2362 switch(option) {
2363 case INTERNET_OPTION_HTTP_VERSION:
2364 if (*size < sizeof(HTTP_VERSION_INFO))
2365 return ERROR_INSUFFICIENT_BUFFER;
2366
2367 /*
2368 * Presently hardcoded to 1.1
2369 */
2370 ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2371 ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2372 *size = sizeof(HTTP_VERSION_INFO);
2373
2374 return ERROR_SUCCESS;
2375
2376 case INTERNET_OPTION_CONNECTED_STATE:
2377 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2378
2379 if (*size < sizeof(ULONG))
2380 return ERROR_INSUFFICIENT_BUFFER;
2381
2382 *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2383 *size = sizeof(ULONG);
2384
2385 return ERROR_SUCCESS;
2386
2387 case INTERNET_OPTION_PROXY: {
2388 appinfo_t ai;
2389 BOOL ret;
2390
2391 TRACE("Getting global proxy info\n");
2392 memset(&ai, 0, sizeof(appinfo_t));
2393 INTERNET_ConfigureProxy(&ai);
2394
2395 ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2396 APPINFO_Destroy(&ai.hdr);
2397 return ret;
2398 }
2399
2400 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2401 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2402
2403 if (*size < sizeof(ULONG))
2404 return ERROR_INSUFFICIENT_BUFFER;
2405
2406 *(ULONG*)buffer = max_conns;
2407 *size = sizeof(ULONG);
2408
2409 return ERROR_SUCCESS;
2410
2411 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2412 TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2413
2414 if (*size < sizeof(ULONG))
2415 return ERROR_INSUFFICIENT_BUFFER;
2416
2417 *(ULONG*)buffer = max_1_0_conns;
2418 *size = sizeof(ULONG);
2419
2420 return ERROR_SUCCESS;
2421
2422 case INTERNET_OPTION_SECURITY_FLAGS:
2423 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2424 return ERROR_SUCCESS;
2425
2426 case INTERNET_OPTION_VERSION: {
2427 static const INTERNET_VERSION_INFO info = { 1, 2 };
2428
2429 TRACE("INTERNET_OPTION_VERSION\n");
2430
2431 if (*size < sizeof(INTERNET_VERSION_INFO))
2432 return ERROR_INSUFFICIENT_BUFFER;
2433
2434 memcpy(buffer, &info, sizeof(info));
2435 *size = sizeof(info);
2436
2437 return ERROR_SUCCESS;
2438 }
2439
2440 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2441 INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2442 INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2443 DWORD res = ERROR_SUCCESS, i;
2444 proxyinfo_t pi;
2445 LONG ret;
2446
2447 TRACE("Getting global proxy info\n");
2448 if((ret = INTERNET_LoadProxySettings(&pi)))
2449 return ret;
2450
2451 FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2452
2453 if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2454 FreeProxyInfo(&pi);
2455 return ERROR_INSUFFICIENT_BUFFER;
2456 }
2457
2458 for (i = 0; i < con->dwOptionCount; i++) {
2459 INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
2460 INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2461
2462 switch (optionW->dwOption) {
2463 case INTERNET_PER_CONN_FLAGS:
2464 if(pi.proxyEnabled)
2465 optionW->Value.dwValue = PROXY_TYPE_PROXY;
2466 else
2467 optionW->Value.dwValue = PROXY_TYPE_DIRECT;
2468 break;
2469
2470 case INTERNET_PER_CONN_PROXY_SERVER:
2471 if (unicode)
2472 optionW->Value.pszValue = heap_strdupW(pi.proxy);
2473 else
2474 optionA->Value.pszValue = heap_strdupWtoA(pi.proxy);
2475 break;
2476
2477 case INTERNET_PER_CONN_PROXY_BYPASS:
2478 if (unicode)
2479 optionW->Value.pszValue = heap_strdupW(pi.proxyBypass);
2480 else
2481 optionA->Value.pszValue = heap_strdupWtoA(pi.proxyBypass);
2482 break;
2483
2484 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2485 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2486 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2487 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2488 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2489 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2490 FIXME("Unhandled dwOption %d\n", optionW->dwOption);
2491 memset(&optionW->Value, 0, sizeof(optionW->Value));
2492 break;
2493
2494 default:
2495 FIXME("Unknown dwOption %d\n", optionW->dwOption);
2496 res = ERROR_INVALID_PARAMETER;
2497 break;
2498 }
2499 }
2500 FreeProxyInfo(&pi);
2501
2502 return res;
2503 }
2504 case INTERNET_OPTION_REQUEST_FLAGS:
2505 case INTERNET_OPTION_USER_AGENT:
2506 *size = 0;
2507 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2508 case INTERNET_OPTION_POLICY:
2509 return ERROR_INVALID_PARAMETER;
2510 case INTERNET_OPTION_CONNECT_TIMEOUT:
2511 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2512
2513 if (*size < sizeof(ULONG))
2514 return ERROR_INSUFFICIENT_BUFFER;
2515
2516 *(ULONG*)buffer = connect_timeout;
2517 *size = sizeof(ULONG);
2518
2519 return ERROR_SUCCESS;
2520 }
2521
2522 FIXME("Stub for %d\n", option);
2523 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2524 }
2525
2526 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2527 {
2528 switch(option) {
2529 case INTERNET_OPTION_CONTEXT_VALUE:
2530 if (!size)
2531 return ERROR_INVALID_PARAMETER;
2532
2533 if (*size < sizeof(DWORD_PTR)) {
2534 *size = sizeof(DWORD_PTR);
2535 return ERROR_INSUFFICIENT_BUFFER;
2536 }
2537 if (!buffer)
2538 return ERROR_INVALID_PARAMETER;
2539
2540 *(DWORD_PTR *)buffer = hdr->dwContext;
2541 *size = sizeof(DWORD_PTR);
2542 return ERROR_SUCCESS;
2543
2544 case INTERNET_OPTION_REQUEST_FLAGS:
2545 WARN("INTERNET_OPTION_REQUEST_FLAGS\n");
2546 *size = sizeof(DWORD);
2547 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2548
2549 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2550 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2551 WARN("Called on global option %u\n", option);
2552 return ERROR_INTERNET_INVALID_OPERATION;
2553 }
2554
2555 /* FIXME: we shouldn't call it here */
2556 return query_global_option(option, buffer, size, unicode);
2557 }
2558
2559 /***********************************************************************
2560 * InternetQueryOptionW (WININET.@)
2561 *
2562 * Queries an options on the specified handle
2563 *
2564 * RETURNS
2565 * TRUE on success
2566 * FALSE on failure
2567 *
2568 */
2569 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2570 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2571 {
2572 object_header_t *hdr;
2573 DWORD res = ERROR_INVALID_HANDLE;
2574
2575 TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2576
2577 if(hInternet) {
2578 hdr = get_handle_object(hInternet);
2579 if (hdr) {
2580 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2581 WININET_Release(hdr);
2582 }
2583 }else {
2584 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE);
2585 }
2586
2587 if(res != ERROR_SUCCESS)
2588 SetLastError(res);
2589 return res == ERROR_SUCCESS;
2590 }
2591
2592 /***********************************************************************
2593 * InternetQueryOptionA (WININET.@)
2594 *
2595 * Queries an options on the specified handle
2596 *
2597 * RETURNS
2598 * TRUE on success
2599 * FALSE on failure
2600 *
2601 */
2602 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2603 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2604 {
2605 object_header_t *hdr;
2606 DWORD res = ERROR_INVALID_HANDLE;
2607
2608 TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2609
2610 if(hInternet) {
2611 hdr = get_handle_object(hInternet);
2612 if (hdr) {
2613 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2614 WININET_Release(hdr);
2615 }
2616 }else {
2617 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE);
2618 }
2619
2620 if(res != ERROR_SUCCESS)
2621 SetLastError(res);
2622 return res == ERROR_SUCCESS;
2623 }
2624
2625 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
2626 {
2627 switch(option) {
2628 case INTERNET_OPTION_CALLBACK:
2629 WARN("Not settable option %u\n", option);
2630 return ERROR_INTERNET_OPTION_NOT_SETTABLE;
2631 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2632 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2633 WARN("Called on global option %u\n", option);
2634 return ERROR_INTERNET_INVALID_OPERATION;
2635 }
2636
2637 return ERROR_INTERNET_INVALID_OPTION;
2638 }
2639
2640 static DWORD set_global_option(DWORD option, void *buf, DWORD size)
2641 {
2642 switch(option) {
2643 case INTERNET_OPTION_CALLBACK:
2644 WARN("Not global option %u\n", option);
2645 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2646
2647 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2648 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2649
2650 if(size != sizeof(max_conns))
2651 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2652 if(!*(ULONG*)buf)
2653 return ERROR_BAD_ARGUMENTS;
2654
2655 max_conns = *(ULONG*)buf;
2656 return ERROR_SUCCESS;
2657
2658 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2659 TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n");
2660
2661 if(size != sizeof(max_1_0_conns))
2662 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2663 if(!*(ULONG*)buf)
2664 return ERROR_BAD_ARGUMENTS;
2665
2666 max_1_0_conns = *(ULONG*)buf;
2667 return ERROR_SUCCESS;
2668
2669 case INTERNET_OPTION_CONNECT_TIMEOUT:
2670 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2671
2672 if(size != sizeof(connect_timeout))
2673 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2674 if(!*(ULONG*)buf)
2675 return ERROR_BAD_ARGUMENTS;
2676
2677 connect_timeout = *(ULONG*)buf;
2678 return ERROR_SUCCESS;
2679
2680 case INTERNET_OPTION_SETTINGS_CHANGED:
2681 FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
2682 collect_connections(COLLECT_CONNECTIONS);
2683 return ERROR_SUCCESS;
2684 }
2685
2686 return ERROR_INTERNET_INVALID_OPTION;
2687 }
2688
2689 /***********************************************************************
2690 * InternetSetOptionW (WININET.@)
2691 *
2692 * Sets an options on the specified handle
2693 *
2694 * RETURNS
2695 * TRUE on success
2696 * FALSE on failure
2697 *
2698 */
2699 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2700 LPVOID lpBuffer, DWORD dwBufferLength)
2701 {
2702 object_header_t *lpwhh;
2703 BOOL ret = TRUE;
2704 DWORD res;
2705
2706 TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2707
2708 lpwhh = (object_header_t*) get_handle_object( hInternet );
2709 if(lpwhh)
2710 res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2711 else
2712 res = set_global_option(dwOption, lpBuffer, dwBufferLength);
2713
2714 if(res != ERROR_INTERNET_INVALID_OPTION) {
2715 if(lpwhh)
2716 WININET_Release(lpwhh);
2717
2718 if(res != ERROR_SUCCESS)
2719 SetLastError(res);
2720
2721 return res == ERROR_SUCCESS;
2722 }
2723
2724 switch (dwOption)
2725 {
2726 case INTERNET_OPTION_HTTP_VERSION:
2727 {
2728 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2729 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2730 }
2731 break;
2732 case INTERNET_OPTION_ERROR_MASK:
2733 {
2734 if(!lpwhh) {
2735 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2736 return FALSE;
2737 } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
2738 INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
2739 INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
2740 SetLastError(ERROR_INVALID_PARAMETER);
2741 ret = FALSE;
2742 } else if(dwBufferLength != sizeof(ULONG)) {
2743 SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
2744 ret = FALSE;
2745 } else
2746 TRACE("INTERNET_OPTION_ERROR_MASK: %x\n", *(ULONG*)lpBuffer);
2747 lpwhh->ErrorMask = *(ULONG*)lpBuffer;
2748 }
2749 break;
2750 case INTERNET_OPTION_PROXY:
2751 {
2752 INTERNET_PROXY_INFOW *info = lpBuffer;
2753
2754 if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW))
2755 {
2756 SetLastError(ERROR_INVALID_PARAMETER);
2757 return FALSE;
2758 }
2759 if (!hInternet)
2760 {
2761 EnterCriticalSection( &WININET_cs );
2762 free_global_proxy();
2763 global_proxy = heap_alloc( sizeof(proxyinfo_t) );
2764 if (global_proxy)
2765 {
2766 if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
2767 {
2768 global_proxy->proxyEnabled = 1;
2769 global_proxy->proxy = heap_strdupW( info->lpszProxy );
2770 global_proxy->proxyBypass = heap_strdupW( info->lpszProxyBypass );
2771 }
2772 else
2773 {
2774 global_proxy->proxyEnabled = 0;
2775 global_proxy->proxy = global_proxy->proxyBypass = NULL;
2776 }
2777 }
2778 LeaveCriticalSection( &WININET_cs );
2779 }
2780 else
2781 {
2782 /* In general, each type of object should handle
2783 * INTERNET_OPTION_PROXY directly. This FIXME ensures it doesn't
2784 * get silently dropped.
2785 */
2786 FIXME("INTERNET_OPTION_PROXY unimplemented\n");
2787 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2788 ret = FALSE;
2789 }
2790 break;
2791 }
2792 case INTERNET_OPTION_CODEPAGE:
2793 {
2794 ULONG codepage = *(ULONG *)lpBuffer;
2795 FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2796 }
2797 break;
2798 case INTERNET_OPTION_REQUEST_PRIORITY:
2799 {
2800 ULONG priority = *(ULONG *)lpBuffer;
2801 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2802 }
2803 break;
2804 case INTERNET_OPTION_CONNECT_TIMEOUT:
2805 {
2806 ULONG connecttimeout = *(ULONG *)lpBuffer;
2807 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2808 }
2809 break;
2810 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2811 {
2812 ULONG receivetimeout = *(ULONG *)lpBuffer;
2813 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2814 }
2815 break;
2816 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2817 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2818 break;
2819 case INTERNET_OPTION_END_BROWSER_SESSION:
2820 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2821 break;
2822 case INTERNET_OPTION_CONNECTED_STATE:
2823 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2824 break;
2825 case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2826 TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2827 break;
2828 case INTERNET_OPTION_SEND_TIMEOUT:
2829 case INTERNET_OPTION_RECEIVE_TIMEOUT:
2830 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
2831 {
2832 ULONG timeout = *(ULONG *)lpBuffer;
2833 FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %d\n", timeout);
2834 break;
2835 }
2836 case INTERNET_OPTION_CONNECT_RETRIES:
2837 {
2838 ULONG retries = *(ULONG *)lpBuffer;
2839 FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2840 break;
2841 }
2842 case INTERNET_OPTION_CONTEXT_VALUE:
2843 {
2844 if (!lpwhh)
2845 {
2846 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2847 return FALSE;
2848 }
2849 if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
2850 {
2851 SetLastError(ERROR_INVALID_PARAMETER);
2852 ret = FALSE;
2853 }
2854 else
2855 lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
2856 break;
2857 }
2858 case INTERNET_OPTION_SECURITY_FLAGS:
2859 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2860 break;
2861 case INTERNET_OPTION_DISABLE_AUTODIAL:
2862 FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2863 break;
2864 case INTERNET_OPTION_HTTP_DECODING:
2865 FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
2866 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2867 ret = FALSE;
2868 break;
2869 case INTERNET_OPTION_COOKIES_3RD_PARTY:
2870 FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2871 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2872 ret = FALSE;
2873 break;
2874 case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2875 FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2876 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2877 ret = FALSE;
2878 break;
2879 case INTERNET_OPTION_CODEPAGE_PATH:
2880 FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2881 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2882 ret = FALSE;
2883 break;
2884 case INTERNET_OPTION_CODEPAGE_EXTRA:
2885 FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2886 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2887 ret = FALSE;
2888 break;
2889 case INTERNET_OPTION_IDN:
2890 FIXME("INTERNET_OPTION_IDN; STUB\n");
2891 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2892 ret = FALSE;
2893 break;
2894 case INTERNET_OPTION_POLICY:
2895 SetLastError(ERROR_INVALID_PARAMETER);
2896 ret = FALSE;
2897 break;
2898 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2899 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2900 LONG res;
2901 unsigned int i;
2902 proxyinfo_t pi;
2903
2904 INTERNET_LoadProxySettings(&pi);
2905
2906 for (i = 0; i < con->dwOptionCount; i++) {
2907 INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2908
2909 switch (option->dwOption) {
2910 case INTERNET_PER_CONN_PROXY_SERVER:
2911 heap_free(pi.proxy);
2912 pi.proxy = heap_strdupW(option->Value.pszValue);
2913 break;
2914
2915 case INTERNET_PER_CONN_FLAGS:
2916 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2917 pi.proxyEnabled = 1;
2918 else
2919 {
2920 if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2921 FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2922 pi.proxyEnabled = 0;
2923 }
2924 break;
2925
2926 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2927 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2928 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2929 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2930 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2931 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2932 case INTERNET_PER_CONN_PROXY_BYPASS:
2933 FIXME("Unhandled dwOption %d\n", option->dwOption);
2934 break;
2935
2936 default:
2937 FIXME("Unknown dwOption %d\n", option->dwOption);
2938 SetLastError(ERROR_INVALID_PARAMETER);
2939 break;
2940 }
2941 }
2942
2943 if ((res = INTERNET_SaveProxySettings(&pi)))
2944 SetLastError(res);
2945
2946 FreeProxyInfo(&pi);
2947
2948 ret = (res == ERROR_SUCCESS);
2949 break;
2950 }
2951 default:
2952 FIXME("Option %d STUB\n",dwOption);
2953 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2954 ret = FALSE;
2955 break;
2956 }
2957
2958 if(lpwhh)
2959 WININET_Release( lpwhh );
2960
2961 return ret;
2962 }
2963
2964
2965 /***********************************************************************
2966 * InternetSetOptionA (WININET.@)
2967 *
2968 * Sets an options on the specified handle.
2969 *
2970 * RETURNS
2971 * TRUE on success
2972 * FALSE on failure
2973 *
2974 */
2975 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2976 LPVOID lpBuffer, DWORD dwBufferLength)
2977 {
2978 LPVOID wbuffer;
2979 DWORD wlen;
2980 BOOL r;
2981
2982 switch( dwOption )
2983 {
2984 case INTERNET_OPTION_PROXY:
2985 {
2986 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2987 LPINTERNET_PROXY_INFOW piw;
2988 DWORD proxlen, prbylen;
2989 LPWSTR prox, prby;
2990
2991 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2992 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2993 wlen = sizeof(*piw) + proxlen + prbylen;
2994 wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
2995 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2996 piw->dwAccessType = pi->dwAccessType;
2997 prox = (LPWSTR) &piw[1];
2998 prby = &prox[proxlen+1];
2999 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
3000 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
3001 piw->lpszProxy = prox;
3002 piw->lpszProxyBypass = prby;
3003 }
3004 break;
3005 case INTERNET_OPTION_USER_AGENT:
3006 case INTERNET_OPTION_USERNAME:
3007 case INTERNET_OPTION_PASSWORD:
3008 case INTERNET_OPTION_PROXY_USERNAME:
3009 case INTERNET_OPTION_PROXY_PASSWORD:
3010 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
3011 if (!(wbuffer = heap_alloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
3012 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
3013 break;
3014 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
3015 unsigned int i;
3016 INTERNET_PER_CONN_OPTION_LISTW *listW;
3017 INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
3018 wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3019 wbuffer = heap_alloc(wlen);
3020 listW = wbuffer;
3021
3022 listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3023 if (listA->pszConnection)
3024 {
3025 wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
3026 listW->pszConnection = heap_alloc(wlen*sizeof(WCHAR));
3027 MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
3028 }
3029 else
3030 listW->pszConnection = NULL;
3031 listW->dwOptionCount = listA->dwOptionCount;
3032 listW->dwOptionError = listA->dwOptionError;
3033 listW->pOptions = heap_alloc(sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount);
3034
3035 for (i = 0; i < listA->dwOptionCount; ++i) {
3036 INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
3037 INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
3038
3039 optW->dwOption = optA->dwOption;
3040
3041 switch (optA->dwOption) {
3042 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3043 case INTERNET_PER_CONN_PROXY_BYPASS:
3044 case INTERNET_PER_CONN_PROXY_SERVER:
3045 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3046 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3047 if (optA->Value.pszValue)
3048 {
3049 wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
3050 optW->Value.pszValue = heap_alloc(wlen*sizeof(WCHAR));
3051 MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
3052 }
3053 else
3054 optW->Value.pszValue = NULL;
3055 break;
3056 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3057 case INTERNET_PER_CONN_FLAGS:
3058 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3059 optW->Value.dwValue = optA->Value.dwValue;
3060 break;
3061 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3062 optW->Value.ftValue = optA->Value.ftValue;
3063 break;
3064 default:
3065 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
3066 optW->Value.dwValue = optA->Value.dwValue;
3067 break;
3068 }
3069 }
3070 }
3071 break;
3072 default:
3073 wbuffer = lpBuffer;
3074 wlen = dwBufferLength;
3075 }
3076
3077 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
3078
3079 if( lpBuffer != wbuffer )
3080 {
3081 if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
3082 {
3083 INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
3084 unsigned int i;
3085 for (i = 0; i < list->dwOptionCount; ++i) {
3086 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
3087 switch (opt->dwOption) {
3088 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3089 case INTERNET_PER_CONN_PROXY_BYPASS:
3090 case INTERNET_PER_CONN_PROXY_SERVER:
3091 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3092 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3093 heap_free( opt->Value.pszValue );
3094 break;
3095 default:
3096 break;
3097 }
3098 }
3099 heap_free( list->pOptions );
3100 }
3101 heap_free( wbuffer );
3102 }
3103
3104 return r;
3105 }
3106
3107
3108 /***********************************************************************
3109 * InternetSetOptionExA (WININET.@)
3110 */
3111 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
3112 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3113 {
3114 FIXME("Flags %08x ignored\n", dwFlags);
3115 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
3116 }
3117
3118 /***********************************************************************
3119 * InternetSetOptionExW (WININET.@)
3120 */
3121 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
3122 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3123 {
3124 FIXME("Flags %08x ignored\n", dwFlags);
3125 if( dwFlags & ~ISO_VALID_FLAGS )
3126 {
3127 SetLastError( ERROR_INVALID_PARAMETER );
3128 return FALSE;
3129 }
3130 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
3131 }
3132
3133 static const WCHAR WININET_wkday[7][4] =
3134 { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
3135 { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
3136 static const WCHAR WININET_month[12][4] =
3137 { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
3138 { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
3139 { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
3140
3141 /***********************************************************************
3142 * InternetTimeFromSystemTimeA (WININET.@)
3143 */
3144 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
3145 {
3146 BOOL ret;
3147 WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
3148
3149 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3150
3151 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3152 {
3153 SetLastError(ERROR_INVALID_PARAMETER);
3154 return FALSE;
3155 }
3156
3157 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3158 {
3159 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3160 return FALSE;
3161 }
3162
3163 ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
3164 if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
3165
3166 return ret;
3167 }
3168
3169 /***********************************************************************
3170 * InternetTimeFromSystemTimeW (WININET.@)
3171 */
3172 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
3173 {
3174 static const WCHAR date[] =
3175 { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
3176 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
3177
3178 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3179
3180 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3181 {
3182 SetLastError(ERROR_INVALID_PARAMETER);
3183 return FALSE;
3184 }
3185
3186 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3187 {
3188 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3189 return FALSE;
3190 }
3191
3192 sprintfW( string, date,
3193 WININET_wkday[time->wDayOfWeek],
3194 time->wDay,
3195 WININET_month[time->wMonth - 1],
3196 time->wYear,
3197 time->wHour,
3198 time->wMinute,
3199 time->wSecond );
3200
3201 return TRUE;
3202 }
3203
3204 /***********************************************************************
3205 * InternetTimeToSystemTimeA (WININET.@)
3206 */
3207 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
3208 {
3209 BOOL ret = FALSE;
3210 WCHAR *stringW;
3211
3212 TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
3213
3214 stringW = heap_strdupAtoW(string);
3215 if (stringW)
3216 {
3217 ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3218 heap_free( stringW );
3219 }
3220 return ret;
3221 }
3222
3223 /***********************************************************************
3224 * InternetTimeToSystemTimeW (WININET.@)
3225 */
3226 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3227 {
3228 unsigned int i;
3229 const WCHAR *s = string;
3230 WCHAR *end;
3231
3232 TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
3233
3234 if (!string || !time) return FALSE;
3235
3236 /* Windows does this too */
3237 GetSystemTime( time );
3238
3239 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3240 * a SYSTEMTIME structure.
3241 */
3242
3243 while (*s && !isalphaW( *s )) s++;
3244 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3245 time->wDayOfWeek = 7;
3246
3247 for (i = 0; i < 7; i++)
3248 {
3249 if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
3250 toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
3251 toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
3252 {
3253 time->wDayOfWeek = i;
3254 break;
3255 }
3256 }
3257
3258 if (time->wDayOfWeek > 6) return TRUE;
3259 while (*s && !isdigitW( *s )) s++;
3260 time->wDay = strtolW( s, &end, 10 );
3261 s = end;
3262
3263 while (*s && !isalphaW( *s )) s++;
3264 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3265 time->wMonth = 0;
3266
3267 for (i = 0; i < 12; i++)
3268 {
3269 if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
3270 toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
3271 toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
3272 {
3273 time->wMonth = i + 1;
3274 break;
3275 }
3276 }
3277 if (time->wMonth == 0) return TRUE;
3278
3279 while (*s && !isdigitW( *s )) s++;
3280 if (*s == '\0') return TRUE;
3281 time->wYear = strtolW( s, &end, 10 );
3282 s = end;
3283
3284 while (*s && !isdigitW( *s )) s++;
3285 if (*s == '\0') return TRUE;
3286 time->wHour = strtolW( s, &end, 10 );
3287 s = end;
3288
3289 while (*s && !isdigitW( *s )) s++;
3290 if (*s == '\0') return TRUE;
3291 time->wMinute = strtolW( s, &end, 10 );
3292 s = end;
3293
3294 while (*s && !isdigitW( *s )) s++;
3295 if (*s == '\0') return TRUE;
3296 time->wSecond = strtolW( s, &end, 10 );
3297 s = end;
3298
3299 time->wMilliseconds = 0;
3300 return TRUE;
3301 }
3302
3303 /***********************************************************************
3304 * InternetCheckConnectionW (WININET.@)
3305 *
3306 * Pings a requested host to check internet connection
3307 *
3308 * RETURNS
3309 * TRUE on success and FALSE on failure. If a failure then
3310 * ERROR_NOT_CONNECTED is placed into GetLastError
3311 *
3312 */
3313 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3314 {
3315 /*
3316 * this is a kludge which runs the resident ping program and reads the output.
3317 *
3318 * Anyone have a better idea?
3319 */
3320
3321 BOOL rc = FALSE;
3322 static const CHAR ping[] = "ping -c 1 ";
3323 static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3324 CHAR *command = NULL;
3325 WCHAR hostW[INTERNET_MAX_HOST_NAME_LENGTH];
3326 DWORD len;
3327 INTERNET_PORT port;
3328 int status = -1;
3329
3330 FIXME("\n");
3331
3332 /*
3333 * Crack or set the Address
3334 */
3335 if (lpszUrl == NULL)
3336 {
3337 /*
3338 * According to the doc we are supposed to use the ip for the next
3339 * server in the WnInet internal server database. I have
3340 * no idea what that is or how to get it.
3341 *
3342 * So someone needs to implement this.
3343 */
3344 FIXME("Unimplemented with URL of NULL\n");
3345 return TRUE;
3346 }
3347 else
3348 {
3349 URL_COMPONENTSW components;
3350
3351 ZeroMemory(&components,sizeof(URL_COMPONENTSW));
3352 components.lpszHostName = (LPWSTR)hostW;
3353 components.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
3354
3355 if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3356 goto End;
3357
3358 TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
3359 port = components.nPort;
3360 TRACE("port: %d\n", port);
3361 }
3362
3363 if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3364 {
3365 struct sockaddr_storage saddr;
3366 socklen_t sa_len = sizeof(saddr);
3367 int fd;
3368
3369 if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
3370 goto End;
3371 fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3372 if (fd != -1)
3373 {
3374 if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3375 rc = TRUE;
3376 close(fd);
3377 }
3378 }
3379 else
3380 {
3381 /*
3382 * Build our ping command
3383 */
3384 len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
3385 command = heap_alloc(strlen(ping)+len+strlen(redirect));
3386 strcpy(command,ping);
3387 WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
3388 strcat(command,redirect);
3389
3390 TRACE("Ping command is : %s\n",command);
3391
3392 status = system(command);
3393
3394 TRACE("Ping returned a code of %i\n",status);
3395
3396 /* Ping return code of 0 indicates success */
3397 if (status == 0)
3398 rc = TRUE;
3399 }
3400
3401 End:
3402 heap_free( command );
3403 if (rc == FALSE)
3404 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3405
3406 return rc;
3407 }
3408
3409
3410 /***********************************************************************
3411 * InternetCheckConnectionA (WININET.@)
3412 *
3413 * Pings a requested host to check internet connection
3414 *
3415 * RETURNS
3416 * TRUE on success and FALSE on failure. If a failure then
3417 * ERROR_NOT_CONNECTED is placed into GetLastError
3418 *
3419 */
3420 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3421 {
3422 WCHAR *url = NULL;
3423 BOOL rc;
3424
3425 if(lpszUrl) {
3426 url = heap_strdupAtoW(lpszUrl);
3427 if(!url)
3428 return FALSE;
3429 }
3430
3431 rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3432
3433 heap_free(url);
3434 return rc;
3435 }
3436
3437
3438 /**********************************************************
3439 * INTERNET_InternetOpenUrlW (internal)
3440 *
3441 * Opens an URL
3442 *
3443 * RETURNS
3444 * handle of connection or NULL on failure
3445 */
3446 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3447 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3448 {
3449 URL_COMPONENTSW urlComponents;
3450 WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH];
3451 WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH];
3452 WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH];
3453 WCHAR password[INTERNET_MAX_PASSWORD_LENGTH];
3454 WCHAR path[INTERNET_MAX_PATH_LENGTH];
3455 WCHAR extra[1024];
3456 HINTERNET client = NULL, client1 = NULL;
3457 DWORD res;
3458
3459 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3460 dwHeadersLength, dwFlags, dwContext);
3461
3462 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3463 urlComponents.lpszScheme = protocol;
3464 urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
3465 urlComponents.lpszHostName = hostName;
3466 urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
3467 urlComponents.lpszUserName = userName;
3468 urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
3469 urlComponents.lpszPassword = password;
3470 urlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
3471 urlComponents.lpszUrlPath = path;
3472 urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
3473 urlComponents.lpszExtraInfo = extra;
3474 urlComponents.dwExtraInfoLength = 1024;
3475 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3476 return NULL;
3477 switch(urlComponents.nScheme) {
3478 case INTERNET_SCHEME_FTP:
3479 if(urlComponents.nPort == 0)
3480 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
3481 client = FTP_Connect(hIC, hostName, urlComponents.nPort,
3482 userName, password, dwFlags, dwContext, INET_OPENURL);
3483 if(client == NULL)
3484 break;
3485 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3486 if(client1 == NULL) {
3487 InternetCloseHandle(client);
3488 break;
3489 }
3490 break;
3491
3492 case INTERNET_SCHEME_HTTP:
3493 case INTERNET_SCHEME_HTTPS: {
3494 static const WCHAR szStars[] = { '*','/','*', 0 };
3495 LPCWSTR accept[2] = { szStars, NULL };
3496 if(urlComponents.nPort == 0) {
3497 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
3498 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3499 else
3500 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3501 }
3502 if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3503
3504 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3505 res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
3506 userName, password, dwFlags, dwContext, INET_OPENURL, &client);
3507 if(res != ERROR_SUCCESS) {
3508 INTERNET_SetLastError(res);
3509 break;
3510 }
3511
3512 if (urlComponents.dwExtraInfoLength) {
3513 WCHAR *path_extra;
3514 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
3515
3516 if (!(path_extra = heap_alloc(len * sizeof(WCHAR))))
3517 {
3518 InternetCloseHandle(client);
3519 break;
3520 }
3521 strcpyW(path_extra, urlComponents.lpszUrlPath);
3522 strcatW(path_extra, urlComponents.lpszExtraInfo);
3523 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
3524 heap_free(path_extra);
3525 }
3526 else
3527 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3528
3529 if(client1 == NULL) {
3530 InternetCloseHandle(client);
3531 break;
3532 }
3533 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3534 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3535 GetLastError() != ERROR_IO_PENDING) {
3536 InternetCloseHandle(client1);
3537 client1 = NULL;
3538 break;
3539 }
3540 }
3541 case INTERNET_SCHEME_GOPHER:
3542 /* gopher doesn't seem to be implemented in wine, but it's supposed
3543 * to be supported by InternetOpenUrlA. */
3544 default:
3545 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3546 break;
3547 }
3548
3549 TRACE(" %p <--\n", client1);
3550
3551 return client1;
3552 }
3553
3554 /**********************************************************
3555 * InternetOpenUrlW (WININET.@)
3556 *
3557 * Opens an URL
3558 *
3559 * RETURNS
3560 * handle of connection or NULL on failure
3561 */
3562 typedef struct {
3563 task_header_t hdr;
3564 WCHAR *url;
3565 WCHAR *headers;
3566 DWORD headers_len;
3567 DWORD flags;
3568 DWORD_PTR context;
3569 } open_url_task_t;
3570
3571 static void AsyncInternetOpenUrlProc(task_header_t *hdr)
3572 {
3573 open_url_task_t *task = (open_url_task_t*)hdr;
3574
3575 TRACE("%p\n", task->hdr.hdr);
3576
3577 INTERNET_InternetOpenUrlW((appinfo_t*)task->hdr.hdr, task->url, task->headers,
3578 task->headers_len, task->flags, task->context);
3579 heap_free(task->url);
3580 heap_free(task->headers);
3581 }
3582
3583 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3584 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3585 {
3586 HINTERNET ret = NULL;
3587 appinfo_t *hIC = NULL;
3588
3589 if (TRACE_ON(wininet)) {
3590 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3591 dwHeadersLength, dwFlags, dwContext);
3592 TRACE(" flags :");
3593 dump_INTERNET_FLAGS(dwFlags);
3594 }
3595
3596 if (!lpszUrl)
3597 {
3598 SetLastError(ERROR_INVALID_PARAMETER);
3599 goto lend;
3600 }
3601
3602 hIC = (appinfo_t*)get_handle_object( hInternet );
3603 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
3604 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3605 goto lend;
3606 }
3607
3608 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3609 open_url_task_t *task;
3610
3611 task = alloc_async_task(&hIC->hdr, AsyncInternetOpenUrlProc, sizeof(*task));
3612 task->url = heap_strdupW(lpszUrl);
3613 task->headers = heap_strdupW(lpszHeaders);
3614 task->headers_len = dwHeadersLength;
3615 task->flags = dwFlags;
3616 task->context = dwContext;
3617
3618 INTERNET_AsyncCall(&task->hdr);
3619 SetLastError(ERROR_IO_PENDING);
3620 } else {
3621 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3622 }
3623
3624 lend:
3625 if( hIC )
3626 WININET_Release( &hIC->hdr );
3627 TRACE(" %p <--\n", ret);
3628
3629 return ret;
3630 }
3631
3632 /**********************************************************
3633 * InternetOpenUrlA (WININET.@)
3634 *
3635 * Opens an URL
3636 *
3637 * RETURNS
3638 * handle of connection or NULL on failure
3639 */
3640 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3641 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3642 {
3643 HINTERNET rc = NULL;
3644 DWORD lenHeaders = 0;
3645 LPWSTR szUrl = NULL;
3646 LPWSTR szHeaders = NULL;
3647
3648 TRACE("\n");
3649
3650 if(lpszUrl) {
3651 szUrl = heap_strdupAtoW(lpszUrl);
3652 if(!szUrl)
3653 return NULL;
3654 }
3655
3656 if(lpszHeaders) {
3657 lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3658 szHeaders = heap_alloc(lenHeaders*sizeof(WCHAR));
3659 if(!szHeaders) {
3660 heap_free(szUrl);
3661 return NULL;
3662 }
3663 MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3664 }
3665
3666 rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3667 lenHeaders, dwFlags, dwContext);
3668
3669 heap_free(szUrl);
3670 heap_free(szHeaders);
3671 return rc;
3672 }
3673
3674
3675 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3676 {
3677 LPWITHREADERROR lpwite = heap_alloc(sizeof(*lpwite));
3678
3679 if (lpwite)
3680 {
3681 lpwite->dwError = 0;
3682 lpwite->response[0] = '\0';
3683 }
3684
3685 if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3686 {
3687 heap_free(lpwite);
3688 return NULL;
3689 }
3690 return lpwite;
3691 }
3692
3693
3694 /***********************************************************************
3695 * INTERNET_SetLastError (internal)
3696 *
3697 * Set last thread specific error
3698 *
3699 * RETURNS
3700 *
3701 */
3702 void INTERNET_SetLastError(DWORD dwError)
3703 {
3704 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3705
3706 if (!lpwite)
3707 lpwite = INTERNET_AllocThreadError();
3708
3709 SetLastError(dwError);
3710 if(lpwite)
3711 lpwite->dwError = dwError;
3712 }
3713
3714
3715 /***********************************************************************
3716 * INTERNET_GetLastError (internal)
3717 *
3718 * Get last thread specific error
3719 *
3720 * RETURNS
3721 *
3722 */
3723 DWORD INTERNET_GetLastError(void)
3724 {
3725 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3726 if (!lpwite) return 0;
3727 /* TlsGetValue clears last error, so set it again here */
3728 SetLastError(lpwite->dwError);
3729 return lpwite->dwError;
3730 }
3731
3732
3733 /***********************************************************************
3734 * INTERNET_WorkerThreadFunc (internal)
3735 *
3736 * Worker thread execution function
3737 *
3738 * RETURNS
3739 *
3740 */
3741 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3742 {
3743 task_header_t *task = lpvParam;
3744
3745 TRACE("\n");
3746
3747 task->proc(task);
3748 WININET_Release(task->hdr);
3749 heap_free(task);
3750
3751 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3752 {
3753 heap_free(TlsGetValue(g_dwTlsErrIndex));
3754 TlsSetValue(g_dwTlsErrIndex, NULL);
3755 }
3756 return TRUE;
3757 }
3758
3759 void *alloc_async_task(object_header_t *hdr, async_task_proc_t proc, size_t size)
3760 {
3761 task_header_t *task;
3762
3763 task = heap_alloc(size);
3764 if(!task)
3765 return NULL;
3766
3767 task->hdr = WININET_AddRef(hdr);
3768 task->proc = proc;
3769 return task;
3770 }
3771
3772 /***********************************************************************
3773 * INTERNET_AsyncCall (internal)
3774 *
3775 * Retrieves work request from queue
3776 *
3777 * RETURNS
3778 *
3779 */
3780 DWORD INTERNET_AsyncCall(task_header_t *task)
3781 {
3782 BOOL bSuccess;
3783
3784 TRACE("\n");
3785
3786 bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, task, WT_EXECUTELONGFUNCTION);
3787 if (!bSuccess)
3788 {
3789 heap_free(task);
3790 return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3791 }
3792 return ERROR_SUCCESS;
3793 }
3794
3795
3796 /***********************************************************************
3797 * INTERNET_GetResponseBuffer (internal)
3798 *
3799 * RETURNS
3800 *
3801 */
3802 LPSTR INTERNET_GetResponseBuffer(void)
3803 {
3804 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3805 if (!lpwite)
3806 lpwite = INTERNET_AllocThreadError();
3807 TRACE("\n");
3808 return lpwite->response;
3809 }
3810
3811 /***********************************************************************
3812 * INTERNET_GetNextLine (internal)
3813 *
3814 * Parse next line in directory string listing
3815 *
3816 * RETURNS
3817 * Pointer to beginning of next line
3818 * NULL on failure
3819 *
3820 */
3821
3822 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3823 {
3824 // ReactOS: use select instead of poll
3825 fd_set infd;
3826 struct timeval tv;
3827 BOOL bSuccess = FALSE;
3828 INT nRecv = 0;
3829 LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3830
3831 TRACE("\n");
3832
3833 FD_ZERO(&infd);
3834 FD_SET(nSocket,&infd);
3835 tv.tv_sec = RESPONSE_TIMEOUT;
3836 tv.tv_usec = 0;
3837
3838 while (nRecv < MAX_REPLY_LEN)
3839 {
3840 if (select(0, &infd, NULL, NULL, &tv) > 0)
3841 {
3842 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3843 {
3844 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3845 goto lend;
3846 }
3847
3848 if (lpszBuffer[nRecv] == '\n')
3849 {
3850 bSuccess = TRUE;
3851 break;
3852 }
3853 if (lpszBuffer[nRecv] != '\r')
3854 nRecv++;
3855 }
3856 else
3857 {
3858 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3859 goto lend;
3860 }
3861 }
3862
3863 lend:
3864 if (bSuccess)
3865 {
3866 lpszBuffer[nRecv] = '\0';
3867 *dwLen = nRecv - 1;
3868 TRACE(":%d %s\n", nRecv, lpszBuffer);
3869 return lpszBuffer;
3870 }
3871 else
3872 {
3873 return NULL;
3874 }
3875 }
3876
3877 /**********************************************************
3878 * InternetQueryDataAvailable (WININET.@)
3879 *
3880 * Determines how much data is available to be read.
3881 *
3882 * RETURNS
3883 * TRUE on success, FALSE if an error occurred. If
3884 * INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3885 * no data is presently available, FALSE is returned with
3886 * the last error ERROR_IO_PENDING; a callback with status
3887 * INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3888 * data is available.
3889 */
3890 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3891 LPDWORD lpdwNumberOfBytesAvailable,
3892 DWORD dwFlags, DWORD_PTR dwContext)
3893 {
3894 object_header_t *hdr;
3895 DWORD res;
3896
3897 TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3898
3899 hdr = get_handle_object( hFile );
3900 if (!hdr) {
3901 SetLastError(ERROR_INVALID_HANDLE);
3902 return FALSE;
3903 }
3904
3905 if(hdr->vtbl->QueryDataAvailable) {
3906 res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3907 }else {
3908 WARN("wrong handle\n");
3909 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3910 }
3911
3912 WININET_Release(hdr);
3913
3914 if(res != ERROR_SUCCESS)
3915 SetLastError(res);
3916 return res == ERROR_SUCCESS;
3917 }
3918
3919
3920 /***********************************************************************
3921 * InternetLockRequestFile (WININET.@)
3922 */
3923 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3924 *lphLockReqHandle)
3925 {
3926 FIXME("STUB\n");
3927 return FALSE;
3928 }
3929
3930 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3931 {
3932 FIXME("STUB\n");
3933 return FALSE;
3934 }
3935
3936
3937 /***********************************************************************
3938 * InternetAutodial (WININET.@)
3939 *
3940 * On windows this function is supposed to dial the default internet
3941 * connection. We don't want to have Wine dial out to the internet so
3942 * we return TRUE by default. It might be nice to check if we are connected.
3943 *
3944 * RETURNS
3945 * TRUE on success
3946 * FALSE on failure
3947 *
3948 */
3949 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3950 {
3951 FIXME("STUB\n");
3952
3953 /* Tell that we are connected to the internet. */
3954 return TRUE;
3955 }
3956
3957 /***********************************************************************
3958 * InternetAutodialHangup (WININET.@)
3959 *
3960 * Hangs up a connection made with InternetAutodial
3961 *
3962 * PARAM
3963 * dwReserved
3964 * RETURNS
3965 * TRUE on success
3966 * FALSE on failure
3967 *
3968 */
3969 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3970 {
3971 FIXME("STUB\n");
3972
3973 /* we didn't dial, we don't disconnect */
3974 return TRUE;
3975 }
3976
3977 /***********************************************************************
3978 * InternetCombineUrlA (WININET.@)
3979 *
3980 * Combine a base URL with a relative URL
3981 *
3982 * RETURNS
3983 * TRUE on success
3984 * FALSE on failure
3985 *
3986 */
3987
3988 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3989 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3990 DWORD dwFlags)
3991 {
3992 HRESULT hr=S_OK;
3993
3994 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3995
3996 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3997 dwFlags ^= ICU_NO_ENCODE;
3998 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3999
4000 return (hr==S_OK);
4001 }
4002
4003 /***********************************************************************
4004 * InternetCombineUrlW (WININET.@)
4005 *
4006 * Combine a base URL with a relative URL
4007 *
4008 * RETURNS
4009 * TRUE on success
4010 * FALSE on failure
4011 *
4012 */
4013
4014 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
4015 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
4016 DWORD dwFlags)
4017 {
4018 HRESULT hr=S_OK;
4019
4020 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4021
4022 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4023 dwFlags ^= ICU_NO_ENCODE;
4024 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4025
4026 return (hr==S_OK);
4027 }
4028
4029 /* max port num is 65535 => 5 digits */
4030 #define MAX_WORD_DIGITS 5
4031
4032 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
4033 (url)->dw##component##Length : strlenW((url)->lpsz##component))
4034 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
4035 (url)->dw##component##Length : strlen((url)->lpsz##component))
4036
4037 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
4038 {
4039 if ((nScheme == INTERNET_SCHEME_HTTP) &&
4040 (nPort == INTERNET_DEFAULT_HTTP_PORT))
4041 return TRUE;
4042 if ((nScheme == INTERNET_SCHEME_HTTPS) &&
4043 (nPort == INTERNET_DEFAULT_HTTPS_PORT))
4044 return TRUE;
4045 if ((nScheme == INTERNET_SCHEME_FTP) &&
4046 (nPort == INTERNET_DEFAULT_FTP_PORT))
4047 return TRUE;
4048 if ((nScheme == INTERNET_SCHEME_GOPHER) &&
4049 (nPort == INTERNET_DEFAULT_GOPHER_PORT))
4050 return TRUE;
4051
4052 if (nPort == INTERNET_INVALID_PORT_NUMBER)
4053 return TRUE;
4054
4055 return FALSE;
4056 }
4057
4058 /* opaque urls do not fit into the standard url hierarchy and don't have
4059 * two following slashes */
4060 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
4061 {
4062 return (nScheme != INTERNET_SCHEME_FTP) &&
4063 (nScheme != INTERNET_SCHEME_GOPHER) &&
4064 (nScheme != INTERNET_SCHEME_HTTP) &&
4065 (nScheme != INTERNET_SCHEME_HTTPS) &&
4066 (nScheme != INTERNET_SCHEME_FILE);
4067 }
4068
4069 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
4070 {
4071 int index;
4072 if (scheme < INTERNET_SCHEME_FIRST)
4073 return NULL;
4074 index = scheme - INTERNET_SCHEME_FIRST;
4075 if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
4076 return NULL;
4077 return (LPCWSTR)url_schemes[index];
4078 }
4079
4080 /* we can calculate using ansi strings because we're just
4081 * calculating string length, not size
4082 */
4083 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
4084 LPDWORD lpdwUrlLength)
4085 {
4086 INTERNET_SCHEME nScheme;
4087
4088 *lpdwUrlLength = 0;
4089
4090 if (lpUrlComponents->lpszScheme)
4091 {
4092 DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4093 *lpdwUrlLength += dwLen;
4094 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4095 }
4096 else
4097 {
4098 LPCWSTR scheme;
4099
4100 nScheme = lpUrlComponents->nScheme;
4101
4102 if (nScheme == INTERNET_SCHEME_DEFAULT)
4103 nScheme = INTERNET_SCHEME_HTTP;
4104 scheme = INTERNET_GetSchemeString(nScheme);
4105 *lpdwUrlLength += strlenW(scheme);
4106 }
4107
4108 (*lpdwUrlLength)++; /* ':' */
4109 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4110 *lpdwUrlLength += strlen("//");
4111
4112 if (lpUrlComponents->lpszUserName)
4113 {
4114 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4115 *lpdwUrlLength += strlen("@");
4116 }
4117 else
4118 {
4119 if (lpUrlComponents->lpszPassword)
4120 {
4121 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4122 return FALSE;
4123 }
4124 }
4125
4126 if (lpUrlComponents->lpszPassword)
4127 {
4128 *lpdwUrlLength += strlen(":");
4129 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4130 }
4131
4132 if (lpUrlComponents->lpszHostName)
4133 {
4134 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4135
4136 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4137 {
4138 char szPort[MAX_WORD_DIGITS+1];
4139
4140 sprintf(szPort, "%d", lpUrlComponents->nPort);
4141 *lpdwUrlLength += strlen(szPort);
4142 *lpdwUrlLength += strlen(":");
4143 }
4144
4145 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4146 (*lpdwUrlLength)++; /* '/' */
4147 }
4148
4149 if (lpUrlComponents->lpszUrlPath)
4150 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4151
4152 if (lpUrlComponents->lpszExtraInfo)
4153 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4154
4155 return TRUE;
4156 }
4157
4158 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
4159 {
4160 INT len;
4161
4162 ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
4163
4164 urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
4165 urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
4166 urlCompW->nScheme = lpUrlComponents->nScheme;
4167 urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
4168 urlCompW->nPort = lpUrlComponents->nPort;
4169 urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
4170 urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
4171 urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
4172 urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
4173
4174 if (lpUrlComponents->lpszScheme)
4175 {
4176 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
4177 urlCompW->lpszScheme = heap_alloc(len * sizeof(WCHAR));
4178 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
4179 -1, urlCompW->lpszScheme, len);
4180 }
4181
4182 if (lpUrlComponents->lpszHostName)
4183 {
4184 len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
4185 urlCompW->lpszHostName = heap_alloc(len * sizeof(WCHAR));
4186 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
4187 -1, urlCompW->lpszHostName, len);
4188 }
4189
4190 if (lpUrlComponents->lpszUserName)
4191 {
4192 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
4193 urlCompW->lpszUserName = heap_alloc(len * sizeof(WCHAR));
4194 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
4195 -1, urlCompW->lpszUserName, len);
4196 }
4197
4198 if (lpUrlComponents->lpszPassword)
4199 {
4200 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
4201 urlCompW->lpszPassword = heap_alloc(len * sizeof(WCHAR));
4202 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
4203 -1, urlCompW->lpszPassword, len);
4204 }
4205
4206 if (lpUrlComponents->lpszUrlPath)
4207 {
4208 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
4209 urlCompW->lpszUrlPath = heap_alloc(len * sizeof(WCHAR));
4210 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
4211 -1, urlCompW->lpszUrlPath, len);
4212 }
4213
4214 if (lpUrlComponents->lpszExtraInfo)
4215 {
4216 len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4217 urlCompW->lpszExtraInfo = heap_alloc(len * sizeof(WCHAR));
4218 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4219 -1, urlCompW->lpszExtraInfo, len);
4220 }
4221 }
4222
4223 /***********************************************************************
4224 * InternetCreateUrlA (WININET.@)
4225 *
4226 * See InternetCreateUrlW.
4227 */
4228 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4229 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4230 {
4231 BOOL ret;
4232 LPWSTR urlW = NULL;
4233 URL_COMPONENTSW urlCompW;
4234
4235 TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4236
4237 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4238 {
4239 SetLastError(ERROR_INVALID_PARAMETER);
4240 return FALSE;
4241 }
4242
4243 convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4244
4245 if (lpszUrl)
4246 urlW = heap_alloc(*lpdwUrlLength * sizeof(WCHAR));
4247
4248 ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4249
4250 if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4251 *lpdwUrlLength /= sizeof(WCHAR);
4252
4253 /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4254 * minus one, so add one to leave room for NULL terminator
4255 */
4256 if (ret)
4257 WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4258
4259 heap_free(urlCompW.lpszScheme);
4260 heap_free(urlCompW.lpszHostName);
4261 heap_free(urlCompW.lpszUserName);
4262 heap_free(urlCompW.lpszPassword);
4263 heap_free(urlCompW.lpszUrlPath);
4264 heap_free(urlCompW.lpszExtraInfo);
4265 heap_free(urlW);
4266 return ret;
4267 }
4268
4269 /***********************************************************************
4270 * InternetCreateUrlW (WININET.@)
4271 *
4272 * Creates a URL from its component parts.
4273 *
4274 * PARAMS
4275 * lpUrlComponents [I] URL Components.
4276 * dwFlags [I] Flags. See notes.
4277 * lpszUrl [I] Buffer in which to store the created URL.
4278 * lpdwUrlLength [I/O] On input, the length of the buffer pointed to by
4279 * lpszUrl in characters. On output, the number of bytes
4280 * required to store the URL including terminator.
4281 *
4282 * NOTES
4283 *
4284 * The dwFlags parameter can be zero or more of the following:
4285 *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4286 *
4287 * RETURNS
4288 * TRUE on success
4289 * FALSE on failure
4290 *
4291 */
4292 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4293 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4294 {
4295 DWORD dwLen;
4296 INTERNET_SCHEME nScheme;
4297
4298 static const WCHAR slashSlashW[] = {'/','/'};
4299 static const WCHAR fmtW[] = {'%','u',0};
4300
4301 TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4302
4303 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4304 {
4305 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4306 return FALSE;
4307 }
4308
4309 if (!calc_url_length(lpUrlComponents, &dwLen))
4310 return FALSE;
4311
4312 if (!lpszUrl || *lpdwUrlLength < dwLen)
4313 {
4314 *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4315 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4316 return FALSE;
4317 }
4318
4319 *lpdwUrlLength = dwLen;
4320 lpszUrl[0] = 0x00;
4321
4322 dwLen = 0;
4323
4324 if (lpUrlComponents->lpszScheme)
4325 {
4326 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4327 memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4328 lpszUrl += dwLen;
4329
4330 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4331 }
4332 else
4333 {
4334 LPCWSTR scheme;
4335 nScheme = lpUrlComponents->nScheme;
4336
4337 if (nScheme == INTERNET_SCHEME_DEFAULT)
4338 nScheme = INTERNET_SCHEME_HTTP;
4339
4340 scheme = INTERNET_GetSchemeString(nScheme);
4341 dwLen = strlenW(scheme);
4342 memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4343 lpszUrl += dwLen;
4344 }
4345
4346 /* all schemes are followed by at least a colon */
4347 *lpszUrl = ':';
4348 lpszUrl++;
4349
4350 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4351 {
4352 memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4353 lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4354 }
4355
4356 if (lpUrlComponents->lpszUserName)
4357 {
4358 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4359 memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4360 lpszUrl += dwLen;
4361
4362 if (lpUrlComponents->lpszPassword)
4363 {
4364 *lpszUrl = ':';
4365 lpszUrl++;
4366
4367 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4368 memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4369 lpszUrl += dwLen;
4370 }
4371
4372 *lpszUrl = '@';
4373 lpszUrl++;
4374 }
4375
4376 if (lpUrlComponents->lpszHostName)
4377 {
4378 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4379 memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4380 lpszUrl += dwLen;
4381
4382 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4383 {
4384 WCHAR szPort[MAX_WORD_DIGITS+1];
4385
4386 sprintfW(szPort, fmtW, lpUrlComponents->nPort);
4387 *lpszUrl = ':';
4388 lpszUrl++;
4389 dwLen = strlenW(szPort);
4390 memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
4391 lpszUrl += dwLen;
4392 }
4393
4394 /* add slash between hostname and path if necessary */
4395 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4396 {
4397 *lpszUrl = '/';
4398 lpszUrl++;
4399 }
4400 }
4401
4402 if (lpUrlComponents->lpszUrlPath)
4403 {
4404 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4405 memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4406 lpszUrl += dwLen;
4407 }
4408
4409 if (lpUrlComponents->lpszExtraInfo)
4410 {
4411 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4412 memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4413 lpszUrl += dwLen;
4414 }
4415
4416 *lpszUrl = '\0';
4417
4418 return TRUE;
4419 }
4420
4421 /***********************************************************************
4422 * InternetConfirmZoneCrossingA (WININET.@)
4423 *
4424 */
4425 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4426 {
4427 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4428 return ERROR_SUCCESS;
4429 }
4430
4431 /***********************************************************************
4432 * InternetConfirmZoneCrossingW (WININET.@)
4433 *
4434 */
4435 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4436 {
4437 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4438 return ERROR_SUCCESS;
4439 }
4440
4441 static DWORD zone_preference = 3;
4442
4443 /***********************************************************************
4444 * PrivacySetZonePreferenceW (WININET.@)
4445 */
4446 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4447 {
4448 FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4449
4450 zone_preference = template;
4451 return 0;
4452 }
4453
4454 /***********************************************************************
4455 * PrivacyGetZonePreferenceW (WININET.@)
4456 */
4457 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4458 LPWSTR preference, LPDWORD length )
4459 {
4460 FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4461
4462 if (template) *template = zone_preference;
4463 return 0;
4464 }
4465
4466 /***********************************************************************
4467 * InternetGetSecurityInfoByURLA (WININET.@)
4468 */
4469 BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4470 {
4471 WCHAR *url;
4472 BOOL res;
4473
4474 TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags);
4475
4476 url = heap_strdupAtoW(lpszURL);
4477 if(!url)
4478 return FALSE;
4479
4480 res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags);
4481 heap_free(url);
4482 return res;
4483 }
4484
4485 /***********************************************************************
4486 * InternetGetSecurityInfoByURLW (WININET.@)
4487 */
4488 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4489 {
4490 WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH];
4491 URL_COMPONENTSW url = {sizeof(url)};
4492 server_t *server;
4493 BOOL res = FALSE;
4494
4495 TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
4496
4497 url.lpszHostName = hostname;
4498 url.dwHostNameLength = sizeof(hostname)/sizeof(WCHAR);
4499
4500 res = InternetCrackUrlW(lpszURL, 0, 0, &url);
4501 if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
4502 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4503 return FALSE;
4504 }
4505
4506 server = get_server(hostname, url.nPort, TRUE, FALSE);
4507 if(!server) {
4508 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4509 return FALSE;
4510 }
4511
4512 if(server->cert_chain) {
4513 const CERT_CHAIN_CONTEXT *chain_dup;
4514
4515 chain_dup = CertDuplicateCertificateChain(server->cert_chain);
4516 if(chain_dup) {
4517 *ppCertChain = chain_dup;
4518 *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
4519 }else {
4520 res = FALSE;
4521 }
4522 }else {
4523 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4524 res = FALSE;
4525 }
4526
4527 server_release(server);
4528 return res;
4529 }
4530
4531 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4532 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4533 {
4534 FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4535 lpdwConnection, dwReserved);
4536 return ERROR_SUCCESS;
4537 }
4538
4539 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4540 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4541 {
4542 FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4543 lpdwConnection, dwReserved);
4544 return ERROR_SUCCESS;
4545 }
4546
4547 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4548 {
4549 FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4550 return TRUE;
4551 }
4552
4553 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4554 {
4555 FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4556 return TRUE;
4557 }
4558
4559 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4560 {
4561 FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4562 return ERROR_SUCCESS;
4563 }
4564
4565 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4566 PBYTE pbHexHash )
4567 {
4568 FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4569 debugstr_w(pwszTarget), pbHexHash);
4570 return FALSE;
4571 }
4572
4573 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4574 {
4575 FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4576 return FALSE;
4577 }
4578
4579 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4580 {
4581 FIXME("(%p, %08lx) stub\n", a, b);
4582 return 0;
4583 }
4584
4585 DWORD WINAPI ShowClientAuthCerts(HWND parent)
4586 {
4587 FIXME("%p: stub\n", parent);
4588 return 0;
4589 }