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 < (sizeof(internet_status) / sizeof(internet_status[0])); 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 } 283