int CHttpControlSocket::SendNextCommand() { LogMessage(Debug_Verbose, _T("CHttpControlSocket::SendNextCommand()")); if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("SendNextCommand called without active operation")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } if (m_pCurOpData->waitForAsyncRequest) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Waiting for async request, ignoring SendNextCommand")); return FZ_REPLY_WOULDBLOCK; } switch (m_pCurOpData->opId) { case cmd_transfer: return FileTransferSend(); default: LogMessage(__TFILE__, __LINE__, this, ::Debug_Warning, _T("Unknown opID (%d) in SendNextCommand"), m_pCurOpData->opId); ResetOperation(FZ_REPLY_INTERNALERROR); break; } return FZ_REPLY_ERROR; }
int CHttpControlSocket::DoInternalConnect() { LogMessage(Debug_Verbose, _T("CHttpControlSocket::DoInternalConnect()")); if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData")); ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; } CHttpConnectOpData *pData = static_cast<CHttpConnectOpData *>(m_pCurOpData); delete m_pBackend; m_pBackend = new CSocketBackend(this, m_pSocket); int res = m_pSocket->Connect(pData->host, pData->port); if (!res) return FZ_REPLY_OK; if (res && res != EINPROGRESS) return ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_WOULDBLOCK; }
int CHttpControlSocket::FileTransferSend() { LogMessage(Debug_Verbose, _T("CHttpControlSocket::FileTransferSend()")); if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData")); ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; } CHttpFileTransferOpData *pData = static_cast<CHttpFileTransferOpData *>(m_pCurOpData); if (pData->opState == filetransfer_waitfileexists) { pData->opState = filetransfer_transfer; pData->pFile = new wxFile(); CreateLocalDir(pData->localFile); if (!pData->pFile->Open(pData->localFile, wxFile::write)) { LogMessage(::Error, _("Failed to open \"%s\" for writing"), pData->localFile.c_str()); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } int res = InternalConnect(m_pCurrentServer->GetHost(), m_pCurrentServer->GetPort(), m_pCurrentServer->GetProtocol() == HTTPS); if (res != FZ_REPLY_OK) return res; } wxString location; wxString hostWithPort; if (pData->m_newLocation == _T("")) { if (m_pCurrentServer->GetProtocol() == HTTPS) location = _T("https://") + wxString(m_pCurrentServer->FormatHost()) + wxString(pData->remotePath.FormatFilename(pData->remoteFile).c_str()); else location = _T("http://") + wxString(m_pCurrentServer->FormatHost()) + wxString(pData->remotePath.FormatFilename(pData->remoteFile).c_str()); hostWithPort = wxString::Format(_T("%s:%d"), m_pCurrentServer->FormatHost(true).c_str(), m_pCurrentServer->GetPort()); } else { location = pData->m_newLocation; hostWithPort = pData->m_newHostWithPort; } wxString action = wxString::Format(_T("GET %s HTTP/1.1"), location.c_str()); LogMessageRaw(Command, action); wxString command = wxString::Format(_T("%s\r\nHost: %s\r\nUser-Agent: %s\r\nConnection: close\r\n\r\n"), action.c_str(), hostWithPort.c_str(), wxString(PACKAGE_STRING, wxConvLocal).c_str()); const wxWX2MBbuf str = command.mb_str(); if (!Send(str, strlen(str))) return FZ_REPLY_ERROR; return FZ_REPLY_WOULDBLOCK; }
int CHttpControlSocket::FileTransfer(const wxString localFile, const CServerPath &remotePath, const wxString &remoteFile, bool download, const CFileTransferCommand::t_transferSettings& transferSettings) { LogMessage(Debug_Verbose, _T("CHttpControlSocket::FileTransfer()")); LogMessage(Status, _("Downloading %s"), remotePath.FormatFilename(remoteFile).c_str()); if (!download) { ResetOperation(FZ_REPLY_CRITICALERROR | FZ_REPLY_NOTSUPPORTED); return FZ_REPLY_ERROR; } if (m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("deleting nonzero pData")); delete m_pCurOpData; } CHttpFileTransferOpData *pData = new CHttpFileTransferOpData(download, localFile, remoteFile, remotePath); m_pCurOpData = pData; m_pHttpOpData = pData; if (localFile != _T("")) { pData->opState = filetransfer_waitfileexists; int res = CheckOverwriteFile(); if (res != FZ_REPLY_OK) return res; pData->opState = filetransfer_transfer; pData->pFile = new wxFile(); CreateLocalDir(pData->localFile); if (!pData->pFile->Open(pData->localFile, wxFile::write)) { LogMessage(::Error, _("Failed to open \"%s\" for writing"), pData->localFile.c_str()); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } } else pData->opState = filetransfer_transfer; int res = InternalConnect(m_pCurrentServer->GetHost(), m_pCurrentServer->GetPort(), m_pCurrentServer->GetProtocol() == HTTPS); if (res != FZ_REPLY_OK) return res; return FileTransferSend(); }
bool CHttpControlSocket::SetAsyncRequestReply(CAsyncRequestNotification *pNotification) { if (m_pCurOpData) { if (!m_pCurOpData->waitForAsyncRequest) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Not waiting for request reply, ignoring request reply %d"), pNotification->GetRequestID()); return false; } m_pCurOpData->waitForAsyncRequest = false; } switch (pNotification->GetRequestID()) { case reqId_fileexists: { if (!m_pCurOpData || m_pCurOpData->opId != cmd_transfer) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("No or invalid operation in progress, ignoring request reply %f"), pNotification->GetRequestID()); return false; } CFileExistsNotification *pFileExistsNotification = reinterpret_cast<CFileExistsNotification *>(pNotification); switch (pFileExistsNotification->overwriteAction) { case CFileExistsNotification::resume: ResetOperation(FZ_REPLY_CRITICALERROR | FZ_REPLY_NOTSUPPORTED); break; default: return SetFileExistsAction(pFileExistsNotification); } } break; case reqId_certificate: { if (!m_pTlsSocket || m_pTlsSocket->GetState() != CTlsSocket::verifycert) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("No or invalid operation in progress, ignoring request reply %d"), pNotification->GetRequestID()); return false; } CCertificateNotification* pCertificateNotification = reinterpret_cast<CCertificateNotification *>(pNotification); m_pTlsSocket->TrustCurrentCert(pCertificateNotification->m_trusted); } break; default: LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Unknown request %d"), pNotification->GetRequestID()); ResetOperation(FZ_REPLY_INTERNALERROR); return false; } return true; }
void CHttpControlSocket::OnConnect() { wxASSERT(GetCurrentCommandId() == cmd_connect); CHttpConnectOpData *pData = static_cast<CHttpConnectOpData *>(m_pCurOpData); if (pData->tls) { if (!m_pTlsSocket) { LogMessage(Status, _("Connection established, initializing TLS...")); delete m_pBackend; m_pTlsSocket = new CTlsSocket(this, m_pSocket, this); m_pBackend = m_pTlsSocket; if (!m_pTlsSocket->Init()) { LogMessage(::Error, _("Failed to initialize TLS.")); DoClose(); return; } const wxString trusted_rootcert = m_pEngine->GetOptions()->GetOption(OPTION_INTERNAL_ROOTCERT); if (trusted_rootcert != _T("") && !m_pTlsSocket->AddTrustedRootCertificate(trusted_rootcert)) { LogMessage(::Error, _("Failed to parse trusted root cert.")); DoClose(); return; } int res = m_pTlsSocket->Handshake(); if (res == FZ_REPLY_ERROR) DoClose(); } else { LogMessage(Status, _("TLS/SSL connection established, sending HTTP request")); ResetOperation(FZ_REPLY_OK); } return; } else { LogMessage(Status, _("Connection established, sending HTTP request")); ResetOperation(FZ_REPLY_OK); } }
void CHttpControlSocket::OnClose(int error) { LogMessage(Debug_Verbose, _T("CHttpControlSocket::OnClose(%d)"), error); if (error) { LogMessage(::Error, _("Disconnected from server: %s"), CSocket::GetErrorDescription(error).c_str()); ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return; } if (DoReceive() == FZ_REPLY_REDIRECTED) return; // Socket got closed already // HTTP socket isn't connected outside operations if (!m_pCurOpData) return; if (m_pCurOpData->pNextOpData) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return; } if (!m_pHttpOpData->m_gotHeader) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return; } if (m_pHttpOpData->m_transferEncoding == CHttpOpData::chunked) { if (!m_pHttpOpData->m_chunkData.getTrailer) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return; } } else { if (m_pHttpOpData->m_totalSize != -1 && m_pHttpOpData->m_receivedData != m_pHttpOpData->m_totalSize) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return; } } ProcessData(0, 0); }
int CFileZillaEngine::Execute(const CCommand &command) { if (command.GetId() != Command::cancel && IsBusy()) return FZ_REPLY_BUSY; m_bIsInCommand = true; int res = FZ_REPLY_INTERNALERROR; switch (command.GetId()) { case Command::connect: res = Connect(reinterpret_cast<const CConnectCommand &>(command)); break; case Command::disconnect: res = Disconnect(reinterpret_cast<const CDisconnectCommand &>(command)); break; case Command::cancel: res = Cancel(reinterpret_cast<const CCancelCommand &>(command)); break; case Command::list: res = List(reinterpret_cast<const CListCommand &>(command)); break; case Command::transfer: res = FileTransfer(reinterpret_cast<const CFileTransferCommand &>(command)); break; case Command::raw: res = RawCommand(reinterpret_cast<const CRawCommand&>(command)); break; case Command::del: res = Delete(reinterpret_cast<const CDeleteCommand&>(command)); break; case Command::removedir: res = RemoveDir(reinterpret_cast<const CRemoveDirCommand&>(command)); break; case Command::mkdir: res = Mkdir(reinterpret_cast<const CMkdirCommand&>(command)); break; case Command::rename: res = Rename(reinterpret_cast<const CRenameCommand&>(command)); break; case Command::chmod: res = Chmod(reinterpret_cast<const CChmodCommand&>(command)); break; default: return FZ_REPLY_SYNTAXERROR; } if (res != FZ_REPLY_WOULDBLOCK) ResetOperation(res); m_bIsInCommand = false; if (command.GetId() != Command::disconnect) res |= m_nControlSocketError; else if (res & FZ_REPLY_DISCONNECTED) res = FZ_REPLY_OK; m_nControlSocketError = 0; return res; }
int CHttpControlSocket::FileTransferParseResponse(char* p, unsigned int len) { LogMessage(Debug_Verbose, _T("CHttpControlSocket::FileTransferParseResponse(%p, %d)"), p, len); if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData")); ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; } CHttpFileTransferOpData *pData = static_cast<CHttpFileTransferOpData *>(m_pCurOpData); if (!p) { ResetOperation(FZ_REPLY_OK); return FZ_REPLY_OK; } if (!m_pTransferStatus) { InitTransferStatus(pData->m_totalSize.GetLo() + ((wxFileOffset)pData->m_totalSize.GetHi() << 32), 0, false); SetTransferStatusStartTime(); } if (pData->localFile == _T("")) { char* q = new char[len]; memcpy(q, p, len); m_pEngine->AddNotification(new CDataNotification(q, len)); } else { wxASSERT(pData->pFile); if (pData->pFile->Write(p, len) != len) { LogMessage(::Error, _("Failed to write to file %s"), pData->localFile.c_str()); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } } UpdateTransferStatus(len); return FZ_REPLY_WOULDBLOCK; }
int CHttpControlSocket::FileTransferSubcommandResult(int prevResult) { LogMessage(Debug_Verbose, _T("CHttpControlSocket::FileTransferSubcommandResult(%d)"), prevResult); if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData")); ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; } if (prevResult != FZ_REPLY_OK) { ResetOperation(prevResult); return FZ_REPLY_ERROR; } return FileTransferSend(); }
void CControlSocket::Cancel() { if (GetCurrentCommandId() != Command::none) { if (GetCurrentCommandId() == Command::connect) DoClose(FZ_REPLY_CANCELED); else ResetOperation(FZ_REPLY_CANCELED); } }
int CHttpControlSocket::ParseSubcommandResult(int prevResult) { LogMessage(Debug_Verbose, _T("CHttpControlSocket::SendNextCommand(%d)"), prevResult); if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("SendNextCommand called without active operation")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } switch (m_pCurOpData->opId) { case cmd_transfer: return FileTransferSubcommandResult(prevResult); default: LogMessage(__TFILE__, __LINE__, this, ::Debug_Warning, _T("Unknown opID (%d) in SendNextCommand"), m_pCurOpData->opId); ResetOperation(FZ_REPLY_INTERNALERROR); break; } return FZ_REPLY_ERROR; }
int CHttpControlSocket::ContinueConnect() { LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CHttpControlSocket::ContinueConnect() m_pEngine=%p"), m_pEngine); if (GetCurrentCommandId() != cmd_connect || !m_pCurrentServer) { LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer); return DoClose(FZ_REPLY_INTERNALERROR); } ResetOperation(FZ_REPLY_OK); return FZ_REPLY_OK; }
int CControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/) { LogMessage(MessageType::Debug_Debug, _T("CControlSocket::DoClose(%d)"), nErrorCode); if (m_closed) { wxASSERT(!m_pCurOpData); return nErrorCode; } m_closed = true; nErrorCode = ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED | nErrorCode); delete m_pCurrentServer; m_pCurrentServer = 0; return nErrorCode; }
int CControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/) { if (m_closed) { wxASSERT(!m_pCurOpData); return nErrorCode; } m_closed = true; nErrorCode = ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED | nErrorCode); delete m_pCurrentServer; m_pCurrentServer = 0; return nErrorCode; }
void CFileZillaEnginePrivate::OnEngineEvent(wxFzEngineEvent &event) { switch (event.m_eventType) { case engineCancel: if (!IsBusy()) break; if (m_pControlSocket) m_pControlSocket->Cancel(); else if (m_pCurrentCommand) ResetOperation(FZ_REPLY_CANCELED); break; case engineTransferEnd: if (m_pControlSocket) m_pControlSocket->TransferEnd(); default: break; } }
int CHttpControlSocket::ProcessData(char* p, int len) { int res; enum Command commandId = GetCurrentCommandId(); switch (commandId) { case cmd_transfer: res = FileTransferParseResponse(p, len); break; default: LogMessage(Debug_Warning, _T("No action for parsing data for command %d"), (int)commandId); ResetOperation(FZ_REPLY_INTERNALERROR); res = FZ_REPLY_ERROR; break; } wxASSERT(p || !m_pCurOpData); return res; }
int CControlSocket::ParseSubcommandResult(int) { ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; }
int CControlSocket::CheckOverwriteFile() { if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, MessageType::Debug_Info, _T("Empty m_pCurOpData")); ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; } CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData); if (pData->download) { if (!wxFile::Exists(pData->localFile)) return FZ_REPLY_OK; } CDirentry entry; bool dirDidExist; bool matchedCase; CServerPath remotePath; if (pData->tryAbsolutePath || m_CurrentPath.empty()) remotePath = pData->remotePath; else remotePath = m_CurrentPath; bool found = engine_.GetDirectoryCache().LookupFile(entry, *m_pCurrentServer, remotePath, pData->remoteFile, dirDidExist, matchedCase); // Ignore entries with wrong case if (found && !matchedCase) found = false; if (!pData->download) { if (!found && pData->remoteFileSize < 0 && !pData->fileTime.empty()) return FZ_REPLY_OK; } CFileExistsNotification *pNotification = new CFileExistsNotification; pNotification->download = pData->download; pNotification->localFile = pData->localFile; pNotification->remoteFile = pData->remoteFile; pNotification->remotePath = pData->remotePath; pNotification->localSize = pData->localFileSize; pNotification->remoteSize = pData->remoteFileSize; pNotification->ascii = !pData->transferSettings.binary; if (pData->download && pNotification->localSize >= 0) pNotification->canResume = true; else if (!pData->download && pNotification->remoteSize >= 0) pNotification->canResume = true; else pNotification->canResume = false; pNotification->localTime = fz::local_filesys::get_modification_time(fz::to_native(pData->localFile)); if (pData->fileTime.empty()) pNotification->remoteTime = pData->fileTime; if (found) { if (!pData->fileTime.empty()) { if (entry.has_date()) { pNotification->remoteTime = entry.time; pData->fileTime = entry.time; } } } SendAsyncRequest(pNotification); return FZ_REPLY_WOULDBLOCK; }
int CControlSocket::SendNextCommand() { ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; }
int CHttpControlSocket::ParseHeader(CHttpOpData* pData) { // Parse the HTTP header. // We do just the neccessary parsing and silently ignore most header fields // Redirects are supported though if the server sends the Location field. for (;;) { // Find line ending unsigned int i = 0; for (i = 0; (i + 1) < m_recvBufferPos; i++) { if (m_pRecvBuffer[i] == '\r') { if (m_pRecvBuffer[i + 1] != '\n') { LogMessage(::Error, _("Malformed reply, server not sending proper line endings")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } break; } } if ((i + 1) >= m_recvBufferPos) { if (m_recvBufferPos == m_recvBufferLen) { // We don't support header lines larger than 4096 LogMessage(::Error, _("Too long header line")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } return FZ_REPLY_WOULDBLOCK; } m_pRecvBuffer[i] = 0; const wxString& line = wxString(m_pRecvBuffer, wxConvLocal); if (line != _T("")) LogMessageRaw(Response, line); if (pData->m_responseCode == -1) { pData->m_responseString = line; if (m_recvBufferPos < 16 || memcmp(m_pRecvBuffer, "HTTP/1.", 7)) { // Invalid HTTP Status-Line LogMessage(::Error, _("Invalid HTTP Response")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } if (m_pRecvBuffer[9] < '1' || m_pRecvBuffer[9] > '5' || m_pRecvBuffer[10] < '0' || m_pRecvBuffer[10] > '9' || m_pRecvBuffer[11] < '0' || m_pRecvBuffer[11] > '9') { // Invalid response code LogMessage(::Error, _("Invalid response code")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } pData->m_responseCode = (m_pRecvBuffer[9] - '0') * 100 + (m_pRecvBuffer[10] - '0') * 10 + m_pRecvBuffer[11] - '0'; if (pData->m_responseCode >= 400) { // Failed request ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } if (pData->m_responseCode == 305) { // Unsupported redirect LogMessage(::Error, _("Unsupported redirect")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } } else { if (!i) { // End of header, data from now on // Redirect if neccessary if (pData->m_responseCode >= 300) { if (pData->m_redirectionCount++ == 5) { LogMessage(::Error, _("Too many redirects")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } ResetSocket(); ResetHttpData(pData); wxString host; enum ServerProtocol protocol; int pos; if ((pos = pData->m_newLocation.Find(_T("://"))) != -1) { protocol = CServer::GetProtocolFromPrefix(pData->m_newLocation.Left(pos)); host = pData->m_newLocation.Mid(pos + 3); } else { protocol = HTTP; host = pData->m_newLocation; } if ((pos = host.Find(_T("/"))) != -1) host = host.Left(pos); unsigned long port; if ((pos = host.Find(':', true)) != -1) { wxString strport = host.Mid(pos + 1); if (!strport.ToULong(&port) || port < 1 || port > 65535) { if (protocol == HTTPS) port = 443; else port = 80; } host = host.Left(pos); } else { if (protocol == HTTPS) port = 443; else port = 80; } if (host == _T("")) { // Unsupported redirect LogMessage(::Error, _("Redirection to invalid address")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } pData->m_newHostWithPort = wxString::Format(_T("%s:%d"), host.c_str(), (int)port); // International domain names host = ConvertDomainName(host); int res = InternalConnect(host, port, protocol == HTTPS); if (res == FZ_REPLY_WOULDBLOCK) res |= FZ_REPLY_REDIRECTED; return res; } pData->m_gotHeader = true; memmove(m_pRecvBuffer, m_pRecvBuffer + 2, m_recvBufferPos - 2); m_recvBufferPos -= 2; if (m_recvBufferPos) { int res; if (pData->m_transferEncoding == pData->chunked) res = OnChunkedData(pData); else { pData->m_receivedData += m_recvBufferPos; res = ProcessData(m_pRecvBuffer, m_recvBufferPos); m_recvBufferPos = 0; } return res; } return FZ_REPLY_WOULDBLOCK; } if (m_recvBufferPos > 12 && !memcmp(m_pRecvBuffer, "Location: ", 10)) { pData->m_newLocation = wxString(m_pRecvBuffer + 10, wxConvLocal); } else if (m_recvBufferPos > 21 && !memcmp(m_pRecvBuffer, "Transfer-Encoding: ", 19)) { if (!strcmp(m_pRecvBuffer + 19, "chunked")) pData->m_transferEncoding = CHttpOpData::chunked; else if (!strcmp(m_pRecvBuffer + 19, "identity")) pData->m_transferEncoding = CHttpOpData::identity; else pData->m_transferEncoding = CHttpOpData::unknown; } else if (i > 16 && !memcmp(m_pRecvBuffer, "Content-Length: ", 16)) { pData->m_totalSize = 0; char* p = m_pRecvBuffer + 16; while (*p) { if (*p < '0' || *p > '9') { LogMessage(::Error, _("Malformed header: %s"), _("Invalid Content-Length")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } pData->m_totalSize = pData->m_totalSize * 10 + *p++ - '0'; } } } memmove(m_pRecvBuffer, m_pRecvBuffer + i + 2, m_recvBufferPos - i - 2); m_recvBufferPos -= i + 2; if (!m_recvBufferPos) break; } return FZ_REPLY_WOULDBLOCK; }
int CHttpControlSocket::DoReceive() { do { const enum CSocket::SocketState state = m_pSocket->GetState(); if (state != CSocket::connected && state != CSocket::closing) return 0; if (!m_pRecvBuffer) { m_pRecvBuffer = new char[m_recvBufferLen]; m_recvBufferPos = 0; } unsigned int len = m_recvBufferLen - m_recvBufferPos; int error; int read = m_pBackend->Read(m_pRecvBuffer + m_recvBufferPos, len, error); if (read == -1) { if (error != EAGAIN) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); } return 0; } m_pEngine->SetActive(CFileZillaEngine::recv); if (!m_pCurOpData || m_pCurOpData->opId == cmd_connect) { // Just ignore all further data m_recvBufferPos = 0; return 0; } m_recvBufferPos += read; if (!m_pHttpOpData->m_gotHeader) { if (!read) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return 0; } int res = ParseHeader(m_pHttpOpData); if ((res & FZ_REPLY_REDIRECTED) == FZ_REPLY_REDIRECTED) return FZ_REPLY_REDIRECTED; if (res != FZ_REPLY_WOULDBLOCK) return 0; } else if (m_pHttpOpData->m_transferEncoding == CHttpOpData::chunked) { if (!read) { ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED); return 0; } OnChunkedData(m_pHttpOpData); } else { if (!read) { wxASSERT(!m_recvBufferPos); ProcessData(0, 0); return 0; } else { m_pHttpOpData->m_receivedData += m_recvBufferPos; ProcessData(m_pRecvBuffer, m_recvBufferPos); m_recvBufferPos = 0; } } } while (m_pSocket); return 0; }
bool CControlSocket::SetFileExistsAction(CFileExistsNotification *pFileExistsNotification) { wxASSERT(pFileExistsNotification); if (!m_pCurOpData || m_pCurOpData->opId != Command::transfer) { LogMessage(__TFILE__, __LINE__, this, MessageType::Debug_Info, _T("No or invalid operation in progress, ignoring request reply %f"), pFileExistsNotification->GetRequestID()); return false; } CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData); switch (pFileExistsNotification->overwriteAction) { case CFileExistsNotification::overwrite: SendNextCommand(); break; case CFileExistsNotification::overwriteNewer: if (!pFileExistsNotification->localTime.empty() || !pFileExistsNotification->remoteTime.empty()) SendNextCommand(); else if (pFileExistsNotification->download && pFileExistsNotification->localTime.earlier_than(pFileExistsNotification->remoteTime)) SendNextCommand(); else if (!pFileExistsNotification->download && pFileExistsNotification->localTime.later_than(pFileExistsNotification->remoteTime)) SendNextCommand(); else { if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(MessageType::Status, _("Skipping download of %s"), filename); } else { LogMessage(MessageType::Status, _("Skipping upload of %s"), pData->localFile); } ResetOperation(FZ_REPLY_OK); } break; case CFileExistsNotification::overwriteSize: /* First compare flags both size known but different, one size known and the other not (obviously they are different). Second compare flags the remaining case in which we need to send command : both size unknown */ if ((pFileExistsNotification->localSize != pFileExistsNotification->remoteSize) || (pFileExistsNotification->localSize < 0)) SendNextCommand(); else { if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(MessageType::Status, _("Skipping download of %s"), filename); } else { LogMessage(MessageType::Status, _("Skipping upload of %s"), pData->localFile); } ResetOperation(FZ_REPLY_OK); } break; case CFileExistsNotification::overwriteSizeOrNewer: if (!pFileExistsNotification->localTime.empty() || !pFileExistsNotification->remoteTime.empty()) SendNextCommand(); /* First compare flags both size known but different, one size known and the other not (obviously they are different). Second compare flags the remaining case in which we need to send command : both size unknown */ else if ((pFileExistsNotification->localSize != pFileExistsNotification->remoteSize) || (pFileExistsNotification->localSize < 0)) SendNextCommand(); else if (pFileExistsNotification->download && pFileExistsNotification->localTime.earlier_than(pFileExistsNotification->remoteTime)) SendNextCommand(); else if (!pFileExistsNotification->download && pFileExistsNotification->localTime.later_than(pFileExistsNotification->remoteTime)) SendNextCommand(); else { if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(MessageType::Status, _("Skipping download of %s"), filename); } else { LogMessage(MessageType::Status, _("Skipping upload of %s"), pData->localFile); } ResetOperation(FZ_REPLY_OK); } break; case CFileExistsNotification::resume: if (pData->download && pData->localFileSize >= 0) pData->resume = true; else if (!pData->download && pData->remoteFileSize >= 0) pData->resume = true; SendNextCommand(); break; case CFileExistsNotification::rename: if (pData->download) { wxFileName fn = pData->localFile; fn.SetFullName(pFileExistsNotification->newName); pData->localFile = fn.GetFullPath(); int64_t size; bool isLink; if (fz::local_filesys::get_file_info(fz::to_native(pData->localFile), isLink, &size, 0, 0) == fz::local_filesys::file) pData->localFileSize = size; else pData->localFileSize = -1; if (CheckOverwriteFile() == FZ_REPLY_OK) SendNextCommand(); } else { pData->remoteFile = pFileExistsNotification->newName; CDirentry entry; bool dir_did_exist; bool matched_case; if (engine_.GetDirectoryCache().LookupFile(entry, *m_pCurrentServer, pData->tryAbsolutePath ? pData->remotePath : m_CurrentPath, pData->remoteFile, dir_did_exist, matched_case) && matched_case) { pData->remoteFileSize = entry.size; if (entry.has_date()) pData->fileTime = entry.time; if (CheckOverwriteFile() != FZ_REPLY_OK) break; } else { pData->fileTime = fz::datetime(); pData->remoteFileSize = -1; } SendNextCommand(); } break; case CFileExistsNotification::skip: if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(MessageType::Status, _("Skipping download of %s"), filename); } else { LogMessage(MessageType::Status, _("Skipping upload of %s"), pData->localFile); } ResetOperation(FZ_REPLY_OK); break; default: LogMessage(__TFILE__, __LINE__, this, MessageType::Debug_Warning, _T("Unknown file exists action: %d"), pFileExistsNotification->overwriteAction); ResetOperation(FZ_REPLY_INTERNALERROR); return false; } return true; }
int CControlSocket::ResetOperation(int nErrorCode) { LogMessage(MessageType::Debug_Verbose, _T("CControlSocket::ResetOperation(%d)"), nErrorCode); if (nErrorCode & FZ_REPLY_WOULDBLOCK) { LogMessage(MessageType::Debug_Warning, _T("ResetOperation with FZ_REPLY_WOULDBLOCK in nErrorCode (%d)"), nErrorCode); } if (m_pCurOpData && m_pCurOpData->holdsLock) UnlockCache(); if (m_pCurOpData && m_pCurOpData->pNextOpData) { COpData *pNext = m_pCurOpData->pNextOpData; m_pCurOpData->pNextOpData = 0; delete m_pCurOpData; m_pCurOpData = pNext; if (nErrorCode == FZ_REPLY_OK || nErrorCode == FZ_REPLY_ERROR || nErrorCode == FZ_REPLY_CRITICALERROR) { return ParseSubcommandResult(nErrorCode); } else return ResetOperation(nErrorCode); } wxString prefix; if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR && (!m_pCurOpData || m_pCurOpData->opId != Command::transfer)) { prefix = _("Critical error:") + _T(" "); } if (m_pCurOpData) { const Command commandId = m_pCurOpData->opId; switch (commandId) { case Command::none: if( !prefix.empty() ) { LogMessage(MessageType::Error, _("Critical error")); } break; case Command::connect: if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(MessageType::Error, prefix + _("Connection attempt interrupted by user")); else if (nErrorCode != FZ_REPLY_OK) LogMessage(MessageType::Error, prefix + _("Could not connect to server")); break; case Command::list: if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(MessageType::Error, prefix + _("Directory listing aborted by user")); else if (nErrorCode != FZ_REPLY_OK) LogMessage(MessageType::Error, prefix + _("Failed to retrieve directory listing")); else { if (m_CurrentPath.empty()) { LogMessage(MessageType::Status, _("Directory listing successful")); } else { LogMessage(MessageType::Status, _("Directory listing of \"%s\" successful"), m_CurrentPath.GetPath()); } } break; case Command::transfer: { CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData); if (!pData->download && pData->transferInitiated) { if (!m_pCurrentServer) LogMessage(__TFILE__, __LINE__, this, MessageType::Debug_Warning, _T("m_pCurrentServer is 0")); else { bool updated = engine_.GetDirectoryCache().UpdateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1); if (updated) engine_.SendDirectoryListingNotification(pData->remotePath, false, true, false); } } LogTransferResultMessage(nErrorCode, pData); } break; default: if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(MessageType::Error, prefix + _("Interrupted by user")); break; } delete m_pCurOpData; m_pCurOpData = 0; } engine_.transfer_status_.Reset(); SetWait(false); if (m_invalidateCurrentPath) { m_CurrentPath.clear(); m_invalidateCurrentPath = false; } return engine_.ResetOperation(nErrorCode); }
int CHttpControlSocket::OnChunkedData(CHttpOpData* pData) { char* p = m_pRecvBuffer; unsigned int len = m_recvBufferPos; for (;;) { if (pData->m_chunkData.size != 0) { unsigned int dataLen = len; if (pData->m_chunkData.size < len) dataLen = pData->m_chunkData.size.GetLo(); pData->m_receivedData += dataLen; int res = ProcessData(p, dataLen); if (res != FZ_REPLY_WOULDBLOCK) return res; pData->m_chunkData.size -= dataLen; p += dataLen; len -= dataLen; if (pData->m_chunkData.size == 0) pData->m_chunkData.terminateChunk = true; if (!len) break; } // Find line ending unsigned int i = 0; for (i = 0; (i + 1) < len; i++) { if (p[i] == '\r') { if (p[i + 1] != '\n') { LogMessage(::Error, _("Malformed chunk data: %s"), _("Wrong line endings")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } break; } } if ((i + 1) >= len) { if (len == m_recvBufferLen) { // We don't support lines larger than 4096 LogMessage(::Error, _("Malformed chunk data: %s"), _("Line length exceeded")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } break; } p[i] = 0; if (pData->m_chunkData.terminateChunk) { if (i) { // The chunk data has to end with CRLF. If i is nonzero, // it didn't end with just CRLF. LogMessage(::Error, _("Malformed chunk data: %s"), _("Chunk data improperly terminated")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } pData->m_chunkData.terminateChunk = false; } else if (pData->m_chunkData.getTrailer) { if (!i) { // We're done return ProcessData(0, 0); } // Ignore the trailer } else { // Read chunk size char* q = p; while (*q) { if (*q >= '0' && *q <= '9') { pData->m_chunkData.size *= 16; pData->m_chunkData.size += *q - '0'; } else if (*q >= 'A' && *q <= 'F') { pData->m_chunkData.size *= 16; pData->m_chunkData.size += *q - 'A' + 10; } else if (*q >= 'a' && *q <= 'f') { pData->m_chunkData.size *= 16; pData->m_chunkData.size += *q - 'a' + 10; } else if (*q == ';' || *q == ' ') break; else { // Invalid size LogMessage(::Error, _("Malformed chunk data: %s"), _("Invalid chunk size")); ResetOperation(FZ_REPLY_ERROR); return FZ_REPLY_ERROR; } q++; } if (pData->m_chunkData.size == 0) pData->m_chunkData.getTrailer = true; } p += i + 2; len -= i + 2; if (!len) break; } if (p != m_pRecvBuffer) { memmove(m_pRecvBuffer, p, len); m_recvBufferPos = len; } return FZ_REPLY_WOULDBLOCK; }
int CControlSocket::ResetOperation(int nErrorCode) { LogMessage(Debug_Verbose, _T("CControlSocket::ResetOperation(%d)"), nErrorCode); if (nErrorCode & FZ_REPLY_WOULDBLOCK) { LogMessage(::Debug_Warning, _T("ResetOperation with FZ_REPLY_WOULDBLOCK in nErrorCode (%d)"), nErrorCode); } if (m_pCurOpData && m_pCurOpData->opId != cmd_rawtransfer) { UnlockCache(); } if (m_pCurOpData && m_pCurOpData->pNextOpData) { COpData *pNext = m_pCurOpData->pNextOpData; m_pCurOpData->pNextOpData = 0; delete m_pCurOpData; m_pCurOpData = pNext; if (nErrorCode == FZ_REPLY_OK || nErrorCode == FZ_REPLY_ERROR || nErrorCode == FZ_REPLY_CRITICALERROR) { return ParseSubcommandResult(nErrorCode); } else return ResetOperation(nErrorCode); } if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR) LogMessage(::Error, _("Critical error")); if (m_pCurOpData) { const enum Command commandId = m_pCurOpData->opId; switch (commandId) { case cmd_none: break; case cmd_connect: if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(::Error, _("Connection attempt interrupted by user")); else if (nErrorCode != FZ_REPLY_OK) LogMessage(::Error, _("Could not connect to server")); break; case cmd_list: if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(::Error, _("Directory listing aborted by user")); else if (nErrorCode != FZ_REPLY_OK) LogMessage(::Error, _("Failed to retrieve directory listing")); else LogMessage(Status, _("Directory listing successful")); break; case cmd_transfer: { CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData); if (!pData->download && pData->transferInitiated) { if (!m_pCurrentServer) LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("m_pCurrentServer is 0")); else { CDirectoryCache cache; bool updated = cache.UpdateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1); if (updated) m_pEngine->SendDirectoryListingNotification(pData->remotePath, false, true, false); } } if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(::Error, _("Transfer aborted by user")); else if (nErrorCode == FZ_REPLY_OK) LogMessage(Status, _("File transfer successful")); } break; default: if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED) LogMessage(::Error, _("Interrupted by user")); break; } delete m_pCurOpData; m_pCurOpData = 0; } ResetTransferStatus(); SetWait(false); if (m_invalidateCurrentPath) { m_CurrentPath.Clear(); m_invalidateCurrentPath = false; } return m_pEngine->ResetOperation(nErrorCode); }
int CControlSocket::CheckOverwriteFile() { if (!m_pCurOpData) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData")); ResetOperation(FZ_REPLY_INTERNALERROR); return FZ_REPLY_ERROR; } CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData); if (pData->download) { if (!wxFile::Exists(pData->localFile)) return FZ_REPLY_OK; } CDirentry entry; bool dirDidExist; bool matchedCase; CDirectoryCache cache; CServerPath remotePath; if (pData->tryAbsolutePath || m_CurrentPath.IsEmpty()) remotePath = pData->remotePath; else remotePath = m_CurrentPath; bool found = cache.LookupFile(entry, *m_pCurrentServer, remotePath, pData->remoteFile, dirDidExist, matchedCase); // Ignore entries with wrong case if (found && !matchedCase) found = false; if (!pData->download) { if (!found && pData->remoteFileSize == -1 && !pData->fileTime.IsValid()) return FZ_REPLY_OK; } CFileExistsNotification *pNotification = new CFileExistsNotification; pNotification->download = pData->download; pNotification->localFile = pData->localFile; pNotification->remoteFile = pData->remoteFile; pNotification->remotePath = pData->remotePath; pNotification->localSize = pData->localFileSize; pNotification->remoteSize = pData->remoteFileSize; pNotification->ascii = !pData->transferSettings.binary; wxStructStat buf; int result; result = wxStat(pData->localFile, &buf); if (!result) { pNotification->localTime = wxDateTime(buf.st_mtime); if (!pNotification->localTime.IsValid()) pNotification->localTime = wxDateTime(buf.st_ctime); } if (pData->fileTime.IsValid()) pNotification->remoteTime = pData->fileTime; if (found) { if (!pData->fileTime.IsValid()) { if (entry.hasDate) { pNotification->remoteTime = entry.time; pData->fileTime = entry.time; } } } pNotification->requestNumber = m_pEngine->GetNextAsyncRequestNumber(); pData->waitForAsyncRequest = true; m_pEngine->AddNotification(pNotification); return FZ_REPLY_WOULDBLOCK; }
int CFileZillaEngine::Command(const CCommand &command) { if (command.GetId() != cmd_cancel && IsBusy()) return FZ_REPLY_BUSY; m_bIsInCommand = true; int res = FZ_REPLY_INTERNALERROR; printf("command id: %d\n", command.GetId()); switch (command.GetId()) { case cmd_connect: res = Connect(reinterpret_cast<const CConnectCommand &>(command)); break; case cmd_disconnect: res = Disconnect(reinterpret_cast<const CDisconnectCommand &>(command)); break; case cmd_cancel: res = Cancel(reinterpret_cast<const CCancelCommand &>(command)); break; case cmd_list: res = List(reinterpret_cast<const CListCommand &>(command)); break; case cmd_transfer: res = FileTransfer(reinterpret_cast<const CFileTransferCommand &>(command)); break; case cmd_raw: res = RawCommand(reinterpret_cast<const CRawCommand&>(command)); break; case cmd_delete: res = Delete(reinterpret_cast<const CDeleteCommand&>(command)); break; case cmd_removedir: res = RemoveDir(reinterpret_cast<const CRemoveDirCommand&>(command)); break; case cmd_mkdir: res = Mkdir(reinterpret_cast<const CMkdirCommand&>(command)); break; case cmd_rename: res = Rename(reinterpret_cast<const CRenameCommand&>(command)); break; case cmd_chmod: res = Chmod(reinterpret_cast<const CChmodCommand&>(command)); break; case cmd_checksum: printf("recognized the checksum command\n"); res = Checksum(reinterpret_cast<const CChecksumCommand&>(command)); break; default: return FZ_REPLY_SYNTAXERROR; } if (res != FZ_REPLY_WOULDBLOCK) ResetOperation(res); m_bIsInCommand = false; if (command.GetId() != cmd_disconnect) res |= m_nControlSocketError; else if (res & FZ_REPLY_DISCONNECTED) res = FZ_REPLY_OK; m_nControlSocketError = 0; return res; }
bool CControlSocket::SetFileExistsAction(CFileExistsNotification *pFileExistsNotification) { wxASSERT(pFileExistsNotification); if (!m_pCurOpData || m_pCurOpData->opId != cmd_transfer) { LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("No or invalid operation in progress, ignoring request reply %f"), pFileExistsNotification->GetRequestID()); return false; } CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData); switch (pFileExistsNotification->overwriteAction) { case CFileExistsNotification::overwrite: SendNextCommand(); break; case CFileExistsNotification::overwriteNewer: if (!pFileExistsNotification->localTime.IsValid() || !pFileExistsNotification->remoteTime.IsValid()) SendNextCommand(); else if (pFileExistsNotification->download && pFileExistsNotification->localTime.IsEarlierThan(pFileExistsNotification->remoteTime)) SendNextCommand(); else if (!pFileExistsNotification->download && pFileExistsNotification->localTime.IsLaterThan(pFileExistsNotification->remoteTime)) SendNextCommand(); else { if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(Status, _("Skipping download of %s"), filename.c_str()); } else { LogMessage(Status, _("Skipping upload of %s"), pData->localFile.c_str()); } ResetOperation(FZ_REPLY_OK); } break; case CFileExistsNotification::overwriteSize: /* First compare flags both size known but different, one size known and the other not (obviously they are different). Second compare flags the remaining case in which we need to send command : both size unknown */ if ((pFileExistsNotification->localSize != pFileExistsNotification->remoteSize) || (pFileExistsNotification->localSize == -1)) SendNextCommand(); else { if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(Status, _("Skipping download of %s"), filename.c_str()); } else { LogMessage(Status, _("Skipping upload of %s"), pData->localFile.c_str()); } ResetOperation(FZ_REPLY_OK); } break; case CFileExistsNotification::overwriteSizeOrNewer: if (!pFileExistsNotification->localTime.IsValid() || !pFileExistsNotification->remoteTime.IsValid()) SendNextCommand(); /* First compare flags both size known but different, one size known and the other not (obviously they are different). Second compare flags the remaining case in which we need to send command : both size unknown */ else if ((pFileExistsNotification->localSize != pFileExistsNotification->remoteSize) || (pFileExistsNotification->localSize == -1)) SendNextCommand(); else if (pFileExistsNotification->download && pFileExistsNotification->localTime.IsEarlierThan(pFileExistsNotification->remoteTime)) SendNextCommand(); else if (!pFileExistsNotification->download && pFileExistsNotification->localTime.IsLaterThan(pFileExistsNotification->remoteTime)) SendNextCommand(); else { if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(Status, _("Skipping download of %s"), filename.c_str()); } else { LogMessage(Status, _("Skipping upload of %s"), pData->localFile.c_str()); } ResetOperation(FZ_REPLY_OK); } break; case CFileExistsNotification::resume: if (pData->download && pData->localFileSize != -1) pData->resume = true; else if (!pData->download && pData->remoteFileSize != -1) pData->resume = true; SendNextCommand(); break; case CFileExistsNotification::rename: if (pData->download) { wxFileName fn = pData->localFile; fn.SetFullName(pFileExistsNotification->newName); pData->localFile = fn.GetFullPath(); wxLongLong size; bool isLink; if (CLocalFileSystem::GetFileInfo(pData->localFile, isLink, &size, 0, 0) == CLocalFileSystem::file) pData->localFileSize = size.GetValue(); else pData->localFileSize = -1; if (CheckOverwriteFile() == FZ_REPLY_OK) SendNextCommand(); } else { pData->remoteFile = pFileExistsNotification->newName; CDirectoryCache cache; CDirentry entry; bool dir_did_exist; bool matched_case; if (cache.LookupFile(entry, *m_pCurrentServer, pData->tryAbsolutePath ? pData->remotePath : m_CurrentPath, pData->remoteFile, dir_did_exist, matched_case) && matched_case) { wxLongLong size = entry.size; pData->remoteFileSize = size.GetLo() + ((wxFileOffset)size.GetHi() << 32); if (CheckOverwriteFile() != FZ_REPLY_OK) break; } SendNextCommand(); } break; case CFileExistsNotification::skip: if (pData->download) { wxString filename = pData->remotePath.FormatFilename(pData->remoteFile); LogMessage(Status, _("Skipping download of %s"), filename.c_str()); } else { LogMessage(Status, _("Skipping upload of %s"), pData->localFile.c_str()); } ResetOperation(FZ_REPLY_OK); break; default: LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Unknown file exists action: %d"), pFileExistsNotification->overwriteAction); ResetOperation(FZ_REPLY_INTERNALERROR); return false; } return true; }