]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000, Red Hat, Inc. | |
3 | * | |
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. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by DJ Delorie <dj@cygnus.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* The purpose of this file is to get the list of mirror sites and ask | |
17 | the user which mirror site they want to download from. */ | |
18 | ||
19 | #include <string> | |
20 | #include <algorithm> | |
21 | ||
22 | #include "site.h" | |
23 | #include "win32.h" | |
24 | #include <stdio.h> | |
25 | #include <stdlib.h> | |
26 | #include <process.h> | |
27 | ||
28 | #include "dialog.h" | |
29 | #include "resource.h" | |
30 | #include "state.h" | |
31 | #include "geturl.h" | |
32 | #include "msg.h" | |
33 | #include "LogSingleton.h" | |
34 | #include "io_stream.h" | |
35 | #include "site.h" | |
36 | ||
37 | #include "propsheet.h" | |
38 | ||
39 | #include "threebar.h" | |
40 | #include "ControlAdjuster.h" | |
41 | #include "Exception.h" | |
42 | #include "String++.h" | |
43 | ||
44 | #define MIRROR_LIST_URL "https://cygwin.com/mirrors.lst" | |
45 | ||
46 | extern ThreeBarProgressPage Progress; | |
47 | ||
48 | /* | |
49 | What to do if dropped mirrors are selected. | |
50 | */ | |
51 | enum | |
52 | { | |
53 | CACHE_REJECT, // Go back to re-select mirrors. | |
54 | CACHE_ACCEPT_WARN, // Go on. Warn again next time. | |
55 | CACHE_ACCEPT_NOWARN // Go on. Don't warn again. | |
56 | }; | |
57 | ||
58 | /* | |
59 | Sizing information. | |
60 | */ | |
61 | static ControlAdjuster::ControlInfo SiteControlsInfo[] = { | |
62 | {IDC_URL_LIST, CP_STRETCH, CP_STRETCH}, | |
63 | {IDC_EDIT_USER_URL, CP_STRETCH, CP_BOTTOM}, | |
64 | {IDC_BUTTON_ADD_URL, CP_RIGHT, CP_BOTTOM}, | |
65 | {IDC_SITE_USERURL, CP_LEFT, CP_BOTTOM}, | |
66 | {0, CP_LEFT, CP_TOP} | |
67 | }; | |
68 | ||
69 | SitePage::SitePage () | |
70 | { | |
71 | sizeProcessor.AddControlInfo (SiteControlsInfo); | |
72 | } | |
73 | ||
74 | #include "getopt++/StringArrayOption.h" | |
75 | #include "getopt++/BoolOption.h" | |
76 | #include "UserSettings.h" | |
77 | ||
78 | bool cache_is_usable; | |
79 | bool cache_needs_writing; | |
80 | std::string cache_warn_urls; | |
81 | ||
82 | /* Selected sites */ | |
83 | SiteList site_list; | |
84 | ||
85 | /* Fresh mirrors + selected sites */ | |
86 | SiteList all_site_list; | |
87 | ||
88 | /* Previously fresh + cached before */ | |
89 | SiteList cached_site_list; | |
90 | ||
91 | /* Stale selected sites to warn about and add to cache */ | |
92 | SiteList dropped_site_list; | |
93 | ||
94 | StringArrayOption SiteOption('s', "site", IDS_HELPTEXT_SITE); | |
95 | BoolOption OnlySiteOption(false, 'O', "only-site", IDS_HELPTEXT_ONLY_SITE); | |
96 | extern BoolOption UnsupportedOption; | |
97 | ||
98 | SiteSetting::SiteSetting (): saved (false) | |
99 | { | |
100 | std::vector<std::string> SiteOptionStrings = SiteOption; | |
101 | if (SiteOptionStrings.size()) | |
102 | { | |
103 | for (std::vector<std::string>::const_iterator n = SiteOptionStrings.begin (); | |
104 | n != SiteOptionStrings.end (); ++n) | |
105 | registerSavedSite (n->c_str ()); | |
106 | } | |
107 | else | |
108 | getSavedSites (); | |
109 | } | |
110 | ||
111 | const char * | |
112 | SiteSetting::lastMirrorKey () | |
113 | { | |
114 | if (UnsupportedOption) | |
115 | return "last-mirror-unsupported"; | |
116 | ||
117 | return "last-mirror"; | |
118 | } | |
119 | ||
120 | void | |
121 | SiteSetting::save() | |
122 | { | |
123 | io_stream *f = UserSettings::instance().open (lastMirrorKey ()); | |
124 | if (f) | |
125 | { | |
126 | for (SiteList::const_iterator n = site_list.begin (); | |
127 | n != site_list.end (); ++n) | |
128 | *f << n->url; | |
129 | delete f; | |
130 | } | |
131 | saved = true; | |
132 | } | |
133 | ||
134 | SiteSetting::~SiteSetting () | |
135 | { | |
136 | if (!saved) | |
137 | save (); | |
138 | } | |
139 | ||
140 | site_list_type::site_list_type (const std::string &_url, | |
141 | const std::string &_servername, | |
142 | const std::string &_area, | |
143 | const std::string &_location, | |
144 | bool _from_mirrors_lst, | |
145 | bool _noshow = false, | |
146 | const std::string &_redir = "") | |
147 | { | |
148 | url = _url; | |
149 | servername = _servername; | |
150 | area = _area; | |
151 | location = _location; | |
152 | from_mirrors_lst = _from_mirrors_lst; | |
153 | noshow = _noshow; | |
154 | redir = _redir; | |
155 | ||
156 | /* Canonicalize URL to ensure it ends with a '/' */ | |
157 | if (url.at(url.length()-1) != '/') | |
158 | url.append("/"); | |
159 | ||
160 | /* displayed_url is protocol and site name part of url */ | |
161 | std::string::size_type path_offset = url.find ("/", url.find ("//") + 2); | |
162 | displayed_url = url.substr(0, path_offset); | |
163 | ||
164 | /* the sorting key is hostname components in reverse order (to sort by country code) | |
165 | plus the url (to ensure uniqueness) */ | |
166 | key = std::string(); | |
167 | std::string::size_type last_idx = displayed_url.length () - 1; | |
168 | std::string::size_type idx = url.find_last_of("./", last_idx); | |
169 | if (last_idx - idx == 3) | |
170 | { | |
171 | /* Sort non-country TLDs (.com, .net, ...) together. */ | |
172 | key += " "; | |
173 | } | |
174 | do | |
175 | { | |
176 | key += url.substr(idx + 1, last_idx - idx); | |
177 | key += " "; | |
178 | last_idx = idx - 1; | |
179 | idx = url.find_last_of("./", last_idx); | |
180 | if (idx == std::string::npos) | |
181 | idx = 0; | |
182 | } while (idx > 0); | |
183 | key += url; | |
184 | } | |
185 | ||
186 | bool | |
187 | site_list_type::operator == (site_list_type const &rhs) const | |
188 | { | |
189 | return stricmp (key.c_str(), rhs.key.c_str()) == 0; | |
190 | } | |
191 | ||
192 | bool | |
193 | site_list_type::operator < (site_list_type const &rhs) const | |
194 | { | |
195 | return stricmp (key.c_str(), rhs.key.c_str()) < 0; | |
196 | } | |
197 | ||
198 | /* | |
199 | A SiteList is maintained as an in-order std::vector of site_list_type, by | |
200 | replacing it with a new object with the new item inserted in the correct | |
201 | place. | |
202 | ||
203 | Yes, we could just use an ordered container, instead. | |
204 | */ | |
205 | static void | |
206 | site_list_insert(SiteList &site_list, site_list_type newsite) | |
207 | { | |
208 | SiteList::iterator i = find (site_list.begin(), site_list.end(), newsite); | |
209 | if (i == site_list.end()) | |
210 | { | |
211 | SiteList result; | |
212 | merge (site_list.begin(), site_list.end(), | |
213 | &newsite, &newsite + 1, | |
214 | inserter (result, result.begin())); | |
215 | site_list = result; | |
216 | } | |
217 | else | |
218 | *i = newsite; | |
219 | } | |
220 | ||
221 | static void | |
222 | save_dialog (HWND h) | |
223 | { | |
224 | // Remove anything that was previously in the selected site list. | |
225 | site_list.clear (); | |
226 | ||
227 | HWND listbox = GetDlgItem (h, IDC_URL_LIST); | |
228 | int sel_count = SendMessage (listbox, LB_GETSELCOUNT, 0, 0); | |
229 | if (sel_count > 0) | |
230 | { | |
231 | int sel_buffer[sel_count]; | |
232 | SendMessage (listbox, LB_GETSELITEMS, sel_count, (LPARAM) sel_buffer); | |
233 | for (int n = 0; n < sel_count; n++) | |
234 | { | |
235 | int mirror = | |
236 | SendMessage (listbox, LB_GETITEMDATA, sel_buffer[n], 0); | |
237 | site_list.push_back (all_site_list[mirror]); | |
238 | } | |
239 | } | |
240 | } | |
241 | ||
242 | // This is called only for lists of mirrors that came (now or in a | |
243 | // previous setup run) from mirrors.lst. | |
244 | void | |
245 | load_site_list (SiteList& theSites, char *theString) | |
246 | { | |
247 | char *bol, *eol, *nl; | |
248 | ||
249 | nl = theString; | |
250 | while (*nl) | |
251 | { | |
252 | bol = nl; | |
253 | for (eol = bol; *eol && *eol != '\n'; eol++); | |
254 | if (*eol) | |
255 | nl = eol + 1; | |
256 | else | |
257 | nl = eol; | |
258 | while (eol > bol && eol[-1] == '\r') | |
259 | eol--; | |
260 | *eol = 0; | |
261 | if (*bol == '#' || !*bol) | |
262 | continue; | |
263 | /* Accept only the URL schemes we can understand. */ | |
264 | if (strncmp(bol, "http://", 7) == 0 || | |
265 | strncmp(bol, "https://", 8) == 0 || | |
266 | strncmp(bol, "ftp://", 6) == 0 || | |
267 | strncmp(bol, "ftps://", 7) == 0) | |
268 | { | |
269 | int i; | |
270 | char *semi[4]; | |
271 | ||
272 | /* split into up to 4 semicolon-delimited parts */ | |
273 | for (i = 0; i < 4; i++) | |
274 | semi[i] = 0; | |
275 | ||
276 | char *p = bol; | |
277 | for (i = 0; i < 4; i++) | |
278 | { | |
279 | semi[i] = strchr (p, ';'); | |
280 | if (!semi[i]) | |
281 | break; | |
282 | ||
283 | *semi[i] = 0; | |
284 | p = ++semi[i]; | |
285 | } | |
286 | ||
287 | /* Ignore malformed lines */ | |
288 | if (!semi[0] || !semi[1] || !semi[2]) | |
289 | continue; | |
290 | ||
291 | /* fourth part is an optional, comma-delimited set of flags */ | |
292 | bool noshow = FALSE; | |
293 | const char *redir = ""; | |
294 | ||
295 | char *flag = semi[3]; | |
296 | while (flag) | |
297 | { | |
298 | if (strncmp(flag, "noshow", 6) == 0) | |
299 | noshow = TRUE; | |
300 | else if (strncmp(flag, "redir=", 6) == 0) | |
301 | redir = flag+6; | |
302 | ||
303 | flag = strchr (flag, ','); | |
304 | if (flag) | |
305 | *flag++ = 0; | |
306 | } | |
307 | ||
308 | /* add site to list */ | |
309 | site_list_type newsite (bol, semi[0], semi[1], semi[2], true, noshow, redir); | |
310 | site_list_insert (theSites, newsite); | |
311 | } | |
312 | else | |
313 | { | |
314 | Log (LOG_BABBLE) << "Discarding line '" << bol << "' due to unknown protocol" << endLog; | |
315 | } | |
316 | } | |
317 | } | |
318 | ||
319 | static void | |
320 | migrate_selected_site_list() | |
321 | { | |
322 | const std::string http = "http://"; | |
323 | ||
324 | for (SiteList::iterator i = site_list.begin(); | |
325 | i != site_list.end(); | |
326 | ++i) | |
327 | { | |
328 | /* If the saved selected site URL starts with "http://", and the same URL, | |
329 | but starting with "https://" appears in the mirror list, migrate to | |
330 | "https://" */ | |
331 | if (strnicmp(i->url.c_str(), http.c_str(), strlen(http.c_str())) == 0) | |
332 | { | |
333 | std::string migrated_site = "https://"; | |
334 | migrated_site.append(i->url.substr(http.length())); | |
335 | ||
336 | site_list_type migrate(migrated_site, "", "", "", false); | |
337 | SiteList::iterator j = find (all_site_list.begin(), | |
338 | all_site_list.end(), migrate); | |
339 | if (j != all_site_list.end()) | |
340 | { | |
341 | Log (LOG_PLAIN) << "Migrated " << i->url << " to " << migrated_site << endLog; | |
342 | *i = migrate; | |
343 | } | |
344 | } | |
345 | ||
346 | /* If the saved selected site URL appears in the site list with a redir | |
347 | flag, replace with the redirected URL */ | |
348 | { | |
349 | SiteList::iterator j = find (all_site_list.begin(), | |
350 | all_site_list.end(), *i); | |
351 | ||
352 | if (j != all_site_list.end()) | |
353 | { | |
354 | if (!j->redir.empty()) | |
355 | { | |
356 | site_list_type migrate(j->redir, "", "", "", false); | |
357 | Log (LOG_PLAIN) << "Migrated " << i->url << " to " << j->redir << endLog; | |
358 | *i = migrate; | |
359 | } | |
360 | } | |
361 | } | |
362 | } | |
363 | } | |
364 | ||
365 | static int | |
366 | get_site_list (HINSTANCE h, HWND owner) | |
367 | { | |
368 | char *theMirrorString, *theCachedString; | |
369 | ||
370 | if (UnsupportedOption) | |
371 | return 0; | |
372 | ||
373 | const char *cached_mirrors = OnlySiteOption ? NULL : UserSettings::instance().get ("mirrors-lst"); | |
374 | if (cached_mirrors) | |
375 | { | |
376 | Log (LOG_BABBLE) << "Loaded cached mirror list" << endLog; | |
377 | cache_is_usable = true; | |
378 | } | |
379 | else | |
380 | { | |
381 | Log (LOG_BABBLE) << "Cached mirror list unavailable" << endLog; | |
382 | cache_is_usable = false; | |
383 | cached_mirrors = ""; | |
384 | } | |
385 | ||
386 | std::string mirrors = OnlySiteOption ? std::string ("") : get_url_to_string (MIRROR_LIST_URL, owner); | |
387 | if (mirrors.size()) | |
388 | cache_needs_writing = true; | |
389 | else | |
390 | { | |
391 | if (!cached_mirrors[0]) | |
392 | { | |
393 | if (!OnlySiteOption) | |
394 | note(owner, IDS_NO_MIRROR_LST); | |
395 | Log (LOG_BABBLE) << "Defaulting to empty mirror list" << endLog; | |
396 | } | |
397 | else | |
398 | { | |
399 | mirrors = cached_mirrors; | |
400 | Log (LOG_BABBLE) << "Using cached mirror list" << endLog; | |
401 | } | |
402 | cache_is_usable = false; | |
403 | cache_needs_writing = false; | |
404 | } | |
405 | theMirrorString = new_cstr_char_array (mirrors); | |
406 | theCachedString = new_cstr_char_array (cached_mirrors); | |
407 | ||
408 | load_site_list (all_site_list, theMirrorString); | |
409 | load_site_list (cached_site_list, theCachedString); | |
410 | ||
411 | delete[] theMirrorString; | |
412 | delete[] theCachedString; | |
413 | ||
414 | migrate_selected_site_list(); | |
415 | ||
416 | return 0; | |
417 | } | |
418 | ||
419 | /* List of machines that should not be used by default when saved | |
420 | in "last-mirror". */ | |
421 | #define NOSAVE1 "ftp://sourceware.org/" | |
422 | #define NOSAVE1_LEN (sizeof (NOSAVE2) - 1) | |
423 | #define NOSAVE2 "ftp://sources.redhat.com/" | |
424 | #define NOSAVE2_LEN (sizeof (NOSAVE1) - 1) | |
425 | #define NOSAVE3 "ftp://gcc.gnu.org/" | |
426 | #define NOSAVE3_LEN (sizeof (NOSAVE3) - 1) | |
427 | ||
428 | void | |
429 | SiteSetting::registerSavedSite (const char * site) | |
430 | { | |
431 | site_list_type tempSite(site, "", "", "", false); | |
432 | ||
433 | /* Don't default to certain machines if they suffer from bandwidth | |
434 | limitations. */ | |
435 | if (strnicmp (site, NOSAVE1, NOSAVE1_LEN) == 0 | |
436 | || strnicmp (site, NOSAVE2, NOSAVE2_LEN) == 0 | |
437 | || strnicmp (site, NOSAVE3, NOSAVE3_LEN) == 0) | |
438 | return; | |
439 | ||
440 | site_list_insert (all_site_list, tempSite); | |
441 | site_list.push_back (tempSite); | |
442 | } | |
443 | ||
444 | void | |
445 | SiteSetting::getSavedSites () | |
446 | { | |
447 | const char *buf = UserSettings::instance().get (lastMirrorKey ()); | |
448 | if (!buf) | |
449 | return; | |
450 | char *fg_ret = strdup (buf); | |
451 | for (char *site = strtok (fg_ret, "\n"); site; site = strtok (NULL, "\n")) | |
452 | registerSavedSite (site); | |
453 | free (fg_ret); | |
454 | } | |
455 | ||
456 | static DWORD WINAPI | |
457 | do_download_site_info_thread (void *p) | |
458 | { | |
459 | HANDLE *context; | |
460 | HINSTANCE hinst; | |
461 | HWND h; | |
462 | context = (HANDLE *) p; | |
463 | ||
464 | SetThreadUILanguage(langid); | |
465 | ||
466 | try | |
467 | { | |
468 | hinst = (HINSTANCE) (context[0]); | |
469 | h = (HWND) (context[1]); | |
470 | static bool downloaded = false; | |
471 | if (!downloaded && get_site_list (hinst, h)) | |
472 | { | |
473 | // Error: Couldn't download the site info. | |
474 | // Go back to the Net setup page. | |
475 | mbox (h, IDS_GET_SITELIST_ERROR, MB_OK); | |
476 | ||
477 | // Tell the progress page that we're done downloading | |
478 | Progress.PostMessageNow (WM_APP_SITE_INFO_DOWNLOAD_COMPLETE, 0, IDD_NET); | |
479 | } | |
480 | else | |
481 | { | |
482 | downloaded = true; | |
483 | // Everything worked, go to the site select page | |
484 | // Tell the progress page that we're done downloading | |
485 | Progress.PostMessageNow (WM_APP_SITE_INFO_DOWNLOAD_COMPLETE, 0, IDD_SITE); | |
486 | } | |
487 | } | |
488 | TOPLEVEL_CATCH((HWND) context[1], "site"); | |
489 | ||
490 | ExitThread(0); | |
491 | } | |
492 | ||
493 | static HANDLE context[2]; | |
494 | ||
495 | void | |
496 | do_download_site_info (HINSTANCE hinst, HWND owner) | |
497 | { | |
498 | ||
499 | context[0] = hinst; | |
500 | context[1] = owner; | |
501 | ||
502 | DWORD threadID; | |
503 | CreateThread (NULL, 0, do_download_site_info_thread, context, 0, &threadID); | |
504 | } | |
505 | ||
506 | static INT_PTR CALLBACK | |
507 | drop_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) | |
508 | { | |
509 | switch (message) | |
510 | { | |
511 | case WM_INITDIALOG: | |
512 | eset(h, IDC_DROP_MIRRORS, cache_warn_urls); | |
513 | /* Should this be set by default? */ | |
514 | // CheckDlgButton (h, IDC_DROP_NOWARN, BST_CHECKED); | |
515 | SetFocus (GetDlgItem(h, IDC_DROP_NOWARN)); | |
516 | return FALSE; | |
517 | break; | |
518 | case WM_COMMAND: | |
519 | switch (LOWORD (wParam)) | |
520 | { | |
521 | case IDYES: | |
522 | if (IsDlgButtonChecked (h, IDC_DROP_NOWARN) == BST_CHECKED) | |
523 | EndDialog (h, CACHE_ACCEPT_NOWARN); | |
524 | else | |
525 | EndDialog (h, CACHE_ACCEPT_WARN); | |
526 | break; | |
527 | ||
528 | case IDNO: | |
529 | EndDialog (h, CACHE_REJECT); | |
530 | break; | |
531 | ||
532 | default: | |
533 | return 0; | |
534 | } | |
535 | return TRUE; | |
536 | break; | |
537 | default: | |
538 | return FALSE; | |
539 | } | |
540 | } | |
541 | ||
542 | int check_dropped_mirrors (HWND h) | |
543 | { | |
544 | cache_warn_urls = ""; | |
545 | dropped_site_list.clear (); | |
546 | ||
547 | for (SiteList::const_iterator n = site_list.begin (); | |
548 | n != site_list.end (); ++n) | |
549 | { | |
550 | SiteList::iterator i = find (all_site_list.begin(), all_site_list.end(), | |
551 | *n); | |
552 | if (i == all_site_list.end() || !i->from_mirrors_lst) | |
553 | { | |
554 | SiteList::iterator j = find (cached_site_list.begin(), | |
555 | cached_site_list.end(), *n); | |
556 | if (j != cached_site_list.end()) | |
557 | { | |
558 | Log (LOG_PLAIN) << "Dropped selected mirror: " << n->url | |
559 | << endLog; | |
560 | dropped_site_list.push_back (*j); | |
561 | if (cache_warn_urls.size()) | |
562 | cache_warn_urls += "\r\n"; | |
563 | cache_warn_urls += i->url; | |
564 | } | |
565 | } | |
566 | } | |
567 | if (cache_warn_urls.size()) | |
568 | { | |
569 | if (unattended_mode) | |
570 | return CACHE_ACCEPT_WARN; | |
571 | return DialogBox (hinstance, MAKEINTRESOURCE (IDD_DROPPED), h, | |
572 | drop_proc); | |
573 | } | |
574 | return CACHE_ACCEPT_NOWARN; | |
575 | } | |
576 | ||
577 | void write_cache_list (io_stream *f, const SiteList& theSites) | |
578 | { | |
579 | for (SiteList::const_iterator n = theSites.begin (); | |
580 | n != theSites.end (); ++n) | |
581 | if (n->from_mirrors_lst) | |
582 | *f << (n->url + ";" + n->servername + ";" + n->area + ";" | |
583 | + n->location); | |
584 | } | |
585 | ||
586 | void save_cache_file (int cache_action) | |
587 | { | |
588 | io_stream *f = UserSettings::instance().open ("mirrors-lst"); | |
589 | if (f) | |
590 | { | |
591 | write_cache_list (f, all_site_list); | |
592 | if (cache_action == CACHE_ACCEPT_WARN) | |
593 | { | |
594 | Log (LOG_PLAIN) << "Adding dropped mirrors to cache to warn again." | |
595 | << endLog; | |
596 | *f << "# Following mirrors re-added by setup.exe to warn again about dropped urls."; | |
597 | write_cache_list (f, dropped_site_list); | |
598 | } | |
599 | delete f; | |
600 | } | |
601 | } | |
602 | ||
603 | bool SitePage::Create () | |
604 | { | |
605 | return PropertyPage::Create (IDD_SITE); | |
606 | } | |
607 | ||
608 | void | |
609 | SitePage::OnInit () | |
610 | { | |
611 | AddTooltip (IDC_EDIT_USER_URL, IDS_USER_URL_TOOLTIP); | |
612 | } | |
613 | ||
614 | long | |
615 | SitePage::OnNext () | |
616 | { | |
617 | HWND h = GetHWND (); | |
618 | int cache_action = CACHE_ACCEPT_NOWARN; | |
619 | ||
620 | save_dialog (h); | |
621 | ||
622 | if (cache_is_usable && !(cache_action = check_dropped_mirrors (h))) | |
623 | return -1; | |
624 | ||
625 | if (cache_needs_writing) | |
626 | save_cache_file (cache_action); | |
627 | ||
628 | // Log all the selected URLs from the list. | |
629 | for (SiteList::const_iterator n = site_list.begin (); | |
630 | n != site_list.end (); ++n) | |
631 | Log (LOG_PLAIN) << "site: " << n->url << endLog; | |
632 | ||
633 | Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD); | |
634 | return IDD_INSTATUS; | |
635 | ||
636 | return 0; | |
637 | } | |
638 | ||
639 | long | |
640 | SitePage::OnBack () | |
641 | { | |
642 | HWND h = GetHWND (); | |
643 | ||
644 | save_dialog (h); | |
645 | ||
646 | // Go back to the net connection type page | |
647 | return 0; | |
648 | } | |
649 | ||
650 | void | |
651 | SitePage::OnActivate () | |
652 | { | |
653 | // Fill the list box with all known sites. | |
654 | PopulateListBox (); | |
655 | ||
656 | // Load the user URL box with nothing - it is in the list already. | |
657 | eset (GetHWND (), IDC_EDIT_USER_URL, ""); | |
658 | ||
659 | // Get the enabled/disabled states of the controls set accordingly. | |
660 | CheckControlsAndDisableAccordingly (); | |
661 | } | |
662 | ||
663 | long | |
664 | SitePage::OnUnattended () | |
665 | { | |
666 | if (SendMessage (GetDlgItem (IDC_URL_LIST), LB_GETSELCOUNT, 0, 0) > 0) | |
667 | return OnNext (); | |
668 | ||
669 | Log (LOG_PLAIN) << "No package repository site(s) specified" << endLog; | |
670 | return -2; | |
671 | } | |
672 | ||
673 | void | |
674 | SitePage::CheckControlsAndDisableAccordingly () const | |
675 | { | |
676 | DWORD ButtonFlags = PSWIZB_BACK; | |
677 | ||
678 | // Check that at least one download site is selected. | |
679 | if (SendMessage (GetDlgItem (IDC_URL_LIST), LB_GETSELCOUNT, 0, 0) > 0) | |
680 | { | |
681 | // At least one site selected, enable "Next". | |
682 | ButtonFlags |= PSWIZB_NEXT; | |
683 | } | |
684 | GetOwner ()->SetButtons (ButtonFlags); | |
685 | } | |
686 | ||
687 | void | |
688 | SitePage::PopulateListBox () | |
689 | { | |
690 | std::vector <int> sel_indicies; | |
691 | HWND listbox = GetDlgItem (IDC_URL_LIST); | |
692 | ||
693 | // Populate the list box with the URLs. | |
694 | SendMessage (listbox, LB_RESETCONTENT, 0, 0); | |
695 | for (SiteList::const_iterator i = all_site_list.begin (); | |
696 | i != all_site_list.end (); ++i) | |
697 | { | |
698 | // If selected, always show | |
699 | SiteList::iterator f = find (site_list.begin(), site_list.end(), *i); | |
700 | if (f == site_list.end()) | |
701 | { | |
702 | // Otherwise, hide redundant legacy URLs: | |
703 | if (i->noshow) | |
704 | continue; | |
705 | } | |
706 | ||
707 | int j = SendMessage (listbox, LB_ADDSTRING, 0, | |
708 | (LPARAM) i->displayed_url.c_str()); | |
709 | // Set the ListBox item data to the index into all_site_list | |
710 | SendMessage (listbox, LB_SETITEMDATA, j, (i - all_site_list.begin())); | |
711 | ||
712 | // For every selected item, remember the index | |
713 | if (f != site_list.end()) | |
714 | { | |
715 | sel_indicies.push_back(j); | |
716 | } | |
717 | } | |
718 | ||
719 | // Select the selected ones. | |
720 | for (std::vector <int>::const_iterator n = sel_indicies.begin (); | |
721 | n != sel_indicies.end (); ++n) | |
722 | { | |
723 | int index = *n; | |
724 | // Highlight the selected item | |
725 | SendMessage (listbox, LB_SELITEMRANGE, TRUE, (index << 16) | index); | |
726 | // Make sure it's fully visible | |
727 | SendMessage (listbox, LB_SETCARETINDEX, index, FALSE); | |
728 | } | |
729 | } | |
730 | ||
731 | bool SitePage::OnMessageCmd (int id, HWND hwndctl, UINT code) | |
732 | { | |
733 | switch (id) | |
734 | { | |
735 | case IDC_EDIT_USER_URL: | |
736 | { | |
737 | // Set the default pushbutton to ADD if the user is entering text. | |
738 | if (code == EN_CHANGE) | |
739 | SendMessage (GetHWND (), DM_SETDEFID, (WPARAM) IDC_BUTTON_ADD_URL, 0); | |
740 | break; | |
741 | } | |
742 | case IDC_URL_LIST: | |
743 | { | |
744 | if (code == LBN_SELCHANGE) | |
745 | { | |
746 | CheckControlsAndDisableAccordingly (); | |
747 | save_dialog (GetHWND ()); | |
748 | } | |
749 | break; | |
750 | } | |
751 | case IDC_BUTTON_ADD_URL: | |
752 | { | |
753 | if (code == BN_CLICKED) | |
754 | { | |
755 | // User pushed the Add button. | |
756 | std::string other_url = egetString (GetHWND (), IDC_EDIT_USER_URL); | |
757 | if (other_url.size()) | |
758 | { | |
759 | site_list_type newsite (other_url, "", "", "", false); | |
760 | SiteList::iterator i = find (all_site_list.begin(), | |
761 | all_site_list.end(), newsite); | |
762 | if (i == all_site_list.end()) | |
763 | { | |
764 | all_site_list.push_back (newsite); | |
765 | Log (LOG_BABBLE) << "Adding site: " << other_url << endLog; | |
766 | site_list.push_back (newsite); | |
767 | } | |
768 | else | |
769 | site_list.push_back (*i); | |
770 | ||
771 | // Update the list box. | |
772 | PopulateListBox (); | |
773 | // And allow the user to continue | |
774 | CheckControlsAndDisableAccordingly (); | |
775 | eset (GetHWND (), IDC_EDIT_USER_URL, ""); | |
776 | } | |
777 | } | |
778 | break; | |
779 | } | |
780 | default: | |
781 | // Wasn't recognized or handled. | |
782 | return false; | |
783 | } | |
784 | ||
785 | // Was handled since we never got to default above. | |
786 | return true; | |
787 | } |