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