source: trunk/src/wininet/internet.c@ 21916

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 44.1 KB
Line 
1/* $Id: internet.c,v 1.7 2002-11-27 14:28:17 sandervl Exp $
2 *
3 * Wininet
4 *
5 * Copyright 1999 Corel Corporation
6 *
7 * Ulrich Czekalla
8 *
9 */
10
11#include <windows.h>
12#include <wininet.h>
13#include <debugtools.h>
14#include <winerror.h>
15#include <shlwapi.h>
16#include <tchar.h>
17#include <winsock.h>
18#include <ipexport.h>
19#include <icmpapi.h>
20
21#ifdef __WIN32OS2__
22#include <stdlib.h>
23#include <string.h>
24#include <ctype.h>
25#include <win/windef.h>
26#define strncasecmp strnicmp
27#define MAXHOSTNAME 100
28#else
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <stdlib.h>
32#endif
33
34#include "internet.h"
35
36DEFAULT_DEBUG_CHANNEL(wininet)
37
38#define MAX_IDLE_WORKER 1000*60*1
39#define MAX_WORKER_THREADS 10
40#define RESPONSE_TIMEOUT 30
41
42#define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh)\
43(LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
44
45typedef struct
46{
47 DWORD dwError;
48 CHAR response[ MAX_REPLY_LEN];
49} WITHREADERROR, *LPWITHREADERROR;
50
51INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, int nMaxCmp);
52BOOL INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpFindData);
53VOID INTERNET_ExecuteWork(void);
54
55DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
56LONG dwNumThreads;
57LONG dwNumIdleThreads;
58HANDLE hEventArray[2];
59#define hQuitEvent hEventArray[0]
60#define hWorkEvent hEventArray[1]
61CRITICAL_SECTION csQueue;
62LPWORKREQUEST lpHeadWorkQueue;
63LPWORKREQUEST lpWorkQueueTail;
64
65/***********************************************************************
66 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
67 *
68 * PARAMS
69 * hinstDLL [I] handle to the 'dlls' instance
70 * fdwReason [I]
71 * lpvReserved [I] reserverd, must be NULL
72 *
73 * RETURNS
74 * Success: TRUE
75 * Failure: FALSE
76 */
77
78BOOL WINAPI
79WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
80{
81 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
82
83 switch (fdwReason) {
84 case DLL_PROCESS_ATTACH:
85 {
86#ifdef __WIN32OS2__
87 WORD ver = MAKEWORD (2, 2);
88 WSADATA data;
89#endif
90 g_dwTlsErrIndex = TlsAlloc();
91
92 if(g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
93 return FALSE;
94
95 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
96 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
97 InitializeCriticalSection(&csQueue);
98
99 dwNumThreads=0;
100 dwNumIdleThreads=0;
101#ifdef __WIN32OS2__
102 WSAStartup ( ver, &data );
103#endif
104 }
105 case DLL_THREAD_ATTACH:
106 {
107 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
108
109 if (NULL == lpwite)
110 return FALSE;
111
112 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
113 }
114 break;
115
116 case DLL_THREAD_DETACH:
117 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
118 {
119 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
120 if(lpwite)
121 HeapFree(GetProcessHeap(), 0, lpwite);
122 }
123 break;
124
125 case DLL_PROCESS_DETACH:
126 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
127 {
128 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
129 TlsFree(g_dwTlsErrIndex);
130 }
131
132 SetEvent(hQuitEvent);
133
134 CloseHandle(hQuitEvent);
135 CloseHandle(hWorkEvent);
136 DeleteCriticalSection(&csQueue);
137#ifdef __WIN32OS2__
138 WSACleanup();
139#endif
140 break;
141 }
142
143 return TRUE;
144}
145
146
147/***********************************************************************
148 * InternetOpenA (WININET.113)
149 *
150 * Per-application initialization of wininet
151 *
152 * RETURNS
153 * HINTERNET on success
154 * NULL on failure
155 *
156 */
157INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
158 DWORD dwAccessType, LPCSTR lpszProxy,
159 LPCSTR lpszProxyBypass, DWORD dwFlags)
160{
161 LPWININETAPPINFOA lpwai = NULL;
162
163 TRACE("InternetOpenA\n");
164
165 /* Clear any error information */
166 INTERNET_SetLastError(0);
167
168 TRACE("InternetOpenA...\n");
169
170 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
171 if (NULL == lpwai)
172 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
173 else
174 {
175 memset(lpwai, 0, sizeof(WININETAPPINFOA));
176 lpwai->hdr.htype = WH_HINIT;
177 lpwai->hdr.lpwhparent = NULL;
178 lpwai->hdr.dwFlags = dwFlags;
179 if (NULL != lpszAgent)
180 lpwai->lpszAgent = strdup(lpszAgent);
181 if (NULL != lpszProxy)
182 lpwai->lpszProxy = strdup(lpszProxy);
183 if (NULL != lpszProxyBypass)
184 lpwai->lpszProxyBypass = strdup(lpszProxyBypass);
185 lpwai->dwAccessType = dwAccessType;
186 }
187
188 return (HINTERNET)lpwai;
189}
190
191
192/***********************************************************************
193 * InternetGetLastResponseInfoA (WININET.108)
194 *
195 * Return last wininet error description on the calling thread
196 *
197 * RETURNS
198 * TRUE on success of writting to buffer
199 * FALSE on failure
200 *
201 */
202BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
203 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
204{
205 LPWITHREADERROR lpwite=(LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
206
207 *lpdwError = lpwite->dwError;
208 if (lpwite->dwError)
209 {
210 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
211 *lpdwBufferLength = strlen( lpszBuffer);
212 }
213 else
214 *lpdwBufferLength=0;
215
216 return TRUE;
217}
218
219/***********************************************************************
220 * InternetGetConnectedState (WININET.105)
221 *
222 * Return connected state
223 *
224 * RETURNS
225 * True if connected
226 * if lpdwStatus is not NULL, return the status (off line,
227 * modem, lan...) in it.
228 * FALSE if not connected
229 */
230BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
231{
232 if (lpdwStatus) {
233 FIXME("always returning LAN connection.\n");
234 *lpdwStatus = INTERNET_CONNECTION_LAN;
235 }
236 return TRUE;
237}
238
239/***********************************************************************
240 * InternetConnectA (WININET.93)
241 *
242 * Open a ftp, gopher or http session
243 *
244 * RETURNS
245 * HINTERNET a session handle on success
246 * NULL on failure
247 *
248 */
249INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
250 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
251 LPCSTR lpszUserName, LPCSTR lpszPassword,
252 DWORD dwService, DWORD dwFlags, DWORD dwContext)
253{
254 HINTERNET rc = (HINTERNET) NULL;
255
256 TRACE("\n");
257
258 /* Clear any error information */
259 INTERNET_SetLastError(0);
260
261 switch (dwService)
262 {
263 case INTERNET_SERVICE_FTP:
264 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
265 lpszUserName, lpszPassword, dwFlags, dwContext);
266 break;
267
268 case INTERNET_SERVICE_HTTP:
269 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
270 lpszUserName, lpszPassword, dwFlags, dwContext);
271 break;
272
273 case INTERNET_SERVICE_GOPHER:
274 default:
275 break;
276 }
277
278 return rc;
279}
280
281
282/***********************************************************************
283 * InternetFindNextFileA (WININET.102)
284 *
285 * Continues a file search from a previous call to FindFirstFile
286 *
287 * RETURNS
288 * TRUE on success
289 * FALSE on failure
290 *
291 */
292BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
293{
294 LPWININETAPPINFOA hIC = NULL;
295 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
296
297 TRACE("\n");
298 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
299 {
300 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
301 return FALSE;
302 }
303
304 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
305 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
306 {
307 WORKREQUEST workRequest;
308
309 workRequest.asyncall = INTERNETFINDNEXTA;
310 workRequest.HFTPSESSION = (DWORD)hFind;
311 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
312
313 return INTERNET_AsyncCall(&workRequest);
314 }
315 else
316 return INTERNET_FindNextFileA(hFind, lpvFindData);
317}
318
319
320/***********************************************************************
321 * INTERNET_FindNextFileA (Internal)
322 *
323 * Continues a file search from a previous call to FindFirstFile
324 *
325 * RETURNS
326 * TRUE on success
327 * FALSE on failure
328 *
329 */
330BOOL INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
331{
332 BOOL bSuccess = TRUE;
333 LPWININETAPPINFOA hIC = NULL;
334 LPWIN32_FIND_DATAA lpFindFileData;
335 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
336
337 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
338 {
339 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
340 return FALSE;
341 }
342
343 /* Clear any error information */
344 INTERNET_SetLastError(0);
345
346 if(lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
347 {
348 FIXME("Only FTP find next supported\n");
349 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
350 return FALSE;
351 }
352
353 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
354 memset(lpFindFileData, 0, sizeof(WIN32_FIND_DATAA));
355
356 if(lpwh->index >= lpwh->size)
357 {
358 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
359 bSuccess = FALSE;
360 goto lend;
361 }
362
363 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
364 lpwh->index++;
365
366lend:
367 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
368 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
369 {
370 INTERNET_ASYNC_RESULT iar;
371
372 iar.dwResult = (DWORD)bSuccess;
373 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
374
375 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
376 &iar, sizeof(INTERNET_ASYNC_RESULT));
377 }
378
379 return bSuccess;
380}
381
382
383/***********************************************************************
384 * INTERNET_CloseHandle (Internal)
385 *
386 * Closes internet handle
387 *
388 * RETURNS
389 * void
390 *
391 */
392void INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
393{
394 if(lpwai->lpszAgent)
395 free(lpwai->lpszAgent);
396
397 if(lpwai->lpszProxy)
398 free(lpwai->lpszProxy);
399
400 if(lpwai->lpszProxyBypass)
401 free(lpwai->lpszProxyBypass);
402
403 HeapFree(GetProcessHeap(), 0, lpwai);
404}
405
406/***********************************************************************
407 * InternetCloseHandle (WININET.89)
408 *
409 * Continues a file search from a previous call to FindFirstFile
410 *
411 * RETURNS
412 * TRUE on success
413 * FALSE on failure
414 *
415 */
416BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
417{
418 BOOL retval = FALSE;
419 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
420
421 TRACE("\n");
422 if (NULL == lpwh)
423 return FALSE;
424
425 /* Clear any error information */
426 INTERNET_SetLastError(0);
427
428 switch (lpwh->htype)
429 {
430 case WH_HINIT:
431 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
432 retval = TRUE;
433 break;
434
435 case WH_HHTTPSESSION:
436 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
437 retval = TRUE;
438 break;
439
440 case WH_HHTTPREQ:
441 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
442 retval = TRUE;
443 break;
444
445 case WH_HFTPSESSION:
446 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
447 break;
448
449 case WH_HFINDNEXT:
450 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
451 break;
452
453 default:
454 break;
455 }
456
457 return retval;
458}
459
460/***********************************************************************
461 * SetUrlComponentValue (Internal)
462 *
463 * Helper function for InternetCrackUrlA
464 *
465 * RETURNS
466 * TRUE on success
467 * FALSE on failure
468 *
469 */
470BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
471 LPCSTR lpszStart, INT len)
472{
473 TRACE("%s (%d)\n", lpszStart, len);
474
475 if (*dwComponentLen != 0)
476 {
477 if (*lppszComponent == NULL)
478 {
479 *lppszComponent = (LPSTR)lpszStart;
480 *dwComponentLen = len;
481 }
482 else
483 {
484 INT ncpylen = min((*dwComponentLen)-1, len);
485 if (lpszStart)
486 strncpy(*lppszComponent, lpszStart, ncpylen);
487 (*lppszComponent)[ncpylen] = '\0';
488 *dwComponentLen = ncpylen;
489 }
490 }
491
492 return TRUE;
493}
494
495
496
497/***********************************************************************
498 * InternetAttemptConnect (WININET.81)
499 *
500 * Attempt to make a connection to the internet
501 *
502 * RETURNS
503 * ERROR_SUCCESS on success
504 * Error value on failure
505 *
506 */
507INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
508{
509 FIXME("Stub\n");
510 return ERROR_SUCCESS;
511}
512
513
514/***********************************************************************
515 * InternetCanonicalizeUrlA (WININET.85)
516 *
517 * Escape unsafe characters and spaces
518 *
519 * RETURNS
520 * TRUE on success
521 * FALSE on failure
522 *
523 */
524BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
525 LPDWORD lpdwBufferLength, DWORD dwFlags)
526{
527 HRESULT hr;
528 TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
529 lpdwBufferLength, dwFlags);
530
531 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
532 dwFlags ^= ICU_NO_ENCODE;
533
534 dwFlags |= 0x80000000; /* Don't know what this means */
535
536 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
537
538 return (hr == S_OK) ? TRUE : FALSE;
539}
540
541/***********************************************************************
542 * InternetSetStatusCallback (WININET.133)
543 *
544 * Sets up a callback function which is called as progress is made
545 * during an operation.
546 *
547 * RETURNS
548 * Previous callback or NULL on success
549 * INTERNET_INVALID_STATUS_CALLBACK on failure
550 *
551 */
552INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
553 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
554{
555 INTERNET_STATUS_CALLBACK retVal;
556 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
557
558 TRACE("\n");
559 if (lpwai->hdr.htype != WH_HINIT)
560 return INTERNET_INVALID_STATUS_CALLBACK;
561
562 retVal = lpwai->lpfnStatusCB;
563 lpwai->lpfnStatusCB = lpfnIntCB;
564
565 return retVal;
566}
567
568
569/***********************************************************************
570 * InternetWriteFile (WININET.138)
571 *
572 * Write data to an open internet file
573 *
574 * RETURNS
575 * TRUE on success
576 * FALSE on failure
577 *
578 */
579BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
580 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
581{
582 BOOL retval = FALSE;
583 int nSocket = INVALID_SOCKET;
584 int nBytesWritten;
585 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
586
587 TRACE("\n");
588 if (NULL == lpwh)
589 return FALSE;
590
591 switch (lpwh->htype)
592 {
593 case WH_HHTTPREQ:
594 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
595 break;
596
597 case WH_HFILE:
598 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
599 break;
600
601 default:
602 break;
603 }
604
605 if (INVALID_SOCKET != nSocket)
606 {
607 nBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
608 if (nBytesWritten < 0)
609 *lpdwNumOfBytesWritten = 0;
610 else
611 {
612 *lpdwNumOfBytesWritten = nBytesWritten;
613 retval = TRUE;
614 }
615 }
616
617 return retval;
618}
619
620
621/***********************************************************************
622 * InternetReadFile (WININET.121)
623 *
624 * Read data from an open internet file
625 *
626 * RETURNS
627 * TRUE on success
628 * FALSE on failure
629 *
630 */
631BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
632 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
633{
634 BOOL retval = FALSE;
635 int nBytesRead;
636 int nSocket = INVALID_SOCKET;
637 LONG *lpBytesAvailable = 0;
638 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
639
640 TRACE("\n");
641 if (NULL == lpwh)
642 return FALSE;
643
644 switch (lpwh->htype)
645 {
646 case WH_HHTTPREQ:
647 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
648 break;
649
650 case WH_HFILE:
651 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
652 lpBytesAvailable = &(((LPWININETFILE)hFile)->lBytesAvailable);
653 break;
654
655 default:
656 break;
657 }
658
659 if (INVALID_SOCKET != nSocket)
660 {
661 nBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
662 if (nBytesRead < 0)
663 *dwNumOfBytesRead = 0;
664 else
665 {
666 *dwNumOfBytesRead = nBytesRead;
667 retval = TRUE;
668 }
669 }
670
671 if(lpBytesAvailable)
672 *lpBytesAvailable -= *dwNumOfBytesRead;
673
674 return retval;
675}
676
677/***********************************************************************
678 * InternetQueryOptionA
679 *
680 * Queries an options on the specified handle
681 *
682 * RETURNS
683 * TRUE on success
684 * FALSE on failure
685 *
686 */
687BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
688 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
689{
690 LPWININETHANDLEHEADER lpwhh;
691 BOOL bSuccess = FALSE;
692
693 TRACE("0x%08lx\n", dwOption);
694
695 if (NULL == hInternet)
696 {
697 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
698 return FALSE;
699 }
700
701 lpwhh = (LPWININETHANDLEHEADER) hInternet;
702
703 switch (dwOption)
704 {
705 case INTERNET_OPTION_HANDLE_TYPE:
706 {
707 ULONG type = lpwhh->htype;
708 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
709
710 if (*lpdwBufferLength < sizeof(ULONG))
711 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
712 else
713 {
714 memcpy(lpBuffer, &type, sizeof(ULONG));
715 *lpdwBufferLength = sizeof(ULONG);
716 bSuccess = TRUE;
717 }
718
719 break;
720 }
721
722 default:
723 FIXME("Stub!");
724 break;
725 }
726
727 return bSuccess;
728}
729
730
731/***********************************************************************
732 * GetInternetScheme (internal)
733 *
734 * Get scheme of url
735 *
736 * RETURNS
737 * scheme on success
738 * INTERNET_SCHEME_UNKNOWN on failure
739 *
740 */
741INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, int nMaxCmp)
742{
743 if(lpszScheme==NULL)
744 return INTERNET_SCHEME_UNKNOWN;
745
746 if( (strncasecmp("ftp", lpszScheme, nMaxCmp) == 0))
747 return INTERNET_SCHEME_FTP;
748
749 else if( (strncasecmp("gopher", lpszScheme, nMaxCmp) == 0))
750 return INTERNET_SCHEME_GOPHER;
751
752 else if( (strncasecmp("http", lpszScheme, nMaxCmp) == 0))
753 return INTERNET_SCHEME_HTTP;
754
755 else if( (strncasecmp("https", lpszScheme, nMaxCmp) == 0))
756 return INTERNET_SCHEME_HTTPS;
757
758 else if( (strncasecmp("file", lpszScheme, nMaxCmp) == 0))
759 return INTERNET_SCHEME_FILE;
760
761 else if( (strncasecmp("news", lpszScheme, nMaxCmp) == 0))
762 return INTERNET_SCHEME_NEWS;
763
764 else if( (strncasecmp("mailto", lpszScheme, nMaxCmp) == 0))
765 return INTERNET_SCHEME_MAILTO;
766 else
767 return INTERNET_SCHEME_UNKNOWN;
768}
769
770/***********************************************************************
771 * InternetCheckConnectionA
772 *
773 * Pings a requested host to check internet connection
774 *
775 * RETURNS
776 * TRUE on success and FALSE on failure.
777 * On failure ERROR_NOT_CONNECTED is placed into GetLastError
778 */
779BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
780{
781 /* Instead of WINE's shelling out and executing a 'ping' we'll use the */
782 /* ICMP.DLL instead. */
783 DWORD rc=0;
784 HANDLE hIcmp;
785 char RequestBuffer[]="Odin - PING request, please reply...";
786 char lpszHost[1024],ReplyBuffer[256];
787 URL_COMPONENTSA UrlComponents;
788 ULONG dest_addr;
789 struct hostent *host;
790
791 if(!lpszUrl)
792 {
793 FIXME("Unimplemented with URL of NULL\n");
794 return TRUE;
795 }
796
797 memset(&UrlComponents, 0, sizeof(URL_COMPONENTSA));
798
799 UrlComponents.lpszHostName = lpszHost;
800 UrlComponents.dwHostNameLength = 1024;
801
802 if(!InternetCrackUrlA(lpszUrl, 0, 0, &UrlComponents))
803 {
804 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
805 return FALSE;
806 }
807
808 hIcmp = IcmpCreateFile();
809
810 if(!hIcmp)
811 {
812 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
813 return FALSE;
814 }
815
816 dest_addr = inet_addr(lpszHost);
817
818 if(dest_addr == 0)
819 host = gethostbyname(lpszHost);
820 else
821 host = gethostbyaddr(lpszHost, strlen(lpszHost), PF_INET);
822
823 if(host->h_addr)
824 rc=IcmpSendEcho(hIcmp,
825 (IPAddr)host->h_addr,
826 RequestBuffer,
827 strlen(RequestBuffer),
828 NULL,
829 ReplyBuffer,
830 256,
831 5000);
832 else
833 rc = 0;
834
835 IcmpCloseHandle(hIcmp);
836
837 return rc>0;
838}
839
840/***********************************************************************
841 * WriteDataToStream (internal)
842 *
843 * Send data to server
844 *
845 * RETURNS
846 *
847 * number of characters sent on success
848 * -1 on error
849 */
850int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
851{
852 if (INVALID_SOCKET == nDataSocket)
853 return SOCKET_ERROR;
854
855 return send(nDataSocket, Buffer, BytesToWrite, 0);
856}
857
858
859/***********************************************************************
860 * INTERNET_ReadDataFromStream (internal)
861 *
862 * Read data from http server
863 *
864 * RETURNS
865 *
866 * number of characters sent on success
867 * -1 on error
868 */
869int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
870{
871 if (INVALID_SOCKET == nDataSocket)
872 return SOCKET_ERROR;
873
874 return recv(nDataSocket, Buffer, BytesToRead, 0);
875}
876
877
878/***********************************************************************
879 * INTERNET_SetLastError (internal)
880 *
881 * Set last thread specific error
882 *
883 * RETURNS
884 *
885 */
886void INTERNET_SetLastError(DWORD dwError)
887{
888 LPWITHREADERROR lpwite;
889
890 lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
891
892 SetLastError(dwError);
893 lpwite->dwError = dwError;
894}
895
896
897/************************************************************************
898 * INTERNET_GetLastError (internal)
899 *
900 * Get last thread specific error
901 *
902 * RETURNS
903 *
904 */
905DWORD INTERNET_GetLastError()
906{
907 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
908 return lpwite->dwError;
909}
910
911
912/************************************************************************
913 * INTERNET_WorkerThreadFunc (internal)
914 *
915 * Worker thread execution function
916 *
917 * RETURNS
918 *
919 */
920DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
921{
922 DWORD dwWaitRes;
923
924 while (1)
925 {
926 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
927
928 if (dwWaitRes == WAIT_OBJECT_0 + 1)
929 INTERNET_ExecuteWork();
930 else
931 break;
932
933 InterlockedIncrement(&dwNumIdleThreads);
934 }
935
936 InterlockedDecrement(&dwNumIdleThreads);
937 InterlockedDecrement(&dwNumThreads);
938 TRACE("Worker thread exiting\n");
939 return TRUE;
940}
941
942
943/************************************************************************
944 * INTERNET_InsertWorkRequest (internal)
945 *
946 * Insert work request into queue
947 *
948 * RETURNS
949 *
950 */
951BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
952{
953 BOOL bSuccess = FALSE;
954 LPWORKREQUEST lpNewRequest;
955
956 TRACE("\n");
957
958 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
959 if (lpNewRequest)
960 {
961 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
962 lpNewRequest->prev = NULL;
963
964 EnterCriticalSection(&csQueue);
965
966 lpNewRequest->next = lpWorkQueueTail;
967 if (lpWorkQueueTail)
968 lpWorkQueueTail->prev = lpNewRequest;
969 lpWorkQueueTail = lpNewRequest;
970 if (!lpHeadWorkQueue)
971 lpHeadWorkQueue = lpWorkQueueTail;
972
973 LeaveCriticalSection(&csQueue);
974
975 bSuccess = TRUE;
976 }
977
978 return bSuccess;
979}
980
981
982/************************************************************************
983 * INTERNET_GetWorkRequest (internal)
984 *
985 * Retrieves work request from queue
986 *
987 * RETURNS
988 *
989 */
990BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
991{
992 BOOL bSuccess = FALSE;
993 LPWORKREQUEST lpRequest = NULL;
994
995 TRACE("\n");
996
997 EnterCriticalSection(&csQueue);
998
999 if (lpHeadWorkQueue)
1000 {
1001 lpRequest = lpHeadWorkQueue;
1002 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1003 if (lpRequest == lpWorkQueueTail)
1004 lpWorkQueueTail = lpHeadWorkQueue;
1005 }
1006
1007 LeaveCriticalSection(&csQueue);
1008
1009 if (lpRequest)
1010 {
1011 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1012 HeapFree(GetProcessHeap(), 0, lpRequest);
1013 bSuccess = TRUE;
1014 }
1015
1016 return bSuccess;
1017}
1018
1019
1020/************************************************************************
1021 * INTERNET_AsyncCall (internal)
1022 *
1023 * Retrieves work request from queue
1024 *
1025 * RETURNS
1026 *
1027 */
1028BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1029{
1030 HANDLE hThread;
1031 DWORD dwTID;
1032 BOOL bSuccess = FALSE;
1033
1034 TRACE("\n");
1035
1036 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1037 {
1038 InterlockedIncrement(&dwNumIdleThreads);
1039
1040 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1041 !(hThread = CreateThread(NULL, 0,
1042 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1043 {
1044 InterlockedDecrement(&dwNumThreads);
1045 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1046 goto lerror;
1047 }
1048
1049 TRACE("Created new thread\n");
1050 }
1051
1052 bSuccess = TRUE;
1053 INTERNET_InsertWorkRequest(lpWorkRequest);
1054 SetEvent(hWorkEvent);
1055
1056lerror:
1057
1058 return bSuccess;
1059}
1060
1061
1062/************************************************************************
1063 * INTERNET_ExecuteWork (internal)
1064 *
1065 * RETURNS
1066 *
1067 */
1068VOID INTERNET_ExecuteWork()
1069{
1070 WORKREQUEST workRequest;
1071
1072 TRACE("\n");
1073
1074 if (INTERNET_GetWorkRequest(&workRequest))
1075 {
1076 switch (workRequest.asyncall)
1077 {
1078 case FTPPUTFILEA:
1079 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1080 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1081 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1082 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1083 break;
1084
1085 case FTPSETCURRENTDIRECTORYA:
1086 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1087 (LPCSTR)workRequest.LPSZDIRECTORY);
1088 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1089 break;
1090
1091 case FTPCREATEDIRECTORYA:
1092 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1093 (LPCSTR)workRequest.LPSZDIRECTORY);
1094 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1095 break;
1096
1097 case FTPFINDFIRSTFILEA:
1098 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1099 (LPCSTR)workRequest.LPSZSEARCHFILE,
1100 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1101 workRequest.DWCONTEXT);
1102 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1103 break;
1104
1105 case FTPGETCURRENTDIRECTORYA:
1106 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1107 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1108 break;
1109
1110 case FTPOPENFILEA:
1111 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1112 (LPCSTR)workRequest.LPSZFILENAME,
1113 workRequest.FDWACCESS,
1114 workRequest.DWFLAGS,
1115 workRequest.DWCONTEXT);
1116 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1117 break;
1118
1119 case FTPGETFILEA:
1120 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1121 (LPCSTR)workRequest.LPSZREMOTEFILE,
1122 (LPCSTR)workRequest.LPSZNEWFILE,
1123 (BOOL)workRequest.FFAILIFEXISTS,
1124 workRequest.DWLOCALFLAGSATTRIBUTE,
1125 workRequest.DWFLAGS,
1126 workRequest.DWCONTEXT);
1127 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1128 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1129 break;
1130
1131 case FTPDELETEFILEA:
1132 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1133 (LPCSTR)workRequest.LPSZFILENAME);
1134 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1135 break;
1136
1137 case FTPREMOVEDIRECTORYA:
1138 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1139 (LPCSTR)workRequest.LPSZDIRECTORY);
1140 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1141 break;
1142
1143 case FTPRENAMEFILEA:
1144 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1145 (LPCSTR)workRequest.LPSZSRCFILE,
1146 (LPCSTR)workRequest.LPSZDESTFILE);
1147 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1148 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1149 break;
1150
1151 case INTERNETFINDNEXTA:
1152 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1153 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1154 break;
1155
1156 case HTTPSENDREQUESTA:
1157 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1158 (LPCSTR)workRequest.LPSZHEADER,
1159 workRequest.DWHEADERLENGTH,
1160 (LPVOID)workRequest.LPOPTIONAL,
1161 workRequest.DWOPTIONALLENGTH);
1162 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1163 break;
1164
1165 case HTTPOPENREQUESTA:
1166 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1167 (LPCSTR)workRequest.LPSZVERB,
1168 (LPCSTR)workRequest.LPSZOBJECTNAME,
1169 (LPCSTR)workRequest.LPSZVERSION,
1170 (LPCSTR)workRequest.LPSZREFERRER,
1171 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1172 workRequest.DWFLAGS,
1173 workRequest.DWCONTEXT);
1174 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1175 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1176 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1177 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1178 break;
1179
1180 }
1181 }
1182}
1183
1184
1185/************************************************************************
1186 * INTERNET_GetResponseBuffer
1187 *
1188 * RETURNS
1189 *
1190 */
1191LPSTR INTERNET_GetResponseBuffer()
1192{
1193 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1194 return lpwite->response;
1195}
1196
1197
1198/************************************************************************
1199 * INTERNET_GetNextLine (internal)
1200 *
1201 * Parse next line in directory string listing
1202 *
1203 * RETURNS
1204 * Pointer to begining of next line
1205 * NULL on failure
1206 *
1207 */
1208LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1209{
1210 struct timeval tv;
1211 fd_set infd;
1212 BOOL bSuccess = FALSE;
1213 INT nRecv = 0;
1214
1215 TRACE("\n");
1216
1217 FD_ZERO(&infd);
1218 FD_SET(nSocket, &infd);
1219 tv.tv_sec=RESPONSE_TIMEOUT;
1220 tv.tv_usec=0;
1221
1222 while (nRecv < *dwBuffer)
1223 {
1224 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1225 {
1226 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1227 {
1228 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1229 goto lend;
1230 }
1231
1232 if (lpszBuffer[nRecv] == '\n')
1233 {
1234 bSuccess = TRUE;
1235 break;
1236 }
1237 if (lpszBuffer[nRecv] != '\r')
1238 nRecv++;
1239 }
1240 else
1241 {
1242 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1243 goto lend;
1244}
1245 }
1246
1247lend:
1248 if (bSuccess)
1249 {
1250 lpszBuffer[nRecv] = '\0';
1251 *dwBuffer = nRecv - 1;
1252 TRACE(":%d %s\n", nRecv, lpszBuffer);
1253 return lpszBuffer;
1254 }
1255 else
1256 {
1257 return NULL;
1258 }
1259}
1260
1261
1262/************************************************************************
1263 * InternetQueryDataAvailable (WININET.118)
1264 *
1265 * Fetch the amount of data available for retrieval
1266 *
1267 * RETURNS
1268 * TRUE on success
1269 * FALSE on failure
1270 *
1271 */
1272BOOL WINAPI InternetQueryDataAvailable(HINTERNET hFile,LPDWORD lpdwNumberOfBytesAvailable,
1273 DWORD dwFlags, DWORD dwContext)
1274{
1275 LONG lBytesAvailable;
1276 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
1277
1278 if (NULL == lpwh)
1279 {
1280 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1281 return FALSE;
1282 }
1283
1284 WriteLog("InternetQueryDataAvailable for hHandle %08x",lpwh);
1285
1286 switch (lpwh->htype)
1287 {
1288 case WH_HHTTPREQ:
1289 *lpdwNumberOfBytesAvailable = -1;
1290 break;
1291
1292 case WH_HFILE:
1293 *lpdwNumberOfBytesAvailable = ((LPWININETFILE)lpwh)->lBytesAvailable;
1294 break;
1295
1296 default:
1297 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1298 return FALSE;
1299 }
1300
1301 if(*lpdwNumberOfBytesAvailable == -1)
1302 return FALSE;
1303
1304 WriteLog("InternetQueryDataAvailable returns %d",*lpdwNumberOfBytesAvailable);
1305
1306 return TRUE;
1307}
1308
1309
1310/**********************************************************
1311 * InternetOpenUrlA (WININET.@)
1312 *
1313 * Opens an URL
1314 *
1315 * RETURNS
1316 * handle of connection or NULL on failure
1317 */
1318HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
1319 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
1320{
1321 URL_COMPONENTSA urlComponents;
1322 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
1323 char password[1024], path[2048], extra[1024];
1324 HINTERNET client = NULL, client1 = NULL;
1325 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
1326 urlComponents.lpszScheme = protocol;
1327 urlComponents.dwSchemeLength = 32;
1328 urlComponents.lpszHostName = hostName;
1329 urlComponents.dwHostNameLength = MAXHOSTNAME;
1330 urlComponents.lpszUserName = userName;
1331 urlComponents.dwUserNameLength = 1024;
1332 urlComponents.lpszPassword = password;
1333 urlComponents.dwPasswordLength = 1024;
1334 urlComponents.lpszUrlPath = path;
1335 urlComponents.dwUrlPathLength = 2048;
1336 urlComponents.lpszExtraInfo = extra;
1337 urlComponents.dwExtraInfoLength = 1024;
1338 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
1339 return NULL;
1340 switch(urlComponents.nScheme) {
1341 case INTERNET_SCHEME_FTP:
1342 if(urlComponents.nPort == 0)
1343 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
1344 client = InternetConnectA(hInternet, hostName, urlComponents.nPort,
1345 userName, password, INTERNET_SERVICE_FTP, dwFlags, dwContext);
1346 return FtpOpenFileA(client, path, GENERIC_READ, dwFlags, dwContext);
1347 break;
1348 case INTERNET_SCHEME_HTTP:
1349 case INTERNET_SCHEME_HTTPS:
1350 {
1351 LPCSTR accept[2] = { "*/*", NULL };
1352 char *hostreq=(char*)malloc(strlen(hostName)+9);
1353 sprintf(hostreq, "Host: %s\r\n", hostName);
1354 if(urlComponents.nPort == 0) {
1355 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
1356 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1357 else
1358 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
1359 }
1360 client = InternetConnectA(hInternet, hostName, urlComponents.nPort, userName,
1361 password, INTERNET_SERVICE_HTTP, dwFlags, dwContext);
1362 if(client == NULL)
1363 return NULL;
1364 client1 = HttpOpenRequestA(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
1365 if(client1 == NULL) {
1366 InternetCloseHandle(client);
1367 return NULL;
1368 }
1369 if (lpszHeaders)
1370 HttpAddRequestHeadersA(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
1371 HttpAddRequestHeadersA(client1, hostreq, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
1372 if(!HttpSendRequestA(client1, NULL, 0, NULL, 0)) {
1373 InternetCloseHandle(client1);
1374 InternetCloseHandle(client);
1375 return NULL;
1376 }
1377 return client1;
1378 break;
1379 }
1380 case INTERNET_SCHEME_GOPHER:
1381 /* gopher doesn't seem to be implemented in wine, but it's supposed
1382 * to be supported by InternetOpenUrlA. */
1383 default:
1384 return NULL;
1385 }
1386 if(client != NULL)
1387 InternetCloseHandle(client);
1388}
1389
1390/**********************************************************
1391 * InternetOpenUrlW (WININET.@)
1392 *
1393 * Opens an URL
1394 *
1395 * RETURNS
1396 * handle of connection or NULL on failure
1397 */
1398HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
1399 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
1400{
1401 HINTERNET rc = (HINTERNET)NULL;
1402
1403 INT lenUrl = lstrlenW(lpszUrl)+1;
1404 INT lenHeaders = lstrlenW(lpszHeaders)+1;
1405 CHAR *szUrl = (CHAR *)malloc(lenUrl*sizeof(CHAR));
1406 CHAR *szHeaders = (CHAR *)malloc(lenHeaders*sizeof(CHAR));
1407
1408 if (!szUrl || !szHeaders)
1409 {
1410 if (szUrl)
1411 free(szUrl);
1412 if (szHeaders)
1413 free(szHeaders);
1414 return (HINTERNET)NULL;
1415 }
1416
1417 WideCharToMultiByte(CP_ACP, -1, lpszUrl, -1, szUrl, lenUrl,
1418 NULL, NULL);
1419 WideCharToMultiByte(CP_ACP, -1, lpszHeaders, -1, szHeaders, lenHeaders,
1420 NULL, NULL);
1421
1422 rc = InternetOpenUrlA(hInternet, szUrl, szHeaders,
1423 dwHeadersLength, dwFlags, dwContext);
1424
1425 free(szUrl);
1426 free(szHeaders);
1427
1428 return rc;
1429}
1430
1431/***********************************************************************
1432 * InternetCrackUrlA (WININET.@)
1433 *
1434 * Break up URL into its components
1435 *
1436 * TODO: Handle dwFlags
1437 *
1438 * RETURNS
1439 * TRUE on success
1440 * FALSE on failure
1441 *
1442 */
1443BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1444 LPURL_COMPONENTSA lpUrlComponents)
1445{
1446 /*
1447 * RFC 1808
1448 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1449 *
1450 */
1451 LPSTR lpszParam = NULL;
1452 BOOL bIsAbsolute = FALSE;
1453 LPSTR lpszap = (char*)lpszUrl;
1454 LPSTR lpszcp = NULL;
1455
1456 TRACE("\n");
1457
1458 /* Determine if the URI is absolute. */
1459 while (*lpszap != '\0')
1460 {
1461 if (isalnum(*lpszap))
1462 {
1463 lpszap++;
1464 continue;
1465 }
1466 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1467 {
1468 bIsAbsolute = TRUE;
1469 lpszcp = lpszap;
1470 }
1471 else
1472 {
1473 lpszcp = (LPSTR)lpszUrl; /* Relative url */
1474 }
1475
1476 break;
1477 }
1478
1479 /* Parse <params> */
1480 lpszParam = strpbrk(lpszap, ";?");
1481 if (lpszParam != NULL)
1482 {
1483 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
1484 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
1485 {
1486 return FALSE;
1487 }
1488 }
1489
1490 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1491 {
1492 LPSTR lpszNetLoc;
1493
1494 /* Get scheme first. */
1495 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
1496 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
1497 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
1498 return FALSE;
1499
1500 /* Eat ':' in protocol. */
1501 lpszcp++;
1502
1503 /* Skip over slashes. */
1504 if (*lpszcp == '/')
1505 {
1506 lpszcp++;
1507 if (*lpszcp == '/')
1508 {
1509 lpszcp++;
1510 if (*lpszcp == '/')
1511 lpszcp++;
1512 }
1513 }
1514
1515 lpszNetLoc = strpbrk(lpszcp, "/");
1516 if (lpszParam)
1517 {
1518 if (lpszNetLoc)
1519 lpszNetLoc = min(lpszNetLoc, lpszParam);
1520 else
1521 lpszNetLoc = lpszParam;
1522 }
1523 else if (!lpszNetLoc)
1524 lpszNetLoc = lpszcp + strlen(lpszcp);
1525
1526 /* Parse net-loc */
1527 if (lpszNetLoc)
1528 {
1529 LPSTR lpszHost;
1530 LPSTR lpszPort;
1531
1532 /* [<user>[<:password>]@]<host>[:<port>] */
1533 /* First find the user and password if they exist */
1534
1535 lpszHost = strchr(lpszcp, '@');
1536 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1537 {
1538 /* username and password not specified. */
1539 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
1540 &lpUrlComponents->dwUserNameLength, NULL, 0);
1541 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
1542 &lpUrlComponents->dwPasswordLength, NULL, 0);
1543 }
1544 else /* Parse out username and password */
1545 {
1546 LPSTR lpszUser = lpszcp;
1547 LPSTR lpszPasswd = lpszHost;
1548
1549 while (lpszcp < lpszHost)
1550 {
1551 if (*lpszcp == ':')
1552 lpszPasswd = lpszcp;
1553
1554 lpszcp++;
1555 }
1556
1557 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
1558 &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
1559
1560 if (lpszPasswd != lpszHost)
1561 lpszPasswd++;
1562 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
1563 &lpUrlComponents->dwPasswordLength,
1564 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1565 lpszHost - lpszPasswd);
1566
1567 lpszcp++; /* Advance to beginning of host */
1568 }
1569
1570 /* Parse <host><:port> */
1571
1572 lpszHost = lpszcp;
1573 lpszPort = lpszNetLoc;
1574
1575 while (lpszcp < lpszNetLoc)
1576 {
1577 if (*lpszcp == ':')
1578 lpszPort = lpszcp;
1579
1580 lpszcp++;
1581 }
1582
1583 SetUrlComponentValue(&lpUrlComponents->lpszHostName,
1584 &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
1585
1586 if (lpszPort != lpszNetLoc)
1587 lpUrlComponents->nPort = atoi(++lpszPort);
1588 else
1589 lpUrlComponents->nPort = 0;
1590 }
1591 }
1592
1593 /* Here lpszcp points to:
1594 *
1595 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1596 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1597 */
1598 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1599 {
1600 INT len;
1601
1602 /* Only truncate the parameter list if it's already been saved
1603 * in lpUrlComponents->lpszExtraInfo.
1604 */
1605 if (lpszParam && lpUrlComponents->dwExtraInfoLength)
1606 len = lpszParam - lpszcp;
1607 else
1608 {
1609 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1610 * newlines if necessary.
1611 */
1612 LPSTR lpsznewline = strchr (lpszcp, '\n');
1613 if (lpsznewline != NULL)
1614 len = lpsznewline - lpszcp;
1615 else
1616 len = strlen(lpszcp);
1617 }
1618
1619 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
1620 &lpUrlComponents->dwUrlPathLength, lpszcp, len))
1621 return FALSE;
1622 }
1623 else
1624 {
1625 lpUrlComponents->dwUrlPathLength = 0;
1626 }
1627
1628 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl, lpUrlComponents->lpszHostName,
1629 lpUrlComponents->lpszUrlPath, lpUrlComponents->lpszExtraInfo);
1630
1631 return TRUE;
1632}
1633
Note: See TracBrowser for help on using the repository browser.