Revert "Default symlink mode from CYGWIN env var"
[cygwin-setup/local.git] / nio-ie5.cc
blob68bb1a8255b2060a32169996936ac3c2e46a4995
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 const std::string &
38 determine_default_useragent(void)
40 static std::string default_useragent;
42 if (!default_useragent.empty())
43 return default_useragent;
45 std::stringstream os;
46 os << "Windows NT " << OSMajorVersion() << "." << OSMinorVersion() << "." << OSBuildNumber();
48 #ifdef __x86_64__
49 USHORT processMachine = IMAGE_FILE_MACHINE_AMD64;
50 #else
51 USHORT processMachine = IMAGE_FILE_MACHINE_I386;
52 #endif
54 USHORT nativeMachine = WowNativeMachine();
56 std::string bitness;
57 if (processMachine != nativeMachine)
58 bitness = machine_name(processMachine) + "-on-" + machine_name(nativeMachine);
59 else
60 bitness = machine_name(processMachine);
62 typedef LANGID (WINAPI *PFNGETTHREADUILANGUAGE)();
63 PFNGETTHREADUILANGUAGE pfnGetThreadUILanguage = (PFNGETTHREADUILANGUAGE)GetProcAddress(GetModuleHandle("kernel32"), "GetThreadUILanguage");
64 std::stringstream langid;
65 if (pfnGetThreadUILanguage)
67 LANGID l = pfnGetThreadUILanguage();
68 langid << std::hex << std::setw(4) << std::setfill('0') << l;
71 std::string symlinks = "";
72 if (nt_sec.hasSymlinkCreationRights())
73 symlinks.append("SymLinkPriv");
74 if (is_developer_mode())
76 if (!symlinks.empty())
77 symlinks.append("+");
78 symlinks.append("UnprivilegedSymLink");
81 default_useragent = std::string("Cygwin-Setup/") + setup_version + " (" + os.str() + ";" + bitness + ";" + langid.str() + ";" + symlinks + ")";
82 Log (LOG_BABBLE) << "User-Agent: default is \"" << default_useragent << "\"" << endLog;
84 return default_useragent;
88 class Proxy
90 int method;
91 std::string host;
92 int port;
93 std::string hostport; // host:port
95 public:
96 Proxy (int method, char const *host, int port)
97 : method(method),
98 host(host ? host : ""),
99 port(port),
100 hostport(std::string(host ? host : "") + ":" + std::to_string(port))
103 bool operator!= (const Proxy &o) const;
105 DWORD type (void) const;
106 char const *string (void) const;
109 bool Proxy::operator!= (const Proxy &o) const
111 if (method != o.method) return true;
112 if (method != IDC_NET_PROXY) return false;
113 // it's only meaningful to compare host:port for method == IDC_NET_PROXY
114 if (host != o.host) return true;
115 if (port != o.port) return true;
116 return false;
119 char const *Proxy::string(void) const
121 if (method == IDC_NET_PROXY)
122 return hostport.c_str();
123 else
124 return NULL;
127 DWORD Proxy::type (void) const
129 switch (method)
131 case IDC_NET_PROXY: return INTERNET_OPEN_TYPE_PROXY;
132 case IDC_NET_PRECONFIG: return INTERNET_OPEN_TYPE_PRECONFIG;
133 default:
134 case IDC_NET_DIRECT: return INTERNET_OPEN_TYPE_DIRECT;
138 static HINTERNET internet = 0;
139 static Proxy last_proxy = Proxy(-1, "", -1);
141 NetIO_IE5::NetIO_IE5 (char const *url, bool cachable)
143 int resend = 0;
145 Proxy proxy = Proxy(net_method, net_proxy_host, net_proxy_port);
146 if (proxy != last_proxy)
148 last_proxy = proxy;
150 if (internet != 0)
151 InternetCloseHandle(internet);
152 else
153 InternetAttemptConnect (0);
155 const char *lpszAgent = determine_default_useragent().c_str();
156 if (UserAgent.isPresent())
158 const std::string &user_agent = UserAgent;
159 if (user_agent.length())
161 // override the default user agent string
162 lpszAgent = user_agent.c_str();
163 Log (LOG_PLAIN) << "User-Agent: header overridden to \"" << lpszAgent << "\"" << endLog;
165 else
167 // user-agent option is present, but no string is specified means
168 // don't add a user-agent header
169 lpszAgent = NULL;
170 Log (LOG_PLAIN) << "User-Agent: header suppressed " << lpszAgent << endLog;
174 internet = InternetOpen (lpszAgent, proxy.type(), proxy.string(), NULL, 0);
177 DWORD flags =
178 INTERNET_FLAG_KEEP_CONNECTION |
179 INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_PASSIVE;
181 if (!cachable) {
182 flags |= INTERNET_FLAG_NO_CACHE_WRITE;
183 } else {
184 flags |= INTERNET_FLAG_RESYNCHRONIZE;
187 connection = InternetOpenUrl (internet, url, NULL, 0, flags, 0);
189 try_again:
191 if (net_user && net_passwd)
193 InternetSetOption (connection, INTERNET_OPTION_USERNAME,
194 net_user, strlen (net_user));
195 InternetSetOption (connection, INTERNET_OPTION_PASSWORD,
196 net_passwd, strlen (net_passwd));
199 if (net_proxy_user && net_proxy_passwd)
201 InternetSetOption (connection, INTERNET_OPTION_PROXY_USERNAME,
202 net_proxy_user, strlen (net_proxy_user));
203 InternetSetOption (connection, INTERNET_OPTION_PROXY_PASSWORD,
204 net_proxy_passwd, strlen (net_proxy_passwd));
207 if (resend)
208 if (!HttpSendRequest (connection, 0, 0, 0, 0))
209 connection = 0;
211 if (!connection)
213 DWORD e = GetLastError ();
214 if (e == ERROR_INTERNET_EXTENDED_ERROR)
216 char buf[2000];
217 DWORD e, l = sizeof (buf);
218 InternetGetLastResponseInfo (&e, buf, &l);
220 // show errors apart from file-not-found (e doesn't contain the
221 // response code so we have to resort to looking at the message)
222 if (strncmp("550", buf, 3) != 0)
223 mbox (0, IDS_NIO_ERROR, MB_OK, buf);
225 for (unsigned int i = 0; i < l; i++)
226 if (buf[i] == '\n' or buf[i] == '\r')
227 buf[i] = ' ';
228 Log (LOG_PLAIN) << "connection error: " << buf << " fetching " << url << endLog;
230 else
232 Log (LOG_PLAIN) << "connection error: " << e << " fetching " << url << endLog;
236 ULONG type = 0;
237 DWORD type_s = sizeof (type);
238 InternetQueryOption (connection, INTERNET_OPTION_HANDLE_TYPE,
239 &type, &type_s);
241 switch (type)
243 case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
244 case INTERNET_HANDLE_TYPE_CONNECT_HTTP:
245 type_s = sizeof (DWORD);
246 if (HttpQueryInfo (connection,
247 HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
248 &type, &type_s, NULL))
250 if (type != 200)
251 Log (LOG_PLAIN) << "HTTP status " << type << " fetching " << url << endLog;
253 if (type == 401) /* authorization required */
255 flush_io ();
256 get_auth (NULL);
257 resend = 1;
258 goto try_again;
260 else if (type == 407) /* proxy authorization required */
262 flush_io ();
263 get_proxy_auth (NULL);
264 resend = 1;
265 goto try_again;
267 else if (type >= 300)
269 InternetCloseHandle (connection);
270 connection = 0;
271 return;
276 InternetQueryOption (connection, INTERNET_OPTION_REQUEST_FLAGS,
277 &type, &type_s);
278 if (type & INTERNET_REQFLAG_FROM_CACHE)
279 Log (LOG_BABBLE) << "Request for URL " << url << " satisfied from cache" << endLog;
282 void
283 NetIO_IE5::flush_io ()
285 DWORD actual = 0;
286 char buf[1024];
289 InternetReadFile (connection, buf, 1024, &actual);
291 while (actual > 0);
294 NetIO_IE5::~NetIO_IE5 ()
296 if (connection)
297 InternetCloseHandle (connection);
301 NetIO_IE5::ok ()
303 return (connection == NULL) ? 0 : 1;
307 NetIO_IE5::read (char *buf, int nbytes)
309 #define READ_CHUNK (64 * 1024)
310 /* Read in chunks rather than the whole file at once, so we can do progress
311 reporting */
312 if (nbytes > READ_CHUNK)
313 nbytes = READ_CHUNK;
315 DWORD actual;
316 if (InternetReadFile (connection, buf, nbytes, &actual))
317 return actual;
319 return -1;