ntdll: Connect syscall frames across user callbacks on x86-64.
[wine.git] / dlls / wininet / utility.c
bloba9a0b9f8d94fc18b0fe60bafdd4afde929abf48e
1 /*
2 * Wininet - Utility functions
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
7 * Ulrich Czekalla
8 * Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "ws2tcpip.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wininet.h"
35 #include "winnls.h"
37 #include "wine/debug.h"
38 #include "internet.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
42 #define TIME_STRING_LEN 30
44 time_t ConvertTimeString(LPCWSTR asctime)
46 WCHAR tmpChar[TIME_STRING_LEN];
47 WCHAR *tmpChar2;
48 struct tm t;
49 int timelen = lstrlenW(asctime);
51 if(!timelen)
52 return 0;
54 /* FIXME: the atoiWs below rely on that tmpChar is \0 padded */
55 memset( tmpChar, 0, sizeof(tmpChar) );
56 lstrcpynW(tmpChar, asctime, TIME_STRING_LEN);
58 /* Assert that the string is the expected length */
59 if (lstrlenW(asctime) >= TIME_STRING_LEN) FIXME("\n");
61 /* Convert a time such as 'Mon, 15 Nov 1999 16:09:35 GMT' into a SYSTEMTIME structure
62 * We assume the time is in this format
63 * and divide it into easy to swallow chunks
65 tmpChar[3]='\0';
66 tmpChar[7]='\0';
67 tmpChar[11]='\0';
68 tmpChar[16]='\0';
69 tmpChar[19]='\0';
70 tmpChar[22]='\0';
71 tmpChar[25]='\0';
73 memset( &t, 0, sizeof(t) );
74 t.tm_year = wcstol(tmpChar+12, NULL, 10) - 1900;
75 t.tm_mday = wcstol(tmpChar+5, NULL, 10);
76 t.tm_hour = wcstol(tmpChar+17, NULL, 10);
77 t.tm_min = wcstol(tmpChar+20, NULL, 10);
78 t.tm_sec = wcstol(tmpChar+23, NULL, 10);
80 /* and month */
81 tmpChar2 = tmpChar + 8;
82 switch(tmpChar2[2])
84 case 'n':
85 if(tmpChar2[1]=='a')
86 t.tm_mon = 0;
87 else
88 t.tm_mon = 5;
89 break;
90 case 'b':
91 t.tm_mon = 1;
92 break;
93 case 'r':
94 if(tmpChar2[1]=='a')
95 t.tm_mon = 2;
96 else
97 t.tm_mon = 3;
98 break;
99 case 'y':
100 t.tm_mon = 4;
101 break;
102 case 'l':
103 t.tm_mon = 6;
104 break;
105 case 'g':
106 t.tm_mon = 7;
107 break;
108 case 'p':
109 t.tm_mon = 8;
110 break;
111 case 't':
112 t.tm_mon = 9;
113 break;
114 case 'v':
115 t.tm_mon = 10;
116 break;
117 case 'c':
118 t.tm_mon = 11;
119 break;
120 default:
121 FIXME("\n");
124 return mktime(&t);
128 BOOL GetAddress(const WCHAR *name, INTERNET_PORT port, struct sockaddr *psa, int *sa_len, char *addr_str)
130 ADDRINFOW *res, hints;
131 void *addr = NULL;
132 int ret;
134 TRACE("%s\n", debugstr_w(name));
136 memset( &hints, 0, sizeof(hints) );
137 /* Prefer IPv4 to IPv6 addresses, since some servers do not listen on
138 * their IPv6 addresses even though they have IPv6 addresses in the DNS.
140 hints.ai_family = AF_INET;
142 ret = GetAddrInfoW(name, NULL, &hints, &res);
143 if (ret != 0)
145 TRACE("failed to get IPv4 address of %s, retrying with IPv6\n", debugstr_w(name));
146 hints.ai_family = AF_INET6;
147 ret = GetAddrInfoW(name, NULL, &hints, &res);
149 if (ret != 0)
151 TRACE("failed to get address of %s\n", debugstr_w(name));
152 return FALSE;
154 if (*sa_len < res->ai_addrlen)
156 WARN("address too small\n");
157 FreeAddrInfoW(res);
158 return FALSE;
160 *sa_len = res->ai_addrlen;
161 memcpy( psa, res->ai_addr, res->ai_addrlen );
162 /* Copy port */
163 switch (res->ai_family)
165 case AF_INET:
166 addr = &((struct sockaddr_in *)psa)->sin_addr;
167 ((struct sockaddr_in *)psa)->sin_port = htons(port);
168 break;
169 case AF_INET6:
170 addr = &((struct sockaddr_in6 *)psa)->sin6_addr;
171 ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
172 break;
175 if(addr_str)
176 inet_ntop(res->ai_family, addr, addr_str, INET6_ADDRSTRLEN);
177 FreeAddrInfoW(res);
178 return TRUE;
182 * Helper function for sending async Callbacks
185 static const char *get_callback_name(DWORD dwInternetStatus) {
186 static const wininet_flag_info internet_status[] = {
187 #define FE(x) { x, #x }
188 FE(INTERNET_STATUS_RESOLVING_NAME),
189 FE(INTERNET_STATUS_NAME_RESOLVED),
190 FE(INTERNET_STATUS_CONNECTING_TO_SERVER),
191 FE(INTERNET_STATUS_CONNECTED_TO_SERVER),
192 FE(INTERNET_STATUS_SENDING_REQUEST),
193 FE(INTERNET_STATUS_REQUEST_SENT),
194 FE(INTERNET_STATUS_RECEIVING_RESPONSE),
195 FE(INTERNET_STATUS_RESPONSE_RECEIVED),
196 FE(INTERNET_STATUS_CTL_RESPONSE_RECEIVED),
197 FE(INTERNET_STATUS_PREFETCH),
198 FE(INTERNET_STATUS_CLOSING_CONNECTION),
199 FE(INTERNET_STATUS_CONNECTION_CLOSED),
200 FE(INTERNET_STATUS_HANDLE_CREATED),
201 FE(INTERNET_STATUS_HANDLE_CLOSING),
202 FE(INTERNET_STATUS_REQUEST_COMPLETE),
203 FE(INTERNET_STATUS_REDIRECT),
204 FE(INTERNET_STATUS_INTERMEDIATE_RESPONSE),
205 FE(INTERNET_STATUS_USER_INPUT_REQUIRED),
206 FE(INTERNET_STATUS_STATE_CHANGE),
207 FE(INTERNET_STATUS_COOKIE_SENT),
208 FE(INTERNET_STATUS_COOKIE_RECEIVED),
209 FE(INTERNET_STATUS_PRIVACY_IMPACTED),
210 FE(INTERNET_STATUS_P3P_HEADER),
211 FE(INTERNET_STATUS_P3P_POLICYREF),
212 FE(INTERNET_STATUS_COOKIE_HISTORY)
213 #undef FE
215 DWORD i;
217 for (i = 0; i < ARRAY_SIZE(internet_status); i++) {
218 if (internet_status[i].val == dwInternetStatus) return internet_status[i].name;
220 return "Unknown";
223 static const char *debugstr_status_info(DWORD status, void *info)
225 switch(status) {
226 case INTERNET_STATUS_REQUEST_COMPLETE: {
227 INTERNET_ASYNC_RESULT *iar = info;
228 return wine_dbg_sprintf("{%s, %ld}", wine_dbgstr_longlong(iar->dwResult), iar->dwError);
230 default:
231 return wine_dbg_sprintf("%p", info);
235 void INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR context, DWORD status, void *info, DWORD info_len)
237 void *new_info = info;
239 if( !hdr->lpfnStatusCB )
240 return;
242 /* the IE5 version of wininet does not
243 send callbacks if dwContext is zero */
244 if(!context)
245 return;
247 switch(status) {
248 case INTERNET_STATUS_NAME_RESOLVED:
249 case INTERNET_STATUS_CONNECTING_TO_SERVER:
250 case INTERNET_STATUS_CONNECTED_TO_SERVER:
251 new_info = malloc(info_len);
252 if(new_info)
253 memcpy(new_info, info, info_len);
254 break;
255 case INTERNET_STATUS_RESOLVING_NAME:
256 case INTERNET_STATUS_REDIRECT:
257 if(hdr->dwInternalFlags & INET_CALLBACKW) {
258 new_info = wcsdup(info);
259 break;
260 }else {
261 new_info = strdupWtoA(info);
262 info_len = strlen(new_info)+1;
263 break;
267 TRACE(" callback(%p) (%p (%p), %08Ix, %ld (%s), %s, %ld)\n",
268 hdr->lpfnStatusCB, hdr->hInternet, hdr, context, status, get_callback_name(status),
269 debugstr_status_info(status, new_info), info_len);
271 hdr->lpfnStatusCB(hdr->hInternet, context, status, new_info, info_len);
273 TRACE(" end callback().\n");
275 if(new_info != info)
276 free(new_info);