Added support for implementing VxDs as separate dlls and loading them
[wine.git] / dlls / wininet / internet.c
blob76715a78a4a927fbffdee48bbb1582b3651214ee
1 /*
2 * Wininet
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 Jaco Greeff
7 * Copyright 2002 TransGaming Technologies Inc.
8 * Copyright 2004 Mike McCormack for CodeWeavers
10 * Ulrich Czekalla
11 * Aric Stewart
12 * David Hammerton
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "config.h"
30 #include "wine/port.h"
32 #define MAXHOSTNAME 100 /* from http.c */
34 #include <string.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
43 #endif
44 #include <stdlib.h>
45 #include <ctype.h>
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
50 #include "ntstatus.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winreg.h"
54 #include "wininet.h"
55 #include "winnls.h"
56 #include "wine/debug.h"
57 #include "winerror.h"
58 #define NO_SHLWAPI_STREAM
59 #include "shlwapi.h"
61 #include "wine/exception.h"
62 #include "excpt.h"
64 #include "internet.h"
66 #include "wine/unicode.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
70 #define MAX_IDLE_WORKER 1000*60*1
71 #define MAX_WORKER_THREADS 10
72 #define RESPONSE_TIMEOUT 30
74 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
75 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
78 typedef struct
80 DWORD dwError;
81 CHAR response[MAX_REPLY_LEN];
82 } WITHREADERROR, *LPWITHREADERROR;
84 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
85 HINTERNET WINAPI INTERNET_InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
86 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext);
87 VOID INTERNET_ExecuteWork();
89 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
90 DWORD dwNumThreads;
91 DWORD dwNumIdleThreads;
92 DWORD dwNumJobs;
93 HANDLE hEventArray[2];
94 #define hQuitEvent hEventArray[0]
95 #define hWorkEvent hEventArray[1]
96 CRITICAL_SECTION csQueue;
97 LPWORKREQUEST lpHeadWorkQueue;
98 LPWORKREQUEST lpWorkQueueTail;
100 extern void URLCacheContainers_CreateDefaults();
101 extern void URLCacheContainers_DeleteAll();
103 #define HANDLE_CHUNK_SIZE 0x10
105 static CRITICAL_SECTION WININET_cs;
106 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
108 0, 0, &WININET_cs,
109 { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
110 0, 0, { 0, (DWORD)(__FILE__ ": WININET_cs") }
112 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
114 static LPWININETHANDLEHEADER *WININET_Handles;
115 static UINT WININET_dwNextHandle;
116 static UINT WININET_dwMaxHandles;
118 HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info )
120 LPWININETHANDLEHEADER *p;
121 UINT handle = 0, num;
123 EnterCriticalSection( &WININET_cs );
124 if( !WININET_dwMaxHandles )
126 num = HANDLE_CHUNK_SIZE;
127 p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
128 sizeof (UINT)* num);
129 if( !p )
130 goto end;
131 WININET_Handles = p;
132 WININET_dwMaxHandles = num;
134 if( WININET_dwMaxHandles == WININET_dwNextHandle )
136 num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
137 p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
138 WININET_Handles, sizeof (UINT)* num);
139 if( !p )
140 goto end;
141 WININET_Handles = p;
142 WININET_dwMaxHandles = num;
145 handle = WININET_dwNextHandle;
146 if( WININET_Handles[handle] )
147 ERR("handle isn't free but should be\n");
148 WININET_Handles[handle] = info;
150 while( WININET_Handles[WININET_dwNextHandle] &&
151 (WININET_dwNextHandle < WININET_dwMaxHandles ) )
152 WININET_dwNextHandle++;
154 end:
155 LeaveCriticalSection( &WININET_cs );
157 return (HINTERNET) (handle+1);
160 HINTERNET WININET_FindHandle( LPWININETHANDLEHEADER info )
162 UINT i, handle = 0;
164 EnterCriticalSection( &WININET_cs );
165 for( i=0; i<WININET_dwMaxHandles; i++ )
167 if( info == WININET_Handles[i] )
169 handle = i+1;
170 break;
173 LeaveCriticalSection( &WININET_cs );
175 return (HINTERNET) handle;
178 LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet )
180 LPWININETHANDLEHEADER info = NULL;
181 UINT handle = (UINT) hinternet;
183 EnterCriticalSection( &WININET_cs );
185 if( (handle > 0) && ( handle <= WININET_dwNextHandle ) )
186 info = WININET_Handles[handle-1];
188 LeaveCriticalSection( &WININET_cs );
190 TRACE("handle %d -> %p\n", handle, info);
192 return info;
195 BOOL WININET_FreeHandle( HINTERNET hinternet )
197 BOOL ret = FALSE;
198 UINT handle = (UINT) hinternet;
200 EnterCriticalSection( &WININET_cs );
202 if( (handle > 1) && ( handle < WININET_dwNextHandle ) )
204 handle--;
205 if( WININET_Handles[handle] )
207 WININET_Handles[handle] = NULL;
208 ret = TRUE;
209 if( WININET_dwNextHandle > handle )
210 WININET_dwNextHandle = handle;
214 LeaveCriticalSection( &WININET_cs );
216 return ret;
219 /***********************************************************************
220 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
222 * PARAMS
223 * hinstDLL [I] handle to the DLL's instance
224 * fdwReason [I]
225 * lpvReserved [I] reserved, must be NULL
227 * RETURNS
228 * Success: TRUE
229 * Failure: FALSE
232 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
234 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
236 switch (fdwReason) {
237 case DLL_PROCESS_ATTACH:
239 g_dwTlsErrIndex = TlsAlloc();
241 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
242 return FALSE;
244 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
245 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
246 InitializeCriticalSection(&csQueue);
248 URLCacheContainers_CreateDefaults();
250 dwNumThreads = 0;
251 dwNumIdleThreads = 0;
252 dwNumJobs = 0;
254 case DLL_THREAD_ATTACH:
256 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
257 if (NULL == lpwite)
258 return FALSE;
260 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
262 break;
264 case DLL_THREAD_DETACH:
265 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
267 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
268 if (lpwite)
269 HeapFree(GetProcessHeap(), 0, lpwite);
271 break;
273 case DLL_PROCESS_DETACH:
275 URLCacheContainers_DeleteAll();
277 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
279 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
280 TlsFree(g_dwTlsErrIndex);
283 SetEvent(hQuitEvent);
285 CloseHandle(hQuitEvent);
286 CloseHandle(hWorkEvent);
287 DeleteCriticalSection(&csQueue);
288 break;
291 return TRUE;
295 /***********************************************************************
296 * InternetInitializeAutoProxyDll (WININET.@)
298 * Setup the internal proxy
300 * PARAMETERS
301 * dwReserved
303 * RETURNS
304 * FALSE on failure
307 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
309 FIXME("STUB\n");
310 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
311 return FALSE;
314 /***********************************************************************
315 * DetectAutoProxyUrl (WININET.@)
317 * Auto detect the proxy url
319 * RETURNS
320 * FALSE on failure
323 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
324 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
326 FIXME("STUB\n");
327 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
328 return FALSE;
332 /***********************************************************************
333 * INTERNET_ConfigureProxyFromReg
335 * FIXME:
336 * The proxy may be specified in the form 'http=proxy.my.org'
337 * Presumably that means there can be ftp=ftpproxy.my.org too.
339 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOA lpwai )
341 HKEY key;
342 DWORD r, keytype, len, enabled;
343 LPSTR lpszInternetSettings =
344 "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
346 r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
347 if ( r != ERROR_SUCCESS )
348 return FALSE;
350 len = sizeof enabled;
351 r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
352 (BYTE*)&enabled, &len);
353 if( (r == ERROR_SUCCESS) && enabled )
355 TRACE("Proxy is enabled.\n");
357 /* figure out how much memory the proxy setting takes */
358 r = RegQueryValueExA( key, "ProxyServer", NULL, &keytype,
359 NULL, &len);
360 if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
362 LPSTR szProxy, p, szHttp = "http=";
364 szProxy=HeapAlloc( GetProcessHeap(), 0, len+1 );
365 RegQueryValueExA( key, "ProxyServer", NULL, &keytype,
366 (BYTE*)szProxy, &len);
368 /* find the http proxy, and strip away everything else */
369 p = strstr( szProxy, szHttp );
370 if( p )
372 p += strlen(szHttp);
373 strcpy( szProxy, p );
375 p = strchr( szProxy, ' ' );
376 if( p )
377 *p = 0;
379 lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
380 lpwai->lpszProxy = szProxy;
382 TRACE("http proxy = %s\n", lpwai->lpszProxy);
384 else
385 ERR("Couldn't read proxy server settings.\n");
387 else
388 TRACE("Proxy is not enabled.\n");
389 RegCloseKey(key);
391 return enabled;
394 /***********************************************************************
395 * InternetOpenA (WININET.@)
397 * Per-application initialization of wininet
399 * RETURNS
400 * HINTERNET on success
401 * NULL on failure
404 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
405 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
407 LPWININETAPPINFOA lpwai = NULL;
408 HINTERNET handle = NULL;
410 if (TRACE_ON(wininet)) {
411 #define FE(x) { x, #x }
412 static const wininet_flag_info access_type[] = {
413 FE(INTERNET_OPEN_TYPE_PRECONFIG),
414 FE(INTERNET_OPEN_TYPE_DIRECT),
415 FE(INTERNET_OPEN_TYPE_PROXY),
416 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
418 static const wininet_flag_info flag[] = {
419 FE(INTERNET_FLAG_ASYNC),
420 FE(INTERNET_FLAG_FROM_CACHE),
421 FE(INTERNET_FLAG_OFFLINE)
423 #undef FE
424 int i;
425 const char *access_type_str = "Unknown";
426 DWORD flag_val = dwFlags;
428 TRACE("(%s, %li, %s, %s, %li)\n", debugstr_a(lpszAgent), dwAccessType,
429 debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
430 for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
431 if (access_type[i].val == dwAccessType) {
432 access_type_str = access_type[i].name;
433 break;
436 TRACE(" access type : %s\n", access_type_str);
437 TRACE(" flags :");
438 for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
439 if (flag[i].val & flag_val) {
440 DPRINTF(" %s", flag[i].name);
441 flag_val &= ~flag[i].val;
444 if (flag_val) DPRINTF(" Unknown flags (%08lx)", flag_val);
445 DPRINTF("\n");
448 /* Clear any error information */
449 INTERNET_SetLastError(0);
451 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
452 if (NULL == lpwai)
454 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
455 goto lend;
458 memset(lpwai, 0, sizeof(WININETAPPINFOA));
459 lpwai->hdr.htype = WH_HINIT;
460 lpwai->hdr.lpwhparent = NULL;
461 lpwai->hdr.dwFlags = dwFlags;
462 lpwai->dwAccessType = dwAccessType;
463 lpwai->lpszProxyUsername = NULL;
464 lpwai->lpszProxyPassword = NULL;
466 handle = WININET_AllocHandle( &lpwai->hdr );
467 if( !handle )
469 HeapFree( GetProcessHeap(), 0, lpwai );
470 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
471 goto lend;
474 if (NULL != lpszAgent)
476 lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
477 strlen(lpszAgent)+1);
478 if (lpwai->lpszAgent)
479 strcpy( lpwai->lpszAgent, lpszAgent );
481 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
482 INTERNET_ConfigureProxyFromReg( lpwai );
483 else if (NULL != lpszProxy)
485 lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
486 strlen(lpszProxy)+1);
487 if (lpwai->lpszProxy)
488 strcpy( lpwai->lpszProxy, lpszProxy );
491 if (NULL != lpszProxyBypass)
493 lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
494 strlen(lpszProxyBypass)+1);
495 if (lpwai->lpszProxyBypass)
496 strcpy( lpwai->lpszProxyBypass, lpszProxyBypass );
499 lend:
500 TRACE("returning %p\n", (HINTERNET)lpwai);
502 return handle;
506 /***********************************************************************
507 * InternetOpenW (WININET.@)
509 * Per-application initialization of wininet
511 * RETURNS
512 * HINTERNET on success
513 * NULL on failure
516 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
517 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
519 HINTERNET rc = (HINTERNET)NULL;
520 INT lenAgent = WideCharToMultiByte(CP_ACP, 0, lpszAgent, -1, NULL, 0, NULL, NULL);
521 INT lenProxy = WideCharToMultiByte(CP_ACP, 0, lpszProxy, -1, NULL, 0, NULL, NULL);
522 INT lenBypass = WideCharToMultiByte(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0, NULL, NULL);
523 CHAR *szAgent = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenAgent*sizeof(CHAR));
524 CHAR *szProxy = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenProxy*sizeof(CHAR));
525 CHAR *szBypass = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenBypass*sizeof(CHAR));
527 TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_w(lpszAgent), dwAccessType, debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
529 if (!szAgent || !szProxy || !szBypass)
531 if (szAgent)
532 HeapFree(GetProcessHeap(), 0, szAgent);
533 if (szProxy)
534 HeapFree(GetProcessHeap(), 0, szProxy);
535 if (szBypass)
536 HeapFree(GetProcessHeap(), 0, szBypass);
537 return (HINTERNET)NULL;
540 WideCharToMultiByte(CP_ACP, 0, lpszAgent, -1, szAgent, lenAgent,
541 NULL, NULL);
542 WideCharToMultiByte(CP_ACP, 0, lpszProxy, -1, szProxy, lenProxy,
543 NULL, NULL);
544 WideCharToMultiByte(CP_ACP, 0, lpszProxyBypass, -1, szBypass, lenBypass,
545 NULL, NULL);
547 rc = InternetOpenA(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
549 HeapFree(GetProcessHeap(), 0, szAgent);
550 HeapFree(GetProcessHeap(), 0, szProxy);
551 HeapFree(GetProcessHeap(), 0, szBypass);
553 return rc;
556 /***********************************************************************
557 * InternetGetLastResponseInfoA (WININET.@)
559 * Return last wininet error description on the calling thread
561 * RETURNS
562 * TRUE on success of writing to buffer
563 * FALSE on failure
566 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
567 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
569 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
571 TRACE("\n");
573 *lpdwError = lpwite->dwError;
574 if (lpwite->dwError)
576 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
577 *lpdwBufferLength = strlen(lpszBuffer);
579 else
580 *lpdwBufferLength = 0;
582 return TRUE;
586 /***********************************************************************
587 * InternetGetConnectedState (WININET.@)
589 * Return connected state
591 * RETURNS
592 * TRUE if connected
593 * if lpdwStatus is not null, return the status (off line,
594 * modem, lan...) in it.
595 * FALSE if not connected
597 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
599 TRACE("(%p, 0x%08lx)\n", lpdwStatus, dwReserved);
601 if (lpdwStatus) {
602 FIXME("always returning LAN connection.\n");
603 *lpdwStatus = INTERNET_CONNECTION_LAN;
605 return TRUE;
608 /***********************************************************************
609 * InternetGetConnectedStateEx (WININET.@)
611 * Return connected state
613 * RETURNS
614 * TRUE if connected
615 * if lpdwStatus is not null, return the status (off line,
616 * modem, lan...) in it.
617 * FALSE if not connected
619 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
620 DWORD dwNameLen, DWORD dwReserved)
622 TRACE("(%p, %s, %ld, 0x%08lx)\n", lpdwStatus, debugstr_w(lpszConnectionName), dwNameLen, dwReserved);
624 /* Must be zero */
625 if(dwReserved)
626 return FALSE;
628 if (lpdwStatus) {
629 FIXME("always returning LAN connection.\n");
630 *lpdwStatus = INTERNET_CONNECTION_LAN;
632 return TRUE;
635 /***********************************************************************
636 * InternetConnectA (WININET.@)
638 * Open a ftp, gopher or http session
640 * RETURNS
641 * HINTERNET a session handle on success
642 * NULL on failure
645 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
646 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
647 LPCSTR lpszUserName, LPCSTR lpszPassword,
648 DWORD dwService, DWORD dwFlags, DWORD dwContext)
650 HINTERNET rc = (HINTERNET) NULL;
652 TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet, debugstr_a(lpszServerName),
653 nServerPort, debugstr_a(lpszUserName), debugstr_a(lpszPassword),
654 dwService, dwFlags, dwContext);
656 /* Clear any error information */
657 INTERNET_SetLastError(0);
659 switch (dwService)
661 case INTERNET_SERVICE_FTP:
662 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
663 lpszUserName, lpszPassword, dwFlags, dwContext);
664 break;
666 case INTERNET_SERVICE_HTTP:
667 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
668 lpszUserName, lpszPassword, dwFlags, dwContext);
669 break;
671 case INTERNET_SERVICE_GOPHER:
672 default:
673 break;
676 TRACE("returning %p\n", rc);
677 return rc;
681 /***********************************************************************
682 * InternetConnectW (WININET.@)
684 * Open a ftp, gopher or http session
686 * RETURNS
687 * HINTERNET a session handle on success
688 * NULL on failure
691 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
692 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
693 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
694 DWORD dwService, DWORD dwFlags, DWORD dwContext)
696 HINTERNET rc = (HINTERNET)NULL;
697 INT lenServer = 0;
698 INT lenUser = 0;
699 INT lenPass = 0;
700 CHAR *szServerName = NULL;
701 CHAR *szUserName = NULL;
702 CHAR *szPassword = NULL;
704 if (lpszServerName)
706 lenServer = WideCharToMultiByte(CP_ACP, 0, lpszServerName, -1, NULL, 0,
707 NULL, NULL);
708 szServerName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenServer*sizeof(CHAR));
709 WideCharToMultiByte(CP_ACP, 0, lpszServerName, -1, szServerName, lenServer,
710 NULL, NULL);
712 if (lpszUserName)
714 lenUser = WideCharToMultiByte(CP_ACP, 0, lpszUserName, -1, NULL, 0,
715 NULL, NULL);
716 szUserName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenUser*sizeof(CHAR));
717 WideCharToMultiByte(CP_ACP, 0, lpszUserName, -1, szUserName, lenUser,
718 NULL, NULL);
720 if (lpszPassword)
722 lenPass = WideCharToMultiByte(CP_ACP, 0, lpszPassword, -1, NULL, 0,
723 NULL, NULL);
724 szPassword = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenPass*sizeof(CHAR));
725 WideCharToMultiByte(CP_ACP, 0, lpszPassword, -1, szPassword, lenPass,
726 NULL, NULL);
730 rc = InternetConnectA(hInternet, szServerName, nServerPort,
731 szUserName, szPassword, dwService, dwFlags, dwContext);
733 if (szServerName) HeapFree(GetProcessHeap(), 0, szServerName);
734 if (szUserName) HeapFree(GetProcessHeap(), 0, szUserName);
735 if (szPassword) HeapFree(GetProcessHeap(), 0, szPassword);
736 return rc;
740 /***********************************************************************
741 * InternetFindNextFileA (WININET.@)
743 * Continues a file search from a previous call to FindFirstFile
745 * RETURNS
746 * TRUE on success
747 * FALSE on failure
750 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
752 LPWININETAPPINFOA hIC = NULL;
753 LPWININETFINDNEXTA lpwh;
755 TRACE("\n");
757 lpwh = (LPWININETFINDNEXTA) WININET_GetObject( hFind );
759 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
761 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
762 return FALSE;
765 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
766 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
768 WORKREQUEST workRequest;
769 struct WORKREQ_INTERNETFINDNEXTA *req;
771 workRequest.asyncall = INTERNETFINDNEXTA;
772 workRequest.handle = hFind;
773 req = &workRequest.u.InternetFindNextA;
774 req->lpFindFileData = lpvFindData;
776 return INTERNET_AsyncCall(&workRequest);
778 else
780 return INTERNET_FindNextFileA(hFind, lpvFindData);
784 /***********************************************************************
785 * INTERNET_FindNextFileA (Internal)
787 * Continues a file search from a previous call to FindFirstFile
789 * RETURNS
790 * TRUE on success
791 * FALSE on failure
794 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
796 BOOL bSuccess = TRUE;
797 LPWININETAPPINFOA hIC = NULL;
798 LPWIN32_FIND_DATAA lpFindFileData;
799 LPWININETFINDNEXTA lpwh;
801 TRACE("\n");
803 lpwh = (LPWININETFINDNEXTA) WININET_GetObject( hFind );
804 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
806 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
807 return FALSE;
810 /* Clear any error information */
811 INTERNET_SetLastError(0);
813 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
815 FIXME("Only FTP find next supported\n");
816 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
817 return FALSE;
820 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
822 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
823 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
825 if (lpwh->index >= lpwh->size)
827 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
828 bSuccess = FALSE;
829 goto lend;
832 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
833 lpwh->index++;
835 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
837 lend:
839 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
840 if (hIC->lpfnStatusCB)
842 INTERNET_ASYNC_RESULT iar;
844 iar.dwResult = (DWORD)bSuccess;
845 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
846 INTERNET_GetLastError();
848 SendAsyncCallback(hIC, hFind, lpwh->hdr.dwContext,
849 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
850 sizeof(INTERNET_ASYNC_RESULT));
853 return bSuccess;
857 /***********************************************************************
858 * INTERNET_CloseHandle (internal)
860 * Close internet handle
862 * RETURNS
863 * Void
866 VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
868 TRACE("%p\n",lpwai);
870 SendAsyncCallback(lpwai, lpwai, lpwai->hdr.dwContext,
871 INTERNET_STATUS_HANDLE_CLOSING, lpwai,
872 sizeof(HINTERNET));
874 if (lpwai->lpszAgent)
875 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
877 if (lpwai->lpszProxy)
878 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
880 if (lpwai->lpszProxyBypass)
881 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
883 if (lpwai->lpszProxyUsername)
884 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
886 if (lpwai->lpszProxyPassword)
887 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
889 HeapFree(GetProcessHeap(), 0, lpwai);
893 /***********************************************************************
894 * InternetCloseHandle (WININET.@)
896 * Generic close handle function
898 * RETURNS
899 * TRUE on success
900 * FALSE on failure
903 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
905 BOOL retval;
906 LPWININETHANDLEHEADER lpwh;
908 TRACE("%p\n",hInternet);
910 lpwh = WININET_GetObject( hInternet );
911 if (NULL == lpwh)
913 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
914 return FALSE;
917 /* Clear any error information */
918 INTERNET_SetLastError(0);
919 retval = FALSE;
921 switch (lpwh->htype)
923 case WH_HINIT:
924 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
925 retval = TRUE;
926 break;
928 case WH_HHTTPSESSION:
929 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
930 retval = TRUE;
931 break;
933 case WH_HHTTPREQ:
934 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
935 retval = TRUE;
936 break;
938 case WH_HFTPSESSION:
939 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
940 break;
942 case WH_HFINDNEXT:
943 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
944 break;
946 case WH_HFILE:
947 retval = FTP_CloseFileTransferHandle((LPWININETFILE) lpwh);
948 break;
950 default:
951 break;
953 if( retval )
954 WININET_FreeHandle( hInternet );
956 return retval;
960 /***********************************************************************
961 * ConvertUrlComponentValue (Internal)
963 * Helper function for InternetCrackUrlW
966 void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
967 LPWSTR lpwszComponent, DWORD dwwComponentLen,
968 LPCSTR lpszStart,
969 LPCWSTR lpwszStart)
971 if (*dwComponentLen != 0)
973 int nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
974 if (*lppszComponent == NULL)
976 int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
977 *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
978 *dwComponentLen = nASCIILength;
980 else
982 INT ncpylen = min((*dwComponentLen)-1, nASCIILength);
983 WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
984 (*lppszComponent)[ncpylen]=0;
985 *dwComponentLen = ncpylen;
991 /***********************************************************************
992 * InternetCrackUrlA (WININET.@)
994 * Break up URL into its components
996 * TODO: Handle dwFlags
998 * RETURNS
999 * TRUE on success
1000 * FALSE on failure
1003 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1004 LPURL_COMPONENTSA lpUrlComponents)
1006 DWORD nLength;
1007 URL_COMPONENTSW UCW;
1008 WCHAR* lpwszUrl;
1009 if(dwUrlLength==0)
1010 dwUrlLength=strlen(lpszUrl);
1011 lpwszUrl=HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(dwUrlLength+1));
1012 memset(lpwszUrl,0,sizeof(WCHAR)*(dwUrlLength+1));
1013 nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,dwUrlLength+1);
1014 memset(&UCW,0,sizeof(UCW));
1015 if(lpUrlComponents->dwHostNameLength!=0)
1016 UCW.dwHostNameLength=1;
1017 if(lpUrlComponents->dwUserNameLength!=0)
1018 UCW.dwUserNameLength=1;
1019 if(lpUrlComponents->dwPasswordLength!=0)
1020 UCW.dwPasswordLength=1;
1021 if(lpUrlComponents->dwUrlPathLength!=0)
1022 UCW.dwUrlPathLength=1;
1023 if(lpUrlComponents->dwSchemeLength!=0)
1024 UCW.dwSchemeLength=1;
1025 if(lpUrlComponents->dwExtraInfoLength!=0)
1026 UCW.dwExtraInfoLength=1;
1027 if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1029 HeapFree(GetProcessHeap(), 0, lpwszUrl);
1030 return FALSE;
1032 ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1033 UCW.lpszHostName, UCW.dwHostNameLength,
1034 lpszUrl, lpwszUrl);
1035 ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1036 UCW.lpszUserName, UCW.dwUserNameLength,
1037 lpszUrl, lpwszUrl);
1038 ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1039 UCW.lpszPassword, UCW.dwPasswordLength,
1040 lpszUrl, lpwszUrl);
1041 ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1042 UCW.lpszUrlPath, UCW.dwUrlPathLength,
1043 lpszUrl, lpwszUrl);
1044 ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1045 UCW.lpszScheme, UCW.dwSchemeLength,
1046 lpszUrl, lpwszUrl);
1047 ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1048 UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1049 lpszUrl, lpwszUrl);
1050 lpUrlComponents->nScheme=UCW.nScheme;
1051 lpUrlComponents->nPort=UCW.nPort;
1052 HeapFree(GetProcessHeap(), 0, lpwszUrl);
1054 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1055 debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1056 debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1057 debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1058 debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1060 return TRUE;
1063 /***********************************************************************
1064 * GetInternetSchemeW (internal)
1066 * Get scheme of url
1068 * RETURNS
1069 * scheme on success
1070 * INTERNET_SCHEME_UNKNOWN on failure
1073 INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, INT nMaxCmp)
1075 INTERNET_SCHEME iScheme=INTERNET_SCHEME_UNKNOWN;
1076 WCHAR lpszFtp[]={'f','t','p',0};
1077 WCHAR lpszGopher[]={'g','o','p','h','e','r',0};
1078 WCHAR lpszHttp[]={'h','t','t','p',0};
1079 WCHAR lpszHttps[]={'h','t','t','p','s',0};
1080 WCHAR lpszFile[]={'f','i','l','e',0};
1081 WCHAR lpszNews[]={'n','e','w','s',0};
1082 WCHAR lpszMailto[]={'m','a','i','l','t','o',0};
1083 WCHAR lpszRes[]={'r','e','s',0};
1084 WCHAR* tempBuffer=NULL;
1085 TRACE("\n");
1086 if(lpszScheme==NULL)
1087 return INTERNET_SCHEME_UNKNOWN;
1089 tempBuffer=HeapAlloc(GetProcessHeap(),0,(nMaxCmp+1)*sizeof(WCHAR));
1090 strncpyW(tempBuffer,lpszScheme,nMaxCmp);
1091 tempBuffer[nMaxCmp]=0;
1092 strlwrW(tempBuffer);
1093 if (nMaxCmp==strlenW(lpszFtp) && !strncmpW(lpszFtp, tempBuffer, nMaxCmp))
1094 iScheme=INTERNET_SCHEME_FTP;
1095 else if (nMaxCmp==strlenW(lpszGopher) && !strncmpW(lpszGopher, tempBuffer, nMaxCmp))
1096 iScheme=INTERNET_SCHEME_GOPHER;
1097 else if (nMaxCmp==strlenW(lpszHttp) && !strncmpW(lpszHttp, tempBuffer, nMaxCmp))
1098 iScheme=INTERNET_SCHEME_HTTP;
1099 else if (nMaxCmp==strlenW(lpszHttps) && !strncmpW(lpszHttps, tempBuffer, nMaxCmp))
1100 iScheme=INTERNET_SCHEME_HTTPS;
1101 else if (nMaxCmp==strlenW(lpszFile) && !strncmpW(lpszFile, tempBuffer, nMaxCmp))
1102 iScheme=INTERNET_SCHEME_FILE;
1103 else if (nMaxCmp==strlenW(lpszNews) && !strncmpW(lpszNews, tempBuffer, nMaxCmp))
1104 iScheme=INTERNET_SCHEME_NEWS;
1105 else if (nMaxCmp==strlenW(lpszMailto) && !strncmpW(lpszMailto, tempBuffer, nMaxCmp))
1106 iScheme=INTERNET_SCHEME_MAILTO;
1107 else if (nMaxCmp==strlenW(lpszRes) && !strncmpW(lpszRes, tempBuffer, nMaxCmp))
1108 iScheme=INTERNET_SCHEME_RES;
1109 HeapFree(GetProcessHeap(),0,tempBuffer);
1110 return iScheme;
1113 /***********************************************************************
1114 * SetUrlComponentValueW (Internal)
1116 * Helper function for InternetCrackUrlW
1118 * RETURNS
1119 * TRUE on success
1120 * FALSE on failure
1123 BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, INT len)
1125 TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1127 if (*dwComponentLen != 0 || *lppszComponent == NULL)
1129 if (*lppszComponent == NULL)
1131 *lppszComponent = (LPWSTR)lpszStart;
1132 *dwComponentLen = len;
1134 else
1136 INT ncpylen = min((*dwComponentLen)-1, len);
1137 strncpyW(*lppszComponent, lpszStart, ncpylen);
1138 (*lppszComponent)[ncpylen] = '\0';
1139 *dwComponentLen = ncpylen;
1143 return TRUE;
1146 /***********************************************************************
1147 * InternetCrackUrlW (WININET.@)
1149 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1150 LPURL_COMPONENTSW lpUC)
1153 * RFC 1808
1154 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1157 LPWSTR lpszParam = NULL;
1158 BOOL bIsAbsolute = FALSE;
1159 LPWSTR lpszap = (WCHAR*)lpszUrl;
1160 LPWSTR lpszcp = NULL;
1161 WCHAR lpszSeparators[3]={';','?',0};
1162 WCHAR lpszSlash[2]={'/',0};
1163 if(dwUrlLength==0)
1164 dwUrlLength=strlenW(lpszUrl);
1166 TRACE("\n");
1168 /* Determine if the URI is absolute. */
1169 while (*lpszap != '\0')
1171 if (isalnumW(*lpszap))
1173 lpszap++;
1174 continue;
1176 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1178 bIsAbsolute = TRUE;
1179 lpszcp = lpszap;
1181 else
1183 lpszcp = (LPWSTR)lpszUrl; /* Relative url */
1186 break;
1189 /* Parse <params> */
1190 lpszParam = strpbrkW(lpszap, lpszSeparators);
1191 if (lpszParam != NULL)
1193 if (!SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1194 lpszParam, dwUrlLength-(lpszParam-lpszUrl)))
1196 return FALSE;
1200 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1202 LPWSTR lpszNetLoc;
1203 WCHAR wszAbout[]={'a','b','o','u','t',':',0};
1205 /* Get scheme first. */
1206 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1207 if (!SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1208 lpszUrl, lpszcp - lpszUrl))
1209 return FALSE;
1211 /* Eat ':' in protocol. */
1212 lpszcp++;
1214 /* if the scheme is "about", there is no host */
1215 if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1217 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1218 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1219 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1220 lpUC->nPort = 0;
1222 else
1224 /* Skip over slashes. */
1225 if (*lpszcp == '/')
1227 lpszcp++;
1228 if (*lpszcp == '/')
1230 lpszcp++;
1231 if (*lpszcp == '/')
1232 lpszcp++;
1236 lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1237 if (lpszParam)
1239 if (lpszNetLoc)
1240 lpszNetLoc = min(lpszNetLoc, lpszParam);
1241 else
1242 lpszNetLoc = lpszParam;
1244 else if (!lpszNetLoc)
1245 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1247 /* Parse net-loc */
1248 if (lpszNetLoc)
1250 LPWSTR lpszHost;
1251 LPWSTR lpszPort;
1253 /* [<user>[<:password>]@]<host>[:<port>] */
1254 /* First find the user and password if they exist */
1256 lpszHost = strchrW(lpszcp, '@');
1257 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1259 /* username and password not specified. */
1260 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1261 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1263 else /* Parse out username and password */
1265 LPWSTR lpszUser = lpszcp;
1266 LPWSTR lpszPasswd = lpszHost;
1268 while (lpszcp < lpszHost)
1270 if (*lpszcp == ':')
1271 lpszPasswd = lpszcp;
1273 lpszcp++;
1276 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1277 lpszUser, lpszPasswd - lpszUser);
1279 if (lpszPasswd != lpszHost)
1280 lpszPasswd++;
1281 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1282 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1283 lpszHost - lpszPasswd);
1285 lpszcp++; /* Advance to beginning of host */
1288 /* Parse <host><:port> */
1290 lpszHost = lpszcp;
1291 lpszPort = lpszNetLoc;
1293 /* special case for res:// URLs: there is no port here, so the host is the
1294 entire string up to the first '/' */
1295 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1297 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1298 lpszHost, lpszPort - lpszHost);
1299 lpUC->nPort = 0;
1300 lpszcp=lpszNetLoc;
1302 else
1304 while (lpszcp < lpszNetLoc)
1306 if (*lpszcp == ':')
1307 lpszPort = lpszcp;
1309 lpszcp++;
1312 /* If the scheme is "file" and the host is just one letter, it's not a host */
1313 if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1315 lpszcp=lpszHost;
1316 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1317 NULL, 0);
1318 lpUC->nPort = 0;
1320 else
1322 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1323 lpszHost, lpszPort - lpszHost);
1324 if (lpszPort != lpszNetLoc)
1325 lpUC->nPort = atoiW(++lpszPort);
1326 else
1327 lpUC->nPort = 0;
1334 /* Here lpszcp points to:
1336 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1337 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1339 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1341 INT len;
1343 /* Only truncate the parameter list if it's already been saved
1344 * in lpUC->lpszExtraInfo.
1346 if (lpszParam && lpUC->dwExtraInfoLength)
1347 len = lpszParam - lpszcp;
1348 else
1350 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1351 * newlines if necessary.
1353 LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1354 if (lpsznewline != NULL)
1355 len = lpsznewline - lpszcp;
1356 else
1357 len = dwUrlLength-(lpszcp-lpszUrl);
1360 if (!SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1361 lpszcp, len))
1362 return FALSE;
1364 else
1366 lpUC->dwUrlPathLength = 0;
1369 TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1370 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1371 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1372 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1374 return TRUE;
1377 /***********************************************************************
1378 * InternetAttemptConnect (WININET.@)
1380 * Attempt to make a connection to the internet
1382 * RETURNS
1383 * ERROR_SUCCESS on success
1384 * Error value on failure
1387 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1389 FIXME("Stub\n");
1390 return ERROR_SUCCESS;
1394 /***********************************************************************
1395 * InternetCanonicalizeUrlA (WININET.@)
1397 * Escape unsafe characters and spaces
1399 * RETURNS
1400 * TRUE on success
1401 * FALSE on failure
1404 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1405 LPDWORD lpdwBufferLength, DWORD dwFlags)
1407 HRESULT hr;
1408 TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1409 lpdwBufferLength, dwFlags);
1411 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1412 dwFlags ^= ICU_NO_ENCODE;
1414 dwFlags |= 0x80000000; /* Don't know what this means */
1416 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1418 return (hr == S_OK) ? TRUE : FALSE;
1421 /***********************************************************************
1422 * InternetCanonicalizeUrlW (WININET.@)
1424 * Escape unsafe characters and spaces
1426 * RETURNS
1427 * TRUE on success
1428 * FALSE on failure
1431 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1432 LPDWORD lpdwBufferLength, DWORD dwFlags)
1434 HRESULT hr;
1435 TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1436 lpdwBufferLength, dwFlags);
1438 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1439 dwFlags ^= ICU_NO_ENCODE;
1441 dwFlags |= 0x80000000; /* Don't know what this means */
1443 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1445 return (hr == S_OK) ? TRUE : FALSE;
1449 /***********************************************************************
1450 * InternetSetStatusCallbackA (WININET.@)
1452 * Sets up a callback function which is called as progress is made
1453 * during an operation.
1455 * RETURNS
1456 * Previous callback or NULL on success
1457 * INTERNET_INVALID_STATUS_CALLBACK on failure
1460 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1461 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1463 INTERNET_STATUS_CALLBACK retVal;
1464 LPWININETAPPINFOA lpwai;
1466 lpwai = (LPWININETAPPINFOA)WININET_GetObject(hInternet);
1467 if (!lpwai)
1468 return NULL;
1470 TRACE("0x%08lx\n", (ULONG)hInternet);
1471 if (lpwai->hdr.htype != WH_HINIT)
1472 return INTERNET_INVALID_STATUS_CALLBACK;
1474 retVal = lpwai->lpfnStatusCB;
1475 lpwai->lpfnStatusCB = lpfnIntCB;
1477 return retVal;
1480 /***********************************************************************
1481 * InternetSetFilePointer (WININET.@)
1483 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1485 FIXME("stub\n");
1486 return FALSE;
1489 /***********************************************************************
1490 * InternetWriteFile (WININET.@)
1492 * Write data to an open internet file
1494 * RETURNS
1495 * TRUE on success
1496 * FALSE on failure
1499 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1500 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1502 BOOL retval = FALSE;
1503 int nSocket = -1;
1504 LPWININETHANDLEHEADER lpwh;
1506 TRACE("\n");
1507 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1508 if (NULL == lpwh)
1509 return FALSE;
1511 switch (lpwh->htype)
1513 case WH_HHTTPREQ:
1514 FIXME("This shouldn't be here! We don't support this kind"
1515 " of connection anymore. Must use NETCON functions,"
1516 " especially if using SSL\n");
1517 nSocket = ((LPWININETHTTPREQA)lpwh)->netConnection.socketFD;
1518 break;
1520 case WH_HFILE:
1521 nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1522 break;
1524 default:
1525 break;
1528 if (nSocket != -1)
1530 int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1531 retval = (res >= 0);
1532 *lpdwNumOfBytesWritten = retval ? res : 0;
1535 return retval;
1539 /***********************************************************************
1540 * InternetReadFile (WININET.@)
1542 * Read data from an open internet file
1544 * RETURNS
1545 * TRUE on success
1546 * FALSE on failure
1549 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1550 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1552 BOOL retval = FALSE;
1553 int nSocket = -1;
1554 LPWININETHANDLEHEADER lpwh;
1556 TRACE("\n");
1558 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1559 if (NULL == lpwh)
1560 return FALSE;
1562 /* FIXME: this should use NETCON functions! */
1563 switch (lpwh->htype)
1565 case WH_HHTTPREQ:
1566 if (!NETCON_recv(&((LPWININETHTTPREQA)lpwh)->netConnection, lpBuffer,
1567 dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead))
1569 *dwNumOfBytesRead = 0;
1570 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1572 else
1573 retval = TRUE;
1574 break;
1576 case WH_HFILE:
1577 /* FIXME: FTP should use NETCON_ stuff */
1578 nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1579 if (nSocket != -1)
1581 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
1582 retval = (res >= 0);
1583 *dwNumOfBytesRead = retval ? res : 0;
1585 break;
1587 default:
1588 break;
1591 return retval;
1594 /***********************************************************************
1595 * InternetReadFileExA (WININET.@)
1597 * Read data from an open internet file
1599 * RETURNS
1600 * TRUE on success
1601 * FALSE on failure
1604 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1605 DWORD dwFlags, DWORD dwContext)
1607 FIXME("stub\n");
1608 return FALSE;
1611 /***********************************************************************
1612 * InternetReadFileExW (WININET.@)
1614 * Read data from an open internet file
1616 * RETURNS
1617 * TRUE on success
1618 * FALSE on failure
1621 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1622 DWORD dwFlags, DWORD dwContext)
1624 FIXME("stub\n");
1626 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1627 return FALSE;
1630 /***********************************************************************
1631 * INET_QueryOptionHelper (internal)
1633 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1634 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1636 LPWININETHANDLEHEADER lpwhh;
1637 BOOL bSuccess = FALSE;
1639 TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1641 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1642 if( !lpwhh )
1643 return FALSE;
1645 switch (dwOption)
1647 case INTERNET_OPTION_HANDLE_TYPE:
1649 ULONG type = lpwhh->htype;
1650 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1652 if (*lpdwBufferLength < sizeof(ULONG))
1653 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1654 else
1656 memcpy(lpBuffer, &type, sizeof(ULONG));
1657 *lpdwBufferLength = sizeof(ULONG);
1658 bSuccess = TRUE;
1660 break;
1663 case INTERNET_OPTION_REQUEST_FLAGS:
1665 ULONG flags = 4;
1666 TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1667 if (*lpdwBufferLength < sizeof(ULONG))
1668 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1669 else
1671 memcpy(lpBuffer, &flags, sizeof(ULONG));
1672 *lpdwBufferLength = sizeof(ULONG);
1673 bSuccess = TRUE;
1675 break;
1678 case INTERNET_OPTION_URL:
1679 case INTERNET_OPTION_DATAFILE_NAME:
1681 ULONG type = lpwhh->htype;
1682 if (type == WH_HHTTPREQ)
1684 LPWININETHTTPREQA lpreq = (LPWININETHTTPREQA) lpwhh;
1685 char url[1023];
1687 sprintf(url,"http://%s%s",lpreq->lpszHostName,lpreq->lpszPath);
1688 TRACE("INTERNET_OPTION_URL: %s\n",url);
1689 if (*lpdwBufferLength < strlen(url)+1)
1690 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1691 else
1693 if(bIsUnicode)
1695 *lpdwBufferLength=MultiByteToWideChar(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength);
1697 else
1699 memcpy(lpBuffer, url, strlen(url)+1);
1700 *lpdwBufferLength = strlen(url)+1;
1702 bSuccess = TRUE;
1705 break;
1707 case INTERNET_OPTION_HTTP_VERSION:
1710 * Presently hardcoded to 1.1
1712 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1713 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1714 bSuccess = TRUE;
1715 break;
1717 case INTERNET_OPTION_SECURITY_FLAGS:
1718 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1719 break;
1721 default:
1722 FIXME("Stub! %ld \n",dwOption);
1723 break;
1726 return bSuccess;
1729 /***********************************************************************
1730 * InternetQueryOptionW (WININET.@)
1732 * Queries an options on the specified handle
1734 * RETURNS
1735 * TRUE on success
1736 * FALSE on failure
1739 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1740 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1742 return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1745 /***********************************************************************
1746 * InternetQueryOptionA (WININET.@)
1748 * Queries an options on the specified handle
1750 * RETURNS
1751 * TRUE on success
1752 * FALSE on failure
1755 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1756 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1758 return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1762 /***********************************************************************
1763 * InternetSetOptionW (WININET.@)
1765 * Sets an options on the specified handle
1767 * RETURNS
1768 * TRUE on success
1769 * FALSE on failure
1772 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1773 LPVOID lpBuffer, DWORD dwBufferLength)
1775 LPWININETHANDLEHEADER lpwhh;
1777 TRACE("0x%08lx\n", dwOption);
1779 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1780 if( !lpwhh )
1781 return FALSE;
1783 switch (dwOption)
1785 case INTERNET_OPTION_HTTP_VERSION:
1787 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1788 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1790 break;
1791 case INTERNET_OPTION_ERROR_MASK:
1793 unsigned long flags=*(unsigned long*)lpBuffer;
1794 FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1796 break;
1797 case INTERNET_OPTION_CODEPAGE:
1799 unsigned long codepage=*(unsigned long*)lpBuffer;
1800 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1802 break;
1803 case INTERNET_OPTION_REQUEST_PRIORITY:
1805 unsigned long priority=*(unsigned long*)lpBuffer;
1806 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1808 break;
1809 case INTERNET_OPTION_CONNECT_TIMEOUT:
1811 unsigned long connecttimeout=*(unsigned long*)lpBuffer;
1812 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
1814 break;
1815 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
1817 unsigned long receivetimeout=*(unsigned long*)lpBuffer;
1818 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
1820 break;
1821 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
1822 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1823 break;
1824 case INTERNET_OPTION_END_BROWSER_SESSION:
1825 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1826 break;
1827 case INTERNET_OPTION_CONNECTED_STATE:
1828 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1829 break;
1830 default:
1831 FIXME("Option %ld STUB\n",dwOption);
1832 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1833 return FALSE;
1836 return TRUE;
1840 /***********************************************************************
1841 * InternetSetOptionA (WININET.@)
1843 * Sets an options on the specified handle.
1845 * RETURNS
1846 * TRUE on success
1847 * FALSE on failure
1850 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1851 LPVOID lpBuffer, DWORD dwBufferLength)
1853 LPVOID wbuffer;
1854 DWORD wlen;
1855 BOOL r;
1857 switch( dwOption )
1859 case INTERNET_OPTION_PROXY:
1861 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1862 LPINTERNET_PROXY_INFOW piw;
1863 DWORD proxlen, prbylen;
1864 LPWSTR prox, prby;
1866 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1867 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1868 wlen = sizeof(*piw) + proxlen + prbylen;
1869 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1870 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1871 piw->dwAccessType = pi->dwAccessType;
1872 prox = (LPWSTR) &piw[1];
1873 prby = &prox[proxlen+1];
1874 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1875 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1876 piw->lpszProxy = prox;
1877 piw->lpszProxyBypass = prby;
1879 break;
1880 case INTERNET_OPTION_USER_AGENT:
1881 case INTERNET_OPTION_USERNAME:
1882 case INTERNET_OPTION_PASSWORD:
1883 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1884 NULL, 0 );
1885 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1886 MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1887 wbuffer, wlen );
1888 break;
1889 default:
1890 wbuffer = lpBuffer;
1891 wlen = dwBufferLength;
1894 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
1896 if( lpBuffer != wbuffer )
1897 HeapFree( GetProcessHeap(), 0, wbuffer );
1899 return r;
1903 /***********************************************************************
1904 * InternetSetOptionExA (WININET.@)
1906 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
1907 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
1909 FIXME("Flags %08lx ignored\n", dwFlags);
1910 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
1913 /***********************************************************************
1914 * InternetSetOptionExW (WININET.@)
1916 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
1917 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
1919 FIXME("Flags %08lx ignored\n", dwFlags);
1920 if( dwFlags & ~ISO_VALID_FLAGS )
1922 SetLastError( ERROR_INVALID_PARAMETER );
1923 return FALSE;
1925 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
1929 /***********************************************************************
1930 * InternetCheckConnectionA (WININET.@)
1932 * Pings a requested host to check internet connection
1934 * RETURNS
1935 * TRUE on success and FALSE on failure. If a failure then
1936 * ERROR_NOT_CONNECTED is placesd into GetLastError
1939 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
1942 * this is a kludge which runs the resident ping program and reads the output.
1944 * Anyone have a better idea?
1947 BOOL rc = FALSE;
1948 char command[1024];
1949 char host[1024];
1950 int status = -1;
1952 FIXME("\n");
1955 * Crack or set the Address
1957 if (lpszUrl == NULL)
1960 * According to the doc we are supost to use the ip for the next
1961 * server in the WnInet internal server database. I have
1962 * no idea what that is or how to get it.
1964 * So someone needs to implement this.
1966 FIXME("Unimplemented with URL of NULL\n");
1967 return TRUE;
1969 else
1971 URL_COMPONENTSA componets;
1973 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
1974 componets.lpszHostName = (LPSTR)&host;
1975 componets.dwHostNameLength = 1024;
1977 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
1978 goto End;
1980 TRACE("host name : %s\n",componets.lpszHostName);
1984 * Build our ping command
1986 strcpy(command,"ping -w 1 ");
1987 strcat(command,host);
1988 strcat(command," >/dev/null 2>/dev/null");
1990 TRACE("Ping command is : %s\n",command);
1992 status = system(command);
1994 TRACE("Ping returned a code of %i \n",status);
1996 /* Ping return code of 0 indicates success */
1997 if (status == 0)
1998 rc = TRUE;
2000 End:
2002 if (rc == FALSE)
2003 SetLastError(ERROR_NOT_CONNECTED);
2005 return rc;
2009 /***********************************************************************
2010 * InternetCheckConnectionW (WININET.@)
2012 * Pings a requested host to check internet connection
2014 * RETURNS
2015 * TRUE on success and FALSE on failure. If a failure then
2016 * ERROR_NOT_CONNECTED is placed into GetLastError
2019 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2021 CHAR *szUrl;
2022 INT len;
2023 BOOL rc;
2025 len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2026 if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2027 return FALSE;
2028 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2029 rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2030 HeapFree(GetProcessHeap(), 0, szUrl);
2032 return rc;
2036 /**********************************************************
2037 * INTERNET_InternetOpenUrlA (internal)
2039 * Opens an URL
2041 * RETURNS
2042 * handle of connection or NULL on failure
2044 HINTERNET WINAPI INTERNET_InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2045 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2047 URL_COMPONENTSA urlComponents;
2048 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
2049 char password[1024], path[2048], extra[1024];
2050 HINTERNET client = NULL, client1 = NULL;
2052 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
2053 dwHeadersLength, dwFlags, dwContext);
2055 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
2056 urlComponents.lpszScheme = protocol;
2057 urlComponents.dwSchemeLength = 32;
2058 urlComponents.lpszHostName = hostName;
2059 urlComponents.dwHostNameLength = MAXHOSTNAME;
2060 urlComponents.lpszUserName = userName;
2061 urlComponents.dwUserNameLength = 1024;
2062 urlComponents.lpszPassword = password;
2063 urlComponents.dwPasswordLength = 1024;
2064 urlComponents.lpszUrlPath = path;
2065 urlComponents.dwUrlPathLength = 2048;
2066 urlComponents.lpszExtraInfo = extra;
2067 urlComponents.dwExtraInfoLength = 1024;
2068 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
2069 return NULL;
2070 switch(urlComponents.nScheme) {
2071 case INTERNET_SCHEME_FTP:
2072 if(urlComponents.nPort == 0)
2073 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2074 client = InternetConnectA(hInternet, hostName, urlComponents.nPort,
2075 userName, password, INTERNET_SERVICE_FTP, dwFlags, dwContext);
2076 client1 = FtpOpenFileA(client, path, GENERIC_READ, dwFlags, dwContext);
2077 break;
2079 case INTERNET_SCHEME_HTTP:
2080 case INTERNET_SCHEME_HTTPS: {
2081 LPCSTR accept[2] = { "*/*", NULL };
2082 if(urlComponents.nPort == 0) {
2083 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2084 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2085 else
2086 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2088 client = InternetConnectA(hInternet, hostName, urlComponents.nPort, userName,
2089 password, INTERNET_SERVICE_HTTP, dwFlags, dwContext);
2090 if(client == NULL)
2091 break;
2092 client1 = HttpOpenRequestA(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2093 if(client1 == NULL) {
2094 InternetCloseHandle(client);
2095 break;
2097 HttpAddRequestHeadersA(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2098 if (!HTTP_HttpSendRequestA(client1, NULL, 0, NULL, 0)) {
2099 InternetCloseHandle(client1);
2100 InternetCloseHandle(client);
2101 client1 = NULL;
2102 break;
2105 case INTERNET_SCHEME_GOPHER:
2106 /* gopher doesn't seem to be implemented in wine, but it's supposed
2107 * to be supported by InternetOpenUrlA. */
2108 default:
2109 break;
2112 TRACE(" %p <--\n", client1);
2114 return client1;
2117 /**********************************************************
2118 * InternetOpenUrlA (WININET.@)
2120 * Opens an URL
2122 * RETURNS
2123 * handle of connection or NULL on failure
2125 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2126 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2128 HINTERNET ret = NULL;
2129 LPWININETAPPINFOA hIC = NULL;
2131 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
2132 dwHeadersLength, dwFlags, dwContext);
2134 hIC = (LPWININETAPPINFOA) WININET_GetObject( hInternet );
2135 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
2136 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2137 goto lend;
2140 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2141 WORKREQUEST workRequest;
2142 struct WORKREQ_INTERNETOPENURLA *req;
2144 workRequest.asyncall = INTERNETOPENURLA;
2145 workRequest.handle = hInternet;
2146 req = &workRequest.u.InternetOpenUrlA;
2147 if (lpszUrl)
2148 req->lpszUrl = WININET_strdup(lpszUrl);
2149 else
2150 req->lpszUrl = 0;
2151 if (lpszHeaders)
2152 req->lpszHeaders = WININET_strdup(lpszHeaders);
2153 else
2154 req->lpszHeaders = 0;
2155 req->dwHeadersLength = dwHeadersLength;
2156 req->dwFlags = dwFlags;
2157 req->dwContext = dwContext;
2159 INTERNET_AsyncCall(&workRequest);
2161 * This is from windows.
2163 SetLastError(ERROR_IO_PENDING);
2164 } else {
2165 ret = INTERNET_InternetOpenUrlA(hInternet, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2168 lend:
2169 TRACE(" %p <--\n", ret);
2171 return ret;
2174 /**********************************************************
2175 * InternetOpenUrlW (WININET.@)
2177 * Opens an URL
2179 * RETURNS
2180 * handle of connection or NULL on failure
2182 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2183 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2185 HINTERNET rc = (HINTERNET)NULL;
2187 INT lenUrl = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2188 INT lenHeaders = WideCharToMultiByte(CP_ACP, 0, lpszHeaders, -1, NULL, 0, NULL, NULL);
2189 CHAR *szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(CHAR));
2190 CHAR *szHeaders = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(CHAR));
2192 TRACE("\n");
2194 if (!szUrl || !szHeaders)
2196 if (szUrl)
2197 HeapFree(GetProcessHeap(), 0, szUrl);
2198 if (szHeaders)
2199 HeapFree(GetProcessHeap(), 0, szHeaders);
2200 return (HINTERNET)NULL;
2203 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl,
2204 NULL, NULL);
2205 WideCharToMultiByte(CP_ACP, 0, lpszHeaders, -1, szHeaders, lenHeaders,
2206 NULL, NULL);
2208 rc = InternetOpenUrlA(hInternet, szUrl, szHeaders,
2209 dwHeadersLength, dwFlags, dwContext);
2211 HeapFree(GetProcessHeap(), 0, szUrl);
2212 HeapFree(GetProcessHeap(), 0, szHeaders);
2214 return rc;
2218 /***********************************************************************
2219 * INTERNET_SetLastError (internal)
2221 * Set last thread specific error
2223 * RETURNS
2226 void INTERNET_SetLastError(DWORD dwError)
2228 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2230 SetLastError(dwError);
2231 if(lpwite)
2232 lpwite->dwError = dwError;
2236 /***********************************************************************
2237 * INTERNET_GetLastError (internal)
2239 * Get last thread specific error
2241 * RETURNS
2244 DWORD INTERNET_GetLastError()
2246 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2247 return lpwite->dwError;
2251 /***********************************************************************
2252 * INTERNET_WorkerThreadFunc (internal)
2254 * Worker thread execution function
2256 * RETURNS
2259 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2261 DWORD dwWaitRes;
2263 while (1)
2265 if(dwNumJobs > 0) {
2266 INTERNET_ExecuteWork();
2267 continue;
2269 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2271 if (dwWaitRes == WAIT_OBJECT_0 + 1)
2272 INTERNET_ExecuteWork();
2273 else
2274 break;
2276 InterlockedIncrement(&dwNumIdleThreads);
2279 InterlockedDecrement(&dwNumIdleThreads);
2280 InterlockedDecrement(&dwNumThreads);
2281 TRACE("Worker thread exiting\n");
2282 return TRUE;
2286 /***********************************************************************
2287 * INTERNET_InsertWorkRequest (internal)
2289 * Insert work request into queue
2291 * RETURNS
2294 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2296 BOOL bSuccess = FALSE;
2297 LPWORKREQUEST lpNewRequest;
2299 TRACE("\n");
2301 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2302 if (lpNewRequest)
2304 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2305 lpNewRequest->prev = NULL;
2307 EnterCriticalSection(&csQueue);
2309 lpNewRequest->next = lpWorkQueueTail;
2310 if (lpWorkQueueTail)
2311 lpWorkQueueTail->prev = lpNewRequest;
2312 lpWorkQueueTail = lpNewRequest;
2313 if (!lpHeadWorkQueue)
2314 lpHeadWorkQueue = lpWorkQueueTail;
2316 LeaveCriticalSection(&csQueue);
2318 bSuccess = TRUE;
2319 InterlockedIncrement(&dwNumJobs);
2322 return bSuccess;
2326 /***********************************************************************
2327 * INTERNET_GetWorkRequest (internal)
2329 * Retrieves work request from queue
2331 * RETURNS
2334 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2336 BOOL bSuccess = FALSE;
2337 LPWORKREQUEST lpRequest = NULL;
2339 TRACE("\n");
2341 EnterCriticalSection(&csQueue);
2343 if (lpHeadWorkQueue)
2345 lpRequest = lpHeadWorkQueue;
2346 lpHeadWorkQueue = lpHeadWorkQueue->prev;
2347 if (lpRequest == lpWorkQueueTail)
2348 lpWorkQueueTail = lpHeadWorkQueue;
2351 LeaveCriticalSection(&csQueue);
2353 if (lpRequest)
2355 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2356 HeapFree(GetProcessHeap(), 0, lpRequest);
2357 bSuccess = TRUE;
2358 InterlockedDecrement(&dwNumJobs);
2361 return bSuccess;
2365 /***********************************************************************
2366 * INTERNET_AsyncCall (internal)
2368 * Retrieves work request from queue
2370 * RETURNS
2373 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2375 HANDLE hThread;
2376 DWORD dwTID;
2377 BOOL bSuccess = FALSE;
2379 TRACE("\n");
2381 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2383 InterlockedIncrement(&dwNumIdleThreads);
2385 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2386 !(hThread = CreateThread(NULL, 0,
2387 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2389 InterlockedDecrement(&dwNumThreads);
2390 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2391 goto lerror;
2394 TRACE("Created new thread\n");
2397 bSuccess = TRUE;
2398 INTERNET_InsertWorkRequest(lpWorkRequest);
2399 SetEvent(hWorkEvent);
2401 lerror:
2403 return bSuccess;
2407 /***********************************************************************
2408 * INTERNET_ExecuteWork (internal)
2410 * RETURNS
2413 VOID INTERNET_ExecuteWork()
2415 WORKREQUEST workRequest;
2417 TRACE("\n");
2419 if (!INTERNET_GetWorkRequest(&workRequest))
2420 return;
2422 if (TRACE_ON(wininet)) {
2423 static const wininet_flag_info work_request_types[] = {
2424 #define FE(x) { x, #x }
2425 FE(FTPPUTFILEA),
2426 FE(FTPSETCURRENTDIRECTORYA),
2427 FE(FTPCREATEDIRECTORYA),
2428 FE(FTPFINDFIRSTFILEA),
2429 FE(FTPGETCURRENTDIRECTORYA),
2430 FE(FTPOPENFILEA),
2431 FE(FTPGETFILEA),
2432 FE(FTPDELETEFILEA),
2433 FE(FTPREMOVEDIRECTORYA),
2434 FE(FTPRENAMEFILEA),
2435 FE(INTERNETFINDNEXTA),
2436 FE(HTTPSENDREQUESTA),
2437 FE(HTTPOPENREQUESTA),
2438 FE(SENDCALLBACK),
2439 FE(INTERNETOPENURLA)
2440 #undef FE
2442 int i;
2443 const char *val = "Unknown";
2445 for (i = 0; i < (sizeof(work_request_types) / sizeof(work_request_types[0])); i++) {
2446 if (work_request_types[i].val == workRequest.asyncall) {
2447 val = work_request_types[i].name;
2448 break;
2452 TRACE("Got work %d (%s)\n", workRequest.asyncall, val);
2454 switch (workRequest.asyncall)
2456 case FTPPUTFILEA:
2458 struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
2460 FTP_FtpPutFileA(workRequest.handle, req->lpszLocalFile,
2461 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2463 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2464 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2466 break;
2468 case FTPSETCURRENTDIRECTORYA:
2470 struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
2472 req = &workRequest.u.FtpSetCurrentDirectoryA;
2473 FTP_FtpSetCurrentDirectoryA(workRequest.handle, req->lpszDirectory);
2474 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2476 break;
2478 case FTPCREATEDIRECTORYA:
2480 struct WORKREQ_FTPCREATEDIRECTORYA *req;
2482 req = &workRequest.u.FtpCreateDirectoryA;
2483 FTP_FtpCreateDirectoryA(workRequest.handle, req->lpszDirectory);
2484 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2486 break;
2488 case FTPFINDFIRSTFILEA:
2490 struct WORKREQ_FTPFINDFIRSTFILEA *req;
2492 req = &workRequest.u.FtpFindFirstFileA;
2493 FTP_FtpFindFirstFileA(workRequest.handle, req->lpszSearchFile,
2494 req->lpFindFileData, req->dwFlags, req->dwContext);
2495 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2497 break;
2499 case FTPGETCURRENTDIRECTORYA:
2501 struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
2503 req = &workRequest.u.FtpGetCurrentDirectoryA;
2504 FTP_FtpGetCurrentDirectoryA(workRequest.handle,
2505 req->lpszDirectory, req->lpdwDirectory);
2507 break;
2509 case FTPOPENFILEA:
2511 struct WORKREQ_FTPOPENFILEA *req = &workRequest.u.FtpOpenFileA;
2513 FTP_FtpOpenFileA(workRequest.handle, req->lpszFilename,
2514 req->dwAccess, req->dwFlags, req->dwContext);
2515 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2517 break;
2519 case FTPGETFILEA:
2521 struct WORKREQ_FTPGETFILEA *req = &workRequest.u.FtpGetFileA;
2523 FTP_FtpGetFileA(workRequest.handle, req->lpszRemoteFile,
2524 req->lpszNewFile, req->fFailIfExists,
2525 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2526 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2527 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2529 break;
2531 case FTPDELETEFILEA:
2533 struct WORKREQ_FTPDELETEFILEA *req = &workRequest.u.FtpDeleteFileA;
2535 FTP_FtpDeleteFileA(workRequest.handle, req->lpszFilename);
2536 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2538 break;
2540 case FTPREMOVEDIRECTORYA:
2542 struct WORKREQ_FTPREMOVEDIRECTORYA *req;
2544 req = &workRequest.u.FtpRemoveDirectoryA;
2545 FTP_FtpRemoveDirectoryA(workRequest.handle, req->lpszDirectory);
2546 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2548 break;
2550 case FTPRENAMEFILEA:
2552 struct WORKREQ_FTPRENAMEFILEA *req = &workRequest.u.FtpRenameFileA;
2554 FTP_FtpRenameFileA(workRequest.handle, req->lpszSrcFile, req->lpszDestFile);
2555 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2556 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2558 break;
2560 case INTERNETFINDNEXTA:
2562 struct WORKREQ_INTERNETFINDNEXTA *req;
2564 req = &workRequest.u.InternetFindNextA;
2565 INTERNET_FindNextFileA(workRequest.handle, req->lpFindFileData);
2567 break;
2569 case HTTPSENDREQUESTA:
2571 struct WORKREQ_HTTPSENDREQUESTA *req = &workRequest.u.HttpSendRequestA;
2573 HTTP_HttpSendRequestA(workRequest.handle, req->lpszHeader,
2574 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2576 HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2578 break;
2580 case HTTPOPENREQUESTA:
2582 struct WORKREQ_HTTPOPENREQUESTA *req = &workRequest.u.HttpOpenRequestA;
2584 HTTP_HttpOpenRequestA(workRequest.handle, req->lpszVerb,
2585 req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2586 req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2588 HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2589 HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2590 HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2591 HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2593 break;
2595 case SENDCALLBACK:
2597 struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2599 SendAsyncCallbackInt(workRequest.handle, req->hHttpSession,
2600 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2601 req->dwStatusInfoLength);
2603 break;
2605 case INTERNETOPENURLA:
2607 struct WORKREQ_INTERNETOPENURLA *req = &workRequest.u.InternetOpenUrlA;
2609 INTERNET_InternetOpenUrlA(workRequest.handle, req->lpszUrl,
2610 req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2611 HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2612 HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2614 break;
2619 /***********************************************************************
2620 * INTERNET_GetResponseBuffer
2622 * RETURNS
2625 LPSTR INTERNET_GetResponseBuffer()
2627 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2628 TRACE("\n");
2629 return lpwite->response;
2632 /***********************************************************************
2633 * INTERNET_GetNextLine (internal)
2635 * Parse next line in directory string listing
2637 * RETURNS
2638 * Pointer to beginning of next line
2639 * NULL on failure
2643 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
2645 struct timeval tv;
2646 fd_set infd;
2647 BOOL bSuccess = FALSE;
2648 INT nRecv = 0;
2650 TRACE("\n");
2652 FD_ZERO(&infd);
2653 FD_SET(nSocket, &infd);
2654 tv.tv_sec=RESPONSE_TIMEOUT;
2655 tv.tv_usec=0;
2657 while (nRecv < *dwBuffer)
2659 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2661 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2663 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2664 goto lend;
2667 if (lpszBuffer[nRecv] == '\n')
2669 bSuccess = TRUE;
2670 break;
2672 if (lpszBuffer[nRecv] != '\r')
2673 nRecv++;
2675 else
2677 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2678 goto lend;
2682 lend:
2683 if (bSuccess)
2685 lpszBuffer[nRecv] = '\0';
2686 *dwBuffer = nRecv - 1;
2687 TRACE(":%d %s\n", nRecv, lpszBuffer);
2688 return lpszBuffer;
2690 else
2692 return NULL;
2696 /***********************************************************************
2699 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2700 LPDWORD lpdwNumberOfBytesAvailble,
2701 DWORD dwFlags, DWORD dwConext)
2703 LPWININETHTTPREQA lpwhr;
2704 INT retval = -1;
2705 char buffer[4048];
2708 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hFile );
2709 if (NULL == lpwhr)
2711 SetLastError(ERROR_NO_MORE_FILES);
2712 return FALSE;
2715 TRACE("--> %p %i\n",lpwhr,lpwhr->hdr.htype);
2717 switch (lpwhr->hdr.htype)
2719 case WH_HHTTPREQ:
2720 if (!NETCON_recv(&lpwhr->netConnection, buffer,
2721 4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2723 SetLastError(ERROR_NO_MORE_FILES);
2724 retval = FALSE;
2726 else
2727 retval = TRUE;
2728 break;
2730 default:
2731 FIXME("unsupported file type\n");
2732 break;
2735 TRACE("<-- %i\n",retval);
2736 return (retval+1);
2740 /***********************************************************************
2743 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2744 *lphLockReqHandle)
2746 FIXME("STUB\n");
2747 return FALSE;
2750 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2752 FIXME("STUB\n");
2753 return FALSE;
2757 /***********************************************************************
2758 * InternetAutodial
2760 * On windows this function is supposed to dial the default internet
2761 * connection. We don't want to have Wine dial out to the internet so
2762 * we return TRUE by default. It might be nice to check if we are connected.
2764 * RETURNS
2765 * TRUE on success
2766 * FALSE on failure
2769 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2771 FIXME("STUB\n");
2773 /* Tell that we are connected to the internet. */
2774 return TRUE;
2777 /***********************************************************************
2778 * InternetAutodialHangup
2780 * Hangs up an connection made with InternetAutodial
2782 * PARAM
2783 * dwReserved
2784 * RETURNS
2785 * TRUE on success
2786 * FALSE on failure
2789 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2791 FIXME("STUB\n");
2793 /* we didn't dial, we don't disconnect */
2794 return TRUE;
2797 /***********************************************************************
2799 * InternetCombineUrlA
2801 * Combine a base URL with a relative URL
2803 * RETURNS
2804 * TRUE on success
2805 * FALSE on failure
2809 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2810 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2811 DWORD dwFlags)
2813 HRESULT hr=S_OK;
2815 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2817 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2818 dwFlags ^= ICU_NO_ENCODE;
2819 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2821 return (hr==S_OK);
2824 /***********************************************************************
2826 * InternetCombineUrlW
2828 * Combine a base URL with a relative URL
2830 * RETURNS
2831 * TRUE on success
2832 * FALSE on failure
2836 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2837 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2838 DWORD dwFlags)
2840 HRESULT hr=S_OK;
2842 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2844 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2845 dwFlags ^= ICU_NO_ENCODE;
2846 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2848 return (hr==S_OK);
2851 /***********************************************************************
2853 * InternetCreateUrlA
2855 * RETURNS
2856 * TRUE on success
2857 * FALSE on failure
2860 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2861 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2863 FIXME("\n");
2864 return FALSE;
2867 /***********************************************************************
2869 * InternetCreateUrlW
2871 * RETURNS
2872 * TRUE on success
2873 * FALSE on failure
2876 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
2877 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
2879 FIXME("\n");
2880 return FALSE;