#include "FileZilla.h" #include "state.h" #include "commandqueue.h" #include "FileZillaEngine.h" #include "Options.h" #include "Mainfrm.h" #include "queue.h" #include "filezillaapp.h" #include "RemoteListView.h" #include "recursive_operation.h" CState::CState(CMainFrame* pMainFrame) { m_pMainFrame = pMainFrame; m_pDirectoryListing = 0; m_pServer = 0; m_pEngine = 0; m_pCommandQueue = 0; m_pRecursiveOperation = new CRecursiveOperation(this); } CState::~CState() { delete m_pDirectoryListing; delete m_pServer; delete m_pCommandQueue; delete m_pEngine; // Unregister all handlers for (std::list::iterator iter = m_handlers.begin(); iter != m_handlers.end(); iter++) (*iter)->m_pState = 0; delete m_pRecursiveOperation; } wxString CState::GetLocalDir() const { return m_localDir; } wxString CState::Canonicalize(wxString oldDir, wxString newDir, wxString *error /*=0*/) { #ifdef __WXMSW__ if (newDir == _T("\\") || newDir == _T("/") || newDir == _T("")) return _T("\\"); // "Go up one level" is a little bit difficult under Windows due to // things like "My Computer" and "Desktop" if (newDir == _T("..")) { newDir = oldDir; if (newDir != _T("\\")) { newDir.RemoveLast(); int pos = newDir.Find('\\', true); if (pos == -1) return _T("\\"); else newDir = newDir.Left(pos + 1); } } else #endif { wxFileName dir(newDir, _T("")); { wxLogNull noLog; if (!dir.MakeAbsolute(oldDir)) return _T(""); } newDir = dir.GetFullPath(); if (newDir.Right(1) != wxFileName::GetPathSeparator()) newDir += wxFileName::GetPathSeparator(); } // Check for partial UNC paths if (newDir.Left(2) == _T("\\\\")) { int pos = newDir.Mid(2).Find('\\'); if (pos == -1 || pos + 3 == (int)newDir.Len()) { // Partial UNC path, no share given return newDir; } pos = newDir.Mid(pos + 3).Find('\\'); if (pos == -1) { // Partial UNC path, no full share yet, skip further processing return _T(""); } } if (!wxDir::Exists(newDir)) { if (!error) return _T(""); *error = wxString::Format(_("'%s' does not exist or cannot be accessed."), newDir.c_str()); #ifdef __WXMSW__ if (newDir[0] == '\\') return _T(""); // Check for removable drive, display a more specific error message in that case if (::GetLastError() != ERROR_NOT_READY) return _T(""); int type = GetDriveType(newDir.Left(3)); if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM) *error = wxString::Format(_("Cannot access '%s', no media inserted or drive not ready."), newDir.c_str()); #endif return _T(""); } return newDir; } bool CState::SetLocalDir(wxString dir, wxString *error /*=0*/) { dir = Canonicalize(m_localDir, dir, error); if (dir == _T("")) return false; m_localDir = dir; COptions::Get()->SetOption(OPTION_LASTLOCALDIR, dir); NotifyHandlers(STATECHANGE_LOCAL_DIR); return true; } bool CState::SetRemoteDir(const CDirectoryListing *pDirectoryListing, bool modified /*=false*/) { if (!pDirectoryListing) { if (modified) return false; if (m_pDirectoryListing) { const CDirectoryListing* pOldListing = m_pDirectoryListing; m_pDirectoryListing = 0; NotifyHandlers(STATECHANGE_REMOTE_DIR); delete pOldListing; } return true; } if (modified) { if (!m_pDirectoryListing || m_pDirectoryListing->path != pDirectoryListing->path) { // We aren't interested in these listings delete pDirectoryListing; return true; } } else COptions::Get()->SetOption(OPTION_LASTSERVERPATH, pDirectoryListing->path.GetSafePath()); if (m_pDirectoryListing && m_pDirectoryListing->path == pDirectoryListing->path && pDirectoryListing->m_failed) { // We still got an old listing, no need to display the new one delete pDirectoryListing; return true; } const CDirectoryListing *pOldListing = m_pDirectoryListing; m_pDirectoryListing = pDirectoryListing; if (!modified) NotifyHandlers(STATECHANGE_REMOTE_DIR); else NotifyHandlers(STATECHANGE_REMOTE_DIR_MODIFIED); delete pOldListing; return true; } const CDirectoryListing *CState::GetRemoteDir() const { return m_pDirectoryListing; } const CServerPath CState::GetRemotePath() const { if (!m_pDirectoryListing) return CServerPath(); return m_pDirectoryListing->path; } void CState::RefreshLocal() { NotifyHandlers(STATECHANGE_LOCAL_DIR); } void CState::RefreshLocalFile(wxString file) { wxFileName fn(file); if (!fn.IsOk()) return; if (!fn.IsAbsolute()) return; wxString path = fn.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); if (path == _T("")) return; if (path == m_localDir) { file = fn.GetFullName(); if (file == _T("")) return; } else if (path.Left(m_localDir.Len()) == m_localDir) { path = path.Mid(m_localDir.Len()); int pos = path.Find(wxFileName::GetPathSeparator()); if (pos < 1) return; file = path.Left(pos); } NotifyHandlers(STATECHANGE_LOCAL_REFRESH_FILE, file); } void CState::SetServer(const CServer* server) { if (m_pServer) { SetRemoteDir(0); delete m_pServer; } if (server) m_pServer = new CServer(*server); else m_pServer = 0; } const CServer* CState::GetServer() const { return m_pServer; } void CState::ApplyCurrentFilter() { NotifyHandlers(STATECHANGE_APPLYFILTER); } bool CState::Connect(const CServer& server, bool askBreak, const CServerPath& path /*=CServerPath()*/) { if (!m_pEngine) return false; if (m_pEngine->IsConnected() || m_pEngine->IsBusy() || !m_pCommandQueue->Idle()) { if (askBreak) if (wxMessageBox(_("Break current connection?"), _T("FileZilla"), wxYES_NO | wxICON_QUESTION) != wxYES) return false; m_pCommandQueue->Cancel(); } m_pCommandQueue->ProcessCommand(new CConnectCommand(server)); m_pCommandQueue->ProcessCommand(new CListCommand(path)); COptions::Get()->SetLastServer(server); COptions::Get()->SetOption(OPTION_LASTSERVERPATH, path.GetSafePath()); return true; } bool CState::CreateEngine() { wxASSERT(!m_pEngine); if (m_pEngine) return true; m_pEngine = new CFileZillaEngine(); m_pEngine->Init(m_pMainFrame, COptions::Get()); m_pCommandQueue = new CCommandQueue(m_pEngine, m_pMainFrame); return true; } void CState::DestroyEngine() { delete m_pCommandQueue; m_pCommandQueue = 0; delete m_pEngine; m_pEngine = 0; } void CState::RegisterHandler(CStateEventHandler* pHandler) { wxASSERT(pHandler); std::list::const_iterator iter; for (iter = m_handlers.begin(); iter != m_handlers.end(); iter++) if (*iter == pHandler) break; if (iter != m_handlers.end()) return; m_handlers.push_back(pHandler); } void CState::UnregisterHandler(CStateEventHandler* pHandler) { for (std::list::iterator iter = m_handlers.begin(); iter != m_handlers.end(); iter++) { if (*iter == pHandler) { m_handlers.erase(iter); return; } } } void CState::NotifyHandlers(unsigned int event, const wxString& data /*=_T("")*/) { for (std::list::iterator iter = m_handlers.begin(); iter != m_handlers.end(); iter++) { if ((*iter)->m_eventMask & event) (*iter)->OnStateChange(event, data); } } CStateEventHandler::CStateEventHandler(CState* pState, unsigned int eventMask) { wxASSERT(pState); wxASSERT(eventMask); if (!pState) return; m_pState = pState; m_eventMask = eventMask; m_pState->RegisterHandler(this); } CStateEventHandler::~CStateEventHandler() { if (!m_pState) return; m_pState->UnregisterHandler(this); } void CState::UploadDroppedFiles(const wxFileDataObject* pFileDataObject, const wxString& subdir, bool queueOnly) { if (!m_pServer || !m_pDirectoryListing) return; CServerPath path = m_pDirectoryListing->path; if (subdir == _T("..") && path.HasParent()) path = path.GetParent(); else if (subdir != _T("")) path.AddSegment(subdir); UploadDroppedFiles(pFileDataObject, path, queueOnly); } void CState::UploadDroppedFiles(const wxFileDataObject* pFileDataObject, const CServerPath& path, bool queueOnly) { if (!m_pServer) return; const wxArrayString& files = pFileDataObject->GetFilenames(); for (unsigned int i = 0; i < files.Count(); i++) { if (wxFile::Exists(files[i])) { const wxFileName name(files[i]); const wxLongLong size = name.GetSize().GetValue(); m_pMainFrame->GetQueue()->QueueFile(queueOnly, false, files[i], name.GetFullName(), path, *m_pServer, size); } else if (wxDir::Exists(files[i])) { wxString name = files[i]; int pos = name.Find(wxFileName::GetPathSeparator(), true); if (pos != -1) { name = name.Mid(pos + 1); CServerPath target = path; target.AddSegment(name); m_pMainFrame->GetQueue()->QueueFolder(queueOnly, false, files[i], target, *m_pServer); } } } } void CState::HandleDroppedFiles(const wxFileDataObject* pFileDataObject, wxString path, bool copy) { if (path.Last() != wxFileName::GetPathSeparator()) path += wxFileName::GetPathSeparator(); const wxArrayString &files = pFileDataObject->GetFilenames(); if (!files.Count()) return; #ifdef __WXMSW__ int len = 1; for (unsigned int i = 0; i < files.Count(); i++) len += files[i].Len() + 1; wxChar* from = new wxChar[len]; wxChar* p = from; for (unsigned int i = 0; i < files.Count(); i++) { wxStrcpy(p, files[i]); p += files[i].Len() + 1; } *p = 0; wxChar* to = new wxChar[path.Len() + 2]; wxStrcpy(to, path); to[path.Len() + 1] = 0; SHFILEOPSTRUCT op = {0}; op.pFrom = from; op.pTo = to; op.wFunc = copy ? FO_COPY : FO_MOVE; op.hwnd = (HWND)m_pMainFrame->GetHandle(); SHFileOperation(&op); delete [] to; delete [] from; #else for (unsigned int i = 0; i < files.Count(); i++) { const wxString& file = files[i]; if (wxFile::Exists(file)) { int pos = file.Find(wxFileName::GetPathSeparator(), true); if (pos == -1 || pos == (int)file.Len() - 1) continue; const wxString& name = file.Mid(pos + 1); if (copy) wxCopyFile(file, path + name); else wxRenameFile(file, path + name); } else if (wxDir::Exists(file)) { if (copy) RecursiveCopy(file, path); else { int pos = file.Find(wxFileName::GetPathSeparator(), true); if (pos == -1 || pos == (int)file.Len() - 1) continue; const wxString& name = file.Mid(pos + 1); wxRenameFile(file, path + name); } } } #endif RefreshLocal(); } bool CState::RecursiveCopy(wxString source, wxString target) { if (source == _T("")) return false; if (target == _T("")) return false; if (target.Last() != wxFileName::GetPathSeparator()) target += wxFileName::GetPathSeparator(); if (source.Last() == wxFileName::GetPathSeparator()) source.RemoveLast(); if (source + wxFileName::GetPathSeparator() == target) return false; if (target.Len() > source.Len() && source == target.Left(source.Len()) && target[source.Len()] == wxFileName::GetPathSeparator()) return false; int pos = source.Find(wxFileName::GetPathSeparator(), true); if (pos == -1 || pos == (int)source.Len() - 1) return false; std::list dirsToVisit; dirsToVisit.push_back(source.Mid(pos + 1) + wxFileName::GetPathSeparator()); source = source.Left(pos + 1); // Process any subdirs which still have to be visited while (!dirsToVisit.empty()) { wxString dirname = dirsToVisit.front(); dirsToVisit.pop_front(); wxMkdir(target + dirname); wxDir dir; if (!dir.Open(source + dirname)) continue; wxString file; for (bool found = dir.GetFirst(&file); found; found = dir.GetNext(&file)) { if (file == _T("")) { wxGetApp().DisplayEncodingWarning(); continue; } if (wxFileName::DirExists(source + dirname + file)) { const wxString subDir = dirname + file + wxFileName::GetPathSeparator(); dirsToVisit.push_back(subDir); } else wxCopyFile(source + dirname + file, target + dirname + file); } } return true; } bool CState::DownloadDroppedFiles(const CRemoteDataObject* pRemoteDataObject, wxString path, bool queueOnly /*=false*/) { bool hasDirs = false; bool hasFiles = false; const std::list& files = pRemoteDataObject->GetFiles(); for (std::list::const_iterator iter = files.begin(); iter != files.end(); iter++) { if (iter->dir) hasDirs = true; else hasFiles = true; } if (hasDirs) { if (!m_pEngine->IsConnected() || m_pEngine->IsBusy() || !m_pCommandQueue->Idle()) return false; } if (hasFiles) m_pMainFrame->GetQueue()->QueueFiles(queueOnly, path, *pRemoteDataObject); if (!hasDirs) return true; return m_pMainFrame->GetRemoteListView()->DownloadDroppedFiles(pRemoteDataObject, path, queueOnly); } bool CState::IsRemoteConnected() const { if (!m_pEngine) return false; return m_pEngine->IsConnected(); } bool CState::IsRemoteIdle() const { if (m_pRecursiveOperation->GetOperationMode() != CRecursiveOperation::recursive_none) return false; if (!m_pCommandQueue) return true; return m_pCommandQueue->Idle(); } bool CState::LocalDirHasParent(const wxString& dir) { #ifdef __WXMSW__ if (dir.Left(2) == _T("\\\\")) { int pos = dir.Mid(2).Find('\\'); if (pos == -1 || pos + 3 == (int)dir.Len()) return false; } if (dir == _T("\\")) return false; #endif if (dir == _T("/")) return false; return true; } bool CState::LocalDirIsWriteable(const wxString& dir) { #ifdef __WXMSW__ if (dir == _T("\\")) return false; if (dir.Left(2) == _T("\\\\")) { int pos = dir.Mid(2).Find('\\'); if (pos == -1 || pos + 3 == (int)dir.Len()) return false; } #endif return true; }