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

Last change on this file since 9439 was 9439, checked in by sandervl, 23 years ago

PF: Some updates

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