b0357a2b55ceeecbeff44554f89742775b2586df
[reactos.git] / reactos / dll / win32 / wininet / internet.c
1 /*
2 * Wininet
3 *
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 Jaco Greeff
7 * Copyright 2002 TransGaming Technologies Inc.
8 * Copyright 2004 Mike McCormack for CodeWeavers
9 *
10 * Ulrich Czekalla
11 * Aric Stewart
12 * David Hammerton
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #define MAXHOSTNAME 100 /* from http.c */
33
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
49 #include <assert.h>
50
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #include "wininet.h"
56 #include "winineti.h"
57 #include "winnls.h"
58 #include "wine/debug.h"
59 #include "winerror.h"
60 #define NO_SHLWAPI_STREAM
61 #include "shlwapi.h"
62 #include "wincrypt.h"
63
64 #include "wine/exception.h"
65
66 #include "internet.h"
67 #include "resource.h"
68
69 #include "wine/unicode.h"
70 #define CP_UNIXCP CP_THREAD_ACP
71
72 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
73
74 #define RESPONSE_TIMEOUT 30
75
76 typedef struct
77 {
78 DWORD dwError;
79 CHAR response[MAX_REPLY_LEN];
80 } WITHREADERROR, *LPWITHREADERROR;
81
82 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr);
83 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
84 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext);
85
86 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
87 static HMODULE WININET_hModule;
88
89 #define HANDLE_CHUNK_SIZE 0x10
90
91 static CRITICAL_SECTION WININET_cs;
92 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
93 {
94 0, 0, &WININET_cs,
95 { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
96 0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
97 };
98 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
99
100 static LPWININETHANDLEHEADER *WININET_Handles;
101 static UINT WININET_dwNextHandle;
102 static UINT WININET_dwMaxHandles;
103
104 HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info )
105 {
106 LPWININETHANDLEHEADER *p;
107 UINT handle = 0, num;
108
109 list_init( &info->children );
110
111 EnterCriticalSection( &WININET_cs );
112 if( !WININET_dwMaxHandles )
113 {
114 num = HANDLE_CHUNK_SIZE;
115 p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
116 sizeof (UINT)* num);
117 if( !p )
118 goto end;
119 WININET_Handles = p;
120 WININET_dwMaxHandles = num;
121 }
122 if( WININET_dwMaxHandles == WININET_dwNextHandle )
123 {
124 num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
125 p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
126 WININET_Handles, sizeof (UINT)* num);
127 if( !p )
128 goto end;
129 WININET_Handles = p;
130 WININET_dwMaxHandles = num;
131 }
132
133 handle = WININET_dwNextHandle;
134 if( WININET_Handles[handle] )
135 ERR("handle isn't free but should be\n");
136 WININET_Handles[handle] = WININET_AddRef( info );
137
138 while( WININET_Handles[WININET_dwNextHandle] &&
139 (WININET_dwNextHandle < WININET_dwMaxHandles ) )
140 WININET_dwNextHandle++;
141
142 end:
143 LeaveCriticalSection( &WININET_cs );
144
145 return info->hInternet = (HINTERNET) (handle+1);
146 }
147
148 LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info )
149 {
150 info->dwRefCount++;
151 TRACE("%p -> refcount = %d\n", info, info->dwRefCount );
152 return info;
153 }
154
155 LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet )
156 {
157 LPWININETHANDLEHEADER info = NULL;
158 UINT handle = (UINT) hinternet;
159
160 EnterCriticalSection( &WININET_cs );
161
162 if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) &&
163 WININET_Handles[handle-1] )
164 info = WININET_AddRef( WININET_Handles[handle-1] );
165
166 LeaveCriticalSection( &WININET_cs );
167
168 TRACE("handle %d -> %p\n", handle, info);
169
170 return info;
171 }
172
173 BOOL WININET_Release( LPWININETHANDLEHEADER info )
174 {
175 info->dwRefCount--;
176 TRACE( "object %p refcount = %d\n", info, info->dwRefCount );
177 if( !info->dwRefCount )
178 {
179 if ( info->close_connection )
180 {
181 TRACE( "closing connection %p\n", info);
182 info->close_connection( info );
183 }
184 INTERNET_SendCallback(info, info->dwContext,
185 INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
186 sizeof(HINTERNET));
187 TRACE( "destroying object %p\n", info);
188 if ( info->htype != WH_HINIT )
189 list_remove( &info->entry );
190 info->destroy( info );
191 }
192 return TRUE;
193 }
194
195 BOOL WININET_FreeHandle( HINTERNET hinternet )
196 {
197 BOOL ret = FALSE;
198 UINT handle = (UINT) hinternet;
199 LPWININETHANDLEHEADER info = NULL, child, next;
200
201 EnterCriticalSection( &WININET_cs );
202
203 if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
204 {
205 handle--;
206 if( WININET_Handles[handle] )
207 {
208 info = WININET_Handles[handle];
209 TRACE( "destroying handle %d for object %p\n", handle+1, info);
210 WININET_Handles[handle] = NULL;
211 ret = TRUE;
212 }
213 }
214
215 LeaveCriticalSection( &WININET_cs );
216
217 /* As on native when the equivalent of WININET_Release is called, the handle
218 * is already invalid, but if a new handle is created at this time it does
219 * not yet get assigned the freed handle number */
220 if( info )
221 {
222 /* Free all children as native does */
223 LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, WININETHANDLEHEADER, entry )
224 {
225 TRACE( "freeing child handle %d for parent handle %d\n",
226 (UINT)child->hInternet, handle+1);
227 WININET_FreeHandle( child->hInternet );
228 }
229 WININET_Release( info );
230 }
231
232 EnterCriticalSection( &WININET_cs );
233
234 if( WININET_dwNextHandle > handle && !WININET_Handles[handle] )
235 WININET_dwNextHandle = handle;
236
237 LeaveCriticalSection( &WININET_cs );
238
239 return ret;
240 }
241
242 /***********************************************************************
243 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
244 *
245 * PARAMS
246 * hinstDLL [I] handle to the DLL's instance
247 * fdwReason [I]
248 * lpvReserved [I] reserved, must be NULL
249 *
250 * RETURNS
251 * Success: TRUE
252 * Failure: FALSE
253 */
254
255 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
256 {
257 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
258
259 switch (fdwReason) {
260 case DLL_PROCESS_ATTACH:
261
262 g_dwTlsErrIndex = TlsAlloc();
263
264 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
265 return FALSE;
266
267 URLCacheContainers_CreateDefaults();
268
269 WININET_hModule = (HMODULE)hinstDLL;
270
271 case DLL_THREAD_ATTACH:
272 break;
273
274 case DLL_THREAD_DETACH:
275 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
276 {
277 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
278 HeapFree(GetProcessHeap(), 0, lpwite);
279 }
280 break;
281
282 case DLL_PROCESS_DETACH:
283
284 URLCacheContainers_DeleteAll();
285
286 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
287 {
288 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
289 TlsFree(g_dwTlsErrIndex);
290 }
291 break;
292 }
293
294 return TRUE;
295 }
296
297
298 /***********************************************************************
299 * InternetInitializeAutoProxyDll (WININET.@)
300 *
301 * Setup the internal proxy
302 *
303 * PARAMETERS
304 * dwReserved
305 *
306 * RETURNS
307 * FALSE on failure
308 *
309 */
310 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
311 {
312 FIXME("STUB\n");
313 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
314 return FALSE;
315 }
316
317 /***********************************************************************
318 * DetectAutoProxyUrl (WININET.@)
319 *
320 * Auto detect the proxy url
321 *
322 * RETURNS
323 * FALSE on failure
324 *
325 */
326 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
327 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
328 {
329 FIXME("STUB\n");
330 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
331 return FALSE;
332 }
333
334
335 /***********************************************************************
336 * INTERNET_ConfigureProxyFromReg
337 *
338 * FIXME:
339 * The proxy may be specified in the form 'http=proxy.my.org'
340 * Presumably that means there can be ftp=ftpproxy.my.org too.
341 */
342 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOW lpwai )
343 {
344 HKEY key;
345 DWORD r, keytype, len, enabled;
346 LPCSTR lpszInternetSettings =
347 "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
348 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
349
350 r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
351 if ( r != ERROR_SUCCESS )
352 return FALSE;
353
354 len = sizeof enabled;
355 r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
356 (BYTE*)&enabled, &len);
357 if( (r == ERROR_SUCCESS) && enabled )
358 {
359 TRACE("Proxy is enabled.\n");
360
361 /* figure out how much memory the proxy setting takes */
362 r = RegQueryValueExW( key, szProxyServer, NULL, &keytype,
363 NULL, &len);
364 if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
365 {
366 LPWSTR szProxy, p;
367 static const WCHAR szHttp[] = {'h','t','t','p','=',0};
368
369 szProxy=HeapAlloc( GetProcessHeap(), 0, len );
370 RegQueryValueExW( key, szProxyServer, NULL, &keytype,
371 (BYTE*)szProxy, &len);
372
373 /* find the http proxy, and strip away everything else */
374 p = strstrW( szProxy, szHttp );
375 if( p )
376 {
377 p += lstrlenW(szHttp);
378 lstrcpyW( szProxy, p );
379 }
380 p = strchrW( szProxy, ' ' );
381 if( p )
382 *p = 0;
383
384 lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
385 lpwai->lpszProxy = szProxy;
386
387 TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
388 }
389 else
390 ERR("Couldn't read proxy server settings.\n");
391 }
392 else
393 TRACE("Proxy is not enabled.\n");
394 RegCloseKey(key);
395
396 return enabled;
397 }
398
399 /***********************************************************************
400 * dump_INTERNET_FLAGS
401 *
402 * Helper function to TRACE the internet flags.
403 *
404 * RETURNS
405 * None
406 *
407 */
408 static void dump_INTERNET_FLAGS(DWORD dwFlags)
409 {
410 #define FE(x) { x, #x }
411 static const wininet_flag_info flag[] = {
412 FE(INTERNET_FLAG_RELOAD),
413 FE(INTERNET_FLAG_RAW_DATA),
414 FE(INTERNET_FLAG_EXISTING_CONNECT),
415 FE(INTERNET_FLAG_ASYNC),
416 FE(INTERNET_FLAG_PASSIVE),
417 FE(INTERNET_FLAG_NO_CACHE_WRITE),
418 FE(INTERNET_FLAG_MAKE_PERSISTENT),
419 FE(INTERNET_FLAG_FROM_CACHE),
420 FE(INTERNET_FLAG_SECURE),
421 FE(INTERNET_FLAG_KEEP_CONNECTION),
422 FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
423 FE(INTERNET_FLAG_READ_PREFETCH),
424 FE(INTERNET_FLAG_NO_COOKIES),
425 FE(INTERNET_FLAG_NO_AUTH),
426 FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
427 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
428 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
429 FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
430 FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
431 FE(INTERNET_FLAG_RESYNCHRONIZE),
432 FE(INTERNET_FLAG_HYPERLINK),
433 FE(INTERNET_FLAG_NO_UI),
434 FE(INTERNET_FLAG_PRAGMA_NOCACHE),
435 FE(INTERNET_FLAG_CACHE_ASYNC),
436 FE(INTERNET_FLAG_FORMS_SUBMIT),
437 FE(INTERNET_FLAG_NEED_FILE),
438 FE(INTERNET_FLAG_TRANSFER_ASCII),
439 FE(INTERNET_FLAG_TRANSFER_BINARY)
440 };
441 #undef FE
442 int i;
443
444 for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
445 if (flag[i].val & dwFlags) {
446 TRACE(" %s", flag[i].name);
447 dwFlags &= ~flag[i].val;
448 }
449 }
450 if (dwFlags)
451 TRACE(" Unknown flags (%08x)\n", dwFlags);
452 else
453 TRACE("\n");
454 }
455
456 /***********************************************************************
457 * InternetOpenW (WININET.@)
458 *
459 * Per-application initialization of wininet
460 *
461 * RETURNS
462 * HINTERNET on success
463 * NULL on failure
464 *
465 */
466 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
467 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
468 {
469 LPWININETAPPINFOW lpwai = NULL;
470 HINTERNET handle = NULL;
471
472 if (TRACE_ON(wininet)) {
473 #define FE(x) { x, #x }
474 static const wininet_flag_info access_type[] = {
475 FE(INTERNET_OPEN_TYPE_PRECONFIG),
476 FE(INTERNET_OPEN_TYPE_DIRECT),
477 FE(INTERNET_OPEN_TYPE_PROXY),
478 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
479 };
480 #undef FE
481 DWORD i;
482 const char *access_type_str = "Unknown";
483
484 TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
485 debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
486 for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
487 if (access_type[i].val == dwAccessType) {
488 access_type_str = access_type[i].name;
489 break;
490 }
491 }
492 TRACE(" access type : %s\n", access_type_str);
493 TRACE(" flags :");
494 dump_INTERNET_FLAGS(dwFlags);
495 }
496
497 /* Clear any error information */
498 INTERNET_SetLastError(0);
499
500 lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW));
501 if (NULL == lpwai)
502 {
503 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
504 goto lend;
505 }
506
507 lpwai->hdr.htype = WH_HINIT;
508 lpwai->hdr.dwFlags = dwFlags;
509 lpwai->hdr.dwRefCount = 1;
510 lpwai->hdr.close_connection = NULL;
511 lpwai->hdr.destroy = INTERNET_CloseHandle;
512 lpwai->dwAccessType = dwAccessType;
513 lpwai->lpszProxyUsername = NULL;
514 lpwai->lpszProxyPassword = NULL;
515
516 handle = WININET_AllocHandle( &lpwai->hdr );
517 if( !handle )
518 {
519 HeapFree( GetProcessHeap(), 0, lpwai );
520 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
521 goto lend;
522 }
523
524 if (NULL != lpszAgent)
525 {
526 lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
527 (strlenW(lpszAgent)+1)*sizeof(WCHAR));
528 if (lpwai->lpszAgent)
529 lstrcpyW( lpwai->lpszAgent, lpszAgent );
530 }
531 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
532 INTERNET_ConfigureProxyFromReg( lpwai );
533 else if (NULL != lpszProxy)
534 {
535 lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
536 (strlenW(lpszProxy)+1)*sizeof(WCHAR));
537 if (lpwai->lpszProxy)
538 lstrcpyW( lpwai->lpszProxy, lpszProxy );
539 }
540
541 if (NULL != lpszProxyBypass)
542 {
543 lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
544 (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
545 if (lpwai->lpszProxyBypass)
546 lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
547 }
548
549 lend:
550 if( lpwai )
551 WININET_Release( &lpwai->hdr );
552
553 TRACE("returning %p\n", lpwai);
554
555 return handle;
556 }
557
558
559 /***********************************************************************
560 * InternetOpenA (WININET.@)
561 *
562 * Per-application initialization of wininet
563 *
564 * RETURNS
565 * HINTERNET on success
566 * NULL on failure
567 *
568 */
569 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
570 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
571 {
572 HINTERNET rc = (HINTERNET)NULL;
573 INT len;
574 WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
575
576 TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
577 dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
578
579 if( lpszAgent )
580 {
581 len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
582 szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
583 MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
584 }
585
586 if( lpszProxy )
587 {
588 len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
589 szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
590 MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
591 }
592
593 if( lpszProxyBypass )
594 {
595 len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
596 szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
597 MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
598 }
599
600 rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
601
602 HeapFree(GetProcessHeap(), 0, szAgent);
603 HeapFree(GetProcessHeap(), 0, szProxy);
604 HeapFree(GetProcessHeap(), 0, szBypass);
605
606 return rc;
607 }
608
609 /***********************************************************************
610 * InternetGetLastResponseInfoA (WININET.@)
611 *
612 * Return last wininet error description on the calling thread
613 *
614 * RETURNS
615 * TRUE on success of writing to buffer
616 * FALSE on failure
617 *
618 */
619 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
620 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
621 {
622 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
623
624 TRACE("\n");
625
626 if (lpwite)
627 {
628 *lpdwError = lpwite->dwError;
629 if (lpwite->dwError)
630 {
631 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
632 *lpdwBufferLength = strlen(lpszBuffer);
633 }
634 else
635 *lpdwBufferLength = 0;
636 }
637 else
638 {
639 *lpdwError = 0;
640 *lpdwBufferLength = 0;
641 }
642
643 return TRUE;
644 }
645
646 /***********************************************************************
647 * InternetGetLastResponseInfoW (WININET.@)
648 *
649 * Return last wininet error description on the calling thread
650 *
651 * RETURNS
652 * TRUE on success of writing to buffer
653 * FALSE on failure
654 *
655 */
656 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
657 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
658 {
659 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
660
661 TRACE("\n");
662
663 if (lpwite)
664 {
665 *lpdwError = lpwite->dwError;
666 if (lpwite->dwError)
667 {
668 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
669 *lpdwBufferLength = lstrlenW(lpszBuffer);
670 }
671 else
672 *lpdwBufferLength = 0;
673 }
674 else
675 {
676 *lpdwError = 0;
677 *lpdwBufferLength = 0;
678 }
679
680 return TRUE;
681 }
682
683 /***********************************************************************
684 * InternetGetConnectedState (WININET.@)
685 *
686 * Return connected state
687 *
688 * RETURNS
689 * TRUE if connected
690 * if lpdwStatus is not null, return the status (off line,
691 * modem, lan...) in it.
692 * FALSE if not connected
693 */
694 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
695 {
696 TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
697
698 if (lpdwStatus) {
699 FIXME("always returning LAN connection.\n");
700 *lpdwStatus = INTERNET_CONNECTION_LAN;
701 }
702 return TRUE;
703 }
704
705
706 /***********************************************************************
707 * InternetGetConnectedStateExW (WININET.@)
708 *
709 * Return connected state
710 *
711 * PARAMS
712 *
713 * lpdwStatus [O] Flags specifying the status of the internet connection.
714 * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
715 * dwNameLen [I] Size of the buffer, in characters.
716 * dwReserved [I] Reserved. Must be set to 0.
717 *
718 * RETURNS
719 * TRUE if connected
720 * if lpdwStatus is not null, return the status (off line,
721 * modem, lan...) in it.
722 * FALSE if not connected
723 *
724 * NOTES
725 * If the system has no available network connections, an empty string is
726 * stored in lpszConnectionName. If there is a LAN connection, a localized
727 * "LAN Connection" string is stored. Presumably, if only a dial-up
728 * connection is available then the name of the dial-up connection is
729 * returned. Why any application, other than the "Internet Settings" CPL,
730 * would want to use this function instead of the simpler InternetGetConnectedStateW
731 * function is beyond me.
732 */
733 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
734 DWORD dwNameLen, DWORD dwReserved)
735 {
736 TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
737
738 /* Must be zero */
739 if(dwReserved)
740 return FALSE;
741
742 if (lpdwStatus) {
743 FIXME("always returning LAN connection.\n");
744 *lpdwStatus = INTERNET_CONNECTION_LAN;
745 }
746 return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
747 }
748
749
750 /***********************************************************************
751 * InternetGetConnectedStateExA (WININET.@)
752 */
753 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
754 DWORD dwNameLen, DWORD dwReserved)
755 {
756 LPWSTR lpwszConnectionName = NULL;
757 BOOL rc;
758
759 TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
760
761 if (lpszConnectionName && dwNameLen > 0)
762 lpwszConnectionName= HeapAlloc(GetProcessHeap(), 0, dwNameLen * sizeof(WCHAR));
763
764 rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
765 dwReserved);
766 if (rc && lpwszConnectionName)
767 {
768 WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
769 dwNameLen, NULL, NULL);
770
771 HeapFree(GetProcessHeap(),0,lpwszConnectionName);
772 }
773
774 return rc;
775 }
776
777
778 /***********************************************************************
779 * InternetConnectW (WININET.@)
780 *
781 * Open a ftp, gopher or http session
782 *
783 * RETURNS
784 * HINTERNET a session handle on success
785 * NULL on failure
786 *
787 */
788 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
789 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
790 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
791 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
792 {
793 LPWININETAPPINFOW hIC;
794 HINTERNET rc = NULL;
795
796 TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName),
797 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
798 dwService, dwFlags, dwContext);
799
800 if (!lpszServerName)
801 {
802 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
803 return NULL;
804 }
805
806 /* Clear any error information */
807 INTERNET_SetLastError(0);
808 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
809 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
810 {
811 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
812 goto lend;
813 }
814
815 switch (dwService)
816 {
817 case INTERNET_SERVICE_FTP:
818 rc = FTP_Connect(hIC, lpszServerName, nServerPort,
819 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
820 break;
821
822 case INTERNET_SERVICE_HTTP:
823 rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
824 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
825 break;
826
827 case INTERNET_SERVICE_GOPHER:
828 default:
829 break;
830 }
831 lend:
832 if( hIC )
833 WININET_Release( &hIC->hdr );
834
835 TRACE("returning %p\n", rc);
836 return rc;
837 }
838
839
840 /***********************************************************************
841 * InternetConnectA (WININET.@)
842 *
843 * Open a ftp, gopher or http session
844 *
845 * RETURNS
846 * HINTERNET a session handle on success
847 * NULL on failure
848 *
849 */
850 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
851 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
852 LPCSTR lpszUserName, LPCSTR lpszPassword,
853 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
854 {
855 HINTERNET rc = (HINTERNET)NULL;
856 INT len = 0;
857 LPWSTR szServerName = NULL;
858 LPWSTR szUserName = NULL;
859 LPWSTR szPassword = NULL;
860
861 if (lpszServerName)
862 {
863 len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
864 szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
865 MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
866 }
867 if (lpszUserName)
868 {
869 len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
870 szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
871 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
872 }
873 if (lpszPassword)
874 {
875 len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
876 szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
877 MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
878 }
879
880
881 rc = InternetConnectW(hInternet, szServerName, nServerPort,
882 szUserName, szPassword, dwService, dwFlags, dwContext);
883
884 HeapFree(GetProcessHeap(), 0, szServerName);
885 HeapFree(GetProcessHeap(), 0, szUserName);
886 HeapFree(GetProcessHeap(), 0, szPassword);
887 return rc;
888 }
889
890
891 /***********************************************************************
892 * InternetFindNextFileA (WININET.@)
893 *
894 * Continues a file search from a previous call to FindFirstFile
895 *
896 * RETURNS
897 * TRUE on success
898 * FALSE on failure
899 *
900 */
901 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
902 {
903 BOOL ret;
904 WIN32_FIND_DATAW fd;
905
906 ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
907 if(lpvFindData)
908 WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
909 return ret;
910 }
911
912 /***********************************************************************
913 * InternetFindNextFileW (WININET.@)
914 *
915 * Continues a file search from a previous call to FindFirstFile
916 *
917 * RETURNS
918 * TRUE on success
919 * FALSE on failure
920 *
921 */
922 static void AsyncFtpFindNextFileProc(WORKREQUEST *workRequest)
923 {
924 struct WORKREQ_FTPFINDNEXTW *req = &workRequest->u.FtpFindNextW;
925 LPWININETFTPFINDNEXTW lpwh = (LPWININETFTPFINDNEXTW) workRequest->hdr;
926
927 TRACE("%p\n", lpwh);
928
929 FTP_FindNextFileW(lpwh, req->lpFindFileData);
930 }
931
932 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
933 {
934 LPWININETAPPINFOW hIC = NULL;
935 LPWININETFTPFINDNEXTW lpwh;
936 BOOL bSuccess = FALSE;
937
938 TRACE("\n");
939
940 lpwh = (LPWININETFTPFINDNEXTW) WININET_GetObject( hFind );
941 if (NULL == lpwh || lpwh->hdr.htype != WH_HFTPFINDNEXT)
942 {
943 FIXME("Only FTP supported\n");
944 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
945 goto lend;
946 }
947
948 hIC = lpwh->lpFtpSession->lpAppInfo;
949 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
950 {
951 WORKREQUEST workRequest;
952 struct WORKREQ_FTPFINDNEXTW *req;
953
954 workRequest.asyncproc = AsyncFtpFindNextFileProc;
955 workRequest.hdr = WININET_AddRef( &lpwh->hdr );
956 req = &workRequest.u.FtpFindNextW;
957 req->lpFindFileData = lpvFindData;
958
959 bSuccess = INTERNET_AsyncCall(&workRequest);
960 }
961 else
962 {
963 bSuccess = FTP_FindNextFileW(lpwh, lpvFindData);
964 }
965 lend:
966 if( lpwh )
967 WININET_Release( &lpwh->hdr );
968 return bSuccess;
969 }
970
971 /***********************************************************************
972 * INTERNET_CloseHandle (internal)
973 *
974 * Close internet handle
975 *
976 * RETURNS
977 * Void
978 *
979 */
980 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr)
981 {
982 LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
983
984 TRACE("%p\n",lpwai);
985
986 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
987 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
988 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
989 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
990 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
991 HeapFree(GetProcessHeap(), 0, lpwai);
992 }
993
994
995 /***********************************************************************
996 * InternetCloseHandle (WININET.@)
997 *
998 * Generic close handle function
999 *
1000 * RETURNS
1001 * TRUE on success
1002 * FALSE on failure
1003 *
1004 */
1005 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1006 {
1007 LPWININETHANDLEHEADER lpwh;
1008
1009 TRACE("%p\n",hInternet);
1010
1011 lpwh = WININET_GetObject( hInternet );
1012 if (NULL == lpwh)
1013 {
1014 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1015 return FALSE;
1016 }
1017
1018 WININET_Release( lpwh );
1019 WININET_FreeHandle( hInternet );
1020
1021 return TRUE;
1022 }
1023
1024
1025 /***********************************************************************
1026 * ConvertUrlComponentValue (Internal)
1027 *
1028 * Helper function for InternetCrackUrlW
1029 *
1030 */
1031 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1032 LPWSTR lpwszComponent, DWORD dwwComponentLen,
1033 LPCSTR lpszStart, LPCWSTR lpwszStart)
1034 {
1035 TRACE("%p %d %p %d %p %p\n", lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
1036 if (*dwComponentLen != 0)
1037 {
1038 DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1039 if (*lppszComponent == NULL)
1040 {
1041 int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
1042 if (lpwszComponent)
1043 *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
1044 else
1045 *lppszComponent = NULL;
1046 *dwComponentLen = nASCIILength;
1047 }
1048 else
1049 {
1050 DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1051 WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1052 (*lppszComponent)[ncpylen]=0;
1053 *dwComponentLen = ncpylen;
1054 }
1055 }
1056 }
1057
1058
1059 /***********************************************************************
1060 * InternetCrackUrlA (WININET.@)
1061 *
1062 * See InternetCrackUrlW.
1063 */
1064 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1065 LPURL_COMPONENTSA lpUrlComponents)
1066 {
1067 DWORD nLength;
1068 URL_COMPONENTSW UCW;
1069 WCHAR* lpwszUrl;
1070
1071 TRACE("(%s %u %x %p)\n", debugstr_a(lpszUrl), dwUrlLength, dwFlags, lpUrlComponents);
1072
1073 if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1074 lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1075 {
1076 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1077 return FALSE;
1078 }
1079
1080 if(dwUrlLength<=0)
1081 dwUrlLength=-1;
1082 nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1083
1084 /* if dwUrlLength=-1 then nLength includes null but length to
1085 InternetCrackUrlW should not include it */
1086 if (dwUrlLength == -1) nLength--;
1087
1088 lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1089 MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1090
1091 memset(&UCW,0,sizeof(UCW));
1092 UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1093 if(lpUrlComponents->dwHostNameLength!=0)
1094 UCW.dwHostNameLength= lpUrlComponents->dwHostNameLength;
1095 if(lpUrlComponents->dwUserNameLength!=0)
1096 UCW.dwUserNameLength=lpUrlComponents->dwUserNameLength;
1097 if(lpUrlComponents->dwPasswordLength!=0)
1098 UCW.dwPasswordLength=lpUrlComponents->dwPasswordLength;
1099 if(lpUrlComponents->dwUrlPathLength!=0)
1100 UCW.dwUrlPathLength=lpUrlComponents->dwUrlPathLength;
1101 if(lpUrlComponents->dwSchemeLength!=0)
1102 UCW.dwSchemeLength=lpUrlComponents->dwSchemeLength;
1103 if(lpUrlComponents->dwExtraInfoLength!=0)
1104 UCW.dwExtraInfoLength=lpUrlComponents->dwExtraInfoLength;
1105 if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1106 {
1107 HeapFree(GetProcessHeap(), 0, lpwszUrl);
1108 return FALSE;
1109 }
1110
1111 ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1112 UCW.lpszHostName, UCW.dwHostNameLength,
1113 lpszUrl, lpwszUrl);
1114 ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1115 UCW.lpszUserName, UCW.dwUserNameLength,
1116 lpszUrl, lpwszUrl);
1117 ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1118 UCW.lpszPassword, UCW.dwPasswordLength,
1119 lpszUrl, lpwszUrl);
1120 ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1121 UCW.lpszUrlPath, UCW.dwUrlPathLength,
1122 lpszUrl, lpwszUrl);
1123 ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1124 UCW.lpszScheme, UCW.dwSchemeLength,
1125 lpszUrl, lpwszUrl);
1126 ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1127 UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1128 lpszUrl, lpwszUrl);
1129 lpUrlComponents->nScheme=UCW.nScheme;
1130 lpUrlComponents->nPort=UCW.nPort;
1131 HeapFree(GetProcessHeap(), 0, lpwszUrl);
1132
1133 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1134 debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1135 debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1136 debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1137 debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1138
1139 return TRUE;
1140 }
1141
1142 static const WCHAR url_schemes[][7] =
1143 {
1144 {'f','t','p',0},
1145 {'g','o','p','h','e','r',0},
1146 {'h','t','t','p',0},
1147 {'h','t','t','p','s',0},
1148 {'f','i','l','e',0},
1149 {'n','e','w','s',0},
1150 {'m','a','i','l','t','o',0},
1151 {'r','e','s',0},
1152 };
1153
1154 /***********************************************************************
1155 * GetInternetSchemeW (internal)
1156 *
1157 * Get scheme of url
1158 *
1159 * RETURNS
1160 * scheme on success
1161 * INTERNET_SCHEME_UNKNOWN on failure
1162 *
1163 */
1164 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1165 {
1166 int i;
1167
1168 TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1169
1170 if(lpszScheme==NULL)
1171 return INTERNET_SCHEME_UNKNOWN;
1172
1173 for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1174 if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
1175 return INTERNET_SCHEME_FIRST + i;
1176
1177 return INTERNET_SCHEME_UNKNOWN;
1178 }
1179
1180 /***********************************************************************
1181 * SetUrlComponentValueW (Internal)
1182 *
1183 * Helper function for InternetCrackUrlW
1184 *
1185 * PARAMS
1186 * lppszComponent [O] Holds the returned string
1187 * dwComponentLen [I] Holds the size of lppszComponent
1188 * [O] Holds the length of the string in lppszComponent without '\0'
1189 * lpszStart [I] Holds the string to copy from
1190 * len [I] Holds the length of lpszStart without '\0'
1191 *
1192 * RETURNS
1193 * TRUE on success
1194 * FALSE on failure
1195 *
1196 */
1197 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1198 {
1199 TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1200
1201 if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1202 return FALSE;
1203
1204 if (*dwComponentLen != 0 || *lppszComponent == NULL)
1205 {
1206 if (*lppszComponent == NULL)
1207 {
1208 *lppszComponent = (LPWSTR)lpszStart;
1209 *dwComponentLen = len;
1210 }
1211 else
1212 {
1213 DWORD ncpylen = min((*dwComponentLen)-1, len);
1214 memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1215 (*lppszComponent)[ncpylen] = '\0';
1216 *dwComponentLen = ncpylen;
1217 }
1218 }
1219
1220 return TRUE;
1221 }
1222
1223 /***********************************************************************
1224 * InternetCrackUrlW (WININET.@)
1225 *
1226 * Break up URL into its components
1227 *
1228 * RETURNS
1229 * TRUE on success
1230 * FALSE on failure
1231 */
1232 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1233 LPURL_COMPONENTSW lpUC)
1234 {
1235 /*
1236 * RFC 1808
1237 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1238 *
1239 */
1240 LPCWSTR lpszParam = NULL;
1241 BOOL bIsAbsolute = FALSE;
1242 LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1243 LPCWSTR lpszcp = NULL;
1244 LPWSTR lpszUrl_decode = NULL;
1245 DWORD dwUrlLength = dwUrlLength_orig;
1246 const WCHAR lpszSeparators[3]={';','?',0};
1247 const WCHAR lpszSlash[2]={'/',0};
1248
1249 TRACE("(%s %u %x %p)\n", debugstr_w(lpszUrl), dwUrlLength, dwFlags, lpUC);
1250
1251 if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1252 {
1253 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1254 return FALSE;
1255 }
1256 if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1257
1258 if (dwFlags & ICU_DECODE)
1259 {
1260 lpszUrl_decode=HeapAlloc( GetProcessHeap(), 0, dwUrlLength * sizeof (WCHAR) );
1261 if( InternetCanonicalizeUrlW(lpszUrl_orig, lpszUrl_decode, &dwUrlLength, dwFlags))
1262 {
1263 lpszUrl = lpszUrl_decode;
1264 }
1265 }
1266 lpszap = lpszUrl;
1267
1268 /* Determine if the URI is absolute. */
1269 while (*lpszap != '\0')
1270 {
1271 if (isalnumW(*lpszap))
1272 {
1273 lpszap++;
1274 continue;
1275 }
1276 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1277 {
1278 bIsAbsolute = TRUE;
1279 lpszcp = lpszap;
1280 }
1281 else
1282 {
1283 lpszcp = lpszUrl; /* Relative url */
1284 }
1285
1286 break;
1287 }
1288
1289 lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1290 lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1291
1292 /* Parse <params> */
1293 lpszParam = strpbrkW(lpszap, lpszSeparators);
1294 SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1295 lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1296
1297 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1298 {
1299 LPCWSTR lpszNetLoc;
1300
1301 /* Get scheme first. */
1302 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1303 SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1304 lpszUrl, lpszcp - lpszUrl);
1305
1306 /* Eat ':' in protocol. */
1307 lpszcp++;
1308
1309 /* double slash indicates the net_loc portion is present */
1310 if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1311 {
1312 lpszcp += 2;
1313
1314 lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1315 if (lpszParam)
1316 {
1317 if (lpszNetLoc)
1318 lpszNetLoc = min(lpszNetLoc, lpszParam);
1319 else
1320 lpszNetLoc = lpszParam;
1321 }
1322 else if (!lpszNetLoc)
1323 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1324
1325 /* Parse net-loc */
1326 if (lpszNetLoc)
1327 {
1328 LPCWSTR lpszHost;
1329 LPCWSTR lpszPort;
1330
1331 /* [<user>[<:password>]@]<host>[:<port>] */
1332 /* First find the user and password if they exist */
1333
1334 lpszHost = strchrW(lpszcp, '@');
1335 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1336 {
1337 /* username and password not specified. */
1338 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1339 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1340 }
1341 else /* Parse out username and password */
1342 {
1343 LPCWSTR lpszUser = lpszcp;
1344 LPCWSTR lpszPasswd = lpszHost;
1345
1346 while (lpszcp < lpszHost)
1347 {
1348 if (*lpszcp == ':')
1349 lpszPasswd = lpszcp;
1350
1351 lpszcp++;
1352 }
1353
1354 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1355 lpszUser, lpszPasswd - lpszUser);
1356
1357 if (lpszPasswd != lpszHost)
1358 lpszPasswd++;
1359 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1360 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1361 lpszHost - lpszPasswd);
1362
1363 lpszcp++; /* Advance to beginning of host */
1364 }
1365
1366 /* Parse <host><:port> */
1367
1368 lpszHost = lpszcp;
1369 lpszPort = lpszNetLoc;
1370
1371 /* special case for res:// URLs: there is no port here, so the host is the
1372 entire string up to the first '/' */
1373 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1374 {
1375 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1376 lpszHost, lpszPort - lpszHost);
1377 lpszcp=lpszNetLoc;
1378 }
1379 else
1380 {
1381 while (lpszcp < lpszNetLoc)
1382 {
1383 if (*lpszcp == ':')
1384 lpszPort = lpszcp;
1385
1386 lpszcp++;
1387 }
1388
1389 /* If the scheme is "file" and the host is just one letter, it's not a host */
1390 if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1391 {
1392 lpszcp=lpszHost;
1393 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1394 NULL, 0);
1395 }
1396 else
1397 {
1398 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1399 lpszHost, lpszPort - lpszHost);
1400 if (lpszPort != lpszNetLoc)
1401 lpUC->nPort = atoiW(++lpszPort);
1402 else switch (lpUC->nScheme)
1403 {
1404 case INTERNET_SCHEME_HTTP:
1405 lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1406 break;
1407 case INTERNET_SCHEME_HTTPS:
1408 lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1409 break;
1410 case INTERNET_SCHEME_FTP:
1411 lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1412 break;
1413 case INTERNET_SCHEME_GOPHER:
1414 lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1415 break;
1416 default:
1417 break;
1418 }
1419 }
1420 }
1421 }
1422 }
1423 else
1424 {
1425 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1426 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1427 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1428 }
1429 }
1430 else
1431 {
1432 SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
1433 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1434 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1435 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1436 }
1437
1438 /* Here lpszcp points to:
1439 *
1440 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1441 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1442 */
1443 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1444 {
1445 INT len;
1446
1447 /* Only truncate the parameter list if it's already been saved
1448 * in lpUC->lpszExtraInfo.
1449 */
1450 if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1451 len = lpszParam - lpszcp;
1452 else
1453 {
1454 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1455 * newlines if necessary.
1456 */
1457 LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1458 if (lpsznewline != NULL)
1459 len = lpsznewline - lpszcp;
1460 else
1461 len = dwUrlLength-(lpszcp-lpszUrl);
1462 }
1463 SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1464 lpszcp, len);
1465 }
1466 else
1467 {
1468 lpUC->dwUrlPathLength = 0;
1469 }
1470
1471 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1472 debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1473 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1474 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1475 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1476
1477 HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
1478 return TRUE;
1479 }
1480
1481 /***********************************************************************
1482 * InternetAttemptConnect (WININET.@)
1483 *
1484 * Attempt to make a connection to the internet
1485 *
1486 * RETURNS
1487 * ERROR_SUCCESS on success
1488 * Error value on failure
1489 *
1490 */
1491 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1492 {
1493 FIXME("Stub\n");
1494 return ERROR_SUCCESS;
1495 }
1496
1497
1498 /***********************************************************************
1499 * InternetCanonicalizeUrlA (WININET.@)
1500 *
1501 * Escape unsafe characters and spaces
1502 *
1503 * RETURNS
1504 * TRUE on success
1505 * FALSE on failure
1506 *
1507 */
1508 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1509 LPDWORD lpdwBufferLength, DWORD dwFlags)
1510 {
1511 HRESULT hr;
1512 DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1513
1514 TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
1515 lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1516
1517 if(dwFlags & ICU_DECODE)
1518 {
1519 dwURLFlags |= URL_UNESCAPE;
1520 dwFlags &= ~ICU_DECODE;
1521 }
1522
1523 if(dwFlags & ICU_ESCAPE)
1524 {
1525 dwURLFlags |= URL_UNESCAPE;
1526 dwFlags &= ~ICU_ESCAPE;
1527 }
1528
1529 if(dwFlags & ICU_BROWSER_MODE)
1530 {
1531 dwURLFlags |= URL_BROWSER_MODE;
1532 dwFlags &= ~ICU_BROWSER_MODE;
1533 }
1534
1535 if(dwFlags & ICU_NO_ENCODE)
1536 {
1537 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1538 dwURLFlags ^= URL_ESCAPE_UNSAFE;
1539 dwFlags &= ~ICU_NO_ENCODE;
1540 }
1541
1542 if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1543
1544 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1545 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1546 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1547
1548 return (hr == S_OK) ? TRUE : FALSE;
1549 }
1550
1551 /***********************************************************************
1552 * InternetCanonicalizeUrlW (WININET.@)
1553 *
1554 * Escape unsafe characters and spaces
1555 *
1556 * RETURNS
1557 * TRUE on success
1558 * FALSE on failure
1559 *
1560 */
1561 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1562 LPDWORD lpdwBufferLength, DWORD dwFlags)
1563 {
1564 HRESULT hr;
1565 DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1566
1567 TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
1568 lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1569
1570 if(dwFlags & ICU_DECODE)
1571 {
1572 dwURLFlags |= URL_UNESCAPE;
1573 dwFlags &= ~ICU_DECODE;
1574 }
1575
1576 if(dwFlags & ICU_ESCAPE)
1577 {
1578 dwURLFlags |= URL_UNESCAPE;
1579 dwFlags &= ~ICU_ESCAPE;
1580 }
1581
1582 if(dwFlags & ICU_BROWSER_MODE)
1583 {
1584 dwURLFlags |= URL_BROWSER_MODE;
1585 dwFlags &= ~ICU_BROWSER_MODE;
1586 }
1587
1588 if(dwFlags & ICU_NO_ENCODE)
1589 {
1590 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1591 dwURLFlags ^= URL_ESCAPE_UNSAFE;
1592 dwFlags &= ~ICU_NO_ENCODE;
1593 }
1594
1595 if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1596
1597 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1598 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1599 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1600
1601 return (hr == S_OK) ? TRUE : FALSE;
1602 }
1603
1604 /* #################################################### */
1605
1606 static INTERNET_STATUS_CALLBACK set_status_callback(
1607 LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
1608 {
1609 INTERNET_STATUS_CALLBACK ret;
1610
1611 if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
1612 else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1613
1614 ret = lpwh->lpfnStatusCB;
1615 lpwh->lpfnStatusCB = callback;
1616
1617 return ret;
1618 }
1619
1620 /***********************************************************************
1621 * InternetSetStatusCallbackA (WININET.@)
1622 *
1623 * Sets up a callback function which is called as progress is made
1624 * during an operation.
1625 *
1626 * RETURNS
1627 * Previous callback or NULL on success
1628 * INTERNET_INVALID_STATUS_CALLBACK on failure
1629 *
1630 */
1631 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1632 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1633 {
1634 INTERNET_STATUS_CALLBACK retVal;
1635 LPWININETHANDLEHEADER lpwh;
1636
1637 TRACE("0x%08x\n", (ULONG)hInternet);
1638
1639 if (!(lpwh = WININET_GetObject(hInternet)))
1640 return INTERNET_INVALID_STATUS_CALLBACK;
1641
1642 retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
1643
1644 WININET_Release( lpwh );
1645 return retVal;
1646 }
1647
1648 /***********************************************************************
1649 * InternetSetStatusCallbackW (WININET.@)
1650 *
1651 * Sets up a callback function which is called as progress is made
1652 * during an operation.
1653 *
1654 * RETURNS
1655 * Previous callback or NULL on success
1656 * INTERNET_INVALID_STATUS_CALLBACK on failure
1657 *
1658 */
1659 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1660 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1661 {
1662 INTERNET_STATUS_CALLBACK retVal;
1663 LPWININETHANDLEHEADER lpwh;
1664
1665 TRACE("0x%08x\n", (ULONG)hInternet);
1666
1667 if (!(lpwh = WININET_GetObject(hInternet)))
1668 return INTERNET_INVALID_STATUS_CALLBACK;
1669
1670 retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
1671
1672 WININET_Release( lpwh );
1673 return retVal;
1674 }
1675
1676 /***********************************************************************
1677 * InternetSetFilePointer (WININET.@)
1678 */
1679 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
1680 PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
1681 {
1682 FIXME("stub\n");
1683 return FALSE;
1684 }
1685
1686 /***********************************************************************
1687 * InternetWriteFile (WININET.@)
1688 *
1689 * Write data to an open internet file
1690 *
1691 * RETURNS
1692 * TRUE on success
1693 * FALSE on failure
1694 *
1695 */
1696 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1697 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1698 {
1699 BOOL retval = FALSE;
1700 int nSocket = -1;
1701 LPWININETHANDLEHEADER lpwh;
1702
1703 TRACE("\n");
1704 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1705 if (NULL == lpwh)
1706 return FALSE;
1707
1708 switch (lpwh->htype)
1709 {
1710 case WH_HHTTPREQ:
1711 {
1712 LPWININETHTTPREQW lpwhr;
1713 lpwhr = (LPWININETHTTPREQW)lpwh;
1714
1715 TRACE("HTTPREQ %i\n",dwNumOfBytesToWrite);
1716 retval = NETCON_send(&lpwhr->netConnection, lpBuffer,
1717 dwNumOfBytesToWrite, 0, (LPINT)lpdwNumOfBytesWritten);
1718
1719 WININET_Release( lpwh );
1720 return retval;
1721 }
1722 break;
1723
1724 case WH_HFILE:
1725 nSocket = ((LPWININETFTPFILE)lpwh)->nDataSocket;
1726 break;
1727
1728 default:
1729 break;
1730 }
1731
1732 if (nSocket != -1)
1733 {
1734 int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1735 retval = (res >= 0);
1736 *lpdwNumOfBytesWritten = retval ? res : 0;
1737 }
1738 WININET_Release( lpwh );
1739
1740 return retval;
1741 }
1742
1743
1744 BOOL INTERNET_ReadFile(LPWININETHANDLEHEADER lpwh, LPVOID lpBuffer,
1745 DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead,
1746 BOOL bWait, BOOL bSendCompletionStatus)
1747 {
1748 BOOL retval = FALSE;
1749 int nSocket = -1;
1750 int bytes_read;
1751 LPWININETHTTPREQW lpwhr;
1752
1753 /* FIXME: this should use NETCON functions! */
1754 switch (lpwh->htype)
1755 {
1756 case WH_HHTTPREQ:
1757 lpwhr = (LPWININETHTTPREQW)lpwh;
1758
1759 if (!NETCON_recv(&lpwhr->netConnection, lpBuffer,
1760 min(dwNumOfBytesToRead, lpwhr->dwContentLength - lpwhr->dwContentRead),
1761 bWait ? MSG_WAITALL : 0, &bytes_read))
1762 {
1763
1764 if (((lpwhr->dwContentLength != -1) &&
1765 (lpwhr->dwContentRead != lpwhr->dwContentLength)))
1766 ERR("not all data received %d/%d\n", lpwhr->dwContentRead,
1767 lpwhr->dwContentLength);
1768
1769 /* always returns TRUE, even if the network layer returns an
1770 * error */
1771 *pdwNumOfBytesRead = 0;
1772 HTTP_FinishedReading(lpwhr);
1773 retval = TRUE;
1774 }
1775 else
1776 {
1777 lpwhr->dwContentRead += bytes_read;
1778 *pdwNumOfBytesRead = bytes_read;
1779 if (!bytes_read && (lpwhr->dwContentRead == lpwhr->dwContentLength))
1780 retval = HTTP_FinishedReading(lpwhr);
1781 else
1782 retval = TRUE;
1783 }
1784 break;
1785
1786 case WH_HFILE:
1787 /* FIXME: FTP should use NETCON_ stuff */
1788 nSocket = ((LPWININETFTPFILE)lpwh)->nDataSocket;
1789 if (nSocket != -1)
1790 {
1791 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, bWait ? MSG_WAITALL : 0);
1792 retval = (res >= 0);
1793 *pdwNumOfBytesRead = retval ? res : 0;
1794 }
1795 break;
1796
1797 default:
1798 break;
1799 }
1800
1801 if (bSendCompletionStatus)
1802 {
1803 INTERNET_ASYNC_RESULT iar;
1804
1805 iar.dwResult = retval;
1806 iar.dwError = iar.dwError = retval ? ERROR_SUCCESS :
1807 INTERNET_GetLastError();
1808
1809 INTERNET_SendCallback(lpwh, lpwh->dwContext,
1810 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1811 sizeof(INTERNET_ASYNC_RESULT));
1812 }
1813 return retval;
1814 }
1815
1816 /***********************************************************************
1817 * InternetReadFile (WININET.@)
1818 *
1819 * Read data from an open internet file
1820 *
1821 * RETURNS
1822 * TRUE on success
1823 * FALSE on failure
1824 *
1825 */
1826 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1827 DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
1828 {
1829 LPWININETHANDLEHEADER lpwh;
1830 BOOL retval;
1831
1832 TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1833
1834 lpwh = WININET_GetObject( hFile );
1835 if (!lpwh)
1836 {
1837 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1838 return FALSE;
1839 }
1840
1841 retval = INTERNET_ReadFile(lpwh, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead, TRUE, FALSE);
1842 WININET_Release( lpwh );
1843
1844 TRACE("-- %s (bytes read: %d)\n", retval ? "TRUE": "FALSE", pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
1845 return retval;
1846 }
1847
1848 /***********************************************************************
1849 * InternetReadFileExA (WININET.@)
1850 *
1851 * Read data from an open internet file
1852 *
1853 * PARAMS
1854 * hFile [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
1855 * lpBuffersOut [I/O] Buffer.
1856 * dwFlags [I] Flags. See notes.
1857 * dwContext [I] Context for callbacks.
1858 *
1859 * RETURNS
1860 * TRUE on success
1861 * FALSE on failure
1862 *
1863 * NOTES
1864 * The parameter dwFlags include zero or more of the following flags:
1865 *|IRF_ASYNC - Makes the call asynchronous.
1866 *|IRF_SYNC - Makes the call synchronous.
1867 *|IRF_USE_CONTEXT - Forces dwContext to be used.
1868 *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
1869 *
1870 * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
1871 *
1872 * SEE
1873 * InternetOpenUrlA(), HttpOpenRequestA()
1874 */
1875 void AsyncInternetReadFileExProc(WORKREQUEST *workRequest)
1876 {
1877 struct WORKREQ_INTERNETREADFILEEXA const *req = &workRequest->u.InternetReadFileExA;
1878
1879 TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
1880
1881 INTERNET_ReadFile(workRequest->hdr, req->lpBuffersOut->lpvBuffer,
1882 req->lpBuffersOut->dwBufferLength,
1883 &req->lpBuffersOut->dwBufferLength, TRUE, TRUE);
1884 }
1885
1886 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
1887 DWORD dwFlags, DWORD_PTR dwContext)
1888 {
1889 BOOL retval = FALSE;
1890 LPWININETHANDLEHEADER lpwh;
1891
1892 TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
1893
1894 if (dwFlags & ~(IRF_ASYNC|IRF_NO_WAIT))
1895 FIXME("these dwFlags aren't implemented: 0x%x\n", dwFlags & ~(IRF_ASYNC|IRF_NO_WAIT));
1896
1897 if (lpBuffersOut->dwStructSize != sizeof(*lpBuffersOut))
1898 {
1899 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1900 return FALSE;
1901 }
1902
1903 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1904 if (!lpwh)
1905 {
1906 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1907 return FALSE;
1908 }
1909
1910 INTERNET_SendCallback(lpwh, lpwh->dwContext,
1911 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1912
1913 /* FIXME: IRF_ASYNC may not be the right thing to test here;
1914 * hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC is probably better */
1915 if (dwFlags & IRF_ASYNC)
1916 {
1917 DWORD dwDataAvailable = 0;
1918
1919 if (lpwh->htype == WH_HHTTPREQ)
1920 NETCON_query_data_available(&((LPWININETHTTPREQW)lpwh)->netConnection,
1921 &dwDataAvailable);
1922
1923 if (!dwDataAvailable)
1924 {
1925 WORKREQUEST workRequest;
1926 struct WORKREQ_INTERNETREADFILEEXA *req;
1927
1928 workRequest.asyncproc = AsyncInternetReadFileExProc;
1929 workRequest.hdr = WININET_AddRef( lpwh );
1930 req = &workRequest.u.InternetReadFileExA;
1931 req->lpBuffersOut = lpBuffersOut;
1932
1933 if (!INTERNET_AsyncCall(&workRequest))
1934 WININET_Release( lpwh );
1935 else
1936 INTERNET_SetLastError(ERROR_IO_PENDING);
1937 goto end;
1938 }
1939 }
1940
1941 retval = INTERNET_ReadFile(lpwh, lpBuffersOut->lpvBuffer,
1942 lpBuffersOut->dwBufferLength, &lpBuffersOut->dwBufferLength,
1943 !(dwFlags & IRF_NO_WAIT), FALSE);
1944
1945 if (retval)
1946 {
1947 DWORD dwBytesReceived = lpBuffersOut->dwBufferLength;
1948 INTERNET_SendCallback(lpwh, lpwh->dwContext,
1949 INTERNET_STATUS_RESPONSE_RECEIVED, &dwBytesReceived,
1950 sizeof(dwBytesReceived));
1951 }
1952
1953 end:
1954 WININET_Release( lpwh );
1955
1956 TRACE("-- %s (bytes read: %d)\n", retval ? "TRUE": "FALSE", lpBuffersOut->dwBufferLength);
1957 return retval;
1958 }
1959
1960 /***********************************************************************
1961 * InternetReadFileExW (WININET.@)
1962 *
1963 * Read data from an open internet file.
1964 *
1965 * PARAMS
1966 * hFile [I] Handle returned by InternetOpenUrl() or HttpOpenRequest().
1967 * lpBuffersOut [I/O] Buffer.
1968 * dwFlags [I] Flags.
1969 * dwContext [I] Context for callbacks.
1970 *
1971 * RETURNS
1972 * FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED
1973 *
1974 * NOTES
1975 * Not implemented in Wine or native either (as of IE6 SP2).
1976 *
1977 */
1978 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1979 DWORD dwFlags, DWORD_PTR dwContext)
1980 {
1981 ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext);
1982
1983 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1984 return FALSE;
1985 }
1986
1987 /***********************************************************************
1988 * INET_QueryOptionHelper (internal)
1989 */
1990 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1991 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1992 {
1993 LPWININETHANDLEHEADER lpwhh;
1994 BOOL bSuccess = FALSE;
1995
1996 TRACE("(%p, 0x%08x, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1997
1998 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1999
2000 switch (dwOption)
2001 {
2002 case INTERNET_OPTION_HANDLE_TYPE:
2003 {
2004 ULONG type;
2005
2006 if (!lpwhh)
2007 {
2008 WARN("Invalid hInternet handle\n");
2009 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2010 return FALSE;
2011 }
2012
2013 type = lpwhh->htype;
2014
2015 TRACE("INTERNET_OPTION_HANDLE_TYPE: %d\n", type);
2016
2017 if (*lpdwBufferLength < sizeof(ULONG))
2018 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2019 else
2020 {
2021 memcpy(lpBuffer, &type, sizeof(ULONG));
2022 bSuccess = TRUE;
2023 }
2024 *lpdwBufferLength = sizeof(ULONG);
2025 break;
2026 }
2027
2028 case INTERNET_OPTION_REQUEST_FLAGS:
2029 {
2030 ULONG flags = 4;
2031 TRACE("INTERNET_OPTION_REQUEST_FLAGS: %d\n", flags);
2032 if (*lpdwBufferLength < sizeof(ULONG))
2033 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2034 else
2035 {
2036 memcpy(lpBuffer, &flags, sizeof(ULONG));
2037 bSuccess = TRUE;
2038 }
2039 *lpdwBufferLength = sizeof(ULONG);
2040 break;
2041 }
2042
2043 case INTERNET_OPTION_URL:
2044 case INTERNET_OPTION_DATAFILE_NAME:
2045 {
2046 if (!lpwhh)
2047 {
2048 WARN("Invalid hInternet handle\n");
2049 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2050 return FALSE;
2051 }
2052 if (lpwhh->htype == WH_HHTTPREQ)
2053 {
2054 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
2055 WCHAR url[1023];
2056 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
2057 static const WCHAR szHost[] = {'H','o','s','t',0};
2058 DWORD sizeRequired;
2059 LPHTTPHEADERW Host;
2060
2061 Host = HTTP_GetHeader(lpreq,szHost);
2062 sprintfW(url,szFmt,Host->lpszValue,lpreq->lpszPath);
2063 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
2064 if(!bIsUnicode)
2065 {
2066 sizeRequired = WideCharToMultiByte(CP_ACP,0,url,-1,
2067 lpBuffer,*lpdwBufferLength,NULL,NULL);
2068 if (sizeRequired > *lpdwBufferLength)
2069 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2070 else
2071 bSuccess = TRUE;
2072 *lpdwBufferLength = sizeRequired;
2073 }
2074 else
2075 {
2076 sizeRequired = (lstrlenW(url)+1) * sizeof(WCHAR);
2077 if (*lpdwBufferLength < sizeRequired)
2078 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2079 else
2080 {
2081 strcpyW(lpBuffer, url);
2082 bSuccess = TRUE;
2083 }
2084 *lpdwBufferLength = sizeRequired;
2085 }
2086 }
2087 break;
2088 }
2089 case INTERNET_OPTION_HTTP_VERSION:
2090 {
2091 if (*lpdwBufferLength < sizeof(HTTP_VERSION_INFO))
2092 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2093 else
2094 {
2095 /*
2096 * Presently hardcoded to 1.1
2097 */
2098 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
2099 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
2100 bSuccess = TRUE;
2101 }
2102 *lpdwBufferLength = sizeof(HTTP_VERSION_INFO);
2103 break;
2104 }
2105 case INTERNET_OPTION_CONNECTED_STATE:
2106 {
2107 DWORD *pdwConnectedState = (DWORD *)lpBuffer;
2108 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2109
2110 if (*lpdwBufferLength < sizeof(*pdwConnectedState))
2111 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2112 else
2113 {
2114 *pdwConnectedState = INTERNET_STATE_CONNECTED;
2115 bSuccess = TRUE;
2116 }
2117 *lpdwBufferLength = sizeof(*pdwConnectedState);
2118 break;
2119 }
2120 case INTERNET_OPTION_PROXY:
2121 {
2122 LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW)lpwhh;
2123 WININETAPPINFOW wai;
2124
2125 if (lpwai == NULL)
2126 {
2127 TRACE("Getting global proxy info\n");
2128 memset(&wai, 0, sizeof(WININETAPPINFOW));
2129 INTERNET_ConfigureProxyFromReg( &wai );
2130 lpwai = &wai;
2131 }
2132
2133 if (bIsUnicode)
2134 {
2135 INTERNET_PROXY_INFOW *pPI = (INTERNET_PROXY_INFOW *)lpBuffer;
2136 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2137
2138 if (lpwai->lpszProxy)
2139 proxyBytesRequired = (lstrlenW(lpwai->lpszProxy) + 1) *
2140 sizeof(WCHAR);
2141 if (lpwai->lpszProxyBypass)
2142 proxyBypassBytesRequired =
2143 (lstrlenW(lpwai->lpszProxyBypass) + 1) * sizeof(WCHAR);
2144 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOW) +
2145 proxyBytesRequired + proxyBypassBytesRequired)
2146 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2147 else
2148 {
2149 LPWSTR proxy = (LPWSTR)((LPBYTE)lpBuffer +
2150 sizeof(INTERNET_PROXY_INFOW));
2151 LPWSTR proxy_bypass = (LPWSTR)((LPBYTE)lpBuffer +
2152 sizeof(INTERNET_PROXY_INFOW) +
2153 proxyBytesRequired);
2154
2155 pPI->dwAccessType = lpwai->dwAccessType;
2156 pPI->lpszProxy = NULL;
2157 pPI->lpszProxyBypass = NULL;
2158 if (lpwai->lpszProxy)
2159 {
2160 lstrcpyW(proxy, lpwai->lpszProxy);
2161 pPI->lpszProxy = proxy;
2162 }
2163
2164 if (lpwai->lpszProxyBypass)
2165 {
2166 lstrcpyW(proxy_bypass, lpwai->lpszProxyBypass);
2167 pPI->lpszProxyBypass = proxy_bypass;
2168 }
2169 bSuccess = TRUE;
2170 }
2171 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOW) +
2172 proxyBytesRequired + proxyBypassBytesRequired;
2173 }
2174 else
2175 {
2176 INTERNET_PROXY_INFOA *pPI = (INTERNET_PROXY_INFOA *)lpBuffer;
2177 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2178
2179 if (lpwai->lpszProxy)
2180 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2181 lpwai->lpszProxy, -1, NULL, 0, NULL, NULL);
2182 if (lpwai->lpszProxyBypass)
2183 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2184 lpwai->lpszProxyBypass, -1, NULL, 0, NULL, NULL);
2185 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOA) +
2186 proxyBytesRequired + proxyBypassBytesRequired)
2187 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2188 else
2189 {
2190 LPSTR proxy = (LPSTR)((LPBYTE)lpBuffer +
2191 sizeof(INTERNET_PROXY_INFOA));
2192 LPSTR proxy_bypass = (LPSTR)((LPBYTE)lpBuffer +
2193 sizeof(INTERNET_PROXY_INFOA) +
2194 proxyBytesRequired);
2195
2196 pPI->dwAccessType = lpwai->dwAccessType;
2197 pPI->lpszProxy = NULL;
2198 pPI->lpszProxyBypass = NULL;
2199 if (lpwai->lpszProxy)
2200 {
2201 WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxy, -1,
2202 proxy, proxyBytesRequired, NULL, NULL);
2203 pPI->lpszProxy = proxy;
2204 }
2205
2206 if (lpwai->lpszProxyBypass)
2207 {
2208 WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxyBypass,
2209 -1, proxy_bypass, proxyBypassBytesRequired,
2210 NULL, NULL);
2211 pPI->lpszProxyBypass = proxy_bypass;
2212 }
2213 bSuccess = TRUE;
2214 }
2215 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOA) +
2216 proxyBytesRequired + proxyBypassBytesRequired;
2217 }
2218 break;
2219 }
2220 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2221 {
2222 ULONG conn = 2;
2223 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER: %d\n", conn);
2224 if (*lpdwBufferLength < sizeof(ULONG))
2225 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2226 else
2227 {
2228 memcpy(lpBuffer, &conn, sizeof(ULONG));
2229 bSuccess = TRUE;
2230 }
2231 *lpdwBufferLength = sizeof(ULONG);
2232 break;
2233 }
2234 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2235 {
2236 ULONG conn = 4;
2237 TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER: %d\n", conn);
2238 if (*lpdwBufferLength < sizeof(ULONG))
2239 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2240 else
2241 {
2242 memcpy(lpBuffer, &conn, sizeof(ULONG));
2243 bSuccess = TRUE;
2244 }
2245 *lpdwBufferLength = sizeof(ULONG);
2246 break;
2247 }
2248 case INTERNET_OPTION_SECURITY_FLAGS:
2249 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2250 bSuccess = TRUE;
2251 break;
2252
2253 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT:
2254 if (!lpwhh)
2255 {
2256 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2257 return FALSE;
2258 }
2259 if (*lpdwBufferLength < sizeof(INTERNET_CERTIFICATE_INFOW))
2260 {
2261 *lpdwBufferLength = sizeof(INTERNET_CERTIFICATE_INFOW);
2262 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2263 }
2264 else if (lpwhh->htype == WH_HHTTPREQ)
2265 {
2266 LPWININETHTTPREQW lpwhr;
2267 PCCERT_CONTEXT context;
2268
2269 lpwhr = (LPWININETHTTPREQW)lpwhh;
2270 context = (PCCERT_CONTEXT)NETCON_GetCert(&(lpwhr->netConnection));
2271 if (context)
2272 {
2273 LPINTERNET_CERTIFICATE_INFOW info = (LPINTERNET_CERTIFICATE_INFOW)lpBuffer;
2274 DWORD strLen;
2275
2276 memset(info,0,sizeof(INTERNET_CERTIFICATE_INFOW));
2277 info->ftExpiry = context->pCertInfo->NotAfter;
2278 info->ftStart = context->pCertInfo->NotBefore;
2279 if (bIsUnicode)
2280 {
2281 strLen = CertNameToStrW(context->dwCertEncodingType,
2282 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2283 NULL, 0);
2284 info->lpszSubjectInfo = LocalAlloc(0,
2285 strLen * sizeof(WCHAR));
2286 if (info->lpszSubjectInfo)
2287 CertNameToStrW(context->dwCertEncodingType,
2288 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2289 info->lpszSubjectInfo, strLen);
2290 strLen = CertNameToStrW(context->dwCertEncodingType,
2291 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2292 NULL, 0);
2293 info->lpszIssuerInfo = LocalAlloc(0,
2294 strLen * sizeof(WCHAR));
2295 if (info->lpszIssuerInfo)
2296 CertNameToStrW(context->dwCertEncodingType,
2297 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2298 info->lpszIssuerInfo, strLen);
2299 }
2300 else
2301 {
2302 LPINTERNET_CERTIFICATE_INFOA infoA =
2303 (LPINTERNET_CERTIFICATE_INFOA)info;
2304
2305 strLen = CertNameToStrA(context->dwCertEncodingType,
2306 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2307 NULL, 0);
2308 infoA->lpszSubjectInfo = LocalAlloc(0, strLen);
2309 if (infoA->lpszSubjectInfo)
2310 CertNameToStrA(context->dwCertEncodingType,
2311 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2312 infoA->lpszSubjectInfo, strLen);
2313 strLen = CertNameToStrA(context->dwCertEncodingType,
2314 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2315 NULL, 0);
2316 infoA->lpszIssuerInfo = LocalAlloc(0, strLen);
2317 if (infoA->lpszIssuerInfo)
2318 CertNameToStrA(context->dwCertEncodingType,
2319 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2320 infoA->lpszIssuerInfo, strLen);
2321 }
2322 /*
2323 * Contrary to MSDN, these do not appear to be set.
2324 * lpszProtocolName
2325 * lpszSignatureAlgName
2326 * lpszEncryptionAlgName
2327 * dwKeySize
2328 */
2329 CertFreeCertificateContext(context);
2330 bSuccess = TRUE;
2331 }
2332 }
2333 break;
2334 case INTERNET_OPTION_VERSION:
2335 {
2336 TRACE("INTERNET_OPTION_VERSION\n");
2337 if (*lpdwBufferLength < sizeof(INTERNET_VERSION_INFO))
2338 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2339 else
2340 {
2341 static const INTERNET_VERSION_INFO info = { 6, 0 };
2342 memcpy(lpBuffer, &info, sizeof(info));
2343 *lpdwBufferLength = sizeof(info);
2344 bSuccess = TRUE;
2345 }
2346 break;
2347 }
2348 default:
2349 FIXME("Stub! %d\n", dwOption);
2350 break;
2351 }
2352 if (lpwhh)
2353 WININET_Release( lpwhh );
2354
2355 return bSuccess;
2356 }
2357
2358 /***********************************************************************
2359 * InternetQueryOptionW (WININET.@)
2360 *
2361 * Queries an options on the specified handle
2362 *
2363 * RETURNS
2364 * TRUE on success
2365 * FALSE on failure
2366 *
2367 */
2368 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2369 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2370 {
2371 return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2372 }
2373
2374 /***********************************************************************
2375 * InternetQueryOptionA (WININET.@)
2376 *
2377 * Queries an options on the specified handle
2378 *
2379 * RETURNS
2380 * TRUE on success
2381 * FALSE on failure
2382 *
2383 */
2384 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2385 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2386 {
2387 return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2388 }
2389
2390
2391 /***********************************************************************
2392 * InternetSetOptionW (WININET.@)
2393 *
2394 * Sets an options on the specified handle
2395 *
2396 * RETURNS
2397 * TRUE on success
2398 * FALSE on failure
2399 *
2400 */
2401 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2402 LPVOID lpBuffer, DWORD dwBufferLength)
2403 {
2404 LPWININETHANDLEHEADER lpwhh;
2405 BOOL ret = TRUE;
2406
2407 TRACE("0x%08x\n", dwOption);
2408
2409 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
2410 if( !lpwhh )
2411 return FALSE;
2412
2413 switch (dwOption)
2414 {
2415 case INTERNET_OPTION_CALLBACK:
2416 {
2417 INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2418 ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK);
2419 break;
2420 }
2421 case INTERNET_OPTION_HTTP_VERSION:
2422 {
2423 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2424 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2425 }
2426 break;
2427 case INTERNET_OPTION_ERROR_MASK:
2428 {
2429 unsigned long flags=*(unsigned long*)lpBuffer;
2430 FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
2431 }
2432 break;
2433 case INTERNET_OPTION_CODEPAGE:
2434 {
2435 unsigned long codepage=*(unsigned long*)lpBuffer;
2436 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
2437 }
2438 break;
2439 case INTERNET_OPTION_REQUEST_PRIORITY:
2440 {
2441 unsigned long priority=*(unsigned long*)lpBuffer;
2442 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
2443 }
2444 break;
2445 case INTERNET_OPTION_CONNECT_TIMEOUT:
2446 {
2447 unsigned long connecttimeout=*(unsigned long*)lpBuffer;
2448 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
2449 }
2450 break;
2451 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2452 {
2453 unsigned long receivetimeout=*(unsigned long*)lpBuffer;
2454 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
2455 }
2456 break;
2457 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2458 {
2459 unsigned long conns=*(unsigned long*)lpBuffer;
2460 FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%ld): STUB\n",conns);
2461 }
2462 break;
2463 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2464 {
2465 unsigned long conns=*(unsigned long*)lpBuffer;
2466 FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%ld): STUB\n",conns);
2467 }
2468 break;
2469 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2470 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2471 break;
2472 case INTERNET_OPTION_END_BROWSER_SESSION:
2473 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2474 break;
2475 case INTERNET_OPTION_CONNECTED_STATE:
2476 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2477 break;
2478 case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2479 TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2480 break;
2481 case INTERNET_OPTION_SEND_TIMEOUT:
2482 case INTERNET_OPTION_RECEIVE_TIMEOUT:
2483 TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
2484 if (dwBufferLength == sizeof(DWORD))
2485 {
2486 if (lpwhh->htype == WH_HHTTPREQ)
2487 ret = NETCON_set_timeout(
2488 &((LPWININETHTTPREQW)lpwhh)->netConnection,
2489 dwOption == INTERNET_OPTION_SEND_TIMEOUT,
2490 *(DWORD *)lpBuffer);
2491 else
2492 {
2493 FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT not supported on protocol %d\n",
2494 lpwhh->htype);
2495 }
2496 }
2497 else
2498 {
2499 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2500 ret = FALSE;
2501 }
2502 break;
2503 case INTERNET_OPTION_CONNECT_RETRIES:
2504 FIXME("Option INTERNET_OPTION_CONNECT_RETRIES: STUB\n");
2505 break;
2506 case INTERNET_OPTION_CONTEXT_VALUE:
2507 FIXME("Option INTERNET_OPTION_CONTEXT_VALUE; STUB\n");
2508 break;
2509 case INTERNET_OPTION_SECURITY_FLAGS:
2510 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2511 break;
2512 default:
2513 FIXME("Option %d STUB\n",dwOption);
2514 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2515 ret = FALSE;
2516 break;
2517 }
2518 WININET_Release( lpwhh );
2519
2520 return ret;
2521 }
2522
2523
2524 /***********************************************************************
2525 * InternetSetOptionA (WININET.@)
2526 *
2527 * Sets an options on the specified handle.
2528 *
2529 * RETURNS
2530 * TRUE on success
2531 * FALSE on failure
2532 *
2533 */
2534 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2535 LPVOID lpBuffer, DWORD dwBufferLength)
2536 {
2537 LPVOID wbuffer;
2538 DWORD wlen;
2539 BOOL r;
2540
2541 switch( dwOption )
2542 {
2543 case INTERNET_OPTION_CALLBACK:
2544 {
2545 LPWININETHANDLEHEADER lpwh;
2546 INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2547
2548 if (!(lpwh = (LPWININETHANDLEHEADER)WININET_GetObject(hInternet))) return FALSE;
2549 r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK);
2550 WININET_Release(lpwh);
2551 return r;
2552 }
2553 case INTERNET_OPTION_PROXY:
2554 {
2555 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2556 LPINTERNET_PROXY_INFOW piw;
2557 DWORD proxlen, prbylen;
2558 LPWSTR prox, prby;
2559
2560 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2561 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2562 wlen = sizeof(*piw) + proxlen + prbylen;
2563 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2564 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2565 piw->dwAccessType = pi->dwAccessType;
2566 prox = (LPWSTR) &piw[1];
2567 prby = &prox[proxlen+1];
2568 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2569 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2570 piw->lpszProxy = prox;
2571 piw->lpszProxyBypass = prby;
2572 }
2573 break;
2574 case INTERNET_OPTION_USER_AGENT:
2575 case INTERNET_OPTION_USERNAME:
2576 case INTERNET_OPTION_PASSWORD:
2577 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2578 NULL, 0 );
2579 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2580 MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2581 wbuffer, wlen );
2582 break;
2583 default:
2584 wbuffer = lpBuffer;
2585 wlen = dwBufferLength;
2586 }
2587
2588 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2589
2590 if( lpBuffer != wbuffer )
2591 HeapFree( GetProcessHeap(), 0, wbuffer );
2592
2593 return r;
2594 }
2595
2596
2597 /***********************************************************************
2598 * InternetSetOptionExA (WININET.@)
2599 */
2600 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2601 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2602 {
2603 FIXME("Flags %08x ignored\n", dwFlags);
2604 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2605 }
2606
2607 /***********************************************************************
2608 * InternetSetOptionExW (WININET.@)
2609 */
2610 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2611 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2612 {
2613 FIXME("Flags %08x ignored\n", dwFlags);
2614 if( dwFlags & ~ISO_VALID_FLAGS )
2615 {
2616 INTERNET_SetLastError( ERROR_INVALID_PARAMETER );
2617 return FALSE;
2618 }
2619 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2620 }
2621
2622 static const WCHAR WININET_wkday[7][4] =
2623 { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2624 { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2625 static const WCHAR WININET_month[12][4] =
2626 { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2627 { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2628 { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2629
2630 /***********************************************************************
2631 * InternetTimeFromSystemTimeA (WININET.@)
2632 */
2633 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2634 {
2635 BOOL ret;
2636 WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2637
2638 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2639
2640 ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2641 if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2642
2643 return ret;
2644 }
2645
2646 /***********************************************************************
2647 * InternetTimeFromSystemTimeW (WININET.@)
2648 */
2649 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2650 {
2651 static const WCHAR date[] =
2652 { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2653 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2654
2655 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2656
2657 if (!time || !string) return FALSE;
2658
2659 if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR))
2660 return FALSE;
2661
2662 sprintfW( string, date,
2663 WININET_wkday[time->wDayOfWeek],
2664 time->wDay,
2665 WININET_month[time->wMonth - 1],
2666 time->wYear,
2667 time->wHour,
2668 time->wMinute,
2669 time->wSecond );
2670
2671 return TRUE;
2672 }
2673
2674 /***********************************************************************
2675 * InternetTimeToSystemTimeA (WININET.@)
2676 */
2677 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2678 {
2679 BOOL ret = FALSE;
2680 WCHAR *stringW;
2681 int len;
2682
2683 TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
2684
2685 len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
2686 stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2687
2688 if (stringW)
2689 {
2690 MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
2691 ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2692 HeapFree( GetProcessHeap(), 0, stringW );
2693 }
2694 return ret;
2695 }
2696
2697 /***********************************************************************
2698 * InternetTimeToSystemTimeW (WININET.@)
2699 */
2700 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2701 {
2702 unsigned int i;
2703 const WCHAR *s = string;
2704 WCHAR *end;
2705
2706 TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
2707
2708 if (!string || !time) return FALSE;
2709
2710 /* Windows does this too */
2711 GetSystemTime( time );
2712
2713 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2714 * a SYSTEMTIME structure.
2715 */
2716
2717 while (*s && !isalphaW( *s )) s++;
2718 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2719 time->wDayOfWeek = 7;
2720
2721 for (i = 0; i < 7; i++)
2722 {
2723 if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2724 toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2725 toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2726 {
2727 time->wDayOfWeek = i;
2728 break;
2729 }
2730 }
2731
2732 if (time->wDayOfWeek > 6) return TRUE;
2733 while (*s && !isdigitW( *s )) s++;
2734 time->wDay = strtolW( s, &end, 10 );
2735 s = end;
2736
2737 while (*s && !isalphaW( *s )) s++;
2738 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2739 time->wMonth = 0;
2740
2741 for (i = 0; i < 12; i++)
2742 {
2743 if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2744 toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2745 toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2746 {
2747 time->wMonth = i + 1;
2748 break;
2749 }
2750 }
2751 if (time->wMonth == 0) return TRUE;
2752
2753 while (*s && !isdigitW( *s )) s++;
2754 if (*s == '\0') return TRUE;
2755 time->wYear = strtolW( s, &end, 10 );
2756 s = end;
2757
2758 while (*s && !isdigitW( *s )) s++;
2759 if (*s == '\0') return TRUE;
2760 time->wHour = strtolW( s, &end, 10 );
2761 s = end;
2762
2763 while (*s && !isdigitW( *s )) s++;
2764 if (*s == '\0') return TRUE;
2765 time->wMinute = strtolW( s, &end, 10 );
2766 s = end;
2767
2768 while (*s && !isdigitW( *s )) s++;
2769 if (*s == '\0') return TRUE;
2770 time->wSecond = strtolW( s, &end, 10 );
2771 s = end;
2772
2773 time->wMilliseconds = 0;
2774 return TRUE;
2775 }
2776
2777 /***********************************************************************
2778 * InternetCheckConnectionW (WININET.@)
2779 *
2780 * Pings a requested host to check internet connection
2781 *
2782 * RETURNS
2783 * TRUE on success and FALSE on failure. If a failure then
2784 * ERROR_NOT_CONNECTED is placed into GetLastError
2785 *
2786 */
2787 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2788 {
2789 /*
2790 * this is a kludge which runs the resident ping program and reads the output.
2791 *
2792 * Anyone have a better idea?
2793 */
2794
2795 BOOL rc = FALSE;
2796 static const CHAR ping[] = "ping -c 1 ";
2797 static const CHAR redirect[] = " >/dev/null 2>/dev/null";
2798 CHAR *command = NULL;
2799 WCHAR hostW[1024];
2800 DWORD len;
2801 INTERNET_PORT port;
2802 int status = -1;
2803
2804 FIXME("\n");
2805
2806 /*
2807 * Crack or set the Address
2808 */
2809 if (lpszUrl == NULL)
2810 {
2811 /*
2812 * According to the doc we are supposed to use the ip for the next
2813 * server in the WnInet internal server database. I have
2814 * no idea what that is or how to get it.
2815 *
2816 * So someone needs to implement this.
2817 */
2818 FIXME("Unimplemented with URL of NULL\n");
2819 return TRUE;
2820 }
2821 else
2822 {
2823 URL_COMPONENTSW components;
2824
2825 ZeroMemory(&components,sizeof(URL_COMPONENTSW));
2826 components.lpszHostName = (LPWSTR)&hostW;
2827 components.dwHostNameLength = 1024;
2828
2829 if (!InternetCrackUrlW(lpszUrl,0,0,&components))
2830 goto End;
2831
2832 TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
2833 port = components.nPort;
2834 TRACE("port: %d\n", port);
2835 }
2836
2837 if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
2838 {
2839 struct sockaddr_in sin;
2840 int fd;
2841
2842 if (!GetAddress(hostW, port, &sin))
2843 goto End;
2844 fd = socket(sin.sin_family, SOCK_STREAM, 0);
2845 if (fd != -1)
2846 {
2847 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
2848 rc = TRUE;
2849 close(fd);
2850 }
2851 }
2852 else
2853 {
2854 /*
2855 * Build our ping command
2856 */
2857 len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
2858 command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
2859 strcpy(command,ping);
2860 WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
2861 strcat(command,redirect);
2862
2863 TRACE("Ping command is : %s\n",command);
2864
2865 status = system(command);
2866
2867 TRACE("Ping returned a code of %i\n",status);
2868
2869 /* Ping return code of 0 indicates success */
2870 if (status == 0)
2871 rc = TRUE;
2872 }
2873
2874 End:
2875
2876 HeapFree( GetProcessHeap(), 0, command );
2877 if (rc == FALSE)
2878 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
2879
2880 return rc;
2881 }
2882
2883
2884 /***********************************************************************
2885 * InternetCheckConnectionA (WININET.@)
2886 *
2887 * Pings a requested host to check internet connection
2888 *
2889 * RETURNS
2890 * TRUE on success and FALSE on failure. If a failure then
2891 * ERROR_NOT_CONNECTED is placed into GetLastError
2892 *
2893 */
2894 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2895 {
2896 WCHAR *szUrl;
2897 INT len;
2898 BOOL rc;
2899
2900 len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
2901 if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
2902 return FALSE;
2903 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len);
2904 rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved);
2905 HeapFree(GetProcessHeap(), 0, szUrl);
2906
2907 return rc;
2908 }
2909
2910
2911 /**********************************************************
2912 * INTERNET_InternetOpenUrlW (internal)
2913 *
2914 * Opens an URL
2915 *
2916 * RETURNS
2917 * handle of connection or NULL on failure
2918 */
2919 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2920 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2921 {
2922 URL_COMPONENTSW urlComponents;
2923 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2924 WCHAR password[1024], path[2048], extra[1024];
2925 HINTERNET client = NULL, client1 = NULL;
2926
2927 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2928 dwHeadersLength, dwFlags, dwContext);
2929
2930 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2931 urlComponents.lpszScheme = protocol;
2932 urlComponents.dwSchemeLength = 32;
2933 urlComponents.lpszHostName = hostName;
2934 urlComponents.dwHostNameLength = MAXHOSTNAME;
2935 urlComponents.lpszUserName = userName;
2936 urlComponents.dwUserNameLength = 1024;
2937 urlComponents.lpszPassword = password;
2938 urlComponents.dwPasswordLength = 1024;
2939 urlComponents.lpszUrlPath = path;
2940 urlComponents.dwUrlPathLength = 2048;
2941 urlComponents.lpszExtraInfo = extra;
2942 urlComponents.dwExtraInfoLength = 1024;
2943 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2944 return NULL;
2945 switch(urlComponents.nScheme) {
2946 case INTERNET_SCHEME_FTP:
2947 if(urlComponents.nPort == 0)
2948 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2949 client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2950 userName, password, dwFlags, dwContext, INET_OPENURL);
2951 if(client == NULL)
2952 break;
2953 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2954 if(client1 == NULL) {
2955 InternetCloseHandle(client);
2956 break;
2957 }
2958 break;
2959
2960 case INTERNET_SCHEME_HTTP:
2961 case INTERNET_SCHEME_HTTPS: {
2962 static const WCHAR szStars[] = { '*','/','*', 0 };
2963 LPCWSTR accept[2] = { szStars, NULL };
2964 if(urlComponents.nPort == 0) {
2965 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2966 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2967 else
2968 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2969 }
2970 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2971 client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2972 userName, password, dwFlags, dwContext, INET_OPENURL);
2973 if(client == NULL)
2974 break;
2975
2976 if (urlComponents.dwExtraInfoLength) {
2977 WCHAR *path_extra;
2978 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
2979
2980 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
2981 {
2982 InternetCloseHandle(client);
2983 break;
2984 }
2985 strcpyW(path_extra, urlComponents.lpszUrlPath);
2986 strcatW(path_extra, urlComponents.lpszExtraInfo);
2987 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
2988 HeapFree(GetProcessHeap(), 0, path_extra);
2989 }
2990 else
2991 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2992
2993 if(client1 == NULL) {
2994 InternetCloseHandle(client);
2995 break;
2996 }
2997 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2998 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
2999 GetLastError() != ERROR_IO_PENDING) {
3000 InternetCloseHandle(client1);
3001 client1 = NULL;
3002 break;
3003 }
3004 }
3005 case INTERNET_SCHEME_GOPHER:
3006 /* gopher doesn't seem to be implemented in wine, but it's supposed
3007 * to be supported by InternetOpenUrlA. */
3008 default:
3009 INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3010 break;
3011 }
3012
3013 TRACE(" %p <--\n", client1);
3014
3015 return client1;
3016 }
3017
3018 /**********************************************************
3019 * InternetOpenUrlW (WININET.@)
3020 *
3021 * Opens an URL
3022 *
3023 * RETURNS
3024 * handle of connection or NULL on failure
3025 */
3026 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
3027 {
3028 struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
3029 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr;
3030
3031 TRACE("%p\n", hIC);
3032
3033 INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
3034 req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
3035 HeapFree(GetProcessHeap(), 0, req->lpszUrl);
3036 HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
3037 }
3038
3039 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3040 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3041 {
3042 HINTERNET ret = NULL;
3043 LPWININETAPPINFOW hIC = NULL;
3044
3045 if (TRACE_ON(wininet)) {
3046 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3047 dwHeadersLength, dwFlags, dwContext);
3048 TRACE(" flags :");
3049 dump_INTERNET_FLAGS(dwFlags);
3050 }
3051
3052 if (!lpszUrl)
3053 {
3054 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3055 goto lend;
3056 }
3057
3058 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
3059 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
3060 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3061 goto lend;
3062 }
3063
3064 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3065 WORKREQUEST workRequest;
3066 struct WORKREQ_INTERNETOPENURLW *req;
3067
3068 workRequest.asyncproc = AsyncInternetOpenUrlProc;
3069 workRequest.hdr = WININET_AddRef( &hIC->hdr );
3070 req = &workRequest.u.InternetOpenUrlW;
3071 req->lpszUrl = WININET_strdupW(lpszUrl);
3072 if (lpszHeaders)
3073 req->lpszHeaders = WININET_strdupW(lpszHeaders);
3074 else
3075 req->lpszHeaders = 0;
3076 req->dwHeadersLength = dwHeadersLength;
3077 req->dwFlags = dwFlags;
3078 req->dwContext = dwContext;
3079
3080 INTERNET_AsyncCall(&workRequest);
3081 /*
3082 * This is from windows.
3083 */
3084 INTERNET_SetLastError(ERROR_IO_PENDING);
3085 } else {
3086 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3087 }
3088
3089 lend:
3090 if( hIC )
3091 WININET_Release( &hIC->hdr );
3092 TRACE(" %p <--\n", ret);
3093
3094 return ret;
3095 }
3096
3097 /**********************************************************
3098 * InternetOpenUrlA (WININET.@)
3099 *
3100 * Opens an URL
3101 *
3102 * RETURNS
3103 * handle of connection or NULL on failure
3104 */
3105 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3106 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3107 {
3108 HINTERNET rc = (HINTERNET)NULL;
3109
3110 INT lenUrl;
3111 INT lenHeaders = 0;
3112 LPWSTR szUrl = NULL;
3113 LPWSTR szHeaders = NULL;
3114
3115 TRACE("\n");
3116
3117 if(lpszUrl) {
3118 lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
3119 szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
3120 if(!szUrl)
3121 return (HINTERNET)NULL;
3122 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
3123 }
3124
3125 if(lpszHeaders) {
3126 lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3127 szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3128 if(!szHeaders) {
3129 HeapFree(GetProcessHeap(), 0, szUrl);
3130 return (HINTERNET)NULL;
3131 }
3132 MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3133 }
3134
3135 rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3136 lenHeaders, dwFlags, dwContext);
3137
3138 HeapFree(GetProcessHeap(), 0, szUrl);
3139 HeapFree(GetProcessHeap(), 0, szHeaders);
3140
3141 return rc;
3142 }
3143
3144
3145 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3146 {
3147 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3148
3149 if (lpwite)
3150 {
3151 lpwite->dwError = 0;
3152 lpwite->response[0] = '\0';
3153 }
3154
3155 if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3156 {
3157 HeapFree(GetProcessHeap(), 0, lpwite);
3158 return NULL;
3159 }
3160
3161 return lpwite;
3162 }
3163
3164
3165 /***********************************************************************
3166 * INTERNET_SetLastError (internal)
3167 *
3168 * Set last thread specific error
3169 *
3170 * RETURNS
3171 *
3172 */
3173 void INTERNET_SetLastError(DWORD dwError)
3174 {
3175 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3176
3177 if (!lpwite)
3178 lpwite = INTERNET_AllocThreadError();
3179
3180 SetLastError(dwError);
3181 if(lpwite)
3182 lpwite->dwError = dwError;
3183 }
3184
3185
3186 /***********************************************************************
3187 * INTERNET_GetLastError (internal)
3188 *
3189 * Get last thread specific error
3190 *
3191 * RETURNS
3192 *
3193 */
3194 DWORD INTERNET_GetLastError(void)
3195 {
3196 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3197 if (!lpwite) return 0;
3198 /* TlsGetValue clears last error, so set it again here */
3199 SetLastError(lpwite->dwError);
3200 return lpwite->dwError;
3201 }
3202
3203
3204 /***********************************************************************
3205 * INTERNET_WorkerThreadFunc (internal)
3206 *
3207 * Worker thread execution function
3208 *
3209 * RETURNS
3210 *
3211 */
3212 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3213 {
3214 LPWORKREQUEST lpRequest = lpvParam;
3215 WORKREQUEST workRequest;
3216
3217 TRACE("\n");
3218
3219 memcpy(&workRequest, lpRequest, sizeof(WORKREQUEST));
3220 HeapFree(GetProcessHeap(), 0, lpRequest);
3221
3222 workRequest.asyncproc(&workRequest);
3223
3224 WININET_Release( workRequest.hdr );
3225 return TRUE;
3226 }
3227
3228
3229 /***********************************************************************
3230 * INTERNET_AsyncCall (internal)
3231 *
3232 * Retrieves work request from queue
3233 *
3234 * RETURNS
3235 *
3236 */
3237 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3238 {
3239 BOOL bSuccess;
3240 LPWORKREQUEST lpNewRequest;
3241
3242 TRACE("\n");
3243
3244 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3245 if (!lpNewRequest)
3246 return FALSE;
3247
3248 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
3249
3250 bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3251 if (!bSuccess)
3252 {
3253 HeapFree(GetProcessHeap(), 0, lpNewRequest);
3254 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
3255 }
3256
3257 return bSuccess;
3258 }
3259
3260
3261 /***********************************************************************
3262 * INTERNET_GetResponseBuffer (internal)
3263 *
3264 * RETURNS
3265 *
3266 */
3267 LPSTR INTERNET_GetResponseBuffer(void)
3268 {
3269 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3270 if (!lpwite)
3271 lpwite = INTERNET_AllocThreadError();
3272 TRACE("\n");
3273 return lpwite->response;
3274 }
3275
3276 /***********************************************************************
3277 * INTERNET_GetNextLine (internal)
3278 *
3279 * Parse next line in directory string listing
3280 *
3281 * RETURNS
3282 * Pointer to beginning of next line
3283 * NULL on failure
3284 *
3285 */
3286
3287 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3288 {
3289 struct timeval tv;
3290 fd_set infd;
3291 BOOL bSuccess = FALSE;
3292 INT nRecv = 0;
3293 LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3294
3295 TRACE("\n");
3296
3297 FD_ZERO(&infd);
3298 FD_SET(nSocket, &infd);
3299 tv.tv_sec=RESPONSE_TIMEOUT;
3300 tv.tv_usec=0;
3301
3302 while (nRecv < MAX_REPLY_LEN)
3303 {
3304 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
3305 {
3306 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3307 {
3308 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3309 goto lend;
3310 }
3311
3312 if (lpszBuffer[nRecv] == '\n')
3313 {
3314 bSuccess = TRUE;
3315 break;
3316 }
3317 if (lpszBuffer[nRecv] != '\r')
3318 nRecv++;
3319 }
3320 else
3321 {
3322 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3323 goto lend;
3324 }
3325 }
3326
3327 lend:
3328 if (bSuccess)
3329 {
3330 lpszBuffer[nRecv] = '\0';
3331 *dwLen = nRecv - 1;
3332 TRACE(":%d %s\n", nRecv, lpszBuffer);
3333 return lpszBuffer;
3334 }
3335 else
3336 {
3337 return NULL;
3338 }
3339 }
3340
3341 /**********************************************************
3342 * InternetQueryDataAvailable (WININET.@)
3343 *
3344 * Determines how much data is available to be read.
3345 *
3346 * RETURNS
3347 * TRUE on success, FALSE if an error occurred. If
3348 * INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3349 * no data is presently available, FALSE is returned with
3350 * the last error ERROR_IO_PENDING; a callback with status
3351 * INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3352 * data is available.
3353 */
3354 void AsyncInternetQueryDataAvailableProc(WORKREQUEST *workRequest)
3355 {
3356 LPWININETHTTPREQW lpwhr;
3357 INTERNET_ASYNC_RESULT iar;
3358 char buffer[4048];
3359
3360 TRACE("INTERNETQUERYDATAAVAILABLE %p\n", workRequest->hdr);
3361
3362 switch (workRequest->hdr->htype)
3363 {
3364 case WH_HHTTPREQ:
3365 lpwhr = (LPWININETHTTPREQW)workRequest->hdr;
3366 iar.dwResult = NETCON_recv(&lpwhr->netConnection, buffer,
3367 min(sizeof(buffer),
3368 lpwhr->dwContentLength - lpwhr->dwContentRead),
3369 MSG_PEEK, (int *)&iar.dwError);
3370 INTERNET_SendCallback(workRequest->hdr, workRequest->hdr->dwContext,
3371 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3372 sizeof(INTERNET_ASYNC_RESULT));
3373 break;
3374
3375 default:
3376 FIXME("unsupported file type\n");
3377 break;
3378 }
3379 }
3380
3381 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3382 LPDWORD lpdwNumberOfBytesAvailble,
3383 DWORD dwFlags, DWORD_PTR dwContext)
3384 {
3385 LPWININETHTTPREQW lpwhr;
3386 BOOL retval = FALSE;
3387 char buffer[4048];
3388
3389 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
3390 if (NULL == lpwhr)
3391 {
3392 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3393 return FALSE;
3394 }
3395
3396 TRACE("--> %p %i\n",lpwhr,lpwhr->hdr.htype);
3397
3398 switch (lpwhr->hdr.htype)
3399 {
3400 case WH_HHTTPREQ:
3401 retval = TRUE;
3402 if (NETCON_query_data_available(&lpwhr->netConnection,
3403 lpdwNumberOfBytesAvailble) &&
3404 !*lpdwNumberOfBytesAvailble)
3405 {
3406 /* Even if we are in async mode, we need to determine whether
3407 * there is actually more data available. We do this by trying
3408 * to peek only a single byte in async mode. */
3409 BOOL async = (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC);
3410 if (NETCON_recv(&lpwhr->netConnection, buffer,
3411 min(async ? 1 : sizeof(buffer),
3412 lpwhr->dwContentLength - lpwhr->dwContentRead),
3413 MSG_PEEK, (int *)lpdwNumberOfBytesAvailble) &&
3414 async && *lpdwNumberOfBytesAvailble)
3415 {
3416 WORKREQUEST workRequest;
3417
3418 *lpdwNumberOfBytesAvailble = 0;
3419 workRequest.asyncproc = AsyncInternetQueryDataAvailableProc;
3420 workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
3421
3422 retval = INTERNET_AsyncCall(&workRequest);
3423 if (!retval)
3424 {
3425 WININET_Release( &lpwhr->hdr );
3426 }
3427 else
3428 {
3429 INTERNET_SetLastError(ERROR_IO_PENDING);
3430 retval = FALSE;
3431 }
3432 }
3433 }
3434 break;
3435
3436 default:
3437 FIXME("unsupported file type\n");
3438 break;
3439 }
3440 WININET_Release( &lpwhr->hdr );
3441
3442 TRACE("<-- %i\n",retval);
3443 return retval;
3444 }
3445
3446
3447 /***********************************************************************
3448 * InternetLockRequestFile (WININET.@)
3449 */
3450 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3451 *lphLockReqHandle)
3452 {
3453 FIXME("STUB\n");
3454 return FALSE;
3455 }
3456
3457 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3458 {
3459 FIXME("STUB\n");
3460 return FALSE;
3461 }
3462
3463
3464 /***********************************************************************
3465 * InternetAutodial (WININET.@)
3466 *
3467 * On windows this function is supposed to dial the default internet
3468 * connection. We don't want to have Wine dial out to the internet so
3469 * we return TRUE by default. It might be nice to check if we are connected.
3470 *
3471 * RETURNS
3472 * TRUE on success
3473 * FALSE on failure
3474 *
3475 */
3476 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3477 {
3478 FIXME("STUB\n");
3479
3480 /* Tell that we are connected to the internet. */
3481 return TRUE;
3482 }
3483
3484 /***********************************************************************
3485 * InternetAutodialHangup (WININET.@)
3486 *
3487 * Hangs up a connection made with InternetAutodial
3488 *
3489 * PARAM
3490 * dwReserved
3491 * RETURNS
3492 * TRUE on success
3493 * FALSE on failure
3494 *
3495 */
3496 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3497 {
3498 FIXME("STUB\n");
3499
3500 /* we didn't dial, we don't disconnect */
3501 return TRUE;
3502 }
3503
3504 /***********************************************************************
3505 * InternetCombineUrlA (WININET.@)
3506 *
3507 * Combine a base URL with a relative URL
3508 *
3509 * RETURNS
3510 * TRUE on success
3511 * FALSE on failure
3512 *
3513 */
3514
3515 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3516 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3517 DWORD dwFlags)
3518 {
3519 HRESULT hr=S_OK;
3520
3521 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3522
3523 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3524 dwFlags ^= ICU_NO_ENCODE;
3525 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3526
3527 return (hr==S_OK);
3528 }
3529
3530 /***********************************************************************
3531 * InternetCombineUrlW (WININET.@)
3532 *
3533 * Combine a base URL with a relative URL
3534 *
3535 * RETURNS
3536 * TRUE on success
3537 * FALSE on failure
3538 *
3539 */
3540
3541 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3542 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3543 DWORD dwFlags)
3544 {
3545 HRESULT hr=S_OK;
3546
3547 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3548
3549 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3550 dwFlags ^= ICU_NO_ENCODE;
3551 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3552
3553 return (hr==S_OK);
3554 }
3555
3556 /* max port num is 65535 => 5 digits */
3557 #define MAX_WORD_DIGITS 5
3558
3559 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3560 (url)->dw##component##Length : strlenW((url)->lpsz##component))
3561 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3562 (url)->dw##component##Length : strlen((url)->lpsz##component))
3563
3564 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3565 {
3566 if ((nScheme == INTERNET_SCHEME_HTTP) &&
3567 (nPort == INTERNET_DEFAULT_HTTP_PORT))
3568 return TRUE;
3569 if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3570 (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3571 return TRUE;
3572 if ((nScheme == INTERNET_SCHEME_FTP) &&
3573 (nPort == INTERNET_DEFAULT_FTP_PORT))
3574 return TRUE;
3575 if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3576 (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3577 return TRUE;
3578
3579 if (nPort == INTERNET_INVALID_PORT_NUMBER)
3580 return TRUE;
3581
3582 return FALSE;
3583 }
3584
3585 /* opaque urls do not fit into the standard url hierarchy and don't have
3586 * two following slashes */
3587 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3588 {
3589 return (nScheme != INTERNET_SCHEME_FTP) &&
3590 (nScheme != INTERNET_SCHEME_GOPHER) &&
3591 (nScheme != INTERNET_SCHEME_HTTP) &&
3592 (nScheme != INTERNET_SCHEME_HTTPS) &&
3593 (nScheme != INTERNET_SCHEME_FILE);
3594 }
3595
3596 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3597 {
3598 int index;
3599 if (scheme < INTERNET_SCHEME_FIRST)
3600 return NULL;
3601 index = scheme - INTERNET_SCHEME_FIRST;
3602 if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3603 return NULL;
3604 return (LPCWSTR)&url_schemes[index];
3605 }
3606
3607 /* we can calculate using ansi strings because we're just
3608 * calculating string length, not size
3609 */
3610 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3611 LPDWORD lpdwUrlLength)
3612 {
3613 INTERNET_SCHEME nScheme;
3614
3615 *lpdwUrlLength = 0;
3616
3617 if (lpUrlComponents->lpszScheme)
3618 {
3619 DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3620 *lpdwUrlLength += dwLen;
3621 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3622 }
3623 else
3624 {
3625 LPCWSTR scheme;
3626
3627 nScheme = lpUrlComponents->nScheme;
3628
3629 if (nScheme == INTERNET_SCHEME_DEFAULT)
3630 nScheme = INTERNET_SCHEME_HTTP;
3631 scheme = INTERNET_GetSchemeString(nScheme);
3632 *lpdwUrlLength += strlenW(scheme);
3633 }
3634
3635 (*lpdwUrlLength)++; /* ':' */
3636 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3637 *lpdwUrlLength += strlen("//");
3638
3639 if (lpUrlComponents->lpszUserName)
3640 {
3641 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3642 *lpdwUrlLength += strlen("@");
3643 }
3644 else
3645 {
3646 if (lpUrlComponents->lpszPassword)
3647 {
3648 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3649 return FALSE;
3650 }
3651 }
3652
3653 if (lpUrlComponents->lpszPassword)
3654 {
3655 *lpdwUrlLength += strlen(":");
3656 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3657 }
3658
3659 if (lpUrlComponents->lpszHostName)
3660 {
3661 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3662
3663 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3664 {
3665