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