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