#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<CStateEventHandler*>::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<CStateEventHandler*>::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<CStateEventHandler*>::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<CStateEventHandler*>::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<wxString> 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<CRemoteDataObject::t_fileInfo>& files = pRemoteDataObject->GetFiles();
for (std::list<CRemoteDataObject::t_fileInfo>::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;
}
syntax highlighted by Code2HTML, v. 0.9.1