4 * Copyright 1999 Corel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define MAXHOSTNAME 100 /* from http.c */
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 # include <sys/socket.h>
42 #include "wine/debug.h"
44 #define NO_SHLWAPI_STREAM
49 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
51 #define MAX_IDLE_WORKER 1000*60*1
52 #define MAX_WORKER_THREADS 10
53 #define RESPONSE_TIMEOUT 30
55 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
56 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
61 CHAR response
[MAX_REPLY_LEN
];
62 } WITHREADERROR
, *LPWITHREADERROR
;
64 INTERNET_SCHEME
GetInternetScheme(LPCSTR lpszScheme
, INT nMaxCmp
);
65 BOOL WINAPI
INTERNET_FindNextFileA(HINTERNET hFind
, LPVOID lpvFindData
);
66 VOID
INTERNET_ExecuteWork();
68 DWORD g_dwTlsErrIndex
= TLS_OUT_OF_INDEXES
;
70 DWORD dwNumIdleThreads
;
71 HANDLE hEventArray
[2];
72 #define hQuitEvent hEventArray[0]
73 #define hWorkEvent hEventArray[1]
74 CRITICAL_SECTION csQueue
;
75 LPWORKREQUEST lpHeadWorkQueue
;
76 LPWORKREQUEST lpWorkQueueTail
;
78 /***********************************************************************
79 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
82 * hinstDLL [I] handle to the DLL's instance
84 * lpvReserved [I] reserved, must be NULL
92 WININET_LibMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
94 TRACE("%x,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
97 case DLL_PROCESS_ATTACH
:
99 g_dwTlsErrIndex
= TlsAlloc();
101 if (g_dwTlsErrIndex
== TLS_OUT_OF_INDEXES
)
104 hQuitEvent
= CreateEventA(0, TRUE
, FALSE
, NULL
);
105 hWorkEvent
= CreateEventA(0, FALSE
, FALSE
, NULL
);
106 InitializeCriticalSection(&csQueue
);
109 dwNumIdleThreads
= 0;
111 case DLL_THREAD_ATTACH
:
113 LPWITHREADERROR lpwite
= HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR
));
117 TlsSetValue(g_dwTlsErrIndex
, (LPVOID
)lpwite
);
121 case DLL_THREAD_DETACH
:
122 if (g_dwTlsErrIndex
!= TLS_OUT_OF_INDEXES
)
124 LPVOID lpwite
= TlsGetValue(g_dwTlsErrIndex
);
126 HeapFree(GetProcessHeap(), 0, lpwite
);
130 case DLL_PROCESS_DETACH
:
132 if (g_dwTlsErrIndex
!= TLS_OUT_OF_INDEXES
)
134 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex
));
135 TlsFree(g_dwTlsErrIndex
);
138 SetEvent(hQuitEvent
);
140 CloseHandle(hQuitEvent
);
141 CloseHandle(hWorkEvent
);
142 DeleteCriticalSection(&csQueue
);
150 /***********************************************************************
151 * InternetOpenA (WININET.@)
153 * Per-application initialization of wininet
156 * HINTERNET on success
160 HINTERNET WINAPI
InternetOpenA(LPCSTR lpszAgent
,
161 DWORD dwAccessType
, LPCSTR lpszProxy
,
162 LPCSTR lpszProxyBypass
, DWORD dwFlags
)
164 LPWININETAPPINFOA lpwai
= NULL
;
168 /* Clear any error information */
169 INTERNET_SetLastError(0);
171 lpwai
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA
));
173 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
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
)
182 if ((lpwai
->lpszAgent
= HeapAlloc( GetProcessHeap(),0,strlen(lpszAgent
)+1)))
183 strcpy( lpwai
->lpszAgent
, lpszAgent
);
185 if (NULL
!= lpszProxy
)
187 if ((lpwai
->lpszProxy
= HeapAlloc( GetProcessHeap(), 0, strlen(lpszProxy
)+1 )))
188 strcpy( lpwai
->lpszProxy
, lpszProxy
);
190 if (NULL
!= lpszProxyBypass
)
192 if ((lpwai
->lpszProxyBypass
= HeapAlloc( GetProcessHeap(), 0, strlen(lpszProxyBypass
)+1)))
193 strcpy( lpwai
->lpszProxyBypass
, lpszProxyBypass
);
195 lpwai
->dwAccessType
= dwAccessType
;
198 return (HINTERNET
)lpwai
;
202 /***********************************************************************
203 * InternetGetLastResponseInfoA (WININET.@)
205 * Return last wininet error description on the calling thread
208 * TRUE on success of writting to buffer
212 BOOL WINAPI
InternetGetLastResponseInfoA(LPDWORD lpdwError
,
213 LPSTR lpszBuffer
, LPDWORD lpdwBufferLength
)
215 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
219 *lpdwError
= lpwite
->dwError
;
222 strncpy(lpszBuffer
, lpwite
->response
, *lpdwBufferLength
);
223 *lpdwBufferLength
= strlen(lpszBuffer
);
226 *lpdwBufferLength
= 0;
232 /***********************************************************************
233 * InternetGetConnectedState (WININET.@)
235 * Return connected state
239 * if lpdwStatus is not null, return the status (off line,
240 * modem, lan...) in it.
241 * FALSE if not connected
243 BOOL WINAPI
InternetGetConnectedState(LPDWORD lpdwStatus
, DWORD dwReserved
)
246 FIXME("always returning LAN connection.\n");
247 *lpdwStatus
= INTERNET_CONNECTION_LAN
;
253 /***********************************************************************
254 * InternetConnectA (WININET.@)
256 * Open a ftp, gopher or http session
259 * HINTERNET a session handle on success
263 HINTERNET WINAPI
InternetConnectA(HINTERNET hInternet
,
264 LPCSTR lpszServerName
, INTERNET_PORT nServerPort
,
265 LPCSTR lpszUserName
, LPCSTR lpszPassword
,
266 DWORD dwService
, DWORD dwFlags
, DWORD dwContext
)
268 HINTERNET rc
= (HINTERNET
) NULL
;
272 /* Clear any error information */
273 INTERNET_SetLastError(0);
277 case INTERNET_SERVICE_FTP
:
278 rc
= FTP_Connect(hInternet
, lpszServerName
, nServerPort
,
279 lpszUserName
, lpszPassword
, dwFlags
, dwContext
);
282 case INTERNET_SERVICE_HTTP
:
283 rc
= HTTP_Connect(hInternet
, lpszServerName
, nServerPort
,
284 lpszUserName
, lpszPassword
, dwFlags
, dwContext
);
287 case INTERNET_SERVICE_GOPHER
:
295 /***********************************************************************
296 * InternetFindNextFileA (WININET.@)
298 * Continues a file search from a previous call to FindFirstFile
305 BOOL WINAPI
InternetFindNextFileA(HINTERNET hFind
, LPVOID lpvFindData
)
307 LPWININETAPPINFOA hIC
= NULL
;
308 LPWININETFINDNEXTA lpwh
= (LPWININETFINDNEXTA
) hFind
;
312 if (NULL
== lpwh
|| lpwh
->hdr
.htype
!= WH_HFINDNEXT
)
314 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
318 hIC
= GET_HWININET_FROM_LPWININETFINDNEXT(lpwh
);
319 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
321 WORKREQUEST workRequest
;
323 workRequest
.asyncall
= INTERNETFINDNEXTA
;
324 workRequest
.HFTPSESSION
= (DWORD
)hFind
;
325 workRequest
.LPFINDFILEDATA
= (DWORD
)lpvFindData
;
327 return INTERNET_AsyncCall(&workRequest
);
331 return INTERNET_FindNextFileA(hFind
, lpvFindData
);
335 /***********************************************************************
336 * INTERNET_FindNextFileA (Internal)
338 * Continues a file search from a previous call to FindFirstFile
345 BOOL WINAPI
INTERNET_FindNextFileA(HINTERNET hFind
, LPVOID lpvFindData
)
347 BOOL bSuccess
= TRUE
;
348 LPWININETAPPINFOA hIC
= NULL
;
349 LPWIN32_FIND_DATAA lpFindFileData
;
350 LPWININETFINDNEXTA lpwh
= (LPWININETFINDNEXTA
) hFind
;
354 if (NULL
== lpwh
|| lpwh
->hdr
.htype
!= WH_HFINDNEXT
)
356 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
360 /* Clear any error information */
361 INTERNET_SetLastError(0);
363 if (lpwh
->hdr
.lpwhparent
->htype
!= WH_HFTPSESSION
)
365 FIXME("Only FTP find next supported\n");
366 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
370 TRACE("index(%d) size(%ld)\n", lpwh
->index
, lpwh
->size
);
372 lpFindFileData
= (LPWIN32_FIND_DATAA
) lpvFindData
;
373 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
375 if (lpwh
->index
>= lpwh
->size
)
377 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
382 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
385 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData
->cFileName
, lpFindFileData
->nFileSizeLow
);
389 hIC
= GET_HWININET_FROM_LPWININETFINDNEXT(lpwh
);
390 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
392 INTERNET_ASYNC_RESULT iar
;
394 iar
.dwResult
= (DWORD
)bSuccess
;
395 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
397 hIC
->lpfnStatusCB(hFind
, lpwh
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
398 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
405 /***********************************************************************
406 * INTERNET_CloseHandle (internal)
408 * Close internet handle
414 VOID
INTERNET_CloseHandle(LPWININETAPPINFOA lpwai
)
416 if (lpwai
->lpszAgent
)
417 HeapFree(GetProcessHeap(), 0, lpwai
->lpszAgent
);
419 if (lpwai
->lpszProxy
)
420 HeapFree(GetProcessHeap(), 0, lpwai
->lpszProxy
);
422 if (lpwai
->lpszProxyBypass
)
423 HeapFree(GetProcessHeap(), 0, lpwai
->lpszProxyBypass
);
425 HeapFree(GetProcessHeap(), 0, lpwai
);
429 /***********************************************************************
430 * InternetCloseHandle (WININET.@)
432 * Generic close handle function
439 BOOL WINAPI
InternetCloseHandle(HINTERNET hInternet
)
442 LPWININETHANDLEHEADER lpwh
= (LPWININETHANDLEHEADER
) hInternet
;
448 /* Clear any error information */
449 INTERNET_SetLastError(0);
454 INTERNET_CloseHandle((LPWININETAPPINFOA
) lpwh
);
458 case WH_HHTTPSESSION
:
459 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA
) lpwh
);
464 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA
) lpwh
);
469 retval
= FTP_CloseSessionHandle((LPWININETFTPSESSIONA
) lpwh
);
473 retval
= FTP_CloseFindNextHandle((LPWININETFINDNEXTA
) lpwh
);
484 /***********************************************************************
485 * SetUrlComponentValue (Internal)
487 * Helper function for InternetCrackUrlA
494 BOOL
SetUrlComponentValue(LPSTR
* lppszComponent
, LPDWORD dwComponentLen
, LPCSTR lpszStart
, INT len
)
496 TRACE("%s (%d)\n", lpszStart
, len
);
498 if (*dwComponentLen
!= 0)
500 if (*lppszComponent
== NULL
)
502 *lppszComponent
= (LPSTR
)lpszStart
;
503 *dwComponentLen
= len
;
507 INT ncpylen
= min((*dwComponentLen
)-1, len
);
508 strncpy(*lppszComponent
, lpszStart
, ncpylen
);
509 (*lppszComponent
)[ncpylen
] = '\0';
510 *dwComponentLen
= ncpylen
;
518 /***********************************************************************
519 * InternetCrackUrlA (WININET.@)
521 * Break up URL into its components
523 * TODO: Handle dwFlags
530 BOOL WINAPI
InternetCrackUrlA(LPCSTR lpszUrl
, DWORD dwUrlLength
, DWORD dwFlags
,
531 LPURL_COMPONENTSA lpUrlComponents
)
535 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
538 LPSTR lpszParam
= NULL
;
539 BOOL bIsAbsolute
= FALSE
;
540 LPSTR lpszap
= (char*)lpszUrl
;
545 /* Determine if the URI is absolute. */
546 while (*lpszap
!= '\0')
548 if (isalnum(*lpszap
))
553 if ((*lpszap
== ':') && (lpszap
- lpszUrl
>= 2))
560 lpszcp
= (LPSTR
)lpszUrl
; /* Relative url */
567 lpszParam
= strpbrk(lpszap
, ";?");
568 if (lpszParam
!= NULL
)
570 if (!SetUrlComponentValue(&lpUrlComponents
->lpszExtraInfo
,
571 &lpUrlComponents
->dwExtraInfoLength
, lpszParam
+1, strlen(lpszParam
+1)))
577 if (bIsAbsolute
) /* Parse <protocol>:[//<net_loc>] */
581 /* Get scheme first. */
582 lpUrlComponents
->nScheme
= GetInternetScheme(lpszUrl
, lpszcp
- lpszUrl
);
583 if (!SetUrlComponentValue(&lpUrlComponents
->lpszScheme
,
584 &lpUrlComponents
->dwSchemeLength
, lpszUrl
, lpszcp
- lpszUrl
))
587 /* Eat ':' in protocol. */
590 /* Skip over slashes. */
602 lpszNetLoc
= strpbrk(lpszcp
, "/");
606 lpszNetLoc
= min(lpszNetLoc
, lpszParam
);
608 lpszNetLoc
= lpszParam
;
610 else if (!lpszNetLoc
)
611 lpszNetLoc
= lpszcp
+ strlen(lpszcp
);
619 /* [<user>[<:password>]@]<host>[:<port>] */
620 /* First find the user and password if they exist */
622 lpszHost
= strchr(lpszcp
, '@');
623 if (lpszHost
== NULL
|| lpszHost
> lpszNetLoc
)
625 /* username and password not specified. */
626 SetUrlComponentValue(&lpUrlComponents
->lpszUserName
,
627 &lpUrlComponents
->dwUserNameLength
, NULL
, 0);
628 SetUrlComponentValue(&lpUrlComponents
->lpszPassword
,
629 &lpUrlComponents
->dwPasswordLength
, NULL
, 0);
631 else /* Parse out username and password */
633 LPSTR lpszUser
= lpszcp
;
634 LPSTR lpszPasswd
= lpszHost
;
636 while (lpszcp
< lpszHost
)
644 SetUrlComponentValue(&lpUrlComponents
->lpszUserName
,
645 &lpUrlComponents
->dwUserNameLength
, lpszUser
, lpszPasswd
- lpszUser
);
647 if (lpszPasswd
!= lpszHost
)
649 SetUrlComponentValue(&lpUrlComponents
->lpszPassword
,
650 &lpUrlComponents
->dwPasswordLength
,
651 lpszPasswd
== lpszHost
? NULL
: lpszPasswd
,
652 lpszHost
- lpszPasswd
);
654 lpszcp
++; /* Advance to beginning of host */
657 /* Parse <host><:port> */
660 lpszPort
= lpszNetLoc
;
662 while (lpszcp
< lpszNetLoc
)
670 SetUrlComponentValue(&lpUrlComponents
->lpszHostName
,
671 &lpUrlComponents
->dwHostNameLength
, lpszHost
, lpszPort
- lpszHost
);
673 if (lpszPort
!= lpszNetLoc
)
674 lpUrlComponents
->nPort
= atoi(++lpszPort
);
678 /* Here lpszcp points to:
680 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
681 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
683 if (lpszcp
!= 0 && *lpszcp
!= '\0' && (!lpszParam
|| lpszcp
< lpszParam
))
687 /* Only truncate the parameter list if it's already been saved
688 * in lpUrlComponents->lpszExtraInfo.
690 if (lpszParam
&& lpUrlComponents
->dwExtraInfoLength
)
691 len
= lpszParam
- lpszcp
;
694 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
695 * newlines if necessary.
697 LPSTR lpsznewline
= strchr (lpszcp
, '\n');
698 if (lpsznewline
!= NULL
)
699 len
= lpsznewline
- lpszcp
;
701 len
= strlen(lpszcp
);
704 if (!SetUrlComponentValue(&lpUrlComponents
->lpszUrlPath
,
705 &lpUrlComponents
->dwUrlPathLength
, lpszcp
, len
))
710 lpUrlComponents
->dwUrlPathLength
= 0;
713 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl
, lpUrlComponents
->lpszHostName
,
714 lpUrlComponents
->lpszUrlPath
, lpUrlComponents
->lpszExtraInfo
);
720 /***********************************************************************
721 * GetUrlCacheEntryInfoA (WININET.@)
724 BOOL WINAPI
GetUrlCacheEntryInfoA(LPCSTR lpszUrl
,
725 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry
,
726 LPDWORD lpCacheEntrySize
)
732 /***********************************************************************
733 * CommitUrlCacheEntryA (WININET.@)
736 BOOL WINAPI
CommitUrlCacheEntryA(LPCSTR lpszUrl
, LPCSTR lpszLocalName
,
737 FILETIME ExpireTime
, FILETIME lastModified
, DWORD cacheEntryType
,
738 LPBYTE lpHeaderInfo
, DWORD headerSize
, LPCSTR fileExtension
,
745 /***********************************************************************
746 * InternetAttemptConnect (WININET.@)
748 * Attempt to make a connection to the internet
751 * ERROR_SUCCESS on success
752 * Error value on failure
755 DWORD WINAPI
InternetAttemptConnect(DWORD dwReserved
)
758 return ERROR_SUCCESS
;
762 /***********************************************************************
763 * InternetCanonicalizeUrlA (WININET.@)
765 * Escape unsafe characters and spaces
772 BOOL WINAPI
InternetCanonicalizeUrlA(LPCSTR lpszUrl
, LPSTR lpszBuffer
,
773 LPDWORD lpdwBufferLength
, DWORD dwFlags
)
776 TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl
), lpszBuffer
,
777 lpdwBufferLength
, dwFlags
);
779 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
780 dwFlags
^= ICU_NO_ENCODE
;
782 dwFlags
|= 0x80000000; /* Don't know what this means */
784 hr
= UrlCanonicalizeA(lpszUrl
, lpszBuffer
, lpdwBufferLength
, dwFlags
);
786 return (hr
== S_OK
) ? TRUE
: FALSE
;
789 /***********************************************************************
790 * InternetSetStatusCallback (WININET.@)
792 * Sets up a callback function which is called as progress is made
793 * during an operation.
796 * Previous callback or NULL on success
797 * INTERNET_INVALID_STATUS_CALLBACK on failure
800 INTERNET_STATUS_CALLBACK WINAPI
InternetSetStatusCallback(
801 HINTERNET hInternet
,INTERNET_STATUS_CALLBACK lpfnIntCB
)
803 INTERNET_STATUS_CALLBACK retVal
;
804 LPWININETAPPINFOA lpwai
= (LPWININETAPPINFOA
)hInternet
;
806 TRACE("0x%08lx\n", (ULONG
)hInternet
);
807 if (lpwai
->hdr
.htype
!= WH_HINIT
)
808 return INTERNET_INVALID_STATUS_CALLBACK
;
810 retVal
= lpwai
->lpfnStatusCB
;
811 lpwai
->lpfnStatusCB
= lpfnIntCB
;
817 /***********************************************************************
818 * InternetWriteFile (WININET.@)
820 * Write data to an open internet file
827 BOOL WINAPI
InternetWriteFile(HINTERNET hFile
, LPCVOID lpBuffer
,
828 DWORD dwNumOfBytesToWrite
, LPDWORD lpdwNumOfBytesWritten
)
832 LPWININETHANDLEHEADER lpwh
= (LPWININETHANDLEHEADER
) hFile
;
841 nSocket
= ((LPWININETHTTPREQA
)hFile
)->nSocketFD
;
845 nSocket
= ((LPWININETFILE
)hFile
)->nDataSocket
;
854 *lpdwNumOfBytesWritten
= INTERNET_WriteDataToStream(nSocket
, lpBuffer
, dwNumOfBytesToWrite
);
855 if (*lpdwNumOfBytesWritten
< 0)
856 *lpdwNumOfBytesWritten
= 0;
865 /***********************************************************************
866 * InternetReadFile (WININET.@)
868 * Read data from an open internet file
875 BOOL WINAPI
InternetReadFile(HINTERNET hFile
, LPVOID lpBuffer
,
876 DWORD dwNumOfBytesToRead
, LPDWORD dwNumOfBytesRead
)
880 LPWININETHANDLEHEADER lpwh
= (LPWININETHANDLEHEADER
) hFile
;
889 nSocket
= ((LPWININETHTTPREQA
)hFile
)->nSocketFD
;
893 nSocket
= ((LPWININETFILE
)hFile
)->nDataSocket
;
902 *dwNumOfBytesRead
= INTERNET_ReadDataFromStream(nSocket
, lpBuffer
, dwNumOfBytesToRead
);
903 if (*dwNumOfBytesRead
< 0)
904 *dwNumOfBytesRead
= 0;
913 /***********************************************************************
914 * InternetQueryOptionA (WININET.@)
916 * Queries an options on the specified handle
923 BOOL WINAPI
InternetQueryOptionA(HINTERNET hInternet
, DWORD dwOption
,
924 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
)
926 LPWININETHANDLEHEADER lpwhh
;
927 BOOL bSuccess
= FALSE
;
929 TRACE("0x%08lx\n", dwOption
);
931 if (NULL
== hInternet
)
933 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
937 lpwhh
= (LPWININETHANDLEHEADER
) hInternet
;
941 case INTERNET_OPTION_HANDLE_TYPE
:
943 ULONG type
= lpwhh
->htype
;
944 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type
);
946 if (*lpdwBufferLength
< sizeof(ULONG
))
947 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
950 memcpy(lpBuffer
, &type
, sizeof(ULONG
));
951 *lpdwBufferLength
= sizeof(ULONG
);
967 /***********************************************************************
968 * InternetSetOptionW (WININET.@)
970 * Sets an options on the specified handle
977 BOOL WINAPI
InternetSetOptionW(HINTERNET hInternet
, DWORD dwOption
,
978 LPVOID lpBuffer
, DWORD dwBufferLength
)
980 LPWININETHANDLEHEADER lpwhh
;
981 BOOL bSuccess
= FALSE
;
983 TRACE("0x%08lx\n", dwOption
);
985 if (NULL
== hInternet
)
987 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
991 lpwhh
= (LPWININETHANDLEHEADER
) hInternet
;
996 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1005 /***********************************************************************
1006 * InternetSetOptionA (WININET.@)
1008 * Sets an options on the specified handle.
1015 BOOL WINAPI
InternetSetOptionA(HINTERNET hInternet
, DWORD dwOption
,
1016 LPVOID lpBuffer
, DWORD dwBufferLength
)
1018 /* FIXME!!! implement if lpBuffer is a string, dwBufferLength is
1020 return InternetSetOptionW(hInternet
,dwOption
, lpBuffer
,
1025 /***********************************************************************
1026 * InternetGetCookieA (WININET.@)
1028 * Retrieve cookie from the specified url
1035 BOOL WINAPI
InternetGetCookieA(LPCSTR lpszUrl
, LPCSTR lpszCookieName
,
1036 LPSTR lpCookieData
, LPDWORD lpdwSize
)
1038 FIXME("(%s,%s,%p), stub!\n",debugstr_a(lpszUrl
),debugstr_a(lpszCookieName
),
1043 /***********************************************************************
1044 * InternetSetCookieA (WININET.@)
1046 * Sets cookie for the specified url
1053 BOOL WINAPI
InternetSetCookieA(
1054 LPCSTR lpszUrl
, LPCSTR lpszCookieName
, LPCSTR lpCookieData
1056 FIXME("(%s,%s,%s), stub!\n",debugstr_a(lpszUrl
),debugstr_a(lpszCookieName
),debugstr_a(lpCookieData
));
1060 /***********************************************************************
1061 * GetInternetScheme (internal)
1067 * INTERNET_SCHEME_UNKNOWN on failure
1070 INTERNET_SCHEME
GetInternetScheme(LPCSTR lpszScheme
, INT nMaxCmp
)
1072 if(lpszScheme
==NULL
)
1073 return INTERNET_SCHEME_UNKNOWN
;
1075 if (!strncasecmp("ftp", lpszScheme
, nMaxCmp
))
1076 return INTERNET_SCHEME_FTP
;
1077 else if (!strncasecmp("gopher", lpszScheme
, nMaxCmp
))
1078 return INTERNET_SCHEME_GOPHER
;
1079 else if (!strncasecmp("http", lpszScheme
, nMaxCmp
))
1080 return INTERNET_SCHEME_HTTP
;
1081 else if (!strncasecmp("https", lpszScheme
, nMaxCmp
))
1082 return INTERNET_SCHEME_HTTPS
;
1083 else if (!strncasecmp("file", lpszScheme
, nMaxCmp
))
1084 return INTERNET_SCHEME_FILE
;
1085 else if (!strncasecmp("news", lpszScheme
, nMaxCmp
))
1086 return INTERNET_SCHEME_NEWS
;
1087 else if (!strncasecmp("mailto", lpszScheme
, nMaxCmp
))
1088 return INTERNET_SCHEME_MAILTO
;
1090 return INTERNET_SCHEME_UNKNOWN
;
1093 /***********************************************************************
1094 * InternetCheckConnectionA (WININET.@)
1096 * Pings a requested host to check internet connection
1100 * TRUE on success and FALSE on failure. if a failures then
1101 * ERROR_NOT_CONNECTED is places into GetLastError
1104 BOOL WINAPI
InternetCheckConnectionA( LPCSTR lpszUrl
, DWORD dwFlags
, DWORD dwReserved
)
1107 * this is a kludge which runs the resident ping program and reads the output.
1109 * Anyone have a better idea?
1118 * Crack or set the Address
1120 if (lpszUrl
== NULL
)
1123 * According to the doc we are supost to use the ip for the next
1124 * server in the WnInet internal server database. I have
1125 * no idea what that is or how to get it.
1127 * So someone needs to implement this.
1129 FIXME("Unimplemented with URL of NULL\n");
1134 URL_COMPONENTSA componets
;
1136 ZeroMemory(&componets
,sizeof(URL_COMPONENTSA
));
1137 componets
.lpszHostName
= (LPSTR
)&host
;
1138 componets
.dwHostNameLength
= 1024;
1140 if (!InternetCrackUrlA(lpszUrl
,0,0,&componets
))
1143 TRACE("host name : %s\n",componets
.lpszHostName
);
1147 * Build our ping command
1149 strcpy(command
,"ping -w 1 ");
1150 strcat(command
,host
);
1151 strcat(command
," >/dev/null 2>/dev/null");
1153 TRACE("Ping command is : %s\n",command
);
1155 status
= system(command
);
1157 TRACE("Ping returned a code of %i \n",status
);
1159 /* Ping return code of 0 indicates success */
1166 SetLastError(ERROR_NOT_CONNECTED
);
1171 /**********************************************************
1172 * InternetOpenUrlA (WININET.@)
1177 * handle of connection or NULL on failure
1179 HINTERNET WINAPI
InternetOpenUrlA(HINTERNET hInternet
, LPCSTR lpszUrl
, LPCSTR lpszHeaders
, DWORD dwHeadersLength
, DWORD dwFlags
, DWORD dwContext
)
1181 URL_COMPONENTSA urlComponents
;
1182 char protocol
[32], hostName
[MAXHOSTNAME
], userName
[1024], password
[1024], path
[2048], extra
[1024];
1183 HINTERNET client
= NULL
, client1
= NULL
;
1184 urlComponents
.dwStructSize
= sizeof(URL_COMPONENTSA
);
1185 urlComponents
.lpszScheme
= protocol
;
1186 urlComponents
.dwSchemeLength
= 32;
1187 urlComponents
.lpszHostName
= hostName
;
1188 urlComponents
.dwHostNameLength
= MAXHOSTNAME
;
1189 urlComponents
.lpszUserName
= userName
;
1190 urlComponents
.dwUserNameLength
= 1024;
1191 urlComponents
.lpszPassword
= password
;
1192 urlComponents
.dwPasswordLength
= 1024;
1193 urlComponents
.lpszUrlPath
= path
;
1194 urlComponents
.dwUrlPathLength
= 2048;
1195 urlComponents
.lpszExtraInfo
= extra
;
1196 urlComponents
.dwExtraInfoLength
= 1024;
1197 if(!InternetCrackUrlA(lpszUrl
, strlen(lpszUrl
), 0, &urlComponents
))
1199 switch(urlComponents
.nScheme
) {
1200 case INTERNET_SCHEME_FTP
:
1201 if(urlComponents
.nPort
== 0)
1202 urlComponents
.nPort
= INTERNET_DEFAULT_FTP_PORT
;
1203 client
= InternetConnectA(hInternet
, hostName
, urlComponents
.nPort
, userName
, password
, INTERNET_SERVICE_FTP
, dwFlags
, dwContext
);
1204 return FtpOpenFileA(client
, path
, GENERIC_READ
, dwFlags
, dwContext
);
1206 case INTERNET_SCHEME_HTTP
:
1207 case INTERNET_SCHEME_HTTPS
:
1209 LPCSTR accept
[2] = { "*/*", NULL
};
1210 char *hostreq
=(char*)malloc(strlen(hostName
)+9);
1211 sprintf(hostreq
, "Host: %s\r\n", hostName
);
1212 if(urlComponents
.nPort
== 0) {
1213 if(urlComponents
.nScheme
== INTERNET_SCHEME_HTTP
)
1214 urlComponents
.nPort
= INTERNET_DEFAULT_HTTP_PORT
;
1216 urlComponents
.nPort
= INTERNET_DEFAULT_HTTPS_PORT
;
1218 client
= InternetConnectA(hInternet
, hostName
, urlComponents
.nPort
, userName
, password
, INTERNET_SERVICE_HTTP
, dwFlags
, dwContext
);
1221 client1
= HttpOpenRequestA(hInternet
, NULL
, path
, NULL
, NULL
, accept
, dwFlags
, dwContext
);
1222 if(client1
== NULL
) {
1223 InternetCloseHandle(client
);
1226 HttpAddRequestHeadersA(client1
, lpszHeaders
, dwHeadersLength
, HTTP_ADDREQ_FLAG_ADD
);
1227 HttpAddRequestHeadersA(client1
, hostreq
, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW
);
1228 if(!HttpSendRequestA(client1
, NULL
, 0, NULL
, 0)) {
1229 InternetCloseHandle(client1
);
1230 InternetCloseHandle(client
);
1236 case INTERNET_SCHEME_GOPHER
:
1237 /* gopher doesn't seem to be implemented in wine, but it's supposed
1238 * to be supported by InternetOpenUrlA. */
1243 InternetCloseHandle(client
);
1246 /***********************************************************************
1247 * INTERNET_WriteDataToStream (internal)
1249 * Send data to server
1253 * number of characters sent on success
1256 int INTERNET_WriteDataToStream(int nDataSocket
, LPCVOID Buffer
, DWORD BytesToWrite
)
1258 if (nDataSocket
== -1)
1261 return send(nDataSocket
, Buffer
, BytesToWrite
, 0);
1265 /***********************************************************************
1266 * INTERNET_ReadDataFromStream (internal)
1268 * Read data from http server
1272 * number of characters sent on success
1275 int INTERNET_ReadDataFromStream(int nDataSocket
, LPVOID Buffer
, DWORD BytesToRead
)
1277 if (nDataSocket
== -1)
1280 return recv(nDataSocket
, Buffer
, BytesToRead
, 0);
1284 /***********************************************************************
1285 * INTERNET_SetLastError (internal)
1287 * Set last thread specific error
1292 void INTERNET_SetLastError(DWORD dwError
)
1294 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
1296 SetLastError(dwError
);
1297 lpwite
->dwError
= dwError
;
1301 /***********************************************************************
1302 * INTERNET_GetLastError (internal)
1304 * Get last thread specific error
1309 DWORD
INTERNET_GetLastError()
1311 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
1312 return lpwite
->dwError
;
1316 /***********************************************************************
1317 * INTERNET_WorkerThreadFunc (internal)
1319 * Worker thread execution function
1324 DWORD
INTERNET_WorkerThreadFunc(LPVOID
*lpvParam
)
1330 dwWaitRes
= WaitForMultipleObjects(2, hEventArray
, FALSE
, MAX_IDLE_WORKER
);
1332 if (dwWaitRes
== WAIT_OBJECT_0
+ 1)
1333 INTERNET_ExecuteWork();
1337 InterlockedIncrement(&dwNumIdleThreads
);
1340 InterlockedDecrement(&dwNumIdleThreads
);
1341 InterlockedDecrement(&dwNumThreads
);
1342 TRACE("Worker thread exiting\n");
1347 /***********************************************************************
1348 * INTERNET_InsertWorkRequest (internal)
1350 * Insert work request into queue
1355 BOOL
INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest
)
1357 BOOL bSuccess
= FALSE
;
1358 LPWORKREQUEST lpNewRequest
;
1362 lpNewRequest
= HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST
));
1365 memcpy(lpNewRequest
, lpWorkRequest
, sizeof(WORKREQUEST
));
1366 lpNewRequest
->prev
= NULL
;
1368 EnterCriticalSection(&csQueue
);
1370 lpNewRequest
->next
= lpWorkQueueTail
;
1371 if (lpWorkQueueTail
)
1372 lpWorkQueueTail
->prev
= lpNewRequest
;
1373 lpWorkQueueTail
= lpNewRequest
;
1374 if (!lpHeadWorkQueue
)
1375 lpHeadWorkQueue
= lpWorkQueueTail
;
1377 LeaveCriticalSection(&csQueue
);
1386 /***********************************************************************
1387 * INTERNET_GetWorkRequest (internal)
1389 * Retrieves work request from queue
1394 BOOL
INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest
)
1396 BOOL bSuccess
= FALSE
;
1397 LPWORKREQUEST lpRequest
= NULL
;
1401 EnterCriticalSection(&csQueue
);
1403 if (lpHeadWorkQueue
)
1405 lpRequest
= lpHeadWorkQueue
;
1406 lpHeadWorkQueue
= lpHeadWorkQueue
->prev
;
1407 if (lpRequest
== lpWorkQueueTail
)
1408 lpWorkQueueTail
= lpHeadWorkQueue
;
1411 LeaveCriticalSection(&csQueue
);
1415 memcpy(lpWorkRequest
, lpRequest
, sizeof(WORKREQUEST
));
1416 HeapFree(GetProcessHeap(), 0, lpRequest
);
1424 /***********************************************************************
1425 * INTERNET_AsyncCall (internal)
1427 * Retrieves work request from queue
1432 BOOL
INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest
)
1436 BOOL bSuccess
= FALSE
;
1440 if (InterlockedDecrement(&dwNumIdleThreads
) < 0)
1442 InterlockedIncrement(&dwNumIdleThreads
);
1444 if (InterlockedIncrement(&dwNumThreads
) > MAX_WORKER_THREADS
||
1445 !(hThread
= CreateThread(NULL
, 0,
1446 (LPTHREAD_START_ROUTINE
)INTERNET_WorkerThreadFunc
, NULL
, 0, &dwTID
)))
1448 InterlockedDecrement(&dwNumThreads
);
1449 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED
);
1453 TRACE("Created new thread\n");
1457 INTERNET_InsertWorkRequest(lpWorkRequest
);
1458 SetEvent(hWorkEvent
);
1466 /***********************************************************************
1467 * INTERNET_ExecuteWork (internal)
1472 VOID
INTERNET_ExecuteWork()
1474 WORKREQUEST workRequest
;
1478 if (INTERNET_GetWorkRequest(&workRequest
))
1480 switch (workRequest
.asyncall
)
1483 FTP_FtpPutFileA((HINTERNET
)workRequest
.HFTPSESSION
, (LPCSTR
)workRequest
.LPSZLOCALFILE
,
1484 (LPCSTR
)workRequest
.LPSZNEWREMOTEFILE
, workRequest
.DWFLAGS
, workRequest
.DWCONTEXT
);
1485 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZLOCALFILE
);
1486 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZNEWREMOTEFILE
);
1489 case FTPSETCURRENTDIRECTORYA
:
1490 FTP_FtpSetCurrentDirectoryA((HINTERNET
)workRequest
.HFTPSESSION
,
1491 (LPCSTR
)workRequest
.LPSZDIRECTORY
);
1492 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZDIRECTORY
);
1495 case FTPCREATEDIRECTORYA
:
1496 FTP_FtpCreateDirectoryA((HINTERNET
)workRequest
.HFTPSESSION
,
1497 (LPCSTR
)workRequest
.LPSZDIRECTORY
);
1498 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZDIRECTORY
);
1501 case FTPFINDFIRSTFILEA
:
1502 FTP_FtpFindFirstFileA((HINTERNET
)workRequest
.HFTPSESSION
,
1503 (LPCSTR
)workRequest
.LPSZSEARCHFILE
,
1504 (LPWIN32_FIND_DATAA
)workRequest
.LPFINDFILEDATA
, workRequest
.DWFLAGS
,
1505 workRequest
.DWCONTEXT
);
1506 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZSEARCHFILE
);
1509 case FTPGETCURRENTDIRECTORYA
:
1510 FTP_FtpGetCurrentDirectoryA((HINTERNET
)workRequest
.HFTPSESSION
,
1511 (LPSTR
)workRequest
.LPSZDIRECTORY
, (LPDWORD
)workRequest
.LPDWDIRECTORY
);
1515 FTP_FtpOpenFileA((HINTERNET
)workRequest
.HFTPSESSION
,
1516 (LPCSTR
)workRequest
.LPSZFILENAME
,
1517 workRequest
.FDWACCESS
,
1518 workRequest
.DWFLAGS
,
1519 workRequest
.DWCONTEXT
);
1520 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZFILENAME
);
1524 FTP_FtpGetFileA((HINTERNET
)workRequest
.HFTPSESSION
,
1525 (LPCSTR
)workRequest
.LPSZREMOTEFILE
,
1526 (LPCSTR
)workRequest
.LPSZNEWFILE
,
1527 (BOOL
)workRequest
.FFAILIFEXISTS
,
1528 workRequest
.DWLOCALFLAGSATTRIBUTE
,
1529 workRequest
.DWFLAGS
,
1530 workRequest
.DWCONTEXT
);
1531 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZREMOTEFILE
);
1532 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZNEWFILE
);
1535 case FTPDELETEFILEA
:
1536 FTP_FtpDeleteFileA((HINTERNET
)workRequest
.HFTPSESSION
,
1537 (LPCSTR
)workRequest
.LPSZFILENAME
);
1538 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZFILENAME
);
1541 case FTPREMOVEDIRECTORYA
:
1542 FTP_FtpRemoveDirectoryA((HINTERNET
)workRequest
.HFTPSESSION
,
1543 (LPCSTR
)workRequest
.LPSZDIRECTORY
);
1544 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZDIRECTORY
);
1547 case FTPRENAMEFILEA
:
1548 FTP_FtpRenameFileA((HINTERNET
)workRequest
.HFTPSESSION
,
1549 (LPCSTR
)workRequest
.LPSZSRCFILE
,
1550 (LPCSTR
)workRequest
.LPSZDESTFILE
);
1551 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZSRCFILE
);
1552 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZDESTFILE
);
1555 case INTERNETFINDNEXTA
:
1556 INTERNET_FindNextFileA((HINTERNET
)workRequest
.HFTPSESSION
,
1557 (LPWIN32_FIND_DATAA
)workRequest
.LPFINDFILEDATA
);
1560 case HTTPSENDREQUESTA
:
1561 HTTP_HttpSendRequestA((HINTERNET
)workRequest
.HFTPSESSION
,
1562 (LPCSTR
)workRequest
.LPSZHEADER
,
1563 workRequest
.DWHEADERLENGTH
,
1564 (LPVOID
)workRequest
.LPOPTIONAL
,
1565 workRequest
.DWOPTIONALLENGTH
);
1566 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZHEADER
);
1569 case HTTPOPENREQUESTA
:
1570 HTTP_HttpOpenRequestA((HINTERNET
)workRequest
.HFTPSESSION
,
1571 (LPCSTR
)workRequest
.LPSZVERB
,
1572 (LPCSTR
)workRequest
.LPSZOBJECTNAME
,
1573 (LPCSTR
)workRequest
.LPSZVERSION
,
1574 (LPCSTR
)workRequest
.LPSZREFERRER
,
1575 (LPCSTR
*)workRequest
.LPSZACCEPTTYPES
,
1576 workRequest
.DWFLAGS
,
1577 workRequest
.DWCONTEXT
);
1578 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZVERB
);
1579 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZOBJECTNAME
);
1580 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZVERSION
);
1581 HeapFree(GetProcessHeap(), 0, (LPVOID
)workRequest
.LPSZREFERRER
);
1589 /***********************************************************************
1590 * INTERNET_GetResponseBuffer
1595 LPSTR
INTERNET_GetResponseBuffer()
1597 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
1598 return lpwite
->response
;
1602 /***********************************************************************
1603 * INTERNET_GetNextLine (internal)
1605 * Parse next line in directory string listing
1608 * Pointer to beginning of next line
1613 LPSTR
INTERNET_GetNextLine(INT nSocket
, LPSTR lpszBuffer
, LPDWORD dwBuffer
)
1617 BOOL bSuccess
= FALSE
;
1623 FD_SET(nSocket
, &infd
);
1624 tv
.tv_sec
=RESPONSE_TIMEOUT
;
1627 while (nRecv
< *dwBuffer
)
1629 if (select(nSocket
+1,&infd
,NULL
,NULL
,&tv
) > 0)
1631 if (recv(nSocket
, &lpszBuffer
[nRecv
], 1, 0) <= 0)
1633 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1637 if (lpszBuffer
[nRecv
] == '\n')
1642 if (lpszBuffer
[nRecv
] != '\r')
1647 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT
);
1655 lpszBuffer
[nRecv
] = '\0';
1656 *dwBuffer
= nRecv
- 1;
1657 TRACE(":%d %s\n", nRecv
, lpszBuffer
);