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