diff --git a/res.rc b/res.rc index 80d1bf1..fa90a65 100644 --- a/res.rc +++ b/res.rc @@ -135,10 +135,10 @@ CAPTION "Cygwin Setup - Choose Download Site(s)" FONT 8, "MS Shell Dlg" BEGIN ICON IDI_CYGWIN,IDC_HEADICON,SETUP_HEADICON_X,0,21,20 - LISTBOX IDC_URL_LIST,66,45,185,110,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_URL_LIST,66,45,216,110,LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_GROUP | WS_TABSTOP - LTEXT "Available Download Sites:",IDC_STATIC,66,34,183,8,NOT + LTEXT "Available Download Sites:",IDC_STATIC,66,34,216,8,NOT WS_GROUP CONTROL "",IDC_HEADSEPARATOR,"Static",SS_BLACKFRAME | SS_SUNKEN,0,28, SETUP_STANDARD_DIALOG_W,1 @@ -146,10 +146,10 @@ BEGIN IDC_STATIC,21,9,239,16,NOT WS_GROUP LTEXT "Choose A Download Site",IDC_STATIC_HEADER_TITLE,7,0,258, 8,NOT WS_GROUP - EDITTEXT IDC_EDIT_USER_URL,65,160,185,14,ES_AUTOHSCROLL | + EDITTEXT IDC_EDIT_USER_URL,65,160,216,14,ES_AUTOHSCROLL | WS_GROUP LTEXT "User URL:",IDC_SITE_USERURL,15,162,45,8,NOT WS_GROUP - PUSHBUTTON "Add",IDC_BUTTON_ADD_URL,255,160,50,14 + PUSHBUTTON "Add",IDC_BUTTON_ADD_URL,288,160,50,14 END IDD_NET DIALOG DISCARDABLE 0, 0, SETUP_STANDARD_DIALOG_DIMS diff --git a/site.cc b/site.cc index c9fac12..a2f9406 100644 --- a/site.cc +++ b/site.cc @@ -18,6 +18,7 @@ #include #include +#include #include "site.h" #include "win32.h" @@ -141,6 +142,130 @@ SiteSetting::~SiteSetting () save (); } +static bool +common (const string &domain) +{ + const string prefixes[] = { "cygwin", "ftp", "mirror", "www" }; + + for (auto& s: prefixes) + { + if (s.length() <= domain.length() && + mismatch(s.begin(), s.end(), domain.begin()).first == s.end()) + return true; + } + + return false; +} + +static string +area_default (const string &servername) +{ + string::size_type last_idx = servername.length () - 1; + string::size_type idx = servername.find_last_of (".", last_idx); + + /* no dots => local server */ + if (idx == string::npos) + { + return "Local"; + } + + string area = servername.substr (idx + 1, last_idx - idx); + /* gTLD - initial cap. */ + area[0] = toupper (area[0]); + + /* length 2 TLD => CC TLD - uppercase. */ + if (last_idx - idx == 2) + { + area[1] = toupper (area[1]); + } + + /* length 2-3 TLD => may have subTLD - check. */ + if (last_idx - idx <= 3) + { + last_idx = idx - 1; + idx = servername.find_last_of (".", last_idx); + + /* domain below length 2-3 subTLD? */ + if (idx != string::npos && last_idx - idx <= 3) + { + string::size_type next_idx = servername.find_last_of (".", idx - 1); + + /* no more dots - begins at start */ + if (next_idx == string::npos) + { + next_idx = -1; + } + + /* check for common domain prefixes to ignore as location */ + if (!common (servername.substr (next_idx + 1, idx - next_idx - 1))) + { + /* not common domain - add subTLD to area with initial cap. */ + area += " " + toupper (servername[idx + 1]) + + servername.substr (idx + 2, last_idx - idx - 1); + } + } + } + + return area; +} + +static string +location_default (const string &servername) +{ + string::size_type last_idx = servername.length () - 1; + string::size_type idx = servername.find_last_of (".", last_idx); + string location = servername; + /* initial cap. */ + location[0] = toupper (location[0]); + + /* no dots => local server */ + if (idx == string::npos) + { + return location; + } + + /* length 2-3 TLD => may have subTLD - check. */ + if (last_idx - idx <= 3) + { + last_idx = idx - 1; + idx = servername.find_last_of (".", last_idx); + + /* domain below length 2-3 subTLD? */ + if (idx != string::npos && last_idx - idx <= 3) + { + string::size_type next_idx = servername.find_last_of (".", idx - 1); + + /* no more dots - begins at start */ + if (next_idx == string::npos) + { + next_idx = -1; + } + + /* check for common domain prefixes to ignore as location */ + if (!common (servername.substr (next_idx + 1, idx - next_idx - 1))) + { + /* not common domain - use that as location. */ + last_idx = idx - 1; + idx = next_idx; + } + } + } + + location = servername.substr (idx + 1, last_idx - idx); + + /* initial cap */ + location[0] = toupper (location[0]); + + idx = 0; + while ((idx = location.find( '-', idx)) != string::npos) + { + ++idx; + location[idx] = toupper (location[idx]); + } + + return location; +} + site_list_type::site_list_type (const string &_url, const string &_servername, const string &_area, @@ -157,30 +282,72 @@ site_list_type::site_list_type (const string &_url, if (url.at(url.length()-1) != '/') url.append("/"); - /* displayed_url is protocol and site name part of url */ - string::size_type path_offset = url.find ("/", url.find ("//") + 2); - displayed_url = url.substr(0, path_offset); + /* get protocol, host flag, and site name parts of url */ + string::size_type host_flag_posn = url.find ("//"); + string::size_type path_offset = (host_flag_posn == string::npos) + ? string::npos + : url.find ("/", host_flag_posn + 2); + /* not url-like, check for Windows UNC paths */ + if (host_flag_posn == string::npos) + { + if ('\\' == url[0] && '\\' == url[1]) + { + /* UNC path - get server */ + host_flag_posn = 0; + /* terminal '/' ensures result */ + path_offset = url.find_first_of ("\\/", host_flag_posn + 2); + } + } + /* default servername to url host or localhost */ + if (servername.length() == 0) { + servername = (path_offset != string::npos && + host_flag_posn + 2 < path_offset) + ? url.substr (host_flag_posn + 2, + path_offset - (host_flag_posn + 2)) + : "localhost"; + } + /* default area to TLD and maybe short 2nd level domain */ + if (area.length() == 0) { + area = area_default (servername); + } + /* default location to next level domain */ + if (location.length() == 0) { + location = location_default (servername); + } + + /* the sorting key is area, location, domain name components in reverse order + * (to group by country code) plus url (to ensure uniqueness) */ + key = area + " " + location + " "; + string::size_type last_idx = path_offset - 1; + string::size_type idx = url.find_last_of ("./", last_idx); - /* the sorting key is hostname components in reverse order (to sort by country code) - plus the url (to ensure uniqueness) */ - key = string(); - string::size_type last_idx = displayed_url.length () - 1; - string::size_type idx = url.find_last_of("./", last_idx); - if (last_idx - idx == 3) + if (3 <= last_idx - idx) { - /* Sort non-country TLDs (.com, .net, ...) together. */ + /* Sort gTLDs (.com, .net, .info, ...) together. */ key += " "; } - do + + while (idx < last_idx) { - key += url.substr(idx + 1, last_idx - idx); + key += url.substr (idx + 1, last_idx - idx); key += " "; last_idx = idx - 1; - idx = url.find_last_of("./", last_idx); - if (idx == string::npos) - idx = 0; - } while (idx > 0); + idx = url.find_last_of ("./\\", last_idx); + } + key += url; + + /* if double (back)slashes at start of url */ + if (host_flag_posn == 0) + { + /* check for next path delimiter */ + string::size_type share_end = url.find_first_of ("\\/", path_offset + 1); + /* include UNC server share name */ + if (share_end != string::npos) + path_offset = share_end; + } + /* displayed_url is area, location, protocol and site name part of url */ + displayed_url = area + " - " + location + " - " + url.substr (0, path_offset); } site_list_type::site_list_type (site_list_type const &rhs) @@ -379,6 +546,15 @@ void SiteSetting::registerSavedSite (const char * site) { site_list_type tempSite(site, "", "", "", false); + + /* use site in list if matching url */ + for (auto& s: all_site_list) + if (site == s.url) + { + tempSite = s; + break; + } + SiteList::iterator i = find (all_site_list.begin(), all_site_list.end(), tempSite); if (i == all_site_list.end()) @@ -699,6 +875,15 @@ bool SitePage::OnMessageCmd (int id, HWND hwndctl, UINT code) if (other_url.size()) { site_list_type newsite (other_url, "", "", "", false); + + /* use site in list if matching url */ + for (auto& s: all_site_list) + if (other_url == s.url) + { + newsite = s; + break; + } + SiteList::iterator i = find (all_site_list.begin(), all_site_list.end(), newsite); if (i == all_site_list.end())