ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

internet.c
Go to the documentation of this file.
00001 /*
00002  * Wininet
00003  *
00004  * Copyright 1999 Corel Corporation
00005  * Copyright 2002 CodeWeavers Inc.
00006  * Copyright 2002 Jaco Greeff
00007  * Copyright 2002 TransGaming Technologies Inc.
00008  * Copyright 2004 Mike McCormack for CodeWeavers
00009  *
00010  * Ulrich Czekalla
00011  * Aric Stewart
00012  * David Hammerton
00013  *
00014  * This library is free software; you can redistribute it and/or
00015  * modify it under the terms of the GNU Lesser General Public
00016  * License as published by the Free Software Foundation; either
00017  * version 2.1 of the License, or (at your option) any later version.
00018  *
00019  * This library is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00022  * Lesser General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public
00025  * License along with this library; if not, write to the Free Software
00026  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00027  */
00028 
00029 #include "config.h"
00030 #include "wine/port.h"
00031 
00032 #define MAXHOSTNAME 100 /* from http.c */
00033 
00034 #if defined(__MINGW32__) || defined (_MSC_VER)
00035 #include <ws2tcpip.h>
00036 #endif
00037 
00038 #include <string.h>
00039 #include <stdarg.h>
00040 #include <stdio.h>
00041 #include <sys/types.h>
00042 #ifdef HAVE_SYS_SOCKET_H
00043 # include <sys/socket.h>
00044 #endif
00045 #ifdef HAVE_POLL_H
00046 #include <poll.h>
00047 #endif
00048 #ifdef HAVE_SYS_POLL_H
00049 # include <sys/poll.h>
00050 #endif
00051 #ifdef HAVE_SYS_TIME_H
00052 # include <sys/time.h>
00053 #endif
00054 #include <stdlib.h>
00055 #include <ctype.h>
00056 #ifdef HAVE_UNISTD_H
00057 # include <unistd.h>
00058 #endif
00059 #include <assert.h>
00060 
00061 #include "windef.h"
00062 #include "winbase.h"
00063 #include "winreg.h"
00064 #include "winuser.h"
00065 #include "wininet.h"
00066 #include "winineti.h"
00067 #include "winnls.h"
00068 #include "wine/debug.h"
00069 #include "winerror.h"
00070 #define NO_SHLWAPI_STREAM
00071 #include "shlwapi.h"
00072 
00073 #include "wine/exception.h"
00074 
00075 #include "internet.h"
00076 #include "resource.h"
00077 
00078 #include "wine/unicode.h"
00079 
00080 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
00081 
00082 #define RESPONSE_TIMEOUT        30
00083 
00084 typedef struct
00085 {
00086     DWORD  dwError;
00087     CHAR   response[MAX_REPLY_LEN];
00088 } WITHREADERROR, *LPWITHREADERROR;
00089 
00090 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
00091 HMODULE WININET_hModule;
00092 
00093 static CRITICAL_SECTION WININET_cs;
00094 static CRITICAL_SECTION_DEBUG WININET_cs_debug = 
00095 {
00096     0, 0, &WININET_cs,
00097     { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
00098       0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
00099 };
00100 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
00101 
00102 static object_header_t **handle_table;
00103 static UINT_PTR next_handle;
00104 static UINT_PTR handle_table_size;
00105 
00106 typedef struct
00107 {
00108     DWORD dwProxyEnabled;
00109     LPWSTR lpszProxyServer;
00110     LPWSTR lpszProxyBypass;
00111 } proxyinfo_t;
00112 
00113 static const WCHAR szInternetSettings[] =
00114     { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
00115       'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
00116       'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
00117 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
00118 static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
00119 
00120 void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
00121 {
00122     UINT_PTR handle = 0, num;
00123     object_header_t *ret;
00124     object_header_t **p;
00125     BOOL res = TRUE;
00126 
00127     ret = heap_alloc_zero(size);
00128     if(!ret)
00129         return NULL;
00130 
00131     list_init(&ret->children);
00132 
00133     EnterCriticalSection( &WININET_cs );
00134 
00135     if(!handle_table_size) {
00136         num = 16;
00137         p = heap_alloc_zero(sizeof(handle_table[0]) * num);
00138         if(p) {
00139             handle_table = p;
00140             handle_table_size = num;
00141             next_handle = 1;
00142         }else {
00143             res = FALSE;
00144         }
00145     }else if(next_handle == handle_table_size) {
00146         num = handle_table_size * 2;
00147         p = heap_realloc_zero(handle_table, sizeof(handle_table[0]) * num);
00148         if(p) {
00149             handle_table = p;
00150             handle_table_size = num;
00151         }else {
00152             res = FALSE;
00153         }
00154     }
00155 
00156     if(res) {
00157         handle = next_handle;
00158         if(handle_table[handle])
00159             ERR("handle isn't free but should be\n");
00160         handle_table[handle] = ret;
00161         ret->valid_handle = TRUE;
00162 
00163         while(handle_table[next_handle] && next_handle < handle_table_size)
00164             next_handle++;
00165     }
00166 
00167     LeaveCriticalSection( &WININET_cs );
00168 
00169     if(!res) {
00170         heap_free(ret);
00171         return NULL;
00172     }
00173 
00174     ret->vtbl = vtbl;
00175     ret->refs = 1;
00176     ret->hInternet = (HINTERNET)handle;
00177 
00178     if(parent) {
00179         ret->lpfnStatusCB = parent->lpfnStatusCB;
00180         ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
00181     }
00182 
00183     return ret;
00184 }
00185 
00186 object_header_t *WININET_AddRef( object_header_t *info )
00187 {
00188     ULONG refs = InterlockedIncrement(&info->refs);
00189     TRACE("%p -> refcount = %d\n", info, refs );
00190     return info;
00191 }
00192 
00193 object_header_t *get_handle_object( HINTERNET hinternet )
00194 {
00195     object_header_t *info = NULL;
00196     UINT_PTR handle = (UINT_PTR) hinternet;
00197 
00198     EnterCriticalSection( &WININET_cs );
00199 
00200     if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
00201         info = WININET_AddRef(handle_table[handle]);
00202 
00203     LeaveCriticalSection( &WININET_cs );
00204 
00205     TRACE("handle %ld -> %p\n", handle, info);
00206 
00207     return info;
00208 }
00209 
00210 static void invalidate_handle(object_header_t *info)
00211 {
00212     object_header_t *child, *next;
00213 
00214     if(!info->valid_handle)
00215         return;
00216     info->valid_handle = FALSE;
00217 
00218     /* Free all children as native does */
00219     LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
00220     {
00221         TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
00222         invalidate_handle( child );
00223     }
00224 
00225     WININET_Release(info);
00226 }
00227 
00228 BOOL WININET_Release( object_header_t *info )
00229 {
00230     ULONG refs = InterlockedDecrement(&info->refs);
00231     TRACE( "object %p refcount = %d\n", info, refs );
00232     if( !refs )
00233     {
00234         invalidate_handle(info);
00235         if ( info->vtbl->CloseConnection )
00236         {
00237             TRACE( "closing connection %p\n", info);
00238             info->vtbl->CloseConnection( info );
00239         }
00240         /* Don't send a callback if this is a session handle created with InternetOpenUrl */
00241         if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
00242             || !(info->dwInternalFlags & INET_OPENURL))
00243         {
00244             INTERNET_SendCallback(info, info->dwContext,
00245                                   INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
00246                                   sizeof(HINTERNET));
00247         }
00248         TRACE( "destroying object %p\n", info);
00249         if ( info->htype != WH_HINIT )
00250             list_remove( &info->entry );
00251         info->vtbl->Destroy( info );
00252 
00253         if(info->hInternet) {
00254             UINT_PTR handle = (UINT_PTR)info->hInternet;
00255 
00256             EnterCriticalSection( &WININET_cs );
00257 
00258             handle_table[handle] = NULL;
00259             if(next_handle > handle)
00260                 next_handle = handle;
00261 
00262             LeaveCriticalSection( &WININET_cs );
00263         }
00264 
00265         heap_free(info);
00266     }
00267     return TRUE;
00268 }
00269 
00270 /***********************************************************************
00271  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
00272  *
00273  * PARAMS
00274  *     hinstDLL    [I] handle to the DLL's instance
00275  *     fdwReason   [I]
00276  *     lpvReserved [I] reserved, must be NULL
00277  *
00278  * RETURNS
00279  *     Success: TRUE
00280  *     Failure: FALSE
00281  */
00282 
00283 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
00284 {
00285     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
00286 
00287     switch (fdwReason) {
00288         case DLL_PROCESS_ATTACH:
00289 
00290             g_dwTlsErrIndex = TlsAlloc();
00291 
00292         if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
00293         return FALSE;
00294 
00295             WININET_hModule = hinstDLL;
00296 
00297         case DLL_THREAD_ATTACH:
00298         break;
00299 
00300         case DLL_THREAD_DETACH:
00301         if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
00302             {
00303                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
00304                                 HeapFree(GetProcessHeap(), 0, lpwite);
00305             }
00306         break;
00307 
00308         case DLL_PROCESS_DETACH:
00309             collect_connections(TRUE);
00310             NETCON_unload();
00311 
00312         URLCacheContainers_DeleteAll();
00313 
00314         if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
00315         {
00316             HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
00317             TlsFree(g_dwTlsErrIndex);
00318         }
00319             break;
00320     }
00321 
00322     return TRUE;
00323 }
00324 
00325 /***********************************************************************
00326  *           INTERNET_SaveProxySettings
00327  *
00328  * Stores the proxy settings given by lpwai into the registry
00329  *
00330  * RETURNS
00331  *     ERROR_SUCCESS if no error, or error code on fail
00332  */
00333 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
00334 {
00335     HKEY key;
00336     LONG ret;
00337 
00338     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
00339         return ret;
00340 
00341     if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD))))
00342     {
00343         RegCloseKey( key );
00344         return ret;
00345     }
00346 
00347     if (lpwpi->lpszProxyServer)
00348     {
00349         if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1))))
00350         {
00351             RegCloseKey( key );
00352             return ret;
00353         }
00354     }
00355     else
00356     {
00357         if ((ret = RegDeleteValueW( key, szProxyServer )))
00358         {
00359             RegCloseKey( key );
00360             return ret;
00361         }
00362     }
00363 
00364     RegCloseKey(key);
00365     return ERROR_SUCCESS;
00366 }
00367 
00368 /***********************************************************************
00369  *           INTERNET_FindProxyForProtocol
00370  *
00371  * Searches the proxy string for a proxy of the given protocol.
00372  * Returns the found proxy, or the default proxy if none of the given
00373  * protocol is found.
00374  *
00375  * PARAMETERS
00376  *     szProxy       [In]     proxy string to search
00377  *     proto         [In]     protocol to search for, e.g. "http"
00378  *     foundProxy    [Out]    found proxy
00379  *     foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
00380  *
00381  * RETURNS
00382  *     TRUE if a proxy is found, FALSE if not.  If foundProxy is too short,
00383  *     *foundProxyLen is set to the required size in WCHARs, including the
00384  *     NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
00385  */
00386 BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen)
00387 {
00388     LPCWSTR ptr;
00389     BOOL ret = FALSE;
00390 
00391     TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
00392 
00393     /* First, look for the specified protocol (proto=scheme://host:port) */
00394     for (ptr = szProxy; !ret && ptr && *ptr; )
00395     {
00396         LPCWSTR end, equal;
00397 
00398         if (!(end = strchrW(ptr, ' ')))
00399             end = ptr + strlenW(ptr);
00400         if ((equal = strchrW(ptr, '=')) && equal < end &&
00401              equal - ptr == strlenW(proto) &&
00402              !strncmpiW(proto, ptr, strlenW(proto)))
00403         {
00404             if (end - equal > *foundProxyLen)
00405             {
00406                 WARN("buffer too short for %s\n",
00407                      debugstr_wn(equal + 1, end - equal - 1));
00408                 *foundProxyLen = end - equal;
00409                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
00410             }
00411             else
00412             {
00413                 memcpy(foundProxy, equal + 1, (end - equal) * sizeof(WCHAR));
00414                 foundProxy[end - equal] = 0;
00415                 ret = TRUE;
00416             }
00417         }
00418         if (*end == ' ')
00419             ptr = end + 1;
00420         else
00421             ptr = end;
00422     }
00423     if (!ret)
00424     {
00425         /* It wasn't found: look for no protocol */
00426         for (ptr = szProxy; !ret && ptr && *ptr; )
00427         {
00428             LPCWSTR end, equal;
00429 
00430             if (!(end = strchrW(ptr, ' ')))
00431                 end = ptr + strlenW(ptr);
00432             if (!(equal = strchrW(ptr, '=')))
00433             {
00434                 if (end - ptr + 1 > *foundProxyLen)
00435                 {
00436                     WARN("buffer too short for %s\n",
00437                          debugstr_wn(ptr, end - ptr));
00438                     *foundProxyLen = end - ptr + 1;
00439                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
00440                 }
00441                 else
00442                 {
00443                     memcpy(foundProxy, ptr, (end - ptr) * sizeof(WCHAR));
00444                     foundProxy[end - ptr] = 0;
00445                     ret = TRUE;
00446                 }
00447             }
00448             if (*end == ' ')
00449                 ptr = end + 1;
00450             else
00451                 ptr = end;
00452         }
00453     }
00454     if (ret)
00455         TRACE("found proxy for %s: %s\n", debugstr_w(proto),
00456               debugstr_w(foundProxy));
00457     return ret;
00458 }
00459 
00460 /***********************************************************************
00461  *           InternetInitializeAutoProxyDll   (WININET.@)
00462  *
00463  * Setup the internal proxy
00464  *
00465  * PARAMETERS
00466  *     dwReserved
00467  *
00468  * RETURNS
00469  *     FALSE on failure
00470  *
00471  */
00472 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
00473 {
00474     FIXME("STUB\n");
00475     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
00476     return FALSE;
00477 }
00478 
00479 /***********************************************************************
00480  *           DetectAutoProxyUrl   (WININET.@)
00481  *
00482  * Auto detect the proxy url
00483  *
00484  * RETURNS
00485  *     FALSE on failure
00486  *
00487  */
00488 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
00489     DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
00490 {
00491     FIXME("STUB\n");
00492     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
00493     return FALSE;
00494 }
00495 
00496 static void FreeProxyInfo( proxyinfo_t *lpwpi )
00497 {
00498     HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyServer);
00499     HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyBypass);
00500 }
00501 
00502 /***********************************************************************
00503  *          INTERNET_LoadProxySettings
00504  *
00505  * Loads proxy information from the registry or environment into lpwpi.
00506  *
00507  * The caller should call FreeProxyInfo when done with lpwpi.
00508  *
00509  * FIXME:
00510  * The proxy may be specified in the form 'http=proxy.my.org'
00511  * Presumably that means there can be ftp=ftpproxy.my.org too.
00512  */
00513 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
00514 {
00515     HKEY key;
00516     DWORD type, len;
00517     LPCSTR envproxy;
00518     LONG ret;
00519 
00520     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
00521         return ret;
00522 
00523     len = sizeof(DWORD);
00524     if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD)
00525     {
00526         lpwpi->dwProxyEnabled = 0;
00527         if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) )))
00528         {
00529             RegCloseKey( key );
00530             return ret;
00531         }
00532     }
00533 
00534     if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled)
00535     {
00536         TRACE("Proxy is enabled.\n");
00537 
00538         /* figure out how much memory the proxy setting takes */
00539         if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
00540         {
00541             LPWSTR szProxy, p;
00542             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
00543 
00544             if (!(szProxy = heap_alloc(len)))
00545             {
00546                 RegCloseKey( key );
00547                 return ERROR_OUTOFMEMORY;
00548             }
00549             RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
00550 
00551             /* find the http proxy, and strip away everything else */
00552             p = strstrW( szProxy, szHttp );
00553             if (p)
00554             {
00555                 p += lstrlenW( szHttp );
00556                 lstrcpyW( szProxy, p );
00557             }
00558             p = strchrW( szProxy, ' ' );
00559             if (p) *p = 0;
00560 
00561             lpwpi->lpszProxyServer = szProxy;
00562 
00563             TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer));
00564         }
00565         else
00566         {
00567             TRACE("No proxy server settings in registry.\n");
00568             lpwpi->lpszProxyServer = NULL;
00569         }
00570     }
00571     else if (envproxy)
00572     {
00573         WCHAR *envproxyW;
00574 
00575         len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
00576         if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
00577             return ERROR_OUTOFMEMORY;
00578         MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
00579 
00580         lpwpi->dwProxyEnabled = 1;
00581         lpwpi->lpszProxyServer = envproxyW;
00582 
00583         TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer));
00584     }
00585     RegCloseKey( key );
00586 
00587     lpwpi->lpszProxyBypass = NULL;
00588 
00589     return ERROR_SUCCESS;
00590 }
00591 
00592 /***********************************************************************
00593  *           INTERNET_ConfigureProxy
00594  */
00595 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
00596 {
00597     proxyinfo_t wpi;
00598 
00599     if (INTERNET_LoadProxySettings( &wpi ))
00600         return FALSE;
00601 
00602     if (wpi.dwProxyEnabled)
00603     {
00604         lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
00605         lpwai->proxy = wpi.lpszProxyServer;
00606         return TRUE;
00607     }
00608 
00609     lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
00610     return FALSE;
00611 }
00612 
00613 /***********************************************************************
00614  *           dump_INTERNET_FLAGS
00615  *
00616  * Helper function to TRACE the internet flags.
00617  *
00618  * RETURNS
00619  *    None
00620  *
00621  */
00622 static void dump_INTERNET_FLAGS(DWORD dwFlags) 
00623 {
00624 #define FE(x) { x, #x }
00625     static const wininet_flag_info flag[] = {
00626         FE(INTERNET_FLAG_RELOAD),
00627         FE(INTERNET_FLAG_RAW_DATA),
00628         FE(INTERNET_FLAG_EXISTING_CONNECT),
00629         FE(INTERNET_FLAG_ASYNC),
00630         FE(INTERNET_FLAG_PASSIVE),
00631         FE(INTERNET_FLAG_NO_CACHE_WRITE),
00632         FE(INTERNET_FLAG_MAKE_PERSISTENT),
00633         FE(INTERNET_FLAG_FROM_CACHE),
00634         FE(INTERNET_FLAG_SECURE),
00635         FE(INTERNET_FLAG_KEEP_CONNECTION),
00636         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
00637         FE(INTERNET_FLAG_READ_PREFETCH),
00638         FE(INTERNET_FLAG_NO_COOKIES),
00639         FE(INTERNET_FLAG_NO_AUTH),
00640         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
00641         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
00642         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
00643         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
00644         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
00645         FE(INTERNET_FLAG_RESYNCHRONIZE),
00646         FE(INTERNET_FLAG_HYPERLINK),
00647         FE(INTERNET_FLAG_NO_UI),
00648         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
00649         FE(INTERNET_FLAG_CACHE_ASYNC),
00650         FE(INTERNET_FLAG_FORMS_SUBMIT),
00651         FE(INTERNET_FLAG_NEED_FILE),
00652         FE(INTERNET_FLAG_TRANSFER_ASCII),
00653         FE(INTERNET_FLAG_TRANSFER_BINARY)
00654     };
00655 #undef FE
00656     unsigned int i;
00657 
00658     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
00659     if (flag[i].val & dwFlags) {
00660         TRACE(" %s", flag[i].name);
00661         dwFlags &= ~flag[i].val;
00662     }
00663     }   
00664     if (dwFlags)
00665         TRACE(" Unknown flags (%08x)\n", dwFlags);
00666     else
00667         TRACE("\n");
00668 }
00669 
00670 /***********************************************************************
00671  *           INTERNET_CloseHandle (internal)
00672  *
00673  * Close internet handle
00674  *
00675  */
00676 static VOID APPINFO_Destroy(object_header_t *hdr)
00677 {
00678     appinfo_t *lpwai = (appinfo_t*)hdr;
00679 
00680     TRACE("%p\n",lpwai);
00681 
00682     HeapFree(GetProcessHeap(), 0, lpwai->agent);
00683     HeapFree(GetProcessHeap(), 0, lpwai->proxy);
00684     HeapFree(GetProcessHeap(), 0, lpwai->proxyBypass);
00685     HeapFree(GetProcessHeap(), 0, lpwai->proxyUsername);
00686     HeapFree(GetProcessHeap(), 0, lpwai->proxyPassword);
00687 }
00688 
00689 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
00690 {
00691     appinfo_t *ai = (appinfo_t*)hdr;
00692 
00693     switch(option) {
00694     case INTERNET_OPTION_HANDLE_TYPE:
00695         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
00696 
00697         if (*size < sizeof(ULONG))
00698             return ERROR_INSUFFICIENT_BUFFER;
00699 
00700         *size = sizeof(DWORD);
00701         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
00702         return ERROR_SUCCESS;
00703 
00704     case INTERNET_OPTION_USER_AGENT: {
00705         DWORD bufsize;
00706 
00707         TRACE("INTERNET_OPTION_USER_AGENT\n");
00708 
00709         bufsize = *size;
00710 
00711         if (unicode) {
00712             DWORD len = ai->agent ? strlenW(ai->agent) : 0;
00713 
00714             *size = (len + 1) * sizeof(WCHAR);
00715             if(!buffer || bufsize < *size)
00716                 return ERROR_INSUFFICIENT_BUFFER;
00717 
00718             if (ai->agent)
00719                 strcpyW(buffer, ai->agent);
00720             else
00721                 *(WCHAR *)buffer = 0;
00722             /* If the buffer is copied, the returned length doesn't include
00723              * the NULL terminator.
00724              */
00725             *size = len * sizeof(WCHAR);
00726         }else {
00727             if (ai->agent)
00728                 *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
00729             else
00730                 *size = 1;
00731             if(!buffer || bufsize < *size)
00732                 return ERROR_INSUFFICIENT_BUFFER;
00733 
00734             if (ai->agent)
00735                 WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
00736             else
00737                 *(char *)buffer = 0;
00738             /* If the buffer is copied, the returned length doesn't include
00739              * the NULL terminator.
00740              */
00741             *size -= 1;
00742         }
00743 
00744         return ERROR_SUCCESS;
00745     }
00746 
00747     case INTERNET_OPTION_PROXY:
00748         if (unicode) {
00749             INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
00750             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
00751             LPWSTR proxy, proxy_bypass;
00752 
00753             if (ai->proxy)
00754                 proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
00755             if (ai->proxyBypass)
00756                 proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
00757             if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
00758             {
00759                 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
00760                 return ERROR_INSUFFICIENT_BUFFER;
00761             }
00762             proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
00763             proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
00764 
00765             pi->dwAccessType = ai->accessType;
00766             pi->lpszProxy = NULL;
00767             pi->lpszProxyBypass = NULL;
00768             if (ai->proxy) {
00769                 lstrcpyW(proxy, ai->proxy);
00770                 pi->lpszProxy = proxy;
00771             }
00772 
00773             if (ai->proxyBypass) {
00774                 lstrcpyW(proxy_bypass, ai->proxyBypass);
00775                 pi->lpszProxyBypass = proxy_bypass;
00776             }
00777 
00778             *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
00779             return ERROR_SUCCESS;
00780         }else {
00781             INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
00782             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
00783             LPSTR proxy, proxy_bypass;
00784 
00785             if (ai->proxy)
00786                 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
00787             if (ai->proxyBypass)
00788                 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
00789                         NULL, 0, NULL, NULL);
00790             if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
00791             {
00792                 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
00793                 return ERROR_INSUFFICIENT_BUFFER;
00794             }
00795             proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
00796             proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
00797 
00798             pi->dwAccessType = ai->accessType;
00799             pi->lpszProxy = NULL;
00800             pi->lpszProxyBypass = NULL;
00801             if (ai->proxy) {
00802                 WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
00803                 pi->lpszProxy = proxy;
00804             }
00805 
00806             if (ai->proxyBypass) {
00807                 WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
00808                         proxyBypassBytesRequired, NULL, NULL);
00809                 pi->lpszProxyBypass = proxy_bypass;
00810             }
00811 
00812             *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
00813             return ERROR_SUCCESS;
00814         }
00815     }
00816 
00817     return INET_QueryOption(hdr, option, buffer, size, unicode);
00818 }
00819 
00820 static const object_vtbl_t APPINFOVtbl = {
00821     APPINFO_Destroy,
00822     NULL,
00823     APPINFO_QueryOption,
00824     NULL,
00825     NULL,
00826     NULL,
00827     NULL,
00828     NULL,
00829     NULL
00830 };
00831 
00832 
00833 /***********************************************************************
00834  *           InternetOpenW   (WININET.@)
00835  *
00836  * Per-application initialization of wininet
00837  *
00838  * RETURNS
00839  *    HINTERNET on success
00840  *    NULL on failure
00841  *
00842  */
00843 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
00844     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
00845 {
00846     appinfo_t *lpwai = NULL;
00847 
00848     if (TRACE_ON(wininet)) {
00849 #define FE(x) { x, #x }
00850     static const wininet_flag_info access_type[] = {
00851         FE(INTERNET_OPEN_TYPE_PRECONFIG),
00852         FE(INTERNET_OPEN_TYPE_DIRECT),
00853         FE(INTERNET_OPEN_TYPE_PROXY),
00854         FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
00855     };
00856 #undef FE
00857     DWORD i;
00858     const char *access_type_str = "Unknown";
00859     
00860     TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
00861           debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
00862     for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
00863         if (access_type[i].val == dwAccessType) {
00864         access_type_str = access_type[i].name;
00865         break;
00866         }
00867     }
00868     TRACE("  access type : %s\n", access_type_str);
00869     TRACE("  flags       :");
00870     dump_INTERNET_FLAGS(dwFlags);
00871     }
00872 
00873     /* Clear any error information */
00874     INTERNET_SetLastError(0);
00875 
00876     lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
00877     if (!lpwai) {
00878         SetLastError(ERROR_OUTOFMEMORY);
00879         return NULL;
00880     }
00881 
00882     lpwai->hdr.htype = WH_HINIT;
00883     lpwai->hdr.dwFlags = dwFlags;
00884     lpwai->accessType = dwAccessType;
00885     lpwai->proxyUsername = NULL;
00886     lpwai->proxyPassword = NULL;
00887 
00888     lpwai->agent = heap_strdupW(lpszAgent);
00889     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
00890         INTERNET_ConfigureProxy( lpwai );
00891     else
00892         lpwai->proxy = heap_strdupW(lpszProxy);
00893     lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);
00894 
00895     TRACE("returning %p\n", lpwai);
00896 
00897     return lpwai->hdr.hInternet;
00898 }
00899 
00900 
00901 /***********************************************************************
00902  *           InternetOpenA   (WININET.@)
00903  *
00904  * Per-application initialization of wininet
00905  *
00906  * RETURNS
00907  *    HINTERNET on success
00908  *    NULL on failure
00909  *
00910  */
00911 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
00912     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
00913 {
00914     WCHAR *szAgent, *szProxy, *szBypass;
00915     HINTERNET rc;
00916 
00917     TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
00918        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
00919 
00920     szAgent = heap_strdupAtoW(lpszAgent);
00921     szProxy = heap_strdupAtoW(lpszProxy);
00922     szBypass = heap_strdupAtoW(lpszProxyBypass);
00923 
00924     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
00925 
00926     HeapFree(GetProcessHeap(), 0, szAgent);
00927     HeapFree(GetProcessHeap(), 0, szProxy);
00928     HeapFree(GetProcessHeap(), 0, szBypass);
00929 
00930     return rc;
00931 }
00932 
00933 /***********************************************************************
00934  *           InternetGetLastResponseInfoA (WININET.@)
00935  *
00936  * Return last wininet error description on the calling thread
00937  *
00938  * RETURNS
00939  *    TRUE on success of writing to buffer
00940  *    FALSE on failure
00941  *
00942  */
00943 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
00944     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
00945 {
00946     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
00947 
00948     TRACE("\n");
00949 
00950     if (lpwite)
00951     {
00952         *lpdwError = lpwite->dwError;
00953         if (lpwite->dwError)
00954         {
00955             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
00956             *lpdwBufferLength = strlen(lpszBuffer);
00957         }
00958         else
00959             *lpdwBufferLength = 0;
00960     }
00961     else
00962     {
00963         *lpdwError = 0;
00964         *lpdwBufferLength = 0;
00965     }
00966 
00967     return TRUE;
00968 }
00969 
00970 /***********************************************************************
00971  *           InternetGetLastResponseInfoW (WININET.@)
00972  *
00973  * Return last wininet error description on the calling thread
00974  *
00975  * RETURNS
00976  *    TRUE on success of writing to buffer
00977  *    FALSE on failure
00978  *
00979  */
00980 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
00981     LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
00982 {
00983     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
00984 
00985     TRACE("\n");
00986 
00987     if (lpwite)
00988     {
00989         *lpdwError = lpwite->dwError;
00990         if (lpwite->dwError)
00991         {
00992             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
00993             *lpdwBufferLength = lstrlenW(lpszBuffer);
00994         }
00995         else
00996             *lpdwBufferLength = 0;
00997     }
00998     else
00999     {
01000         *lpdwError = 0;
01001         *lpdwBufferLength = 0;
01002     }
01003 
01004     return TRUE;
01005 }
01006 
01007 /***********************************************************************
01008  *           InternetGetConnectedState (WININET.@)
01009  *
01010  * Return connected state
01011  *
01012  * RETURNS
01013  *    TRUE if connected
01014  *    if lpdwStatus is not null, return the status (off line,
01015  *    modem, lan...) in it.
01016  *    FALSE if not connected
01017  */
01018 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
01019 {
01020     TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
01021 
01022     if (lpdwStatus) {
01023     WARN("always returning LAN connection.\n");
01024     *lpdwStatus = INTERNET_CONNECTION_LAN;
01025     }
01026     return TRUE;
01027 }
01028 
01029 
01030 /***********************************************************************
01031  *           InternetGetConnectedStateExW (WININET.@)
01032  *
01033  * Return connected state
01034  *
01035  * PARAMS
01036  *
01037  * lpdwStatus         [O] Flags specifying the status of the internet connection.
01038  * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
01039  * dwNameLen          [I] Size of the buffer, in characters.
01040  * dwReserved         [I] Reserved. Must be set to 0.
01041  *
01042  * RETURNS
01043  *    TRUE if connected
01044  *    if lpdwStatus is not null, return the status (off line,
01045  *    modem, lan...) in it.
01046  *    FALSE if not connected
01047  *
01048  * NOTES
01049  *   If the system has no available network connections, an empty string is
01050  *   stored in lpszConnectionName. If there is a LAN connection, a localized
01051  *   "LAN Connection" string is stored. Presumably, if only a dial-up
01052  *   connection is available then the name of the dial-up connection is
01053  *   returned. Why any application, other than the "Internet Settings" CPL,
01054  *   would want to use this function instead of the simpler InternetGetConnectedStateW
01055  *   function is beyond me.
01056  */
01057 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
01058                                          DWORD dwNameLen, DWORD dwReserved)
01059 {
01060     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
01061 
01062     /* Must be zero */
01063     if(dwReserved)
01064     return FALSE;
01065 
01066     if (lpdwStatus) {
01067         WARN("always returning LAN connection.\n");
01068         *lpdwStatus = INTERNET_CONNECTION_LAN;
01069     }
01070     return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
01071 }
01072 
01073 
01074 /***********************************************************************
01075  *           InternetGetConnectedStateExA (WININET.@)
01076  */
01077 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
01078                                          DWORD dwNameLen, DWORD dwReserved)
01079 {
01080     LPWSTR lpwszConnectionName = NULL;
01081     BOOL rc;
01082 
01083     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
01084 
01085     if (lpszConnectionName && dwNameLen > 0)
01086         lpwszConnectionName = heap_alloc(dwNameLen * sizeof(WCHAR));
01087 
01088     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
01089                                       dwReserved);
01090     if (rc && lpwszConnectionName)
01091     {
01092         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
01093                             dwNameLen, NULL, NULL);
01094 
01095         HeapFree(GetProcessHeap(),0,lpwszConnectionName);
01096     }
01097 
01098     return rc;
01099 }
01100 
01101 
01102 /***********************************************************************
01103  *           InternetConnectW (WININET.@)
01104  *
01105  * Open a ftp, gopher or http session
01106  *
01107  * RETURNS
01108  *    HINTERNET a session handle on success
01109  *    NULL on failure
01110  *
01111  */
01112 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
01113     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
01114     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
01115     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
01116 {
01117     appinfo_t *hIC;
01118     HINTERNET rc = NULL;
01119     DWORD res = ERROR_SUCCESS;
01120 
01121     TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName),
01122       nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
01123       dwService, dwFlags, dwContext);
01124 
01125     if (!lpszServerName)
01126     {
01127         SetLastError(ERROR_INVALID_PARAMETER);
01128         return NULL;
01129     }
01130 
01131     hIC = (appinfo_t*)get_handle_object( hInternet );
01132     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
01133     {
01134         res = ERROR_INVALID_HANDLE;
01135         goto lend;
01136     }
01137 
01138     switch (dwService)
01139     {
01140         case INTERNET_SERVICE_FTP:
01141             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
01142             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
01143             if(!rc)
01144                 res = INTERNET_GetLastError();
01145             break;
01146 
01147         case INTERNET_SERVICE_HTTP:
01148         res = HTTP_Connect(hIC, lpszServerName, nServerPort,
01149                     lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
01150             break;
01151 
01152         case INTERNET_SERVICE_GOPHER:
01153         default:
01154             break;
01155     }
01156 lend:
01157     if( hIC )
01158         WININET_Release( &hIC->hdr );
01159 
01160     TRACE("returning %p\n", rc);
01161     SetLastError(res);
01162     return rc;
01163 }
01164 
01165 
01166 /***********************************************************************
01167  *           InternetConnectA (WININET.@)
01168  *
01169  * Open a ftp, gopher or http session
01170  *
01171  * RETURNS
01172  *    HINTERNET a session handle on success
01173  *    NULL on failure
01174  *
01175  */
01176 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
01177     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
01178     LPCSTR lpszUserName, LPCSTR lpszPassword,
01179     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
01180 {
01181     HINTERNET rc = NULL;
01182     LPWSTR szServerName;
01183     LPWSTR szUserName;
01184     LPWSTR szPassword;
01185 
01186     szServerName = heap_strdupAtoW(lpszServerName);
01187     szUserName = heap_strdupAtoW(lpszUserName);
01188     szPassword = heap_strdupAtoW(lpszPassword);
01189 
01190     rc = InternetConnectW(hInternet, szServerName, nServerPort,
01191         szUserName, szPassword, dwService, dwFlags, dwContext);
01192 
01193     HeapFree(GetProcessHeap(), 0, szServerName);
01194     HeapFree(GetProcessHeap(), 0, szUserName);
01195     HeapFree(GetProcessHeap(), 0, szPassword);
01196     return rc;
01197 }
01198 
01199 
01200 /***********************************************************************
01201  *           InternetFindNextFileA (WININET.@)
01202  *
01203  * Continues a file search from a previous call to FindFirstFile
01204  *
01205  * RETURNS
01206  *    TRUE on success
01207  *    FALSE on failure
01208  *
01209  */
01210 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
01211 {
01212     BOOL ret;
01213     WIN32_FIND_DATAW fd;
01214     
01215     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
01216     if(lpvFindData)
01217         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
01218     return ret;
01219 }
01220 
01221 /***********************************************************************
01222  *           InternetFindNextFileW (WININET.@)
01223  *
01224  * Continues a file search from a previous call to FindFirstFile
01225  *
01226  * RETURNS
01227  *    TRUE on success
01228  *    FALSE on failure
01229  *
01230  */
01231 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
01232 {
01233     object_header_t *hdr;
01234     DWORD res;
01235 
01236     TRACE("\n");
01237 
01238     hdr = get_handle_object(hFind);
01239     if(!hdr) {
01240         WARN("Invalid handle\n");
01241         SetLastError(ERROR_INVALID_HANDLE);
01242         return FALSE;
01243     }
01244 
01245     if(hdr->vtbl->FindNextFileW) {
01246         res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
01247     }else {
01248         WARN("Handle doesn't support NextFile\n");
01249         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
01250     }
01251 
01252     WININET_Release(hdr);
01253 
01254     if(res != ERROR_SUCCESS)
01255         SetLastError(res);
01256     return res == ERROR_SUCCESS;
01257 }
01258 
01259 /***********************************************************************
01260  *           InternetCloseHandle (WININET.@)
01261  *
01262  * Generic close handle function
01263  *
01264  * RETURNS
01265  *    TRUE on success
01266  *    FALSE on failure
01267  *
01268  */
01269 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
01270 {
01271     object_header_t *obj;
01272     
01273     TRACE("%p\n", hInternet);
01274 
01275     obj = get_handle_object( hInternet );
01276     if (!obj) {
01277         SetLastError(ERROR_INVALID_HANDLE);
01278         return FALSE;
01279     }
01280 
01281     invalidate_handle(obj);
01282     WININET_Release(obj);
01283 
01284     return TRUE;
01285 }
01286 
01287 
01288 /***********************************************************************
01289  *           ConvertUrlComponentValue (Internal)
01290  *
01291  * Helper function for InternetCrackUrlA
01292  *
01293  */
01294 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
01295                                      LPWSTR lpwszComponent, DWORD dwwComponentLen,
01296                                      LPCSTR lpszStart, LPCWSTR lpwszStart)
01297 {
01298     TRACE("%p %d %p %d %p %p\n", *lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
01299     if (*dwComponentLen != 0)
01300     {
01301         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
01302         if (*lppszComponent == NULL)
01303         {
01304             if (lpwszComponent)
01305             {
01306                 int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL);
01307                 *lppszComponent = (LPSTR)lpszStart + offset;
01308             }
01309             else
01310                 *lppszComponent = NULL;
01311 
01312             *dwComponentLen = nASCIILength;
01313         }
01314         else
01315         {
01316             DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
01317             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
01318             (*lppszComponent)[ncpylen]=0;
01319             *dwComponentLen = ncpylen;
01320         }
01321     }
01322 }
01323 
01324 
01325 /***********************************************************************
01326  *           InternetCrackUrlA (WININET.@)
01327  *
01328  * See InternetCrackUrlW.
01329  */
01330 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
01331     LPURL_COMPONENTSA lpUrlComponents)
01332 {
01333   DWORD nLength;
01334   URL_COMPONENTSW UCW;
01335   BOOL ret = FALSE;
01336   WCHAR *lpwszUrl, *hostname = NULL, *username = NULL, *password = NULL, *path = NULL,
01337         *scheme = NULL, *extra = NULL;
01338 
01339   TRACE("(%s %u %x %p)\n",
01340         lpszUrl ? debugstr_an(lpszUrl, dwUrlLength ? dwUrlLength : strlen(lpszUrl)) : "(null)",
01341         dwUrlLength, dwFlags, lpUrlComponents);
01342 
01343   if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
01344           lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
01345   {
01346       INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
01347       return FALSE;
01348   }
01349 
01350   if(dwUrlLength<=0)
01351       dwUrlLength=-1;
01352   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
01353 
01354   /* if dwUrlLength=-1 then nLength includes null but length to 
01355        InternetCrackUrlW should not include it                  */
01356   if (dwUrlLength == -1) nLength--;
01357 
01358   lpwszUrl = heap_alloc((nLength + 1) * sizeof(WCHAR));
01359   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength + 1);
01360   lpwszUrl[nLength] = '\0';
01361 
01362   memset(&UCW,0,sizeof(UCW));
01363   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
01364   if (lpUrlComponents->dwHostNameLength)
01365   {
01366     UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
01367     if (lpUrlComponents->lpszHostName)
01368     {
01369       hostname = heap_alloc(UCW.dwHostNameLength * sizeof(WCHAR));
01370       UCW.lpszHostName = hostname;
01371     }
01372   }
01373   if (lpUrlComponents->dwUserNameLength)
01374   {
01375     UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
01376     if (lpUrlComponents->lpszUserName)
01377     {
01378       username = heap_alloc(UCW.dwUserNameLength * sizeof(WCHAR));
01379       UCW.lpszUserName = username;
01380     }
01381   }
01382   if (lpUrlComponents->dwPasswordLength)
01383   {
01384     UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
01385     if (lpUrlComponents->lpszPassword)
01386     {
01387       password = heap_alloc(UCW.dwPasswordLength * sizeof(WCHAR));
01388       UCW.lpszPassword = password;
01389     }
01390   }
01391   if (lpUrlComponents->dwUrlPathLength)
01392   {
01393     UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
01394     if (lpUrlComponents->lpszUrlPath)
01395     {
01396       path = heap_alloc(UCW.dwUrlPathLength * sizeof(WCHAR));
01397       UCW.lpszUrlPath = path;
01398     }
01399   }
01400   if (lpUrlComponents->dwSchemeLength)
01401   {
01402     UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
01403     if (lpUrlComponents->lpszScheme)
01404     {
01405       scheme = heap_alloc(UCW.dwSchemeLength * sizeof(WCHAR));
01406       UCW.lpszScheme = scheme;
01407     }
01408   }
01409   if (lpUrlComponents->dwExtraInfoLength)
01410   {
01411     UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
01412     if (lpUrlComponents->lpszExtraInfo)
01413     {
01414       extra = heap_alloc(UCW.dwExtraInfoLength * sizeof(WCHAR));
01415       UCW.lpszExtraInfo = extra;
01416     }
01417   }
01418   if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
01419   {
01420     ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
01421                              UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
01422     ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
01423                              UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
01424     ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
01425                              UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
01426     ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
01427                              UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
01428     ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
01429                              UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
01430     ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
01431                              UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
01432 
01433     lpUrlComponents->nScheme = UCW.nScheme;
01434     lpUrlComponents->nPort = UCW.nPort;
01435 
01436     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(lpszUrl),
01437           debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
01438           debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
01439           debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
01440           debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
01441   }
01442   HeapFree(GetProcessHeap(), 0, lpwszUrl);
01443   HeapFree(GetProcessHeap(), 0, hostname);
01444   HeapFree(GetProcessHeap(), 0, username);
01445   HeapFree(GetProcessHeap(), 0, password);
01446   HeapFree(GetProcessHeap(), 0, path);
01447   HeapFree(GetProcessHeap(), 0, scheme);
01448   HeapFree(GetProcessHeap(), 0, extra);
01449   return ret;
01450 }
01451 
01452 static const WCHAR url_schemes[][7] =
01453 {
01454     {'f','t','p',0},
01455     {'g','o','p','h','e','r',0},
01456     {'h','t','t','p',0},
01457     {'h','t','t','p','s',0},
01458     {'f','i','l','e',0},
01459     {'n','e','w','s',0},
01460     {'m','a','i','l','t','o',0},
01461     {'r','e','s',0},
01462 };
01463 
01464 /***********************************************************************
01465  *           GetInternetSchemeW (internal)
01466  *
01467  * Get scheme of url
01468  *
01469  * RETURNS
01470  *    scheme on success
01471  *    INTERNET_SCHEME_UNKNOWN on failure
01472  *
01473  */
01474 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
01475 {
01476     int i;
01477 
01478     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
01479 
01480     if(lpszScheme==NULL)
01481         return INTERNET_SCHEME_UNKNOWN;
01482 
01483     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
01484         if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
01485             return INTERNET_SCHEME_FIRST + i;
01486 
01487     return INTERNET_SCHEME_UNKNOWN;
01488 }
01489 
01490 /***********************************************************************
01491  *           SetUrlComponentValueW (Internal)
01492  *
01493  * Helper function for InternetCrackUrlW
01494  *
01495  * PARAMS
01496  *     lppszComponent [O] Holds the returned string
01497  *     dwComponentLen [I] Holds the size of lppszComponent
01498  *                    [O] Holds the length of the string in lppszComponent without '\0'
01499  *     lpszStart      [I] Holds the string to copy from
01500  *     len            [I] Holds the length of lpszStart without '\0'
01501  *
01502  * RETURNS
01503  *    TRUE on success
01504  *    FALSE on failure
01505  *
01506  */
01507 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
01508 {
01509     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
01510 
01511     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
01512         return FALSE;
01513 
01514     if (*dwComponentLen != 0 || *lppszComponent == NULL)
01515     {
01516         if (*lppszComponent == NULL)
01517         {
01518             *lppszComponent = (LPWSTR)lpszStart;
01519             *dwComponentLen = len;
01520         }
01521         else
01522         {
01523             DWORD ncpylen = min((*dwComponentLen)-1, len);
01524             memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
01525             (*lppszComponent)[ncpylen] = '\0';
01526             *dwComponentLen = ncpylen;
01527         }
01528     }
01529 
01530     return TRUE;
01531 }
01532 
01533 /***********************************************************************
01534  *           InternetCrackUrlW   (WININET.@)
01535  *
01536  * Break up URL into its components
01537  *
01538  * RETURNS
01539  *    TRUE on success
01540  *    FALSE on failure
01541  */
01542 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
01543                               LPURL_COMPONENTSW lpUC)
01544 {
01545   /*
01546    * RFC 1808
01547    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
01548    *
01549    */
01550     LPCWSTR lpszParam    = NULL;
01551     BOOL  bIsAbsolute = FALSE;
01552     LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
01553     LPCWSTR lpszcp = NULL;
01554     LPWSTR  lpszUrl_decode = NULL;
01555     DWORD dwUrlLength = dwUrlLength_orig;
01556 
01557     TRACE("(%s %u %x %p)\n",
01558           lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
01559           dwUrlLength, dwFlags, lpUC);
01560 
01561     if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
01562     {
01563         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
01564         return FALSE;
01565     }
01566     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
01567 
01568     if (dwFlags & ICU_DECODE)
01569     {
01570         WCHAR *url_tmp;
01571         DWORD len = dwUrlLength + 1;
01572 
01573         if (!(url_tmp = heap_alloc(len * sizeof(WCHAR))))
01574         {
01575             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
01576             return FALSE;
01577         }
01578         memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
01579         url_tmp[dwUrlLength] = 0;
01580         if (!(lpszUrl_decode = heap_alloc(len * sizeof(WCHAR))))
01581         {
01582             HeapFree(GetProcessHeap(), 0, url_tmp);
01583             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
01584             return FALSE;
01585         }
01586         if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
01587         {
01588             dwUrlLength = len;
01589             lpszUrl = lpszUrl_decode;
01590         }
01591         HeapFree(GetProcessHeap(), 0, url_tmp);
01592     }
01593     lpszap = lpszUrl;
01594     
01595     /* Determine if the URI is absolute. */
01596     while (lpszap - lpszUrl < dwUrlLength)
01597     {
01598         if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
01599         {
01600             lpszap++;
01601             continue;
01602         }
01603         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
01604         {
01605             bIsAbsolute = TRUE;
01606             lpszcp = lpszap;
01607         }
01608         else
01609         {
01610             lpszcp = lpszUrl; /* Relative url */
01611         }
01612 
01613         break;
01614     }
01615 
01616     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
01617     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
01618 
01619     /* Parse <params> */
01620     lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl));
01621     if(!lpszParam)
01622         lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
01623     if(!lpszParam)
01624         lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
01625 
01626     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
01627                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
01628 
01629     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
01630     {
01631         LPCWSTR lpszNetLoc;
01632 
01633         /* Get scheme first. */
01634         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
01635         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
01636                                    lpszUrl, lpszcp - lpszUrl);
01637 
01638         /* Eat ':' in protocol. */
01639         lpszcp++;
01640 
01641         /* double slash indicates the net_loc portion is present */
01642         if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
01643         {
01644             lpszcp += 2;
01645 
01646             lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
01647             if (lpszParam)
01648             {
01649                 if (lpszNetLoc)
01650                     lpszNetLoc = min(lpszNetLoc, lpszParam);
01651                 else
01652                     lpszNetLoc = lpszParam;
01653             }
01654             else if (!lpszNetLoc)
01655                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
01656 
01657             /* Parse net-loc */
01658             if (lpszNetLoc)
01659             {
01660                 LPCWSTR lpszHost;
01661                 LPCWSTR lpszPort;
01662 
01663                 /* [<user>[<:password>]@]<host>[:<port>] */
01664                 /* First find the user and password if they exist */
01665 
01666                 lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
01667                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
01668                 {
01669                     /* username and password not specified. */
01670                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
01671                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
01672                 }
01673                 else /* Parse out username and password */
01674                 {
01675                     LPCWSTR lpszUser = lpszcp;
01676                     LPCWSTR lpszPasswd = lpszHost;
01677 
01678                     while (lpszcp < lpszHost)
01679                     {
01680                         if (*lpszcp == ':')
01681                             lpszPasswd = lpszcp;
01682 
01683                         lpszcp++;
01684                     }
01685 
01686                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
01687                                           lpszUser, lpszPasswd - lpszUser);
01688 
01689                     if (lpszPasswd != lpszHost)
01690                         lpszPasswd++;
01691                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
01692                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
01693                                           lpszHost - lpszPasswd);
01694 
01695                     lpszcp++; /* Advance to beginning of host */
01696                 }
01697 
01698                 /* Parse <host><:port> */
01699 
01700                 lpszHost = lpszcp;
01701                 lpszPort = lpszNetLoc;
01702 
01703                 /* special case for res:// URLs: there is no port here, so the host is the
01704                    entire string up to the first '/' */
01705                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
01706                 {
01707                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
01708                                           lpszHost, lpszPort - lpszHost);
01709                     lpszcp=lpszNetLoc;
01710                 }
01711                 else
01712                 {
01713                     while (lpszcp < lpszNetLoc)
01714                     {
01715                         if (*lpszcp == ':')
01716                             lpszPort = lpszcp;
01717 
01718                         lpszcp++;
01719                     }
01720 
01721                     /* If the scheme is "file" and the host is just one letter, it's not a host */
01722                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
01723                     {
01724                         lpszcp=lpszHost;
01725                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
01726                                               NULL, 0);
01727                     }
01728                     else
01729                     {
01730                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
01731                                               lpszHost, lpszPort - lpszHost);
01732                         if (lpszPort != lpszNetLoc)
01733                             lpUC->nPort = atoiW(++lpszPort);
01734                         else switch (lpUC->nScheme)
01735                         {
01736                         case INTERNET_SCHEME_HTTP:
01737                             lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
01738                             break;
01739                         case INTERNET_SCHEME_HTTPS:
01740                             lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
01741                             break;
01742                         case INTERNET_SCHEME_FTP:
01743                             lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
01744                             break;
01745                         case INTERNET_SCHEME_GOPHER:
01746                             lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
01747                             break;
01748                         default:
01749                             break;
01750                         }
01751                     }
01752                 }
01753             }
01754         }
01755         else
01756         {
01757             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
01758             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
01759             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
01760         }
01761     }
01762     else
01763     {
01764         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
01765         SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
01766         SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
01767         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
01768     }
01769 
01770     /* Here lpszcp points to:
01771      *
01772      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
01773      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
01774      */
01775     if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
01776     {
01777         DWORD len;
01778 
01779         /* Only truncate the parameter list if it's already been saved
01780          * in lpUC->lpszExtraInfo.
01781          */
01782         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
01783             len = lpszParam - lpszcp;
01784         else
01785         {
01786             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
01787              * newlines if necessary.
01788              */
01789             LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
01790             if (lpsznewline != NULL)
01791                 len = lpsznewline - lpszcp;
01792             else
01793                 len = dwUrlLength-(lpszcp-lpszUrl);
01794         }
01795         if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
01796                 lpUC->nScheme == INTERNET_SCHEME_FILE)
01797         {
01798             WCHAR tmppath[MAX_PATH];
01799             if (*lpszcp == '/')
01800             {
01801                 len = MAX_PATH;
01802                 PathCreateFromUrlW(lpszUrl_orig, tmppath, &len, 0);
01803             }
01804             else
01805             {
01806                 WCHAR *iter;
01807                 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
01808                 tmppath[len] = '\0';
01809 
01810                 iter = tmppath;
01811                 while (*iter) {
01812                     if (*iter == '/')
01813                         *iter = '\\';
01814                     ++iter;
01815                 }
01816             }
01817             /* if ends in \. or \.. append a backslash */
01818             if (tmppath[len - 1] == '.' &&
01819                     (tmppath[len - 2] == '\\' ||
01820                      (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
01821             {
01822                 if (len < MAX_PATH - 1)
01823                 {
01824                     tmppath[len] = '\\';
01825                     tmppath[len+1] = '\0';
01826                     ++len;
01827                 }
01828             }
01829             SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
01830                                        tmppath, len);
01831         }
01832         else
01833             SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
01834                                        lpszcp, len);
01835     }
01836     else
01837     {
01838         if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
01839             lpUC->lpszUrlPath[0] = 0;
01840         lpUC->dwUrlPathLength = 0;
01841     }
01842 
01843     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
01844              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
01845              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
01846              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
01847              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
01848 
01849     HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
01850     return TRUE;
01851 }
01852 
01853 /***********************************************************************
01854  *           InternetAttemptConnect (WININET.@)
01855  *
01856  * Attempt to make a connection to the internet
01857  *
01858  * RETURNS
01859  *    ERROR_SUCCESS on success
01860  *    Error value   on failure
01861  *
01862  */
01863 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
01864 {
01865     FIXME("Stub\n");
01866     return ERROR_SUCCESS;
01867 }
01868 
01869 
01870 /***********************************************************************
01871  *           InternetCanonicalizeUrlA (WININET.@)
01872  *
01873  * Escape unsafe characters and spaces
01874  *
01875  * RETURNS
01876  *    TRUE on success
01877  *    FALSE on failure
01878  *
01879  */
01880 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
01881     LPDWORD lpdwBufferLength, DWORD dwFlags)
01882 {
01883     HRESULT hr;
01884     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
01885 
01886     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
01887         lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
01888 
01889     if(dwFlags & ICU_DECODE)
01890     {
01891         dwURLFlags |= URL_UNESCAPE;
01892         dwFlags &= ~ICU_DECODE;
01893     }
01894 
01895     if(dwFlags & ICU_ESCAPE)
01896     {
01897         dwURLFlags |= URL_UNESCAPE;
01898         dwFlags &= ~ICU_ESCAPE;
01899     }
01900 
01901     if(dwFlags & ICU_BROWSER_MODE)
01902     {
01903         dwURLFlags |= URL_BROWSER_MODE;
01904         dwFlags &= ~ICU_BROWSER_MODE;
01905     }
01906 
01907     if(dwFlags & ICU_NO_ENCODE)
01908     {
01909         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
01910         dwURLFlags ^= URL_ESCAPE_UNSAFE;
01911         dwFlags &= ~ICU_NO_ENCODE;
01912     }
01913 
01914     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
01915 
01916     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
01917     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
01918     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
01919 
01920     return (hr == S_OK) ? TRUE : FALSE;
01921 }
01922 
01923 /***********************************************************************
01924  *           InternetCanonicalizeUrlW (WININET.@)
01925  *
01926  * Escape unsafe characters and spaces
01927  *
01928  * RETURNS
01929  *    TRUE on success
01930  *    FALSE on failure
01931  *
01932  */
01933 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
01934     LPDWORD lpdwBufferLength, DWORD dwFlags)
01935 {
01936     HRESULT hr;
01937     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
01938 
01939     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
01940           lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
01941 
01942     if(dwFlags & ICU_DECODE)
01943     {
01944         dwURLFlags |= URL_UNESCAPE;
01945         dwFlags &= ~ICU_DECODE;
01946     }
01947 
01948     if(dwFlags & ICU_ESCAPE)
01949     {
01950         dwURLFlags |= URL_UNESCAPE;
01951         dwFlags &= ~ICU_ESCAPE;
01952     }
01953 
01954     if(dwFlags & ICU_BROWSER_MODE)
01955     {
01956         dwURLFlags |= URL_BROWSER_MODE;
01957         dwFlags &= ~ICU_BROWSER_MODE;
01958     }
01959 
01960     if(dwFlags & ICU_NO_ENCODE)
01961     {
01962         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
01963         dwURLFlags ^= URL_ESCAPE_UNSAFE;
01964         dwFlags &= ~ICU_NO_ENCODE;
01965     }
01966 
01967     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
01968 
01969     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
01970     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
01971     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
01972 
01973     return (hr == S_OK) ? TRUE : FALSE;
01974 }
01975 
01976 /* #################################################### */
01977 
01978 static INTERNET_STATUS_CALLBACK set_status_callback(
01979     object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
01980 {
01981     INTERNET_STATUS_CALLBACK ret;
01982 
01983     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
01984     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
01985 
01986     ret = lpwh->lpfnStatusCB;
01987     lpwh->lpfnStatusCB = callback;
01988 
01989     return ret;
01990 }
01991 
01992 /***********************************************************************
01993  *           InternetSetStatusCallbackA (WININET.@)
01994  *
01995  * Sets up a callback function which is called as progress is made
01996  * during an operation.
01997  *
01998  * RETURNS
01999  *    Previous callback or NULL     on success
02000  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
02001  *
02002  */
02003 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
02004     HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
02005 {
02006     INTERNET_STATUS_CALLBACK retVal;
02007     object_header_t *lpwh;
02008 
02009     TRACE("%p\n", hInternet);
02010 
02011     if (!(lpwh = get_handle_object(hInternet)))
02012         return INTERNET_INVALID_STATUS_CALLBACK;
02013 
02014     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
02015 
02016     WININET_Release( lpwh );
02017     return retVal;
02018 }
02019 
02020 /***********************************************************************
02021  *           InternetSetStatusCallbackW (WININET.@)
02022  *
02023  * Sets up a callback function which is called as progress is made
02024  * during an operation.
02025  *
02026  * RETURNS
02027  *    Previous callback or NULL     on success
02028  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
02029  *
02030  */
02031 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
02032     HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
02033 {
02034     INTERNET_STATUS_CALLBACK retVal;
02035     object_header_t *lpwh;
02036 
02037     TRACE("%p\n", hInternet);
02038 
02039     if (!(lpwh = get_handle_object(hInternet)))
02040         return INTERNET_INVALID_STATUS_CALLBACK;
02041 
02042     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
02043 
02044     WININET_Release( lpwh );
02045     return retVal;
02046 }
02047 
02048 /***********************************************************************
02049  *           InternetSetFilePointer (WININET.@)
02050  */
02051 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
02052     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
02053 {
02054     FIXME("stub\n");
02055     return FALSE;
02056 }
02057 
02058 /***********************************************************************
02059  *           InternetWriteFile (WININET.@)
02060  *
02061  * Write data to an open internet file
02062  *
02063  * RETURNS
02064  *    TRUE  on success
02065  *    FALSE on failure
02066  *
02067  */
02068 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
02069     DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
02070 {
02071     object_header_t *lpwh;
02072     BOOL res;
02073 
02074     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
02075 
02076     lpwh = get_handle_object( hFile );
02077     if (!lpwh) {
02078         WARN("Invalid handle\n");
02079         SetLastError(ERROR_INVALID_HANDLE);
02080         return FALSE;
02081     }
02082 
02083     if(lpwh->vtbl->WriteFile) {
02084         res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
02085     }else {
02086         WARN("No Writefile method.\n");
02087         res = ERROR_INVALID_HANDLE;
02088     }
02089 
02090     WININET_Release( lpwh );
02091 
02092     if(res != ERROR_SUCCESS)
02093         SetLastError(res);
02094     return res == ERROR_SUCCESS;
02095 }
02096 
02097 
02098 /***********************************************************************
02099  *           InternetReadFile (WININET.@)
02100  *
02101  * Read data from an open internet file
02102  *
02103  * RETURNS
02104  *    TRUE  on success
02105  *    FALSE on failure
02106  *
02107  */
02108 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
02109         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
02110 {
02111     object_header_t *hdr;
02112     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
02113 
02114     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
02115 
02116     hdr = get_handle_object(hFile);
02117     if (!hdr) {
02118         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
02119         return FALSE;
02120     }
02121 
02122     if(hdr->vtbl->ReadFile)
02123         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
02124 
02125     WININET_Release(hdr);
02126 
02127     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
02128           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
02129 
02130     if(res != ERROR_SUCCESS)
02131         SetLastError(res);
02132     return res == ERROR_SUCCESS;
02133 }
02134 
02135 /***********************************************************************
02136  *           InternetReadFileExA (WININET.@)
02137  *
02138  * Read data from an open internet file
02139  *
02140  * PARAMS
02141  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
02142  *  lpBuffersOut  [I/O] Buffer.
02143  *  dwFlags       [I] Flags. See notes.
02144  *  dwContext     [I] Context for callbacks.
02145  *
02146  * RETURNS
02147  *    TRUE  on success
02148  *    FALSE on failure
02149  *
02150  * NOTES
02151  *  The parameter dwFlags include zero or more of the following flags:
02152  *|IRF_ASYNC - Makes the call asynchronous.
02153  *|IRF_SYNC - Makes the call synchronous.
02154  *|IRF_USE_CONTEXT - Forces dwContext to be used.
02155  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
02156  *
02157  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
02158  *
02159  * SEE
02160  *  InternetOpenUrlA(), HttpOpenRequestA()
02161  */
02162 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
02163     DWORD dwFlags, DWORD_PTR dwContext)
02164 {
02165     object_header_t *hdr;
02166     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
02167 
02168     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
02169 
02170     hdr = get_handle_object(hFile);
02171     if (!hdr) {
02172         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
02173         return FALSE;
02174     }
02175 
02176     if(hdr->vtbl->ReadFileExA)
02177         res = hdr->vtbl->ReadFileExA(hdr, lpBuffersOut, dwFlags, dwContext);
02178 
02179     WININET_Release(hdr);
02180 
02181     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
02182           res, lpBuffersOut->dwBufferLength);
02183 
02184     if(res != ERROR_SUCCESS)
02185         SetLastError(res);
02186     return res == ERROR_SUCCESS;
02187 }
02188 
02189 /***********************************************************************
02190  *           InternetReadFileExW (WININET.@)
02191  * SEE
02192  *  InternetReadFileExA()
02193  */
02194 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
02195     DWORD dwFlags, DWORD_PTR dwContext)
02196 {
02197     object_header_t *hdr;
02198     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
02199 
02200     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
02201 
02202     hdr = get_handle_object(hFile);
02203     if (!hdr) {
02204         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
02205         return FALSE;
02206     }
02207 
02208     if(hdr->vtbl->ReadFileExW)
02209         res = hdr->vtbl->ReadFileExW(hdr, lpBuffer, dwFlags, dwContext);
02210 
02211     WININET_Release(hdr);
02212 
02213     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
02214           res, lpBuffer->dwBufferLength);
02215 
02216     if(res != ERROR_SUCCESS)
02217         SetLastError(res);
02218     return res == ERROR_SUCCESS;
02219 }
02220 
02221 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
02222 {
02223     static BOOL warn = TRUE;
02224 
02225     switch(option) {
02226     case INTERNET_OPTION_REQUEST_FLAGS:
02227         TRACE("INTERNET_OPTION_REQUEST_FLAGS\n");
02228 
02229         if (*size < sizeof(ULONG))
02230             return ERROR_INSUFFICIENT_BUFFER;
02231 
02232         *(ULONG*)buffer = 4;
02233         *size = sizeof(ULONG);
02234 
02235         return ERROR_SUCCESS;
02236 
02237     case INTERNET_OPTION_HTTP_VERSION:
02238         if (*size < sizeof(HTTP_VERSION_INFO))
02239             return ERROR_INSUFFICIENT_BUFFER;
02240 
02241         /*
02242          * Presently hardcoded to 1.1
02243          */
02244         ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
02245         ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
02246         *size = sizeof(HTTP_VERSION_INFO);
02247 
02248         return ERROR_SUCCESS;
02249 
02250     case INTERNET_OPTION_CONNECTED_STATE:
02251         if (warn) {
02252             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
02253             warn = FALSE;
02254         }
02255         if (*size < sizeof(ULONG))
02256             return ERROR_INSUFFICIENT_BUFFER;
02257 
02258         *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
02259         *size = sizeof(ULONG);
02260 
02261         return ERROR_SUCCESS;
02262 
02263     case INTERNET_OPTION_PROXY: {
02264         appinfo_t ai;
02265         BOOL ret;
02266 
02267         TRACE("Getting global proxy info\n");
02268         memset(&ai, 0, sizeof(appinfo_t));
02269         INTERNET_ConfigureProxy(&ai);
02270 
02271         ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
02272         APPINFO_Destroy(&ai.hdr);
02273         return ret;
02274     }
02275 
02276     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
02277         TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
02278 
02279         if (*size < sizeof(ULONG))
02280             return ERROR_INSUFFICIENT_BUFFER;
02281 
02282         *(ULONG*)buffer = 2;
02283         *size = sizeof(ULONG);
02284 
02285         return ERROR_SUCCESS;
02286 
02287     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
02288             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
02289 
02290             if (*size < sizeof(ULONG))
02291                 return ERROR_INSUFFICIENT_BUFFER;
02292 
02293             *(ULONG*)buffer = 4;
02294             *size = sizeof(ULONG);
02295 
02296             return ERROR_SUCCESS;
02297 
02298     case INTERNET_OPTION_SECURITY_FLAGS:
02299         FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
02300         return ERROR_SUCCESS;
02301 
02302     case INTERNET_OPTION_VERSION: {
02303         static const INTERNET_VERSION_INFO info = { 1, 2 };
02304 
02305         TRACE("INTERNET_OPTION_VERSION\n");
02306 
02307         if (*size < sizeof(INTERNET_VERSION_INFO))
02308             return ERROR_INSUFFICIENT_BUFFER;
02309 
02310         memcpy(buffer, &info, sizeof(info));
02311         *size = sizeof(info);
02312 
02313         return ERROR_SUCCESS;
02314     }
02315 
02316     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
02317         INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
02318         INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
02319         DWORD res = ERROR_SUCCESS, i;
02320         proxyinfo_t pi;
02321         LONG ret;
02322 
02323         TRACE("Getting global proxy info\n");
02324         if((ret = INTERNET_LoadProxySettings(&pi)))
02325             return ret;
02326 
02327         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
02328 
02329         if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
02330             FreeProxyInfo(&pi);
02331             return ERROR_INSUFFICIENT_BUFFER;
02332         }
02333 
02334         for (i = 0; i < con->dwOptionCount; i++) {
02335             INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
02336             INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
02337 
02338             switch (optionW->dwOption) {
02339             case INTERNET_PER_CONN_FLAGS:
02340                 if(pi.dwProxyEnabled)
02341                     optionW->Value.dwValue = PROXY_TYPE_PROXY;
02342                 else
02343                     optionW->Value.dwValue = PROXY_TYPE_DIRECT;
02344                 break;
02345 
02346             case INTERNET_PER_CONN_PROXY_SERVER:
02347                 if (unicode)
02348                     optionW->Value.pszValue = heap_strdupW(pi.lpszProxyServer);
02349                 else
02350                     optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer);
02351                 break;
02352 
02353             case INTERNET_PER_CONN_PROXY_BYPASS:
02354                 if (unicode)
02355                     optionW->Value.pszValue = heap_strdupW(pi.lpszProxyBypass);
02356                 else
02357                     optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass);
02358                 break;
02359 
02360             case INTERNET_PER_CONN_AUTOCONFIG_URL:
02361             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
02362             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
02363             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
02364             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
02365             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
02366                 FIXME("Unhandled dwOption %d\n", optionW->dwOption);
02367                 memset(&optionW->Value, 0, sizeof(optionW->Value));
02368                 break;
02369 
02370             default:
02371                 FIXME("Unknown dwOption %d\n", optionW->dwOption);
02372                 res = ERROR_INVALID_PARAMETER;
02373                 break;
02374             }
02375         }
02376         FreeProxyInfo(&pi);
02377 
02378         return res;
02379     }
02380     case INTERNET_OPTION_USER_AGENT:
02381         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
02382     case INTERNET_OPTION_POLICY:
02383         return ERROR_INVALID_PARAMETER;
02384     case INTERNET_OPTION_CONTEXT_VALUE:
02385     {
02386         if (!hdr)
02387             return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
02388         if (!size)
02389             return ERROR_INVALID_PARAMETER;
02390 
02391         if (*size < sizeof(DWORD_PTR))
02392         {
02393             *size = sizeof(DWORD_PTR);
02394             return ERROR_INSUFFICIENT_BUFFER;
02395         }
02396         if (!buffer)
02397             return ERROR_INVALID_PARAMETER;
02398 
02399         *(DWORD_PTR *)buffer = hdr->dwContext;
02400         *size = sizeof(DWORD_PTR);
02401         return ERROR_SUCCESS;
02402     }
02403     }
02404 
02405     FIXME("Stub for %d\n", option);
02406     return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
02407 }
02408 
02409 /***********************************************************************
02410  *           InternetQueryOptionW (WININET.@)
02411  *
02412  * Queries an options on the specified handle
02413  *
02414  * RETURNS
02415  *    TRUE  on success
02416  *    FALSE on failure
02417  *
02418  */
02419 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
02420                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
02421 {
02422     object_header_t *hdr;
02423     DWORD res = ERROR_INVALID_HANDLE;
02424 
02425     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
02426 
02427     if(hInternet) {
02428         hdr = get_handle_object(hInternet);
02429         if (hdr) {
02430             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
02431             WININET_Release(hdr);
02432         }
02433     }else {
02434         res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, TRUE);
02435     }
02436 
02437     if(res != ERROR_SUCCESS)
02438         SetLastError(res);
02439     return res == ERROR_SUCCESS;
02440 }
02441 
02442 /***********************************************************************
02443  *           InternetQueryOptionA (WININET.@)
02444  *
02445  * Queries an options on the specified handle
02446  *
02447  * RETURNS
02448  *    TRUE  on success
02449  *    FALSE on failure
02450  *
02451  */
02452 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
02453                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
02454 {
02455     object_header_t *hdr;
02456     DWORD res = ERROR_INVALID_HANDLE;
02457 
02458     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
02459 
02460     if(hInternet) {
02461         hdr = get_handle_object(hInternet);
02462         if (hdr) {
02463             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
02464             WININET_Release(hdr);
02465         }
02466     }else {
02467         res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, FALSE);
02468     }
02469 
02470     if(res != ERROR_SUCCESS)
02471         SetLastError(res);
02472     return res == ERROR_SUCCESS;
02473 }
02474 
02475 
02476 /***********************************************************************
02477  *           InternetSetOptionW (WININET.@)
02478  *
02479  * Sets an options on the specified handle
02480  *
02481  * RETURNS
02482  *    TRUE  on success
02483  *    FALSE on failure
02484  *
02485  */
02486 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
02487                            LPVOID lpBuffer, DWORD dwBufferLength)
02488 {
02489     object_header_t *lpwhh;
02490     BOOL ret = TRUE;
02491 
02492     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
02493 
02494     lpwhh = (object_header_t*) get_handle_object( hInternet );
02495     if(lpwhh && lpwhh->vtbl->SetOption) {
02496         DWORD res;
02497 
02498         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
02499         if(res != ERROR_INTERNET_INVALID_OPTION) {
02500             WININET_Release( lpwhh );
02501 
02502             if(res != ERROR_SUCCESS)
02503                 SetLastError(res);
02504 
02505             return res == ERROR_SUCCESS;
02506         }
02507     }
02508 
02509     switch (dwOption)
02510     {
02511     case INTERNET_OPTION_CALLBACK:
02512       {
02513         if (!lpwhh)
02514         {
02515             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
02516             return FALSE;
02517         }
02518         WININET_Release(lpwhh);
02519         SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
02520         return FALSE;
02521       }
02522     case INTERNET_OPTION_HTTP_VERSION:
02523       {
02524         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
02525         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
02526       }
02527       break;
02528     case INTERNET_OPTION_ERROR_MASK:
02529       {
02530         if(!lpwhh) {
02531             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
02532             return FALSE;
02533         } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
02534                         INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
02535                         INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
02536             SetLastError(ERROR_INVALID_PARAMETER);
02537             ret = FALSE;
02538         } else if(dwBufferLength != sizeof(ULONG)) {
02539             SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
02540             ret = FALSE;
02541         } else
02542             lpwhh->ErrorMask = *(ULONG*)lpBuffer;
02543       }
02544       break;
02545     case INTERNET_OPTION_CODEPAGE:
02546       {
02547         ULONG codepage = *(ULONG *)lpBuffer;
02548         FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
02549       }
02550       break;
02551     case INTERNET_OPTION_REQUEST_PRIORITY:
02552       {
02553         ULONG priority = *(ULONG *)lpBuffer;
02554         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
02555       }
02556       break;
02557     case INTERNET_OPTION_CONNECT_TIMEOUT:
02558       {
02559         ULONG connecttimeout = *(ULONG *)lpBuffer;
02560         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
02561       }
02562       break;
02563     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
02564       {
02565         ULONG receivetimeout = *(ULONG *)lpBuffer;
02566         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
02567       }
02568       break;
02569     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
02570       {
02571         ULONG conns = *(ULONG *)lpBuffer;
02572         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%d): STUB\n", conns);
02573       }
02574       break;
02575     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
02576       {
02577         ULONG conns = *(ULONG *)lpBuffer;
02578         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%d): STUB\n", conns);
02579       }
02580       break;
02581     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
02582         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
02583         break;
02584     case INTERNET_OPTION_END_BROWSER_SESSION:
02585         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
02586         break;
02587     case INTERNET_OPTION_CONNECTED_STATE:
02588         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
02589         break;
02590     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
02591     TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
02592     break;
02593     case INTERNET_OPTION_SEND_TIMEOUT:
02594     case INTERNET_OPTION_RECEIVE_TIMEOUT:
02595     case INTERNET_OPTION_DATA_SEND_TIMEOUT:
02596     {
02597         ULONG timeout = *(ULONG *)lpBuffer;
02598         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %d\n", timeout);
02599         break;
02600     }
02601     case INTERNET_OPTION_CONNECT_RETRIES:
02602     {
02603         ULONG retries = *(ULONG *)lpBuffer;
02604         FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
02605         break;
02606     }
02607     case INTERNET_OPTION_CONTEXT_VALUE:
02608     {
02609         if (!lpwhh)
02610         {
02611             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
02612             return FALSE;
02613         }
02614         if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
02615         {
02616             SetLastError(ERROR_INVALID_PARAMETER);
02617             ret = FALSE;
02618         }
02619         else
02620             lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
02621         break;
02622     }
02623     case INTERNET_OPTION_SECURITY_FLAGS:
02624      FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
02625      break;
02626     case INTERNET_OPTION_DISABLE_AUTODIAL:
02627      FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
02628      break;
02629     case INTERNET_OPTION_HTTP_DECODING:
02630         FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
02631         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02632         ret = FALSE;
02633         break;
02634     case INTERNET_OPTION_COOKIES_3RD_PARTY:
02635         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
02636         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02637         ret = FALSE;
02638         break;
02639     case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
02640         FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
02641         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02642         ret = FALSE;
02643         break;
02644     case INTERNET_OPTION_CODEPAGE_PATH:
02645         FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
02646         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02647         ret = FALSE;
02648         break;
02649     case INTERNET_OPTION_CODEPAGE_EXTRA:
02650         FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
02651         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02652         ret = FALSE;
02653         break;
02654     case INTERNET_OPTION_IDN:
02655         FIXME("INTERNET_OPTION_IDN; STUB\n");
02656         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02657         ret = FALSE;
02658         break;
02659     case INTERNET_OPTION_POLICY:
02660         SetLastError(ERROR_INVALID_PARAMETER);
02661         ret = FALSE;
02662         break;
02663     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
02664         INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
02665         LONG res;
02666         int i;
02667         proxyinfo_t pi;
02668 
02669         INTERNET_LoadProxySettings(&pi);
02670 
02671         for (i = 0; i < con->dwOptionCount; i++) {
02672             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
02673 
02674             switch (option->dwOption) {
02675             case INTERNET_PER_CONN_PROXY_SERVER:
02676                 HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer);
02677                 pi.lpszProxyServer = heap_strdupW(option->Value.pszValue);
02678                 break;
02679 
02680             case INTERNET_PER_CONN_FLAGS:
02681                 if(option->Value.dwValue & PROXY_TYPE_PROXY)
02682                     pi.dwProxyEnabled = 1;
02683                 else
02684                 {
02685                     if(option->Value.dwValue != PROXY_TYPE_DIRECT)
02686                         FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
02687                     pi.dwProxyEnabled = 0;
02688                 }
02689                 break;
02690 
02691             case INTERNET_PER_CONN_AUTOCONFIG_URL:
02692             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
02693             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
02694             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
02695             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
02696             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
02697             case INTERNET_PER_CONN_PROXY_BYPASS:
02698                 FIXME("Unhandled dwOption %d\n", option->dwOption);
02699                 break;
02700 
02701             default:
02702                 FIXME("Unknown dwOption %d\n", option->dwOption);
02703                 SetLastError(ERROR_INVALID_PARAMETER);
02704                 break;
02705             }
02706         }
02707 
02708         if ((res = INTERNET_SaveProxySettings(&pi)))
02709             SetLastError(res);
02710 
02711         FreeProxyInfo(&pi);
02712 
02713         ret = (res == ERROR_SUCCESS);
02714         break;
02715         }
02716     default:
02717         FIXME("Option %d STUB\n",dwOption);
02718         SetLastError(ERROR_INTERNET_INVALID_OPTION);
02719         ret = FALSE;
02720         break;
02721     }
02722 
02723     if(lpwhh)
02724         WININET_Release( lpwhh );
02725 
02726     return ret;
02727 }
02728 
02729 
02730 /***********************************************************************
02731  *           InternetSetOptionA (WININET.@)
02732  *
02733  * Sets an options on the specified handle.
02734  *
02735  * RETURNS
02736  *    TRUE  on success
02737  *    FALSE on failure
02738  *
02739  */
02740 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
02741                            LPVOID lpBuffer, DWORD dwBufferLength)
02742 {
02743     LPVOID wbuffer;
02744     DWORD wlen;
02745     BOOL r;
02746 
02747     switch( dwOption )
02748     {
02749     case INTERNET_OPTION_CALLBACK:
02750         {
02751         object_header_t *lpwh;
02752 
02753         if (!(lpwh = get_handle_object(hInternet)))
02754         {
02755             INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
02756             return FALSE;
02757         }
02758         WININET_Release(lpwh);
02759         INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
02760         return FALSE;
02761         }
02762     case INTERNET_OPTION_PROXY:
02763         {
02764         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
02765         LPINTERNET_PROXY_INFOW piw;
02766         DWORD proxlen, prbylen;
02767         LPWSTR prox, prby;
02768 
02769         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
02770         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
02771         wlen = sizeof(*piw) + proxlen + prbylen;
02772         wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
02773         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
02774         piw->dwAccessType = pi->dwAccessType;
02775         prox = (LPWSTR) &piw[1];
02776         prby = &prox[proxlen+1];
02777         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
02778         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
02779         piw->lpszProxy = prox;
02780         piw->lpszProxyBypass = prby;
02781         }
02782         break;
02783     case INTERNET_OPTION_USER_AGENT:
02784     case INTERNET_OPTION_USERNAME:
02785     case INTERNET_OPTION_PASSWORD:
02786         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
02787                                    NULL, 0 );
02788         wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
02789         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
02790                                    wbuffer, wlen );
02791         break;
02792     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
02793         int i;
02794         INTERNET_PER_CONN_OPTION_LISTW *listW;
02795         INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
02796         wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
02797         wbuffer = heap_alloc(wlen);
02798         listW = wbuffer;
02799 
02800         listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
02801         if (listA->pszConnection)
02802         {
02803             wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
02804             listW->pszConnection = heap_alloc(wlen*sizeof(WCHAR));
02805             MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
02806         }
02807         else
02808             listW->pszConnection = NULL;
02809         listW->dwOptionCount = listA->dwOptionCount;
02810         listW->dwOptionError = listA->dwOptionError;
02811         listW->pOptions = heap_alloc(sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount);
02812 
02813         for (i = 0; i < listA->dwOptionCount; ++i) {
02814             INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
02815             INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
02816 
02817             optW->dwOption = optA->dwOption;
02818 
02819             switch (optA->dwOption) {
02820             case INTERNET_PER_CONN_AUTOCONFIG_URL:
02821             case INTERNET_PER_CONN_PROXY_BYPASS:
02822             case INTERNET_PER_CONN_PROXY_SERVER:
02823             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
02824             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
02825                 if (optA->Value.pszValue)
02826                 {
02827                     wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
02828                     optW->Value.pszValue = heap_alloc(wlen*sizeof(WCHAR));
02829                     MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
02830                 }
02831                 else
02832                     optW->Value.pszValue = NULL;
02833                 break;
02834             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
02835             case INTERNET_PER_CONN_FLAGS:
02836             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
02837                 optW->Value.dwValue = optA->Value.dwValue;
02838                 break;
02839             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
02840                 optW->Value.ftValue = optA->Value.ftValue;
02841                 break;
02842             default:
02843                 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
02844                 optW->Value.dwValue = optA->Value.dwValue;
02845                 break;
02846             }
02847         }
02848         }
02849         break;
02850     default:
02851         wbuffer = lpBuffer;
02852         wlen = dwBufferLength;
02853     }
02854 
02855     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
02856 
02857     if( lpBuffer != wbuffer )
02858     {
02859         if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
02860         {
02861             INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
02862             int i;
02863             for (i = 0; i < list->dwOptionCount; ++i) {
02864                 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
02865                 switch (opt->dwOption) {
02866                 case INTERNET_PER_CONN_AUTOCONFIG_URL:
02867                 case INTERNET_PER_CONN_PROXY_BYPASS:
02868                 case INTERNET_PER_CONN_PROXY_SERVER:
02869                 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
02870                 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
02871                     HeapFree( GetProcessHeap(), 0, opt->Value.pszValue );
02872                     break;
02873                 default:
02874                     break;
02875                 }
02876             }
02877             HeapFree( GetProcessHeap(), 0, list->pOptions );
02878         }
02879         HeapFree( GetProcessHeap(), 0, wbuffer );
02880     }
02881 
02882     return r;
02883 }
02884 
02885 
02886 /***********************************************************************
02887  *           InternetSetOptionExA (WININET.@)
02888  */
02889 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
02890                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
02891 {
02892     FIXME("Flags %08x ignored\n", dwFlags);
02893     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
02894 }
02895 
02896 /***********************************************************************
02897  *           InternetSetOptionExW (WININET.@)
02898  */
02899 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
02900                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
02901 {
02902     FIXME("Flags %08x ignored\n", dwFlags);
02903     if( dwFlags & ~ISO_VALID_FLAGS )
02904     {
02905         SetLastError( ERROR_INVALID_PARAMETER );
02906         return FALSE;
02907     }
02908     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
02909 }
02910 
02911 static const WCHAR WININET_wkday[7][4] =
02912     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
02913       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
02914 static const WCHAR WININET_month[12][4] =
02915     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
02916       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
02917       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
02918 
02919 /***********************************************************************
02920  *           InternetTimeFromSystemTimeA (WININET.@)
02921  */
02922 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
02923 {
02924     BOOL ret;
02925     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
02926 
02927     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
02928 
02929     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
02930     {
02931         SetLastError(ERROR_INVALID_PARAMETER);
02932         return FALSE;
02933     }
02934 
02935     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
02936     {
02937         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02938         return FALSE;
02939     }
02940 
02941     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
02942     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
02943 
02944     return ret;
02945 }
02946 
02947 /***********************************************************************
02948  *           InternetTimeFromSystemTimeW (WININET.@)
02949  */
02950 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
02951 {
02952     static const WCHAR date[] =
02953         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
02954           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
02955 
02956     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
02957 
02958     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
02959     {
02960         SetLastError(ERROR_INVALID_PARAMETER);
02961         return FALSE;
02962     }
02963 
02964     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
02965     {
02966         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02967         return FALSE;
02968     }
02969 
02970     sprintfW( string, date,
02971               WININET_wkday[time->wDayOfWeek],
02972               time->wDay,
02973               WININET_month[time->wMonth - 1],
02974               time->wYear,
02975               time->wHour,
02976               time->wMinute,
02977               time->wSecond );
02978 
02979     return TRUE;
02980 }
02981 
02982 /***********************************************************************
02983  *           InternetTimeToSystemTimeA (WININET.@)
02984  */
02985 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
02986 {
02987     BOOL ret = FALSE;
02988     WCHAR *stringW;
02989 
02990     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
02991 
02992     stringW = heap_strdupAtoW(string);
02993     if (stringW)
02994     {
02995         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
02996         HeapFree( GetProcessHeap(), 0, stringW );
02997     }
02998     return ret;
02999 }
03000 
03001 /***********************************************************************
03002  *           InternetTimeToSystemTimeW (WININET.@)
03003  */
03004 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
03005 {
03006     unsigned int i;
03007     const WCHAR *s = string;
03008     WCHAR       *end;
03009 
03010     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
03011 
03012     if (!string || !time) return FALSE;
03013 
03014     /* Windows does this too */
03015     GetSystemTime( time );
03016 
03017     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
03018      *  a SYSTEMTIME structure.
03019      */
03020 
03021     while (*s && !isalphaW( *s )) s++;
03022     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
03023     time->wDayOfWeek = 7;
03024 
03025     for (i = 0; i < 7; i++)
03026     {
03027         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
03028             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
03029             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
03030         {
03031             time->wDayOfWeek = i;
03032             break;
03033         }
03034     }
03035 
03036     if (time->wDayOfWeek > 6) return TRUE;
03037     while (*s && !isdigitW( *s )) s++;
03038     time->wDay = strtolW( s, &end, 10 );
03039     s = end;
03040 
03041     while (*s && !isalphaW( *s )) s++;
03042     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
03043     time->wMonth = 0;
03044 
03045     for (i = 0; i < 12; i++)
03046     {
03047         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
03048             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
03049             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
03050         {
03051             time->wMonth = i + 1;
03052             break;
03053         }
03054     }
03055     if (time->wMonth == 0) return TRUE;
03056 
03057     while (*s && !isdigitW( *s )) s++;
03058     if (*s == '\0') return TRUE;
03059     time->wYear = strtolW( s, &end, 10 );
03060     s = end;
03061 
03062     while (*s && !isdigitW( *s )) s++;
03063     if (*s == '\0') return TRUE;
03064     time->wHour = strtolW( s, &end, 10 );
03065     s = end;
03066 
03067     while (*s && !isdigitW( *s )) s++;
03068     if (*s == '\0') return TRUE;
03069     time->wMinute = strtolW( s, &end, 10 );
03070     s = end;
03071 
03072     while (*s && !isdigitW( *s )) s++;
03073     if (*s == '\0') return TRUE;
03074     time->wSecond = strtolW( s, &end, 10 );
03075     s = end;
03076 
03077     time->wMilliseconds = 0;
03078     return TRUE;
03079 }
03080 
03081 /***********************************************************************
03082  *  InternetCheckConnectionW (WININET.@)
03083  *
03084  * Pings a requested host to check internet connection
03085  *
03086  * RETURNS
03087  *   TRUE on success and FALSE on failure. If a failure then
03088  *   ERROR_NOT_CONNECTED is placed into GetLastError
03089  *
03090  */
03091 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
03092 {
03093 /*
03094  * this is a kludge which runs the resident ping program and reads the output.
03095  *
03096  * Anyone have a better idea?
03097  */
03098 
03099   BOOL   rc = FALSE;
03100   static const CHAR ping[] = "ping -c 1 ";
03101   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
03102   CHAR *command = NULL;
03103   WCHAR hostW[1024];
03104   DWORD len;
03105   INTERNET_PORT port;
03106   int status = -1;
03107 
03108   FIXME("\n");
03109 
03110   /*
03111    * Crack or set the Address
03112    */
03113   if (lpszUrl == NULL)
03114   {
03115      /*
03116       * According to the doc we are supposed to use the ip for the next
03117       * server in the WnInet internal server database. I have
03118       * no idea what that is or how to get it.
03119       *
03120       * So someone needs to implement this.
03121       */
03122      FIXME("Unimplemented with URL of NULL\n");
03123      return TRUE;
03124   }
03125   else
03126   {
03127      URL_COMPONENTSW components;
03128 
03129      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
03130      components.lpszHostName = (LPWSTR)hostW;
03131      components.dwHostNameLength = 1024;
03132 
03133      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
03134        goto End;
03135 
03136      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
03137      port = components.nPort;
03138      TRACE("port: %d\n", port);
03139   }
03140 
03141   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
03142   {
03143       struct sockaddr_storage saddr;
03144       socklen_t sa_len = sizeof(saddr);
03145       int fd;
03146 
03147       if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
03148           goto End;
03149       fd = socket(saddr.ss_family, SOCK_STREAM, 0);
03150       if (fd != -1)
03151       {
03152           if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
03153               rc = TRUE;
03154           close(fd);
03155       }
03156   }
03157   else
03158   {
03159       /*
03160        * Build our ping command
03161        */
03162       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
03163       command = heap_alloc(strlen(ping)+len+strlen(redirect));
03164       strcpy(command,ping);
03165       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
03166       strcat(command,redirect);
03167 
03168       TRACE("Ping command is : %s\n",command);
03169 
03170       status = system(command);
03171 
03172       TRACE("Ping returned a code of %i\n",status);
03173 
03174       /* Ping return code of 0 indicates success */
03175       if (status == 0)
03176          rc = TRUE;
03177   }
03178 
03179 End:
03180 
03181   HeapFree( GetProcessHeap(), 0, command );
03182   if (rc == FALSE)
03183     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
03184 
03185   return rc;
03186 }
03187 
03188 
03189 /***********************************************************************
03190  *  InternetCheckConnectionA (WININET.@)
03191  *
03192  * Pings a requested host to check internet connection
03193  *
03194  * RETURNS
03195  *   TRUE on success and FALSE on failure. If a failure then
03196  *   ERROR_NOT_CONNECTED is placed into GetLastError
03197  *
03198  */
03199 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
03200 {
03201     WCHAR *url = NULL;
03202     BOOL rc;
03203 
03204     if(lpszUrl) {
03205         url = heap_strdupAtoW(lpszUrl);
03206         if(!url)
03207             return FALSE;
03208     }
03209 
03210     rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
03211 
03212     HeapFree(GetProcessHeap(), 0, url);
03213     return rc;
03214 }
03215 
03216 
03217 /**********************************************************
03218  *  INTERNET_InternetOpenUrlW (internal)
03219  *
03220  * Opens an URL
03221  *
03222  * RETURNS
03223  *   handle of connection or NULL on failure
03224  */
03225 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
03226     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
03227 {
03228     URL_COMPONENTSW urlComponents;
03229     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
03230     WCHAR password[1024], path[2048], extra[1024];
03231     HINTERNET client = NULL, client1 = NULL;
03232     DWORD res;
03233     
03234     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
03235       dwHeadersLength, dwFlags, dwContext);
03236     
03237     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
03238     urlComponents.lpszScheme = protocol;
03239     urlComponents.dwSchemeLength = 32;
03240     urlComponents.lpszHostName = hostName;
03241     urlComponents.dwHostNameLength = MAXHOSTNAME;
03242     urlComponents.lpszUserName = userName;
03243     urlComponents.dwUserNameLength = 1024;
03244     urlComponents.lpszPassword = password;
03245     urlComponents.dwPasswordLength = 1024;
03246     urlComponents.lpszUrlPath = path;
03247     urlComponents.dwUrlPathLength = 2048;
03248     urlComponents.lpszExtraInfo = extra;
03249     urlComponents.dwExtraInfoLength = 1024;
03250     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
03251     return NULL;
03252     switch(urlComponents.nScheme) {
03253     case INTERNET_SCHEME_FTP:
03254     if(urlComponents.nPort == 0)
03255         urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
03256     client = FTP_Connect(hIC, hostName, urlComponents.nPort,
03257                  userName, password, dwFlags, dwContext, INET_OPENURL);
03258     if(client == NULL)
03259         break;
03260     client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
03261     if(client1 == NULL) {
03262         InternetCloseHandle(client);
03263         break;
03264     }
03265     break;
03266     
03267     case INTERNET_SCHEME_HTTP:
03268     case INTERNET_SCHEME_HTTPS: {
03269     static const WCHAR szStars[] = { '*','/','*', 0 };
03270     LPCWSTR accept[2] = { szStars, NULL };
03271     if(urlComponents.nPort == 0) {
03272         if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
03273         urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
03274         else
03275         urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
03276     }
03277         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
03278 
03279         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
03280     res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
03281                            userName, password, dwFlags, dwContext, INET_OPENURL, &client);
03282         if(res != ERROR_SUCCESS) {
03283             INTERNET_SetLastError(res);
03284         break;
03285         }
03286 
03287     if (urlComponents.dwExtraInfoLength) {
03288         WCHAR *path_extra;
03289         DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
03290 
03291         if (!(path_extra = heap_alloc(len * sizeof(WCHAR))))
03292         {
03293             InternetCloseHandle(client);
03294             break;
03295         }
03296         strcpyW(path_extra, urlComponents.lpszUrlPath);
03297         strcatW(path_extra, urlComponents.lpszExtraInfo);
03298         client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
03299         HeapFree(GetProcessHeap(), 0, path_extra);
03300     }
03301     else
03302         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
03303 
03304     if(client1 == NULL) {
03305         InternetCloseHandle(client);
03306         break;
03307     }
03308     HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
03309     if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
03310             GetLastError() != ERROR_IO_PENDING) {
03311         InternetCloseHandle(client1);
03312         client1 = NULL;
03313         break;
03314     }
03315     }
03316     case INTERNET_SCHEME_GOPHER:
03317     /* gopher doesn't seem to be implemented in wine, but it's supposed
03318      * to be supported by InternetOpenUrlA. */
03319     default:
03320         SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
03321     break;
03322     }
03323 
03324     TRACE(" %p <--\n", client1);
03325     
03326     return client1;
03327 }
03328 
03329 /**********************************************************
03330  *  InternetOpenUrlW (WININET.@)
03331  *
03332  * Opens an URL
03333  *
03334  * RETURNS
03335  *   handle of connection or NULL on failure
03336  */
03337 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
03338 {
03339     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
03340     appinfo_t *hIC = (appinfo_t*) workRequest->hdr;
03341 
03342     TRACE("%p\n", hIC);
03343 
03344     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
03345                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
03346     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
03347     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
03348 }
03349 
03350 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
03351     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
03352 {
03353     HINTERNET ret = NULL;
03354     appinfo_t *hIC = NULL;
03355 
03356     if (TRACE_ON(wininet)) {
03357     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
03358           dwHeadersLength, dwFlags, dwContext);
03359     TRACE("  flags :");
03360     dump_INTERNET_FLAGS(dwFlags);
03361     }
03362 
03363     if (!lpszUrl)
03364     {
03365         SetLastError(ERROR_INVALID_PARAMETER);
03366         goto lend;
03367     }
03368 
03369     hIC = (appinfo_t*)get_handle_object( hInternet );
03370     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
03371     SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
03372     goto lend;
03373     }
03374     
03375     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
03376     WORKREQUEST workRequest;
03377     struct WORKREQ_INTERNETOPENURLW *req;
03378 
03379     workRequest.asyncproc = AsyncInternetOpenUrlProc;
03380     workRequest.hdr = WININET_AddRef( &hIC->hdr );
03381         req = &workRequest.u.InternetOpenUrlW;
03382         req->lpszUrl = heap_strdupW(lpszUrl);
03383         req->lpszHeaders = heap_strdupW(lpszHeaders);
03384     req->dwHeadersLength = dwHeadersLength;
03385     req->dwFlags = dwFlags;
03386     req->dwContext = dwContext;
03387     
03388     INTERNET_AsyncCall(&workRequest);
03389     /*
03390      * This is from windows.
03391      */
03392     SetLastError(ERROR_IO_PENDING);
03393     } else {
03394     ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
03395     }
03396     
03397   lend:
03398     if( hIC )
03399         WININET_Release( &hIC->hdr );
03400     TRACE(" %p <--\n", ret);
03401     
03402     return ret;
03403 }
03404 
03405 /**********************************************************
03406  *  InternetOpenUrlA (WININET.@)
03407  *
03408  * Opens an URL
03409  *
03410  * RETURNS
03411  *   handle of connection or NULL on failure
03412  */
03413 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
03414     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
03415 {
03416     HINTERNET rc = NULL;
03417     DWORD lenHeaders = 0;
03418     LPWSTR szUrl = NULL;
03419     LPWSTR szHeaders = NULL;
03420 
03421     TRACE("\n");
03422 
03423     if(lpszUrl) {
03424         szUrl = heap_strdupAtoW(lpszUrl);
03425         if(!szUrl)
03426             return NULL;
03427     }
03428 
03429     if(lpszHeaders) {
03430         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
03431         szHeaders = heap_alloc(lenHeaders*sizeof(WCHAR));
03432         if(!szHeaders) {
03433             HeapFree(GetProcessHeap(), 0, szUrl);
03434             return NULL;
03435         }
03436         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
03437     }
03438     
03439     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
03440         lenHeaders, dwFlags, dwContext);
03441 
03442     HeapFree(GetProcessHeap(), 0, szUrl);
03443     HeapFree(GetProcessHeap(), 0, szHeaders);
03444 
03445     return rc;
03446 }
03447 
03448 
03449 static LPWITHREADERROR INTERNET_AllocThreadError(void)
03450 {
03451     LPWITHREADERROR lpwite = heap_alloc(sizeof(*lpwite));
03452 
03453     if (lpwite)
03454     {
03455         lpwite->dwError = 0;
03456         lpwite->response[0] = '\0';
03457     }
03458 
03459     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
03460     {
03461         HeapFree(GetProcessHeap(), 0, lpwite);
03462         return NULL;
03463     }
03464 
03465     return lpwite;
03466 }
03467 
03468 
03469 /***********************************************************************
03470  *           INTERNET_SetLastError (internal)
03471  *
03472  * Set last thread specific error
03473  *
03474  * RETURNS
03475  *
03476  */
03477 void INTERNET_SetLastError(DWORD dwError)
03478 {
03479     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
03480 
03481     if (!lpwite)
03482         lpwite = INTERNET_AllocThreadError();
03483 
03484     SetLastError(dwError);
03485     if(lpwite)
03486         lpwite->dwError = dwError;
03487 }
03488 
03489 
03490 /***********************************************************************
03491  *           INTERNET_GetLastError (internal)
03492  *
03493  * Get last thread specific error
03494  *
03495  * RETURNS
03496  *
03497  */
03498 DWORD INTERNET_GetLastError(void)
03499 {
03500     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
03501     if (!lpwite) return 0;
03502     /* TlsGetValue clears last error, so set it again here */
03503     SetLastError(lpwite->dwError);
03504     return lpwite->dwError;
03505 }
03506 
03507 
03508 /***********************************************************************
03509  *           INTERNET_WorkerThreadFunc (internal)
03510  *
03511  * Worker thread execution function
03512  *
03513  * RETURNS
03514  *
03515  */
03516 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
03517 {
03518     LPWORKREQUEST lpRequest = lpvParam;
03519     WORKREQUEST workRequest;
03520 
03521     TRACE("\n");
03522 
03523     workRequest = *lpRequest;
03524     HeapFree(GetProcessHeap(), 0, lpRequest);
03525 
03526     workRequest.asyncproc(&workRequest);
03527     WININET_Release( workRequest.hdr );
03528 
03529     if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
03530     {
03531         HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
03532         TlsSetValue(g_dwTlsErrIndex, NULL);
03533     }
03534     return TRUE;
03535 }
03536 
03537 
03538 /***********************************************************************
03539  *           INTERNET_AsyncCall (internal)
03540  *
03541  * Retrieves work request from queue
03542  *
03543  * RETURNS
03544  *
03545  */
03546 DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
03547 {
03548     BOOL bSuccess;
03549     LPWORKREQUEST lpNewRequest;
03550 
03551     TRACE("\n");
03552 
03553     lpNewRequest = heap_alloc(sizeof(WORKREQUEST));
03554     if (!lpNewRequest)
03555         return ERROR_OUTOFMEMORY;
03556 
03557     *lpNewRequest = *lpWorkRequest;
03558 
03559     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
03560     if (!bSuccess)
03561     {
03562         HeapFree(GetProcessHeap(), 0, lpNewRequest);
03563         return ERROR_INTERNET_ASYNC_THREAD_FAILED;
03564     }
03565 
03566     return ERROR_SUCCESS;
03567 }
03568 
03569 
03570 /***********************************************************************
03571  *          INTERNET_GetResponseBuffer  (internal)
03572  *
03573  * RETURNS
03574  *
03575  */
03576 LPSTR INTERNET_GetResponseBuffer(void)
03577 {
03578     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
03579     if (!lpwite)
03580         lpwite = INTERNET_AllocThreadError();
03581     TRACE("\n");
03582     return lpwite->response;
03583 }
03584 
03585 /***********************************************************************
03586  *           INTERNET_GetNextLine  (internal)
03587  *
03588  * Parse next line in directory string listing
03589  *
03590  * RETURNS
03591  *   Pointer to beginning of next line
03592  *   NULL on failure
03593  *
03594  */
03595 
03596 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
03597 {
03598     fd_set infd;
03599     struct timeval tv;
03600     BOOL bSuccess = FALSE;
03601     INT nRecv = 0;
03602     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
03603 
03604     TRACE("\n");
03605 
03606     FD_ZERO(&infd);
03607     FD_SET(nSocket,&infd);
03608     tv.tv_sec = RESPONSE_TIMEOUT;
03609     tv.tv_usec = 0;
03610 
03611     while (nRecv < MAX_REPLY_LEN)
03612     {
03613         if (select(0, &infd, NULL, NULL, &tv) > 0)
03614         {
03615             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
03616             {
03617                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
03618                 goto lend;
03619             }
03620 
03621             if (lpszBuffer[nRecv] == '\n')
03622         {
03623         bSuccess = TRUE;
03624                 break;
03625         }
03626             if (lpszBuffer[nRecv] != '\r')
03627                 nRecv++;
03628         }
03629     else
03630     {
03631             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
03632             goto lend;
03633         }
03634     }
03635 
03636 lend:
03637     if (bSuccess)
03638     {
03639         lpszBuffer[nRecv] = '\0';
03640     *dwLen = nRecv - 1;
03641         TRACE(":%d %s\n", nRecv, lpszBuffer);
03642         return lpszBuffer;
03643     }
03644     else
03645     {
03646         return NULL;
03647     }
03648 }
03649 
03650 /**********************************************************
03651  *  InternetQueryDataAvailable (WININET.@)
03652  *
03653  * Determines how much data is available to be read.
03654  *
03655  * RETURNS
03656  *   TRUE on success, FALSE if an error occurred. If
03657  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
03658  *   no data is presently available, FALSE is returned with
03659  *   the last error ERROR_IO_PENDING; a callback with status
03660  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
03661  *   data is available.
03662  */
03663 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
03664                                 LPDWORD lpdwNumberOfBytesAvailble,
03665                                 DWORD dwFlags, DWORD_PTR dwContext)
03666 {
03667     object_header_t *hdr;
03668     DWORD res;
03669 
03670     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
03671 
03672     hdr = get_handle_object( hFile );
03673     if (!hdr) {
03674         SetLastError(ERROR_INVALID_HANDLE);
03675         return FALSE;
03676     }
03677 
03678     if(hdr->vtbl->QueryDataAvailable) {
03679         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
03680     }else {
03681         WARN("wrong handle\n");
03682         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
03683     }
03684 
03685     WININET_Release(hdr);
03686 
03687     if(res != ERROR_SUCCESS)
03688         SetLastError(res);
03689     return res == ERROR_SUCCESS;
03690 }
03691 
03692 
03693 /***********************************************************************
03694  *      InternetLockRequestFile (WININET.@)
03695  */
03696 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
03697 *lphLockReqHandle)
03698 {
03699     FIXME("STUB\n");
03700     return FALSE;
03701 }
03702 
03703 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
03704 {
03705     FIXME("STUB\n");
03706     return FALSE;
03707 }
03708 
03709 
03710 /***********************************************************************
03711  *      InternetAutodial (WININET.@)
03712  *
03713  * On windows this function is supposed to dial the default internet
03714  * connection. We don't want to have Wine dial out to the internet so
03715  * we return TRUE by default. It might be nice to check if we are connected.
03716  *
03717  * RETURNS
03718  *   TRUE on success
03719  *   FALSE on failure
03720  *
03721  */
03722 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
03723 {
03724     FIXME("STUB\n");
03725 
03726     /* Tell that we are connected to the internet. */
03727     return TRUE;
03728 }
03729 
03730 /***********************************************************************
03731  *      InternetAutodialHangup (WININET.@)
03732  *
03733  * Hangs up a connection made with InternetAutodial
03734  *
03735  * PARAM
03736  *    dwReserved
03737  * RETURNS
03738  *   TRUE on success
03739  *   FALSE on failure
03740  *
03741  */
03742 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
03743 {
03744     FIXME("STUB\n");
03745 
03746     /* we didn't dial, we don't disconnect */
03747     return TRUE;
03748 }
03749 
03750 /***********************************************************************
03751  *      InternetCombineUrlA (WININET.@)
03752  *
03753  * Combine a base URL with a relative URL
03754  *
03755  * RETURNS
03756  *   TRUE on success
03757  *   FALSE on failure
03758  *
03759  */
03760 
03761 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
03762                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
03763                                 DWORD dwFlags)
03764 {
03765     HRESULT hr=S_OK;
03766 
03767     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
03768 
03769     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
03770     dwFlags ^= ICU_NO_ENCODE;
03771     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
03772 
03773     return (hr==S_OK);
03774 }
03775 
03776 /***********************************************************************
03777  *      InternetCombineUrlW (WININET.@)
03778  *
03779  * Combine a base URL with a relative URL
03780  *
03781  * RETURNS
03782  *   TRUE on success
03783  *   FALSE on failure
03784  *
03785  */
03786 
03787 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
03788                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
03789                                 DWORD dwFlags)
03790 {
03791     HRESULT hr=S_OK;
03792 
03793     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
03794 
03795     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
03796     dwFlags ^= ICU_NO_ENCODE;
03797     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
03798 
03799     return (hr==S_OK);
03800 }
03801 
03802 /* max port num is 65535 => 5 digits */
03803 #define MAX_WORD_DIGITS 5
03804 
03805 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
03806     (url)->dw##component##Length : strlenW((url)->lpsz##component))
03807 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
03808     (url)->dw##component##Length : strlen((url)->lpsz##component))
03809 
03810 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
03811 {
03812     if ((nScheme == INTERNET_SCHEME_HTTP) &&
03813         (nPort == INTERNET_DEFAULT_HTTP_PORT))
03814         return TRUE;
03815     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
03816         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
03817         return TRUE;
03818     if ((nScheme == INTERNET_SCHEME_FTP) &&
03819         (nPort == INTERNET_DEFAULT_FTP_PORT))
03820         return TRUE;
03821     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
03822         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
03823         return TRUE;
03824 
03825     if (nPort == INTERNET_INVALID_PORT_NUMBER)
03826         return TRUE;
03827 
03828     return FALSE;
03829 }
03830 
03831 /* opaque urls do not fit into the standard url hierarchy and don't have
03832  * two following slashes */
03833 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
03834 {
03835     return (nScheme != INTERNET_SCHEME_FTP) &&
03836            (nScheme != INTERNET_SCHEME_GOPHER) &&
03837            (nScheme != INTERNET_SCHEME_HTTP) &&
03838            (nScheme != INTERNET_SCHEME_HTTPS) &&
03839            (nScheme != INTERNET_SCHEME_FILE);
03840 }
03841 
03842 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
03843 {
03844     int index;
03845     if (scheme < INTERNET_SCHEME_FIRST)
03846         return NULL;
03847     index = scheme - INTERNET_SCHEME_FIRST;
03848     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
03849         return NULL;
03850     return (LPCWSTR)url_schemes[index];
03851 }
03852 
03853 /* we can calculate using ansi strings because we're just
03854  * calculating string length, not size
03855  */
03856 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
03857                             LPDWORD lpdwUrlLength)
03858 {
03859     INTERNET_SCHEME nScheme;
03860 
03861     *lpdwUrlLength = 0;
03862 
03863     if (lpUrlComponents->lpszScheme)
03864     {
03865         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
03866         *lpdwUrlLength += dwLen;
03867         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
03868     }
03869     else
03870     {
03871         LPCWSTR scheme;
03872 
03873         nScheme = lpUrlComponents->nScheme;
03874 
03875         if (nScheme == INTERNET_SCHEME_DEFAULT)
03876             nScheme = INTERNET_SCHEME_HTTP;
03877         scheme = INTERNET_GetSchemeString(nScheme);
03878         *lpdwUrlLength += strlenW(scheme);
03879     }
03880 
03881     (*lpdwUrlLength)++; /* ':' */
03882     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
03883         *lpdwUrlLength += strlen("//");
03884 
03885     if (lpUrlComponents->lpszUserName)
03886     {
03887         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
03888         *lpdwUrlLength += strlen("@");
03889     }
03890     else
03891     {
03892         if (lpUrlComponents->lpszPassword)
03893         {
03894             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
03895             return FALSE;
03896         }
03897     }
03898 
03899     if (lpUrlComponents->lpszPassword)
03900     {
03901         *lpdwUrlLength += strlen(":");
03902         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
03903     }
03904 
03905     if (lpUrlComponents->lpszHostName)
03906     {
03907         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
03908 
03909         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
03910         {
03911             char szPort[MAX_WORD_DIGITS+1];
03912 
03913             sprintf(szPort, "%d", lpUrlComponents->nPort);
03914             *lpdwUrlLength += strlen(szPort);
03915             *lpdwUrlLength += strlen(":");
03916         }
03917 
03918         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
03919             (*lpdwUrlLength)++; /* '/' */
03920     }
03921 
03922     if (lpUrlComponents->lpszUrlPath)
03923         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
03924 
03925     if (lpUrlComponents->lpszExtraInfo)
03926         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
03927 
03928     return TRUE;
03929 }
03930 
03931 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
03932 {
03933     INT len;
03934 
03935     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
03936 
03937     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
03938     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
03939     urlCompW->nScheme = lpUrlComponents->nScheme;
03940     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
03941     urlCompW->nPort = lpUrlComponents->nPort;
03942     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
03943     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
03944     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
03945     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
03946 
03947     if (lpUrlComponents->lpszScheme)
03948     {
03949         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
03950         urlCompW->lpszScheme = heap_alloc(len * sizeof(WCHAR));
03951         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
03952                             -1, urlCompW->lpszScheme, len);
03953     }
03954 
03955     if (lpUrlComponents->lpszHostName)
03956     {
03957         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
03958         urlCompW->lpszHostName = heap_alloc(len * sizeof(WCHAR));
03959         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
03960                             -1, urlCompW->lpszHostName, len);
03961     }
03962 
03963     if (lpUrlComponents->lpszUserName)
03964     {
03965         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
03966         urlCompW->lpszUserName = heap_alloc(len * sizeof(WCHAR));
03967         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
03968                             -1, urlCompW->lpszUserName, len);
03969     }
03970 
03971     if (lpUrlComponents->lpszPassword)
03972     {
03973         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
03974         urlCompW->lpszPassword = heap_alloc(len * sizeof(WCHAR));
03975         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
03976                             -1, urlCompW->lpszPassword, len);
03977     }
03978 
03979     if (lpUrlComponents->lpszUrlPath)
03980     {
03981         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
03982         urlCompW->lpszUrlPath = heap_alloc(len * sizeof(WCHAR));
03983         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
03984                             -1, urlCompW->lpszUrlPath, len);
03985     }
03986 
03987     if (lpUrlComponents->lpszExtraInfo)
03988     {
03989         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
03990         urlCompW->lpszExtraInfo = heap_alloc(len * sizeof(WCHAR));
03991         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
03992                             -1, urlCompW->lpszExtraInfo, len);
03993     }
03994 }
03995 
03996 /***********************************************************************
03997  *      InternetCreateUrlA (WININET.@)
03998  *
03999  * See InternetCreateUrlW.
04000  */
04001 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
04002                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
04003 {
04004     BOOL ret;
04005     LPWSTR urlW = NULL;
04006     URL_COMPONENTSW urlCompW;
04007 
04008     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
04009 
04010     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
04011     {
04012         SetLastError(ERROR_INVALID_PARAMETER);
04013         return FALSE;
04014     }
04015 
04016     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
04017 
04018     if (lpszUrl)
04019         urlW = heap_alloc(*lpdwUrlLength * sizeof(WCHAR));
04020 
04021     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
04022 
04023     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
04024         *lpdwUrlLength /= sizeof(WCHAR);
04025 
04026     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
04027     * minus one, so add one to leave room for NULL terminator
04028     */
04029     if (ret)
04030         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
04031 
04032     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
04033     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
04034     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
04035     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
04036     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
04037     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
04038     HeapFree(GetProcessHeap(), 0, urlW);
04039 
04040     return ret;
04041 }
04042 
04043 /***********************************************************************
04044  *      InternetCreateUrlW (WININET.@)
04045  *
04046  * Creates a URL from its component parts.
04047  *
04048  * PARAMS
04049  *  lpUrlComponents [I] URL Components.
04050  *  dwFlags         [I] Flags. See notes.
04051  *  lpszUrl         [I] Buffer in which to store the created URL.
04052  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
04053  *                        lpszUrl in characters. On output, the number of bytes
04054  *                        required to store the URL including terminator.
04055  *
04056  * NOTES
04057  *
04058  * The dwFlags parameter can be zero or more of the following:
04059  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
04060  *
04061  * RETURNS
04062  *   TRUE on success
04063  *   FALSE on failure
04064  *
04065  */
04066 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
04067                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
04068 {
04069     DWORD dwLen;
04070     INTERNET_SCHEME nScheme;
04071 
04072     static const WCHAR slashSlashW[] = {'/','/'};
04073     static const WCHAR fmtW[] = {'%','u',0};
04074 
04075     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
04076 
04077     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
04078     {
04079         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
04080         return FALSE;
04081     }
04082 
04083     if (!calc_url_length(lpUrlComponents, &dwLen))
04084         return FALSE;
04085 
04086     if (!lpszUrl || *lpdwUrlLength < dwLen)
04087     {
04088         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
04089         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
04090         return FALSE;
04091     }
04092 
04093     *lpdwUrlLength = dwLen;
04094     lpszUrl[0] = 0x00;
04095 
04096     dwLen = 0;
04097 
04098     if (lpUrlComponents->lpszScheme)
04099     {
04100         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
04101         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
04102         lpszUrl += dwLen;
04103 
04104         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
04105     }
04106     else
04107     {
04108         LPCWSTR scheme;
04109         nScheme = lpUrlComponents->nScheme;
04110 
04111         if (nScheme == INTERNET_SCHEME_DEFAULT)
04112             nScheme = INTERNET_SCHEME_HTTP;
04113 
04114         scheme = INTERNET_GetSchemeString(nScheme);
04115         dwLen = strlenW(scheme);
04116         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
04117         lpszUrl += dwLen;
04118     }
04119 
04120     /* all schemes are followed by at least a colon */
04121     *lpszUrl = ':';
04122     lpszUrl++;
04123 
04124     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
04125     {
04126         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
04127         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
04128     }
04129 
04130     if (lpUrlComponents->lpszUserName)
04131     {
04132         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
04133         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
04134         lpszUrl += dwLen;
04135 
04136         if (lpUrlComponents->lpszPassword)
04137         {
04138             *lpszUrl = ':';
04139             lpszUrl++;
04140 
04141             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
04142             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
04143             lpszUrl += dwLen;
04144         }
04145 
04146         *lpszUrl = '@';
04147         lpszUrl++;
04148     }
04149 
04150     if (lpUrlComponents->lpszHostName)
04151     {
04152         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
04153         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
04154         lpszUrl += dwLen;
04155 
04156         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
04157         {
04158             WCHAR szPort[MAX_WORD_DIGITS+1];
04159 
04160             sprintfW(szPort, fmtW, lpUrlComponents->nPort);
04161             *lpszUrl = ':';
04162             lpszUrl++;
04163             dwLen = strlenW(szPort);
04164             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
04165             lpszUrl += dwLen;
04166         }
04167 
04168         /* add slash between hostname and path if necessary */
04169         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
04170         {
04171             *lpszUrl = '/';
04172             lpszUrl++;
04173         }
04174     }
04175 
04176     if (lpUrlComponents->lpszUrlPath)
04177     {
04178         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
04179         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
04180         lpszUrl += dwLen;
04181     }
04182 
04183     if (lpUrlComponents->lpszExtraInfo)
04184     {
04185         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
04186         memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
04187         lpszUrl += dwLen;
04188     }
04189 
04190     *lpszUrl = '\0';
04191 
04192     return TRUE;
04193 }
04194 
04195 /***********************************************************************
04196  *      InternetConfirmZoneCrossingA (WININET.@)
04197  *
04198  */
04199 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
04200 {
04201     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
04202     return ERROR_SUCCESS;
04203 }
04204 
04205 /***********************************************************************
04206  *      InternetConfirmZoneCrossingW (WININET.@)
04207  *
04208  */
04209 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
04210 {
04211     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
04212     return ERROR_SUCCESS;
04213 }
04214 
04215 static DWORD zone_preference = 3;
04216 
04217 /***********************************************************************
04218  *      PrivacySetZonePreferenceW (WININET.@)
04219  */
04220 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
04221 {
04222     FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
04223 
04224     zone_preference = template;
04225     return 0;
04226 }
04227 
04228 /***********************************************************************
04229  *      PrivacyGetZonePreferenceW (WININET.@)
04230  */
04231 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
04232                                         LPWSTR preference, LPDWORD length )
04233 {
04234     FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
04235 
04236     if (template) *template = zone_preference;
04237     return 0;
04238 }
04239 
04240 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
04241                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
04242 {
04243     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
04244           lpdwConnection, dwReserved);
04245     return ERROR_SUCCESS;
04246 }
04247 
04248 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
04249                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
04250 {
04251     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
04252           lpdwConnection, dwReserved);
04253     return ERROR_SUCCESS;
04254 }
04255 
04256 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
04257 {
04258     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
04259     return TRUE;
04260 }
04261 
04262 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
04263 {
04264     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
04265     return TRUE;
04266 }
04267 
04268 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
04269 {
04270     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
04271     return ERROR_SUCCESS;
04272 }
04273 
04274 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
04275                               PBYTE pbHexHash )
04276 {
04277     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
04278           debugstr_w(pwszTarget), pbHexHash);
04279     return FALSE;
04280 }
04281 
04282 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
04283 {
04284     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
04285     return FALSE;
04286 }
04287 
04288 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
04289 {
04290     FIXME("(%p, %08lx) stub\n", a, b);
04291     return 0;
04292 }

Generated on Fri May 25 2012 04:24:47 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.