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