[WININET] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / wininet / utility.c
1 /*
2 * Wininet - Utility functions
3 *
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 *
7 * Ulrich Czekalla
8 * Aric Stewart
9 *
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.
14 *
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.
19 *
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
23 */
24
25 #include "ws2tcpip.h"
26
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wininet.h"
35 #include "winnls.h"
36
37 #include "wine/debug.h"
38 #include "internet.h"
39
40 #ifdef __REACTOS__
41 #include <stdio.h>
42 #include "inet_ntop.c"
43 #endif
44
45 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
46
47 #define TIME_STRING_LEN 30
48
49 time_t ConvertTimeString(LPCWSTR asctime)
50 {
51 WCHAR tmpChar[TIME_STRING_LEN];
52 WCHAR *tmpChar2;
53 struct tm t;
54 int timelen = strlenW(asctime);
55
56 if(!timelen)
57 return 0;
58
59 /* FIXME: the atoiWs below rely on that tmpChar is \0 padded */
60 memset( tmpChar, 0, sizeof(tmpChar) );
61 lstrcpynW(tmpChar, asctime, TIME_STRING_LEN);
62
63 /* Assert that the string is the expected length */
64 if (strlenW(asctime) >= TIME_STRING_LEN) FIXME("\n");
65
66 /* Convert a time such as 'Mon, 15 Nov 1999 16:09:35 GMT' into a SYSTEMTIME structure
67 * We assume the time is in this format
68 * and divide it into easy to swallow chunks
69 */
70 tmpChar[3]='\0';
71 tmpChar[7]='\0';
72 tmpChar[11]='\0';
73 tmpChar[16]='\0';
74 tmpChar[19]='\0';
75 tmpChar[22]='\0';
76 tmpChar[25]='\0';
77
78 memset( &t, 0, sizeof(t) );
79 t.tm_year = atoiW(tmpChar+12) - 1900;
80 t.tm_mday = atoiW(tmpChar+5);
81 t.tm_hour = atoiW(tmpChar+17);
82 t.tm_min = atoiW(tmpChar+20);
83 t.tm_sec = atoiW(tmpChar+23);
84
85 /* and month */
86 tmpChar2 = tmpChar + 8;
87 switch(tmpChar2[2])
88 {
89 case 'n':
90 if(tmpChar2[1]=='a')
91 t.tm_mon = 0;
92 else
93 t.tm_mon = 5;
94 break;
95 case 'b':
96 t.tm_mon = 1;
97 break;
98 case 'r':
99 if(tmpChar2[1]=='a')
100 t.tm_mon = 2;
101 else
102 t.tm_mon = 3;
103 break;
104 case 'y':
105 t.tm_mon = 4;
106 break;
107 case 'l':
108 t.tm_mon = 6;
109 break;
110 case 'g':
111 t.tm_mon = 7;
112 break;
113 case 'p':
114 t.tm_mon = 8;
115 break;
116 case 't':
117 t.tm_mon = 9;
118 break;
119 case 'v':
120 t.tm_mon = 10;
121 break;
122 case 'c':
123 t.tm_mon = 11;
124 break;
125 default:
126 FIXME("\n");
127 }
128
129 return mktime(&t);
130 }
131
132
133 BOOL GetAddress(const WCHAR *name, INTERNET_PORT port, struct sockaddr *psa, int *sa_len, char *addr_str)
134 {
135 ADDRINFOW *res, hints;
136 void *addr = NULL;
137 int ret;
138
139 TRACE("%s\n", debugstr_w(name));
140
141 memset( &hints, 0, sizeof(hints) );
142 /* Prefer IPv4 to IPv6 addresses, since some servers do not listen on
143 * their IPv6 addresses even though they have IPv6 addresses in the DNS.
144 */
145 hints.ai_family = AF_INET;
146
147 ret = GetAddrInfoW(name, NULL, &hints, &res);
148 if (ret != 0)
149 {
150 TRACE("failed to get IPv4 address of %s, retrying with IPv6\n", debugstr_w(name));
151 hints.ai_family = AF_INET6;
152 ret = GetAddrInfoW(name, NULL, &hints, &res);
153 }
154 if (ret != 0)
155 {
156 TRACE("failed to get address of %s\n", debugstr_w(name));
157 return FALSE;
158 }
159 if (*sa_len < res->ai_addrlen)
160 {
161 WARN("address too small\n");
162 FreeAddrInfoW(res);
163 return FALSE;
164 }
165 *sa_len = res->ai_addrlen;
166 memcpy( psa, res->ai_addr, res->ai_addrlen );
167 /* Copy port */
168 switch (res->ai_family)
169 {
170 case AF_INET:
171 addr = &((struct sockaddr_in *)psa)->sin_addr;
172 ((struct sockaddr_in *)psa)->sin_port = htons(port);
173 break;
174 case AF_INET6:
175 addr = &((struct sockaddr_in6 *)psa)->sin6_addr;
176 ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
177 break;
178 }
179
180 if(addr_str)
181 inet_ntop(res->ai_family, addr, addr_str, INET6_ADDRSTRLEN);
182 FreeAddrInfoW(res);
183 return TRUE;
184 }
185
186 /*
187 * Helper function for sending async Callbacks
188 */
189
190 static const char *get_callback_name(DWORD dwInternetStatus) {
191 static const wininet_flag_info internet_status[] = {
192 #define FE(x) { x, #x }
193 FE(INTERNET_STATUS_RESOLVING_NAME),
194 FE(INTERNET_STATUS_NAME_RESOLVED),
195 FE(INTERNET_STATUS_CONNECTING_TO_SERVER),
196 FE(INTERNET_STATUS_CONNECTED_TO_SERVER),
197 FE(INTERNET_STATUS_SENDING_REQUEST),
198 FE(INTERNET_STATUS_REQUEST_SENT),
199 FE(INTERNET_STATUS_RECEIVING_RESPONSE),
200 FE(INTERNET_STATUS_RESPONSE_RECEIVED),
201 FE(INTERNET_STATUS_CTL_RESPONSE_RECEIVED),
202 FE(INTERNET_STATUS_PREFETCH),
203 FE(INTERNET_STATUS_CLOSING_CONNECTION),
204 FE(INTERNET_STATUS_CONNECTION_CLOSED),
205 FE(INTERNET_STATUS_HANDLE_CREATED),
206 FE(INTERNET_STATUS_HANDLE_CLOSING),
207 FE(INTERNET_STATUS_REQUEST_COMPLETE),
208 FE(INTERNET_STATUS_REDIRECT),
209 FE(INTERNET_STATUS_INTERMEDIATE_RESPONSE),
210 FE(INTERNET_STATUS_USER_INPUT_REQUIRED),
211 FE(INTERNET_STATUS_STATE_CHANGE),
212 FE(INTERNET_STATUS_COOKIE_SENT),
213 FE(INTERNET_STATUS_COOKIE_RECEIVED),
214 FE(INTERNET_STATUS_PRIVACY_IMPACTED),
215 FE(INTERNET_STATUS_P3P_HEADER),
216 FE(INTERNET_STATUS_P3P_POLICYREF),
217 FE(INTERNET_STATUS_COOKIE_HISTORY)
218 #undef FE
219 };
220 DWORD i;
221
222 for (i = 0; i < ARRAY_SIZE(internet_status); i++) {
223 if (internet_status[i].val == dwInternetStatus) return internet_status[i].name;
224 }
225 return "Unknown";
226 }
227
228 static const char *debugstr_status_info(DWORD status, void *info)
229 {
230 switch(status) {
231 case INTERNET_STATUS_REQUEST_COMPLETE: {
232 INTERNET_ASYNC_RESULT *iar = info;
233 return wine_dbg_sprintf("{%s, %d}", wine_dbgstr_longlong(iar->dwResult), iar->dwError);
234 }
235 default:
236 return wine_dbg_sprintf("%p", info);
237 }
238 }
239
240 void INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR context, DWORD status, void *info, DWORD info_len)
241 {
242 void *new_info = info;
243
244 if( !hdr->lpfnStatusCB )
245 return;
246
247 /* the IE5 version of wininet does not
248 send callbacks if dwContext is zero */
249 if(!context)
250 return;
251
252 switch(status) {
253 case INTERNET_STATUS_NAME_RESOLVED:
254 case INTERNET_STATUS_CONNECTING_TO_SERVER:
255 case INTERNET_STATUS_CONNECTED_TO_SERVER:
256 new_info = heap_alloc(info_len);
257 if(new_info)
258 memcpy(new_info, info, info_len);
259 break;
260 case INTERNET_STATUS_RESOLVING_NAME:
261 case INTERNET_STATUS_REDIRECT:
262 if(hdr->dwInternalFlags & INET_CALLBACKW) {
263 new_info = heap_strdupW(info);
264 break;
265 }else {
266 new_info = heap_strdupWtoA(info);
267 info_len = strlen(new_info)+1;
268 break;
269 }
270 }
271
272 TRACE(" callback(%p) (%p (%p), %08lx, %d (%s), %s, %d)\n",
273 hdr->lpfnStatusCB, hdr->hInternet, hdr, context, status, get_callback_name(status),
274 debugstr_status_info(status, new_info), info_len);
275
276 hdr->lpfnStatusCB(hdr->hInternet, context, status, new_info, info_len);
277
278 TRACE(" end callback().\n");
279
280 if(new_info != info)
281 heap_free(new_info);
282 }