wininet: Accept ProxyBypass from environment or registry.
[wine/multimedia.git] / dlls / wininet / internet.c
blobb9f3e9883b636623ba15d4edd026449ab37afa48
1 /*
2 * Wininet
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
10 * Ulrich Czekalla
11 * Aric Stewart
12 * David Hammerton
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.
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.
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
29 #include "config.h"
30 #include "wine/port.h"
32 #if defined(__MINGW32__) || defined (_MSC_VER)
33 #include <ws2tcpip.h>
34 #endif
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>
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winreg.h"
62 #include "winuser.h"
63 #include "wininet.h"
64 #include "winnls.h"
65 #include "wine/debug.h"
66 #include "winerror.h"
67 #define NO_SHLWAPI_STREAM
68 #include "shlwapi.h"
70 #include "wine/exception.h"
72 #include "internet.h"
73 #include "resource.h"
75 #include "wine/unicode.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
79 #define RESPONSE_TIMEOUT 30
81 typedef struct
83 DWORD dwError;
84 CHAR response[MAX_REPLY_LEN];
85 } WITHREADERROR, *LPWITHREADERROR;
87 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
88 HMODULE WININET_hModule;
90 static CRITICAL_SECTION WININET_cs;
91 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
93 0, 0, &WININET_cs,
94 { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
95 0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
97 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
99 static object_header_t **handle_table;
100 static UINT_PTR next_handle;
101 static UINT_PTR handle_table_size;
103 typedef struct
105 DWORD proxyEnabled;
106 LPWSTR proxy;
107 LPWSTR proxyBypass;
108 } proxyinfo_t;
110 static ULONG max_conns = 2, max_1_0_conns = 4;
111 static ULONG connect_timeout = 60000;
113 static const WCHAR szInternetSettings[] =
114 { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
115 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
116 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
117 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
118 static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
119 static const WCHAR szProxyOverride[] = { 'P','r','o','x','y','O','v','e','r','r','i','d','e', 0 };
121 void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
123 UINT_PTR handle = 0, num;
124 object_header_t *ret;
125 object_header_t **p;
126 BOOL res = TRUE;
128 ret = heap_alloc_zero(size);
129 if(!ret)
130 return NULL;
132 list_init(&ret->children);
134 EnterCriticalSection( &WININET_cs );
136 if(!handle_table_size) {
137 num = 16;
138 p = heap_alloc_zero(sizeof(handle_table[0]) * num);
139 if(p) {
140 handle_table = p;
141 handle_table_size = num;
142 next_handle = 1;
143 }else {
144 res = FALSE;
146 }else if(next_handle == handle_table_size) {
147 num = handle_table_size * 2;
148 p = heap_realloc_zero(handle_table, sizeof(handle_table[0]) * num);
149 if(p) {
150 handle_table = p;
151 handle_table_size = num;
152 }else {
153 res = FALSE;
157 if(res) {
158 handle = next_handle;
159 if(handle_table[handle])
160 ERR("handle isn't free but should be\n");
161 handle_table[handle] = ret;
162 ret->valid_handle = TRUE;
164 while(handle_table[next_handle] && next_handle < handle_table_size)
165 next_handle++;
168 LeaveCriticalSection( &WININET_cs );
170 if(!res) {
171 heap_free(ret);
172 return NULL;
175 ret->vtbl = vtbl;
176 ret->refs = 1;
177 ret->hInternet = (HINTERNET)handle;
179 if(parent) {
180 ret->lpfnStatusCB = parent->lpfnStatusCB;
181 ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
184 return ret;
187 object_header_t *WININET_AddRef( object_header_t *info )
189 ULONG refs = InterlockedIncrement(&info->refs);
190 TRACE("%p -> refcount = %d\n", info, refs );
191 return info;
194 object_header_t *get_handle_object( HINTERNET hinternet )
196 object_header_t *info = NULL;
197 UINT_PTR handle = (UINT_PTR) hinternet;
199 EnterCriticalSection( &WININET_cs );
201 if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
202 info = WININET_AddRef(handle_table[handle]);
204 LeaveCriticalSection( &WININET_cs );
206 TRACE("handle %ld -> %p\n", handle, info);
208 return info;
211 static void invalidate_handle(object_header_t *info)
213 object_header_t *child, *next;
215 if(!info->valid_handle)
216 return;
217 info->valid_handle = FALSE;
219 /* Free all children as native does */
220 LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
222 TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
223 invalidate_handle( child );
226 WININET_Release(info);
229 BOOL WININET_Release( object_header_t *info )
231 ULONG refs = InterlockedDecrement(&info->refs);
232 TRACE( "object %p refcount = %d\n", info, refs );
233 if( !refs )
235 invalidate_handle(info);
236 if ( info->vtbl->CloseConnection )
238 TRACE( "closing connection %p\n", info);
239 info->vtbl->CloseConnection( info );
241 /* Don't send a callback if this is a session handle created with InternetOpenUrl */
242 if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
243 || !(info->dwInternalFlags & INET_OPENURL))
245 INTERNET_SendCallback(info, info->dwContext,
246 INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
247 sizeof(HINTERNET));
249 TRACE( "destroying object %p\n", info);
250 if ( info->htype != WH_HINIT )
251 list_remove( &info->entry );
252 info->vtbl->Destroy( info );
254 if(info->hInternet) {
255 UINT_PTR handle = (UINT_PTR)info->hInternet;
257 EnterCriticalSection( &WININET_cs );
259 handle_table[handle] = NULL;
260 if(next_handle > handle)
261 next_handle = handle;
263 LeaveCriticalSection( &WININET_cs );
266 heap_free(info);
268 return TRUE;
271 /***********************************************************************
272 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
274 * PARAMS
275 * hinstDLL [I] handle to the DLL's instance
276 * fdwReason [I]
277 * lpvReserved [I] reserved, must be NULL
279 * RETURNS
280 * Success: TRUE
281 * Failure: FALSE
284 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
286 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
288 switch (fdwReason) {
289 case DLL_PROCESS_ATTACH:
291 g_dwTlsErrIndex = TlsAlloc();
293 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
294 return FALSE;
296 if(!init_urlcache())
298 TlsFree(g_dwTlsErrIndex);
299 return FALSE;
302 WININET_hModule = hinstDLL;
303 break;
305 case DLL_THREAD_ATTACH:
306 break;
308 case DLL_THREAD_DETACH:
309 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
311 heap_free(TlsGetValue(g_dwTlsErrIndex));
313 break;
315 case DLL_PROCESS_DETACH:
316 collect_connections(COLLECT_CLEANUP);
317 NETCON_unload();
318 free_urlcache();
319 free_cookie();
321 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
323 heap_free(TlsGetValue(g_dwTlsErrIndex));
324 TlsFree(g_dwTlsErrIndex);
326 break;
328 return TRUE;
331 /***********************************************************************
332 * INTERNET_SaveProxySettings
334 * Stores the proxy settings given by lpwai into the registry
336 * RETURNS
337 * ERROR_SUCCESS if no error, or error code on fail
339 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
341 HKEY key;
342 LONG ret;
344 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
345 return ret;
347 if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->proxyEnabled, sizeof(DWORD))))
349 RegCloseKey( key );
350 return ret;
353 if (lpwpi->proxy)
355 if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->proxy, sizeof(WCHAR) * (lstrlenW(lpwpi->proxy) + 1))))
357 RegCloseKey( key );
358 return ret;
361 else
363 if ((ret = RegDeleteValueW( key, szProxyServer )))
365 RegCloseKey( key );
366 return ret;
370 RegCloseKey(key);
371 return ERROR_SUCCESS;
374 /***********************************************************************
375 * INTERNET_FindProxyForProtocol
377 * Searches the proxy string for a proxy of the given protocol.
378 * Returns the found proxy, or the default proxy if none of the given
379 * protocol is found.
381 * PARAMETERS
382 * szProxy [In] proxy string to search
383 * proto [In] protocol to search for, e.g. "http"
384 * foundProxy [Out] found proxy
385 * foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
387 * RETURNS
388 * TRUE if a proxy is found, FALSE if not. If foundProxy is too short,
389 * *foundProxyLen is set to the required size in WCHARs, including the
390 * NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
392 BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen)
394 LPCWSTR ptr;
395 BOOL ret = FALSE;
397 TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
399 /* First, look for the specified protocol (proto=scheme://host:port) */
400 for (ptr = szProxy; !ret && ptr && *ptr; )
402 LPCWSTR end, equal;
404 if (!(end = strchrW(ptr, ' ')))
405 end = ptr + strlenW(ptr);
406 if ((equal = strchrW(ptr, '=')) && equal < end &&
407 equal - ptr == strlenW(proto) &&
408 !strncmpiW(proto, ptr, strlenW(proto)))
410 if (end - equal > *foundProxyLen)
412 WARN("buffer too short for %s\n",
413 debugstr_wn(equal + 1, end - equal - 1));
414 *foundProxyLen = end - equal;
415 SetLastError(ERROR_INSUFFICIENT_BUFFER);
417 else
419 memcpy(foundProxy, equal + 1, (end - equal) * sizeof(WCHAR));
420 foundProxy[end - equal] = 0;
421 ret = TRUE;
424 if (*end == ' ')
425 ptr = end + 1;
426 else
427 ptr = end;
429 if (!ret)
431 /* It wasn't found: look for no protocol */
432 for (ptr = szProxy; !ret && ptr && *ptr; )
434 LPCWSTR end;
436 if (!(end = strchrW(ptr, ' ')))
437 end = ptr + strlenW(ptr);
438 if (!strchrW(ptr, '='))
440 if (end - ptr + 1 > *foundProxyLen)
442 WARN("buffer too short for %s\n",
443 debugstr_wn(ptr, end - ptr));
444 *foundProxyLen = end - ptr + 1;
445 SetLastError(ERROR_INSUFFICIENT_BUFFER);
447 else
449 memcpy(foundProxy, ptr, (end - ptr) * sizeof(WCHAR));
450 foundProxy[end - ptr] = 0;
451 ret = TRUE;
454 if (*end == ' ')
455 ptr = end + 1;
456 else
457 ptr = end;
460 if (ret)
461 TRACE("found proxy for %s: %s\n", debugstr_w(proto),
462 debugstr_w(foundProxy));
463 return ret;
466 /***********************************************************************
467 * InternetInitializeAutoProxyDll (WININET.@)
469 * Setup the internal proxy
471 * PARAMETERS
472 * dwReserved
474 * RETURNS
475 * FALSE on failure
478 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
480 FIXME("STUB\n");
481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
482 return FALSE;
485 /***********************************************************************
486 * DetectAutoProxyUrl (WININET.@)
488 * Auto detect the proxy url
490 * RETURNS
491 * FALSE on failure
494 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
495 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
497 FIXME("STUB\n");
498 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
499 return FALSE;
502 static void FreeProxyInfo( proxyinfo_t *lpwpi )
504 heap_free(lpwpi->proxy);
505 heap_free(lpwpi->proxyBypass);
508 static proxyinfo_t *global_proxy;
510 static void free_global_proxy( void )
512 EnterCriticalSection( &WININET_cs );
513 if (global_proxy)
515 FreeProxyInfo( global_proxy );
516 heap_free( global_proxy );
518 LeaveCriticalSection( &WININET_cs );
521 /***********************************************************************
522 * INTERNET_LoadProxySettings
524 * Loads proxy information from process-wide global settings, the registry,
525 * or the environment into lpwpi.
527 * The caller should call FreeProxyInfo when done with lpwpi.
529 * FIXME:
530 * The proxy may be specified in the form 'http=proxy.my.org'
531 * Presumably that means there can be ftp=ftpproxy.my.org too.
533 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
535 HKEY key;
536 DWORD type, len;
537 LPCSTR envproxy;
538 LONG ret;
540 EnterCriticalSection( &WININET_cs );
541 if (global_proxy)
543 lpwpi->proxyEnabled = global_proxy->proxyEnabled;
544 lpwpi->proxy = heap_strdupW( global_proxy->proxy );
545 lpwpi->proxyBypass = heap_strdupW( global_proxy->proxyBypass );
547 LeaveCriticalSection( &WININET_cs );
549 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
550 return ret;
552 len = sizeof(DWORD);
553 if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->proxyEnabled, &len ) || type != REG_DWORD)
555 lpwpi->proxyEnabled = 0;
556 if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->proxyEnabled, sizeof(DWORD) )))
558 RegCloseKey( key );
559 return ret;
563 if (!(envproxy = getenv( "http_proxy" )) || lpwpi->proxyEnabled)
565 TRACE("Proxy is enabled.\n");
567 /* figure out how much memory the proxy setting takes */
568 if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
570 LPWSTR szProxy, p;
571 static const WCHAR szHttp[] = {'h','t','t','p','=',0};
573 if (!(szProxy = heap_alloc(len)))
575 RegCloseKey( key );
576 return ERROR_OUTOFMEMORY;
578 RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
580 /* find the http proxy, and strip away everything else */
581 p = strstrW( szProxy, szHttp );
582 if (p)
584 p += lstrlenW( szHttp );
585 lstrcpyW( szProxy, p );
587 p = strchrW( szProxy, ' ' );
588 if (p) *p = 0;
590 lpwpi->proxy = szProxy;
592 TRACE("http proxy = %s\n", debugstr_w(lpwpi->proxy));
594 else
596 TRACE("No proxy server settings in registry.\n");
597 lpwpi->proxy = NULL;
600 else if (envproxy)
602 WCHAR *envproxyW;
604 len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
605 if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
606 return ERROR_OUTOFMEMORY;
607 MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
609 lpwpi->proxyEnabled = 1;
610 lpwpi->proxy = envproxyW;
612 TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
615 lpwpi->proxyBypass = NULL;
616 if (lpwpi->proxyEnabled)
618 if (!(envproxy = getenv( "no_proxy" )))
620 /* figure out how much memory the proxy setting takes */
621 if (!RegQueryValueExW( key, szProxyOverride, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
623 LPWSTR szProxy;
625 if (!(szProxy = heap_alloc(len)))
627 RegCloseKey( key );
628 return ERROR_OUTOFMEMORY;
630 RegQueryValueExW( key, szProxyOverride, NULL, &type, (BYTE*)szProxy, &len );
632 lpwpi->proxyBypass = szProxy;
634 TRACE("http proxy bypass = %s\n", debugstr_w(lpwpi->proxyBypass));
636 else
638 TRACE("No proxy bypass server settings in registry.\n");
641 else if (envproxy)
643 WCHAR *envproxyW;
645 len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
646 if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
647 return ERROR_OUTOFMEMORY;
648 MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
650 lpwpi->proxyBypass = envproxyW;
652 TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass));
656 RegCloseKey( key );
658 return ERROR_SUCCESS;
661 /***********************************************************************
662 * INTERNET_ConfigureProxy
664 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
666 proxyinfo_t wpi;
668 if (INTERNET_LoadProxySettings( &wpi ))
669 return FALSE;
671 if (wpi.proxyEnabled)
673 WCHAR proxyurl[INTERNET_MAX_URL_LENGTH];
674 WCHAR username[INTERNET_MAX_USER_NAME_LENGTH];
675 WCHAR password[INTERNET_MAX_PASSWORD_LENGTH];
676 WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH];
677 URL_COMPONENTSW UrlComponents;
679 UrlComponents.dwStructSize = sizeof UrlComponents;
680 UrlComponents.dwSchemeLength = 0;
681 UrlComponents.lpszHostName = hostname;
682 UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
683 UrlComponents.lpszUserName = username;
684 UrlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
685 UrlComponents.lpszPassword = password;
686 UrlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
687 UrlComponents.dwUrlPathLength = 0;
688 UrlComponents.dwExtraInfoLength = 0;
690 if(InternetCrackUrlW(wpi.proxy, 0, 0, &UrlComponents))
692 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 };
694 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
695 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
696 sprintfW(proxyurl, szFormat, hostname, UrlComponents.nPort);
698 lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
699 lpwai->proxy = heap_strdupW(proxyurl);
700 if (UrlComponents.dwUserNameLength)
702 lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName);
703 lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword);
706 TRACE("http proxy = %s\n", debugstr_w(lpwai->proxy));
707 return TRUE;
709 else
711 TRACE("Failed to parse proxy: %s\n", debugstr_w(wpi.proxy));
712 lpwai->proxy = NULL;
716 lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
717 return FALSE;
720 /***********************************************************************
721 * dump_INTERNET_FLAGS
723 * Helper function to TRACE the internet flags.
725 * RETURNS
726 * None
729 static void dump_INTERNET_FLAGS(DWORD dwFlags)
731 #define FE(x) { x, #x }
732 static const wininet_flag_info flag[] = {
733 FE(INTERNET_FLAG_RELOAD),
734 FE(INTERNET_FLAG_RAW_DATA),
735 FE(INTERNET_FLAG_EXISTING_CONNECT),
736 FE(INTERNET_FLAG_ASYNC),
737 FE(INTERNET_FLAG_PASSIVE),
738 FE(INTERNET_FLAG_NO_CACHE_WRITE),
739 FE(INTERNET_FLAG_MAKE_PERSISTENT),
740 FE(INTERNET_FLAG_FROM_CACHE),
741 FE(INTERNET_FLAG_SECURE),
742 FE(INTERNET_FLAG_KEEP_CONNECTION),
743 FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
744 FE(INTERNET_FLAG_READ_PREFETCH),
745 FE(INTERNET_FLAG_NO_COOKIES),
746 FE(INTERNET_FLAG_NO_AUTH),
747 FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
748 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
749 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
750 FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
751 FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
752 FE(INTERNET_FLAG_RESYNCHRONIZE),
753 FE(INTERNET_FLAG_HYPERLINK),
754 FE(INTERNET_FLAG_NO_UI),
755 FE(INTERNET_FLAG_PRAGMA_NOCACHE),
756 FE(INTERNET_FLAG_CACHE_ASYNC),
757 FE(INTERNET_FLAG_FORMS_SUBMIT),
758 FE(INTERNET_FLAG_NEED_FILE),
759 FE(INTERNET_FLAG_TRANSFER_ASCII),
760 FE(INTERNET_FLAG_TRANSFER_BINARY)
762 #undef FE
763 unsigned int i;
765 for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
766 if (flag[i].val & dwFlags) {
767 TRACE(" %s", flag[i].name);
768 dwFlags &= ~flag[i].val;
771 if (dwFlags)
772 TRACE(" Unknown flags (%08x)\n", dwFlags);
773 else
774 TRACE("\n");
777 /***********************************************************************
778 * INTERNET_CloseHandle (internal)
780 * Close internet handle
783 static VOID APPINFO_Destroy(object_header_t *hdr)
785 appinfo_t *lpwai = (appinfo_t*)hdr;
787 TRACE("%p\n",lpwai);
789 heap_free(lpwai->agent);
790 heap_free(lpwai->proxy);
791 heap_free(lpwai->proxyBypass);
792 heap_free(lpwai->proxyUsername);
793 heap_free(lpwai->proxyPassword);
796 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
798 appinfo_t *ai = (appinfo_t*)hdr;
800 switch(option) {
801 case INTERNET_OPTION_HANDLE_TYPE:
802 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
804 if (*size < sizeof(ULONG))
805 return ERROR_INSUFFICIENT_BUFFER;
807 *size = sizeof(DWORD);
808 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
809 return ERROR_SUCCESS;
811 case INTERNET_OPTION_USER_AGENT: {
812 DWORD bufsize;
814 TRACE("INTERNET_OPTION_USER_AGENT\n");
816 bufsize = *size;
818 if (unicode) {
819 DWORD len = ai->agent ? strlenW(ai->agent) : 0;
821 *size = (len + 1) * sizeof(WCHAR);
822 if(!buffer || bufsize < *size)
823 return ERROR_INSUFFICIENT_BUFFER;
825 if (ai->agent)
826 strcpyW(buffer, ai->agent);
827 else
828 *(WCHAR *)buffer = 0;
829 /* If the buffer is copied, the returned length doesn't include
830 * the NULL terminator.
832 *size = len;
833 }else {
834 if (ai->agent)
835 *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
836 else
837 *size = 1;
838 if(!buffer || bufsize < *size)
839 return ERROR_INSUFFICIENT_BUFFER;
841 if (ai->agent)
842 WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
843 else
844 *(char *)buffer = 0;
845 /* If the buffer is copied, the returned length doesn't include
846 * the NULL terminator.
848 *size -= 1;
851 return ERROR_SUCCESS;
854 case INTERNET_OPTION_PROXY:
855 if(!size) return ERROR_INVALID_PARAMETER;
856 if (unicode) {
857 INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
858 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
859 LPWSTR proxy, proxy_bypass;
861 if (ai->proxy)
862 proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
863 if (ai->proxyBypass)
864 proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
865 if (!pi || *size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
867 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
868 return ERROR_INSUFFICIENT_BUFFER;
870 proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
871 proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
873 pi->dwAccessType = ai->accessType;
874 pi->lpszProxy = NULL;
875 pi->lpszProxyBypass = NULL;
876 if (ai->proxy) {
877 lstrcpyW(proxy, ai->proxy);
878 pi->lpszProxy = proxy;
881 if (ai->proxyBypass) {
882 lstrcpyW(proxy_bypass, ai->proxyBypass);
883 pi->lpszProxyBypass = proxy_bypass;
886 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
887 return ERROR_SUCCESS;
888 }else {
889 INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
890 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
891 LPSTR proxy, proxy_bypass;
893 if (ai->proxy)
894 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
895 if (ai->proxyBypass)
896 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
897 NULL, 0, NULL, NULL);
898 if (!pi || *size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
900 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
901 return ERROR_INSUFFICIENT_BUFFER;
903 proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
904 proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
906 pi->dwAccessType = ai->accessType;
907 pi->lpszProxy = NULL;
908 pi->lpszProxyBypass = NULL;
909 if (ai->proxy) {
910 WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
911 pi->lpszProxy = proxy;
914 if (ai->proxyBypass) {
915 WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
916 proxyBypassBytesRequired, NULL, NULL);
917 pi->lpszProxyBypass = proxy_bypass;
920 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
921 return ERROR_SUCCESS;
924 case INTERNET_OPTION_CONNECT_TIMEOUT:
925 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
927 if (*size < sizeof(ULONG))
928 return ERROR_INSUFFICIENT_BUFFER;
930 *(ULONG*)buffer = ai->connect_timeout;
931 *size = sizeof(ULONG);
933 return ERROR_SUCCESS;
936 return INET_QueryOption(hdr, option, buffer, size, unicode);
939 static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
941 appinfo_t *ai = (appinfo_t*)hdr;
943 switch(option) {
944 case INTERNET_OPTION_CONNECT_TIMEOUT:
945 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
947 if(size != sizeof(connect_timeout))
948 return ERROR_INTERNET_BAD_OPTION_LENGTH;
949 if(!*(ULONG*)buf)
950 return ERROR_BAD_ARGUMENTS;
952 ai->connect_timeout = *(ULONG*)buf;
953 return ERROR_SUCCESS;
954 case INTERNET_OPTION_USER_AGENT:
955 heap_free(ai->agent);
956 if (!(ai->agent = heap_strdupW(buf))) return ERROR_OUTOFMEMORY;
957 return ERROR_SUCCESS;
960 return INET_SetOption(hdr, option, buf, size);
963 static const object_vtbl_t APPINFOVtbl = {
964 APPINFO_Destroy,
965 NULL,
966 APPINFO_QueryOption,
967 APPINFO_SetOption,
968 NULL,
969 NULL,
970 NULL,
971 NULL
975 /***********************************************************************
976 * InternetOpenW (WININET.@)
978 * Per-application initialization of wininet
980 * RETURNS
981 * HINTERNET on success
982 * NULL on failure
985 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
986 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
988 appinfo_t *lpwai = NULL;
990 if (TRACE_ON(wininet)) {
991 #define FE(x) { x, #x }
992 static const wininet_flag_info access_type[] = {
993 FE(INTERNET_OPEN_TYPE_PRECONFIG),
994 FE(INTERNET_OPEN_TYPE_DIRECT),
995 FE(INTERNET_OPEN_TYPE_PROXY),
996 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
998 #undef FE
999 DWORD i;
1000 const char *access_type_str = "Unknown";
1002 TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
1003 debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
1004 for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
1005 if (access_type[i].val == dwAccessType) {
1006 access_type_str = access_type[i].name;
1007 break;
1010 TRACE(" access type : %s\n", access_type_str);
1011 TRACE(" flags :");
1012 dump_INTERNET_FLAGS(dwFlags);
1015 /* Clear any error information */
1016 INTERNET_SetLastError(0);
1018 lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
1019 if (!lpwai) {
1020 SetLastError(ERROR_OUTOFMEMORY);
1021 return NULL;
1024 lpwai->hdr.htype = WH_HINIT;
1025 lpwai->hdr.dwFlags = dwFlags;
1026 lpwai->accessType = dwAccessType;
1027 lpwai->proxyUsername = NULL;
1028 lpwai->proxyPassword = NULL;
1029 lpwai->connect_timeout = connect_timeout;
1031 lpwai->agent = heap_strdupW(lpszAgent);
1032 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
1033 INTERNET_ConfigureProxy( lpwai );
1034 else
1035 lpwai->proxy = heap_strdupW(lpszProxy);
1036 lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);
1038 TRACE("returning %p\n", lpwai);
1040 return lpwai->hdr.hInternet;
1044 /***********************************************************************
1045 * InternetOpenA (WININET.@)
1047 * Per-application initialization of wininet
1049 * RETURNS
1050 * HINTERNET on success
1051 * NULL on failure
1054 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
1055 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
1057 WCHAR *szAgent, *szProxy, *szBypass;
1058 HINTERNET rc;
1060 TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
1061 dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
1063 szAgent = heap_strdupAtoW(lpszAgent);
1064 szProxy = heap_strdupAtoW(lpszProxy);
1065 szBypass = heap_strdupAtoW(lpszProxyBypass);
1067 rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
1069 heap_free(szAgent);
1070 heap_free(szProxy);
1071 heap_free(szBypass);
1072 return rc;
1075 /***********************************************************************
1076 * InternetGetLastResponseInfoA (WININET.@)
1078 * Return last wininet error description on the calling thread
1080 * RETURNS
1081 * TRUE on success of writing to buffer
1082 * FALSE on failure
1085 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
1086 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
1088 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1090 TRACE("\n");
1092 if (lpwite)
1094 *lpdwError = lpwite->dwError;
1095 if (lpwite->dwError)
1097 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1098 *lpdwBufferLength = strlen(lpszBuffer);
1100 else
1101 *lpdwBufferLength = 0;
1103 else
1105 *lpdwError = 0;
1106 *lpdwBufferLength = 0;
1109 return TRUE;
1112 /***********************************************************************
1113 * InternetGetLastResponseInfoW (WININET.@)
1115 * Return last wininet error description on the calling thread
1117 * RETURNS
1118 * TRUE on success of writing to buffer
1119 * FALSE on failure
1122 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
1123 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
1125 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1127 TRACE("\n");
1129 if (lpwite)
1131 *lpdwError = lpwite->dwError;
1132 if (lpwite->dwError)
1134 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1135 *lpdwBufferLength = lstrlenW(lpszBuffer);
1137 else
1138 *lpdwBufferLength = 0;
1140 else
1142 *lpdwError = 0;
1143 *lpdwBufferLength = 0;
1146 return TRUE;
1149 /***********************************************************************
1150 * InternetGetConnectedState (WININET.@)
1152 * Return connected state
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
1160 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
1162 TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
1164 if (lpdwStatus) {
1165 WARN("always returning LAN connection.\n");
1166 *lpdwStatus = INTERNET_CONNECTION_LAN;
1168 return TRUE;
1172 /***********************************************************************
1173 * InternetGetConnectedStateExW (WININET.@)
1175 * Return connected state
1177 * PARAMS
1179 * lpdwStatus [O] Flags specifying the status of the internet connection.
1180 * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
1181 * dwNameLen [I] Size of the buffer, in characters.
1182 * dwReserved [I] Reserved. Must be set to 0.
1184 * RETURNS
1185 * TRUE if connected
1186 * if lpdwStatus is not null, return the status (off line,
1187 * modem, lan...) in it.
1188 * FALSE if not connected
1190 * NOTES
1191 * If the system has no available network connections, an empty string is
1192 * stored in lpszConnectionName. If there is a LAN connection, a localized
1193 * "LAN Connection" string is stored. Presumably, if only a dial-up
1194 * connection is available then the name of the dial-up connection is
1195 * returned. Why any application, other than the "Internet Settings" CPL,
1196 * would want to use this function instead of the simpler InternetGetConnectedStateW
1197 * function is beyond me.
1199 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
1200 DWORD dwNameLen, DWORD dwReserved)
1202 TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1204 /* Must be zero */
1205 if(dwReserved)
1206 return FALSE;
1208 if (lpdwStatus) {
1209 WARN("always returning LAN connection.\n");
1210 *lpdwStatus = INTERNET_CONNECTION_LAN;
1212 return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
1216 /***********************************************************************
1217 * InternetGetConnectedStateExA (WININET.@)
1219 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
1220 DWORD dwNameLen, DWORD dwReserved)
1222 LPWSTR lpwszConnectionName = NULL;
1223 BOOL rc;
1225 TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1227 if (lpszConnectionName && dwNameLen > 0)
1228 lpwszConnectionName = heap_alloc(dwNameLen * sizeof(WCHAR));
1230 rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
1231 dwReserved);
1232 if (rc && lpwszConnectionName)
1234 WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
1235 dwNameLen, NULL, NULL);
1236 heap_free(lpwszConnectionName);
1238 return rc;
1242 /***********************************************************************
1243 * InternetConnectW (WININET.@)
1245 * Open a ftp, gopher or http session
1247 * RETURNS
1248 * HINTERNET a session handle on success
1249 * NULL on failure
1252 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
1253 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
1254 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
1255 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1257 appinfo_t *hIC;
1258 HINTERNET rc = NULL;
1259 DWORD res = ERROR_SUCCESS;
1261 TRACE("(%p, %s, %i, %s, %s, %i, %x, %lx)\n", hInternet, debugstr_w(lpszServerName),
1262 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
1263 dwService, dwFlags, dwContext);
1265 if (!lpszServerName)
1267 SetLastError(ERROR_INVALID_PARAMETER);
1268 return NULL;
1271 hIC = (appinfo_t*)get_handle_object( hInternet );
1272 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1274 res = ERROR_INVALID_HANDLE;
1275 goto lend;
1278 switch (dwService)
1280 case INTERNET_SERVICE_FTP:
1281 rc = FTP_Connect(hIC, lpszServerName, nServerPort,
1282 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
1283 if(!rc)
1284 res = INTERNET_GetLastError();
1285 break;
1287 case INTERNET_SERVICE_HTTP:
1288 res = HTTP_Connect(hIC, lpszServerName, nServerPort,
1289 lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
1290 break;
1292 case INTERNET_SERVICE_GOPHER:
1293 default:
1294 break;
1296 lend:
1297 if( hIC )
1298 WININET_Release( &hIC->hdr );
1300 TRACE("returning %p\n", rc);
1301 SetLastError(res);
1302 return rc;
1306 /***********************************************************************
1307 * InternetConnectA (WININET.@)
1309 * Open a ftp, gopher or http session
1311 * RETURNS
1312 * HINTERNET a session handle on success
1313 * NULL on failure
1316 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
1317 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
1318 LPCSTR lpszUserName, LPCSTR lpszPassword,
1319 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1321 HINTERNET rc = NULL;
1322 LPWSTR szServerName;
1323 LPWSTR szUserName;
1324 LPWSTR szPassword;
1326 szServerName = heap_strdupAtoW(lpszServerName);
1327 szUserName = heap_strdupAtoW(lpszUserName);
1328 szPassword = heap_strdupAtoW(lpszPassword);
1330 rc = InternetConnectW(hInternet, szServerName, nServerPort,
1331 szUserName, szPassword, dwService, dwFlags, dwContext);
1333 heap_free(szServerName);
1334 heap_free(szUserName);
1335 heap_free(szPassword);
1336 return rc;
1340 /***********************************************************************
1341 * InternetFindNextFileA (WININET.@)
1343 * Continues a file search from a previous call to FindFirstFile
1345 * RETURNS
1346 * TRUE on success
1347 * FALSE on failure
1350 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
1352 BOOL ret;
1353 WIN32_FIND_DATAW fd;
1355 ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
1356 if(lpvFindData)
1357 WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
1358 return ret;
1361 /***********************************************************************
1362 * InternetFindNextFileW (WININET.@)
1364 * Continues a file search from a previous call to FindFirstFile
1366 * RETURNS
1367 * TRUE on success
1368 * FALSE on failure
1371 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
1373 object_header_t *hdr;
1374 DWORD res;
1376 TRACE("\n");
1378 hdr = get_handle_object(hFind);
1379 if(!hdr) {
1380 WARN("Invalid handle\n");
1381 SetLastError(ERROR_INVALID_HANDLE);
1382 return FALSE;
1385 if(hdr->vtbl->FindNextFileW) {
1386 res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1387 }else {
1388 WARN("Handle doesn't support NextFile\n");
1389 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1392 WININET_Release(hdr);
1394 if(res != ERROR_SUCCESS)
1395 SetLastError(res);
1396 return res == ERROR_SUCCESS;
1399 /***********************************************************************
1400 * InternetCloseHandle (WININET.@)
1402 * Generic close handle function
1404 * RETURNS
1405 * TRUE on success
1406 * FALSE on failure
1409 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1411 object_header_t *obj;
1413 TRACE("%p\n", hInternet);
1415 obj = get_handle_object( hInternet );
1416 if (!obj) {
1417 SetLastError(ERROR_INVALID_HANDLE);
1418 return FALSE;
1421 invalidate_handle(obj);
1422 WININET_Release(obj);
1424 return TRUE;
1428 /***********************************************************************
1429 * ConvertUrlComponentValue (Internal)
1431 * Helper function for InternetCrackUrlA
1434 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1435 LPWSTR lpwszComponent, DWORD dwwComponentLen,
1436 LPCSTR lpszStart, LPCWSTR lpwszStart)
1438 TRACE("%p %d %p %d %p %p\n", *lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
1439 if (*dwComponentLen != 0)
1441 DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1442 if (*lppszComponent == NULL)
1444 if (lpwszComponent)
1446 int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL);
1447 *lppszComponent = (LPSTR)lpszStart + offset;
1449 else
1450 *lppszComponent = NULL;
1452 *dwComponentLen = nASCIILength;
1454 else
1456 DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1457 WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1458 (*lppszComponent)[ncpylen]=0;
1459 *dwComponentLen = ncpylen;
1465 /***********************************************************************
1466 * InternetCrackUrlA (WININET.@)
1468 * See InternetCrackUrlW.
1470 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1471 LPURL_COMPONENTSA lpUrlComponents)
1473 DWORD nLength;
1474 URL_COMPONENTSW UCW;
1475 BOOL ret = FALSE;
1476 WCHAR *lpwszUrl, *hostname = NULL, *username = NULL, *password = NULL, *path = NULL,
1477 *scheme = NULL, *extra = NULL;
1479 TRACE("(%s %u %x %p)\n",
1480 lpszUrl ? debugstr_an(lpszUrl, dwUrlLength ? dwUrlLength : strlen(lpszUrl)) : "(null)",
1481 dwUrlLength, dwFlags, lpUrlComponents);
1483 if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1484 lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1486 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1487 return FALSE;
1490 if(dwUrlLength<=0)
1491 dwUrlLength=-1;
1492 nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1494 /* if dwUrlLength=-1 then nLength includes null but length to
1495 InternetCrackUrlW should not include it */
1496 if (dwUrlLength == -1) nLength--;
1498 lpwszUrl = heap_alloc((nLength + 1) * sizeof(WCHAR));
1499 MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength + 1);
1500 lpwszUrl[nLength] = '\0';
1502 memset(&UCW,0,sizeof(UCW));
1503 UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1504 if (lpUrlComponents->dwHostNameLength)
1506 UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
1507 if (lpUrlComponents->lpszHostName)
1509 hostname = heap_alloc(UCW.dwHostNameLength * sizeof(WCHAR));
1510 UCW.lpszHostName = hostname;
1513 if (lpUrlComponents->dwUserNameLength)
1515 UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
1516 if (lpUrlComponents->lpszUserName)
1518 username = heap_alloc(UCW.dwUserNameLength * sizeof(WCHAR));
1519 UCW.lpszUserName = username;
1522 if (lpUrlComponents->dwPasswordLength)
1524 UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
1525 if (lpUrlComponents->lpszPassword)
1527 password = heap_alloc(UCW.dwPasswordLength * sizeof(WCHAR));
1528 UCW.lpszPassword = password;
1531 if (lpUrlComponents->dwUrlPathLength)
1533 UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
1534 if (lpUrlComponents->lpszUrlPath)
1536 path = heap_alloc(UCW.dwUrlPathLength * sizeof(WCHAR));
1537 UCW.lpszUrlPath = path;
1540 if (lpUrlComponents->dwSchemeLength)
1542 UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
1543 if (lpUrlComponents->lpszScheme)
1545 scheme = heap_alloc(UCW.dwSchemeLength * sizeof(WCHAR));
1546 UCW.lpszScheme = scheme;
1549 if (lpUrlComponents->dwExtraInfoLength)
1551 UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
1552 if (lpUrlComponents->lpszExtraInfo)
1554 extra = heap_alloc(UCW.dwExtraInfoLength * sizeof(WCHAR));
1555 UCW.lpszExtraInfo = extra;
1558 if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
1560 ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1561 UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
1562 ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1563 UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
1564 ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1565 UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
1566 ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1567 UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
1568 ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1569 UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
1570 ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1571 UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
1573 lpUrlComponents->nScheme = UCW.nScheme;
1574 lpUrlComponents->nPort = UCW.nPort;
1576 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(lpszUrl),
1577 debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
1578 debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
1579 debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
1580 debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
1582 heap_free(lpwszUrl);
1583 heap_free(hostname);
1584 heap_free(username);
1585 heap_free(password);
1586 heap_free(path);
1587 heap_free(scheme);
1588 heap_free(extra);
1589 return ret;
1592 static const WCHAR url_schemes[][7] =
1594 {'f','t','p',0},
1595 {'g','o','p','h','e','r',0},
1596 {'h','t','t','p',0},
1597 {'h','t','t','p','s',0},
1598 {'f','i','l','e',0},
1599 {'n','e','w','s',0},
1600 {'m','a','i','l','t','o',0},
1601 {'r','e','s',0},
1604 /***********************************************************************
1605 * GetInternetSchemeW (internal)
1607 * Get scheme of url
1609 * RETURNS
1610 * scheme on success
1611 * INTERNET_SCHEME_UNKNOWN on failure
1614 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1616 int i;
1618 TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1620 if(lpszScheme==NULL)
1621 return INTERNET_SCHEME_UNKNOWN;
1623 for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1624 if (!strncmpiW(lpszScheme, url_schemes[i], nMaxCmp))
1625 return INTERNET_SCHEME_FIRST + i;
1627 return INTERNET_SCHEME_UNKNOWN;
1630 /***********************************************************************
1631 * SetUrlComponentValueW (Internal)
1633 * Helper function for InternetCrackUrlW
1635 * PARAMS
1636 * lppszComponent [O] Holds the returned string
1637 * dwComponentLen [I] Holds the size of lppszComponent
1638 * [O] Holds the length of the string in lppszComponent without '\0'
1639 * lpszStart [I] Holds the string to copy from
1640 * len [I] Holds the length of lpszStart without '\0'
1642 * RETURNS
1643 * TRUE on success
1644 * FALSE on failure
1647 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1649 TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1651 if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1652 return FALSE;
1654 if (*dwComponentLen != 0 || *lppszComponent == NULL)
1656 if (*lppszComponent == NULL)
1658 *lppszComponent = (LPWSTR)lpszStart;
1659 *dwComponentLen = len;
1661 else
1663 DWORD ncpylen = min((*dwComponentLen)-1, len);
1664 memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1665 (*lppszComponent)[ncpylen] = '\0';
1666 *dwComponentLen = ncpylen;
1670 return TRUE;
1673 /***********************************************************************
1674 * InternetCrackUrlW (WININET.@)
1676 * Break up URL into its components
1678 * RETURNS
1679 * TRUE on success
1680 * FALSE on failure
1682 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1683 LPURL_COMPONENTSW lpUC)
1686 * RFC 1808
1687 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1690 LPCWSTR lpszParam = NULL;
1691 BOOL found_colon = FALSE;
1692 LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1693 LPCWSTR lpszcp = NULL, lpszNetLoc;
1694 LPWSTR lpszUrl_decode = NULL;
1695 DWORD dwUrlLength = dwUrlLength_orig;
1697 TRACE("(%s %u %x %p)\n",
1698 lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
1699 dwUrlLength, dwFlags, lpUC);
1701 if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1703 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1704 return FALSE;
1706 if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1708 if (dwFlags & ICU_DECODE)
1710 WCHAR *url_tmp;
1711 DWORD len = dwUrlLength + 1;
1713 if (!(url_tmp = heap_alloc(len * sizeof(WCHAR))))
1715 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1716 return FALSE;
1718 memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
1719 url_tmp[dwUrlLength] = 0;
1720 if (!(lpszUrl_decode = heap_alloc(len * sizeof(WCHAR))))
1722 heap_free(url_tmp);
1723 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1724 return FALSE;
1726 if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
1728 dwUrlLength = len;
1729 lpszUrl = lpszUrl_decode;
1731 heap_free(url_tmp);
1733 lpszap = lpszUrl;
1735 /* Determine if the URI is absolute. */
1736 while (lpszap - lpszUrl < dwUrlLength)
1738 if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
1740 lpszap++;
1741 continue;
1743 if (*lpszap == ':')
1745 found_colon = TRUE;
1746 lpszcp = lpszap;
1748 else
1750 lpszcp = lpszUrl; /* Relative url */
1753 break;
1756 if(!found_colon){
1757 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
1758 return 0;
1761 lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1762 lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1764 /* Parse <params> */
1765 lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1766 if(!lpszParam)
1767 lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
1769 SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1770 lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1773 /* Get scheme first. */
1774 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1775 SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1776 lpszUrl, lpszcp - lpszUrl);
1778 /* Eat ':' in protocol. */
1779 lpszcp++;
1781 /* double slash indicates the net_loc portion is present */
1782 if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1784 lpszcp += 2;
1786 lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1787 if (lpszParam)
1789 if (lpszNetLoc)
1790 lpszNetLoc = min(lpszNetLoc, lpszParam);
1791 else
1792 lpszNetLoc = lpszParam;
1794 else if (!lpszNetLoc)
1795 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1797 /* Parse net-loc */
1798 if (lpszNetLoc)
1800 LPCWSTR lpszHost;
1801 LPCWSTR lpszPort;
1803 /* [<user>[<:password>]@]<host>[:<port>] */
1804 /* First find the user and password if they exist */
1806 lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1807 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1809 /* username and password not specified. */
1810 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1811 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1813 else /* Parse out username and password */
1815 LPCWSTR lpszUser = lpszcp;
1816 LPCWSTR lpszPasswd = lpszHost;
1818 while (lpszcp < lpszHost)
1820 if (*lpszcp == ':')
1821 lpszPasswd = lpszcp;
1823 lpszcp++;
1826 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1827 lpszUser, lpszPasswd - lpszUser);
1829 if (lpszPasswd != lpszHost)
1830 lpszPasswd++;
1831 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1832 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1833 lpszHost - lpszPasswd);
1835 lpszcp++; /* Advance to beginning of host */
1838 /* Parse <host><:port> */
1840 lpszHost = lpszcp;
1841 lpszPort = lpszNetLoc;
1843 /* special case for res:// URLs: there is no port here, so the host is the
1844 entire string up to the first '/' */
1845 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1847 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1848 lpszHost, lpszPort - lpszHost);
1849 lpszcp=lpszNetLoc;
1851 else
1853 while (lpszcp < lpszNetLoc)
1855 if (*lpszcp == ':')
1856 lpszPort = lpszcp;
1858 lpszcp++;
1861 /* If the scheme is "file" and the host is just one letter, it's not a host */
1862 if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
1864 lpszcp=lpszHost;
1865 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1866 NULL, 0);
1868 else
1870 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1871 lpszHost, lpszPort - lpszHost);
1872 if (lpszPort != lpszNetLoc)
1873 lpUC->nPort = atoiW(++lpszPort);
1874 else switch (lpUC->nScheme)
1876 case INTERNET_SCHEME_HTTP:
1877 lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1878 break;
1879 case INTERNET_SCHEME_HTTPS:
1880 lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1881 break;
1882 case INTERNET_SCHEME_FTP:
1883 lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1884 break;
1885 case INTERNET_SCHEME_GOPHER:
1886 lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1887 break;
1888 default:
1889 break;
1895 else
1897 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1898 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1899 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1902 /* Here lpszcp points to:
1904 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1905 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1907 if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
1909 DWORD len;
1911 /* Only truncate the parameter list if it's already been saved
1912 * in lpUC->lpszExtraInfo.
1914 if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1915 len = lpszParam - lpszcp;
1916 else
1918 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1919 * newlines if necessary.
1921 LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1922 if (lpsznewline != NULL)
1923 len = lpsznewline - lpszcp;
1924 else
1925 len = dwUrlLength-(lpszcp-lpszUrl);
1927 if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
1928 lpUC->nScheme == INTERNET_SCHEME_FILE)
1930 WCHAR tmppath[MAX_PATH];
1931 if (*lpszcp == '/')
1933 len = MAX_PATH;
1934 PathCreateFromUrlW(lpszUrl_orig, tmppath, &len, 0);
1936 else
1938 WCHAR *iter;
1939 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
1940 tmppath[len] = '\0';
1942 iter = tmppath;
1943 while (*iter) {
1944 if (*iter == '/')
1945 *iter = '\\';
1946 ++iter;
1949 /* if ends in \. or \.. append a backslash */
1950 if (tmppath[len - 1] == '.' &&
1951 (tmppath[len - 2] == '\\' ||
1952 (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
1954 if (len < MAX_PATH - 1)
1956 tmppath[len] = '\\';
1957 tmppath[len+1] = '\0';
1958 ++len;
1961 SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1962 tmppath, len);
1964 else
1965 SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1966 lpszcp, len);
1968 else
1970 if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
1971 lpUC->lpszUrlPath[0] = 0;
1972 lpUC->dwUrlPathLength = 0;
1975 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1976 debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1977 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1978 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1979 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1981 heap_free( lpszUrl_decode );
1982 return TRUE;
1985 /***********************************************************************
1986 * InternetAttemptConnect (WININET.@)
1988 * Attempt to make a connection to the internet
1990 * RETURNS
1991 * ERROR_SUCCESS on success
1992 * Error value on failure
1995 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1997 FIXME("Stub\n");
1998 return ERROR_SUCCESS;
2002 /***********************************************************************
2003 * convert_url_canonicalization_flags
2005 * Helper for InternetCanonicalizeUrl
2007 * PARAMS
2008 * dwFlags [I] Flags suitable for InternetCanonicalizeUrl
2010 * RETURNS
2011 * Flags suitable for UrlCanonicalize
2013 static DWORD convert_url_canonicalization_flags(DWORD dwFlags)
2015 DWORD dwUrlFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
2017 if (dwFlags & ICU_BROWSER_MODE) dwUrlFlags |= URL_BROWSER_MODE;
2018 if (dwFlags & ICU_DECODE) dwUrlFlags |= URL_UNESCAPE;
2019 if (dwFlags & ICU_ENCODE_PERCENT) dwUrlFlags |= URL_ESCAPE_PERCENT;
2020 if (dwFlags & ICU_ENCODE_SPACES_ONLY) dwUrlFlags |= URL_ESCAPE_SPACES_ONLY;
2021 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2022 if (dwFlags & ICU_NO_ENCODE) dwUrlFlags ^= URL_ESCAPE_UNSAFE;
2023 if (dwFlags & ICU_NO_META) dwUrlFlags |= URL_NO_META;
2025 return dwUrlFlags;
2028 /***********************************************************************
2029 * InternetCanonicalizeUrlA (WININET.@)
2031 * Escape unsafe characters and spaces
2033 * RETURNS
2034 * TRUE on success
2035 * FALSE on failure
2038 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
2039 LPDWORD lpdwBufferLength, DWORD dwFlags)
2041 HRESULT hr;
2043 TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
2044 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2046 dwFlags = convert_url_canonicalization_flags(dwFlags);
2047 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2048 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2049 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2051 return hr == S_OK;
2054 /***********************************************************************
2055 * InternetCanonicalizeUrlW (WININET.@)
2057 * Escape unsafe characters and spaces
2059 * RETURNS
2060 * TRUE on success
2061 * FALSE on failure
2064 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
2065 LPDWORD lpdwBufferLength, DWORD dwFlags)
2067 HRESULT hr;
2069 TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
2070 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2072 dwFlags = convert_url_canonicalization_flags(dwFlags);
2073 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2074 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2075 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2077 return hr == S_OK;
2080 /* #################################################### */
2082 static INTERNET_STATUS_CALLBACK set_status_callback(
2083 object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
2085 INTERNET_STATUS_CALLBACK ret;
2087 if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
2088 else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
2090 ret = lpwh->lpfnStatusCB;
2091 lpwh->lpfnStatusCB = callback;
2093 return ret;
2096 /***********************************************************************
2097 * InternetSetStatusCallbackA (WININET.@)
2099 * Sets up a callback function which is called as progress is made
2100 * during an operation.
2102 * RETURNS
2103 * Previous callback or NULL on success
2104 * INTERNET_INVALID_STATUS_CALLBACK on failure
2107 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
2108 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2110 INTERNET_STATUS_CALLBACK retVal;
2111 object_header_t *lpwh;
2113 TRACE("%p\n", hInternet);
2115 if (!(lpwh = get_handle_object(hInternet)))
2116 return INTERNET_INVALID_STATUS_CALLBACK;
2118 retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
2120 WININET_Release( lpwh );
2121 return retVal;
2124 /***********************************************************************
2125 * InternetSetStatusCallbackW (WININET.@)
2127 * Sets up a callback function which is called as progress is made
2128 * during an operation.
2130 * RETURNS
2131 * Previous callback or NULL on success
2132 * INTERNET_INVALID_STATUS_CALLBACK on failure
2135 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2136 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2138 INTERNET_STATUS_CALLBACK retVal;
2139 object_header_t *lpwh;
2141 TRACE("%p\n", hInternet);
2143 if (!(lpwh = get_handle_object(hInternet)))
2144 return INTERNET_INVALID_STATUS_CALLBACK;
2146 retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2148 WININET_Release( lpwh );
2149 return retVal;
2152 /***********************************************************************
2153 * InternetSetFilePointer (WININET.@)
2155 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2156 PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2158 FIXME("(%p %d %p %d %lx): stub\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
2159 return FALSE;
2162 /***********************************************************************
2163 * InternetWriteFile (WININET.@)
2165 * Write data to an open internet file
2167 * RETURNS
2168 * TRUE on success
2169 * FALSE on failure
2172 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2173 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2175 object_header_t *lpwh;
2176 BOOL res;
2178 TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2180 lpwh = get_handle_object( hFile );
2181 if (!lpwh) {
2182 WARN("Invalid handle\n");
2183 SetLastError(ERROR_INVALID_HANDLE);
2184 return FALSE;
2187 if(lpwh->vtbl->WriteFile) {
2188 res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2189 }else {
2190 WARN("No Writefile method.\n");
2191 res = ERROR_INVALID_HANDLE;
2194 WININET_Release( lpwh );
2196 if(res != ERROR_SUCCESS)
2197 SetLastError(res);
2198 return res == ERROR_SUCCESS;
2202 /***********************************************************************
2203 * InternetReadFile (WININET.@)
2205 * Read data from an open internet file
2207 * RETURNS
2208 * TRUE on success
2209 * FALSE on failure
2212 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2213 DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2215 object_header_t *hdr;
2216 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2218 TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2220 hdr = get_handle_object(hFile);
2221 if (!hdr) {
2222 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2223 return FALSE;
2226 if(hdr->vtbl->ReadFile)
2227 res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2229 WININET_Release(hdr);
2231 TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2232 pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2234 if(res != ERROR_SUCCESS)
2235 SetLastError(res);
2236 return res == ERROR_SUCCESS;
2239 /***********************************************************************
2240 * InternetReadFileExA (WININET.@)
2242 * Read data from an open internet file
2244 * PARAMS
2245 * hFile [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2246 * lpBuffersOut [I/O] Buffer.
2247 * dwFlags [I] Flags. See notes.
2248 * dwContext [I] Context for callbacks.
2250 * RETURNS
2251 * TRUE on success
2252 * FALSE on failure
2254 * NOTES
2255 * The parameter dwFlags include zero or more of the following flags:
2256 *|IRF_ASYNC - Makes the call asynchronous.
2257 *|IRF_SYNC - Makes the call synchronous.
2258 *|IRF_USE_CONTEXT - Forces dwContext to be used.
2259 *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2261 * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2263 * SEE
2264 * InternetOpenUrlA(), HttpOpenRequestA()
2266 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2267 DWORD dwFlags, DWORD_PTR dwContext)
2269 object_header_t *hdr;
2270 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2272 TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2274 if (lpBuffersOut->dwStructSize != sizeof(*lpBuffersOut)) {
2275 SetLastError(ERROR_INVALID_PARAMETER);
2276 return FALSE;
2279 hdr = get_handle_object(hFile);
2280 if (!hdr) {
2281 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2282 return FALSE;
2285 if(hdr->vtbl->ReadFileEx)
2286 res = hdr->vtbl->ReadFileEx(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
2287 &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
2289 WININET_Release(hdr);
2291 TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2292 res, lpBuffersOut->dwBufferLength);
2294 if(res != ERROR_SUCCESS)
2295 SetLastError(res);
2296 return res == ERROR_SUCCESS;
2299 /***********************************************************************
2300 * InternetReadFileExW (WININET.@)
2301 * SEE
2302 * InternetReadFileExA()
2304 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2305 DWORD dwFlags, DWORD_PTR dwContext)
2307 object_header_t *hdr;
2308 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2310 TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
2312 if (lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
2313 SetLastError(ERROR_INVALID_PARAMETER);
2314 return FALSE;
2317 hdr = get_handle_object(hFile);
2318 if (!hdr) {
2319 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2320 return FALSE;
2323 if(hdr->vtbl->ReadFileEx)
2324 res = hdr->vtbl->ReadFileEx(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
2325 dwFlags, dwContext);
2327 WININET_Release(hdr);
2329 TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2330 res, lpBuffer->dwBufferLength);
2332 if(res != ERROR_SUCCESS)
2333 SetLastError(res);
2334 return res == ERROR_SUCCESS;
2337 static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)
2339 /* FIXME: This function currently handles more options than it should. Options requiring
2340 * proper handles should be moved to proper functions */
2341 switch(option) {
2342 case INTERNET_OPTION_HTTP_VERSION:
2343 if (*size < sizeof(HTTP_VERSION_INFO))
2344 return ERROR_INSUFFICIENT_BUFFER;
2347 * Presently hardcoded to 1.1
2349 ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2350 ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2351 *size = sizeof(HTTP_VERSION_INFO);
2353 return ERROR_SUCCESS;
2355 case INTERNET_OPTION_CONNECTED_STATE:
2356 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2358 if (*size < sizeof(ULONG))
2359 return ERROR_INSUFFICIENT_BUFFER;
2361 *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2362 *size = sizeof(ULONG);
2364 return ERROR_SUCCESS;
2366 case INTERNET_OPTION_PROXY: {
2367 appinfo_t ai;
2368 BOOL ret;
2370 TRACE("Getting global proxy info\n");
2371 memset(&ai, 0, sizeof(appinfo_t));
2372 INTERNET_ConfigureProxy(&ai);
2374 ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2375 APPINFO_Destroy(&ai.hdr);
2376 return ret;
2379 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2380 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2382 if (*size < sizeof(ULONG))
2383 return ERROR_INSUFFICIENT_BUFFER;
2385 *(ULONG*)buffer = max_conns;
2386 *size = sizeof(ULONG);
2388 return ERROR_SUCCESS;
2390 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2391 TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2393 if (*size < sizeof(ULONG))
2394 return ERROR_INSUFFICIENT_BUFFER;
2396 *(ULONG*)buffer = max_1_0_conns;
2397 *size = sizeof(ULONG);
2399 return ERROR_SUCCESS;
2401 case INTERNET_OPTION_SECURITY_FLAGS:
2402 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2403 return ERROR_SUCCESS;
2405 case INTERNET_OPTION_VERSION: {
2406 static const INTERNET_VERSION_INFO info = { 1, 2 };
2408 TRACE("INTERNET_OPTION_VERSION\n");
2410 if (*size < sizeof(INTERNET_VERSION_INFO))
2411 return ERROR_INSUFFICIENT_BUFFER;
2413 memcpy(buffer, &info, sizeof(info));
2414 *size = sizeof(info);
2416 return ERROR_SUCCESS;
2419 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2420 INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2421 INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2422 DWORD res = ERROR_SUCCESS, i;
2423 proxyinfo_t pi;
2424 LONG ret;
2426 TRACE("Getting global proxy info\n");
2427 if((ret = INTERNET_LoadProxySettings(&pi)))
2428 return ret;
2430 FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2432 if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2433 FreeProxyInfo(&pi);
2434 return ERROR_INSUFFICIENT_BUFFER;
2437 for (i = 0; i < con->dwOptionCount; i++) {
2438 INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
2439 INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2441 switch (optionW->dwOption) {
2442 case INTERNET_PER_CONN_FLAGS:
2443 if(pi.proxyEnabled)
2444 optionW->Value.dwValue = PROXY_TYPE_PROXY;
2445 else
2446 optionW->Value.dwValue = PROXY_TYPE_DIRECT;
2447 break;
2449 case INTERNET_PER_CONN_PROXY_SERVER:
2450 if (unicode)
2451 optionW->Value.pszValue = heap_strdupW(pi.proxy);
2452 else
2453 optionA->Value.pszValue = heap_strdupWtoA(pi.proxy);
2454 break;
2456 case INTERNET_PER_CONN_PROXY_BYPASS:
2457 if (unicode)
2458 optionW->Value.pszValue = heap_strdupW(pi.proxyBypass);
2459 else
2460 optionA->Value.pszValue = heap_strdupWtoA(pi.proxyBypass);
2461 break;
2463 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2464 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2465 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2466 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2467 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2468 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2469 FIXME("Unhandled dwOption %d\n", optionW->dwOption);
2470 memset(&optionW->Value, 0, sizeof(optionW->Value));
2471 break;
2473 default:
2474 FIXME("Unknown dwOption %d\n", optionW->dwOption);
2475 res = ERROR_INVALID_PARAMETER;
2476 break;
2479 FreeProxyInfo(&pi);
2481 return res;
2483 case INTERNET_OPTION_REQUEST_FLAGS:
2484 case INTERNET_OPTION_USER_AGENT:
2485 *size = 0;
2486 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2487 case INTERNET_OPTION_POLICY:
2488 return ERROR_INVALID_PARAMETER;
2489 case INTERNET_OPTION_CONNECT_TIMEOUT:
2490 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2492 if (*size < sizeof(ULONG))
2493 return ERROR_INSUFFICIENT_BUFFER;
2495 *(ULONG*)buffer = connect_timeout;
2496 *size = sizeof(ULONG);
2498 return ERROR_SUCCESS;
2501 FIXME("Stub for %d\n", option);
2502 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2505 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2507 switch(option) {
2508 case INTERNET_OPTION_CONTEXT_VALUE:
2509 if (!size)
2510 return ERROR_INVALID_PARAMETER;
2512 if (*size < sizeof(DWORD_PTR)) {
2513 *size = sizeof(DWORD_PTR);
2514 return ERROR_INSUFFICIENT_BUFFER;
2516 if (!buffer)
2517 return ERROR_INVALID_PARAMETER;
2519 *(DWORD_PTR *)buffer = hdr->dwContext;
2520 *size = sizeof(DWORD_PTR);
2521 return ERROR_SUCCESS;
2523 case INTERNET_OPTION_REQUEST_FLAGS:
2524 WARN("INTERNET_OPTION_REQUEST_FLAGS\n");
2525 *size = sizeof(DWORD);
2526 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2528 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2529 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2530 WARN("Called on global option %u\n", option);
2531 return ERROR_INTERNET_INVALID_OPERATION;
2534 /* FIXME: we shouldn't call it here */
2535 return query_global_option(option, buffer, size, unicode);
2538 /***********************************************************************
2539 * InternetQueryOptionW (WININET.@)
2541 * Queries an options on the specified handle
2543 * RETURNS
2544 * TRUE on success
2545 * FALSE on failure
2548 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2549 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2551 object_header_t *hdr;
2552 DWORD res = ERROR_INVALID_HANDLE;
2554 TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2556 if(hInternet) {
2557 hdr = get_handle_object(hInternet);
2558 if (hdr) {
2559 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2560 WININET_Release(hdr);
2562 }else {
2563 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE);
2566 if(res != ERROR_SUCCESS)
2567 SetLastError(res);
2568 return res == ERROR_SUCCESS;
2571 /***********************************************************************
2572 * InternetQueryOptionA (WININET.@)
2574 * Queries an options on the specified handle
2576 * RETURNS
2577 * TRUE on success
2578 * FALSE on failure
2581 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2582 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2584 object_header_t *hdr;
2585 DWORD res = ERROR_INVALID_HANDLE;
2587 TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2589 if(hInternet) {
2590 hdr = get_handle_object(hInternet);
2591 if (hdr) {
2592 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2593 WININET_Release(hdr);
2595 }else {
2596 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE);
2599 if(res != ERROR_SUCCESS)
2600 SetLastError(res);
2601 return res == ERROR_SUCCESS;
2604 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
2606 switch(option) {
2607 case INTERNET_OPTION_CALLBACK:
2608 WARN("Not settable option %u\n", option);
2609 return ERROR_INTERNET_OPTION_NOT_SETTABLE;
2610 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2611 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2612 WARN("Called on global option %u\n", option);
2613 return ERROR_INTERNET_INVALID_OPERATION;
2616 return ERROR_INTERNET_INVALID_OPTION;
2619 static DWORD set_global_option(DWORD option, void *buf, DWORD size)
2621 switch(option) {
2622 case INTERNET_OPTION_CALLBACK:
2623 WARN("Not global option %u\n", option);
2624 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2626 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2627 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2629 if(size != sizeof(max_conns))
2630 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2631 if(!*(ULONG*)buf)
2632 return ERROR_BAD_ARGUMENTS;
2634 max_conns = *(ULONG*)buf;
2635 return ERROR_SUCCESS;
2637 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2638 TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n");
2640 if(size != sizeof(max_1_0_conns))
2641 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2642 if(!*(ULONG*)buf)
2643 return ERROR_BAD_ARGUMENTS;
2645 max_1_0_conns = *(ULONG*)buf;
2646 return ERROR_SUCCESS;
2648 case INTERNET_OPTION_CONNECT_TIMEOUT:
2649 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2651 if(size != sizeof(connect_timeout))
2652 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2653 if(!*(ULONG*)buf)
2654 return ERROR_BAD_ARGUMENTS;
2656 connect_timeout = *(ULONG*)buf;
2657 return ERROR_SUCCESS;
2659 case INTERNET_OPTION_SETTINGS_CHANGED:
2660 FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
2661 collect_connections(COLLECT_CONNECTIONS);
2662 return ERROR_SUCCESS;
2665 return ERROR_INTERNET_INVALID_OPTION;
2668 /***********************************************************************
2669 * InternetSetOptionW (WININET.@)
2671 * Sets an options on the specified handle
2673 * RETURNS
2674 * TRUE on success
2675 * FALSE on failure
2678 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2679 LPVOID lpBuffer, DWORD dwBufferLength)
2681 object_header_t *lpwhh;
2682 BOOL ret = TRUE;
2683 DWORD res;
2685 TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2687 lpwhh = (object_header_t*) get_handle_object( hInternet );
2688 if(lpwhh)
2689 res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2690 else
2691 res = set_global_option(dwOption, lpBuffer, dwBufferLength);
2693 if(res != ERROR_INTERNET_INVALID_OPTION) {
2694 if(lpwhh)
2695 WININET_Release(lpwhh);
2697 if(res != ERROR_SUCCESS)
2698 SetLastError(res);
2700 return res == ERROR_SUCCESS;
2703 switch (dwOption)
2705 case INTERNET_OPTION_HTTP_VERSION:
2707 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2708 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2710 break;
2711 case INTERNET_OPTION_ERROR_MASK:
2713 if(!lpwhh) {
2714 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2715 return FALSE;
2716 } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
2717 INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
2718 INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
2719 SetLastError(ERROR_INVALID_PARAMETER);
2720 ret = FALSE;
2721 } else if(dwBufferLength != sizeof(ULONG)) {
2722 SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
2723 ret = FALSE;
2724 } else
2725 TRACE("INTERNET_OPTION_ERROR_MASK: %x\n", *(ULONG*)lpBuffer);
2726 lpwhh->ErrorMask = *(ULONG*)lpBuffer;
2728 break;
2729 case INTERNET_OPTION_PROXY:
2731 INTERNET_PROXY_INFOW *info = lpBuffer;
2733 if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW))
2735 SetLastError(ERROR_INVALID_PARAMETER);
2736 return FALSE;
2738 if (!hInternet)
2740 EnterCriticalSection( &WININET_cs );
2741 free_global_proxy();
2742 global_proxy = heap_alloc( sizeof(proxyinfo_t) );
2743 if (global_proxy)
2745 if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
2747 global_proxy->proxyEnabled = 1;
2748 global_proxy->proxy = heap_strdupW( info->lpszProxy );
2749 global_proxy->proxyBypass = heap_strdupW( info->lpszProxyBypass );
2751 else
2753 global_proxy->proxyEnabled = 0;
2754 global_proxy->proxy = global_proxy->proxyBypass = NULL;
2757 LeaveCriticalSection( &WININET_cs );
2759 else
2761 /* In general, each type of object should handle
2762 * INTERNET_OPTION_PROXY directly. This FIXME ensures it doesn't
2763 * get silently dropped.
2765 FIXME("INTERNET_OPTION_PROXY unimplemented\n");
2766 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2767 ret = FALSE;
2769 break;
2771 case INTERNET_OPTION_CODEPAGE:
2773 ULONG codepage = *(ULONG *)lpBuffer;
2774 FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2776 break;
2777 case INTERNET_OPTION_REQUEST_PRIORITY:
2779 ULONG priority = *(ULONG *)lpBuffer;
2780 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2782 break;
2783 case INTERNET_OPTION_CONNECT_TIMEOUT:
2785 ULONG connecttimeout = *(ULONG *)lpBuffer;
2786 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2788 break;
2789 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2791 ULONG receivetimeout = *(ULONG *)lpBuffer;
2792 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2794 break;
2795 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2796 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2797 break;
2798 case INTERNET_OPTION_END_BROWSER_SESSION:
2799 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2800 break;
2801 case INTERNET_OPTION_CONNECTED_STATE:
2802 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2803 break;
2804 case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2805 TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2806 break;
2807 case INTERNET_OPTION_SEND_TIMEOUT:
2808 case INTERNET_OPTION_RECEIVE_TIMEOUT:
2809 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
2811 ULONG timeout = *(ULONG *)lpBuffer;
2812 FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %d\n", timeout);
2813 break;
2815 case INTERNET_OPTION_CONNECT_RETRIES:
2817 ULONG retries = *(ULONG *)lpBuffer;
2818 FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2819 break;
2821 case INTERNET_OPTION_CONTEXT_VALUE:
2823 if (!lpwhh)
2825 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2826 return FALSE;
2828 if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
2830 SetLastError(ERROR_INVALID_PARAMETER);
2831 ret = FALSE;
2833 else
2834 lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
2835 break;
2837 case INTERNET_OPTION_SECURITY_FLAGS:
2838 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2839 break;
2840 case INTERNET_OPTION_DISABLE_AUTODIAL:
2841 FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2842 break;
2843 case INTERNET_OPTION_HTTP_DECODING:
2844 FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
2845 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2846 ret = FALSE;
2847 break;
2848 case INTERNET_OPTION_COOKIES_3RD_PARTY:
2849 FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2850 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2851 ret = FALSE;
2852 break;
2853 case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2854 FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2855 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2856 ret = FALSE;
2857 break;
2858 case INTERNET_OPTION_CODEPAGE_PATH:
2859 FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2860 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2861 ret = FALSE;
2862 break;
2863 case INTERNET_OPTION_CODEPAGE_EXTRA:
2864 FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2865 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2866 ret = FALSE;
2867 break;
2868 case INTERNET_OPTION_IDN:
2869 FIXME("INTERNET_OPTION_IDN; STUB\n");
2870 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2871 ret = FALSE;
2872 break;
2873 case INTERNET_OPTION_POLICY:
2874 SetLastError(ERROR_INVALID_PARAMETER);
2875 ret = FALSE;
2876 break;
2877 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2878 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2879 LONG res;
2880 unsigned int i;
2881 proxyinfo_t pi;
2883 INTERNET_LoadProxySettings(&pi);
2885 for (i = 0; i < con->dwOptionCount; i++) {
2886 INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2888 switch (option->dwOption) {
2889 case INTERNET_PER_CONN_PROXY_SERVER:
2890 heap_free(pi.proxy);
2891 pi.proxy = heap_strdupW(option->Value.pszValue);
2892 break;
2894 case INTERNET_PER_CONN_FLAGS:
2895 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2896 pi.proxyEnabled = 1;
2897 else
2899 if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2900 FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2901 pi.proxyEnabled = 0;
2903 break;
2905 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2906 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2907 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2908 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2909 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2910 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2911 case INTERNET_PER_CONN_PROXY_BYPASS:
2912 FIXME("Unhandled dwOption %d\n", option->dwOption);
2913 break;
2915 default:
2916 FIXME("Unknown dwOption %d\n", option->dwOption);
2917 SetLastError(ERROR_INVALID_PARAMETER);
2918 break;
2922 if ((res = INTERNET_SaveProxySettings(&pi)))
2923 SetLastError(res);
2925 FreeProxyInfo(&pi);
2927 ret = (res == ERROR_SUCCESS);
2928 break;
2930 default:
2931 FIXME("Option %d STUB\n",dwOption);
2932 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2933 ret = FALSE;
2934 break;
2937 if(lpwhh)
2938 WININET_Release( lpwhh );
2940 return ret;
2944 /***********************************************************************
2945 * InternetSetOptionA (WININET.@)
2947 * Sets an options on the specified handle.
2949 * RETURNS
2950 * TRUE on success
2951 * FALSE on failure
2954 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2955 LPVOID lpBuffer, DWORD dwBufferLength)
2957 LPVOID wbuffer;
2958 DWORD wlen;
2959 BOOL r;
2961 switch( dwOption )
2963 case INTERNET_OPTION_PROXY:
2965 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2966 LPINTERNET_PROXY_INFOW piw;
2967 DWORD proxlen, prbylen;
2968 LPWSTR prox, prby;
2970 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2971 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2972 wlen = sizeof(*piw) + proxlen + prbylen;
2973 wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
2974 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2975 piw->dwAccessType = pi->dwAccessType;
2976 prox = (LPWSTR) &piw[1];
2977 prby = &prox[proxlen+1];
2978 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2979 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2980 piw->lpszProxy = prox;
2981 piw->lpszProxyBypass = prby;
2983 break;
2984 case INTERNET_OPTION_USER_AGENT:
2985 case INTERNET_OPTION_USERNAME:
2986 case INTERNET_OPTION_PASSWORD:
2987 case INTERNET_OPTION_PROXY_USERNAME:
2988 case INTERNET_OPTION_PROXY_PASSWORD:
2989 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
2990 if (!(wbuffer = heap_alloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
2991 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
2992 break;
2993 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2994 unsigned int i;
2995 INTERNET_PER_CONN_OPTION_LISTW *listW;
2996 INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
2997 wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2998 wbuffer = heap_alloc(wlen);
2999 listW = wbuffer;
3001 listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3002 if (listA->pszConnection)
3004 wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
3005 listW->pszConnection = heap_alloc(wlen*sizeof(WCHAR));
3006 MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
3008 else
3009 listW->pszConnection = NULL;
3010 listW->dwOptionCount = listA->dwOptionCount;
3011 listW->dwOptionError = listA->dwOptionError;
3012 listW->pOptions = heap_alloc(sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount);
3014 for (i = 0; i < listA->dwOptionCount; ++i) {
3015 INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
3016 INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
3018 optW->dwOption = optA->dwOption;
3020 switch (optA->dwOption) {
3021 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3022 case INTERNET_PER_CONN_PROXY_BYPASS:
3023 case INTERNET_PER_CONN_PROXY_SERVER:
3024 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3025 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3026 if (optA->Value.pszValue)
3028 wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
3029 optW->Value.pszValue = heap_alloc(wlen*sizeof(WCHAR));
3030 MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
3032 else
3033 optW->Value.pszValue = NULL;
3034 break;
3035 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3036 case INTERNET_PER_CONN_FLAGS:
3037 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3038 optW->Value.dwValue = optA->Value.dwValue;
3039 break;
3040 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3041 optW->Value.ftValue = optA->Value.ftValue;
3042 break;
3043 default:
3044 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
3045 optW->Value.dwValue = optA->Value.dwValue;
3046 break;
3050 break;
3051 default:
3052 wbuffer = lpBuffer;
3053 wlen = dwBufferLength;
3056 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
3058 if( lpBuffer != wbuffer )
3060 if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
3062 INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
3063 unsigned int i;
3064 for (i = 0; i < list->dwOptionCount; ++i) {
3065 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
3066 switch (opt->dwOption) {
3067 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3068 case INTERNET_PER_CONN_PROXY_BYPASS:
3069 case INTERNET_PER_CONN_PROXY_SERVER:
3070 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3071 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3072 heap_free( opt->Value.pszValue );
3073 break;
3074 default:
3075 break;
3078 heap_free( list->pOptions );
3080 heap_free( wbuffer );
3083 return r;
3087 /***********************************************************************
3088 * InternetSetOptionExA (WININET.@)
3090 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
3091 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3093 FIXME("Flags %08x ignored\n", dwFlags);
3094 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
3097 /***********************************************************************
3098 * InternetSetOptionExW (WININET.@)
3100 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
3101 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3103 FIXME("Flags %08x ignored\n", dwFlags);
3104 if( dwFlags & ~ISO_VALID_FLAGS )
3106 SetLastError( ERROR_INVALID_PARAMETER );
3107 return FALSE;
3109 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
3112 static const WCHAR WININET_wkday[7][4] =
3113 { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
3114 { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
3115 static const WCHAR WININET_month[12][4] =
3116 { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
3117 { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
3118 { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
3120 /***********************************************************************
3121 * InternetTimeFromSystemTimeA (WININET.@)
3123 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
3125 BOOL ret;
3126 WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
3128 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3130 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3132 SetLastError(ERROR_INVALID_PARAMETER);
3133 return FALSE;
3136 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3138 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3139 return FALSE;
3142 ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
3143 if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
3145 return ret;
3148 /***********************************************************************
3149 * InternetTimeFromSystemTimeW (WININET.@)
3151 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
3153 static const WCHAR date[] =
3154 { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
3155 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
3157 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3159 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3161 SetLastError(ERROR_INVALID_PARAMETER);
3162 return FALSE;
3165 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3167 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3168 return FALSE;
3171 sprintfW( string, date,
3172 WININET_wkday[time->wDayOfWeek],
3173 time->wDay,
3174 WININET_month[time->wMonth - 1],
3175 time->wYear,
3176 time->wHour,
3177 time->wMinute,
3178 time->wSecond );
3180 return TRUE;
3183 /***********************************************************************
3184 * InternetTimeToSystemTimeA (WININET.@)
3186 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
3188 BOOL ret = FALSE;
3189 WCHAR *stringW;
3191 TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
3193 stringW = heap_strdupAtoW(string);
3194 if (stringW)
3196 ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3197 heap_free( stringW );
3199 return ret;
3202 /***********************************************************************
3203 * InternetTimeToSystemTimeW (WININET.@)
3205 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3207 unsigned int i;
3208 const WCHAR *s = string;
3209 WCHAR *end;
3211 TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
3213 if (!string || !time) return FALSE;
3215 /* Windows does this too */
3216 GetSystemTime( time );
3218 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3219 * a SYSTEMTIME structure.
3222 while (*s && !isalphaW( *s )) s++;
3223 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3224 time->wDayOfWeek = 7;
3226 for (i = 0; i < 7; i++)
3228 if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
3229 toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
3230 toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
3232 time->wDayOfWeek = i;
3233 break;
3237 if (time->wDayOfWeek > 6) return TRUE;
3238 while (*s && !isdigitW( *s )) s++;
3239 time->wDay = strtolW( s, &end, 10 );
3240 s = end;
3242 while (*s && !isalphaW( *s )) s++;
3243 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3244 time->wMonth = 0;
3246 for (i = 0; i < 12; i++)
3248 if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
3249 toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
3250 toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
3252 time->wMonth = i + 1;
3253 break;
3256 if (time->wMonth == 0) return TRUE;
3258 while (*s && !isdigitW( *s )) s++;
3259 if (*s == '\0') return TRUE;
3260 time->wYear = strtolW( s, &end, 10 );
3261 s = end;
3263 while (*s && !isdigitW( *s )) s++;
3264 if (*s == '\0') return TRUE;
3265 time->wHour = strtolW( s, &end, 10 );
3266 s = end;
3268 while (*s && !isdigitW( *s )) s++;
3269 if (*s == '\0') return TRUE;
3270 time->wMinute = strtolW( s, &end, 10 );
3271 s = end;
3273 while (*s && !isdigitW( *s )) s++;
3274 if (*s == '\0') return TRUE;
3275 time->wSecond = strtolW( s, &end, 10 );
3276 s = end;
3278 time->wMilliseconds = 0;
3279 return TRUE;
3282 /***********************************************************************
3283 * InternetCheckConnectionW (WININET.@)
3285 * Pings a requested host to check internet connection
3287 * RETURNS
3288 * TRUE on success and FALSE on failure. If a failure then
3289 * ERROR_NOT_CONNECTED is placed into GetLastError
3292 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3295 * this is a kludge which runs the resident ping program and reads the output.
3297 * Anyone have a better idea?
3300 BOOL rc = FALSE;
3301 static const CHAR ping[] = "ping -c 1 ";
3302 static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3303 CHAR *command = NULL;
3304 WCHAR hostW[INTERNET_MAX_HOST_NAME_LENGTH];
3305 DWORD len;
3306 INTERNET_PORT port;
3307 int status = -1;
3309 FIXME("\n");
3312 * Crack or set the Address
3314 if (lpszUrl == NULL)
3317 * According to the doc we are supposed to use the ip for the next
3318 * server in the WnInet internal server database. I have
3319 * no idea what that is or how to get it.
3321 * So someone needs to implement this.
3323 FIXME("Unimplemented with URL of NULL\n");
3324 return TRUE;
3326 else
3328 URL_COMPONENTSW components;
3330 ZeroMemory(&components,sizeof(URL_COMPONENTSW));
3331 components.lpszHostName = (LPWSTR)hostW;
3332 components.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
3334 if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3335 goto End;
3337 TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
3338 port = components.nPort;
3339 TRACE("port: %d\n", port);
3342 if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3344 struct sockaddr_storage saddr;
3345 socklen_t sa_len = sizeof(saddr);
3346 int fd;
3348 if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
3349 goto End;
3350 fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3351 if (fd != -1)
3353 if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3354 rc = TRUE;
3355 close(fd);
3358 else
3361 * Build our ping command
3363 len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
3364 command = heap_alloc(strlen(ping)+len+strlen(redirect));
3365 strcpy(command,ping);
3366 WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
3367 strcat(command,redirect);
3369 TRACE("Ping command is : %s\n",command);
3371 status = system(command);
3373 TRACE("Ping returned a code of %i\n",status);
3375 /* Ping return code of 0 indicates success */
3376 if (status == 0)
3377 rc = TRUE;
3380 End:
3381 heap_free( command );
3382 if (rc == FALSE)
3383 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3385 return rc;
3389 /***********************************************************************
3390 * InternetCheckConnectionA (WININET.@)
3392 * Pings a requested host to check internet connection
3394 * RETURNS
3395 * TRUE on success and FALSE on failure. If a failure then
3396 * ERROR_NOT_CONNECTED is placed into GetLastError
3399 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3401 WCHAR *url = NULL;
3402 BOOL rc;
3404 if(lpszUrl) {
3405 url = heap_strdupAtoW(lpszUrl);
3406 if(!url)
3407 return FALSE;
3410 rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3412 heap_free(url);
3413 return rc;
3417 /**********************************************************
3418 * INTERNET_InternetOpenUrlW (internal)
3420 * Opens an URL
3422 * RETURNS
3423 * handle of connection or NULL on failure
3425 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3426 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3428 URL_COMPONENTSW urlComponents;
3429 WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH];
3430 WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH];
3431 WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH];
3432 WCHAR password[INTERNET_MAX_PASSWORD_LENGTH];
3433 WCHAR path[INTERNET_MAX_PATH_LENGTH];
3434 WCHAR extra[1024];
3435 HINTERNET client = NULL, client1 = NULL;
3436 DWORD res;
3438 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3439 dwHeadersLength, dwFlags, dwContext);
3441 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3442 urlComponents.lpszScheme = protocol;
3443 urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
3444 urlComponents.lpszHostName = hostName;
3445 urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
3446 urlComponents.lpszUserName = userName;
3447 urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
3448 urlComponents.lpszPassword = password;
3449 urlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
3450 urlComponents.lpszUrlPath = path;
3451 urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
3452 urlComponents.lpszExtraInfo = extra;
3453 urlComponents.dwExtraInfoLength = 1024;
3454 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3455 return NULL;
3456 switch(urlComponents.nScheme) {
3457 case INTERNET_SCHEME_FTP:
3458 if(urlComponents.nPort == 0)
3459 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
3460 client = FTP_Connect(hIC, hostName, urlComponents.nPort,
3461 userName, password, dwFlags, dwContext, INET_OPENURL);
3462 if(client == NULL)
3463 break;
3464 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3465 if(client1 == NULL) {
3466 InternetCloseHandle(client);
3467 break;
3469 break;
3471 case INTERNET_SCHEME_HTTP:
3472 case INTERNET_SCHEME_HTTPS: {
3473 static const WCHAR szStars[] = { '*','/','*', 0 };
3474 LPCWSTR accept[2] = { szStars, NULL };
3475 if(urlComponents.nPort == 0) {
3476 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
3477 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3478 else
3479 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3481 if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3483 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3484 res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
3485 userName, password, dwFlags, dwContext, INET_OPENURL, &client);
3486 if(res != ERROR_SUCCESS) {
3487 INTERNET_SetLastError(res);
3488 break;
3491 if (urlComponents.dwExtraInfoLength) {
3492 WCHAR *path_extra;
3493 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
3495 if (!(path_extra = heap_alloc(len * sizeof(WCHAR))))
3497 InternetCloseHandle(client);
3498 break;
3500 strcpyW(path_extra, urlComponents.lpszUrlPath);
3501 strcatW(path_extra, urlComponents.lpszExtraInfo);
3502 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
3503 heap_free(path_extra);
3505 else
3506 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3508 if(client1 == NULL) {
3509 InternetCloseHandle(client);
3510 break;
3512 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3513 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3514 GetLastError() != ERROR_IO_PENDING) {
3515 InternetCloseHandle(client1);
3516 client1 = NULL;
3517 break;
3520 case INTERNET_SCHEME_GOPHER:
3521 /* gopher doesn't seem to be implemented in wine, but it's supposed
3522 * to be supported by InternetOpenUrlA. */
3523 default:
3524 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3525 break;
3528 TRACE(" %p <--\n", client1);
3530 return client1;
3533 /**********************************************************
3534 * InternetOpenUrlW (WININET.@)
3536 * Opens an URL
3538 * RETURNS
3539 * handle of connection or NULL on failure
3541 typedef struct {
3542 task_header_t hdr;
3543 WCHAR *url;
3544 WCHAR *headers;
3545 DWORD headers_len;
3546 DWORD flags;
3547 DWORD_PTR context;
3548 } open_url_task_t;
3550 static void AsyncInternetOpenUrlProc(task_header_t *hdr)
3552 open_url_task_t *task = (open_url_task_t*)hdr;
3554 TRACE("%p\n", task->hdr.hdr);
3556 INTERNET_InternetOpenUrlW((appinfo_t*)task->hdr.hdr, task->url, task->headers,
3557 task->headers_len, task->flags, task->context);
3558 heap_free(task->url);
3559 heap_free(task->headers);
3562 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3563 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3565 HINTERNET ret = NULL;
3566 appinfo_t *hIC = NULL;
3568 if (TRACE_ON(wininet)) {
3569 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3570 dwHeadersLength, dwFlags, dwContext);
3571 TRACE(" flags :");
3572 dump_INTERNET_FLAGS(dwFlags);
3575 if (!lpszUrl)
3577 SetLastError(ERROR_INVALID_PARAMETER);
3578 goto lend;
3581 hIC = (appinfo_t*)get_handle_object( hInternet );
3582 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
3583 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3584 goto lend;
3587 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3588 open_url_task_t *task;
3590 task = alloc_async_task(&hIC->hdr, AsyncInternetOpenUrlProc, sizeof(*task));
3591 task->url = heap_strdupW(lpszUrl);
3592 task->headers = heap_strdupW(lpszHeaders);
3593 task->headers_len = dwHeadersLength;
3594 task->flags = dwFlags;
3595 task->context = dwContext;
3597 INTERNET_AsyncCall(&task->hdr);
3598 SetLastError(ERROR_IO_PENDING);
3599 } else {
3600 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3603 lend:
3604 if( hIC )
3605 WININET_Release( &hIC->hdr );
3606 TRACE(" %p <--\n", ret);
3608 return ret;
3611 /**********************************************************
3612 * InternetOpenUrlA (WININET.@)
3614 * Opens an URL
3616 * RETURNS
3617 * handle of connection or NULL on failure
3619 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3620 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3622 HINTERNET rc = NULL;
3623 DWORD lenHeaders = 0;
3624 LPWSTR szUrl = NULL;
3625 LPWSTR szHeaders = NULL;
3627 TRACE("\n");
3629 if(lpszUrl) {
3630 szUrl = heap_strdupAtoW(lpszUrl);
3631 if(!szUrl)
3632 return NULL;
3635 if(lpszHeaders) {
3636 lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3637 szHeaders = heap_alloc(lenHeaders*sizeof(WCHAR));
3638 if(!szHeaders) {
3639 heap_free(szUrl);
3640 return NULL;
3642 MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3645 rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3646 lenHeaders, dwFlags, dwContext);
3648 heap_free(szUrl);
3649 heap_free(szHeaders);
3650 return rc;
3654 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3656 LPWITHREADERROR lpwite = heap_alloc(sizeof(*lpwite));
3658 if (lpwite)
3660 lpwite->dwError = 0;
3661 lpwite->response[0] = '\0';
3664 if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3666 heap_free(lpwite);
3667 return NULL;
3669 return lpwite;
3673 /***********************************************************************
3674 * INTERNET_SetLastError (internal)
3676 * Set last thread specific error
3678 * RETURNS
3681 void INTERNET_SetLastError(DWORD dwError)
3683 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3685 if (!lpwite)
3686 lpwite = INTERNET_AllocThreadError();
3688 SetLastError(dwError);
3689 if(lpwite)
3690 lpwite->dwError = dwError;
3694 /***********************************************************************
3695 * INTERNET_GetLastError (internal)
3697 * Get last thread specific error
3699 * RETURNS
3702 DWORD INTERNET_GetLastError(void)
3704 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3705 if (!lpwite) return 0;
3706 /* TlsGetValue clears last error, so set it again here */
3707 SetLastError(lpwite->dwError);
3708 return lpwite->dwError;
3712 /***********************************************************************
3713 * INTERNET_WorkerThreadFunc (internal)
3715 * Worker thread execution function
3717 * RETURNS
3720 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3722 task_header_t *task = lpvParam;
3724 TRACE("\n");
3726 task->proc(task);
3727 WININET_Release(task->hdr);
3728 heap_free(task);
3730 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3732 heap_free(TlsGetValue(g_dwTlsErrIndex));
3733 TlsSetValue(g_dwTlsErrIndex, NULL);
3735 return TRUE;
3738 void *alloc_async_task(object_header_t *hdr, async_task_proc_t proc, size_t size)
3740 task_header_t *task;
3742 task = heap_alloc(size);
3743 if(!task)
3744 return NULL;
3746 task->hdr = WININET_AddRef(hdr);
3747 task->proc = proc;
3748 return task;
3751 /***********************************************************************
3752 * INTERNET_AsyncCall (internal)
3754 * Retrieves work request from queue
3756 * RETURNS
3759 DWORD INTERNET_AsyncCall(task_header_t *task)
3761 BOOL bSuccess;
3763 TRACE("\n");
3765 bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, task, WT_EXECUTELONGFUNCTION);
3766 if (!bSuccess)
3768 heap_free(task);
3769 return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3771 return ERROR_SUCCESS;
3775 /***********************************************************************
3776 * INTERNET_GetResponseBuffer (internal)
3778 * RETURNS
3781 LPSTR INTERNET_GetResponseBuffer(void)
3783 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3784 if (!lpwite)
3785 lpwite = INTERNET_AllocThreadError();
3786 TRACE("\n");
3787 return lpwite->response;
3790 /***********************************************************************
3791 * INTERNET_GetNextLine (internal)
3793 * Parse next line in directory string listing
3795 * RETURNS
3796 * Pointer to beginning of next line
3797 * NULL on failure
3801 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3803 struct pollfd pfd;
3804 BOOL bSuccess = FALSE;
3805 INT nRecv = 0;
3806 LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3808 TRACE("\n");
3810 pfd.fd = nSocket;
3811 pfd.events = POLLIN;
3813 while (nRecv < MAX_REPLY_LEN)
3815 if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
3817 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3819 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3820 goto lend;
3823 if (lpszBuffer[nRecv] == '\n')
3825 bSuccess = TRUE;
3826 break;
3828 if (lpszBuffer[nRecv] != '\r')
3829 nRecv++;
3831 else
3833 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3834 goto lend;
3838 lend:
3839 if (bSuccess)
3841 lpszBuffer[nRecv] = '\0';
3842 *dwLen = nRecv - 1;
3843 TRACE(":%d %s\n", nRecv, lpszBuffer);
3844 return lpszBuffer;
3846 else
3848 return NULL;
3852 /**********************************************************
3853 * InternetQueryDataAvailable (WININET.@)
3855 * Determines how much data is available to be read.
3857 * RETURNS
3858 * TRUE on success, FALSE if an error occurred. If
3859 * INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3860 * no data is presently available, FALSE is returned with
3861 * the last error ERROR_IO_PENDING; a callback with status
3862 * INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3863 * data is available.
3865 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3866 LPDWORD lpdwNumberOfBytesAvailable,
3867 DWORD dwFlags, DWORD_PTR dwContext)
3869 object_header_t *hdr;
3870 DWORD res;
3872 TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3874 hdr = get_handle_object( hFile );
3875 if (!hdr) {
3876 SetLastError(ERROR_INVALID_HANDLE);
3877 return FALSE;
3880 if(hdr->vtbl->QueryDataAvailable) {
3881 res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3882 }else {
3883 WARN("wrong handle\n");
3884 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3887 WININET_Release(hdr);
3889 if(res != ERROR_SUCCESS)
3890 SetLastError(res);
3891 return res == ERROR_SUCCESS;
3895 /***********************************************************************
3896 * InternetLockRequestFile (WININET.@)
3898 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3899 *lphLockReqHandle)
3901 FIXME("STUB\n");
3902 return FALSE;
3905 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3907 FIXME("STUB\n");
3908 return FALSE;
3912 /***********************************************************************
3913 * InternetAutodial (WININET.@)
3915 * On windows this function is supposed to dial the default internet
3916 * connection. We don't want to have Wine dial out to the internet so
3917 * we return TRUE by default. It might be nice to check if we are connected.
3919 * RETURNS
3920 * TRUE on success
3921 * FALSE on failure
3924 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3926 FIXME("STUB\n");
3928 /* Tell that we are connected to the internet. */
3929 return TRUE;
3932 /***********************************************************************
3933 * InternetAutodialHangup (WININET.@)
3935 * Hangs up a connection made with InternetAutodial
3937 * PARAM
3938 * dwReserved
3939 * RETURNS
3940 * TRUE on success
3941 * FALSE on failure
3944 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3946 FIXME("STUB\n");
3948 /* we didn't dial, we don't disconnect */
3949 return TRUE;
3952 /***********************************************************************
3953 * InternetCombineUrlA (WININET.@)
3955 * Combine a base URL with a relative URL
3957 * RETURNS
3958 * TRUE on success
3959 * FALSE on failure
3963 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3964 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3965 DWORD dwFlags)
3967 HRESULT hr=S_OK;
3969 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3971 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3972 dwFlags ^= ICU_NO_ENCODE;
3973 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3975 return (hr==S_OK);
3978 /***********************************************************************
3979 * InternetCombineUrlW (WININET.@)
3981 * Combine a base URL with a relative URL
3983 * RETURNS
3984 * TRUE on success
3985 * FALSE on failure
3989 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3990 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3991 DWORD dwFlags)
3993 HRESULT hr=S_OK;
3995 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3997 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3998 dwFlags ^= ICU_NO_ENCODE;
3999 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4001 return (hr==S_OK);
4004 /* max port num is 65535 => 5 digits */
4005 #define MAX_WORD_DIGITS 5
4007 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
4008 (url)->dw##component##Length : strlenW((url)->lpsz##component))
4009 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
4010 (url)->dw##component##Length : strlen((url)->lpsz##component))
4012 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
4014 if ((nScheme == INTERNET_SCHEME_HTTP) &&
4015 (nPort == INTERNET_DEFAULT_HTTP_PORT))
4016 return TRUE;
4017 if ((nScheme == INTERNET_SCHEME_HTTPS) &&
4018 (nPort == INTERNET_DEFAULT_HTTPS_PORT))
4019 return TRUE;
4020 if ((nScheme == INTERNET_SCHEME_FTP) &&
4021 (nPort == INTERNET_DEFAULT_FTP_PORT))
4022 return TRUE;
4023 if ((nScheme == INTERNET_SCHEME_GOPHER) &&
4024 (nPort == INTERNET_DEFAULT_GOPHER_PORT))
4025 return TRUE;
4027 if (nPort == INTERNET_INVALID_PORT_NUMBER)
4028 return TRUE;
4030 return FALSE;
4033 /* opaque urls do not fit into the standard url hierarchy and don't have
4034 * two following slashes */
4035 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
4037 return (nScheme != INTERNET_SCHEME_FTP) &&
4038 (nScheme != INTERNET_SCHEME_GOPHER) &&
4039 (nScheme != INTERNET_SCHEME_HTTP) &&
4040 (nScheme != INTERNET_SCHEME_HTTPS) &&
4041 (nScheme != INTERNET_SCHEME_FILE);
4044 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
4046 int index;
4047 if (scheme < INTERNET_SCHEME_FIRST)
4048 return NULL;
4049 index = scheme - INTERNET_SCHEME_FIRST;
4050 if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
4051 return NULL;
4052 return (LPCWSTR)url_schemes[index];
4055 /* we can calculate using ansi strings because we're just
4056 * calculating string length, not size
4058 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
4059 LPDWORD lpdwUrlLength)
4061 INTERNET_SCHEME nScheme;
4063 *lpdwUrlLength = 0;
4065 if (lpUrlComponents->lpszScheme)
4067 DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4068 *lpdwUrlLength += dwLen;
4069 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4071 else
4073 LPCWSTR scheme;
4075 nScheme = lpUrlComponents->nScheme;
4077 if (nScheme == INTERNET_SCHEME_DEFAULT)
4078 nScheme = INTERNET_SCHEME_HTTP;
4079 scheme = INTERNET_GetSchemeString(nScheme);
4080 *lpdwUrlLength += strlenW(scheme);
4083 (*lpdwUrlLength)++; /* ':' */
4084 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4085 *lpdwUrlLength += strlen("//");
4087 if (lpUrlComponents->lpszUserName)
4089 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4090 *lpdwUrlLength += strlen("@");
4092 else
4094 if (lpUrlComponents->lpszPassword)
4096 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4097 return FALSE;
4101 if (lpUrlComponents->lpszPassword)
4103 *lpdwUrlLength += strlen(":");
4104 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4107 if (lpUrlComponents->lpszHostName)
4109 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4111 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4113 char szPort[MAX_WORD_DIGITS+1];
4115 sprintf(szPort, "%d", lpUrlComponents->nPort);
4116 *lpdwUrlLength += strlen(szPort);
4117 *lpdwUrlLength += strlen(":");
4120 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4121 (*lpdwUrlLength)++; /* '/' */
4124 if (lpUrlComponents->lpszUrlPath)
4125 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4127 if (lpUrlComponents->lpszExtraInfo)
4128 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4130 return TRUE;
4133 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
4135 INT len;
4137 ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
4139 urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
4140 urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
4141 urlCompW->nScheme = lpUrlComponents->nScheme;
4142 urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
4143 urlCompW->nPort = lpUrlComponents->nPort;
4144 urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
4145 urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
4146 urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
4147 urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
4149 if (lpUrlComponents->lpszScheme)
4151 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
4152 urlCompW->lpszScheme = heap_alloc(len * sizeof(WCHAR));
4153 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
4154 -1, urlCompW->lpszScheme, len);
4157 if (lpUrlComponents->lpszHostName)
4159 len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
4160 urlCompW->lpszHostName = heap_alloc(len * sizeof(WCHAR));
4161 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
4162 -1, urlCompW->lpszHostName, len);
4165 if (lpUrlComponents->lpszUserName)
4167 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
4168 urlCompW->lpszUserName = heap_alloc(len * sizeof(WCHAR));
4169 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
4170 -1, urlCompW->lpszUserName, len);
4173 if (lpUrlComponents->lpszPassword)
4175 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
4176 urlCompW->lpszPassword = heap_alloc(len * sizeof(WCHAR));
4177 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
4178 -1, urlCompW->lpszPassword, len);
4181 if (lpUrlComponents->lpszUrlPath)
4183 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
4184 urlCompW->lpszUrlPath = heap_alloc(len * sizeof(WCHAR));
4185 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
4186 -1, urlCompW->lpszUrlPath, len);
4189 if (lpUrlComponents->lpszExtraInfo)
4191 len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4192 urlCompW->lpszExtraInfo = heap_alloc(len * sizeof(WCHAR));
4193 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4194 -1, urlCompW->lpszExtraInfo, len);
4198 /***********************************************************************
4199 * InternetCreateUrlA (WININET.@)
4201 * See InternetCreateUrlW.
4203 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4204 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4206 BOOL ret;
4207 LPWSTR urlW = NULL;
4208 URL_COMPONENTSW urlCompW;
4210 TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4212 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4214 SetLastError(ERROR_INVALID_PARAMETER);
4215 return FALSE;
4218 convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4220 if (lpszUrl)
4221 urlW = heap_alloc(*lpdwUrlLength * sizeof(WCHAR));
4223 ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4225 if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4226 *lpdwUrlLength /= sizeof(WCHAR);
4228 /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4229 * minus one, so add one to leave room for NULL terminator
4231 if (ret)
4232 WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4234 heap_free(urlCompW.lpszScheme);
4235 heap_free(urlCompW.lpszHostName);
4236 heap_free(urlCompW.lpszUserName);
4237 heap_free(urlCompW.lpszPassword);
4238 heap_free(urlCompW.lpszUrlPath);
4239 heap_free(urlCompW.lpszExtraInfo);
4240 heap_free(urlW);
4241 return ret;
4244 /***********************************************************************
4245 * InternetCreateUrlW (WININET.@)
4247 * Creates a URL from its component parts.
4249 * PARAMS
4250 * lpUrlComponents [I] URL Components.
4251 * dwFlags [I] Flags. See notes.
4252 * lpszUrl [I] Buffer in which to store the created URL.
4253 * lpdwUrlLength [I/O] On input, the length of the buffer pointed to by
4254 * lpszUrl in characters. On output, the number of bytes
4255 * required to store the URL including terminator.
4257 * NOTES
4259 * The dwFlags parameter can be zero or more of the following:
4260 *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4262 * RETURNS
4263 * TRUE on success
4264 * FALSE on failure
4267 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4268 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4270 DWORD dwLen;
4271 INTERNET_SCHEME nScheme;
4273 static const WCHAR slashSlashW[] = {'/','/'};
4274 static const WCHAR fmtW[] = {'%','u',0};
4276 TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4278 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4280 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4281 return FALSE;
4284 if (!calc_url_length(lpUrlComponents, &dwLen))
4285 return FALSE;
4287 if (!lpszUrl || *lpdwUrlLength < dwLen)
4289 *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4290 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4291 return FALSE;
4294 *lpdwUrlLength = dwLen;
4295 lpszUrl[0] = 0x00;
4297 dwLen = 0;
4299 if (lpUrlComponents->lpszScheme)
4301 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4302 memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4303 lpszUrl += dwLen;
4305 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4307 else
4309 LPCWSTR scheme;
4310 nScheme = lpUrlComponents->nScheme;
4312 if (nScheme == INTERNET_SCHEME_DEFAULT)
4313 nScheme = INTERNET_SCHEME_HTTP;
4315 scheme = INTERNET_GetSchemeString(nScheme);
4316 dwLen = strlenW(scheme);
4317 memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4318 lpszUrl += dwLen;
4321 /* all schemes are followed by at least a colon */
4322 *lpszUrl = ':';
4323 lpszUrl++;
4325 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4327 memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4328 lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4331 if (lpUrlComponents->lpszUserName)
4333 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4334 memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4335 lpszUrl += dwLen;
4337 if (lpUrlComponents->lpszPassword)
4339 *lpszUrl = ':';
4340 lpszUrl++;
4342 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4343 memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4344 lpszUrl += dwLen;
4347 *lpszUrl = '@';
4348 lpszUrl++;
4351 if (lpUrlComponents->lpszHostName)
4353 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4354 memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4355 lpszUrl += dwLen;
4357 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4359 WCHAR szPort[MAX_WORD_DIGITS+1];
4361 sprintfW(szPort, fmtW, lpUrlComponents->nPort);
4362 *lpszUrl = ':';
4363 lpszUrl++;
4364 dwLen = strlenW(szPort);
4365 memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
4366 lpszUrl += dwLen;
4369 /* add slash between hostname and path if necessary */
4370 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4372 *lpszUrl = '/';
4373 lpszUrl++;
4377 if (lpUrlComponents->lpszUrlPath)
4379 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4380 memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4381 lpszUrl += dwLen;
4384 if (lpUrlComponents->lpszExtraInfo)
4386 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4387 memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4388 lpszUrl += dwLen;
4391 *lpszUrl = '\0';
4393 return TRUE;
4396 /***********************************************************************
4397 * InternetConfirmZoneCrossingA (WININET.@)
4400 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4402 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4403 return ERROR_SUCCESS;
4406 /***********************************************************************
4407 * InternetConfirmZoneCrossingW (WININET.@)
4410 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4412 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4413 return ERROR_SUCCESS;
4416 static DWORD zone_preference = 3;
4418 /***********************************************************************
4419 * PrivacySetZonePreferenceW (WININET.@)
4421 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4423 FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4425 zone_preference = template;
4426 return 0;
4429 /***********************************************************************
4430 * PrivacyGetZonePreferenceW (WININET.@)
4432 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4433 LPWSTR preference, LPDWORD length )
4435 FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4437 if (template) *template = zone_preference;
4438 return 0;
4441 /***********************************************************************
4442 * InternetGetSecurityInfoByURLA (WININET.@)
4444 BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4446 WCHAR *url;
4447 BOOL res;
4449 TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags);
4451 url = heap_strdupAtoW(lpszURL);
4452 if(!url)
4453 return FALSE;
4455 res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags);
4456 heap_free(url);
4457 return res;
4460 /***********************************************************************
4461 * InternetGetSecurityInfoByURLW (WININET.@)
4463 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4465 WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH];
4466 URL_COMPONENTSW url = {sizeof(url)};
4467 server_t *server;
4468 BOOL res = FALSE;
4470 TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
4472 url.lpszHostName = hostname;
4473 url.dwHostNameLength = sizeof(hostname)/sizeof(WCHAR);
4475 res = InternetCrackUrlW(lpszURL, 0, 0, &url);
4476 if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
4477 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4478 return FALSE;
4481 server = get_server(hostname, url.nPort, TRUE, FALSE);
4482 if(!server) {
4483 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4484 return FALSE;
4487 if(server->cert_chain) {
4488 const CERT_CHAIN_CONTEXT *chain_dup;
4490 chain_dup = CertDuplicateCertificateChain(server->cert_chain);
4491 if(chain_dup) {
4492 *ppCertChain = chain_dup;
4493 *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
4494 }else {
4495 res = FALSE;
4497 }else {
4498 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4499 res = FALSE;
4502 server_release(server);
4503 return res;
4506 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4507 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4509 FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4510 lpdwConnection, dwReserved);
4511 return ERROR_SUCCESS;
4514 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4515 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4517 FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4518 lpdwConnection, dwReserved);
4519 return ERROR_SUCCESS;
4522 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4524 FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4525 return TRUE;
4528 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4530 FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4531 return TRUE;
4534 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4536 FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4537 return ERROR_SUCCESS;
4540 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4541 PBYTE pbHexHash )
4543 FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4544 debugstr_w(pwszTarget), pbHexHash);
4545 return FALSE;
4548 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4550 FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4551 return FALSE;
4554 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4556 FIXME("(%p, %08lx) stub\n", a, b);
4557 return 0;
4560 DWORD WINAPI ShowClientAuthCerts(HWND parent)
4562 FIXME("%p: stub\n", parent);
4563 return 0;