Allow to run on Windows lacking CreateSymbolicLinkW()
[cygwin-setup.git] / nio-ie5.cc
blob2117e33ee9bceb8b4fee01d5449899fa2fbbc354
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* The purpose of this file is to manage internet downloads using the
17 Internet Explorer version 5 DLLs. To use this method, the user
18 must already have installed and configured IE5. This module is
19 called from netio.cc, which is called from geturl.cc */
21 #include "win32.h"
23 #include "resource.h"
24 #include "state.h"
25 #include "dialog.h"
26 #include "msg.h"
27 #include "netio.h"
28 #include "nio-ie5.h"
29 #include "LogSingleton.h"
30 #include "setup_version.h"
31 #include "getopt++/StringOption.h"
32 #include <sstream>
33 #include <iomanip>
35 static StringOption UserAgent ("", '\0', "user-agent", IDS_HELPTEXT_USER_AGENT);
37 static const std::string
38 machine_name(USHORT machine)
40 switch (machine)
42 case IMAGE_FILE_MACHINE_I386:
43 return "Win32";
44 break;
45 case IMAGE_FILE_MACHINE_AMD64:
46 return "Win64";
47 break;
48 case IMAGE_FILE_MACHINE_ARM64:
49 return "ARM64";
50 break;
51 default:
52 std::stringstream machine_desc;
53 machine_desc << std::hex << machine;
54 return machine_desc.str();
58 const std::string &
59 determine_default_useragent(void)
61 static std::string default_useragent;
63 if (!default_useragent.empty())
64 return default_useragent;
66 std::stringstream os;
67 os << "Windows NT " << OSMajorVersion() << "." << OSMinorVersion() << "." << OSBuildNumber();
69 #ifdef __x86_64__
70 USHORT processMachine = IMAGE_FILE_MACHINE_AMD64;
71 #else
72 USHORT processMachine = IMAGE_FILE_MACHINE_I386;
73 #endif
75 USHORT nativeMachine = WowNativeMachine();
77 std::string bitness;
78 if (processMachine != nativeMachine)
79 bitness = machine_name(processMachine) + "-on-" + machine_name(nativeMachine);
80 else
81 bitness = machine_name(processMachine);
83 typedef LANGID (WINAPI *PFNGETTHREADUILANGUAGE)();
84 PFNGETTHREADUILANGUAGE pfnGetThreadUILanguage = (PFNGETTHREADUILANGUAGE)GetProcAddress(GetModuleHandle("kernel32"), "GetThreadUILanguage");
85 std::stringstream langid;
86 if (pfnGetThreadUILanguage)
88 LANGID l = pfnGetThreadUILanguage();
89 langid << std::hex << std::setw(4) << std::setfill('0') << l;
92 std::string symlinks = "";
93 if (nt_sec.hasSymlinkCreationRights())
94 symlinks.append("SymLinkPriv");
95 if (is_developer_mode())
97 if (!symlinks.empty())
98 symlinks.append("+");
99 symlinks.append("UnprivilegedSymLink");
102 default_useragent = std::string("Cygwin-Setup/") + setup_version + " (" + os.str() + ";" + bitness + ";" + langid.str() + ";" + symlinks + ")";
103 Log (LOG_BABBLE) << "User-Agent: default is \"" << default_useragent << "\"" << endLog;
105 return default_useragent;
109 class Proxy
111 int method;
112 std::string host;
113 int port;
114 std::string hostport; // host:port
116 public:
117 Proxy (int method, char const *host, int port)
118 : method(method),
119 host(host ? host : ""),
120 port(port),
121 hostport(std::string(host ? host : "") + ":" + std::to_string(port))
124 bool operator!= (const Proxy &o) const;
126 DWORD type (void) const;
127 char const *string (void) const;
130 bool Proxy::operator!= (const Proxy &o) const
132 if (method != o.method) return true;
133 if (method != IDC_NET_PROXY) return false;
134 // it's only meaningful to compare host:port for method == IDC_NET_PROXY
135 if (host != o.host) return true;
136 if (port != o.port) return true;
137 return false;
140 char const *Proxy::string(void) const
142 if (method == IDC_NET_PROXY)
143 return hostport.c_str();
144 else
145 return NULL;
148 DWORD Proxy::type (void) const
150 switch (method)
152 case IDC_NET_PROXY: return INTERNET_OPEN_TYPE_PROXY;
153 case IDC_NET_PRECONFIG: return INTERNET_OPEN_TYPE_PRECONFIG;
154 default:
155 case IDC_NET_DIRECT: return INTERNET_OPEN_TYPE_DIRECT;
159 static HINTERNET internet = 0;
160 static Proxy last_proxy = Proxy(-1, "", -1);
162 NetIO_IE5::NetIO_IE5 (char const *url, bool cachable)
164 int resend = 0;
166 Proxy proxy = Proxy(net_method, net_proxy_host, net_proxy_port);
167 if (proxy != last_proxy)
169 last_proxy = proxy;
171 if (internet != 0)
172 InternetCloseHandle(internet);
173 else
174 InternetAttemptConnect (0);
176 const char *lpszAgent = determine_default_useragent().c_str();
177 if (UserAgent.isPresent())
179 const std::string &user_agent = UserAgent;
180 if (user_agent.length())
182 // override the default user agent string
183 lpszAgent = user_agent.c_str();
184 Log (LOG_PLAIN) << "User-Agent: header overridden to \"" << lpszAgent << "\"" << endLog;
186 else
188 // user-agent option is present, but no string is specified means
189 // don't add a user-agent header
190 lpszAgent = NULL;
191 Log (LOG_PLAIN) << "User-Agent: header suppressed " << lpszAgent << endLog;
195 internet = InternetOpen (lpszAgent, proxy.type(), proxy.string(), NULL, 0);
198 DWORD flags =
199 INTERNET_FLAG_KEEP_CONNECTION |
200 INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_PASSIVE;
202 if (!cachable) {
203 flags |= INTERNET_FLAG_NO_CACHE_WRITE;
204 } else {
205 flags |= INTERNET_FLAG_RESYNCHRONIZE;
208 connection = InternetOpenUrl (internet, url, NULL, 0, flags, 0);
210 try_again:
212 if (net_user && net_passwd)
214 InternetSetOption (connection, INTERNET_OPTION_USERNAME,
215 net_user, strlen (net_user));
216 InternetSetOption (connection, INTERNET_OPTION_PASSWORD,
217 net_passwd, strlen (net_passwd));
220 if (net_proxy_user && net_proxy_passwd)
222 InternetSetOption (connection, INTERNET_OPTION_PROXY_USERNAME,
223 net_proxy_user, strlen (net_proxy_user));
224 InternetSetOption (connection, INTERNET_OPTION_PROXY_PASSWORD,
225 net_proxy_passwd, strlen (net_proxy_passwd));
228 if (resend)
229 if (!HttpSendRequest (connection, 0, 0, 0, 0))
230 connection = 0;
232 if (!connection)
234 DWORD e = GetLastError ();
235 if (e == ERROR_INTERNET_EXTENDED_ERROR)
237 char buf[2000];
238 DWORD e, l = sizeof (buf);
239 InternetGetLastResponseInfo (&e, buf, &l);
241 // show errors apart from file-not-found (e doesn't contain the
242 // response code so we have to resort to looking at the message)
243 if (strncmp("550", buf, 3) != 0)
244 mbox (0, IDS_NIO_ERROR, MB_OK, buf);
246 for (unsigned int i = 0; i < l; i++)
247 if (buf[i] == '\n' or buf[i] == '\r')
248 buf[i] = ' ';
249 Log (LOG_PLAIN) << "connection error: " << buf << " fetching " << url << endLog;
251 else
253 Log (LOG_PLAIN) << "connection error: " << e << " fetching " << url << endLog;
257 ULONG type = 0;
258 DWORD type_s = sizeof (type);
259 InternetQueryOption (connection, INTERNET_OPTION_HANDLE_TYPE,
260 &type, &type_s);
262 switch (type)
264 case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
265 case INTERNET_HANDLE_TYPE_CONNECT_HTTP:
266 type_s = sizeof (DWORD);
267 if (HttpQueryInfo (connection,
268 HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
269 &type, &type_s, NULL))
271 if (type != 200)
272 Log (LOG_PLAIN) << "HTTP status " << type << " fetching " << url << endLog;
274 if (type == 401) /* authorization required */
276 flush_io ();
277 get_auth (NULL);
278 resend = 1;
279 goto try_again;
281 else if (type == 407) /* proxy authorization required */
283 flush_io ();
284 get_proxy_auth (NULL);
285 resend = 1;
286 goto try_again;
288 else if (type >= 300)
290 InternetCloseHandle (connection);
291 connection = 0;
292 return;
297 InternetQueryOption (connection, INTERNET_OPTION_REQUEST_FLAGS,
298 &type, &type_s);
299 if (type & INTERNET_REQFLAG_FROM_CACHE)
300 Log (LOG_BABBLE) << "Request for URL " << url << " satisfied from cache" << endLog;
303 void
304 NetIO_IE5::flush_io ()
306 DWORD actual = 0;
307 char buf[1024];
310 InternetReadFile (connection, buf, 1024, &actual);
312 while (actual > 0);
315 NetIO_IE5::~NetIO_IE5 ()
317 if (connection)
318 InternetCloseHandle (connection);
322 NetIO_IE5::ok ()
324 return (connection == NULL) ? 0 : 1;
328 NetIO_IE5::read (char *buf, int nbytes)
330 #define READ_CHUNK (64 * 1024)
331 /* Read in chunks rather than the whole file at once, so we can do progress
332 reporting */
333 if (nbytes > READ_CHUNK)
334 nbytes = READ_CHUNK;
336 DWORD actual;
337 if (InternetReadFile (connection, buf, nbytes, &actual))
338 return actual;
340 return -1;