#include struct t_protocolInfo { const ServerProtocol protocol; const wxString prefix; bool alwaysShowPrefix; unsigned int defaultPort; const bool translateable; const wxChar* const name; bool supportsPostlogin; }; static const t_protocolInfo protocolInfos[] = { { FTP, _T("ftp"), false, 21, true, TRANSLATE_T("FTP - File Transfer Protocol with optional encryption"), true }, { SFTP, _T("sftp"), true, 22, false, _T("SFTP - SSH File Transfer Protocol"), false }, { HTTP, _T("http"), true, 80, false, _T("HTTP - Hypertext Transfer Protocol"), false }, { HTTPS, _T("https"), true, 443, true, TRANSLATE_T("HTTPS - HTTP over TLS"), false }, { FTPS, _T("ftps"), true, 990, true, TRANSLATE_T("FTPS - FTP over implicit TLS"), true }, { FTPES, _T("ftpes"), true, 21, true, TRANSLATE_T("FTPES - FTP over explicit TLS"), true }, { INSECURE_FTP, _T("ftp"), false, 21, true, TRANSLATE_T("FTP - Insecure File Transfer Protocol"), true }, { UNKNOWN, _T(""), false, 21, false, _T(""), false } }; static const wxString typeNames[SERVERTYPE_MAX] = { TRANSLATE_T("Default (Autodetect)"), _T("Unix"), _T("VMS"), _T("DOS"), _T("MVS, OS/390, z/OS"), _T("VxWorks"), _T("z/VM"), _T("HP NonStop"), TRANSLATE_T("DOS-like with virtual paths"), _T("Cygwin") }; static const t_protocolInfo& GetProtocolInfo(ServerProtocol protocol) { unsigned int i = 0; for ( ; protocolInfos[i].protocol != UNKNOWN; ++i) { if (protocolInfos[i].protocol == protocol) break; } return protocolInfos[i]; } CServer::CServer() { Initialize(); } bool CServer::ParseUrl(wxString host, wxString port, wxString user, wxString pass, wxString &error, CServerPath &path) { unsigned long nPort = 0; if (!port.empty()) { port.Trim(false); port.Trim(true); if (port.size() > 5 || !port.ToULong(&nPort) || !nPort || nPort > 65535) { error = _("Invalid port given. The port has to be a value from 1 to 65535."); error += _T("\n"); error += _("You can leave the port field empty to use the default port."); return false; } } return ParseUrl(host, nPort, user, pass, error, path); } bool CServer::ParseUrl(wxString host, unsigned int port, wxString user, wxString pass, wxString &error, CServerPath &path) { m_type = DEFAULT; if (host.empty()) { error = _("No host given, please enter a host."); return false; } int pos = host.Find(_T("://")); if (pos != -1) { wxString protocol = host.Left(pos).Lower(); host = host.Mid(pos + 3); if (protocol.Left(3) == _T("fz_")) protocol = protocol.Mid(3); m_protocol = GetProtocolFromPrefix(protocol.Lower()); if (m_protocol == UNKNOWN) { // TODO: http:// once WebDAV is officially supported error = _("Invalid protocol specified. Valid protocols are:\nftp:// for normal FTP with optional encryption,\nsftp:// for SSH file transfer protocol,\nftps:// for FTP over TLS (implicit) and\nftpes:// for FTP over TLS (explicit)."); return false; } } pos = host.Find('@'); if (pos != -1) { // Check if it's something like // user@name:password@host:port/path // => If there are multiple at signs, username/port ends at last at before // the first slash. (Since host and port never contain any at sign) int slash = host.Mid(pos + 1).Find('/'); if (slash != -1) slash += pos + 1; int next_at = host.Mid(pos + 1).Find('@'); while (next_at != -1) { next_at += pos + 1; if (slash != -1 && next_at > slash) break; pos = next_at; next_at = host.Mid(pos + 1).Find('@'); } user = host.Left(pos); host = host.Mid(pos + 1); // Extract password (if any) from username pos = user.Find(':'); if (pos != -1) { pass = user.Mid(pos + 1); user = user.Left(pos); } // Remove leading and trailing whitespace user.Trim(true); user.Trim(false); if (user.empty()) { error = _("Invalid username given."); return false; } } else { // Remove leading and trailing whitespace user.Trim(true); user.Trim(false); if (user.empty() && m_logonType != ASK && m_logonType != INTERACTIVE) { user = _T("anonymous"); pass = _T("anonymous@example.com"); } } pos = host.Find('/'); if (pos != -1) { path = CServerPath(host.Mid(pos)); host = host.Left(pos); } if (!host.empty() && host[0] == '[') { // Probably IPv6 address pos = host.Find(']'); if (pos == -1) { error = _("Host starts with '[' but no closing bracket found."); return false; } if (pos + 1 < static_cast(host.Len()) ) { if (host[pos + 1] != ':') { error = _("Invalid host, after closing bracket only colon and port may follow."); return false; } ++pos; } else pos = -1; } else pos = host.Find(':'); if (pos != -1) { if (!pos) { error = _("No host given, please enter a host."); return false; } long tmp; if (!host.Mid(pos + 1).ToLong(&tmp) || tmp < 1 || tmp > 65535) { error = _("Invalid port given. The port has to be a value from 1 to 65535."); return false; } port = tmp; host = host.Left(pos); } else { if (!port) port = GetDefaultPort(m_protocol); else if (port > 65535) { error = _("Invalid port given. The port has to be a value from 1 to 65535."); return false; } } host.Trim(true); host.Trim(false); if (host.empty()) { error = _("No host given, please enter a host."); return false; } m_host = host; if (m_host[0] == '[') { m_host.RemoveLast(); m_host = m_host.Mid(1); } m_port = port; m_user = user; m_pass = pass; m_account.clear(); if (m_logonType != ASK && m_logonType != INTERACTIVE) { if (m_user.empty()) m_logonType = ANONYMOUS; else if (m_user == _T("anonymous")) if (m_pass.empty() || m_pass == _T("anonymous@example.com")) m_logonType = ANONYMOUS; else m_logonType = NORMAL; else m_logonType = NORMAL; } if (m_protocol == UNKNOWN) m_protocol = GetProtocolFromPort(port); return true; } ServerProtocol CServer::GetProtocol() const { return m_protocol; } ServerType CServer::GetType() const { return m_type; } wxString CServer::GetHost() const { return m_host; } unsigned int CServer::GetPort() const { return m_port; } wxString CServer::GetUser() const { if (m_logonType == ANONYMOUS) return _T("anonymous"); return m_user; } wxString CServer::GetPass() const { if (m_logonType == ANONYMOUS) return _T("anon@localhost"); return m_pass; } wxString CServer::GetAccount() const { if (m_logonType != ACCOUNT) return wxString(); return m_account; } wxString CServer::GetKeyFile() const { if (m_logonType != KEY) return wxString(); return m_keyFile; } CServer& CServer::operator=(const CServer &op) { m_protocol = op.m_protocol; m_type = op.m_type; m_host = op.m_host; m_port = op.m_port; m_logonType = op.m_logonType; m_user = op.m_user; m_pass = op.m_pass; m_account = op.m_account; m_keyFile = op.m_keyFile; m_timezoneOffset = op.m_timezoneOffset; m_pasvMode = op.m_pasvMode; m_maximumMultipleConnections = op.m_maximumMultipleConnections; m_encodingType = op.m_encodingType; m_customEncoding = op.m_customEncoding; m_postLoginCommands = op.m_postLoginCommands; m_bypassProxy = op.m_bypassProxy; m_name = op.m_name; return *this; } bool CServer::operator==(const CServer &op) const { if (m_protocol != op.m_protocol) return false; else if (m_type != op.m_type) return false; else if (m_host != op.m_host) return false; else if (m_port != op.m_port) return false; else if (m_logonType != op.m_logonType) return false; else if (m_logonType != ANONYMOUS) { if (m_user != op.m_user) return false; if (m_logonType == NORMAL) { if (m_pass != op.m_pass) return false; } else if (m_logonType == ACCOUNT) { if (m_pass != op.m_pass) return false; if (m_account != op.m_account) return false; } else if (m_logonType == KEY) { if (m_keyFile != op.m_keyFile) return false; } } if (m_timezoneOffset != op.m_timezoneOffset) return false; else if (m_pasvMode != op.m_pasvMode) return false; else if (m_encodingType != op.m_encodingType) return false; else if (m_encodingType == ENCODING_CUSTOM) { if (m_customEncoding != op.m_customEncoding) return false; } if (m_postLoginCommands != op.m_postLoginCommands) return false; if (m_bypassProxy != op.m_bypassProxy) return false; // Do not compare number of allowed multiple connections return true; } bool CServer::operator<(const CServer &op) const { if (m_protocol < op.m_protocol) return true; else if (m_protocol > op.m_protocol) return false; if (m_type < op.m_type) return true; else if (m_type > op.m_type) return false; int cmp = m_host.Cmp(op.m_host); if (cmp < 0) return true; else if (cmp > 0) return false; if (m_port < op.m_port) return true; else if (m_port > op.m_port) return false; if (m_logonType < op.m_logonType) return true; else if (m_logonType > op.m_logonType) return false; if (m_logonType != ANONYMOUS) { cmp = m_user.Cmp(op.m_user); if (cmp < 0) return true; else if (cmp > 0) return false; if (m_logonType == NORMAL) { cmp = m_pass.Cmp(op.m_pass); if (cmp < 0) return true; else if (cmp > 0) return false; } else if (m_logonType == ACCOUNT) { cmp = m_pass.Cmp(op.m_pass); if (cmp < 0) return true; else if (cmp > 0) return false; cmp = m_account.Cmp(op.m_account); if (cmp < 0) return true; else if (cmp > 0) return false; } } if (m_timezoneOffset < op.m_timezoneOffset) return true; else if (m_timezoneOffset > op.m_timezoneOffset) return false; if (m_pasvMode < op.m_pasvMode) return true; else if (m_pasvMode > op.m_pasvMode) return false; if (m_encodingType < op.m_encodingType) return true; else if (m_encodingType > op.m_encodingType) return false; if (m_encodingType == ENCODING_CUSTOM) { if (m_customEncoding < op.m_customEncoding) return true; else if (m_customEncoding > op.m_customEncoding) return false; } if (m_bypassProxy < op.m_bypassProxy) return true; else if (m_bypassProxy > op.m_bypassProxy) return false; // Do not compare number of allowed multiple connections return false; } bool CServer::operator!=(const CServer &op) const { return !(*this == op); } bool CServer::EqualsNoPass(const CServer &op) const { if (m_protocol != op.m_protocol) return false; else if (m_type != op.m_type) return false; else if (m_host != op.m_host) return false; else if (m_port != op.m_port) return false; else if ((m_logonType == ANONYMOUS) != (op.m_logonType == ANONYMOUS)) return false; else if ((m_logonType == ACCOUNT) != (op.m_logonType == ACCOUNT)) return false; else if (m_logonType != ANONYMOUS) { if (m_user != op.m_user) return false; if (m_logonType == ACCOUNT) if (m_account != op.m_account) return false; } if (m_timezoneOffset != op.m_timezoneOffset) return false; else if (m_pasvMode != op.m_pasvMode) return false; else if (m_encodingType != op.m_encodingType) return false; else if (m_encodingType == ENCODING_CUSTOM) { if (m_customEncoding != op.m_customEncoding) return false; } if (m_postLoginCommands != op.m_postLoginCommands) return false; if (m_bypassProxy != op.m_bypassProxy) return false; // Do not compare number of allowed multiple connections return true; } CServer::CServer(ServerProtocol protocol, ServerType type, wxString host, unsigned int port, wxString user, wxString pass, wxString account) { Initialize(); m_protocol = protocol; m_type = type; m_host = host; m_port = port; m_logonType = NORMAL; m_user = user; m_pass = pass; m_account = account; } CServer::CServer(ServerProtocol protocol, ServerType type, wxString host, unsigned int port) { Initialize(); m_protocol = protocol; m_type = type; m_host = host; m_port = port; } void CServer::SetType(ServerType type) { m_type = type; } LogonType CServer::GetLogonType() const { return m_logonType; } void CServer::SetLogonType(LogonType logonType) { wxASSERT(logonType != LOGONTYPE_MAX); m_logonType = logonType; } void CServer::SetProtocol(ServerProtocol serverProtocol) { wxASSERT(serverProtocol != UNKNOWN); if (!GetProtocolInfo(serverProtocol).supportsPostlogin) m_postLoginCommands.clear(); m_protocol = serverProtocol; } bool CServer::SetHost(wxString host, unsigned int port) { if (host.empty()) return false; if (port < 1 || port > 65535) return false; m_host = host; m_port = port; if (m_protocol == UNKNOWN) m_protocol = GetProtocolFromPort(m_port); return true; } bool CServer::SetUser(const wxString& user, const wxString& pass) { if (m_logonType == ANONYMOUS) return true; if (user.empty()) { if (m_logonType != ASK && m_logonType != INTERACTIVE) return false; m_pass.clear(); } else m_pass = pass; m_user = user; return true; } bool CServer::SetAccount(const wxString& account) { if (m_logonType != ACCOUNT) return false; m_account = account; return true; } bool CServer::SetKeyFile(const wxString& keyFile) { if (m_logonType != KEY) return false; m_keyFile = keyFile; return true; } bool CServer::SetTimezoneOffset(int minutes) { if (minutes > (60 * 24) || minutes < (-60 * 24)) return false; m_timezoneOffset = minutes; return true; } int CServer::GetTimezoneOffset() const { return m_timezoneOffset; } PasvMode CServer::GetPasvMode() const { return m_pasvMode; } void CServer::SetPasvMode(PasvMode pasvMode) { m_pasvMode = pasvMode; } void CServer::MaximumMultipleConnections(int maximumMultipleConnections) { m_maximumMultipleConnections = maximumMultipleConnections; } int CServer::MaximumMultipleConnections() const { return m_maximumMultipleConnections; } wxString CServer::FormatHost(bool always_omit_port /*=false*/) const { wxString host = m_host; if (host.Find(':') != -1) host = _T("[") + host + _T("]"); if (!always_omit_port) { if (m_port != GetDefaultPort(m_protocol)) host += wxString::Format(_T(":%d"), m_port); } return host; } wxString CServer::FormatServer(const bool always_include_prefix /*=false*/) const { wxString server = FormatHost(); if (m_logonType != ANONYMOUS) server = GetUser() + _T("@") + server; const t_protocolInfo& info = GetProtocolInfo(m_protocol); if (!info.prefix.empty()) { if (always_include_prefix || info.alwaysShowPrefix) server = info.prefix + _T("://") + server; else if (m_port != info.defaultPort) server = info.prefix + _T("://") + server; } return server; } void CServer::Initialize() { m_protocol = UNKNOWN; m_type = DEFAULT; m_host.clear(); m_port = 21; m_logonType = ANONYMOUS; m_user.clear(); m_pass.clear(); m_account.clear(); m_timezoneOffset = 0; m_pasvMode = MODE_DEFAULT; m_maximumMultipleConnections = 0; m_encodingType = ENCODING_AUTO; m_customEncoding.clear(); m_bypassProxy = false; } bool CServer::SetEncodingType(CharsetEncoding type, const wxString& encoding) { if (type == ENCODING_CUSTOM && encoding.empty()) return false; m_encodingType = type; m_customEncoding = encoding; return true; } bool CServer::SetCustomEncoding(const wxString& encoding) { if (encoding.empty()) return false; m_encodingType = ENCODING_CUSTOM; m_customEncoding = encoding; return true; } CharsetEncoding CServer::GetEncodingType() const { return m_encodingType; } wxString CServer::GetCustomEncoding() const { return m_customEncoding; } unsigned int CServer::GetDefaultPort(ServerProtocol protocol) { const t_protocolInfo& info = GetProtocolInfo(protocol); return info.defaultPort; } ServerProtocol CServer::GetProtocolFromPort(unsigned int port, bool defaultOnly /*=false*/) { for (unsigned int i = 0; protocolInfos[i].protocol != UNKNOWN; ++i) { if (protocolInfos[i].defaultPort == port) return protocolInfos[i].protocol; } if (defaultOnly) return UNKNOWN; // Else default to FTP return FTP; } wxString CServer::GetProtocolName(ServerProtocol protocol) { const t_protocolInfo *protocolInfo = protocolInfos; while (protocolInfo->protocol != UNKNOWN) { if (protocolInfo->protocol != protocol) { ++protocolInfo; continue; } if (protocolInfo->translateable) return wxGetTranslation(protocolInfo->name); else return protocolInfo->name; } return wxString(); } ServerProtocol CServer::GetProtocolFromName(const wxString& name) { const t_protocolInfo *protocolInfo = protocolInfos; while (protocolInfo->protocol != UNKNOWN) { if (protocolInfo->translateable) { if (wxGetTranslation(protocolInfo->name) == name) return protocolInfo->protocol; } else { if (protocolInfo->name == name) return protocolInfo->protocol; } ++protocolInfo; } return UNKNOWN; } bool CServer::SetPostLoginCommands(const std::vector& postLoginCommands) { if (!SupportsPostLoginCommands(m_protocol)) { m_postLoginCommands.clear(); return false; } m_postLoginCommands = postLoginCommands; return true; } bool CServer::SupportsPostLoginCommands(ServerProtocol const protocol) { return protocol == FTP || protocol == FTPS || protocol == FTPES || protocol == INSECURE_FTP; } ServerProtocol CServer::GetProtocolFromPrefix(const wxString& prefix) { for (unsigned int i = 0; protocolInfos[i].protocol != UNKNOWN; ++i) { if (!protocolInfos[i].prefix.CmpNoCase(prefix)) return protocolInfos[i].protocol; } return UNKNOWN; } wxString CServer::GetPrefixFromProtocol(const ServerProtocol protocol) { const t_protocolInfo& info = GetProtocolInfo(protocol); return info.prefix; } void CServer::SetBypassProxy(bool val) { m_bypassProxy = val; } bool CServer::GetBypassProxy() const { return m_bypassProxy; } bool CServer::ProtocolHasDataTypeConcept(const ServerProtocol protocol) { if (protocol == FTP || protocol == FTPS || protocol == FTPES || protocol == INSECURE_FTP) return true; return false; } wxString CServer::GetNameFromServerType(ServerType type) { wxASSERT(type != SERVERTYPE_MAX); return wxGetTranslation(typeNames[type]); } ServerType CServer::GetServerTypeFromName(const wxString& name) { for (int i = 0; i < SERVERTYPE_MAX; ++i) { ServerType type = static_cast(i); if (name == CServer::GetNameFromServerType(type)) return type; } return DEFAULT; } LogonType CServer::GetLogonTypeFromName(const wxString& name) { if (name == _("Normal")) return NORMAL; else if (name == _("Ask for password")) return ASK; else if (name == _("Key file")) return KEY; else if (name == _("Interactive")) return INTERACTIVE; else if (name == _("Account")) return ACCOUNT; else return ANONYMOUS; } wxString CServer::GetNameFromLogonType(LogonType type) { wxASSERT(type != LOGONTYPE_MAX); switch (type) { case NORMAL: return _("Normal"); case ASK: return _("Ask for password"); case KEY: return _("Key file"); case INTERACTIVE: return _("Interactive"); case ACCOUNT: return _("Account"); default: return _("Anonymous"); } }