+// ----------------------------------------------------------------------------
+// Send command to FTP server
+// ----------------------------------------------------------------------------
+
+char wxFTP::SendCommand(const wxString& command)
+{
+ if ( m_streaming )
+ {
+ m_lastError = wxPROTO_STREAMING;
+ return 0;
+ }
+
+ wxString tmp_str = command + wxT("\r\n");
+ const wxWX2MBbuf tmp_buf = tmp_str.mb_str();
+ if ( Write(wxMBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error())
+ {
+ m_lastError = wxPROTO_NETERR;
+ return 0;
+ }
+
+ // don't show the passwords in the logs (even in debug ones)
+ wxString cmd, password;
+ if ( command.Upper().StartsWith(_T("PASS "), &password) )
+ {
+ cmd << _T("PASS ") << wxString(_T('*'), password.length());
+ }
+ else
+ {
+ cmd = command;
+ }
+
+ LogRequest(cmd);
+
+ m_lastError = wxPROTO_NOERR;
+ return GetResult();
+}
+
+// ----------------------------------------------------------------------------
+// Receive servers reply
+// ----------------------------------------------------------------------------
+
+char wxFTP::GetResult()
+{
+ // if we've already had a read or write timeout error, the connection is
+ // probably toast, so don't bother, it just wastes the users time
+ if ( m_bEncounteredError )
+ return 0;
+
+ wxString code;
+
+ // m_lastResult will contain the entire server response, possibly on
+ // multiple lines
+ m_lastResult.clear();
+
+ // we handle multiline replies here according to RFC 959: it says that a
+ // reply may either be on 1 line of the form "xyz ..." or on several lines
+ // in whuch case it looks like
+ // xyz-...
+ // ...
+ // xyz ...
+ // and the intermeidate lines may start with xyz or not
+ bool badReply = false;
+ bool firstLine = true;
+ bool endOfReply = false;
+ while ( !endOfReply && !badReply )
+ {
+ wxString line;
+ m_lastError = ReadLine(this,line);
+ if ( m_lastError )
+ {
+ m_bEncounteredError = true;
+ return 0;
+ }
+
+ LogResponse(line);
+
+ if ( !m_lastResult.empty() )
+ {
+ // separate from last line
+ m_lastResult += _T('\n');
+ }
+
+ m_lastResult += line;
+
+ // unless this is an intermediate line of a multiline reply, it must
+ // contain the code in the beginning and '-' or ' ' following it
+ if ( line.Len() < LEN_CODE + 1 )
+ {
+ if ( firstLine )
+ {
+ badReply = true;
+ }
+ }
+ else // line has at least 4 chars
+ {
+ // this is the char which tells us what we're dealing with
+ wxChar chMarker = line.GetChar(LEN_CODE);
+
+ if ( firstLine )
+ {
+ code = wxString(line, LEN_CODE);
+
+ switch ( chMarker )
+ {
+ case _T(' '):
+ endOfReply = true;
+ break;
+
+ case _T('-'):
+ firstLine = false;
+ break;
+
+ default:
+ // unexpected
+ badReply = true;
+ }
+ }
+ else // subsequent line of multiline reply
+ {
+ if ( line.compare(0, LEN_CODE, code) == 0 )
+ {
+ if ( chMarker == _T(' ') )
+ {
+ endOfReply = true;
+ }
+ }
+ }
+ }
+ }
+
+ if ( badReply )
+ {
+ wxLogDebug(_T("Broken FTP server: '%s' is not a valid reply."),
+ m_lastResult.c_str());
+
+ m_lastError = wxPROTO_PROTERR;
+
+ return 0;
+ }
+ else
+ m_lastError = wxPROTO_NOERR;
+
+ // if we got here we must have a non empty code string
+ return (char)code[0u];
+}
+
+// ----------------------------------------------------------------------------
+// wxFTP simple commands
+// ----------------------------------------------------------------------------
+
+bool wxFTP::SetTransferMode(TransferMode transferMode)
+{
+ if ( transferMode == m_currentTransfermode )
+ {
+ // nothing to do
+ return true;
+ }
+
+ wxString mode;
+ switch ( transferMode )
+ {
+ default:
+ wxFAIL_MSG(_T("unknown FTP transfer mode"));
+ // fall through
+
+ case BINARY:
+ mode = _T('I');
+ break;
+
+ case ASCII:
+ mode = _T('A');
+ break;
+ }
+
+ if ( !DoSimpleCommand(_T("TYPE"), mode) )
+ {
+ wxLogError(_("Failed to set FTP transfer mode to %s."),
+ (transferMode == ASCII ? _("ASCII") : _("binary")));
+
+ return false;
+ }
+
+ // If we get here the operation has been successfully completed
+ // Set the status-member
+ m_currentTransfermode = transferMode;
+
+ return true;
+}
+
+bool wxFTP::DoSimpleCommand(const wxChar *command, const wxString& arg)
+{
+ wxString fullcmd = command;
+ if ( !arg.empty() )
+ {
+ fullcmd << _T(' ') << arg;
+ }