source: filezilla/trunk/fuentes/src/interface/state.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 29.7 KB
Line 
1#include <filezilla.h>
2#include "state.h"
3#include "commandqueue.h"
4#include "FileZillaEngine.h"
5#include "Options.h"
6#include "Mainfrm.h"
7#include "queue.h"
8#include "filezillaapp.h"
9#include "recursive_operation.h"
10#include "local_filesys.h"
11#include "listingcomparison.h"
12#include "xrc_helper.h"
13
14CContextManager CContextManager::m_the_context_manager;
15
16CContextManager::CContextManager()
17{
18        m_current_context = -1;
19}
20
21CContextManager* CContextManager::Get()
22{
23        return &m_the_context_manager;
24}
25
26CState* CContextManager::CreateState(CMainFrame &mainFrame)
27{
28        CState* pState = new CState(mainFrame);
29
30        m_contexts.push_back(pState);
31
32        NotifyHandlers(pState, STATECHANGE_NEWCONTEXT, _T(""), 0);
33
34        return pState;
35}
36
37void CContextManager::DestroyState(CState* pState)
38{
39        for (unsigned int i = 0; i < m_contexts.size(); ++i) {
40                if (m_contexts[i] != pState)
41                        continue;
42
43                m_contexts.erase(m_contexts.begin() + i);
44                if ((int)i < m_current_context)
45                        m_current_context--;
46                else if ((int)i == m_current_context)
47                {
48                        if (i >= m_contexts.size())
49                                m_current_context--;
50                        NotifyHandlers(GetCurrentContext(), STATECHANGE_CHANGEDCONTEXT, _T(""), 0);
51                }
52
53                break;
54        }
55
56        NotifyHandlers(pState, STATECHANGE_REMOVECONTEXT, _T(""), 0);
57        delete pState;
58}
59
60void CContextManager::SetCurrentContext(CState* pState)
61{
62        if (GetCurrentContext() == pState)
63                return;
64
65        for (unsigned int i = 0; i < m_contexts.size(); i++)
66        {
67                if (m_contexts[i] != pState)
68                        continue;
69
70                m_current_context = i;
71                NotifyHandlers(GetCurrentContext(), STATECHANGE_CHANGEDCONTEXT, _T(""), 0);
72        }
73}
74
75void CContextManager::DestroyAllStates()
76{
77        m_current_context = -1;
78        NotifyHandlers(GetCurrentContext(), STATECHANGE_CHANGEDCONTEXT, _T(""), 0);
79
80        while (!m_contexts.empty())
81        {
82                CState* pState = m_contexts.back();
83                m_contexts.pop_back();
84
85                NotifyHandlers(pState, STATECHANGE_REMOVECONTEXT, _T(""), 0);
86                delete pState;
87        }
88}
89
90void CContextManager::RegisterHandler(CStateEventHandler* pHandler, enum t_statechange_notifications notification, bool current_only)
91{
92        wxASSERT(pHandler);
93        wxASSERT(notification != STATECHANGE_MAX && notification != STATECHANGE_NONE);
94
95        auto &handlers = m_handlers[notification];
96        for (auto const& it : handlers) {
97                if (it.pHandler == pHandler) {
98                        return;
99                }
100        }
101
102        t_handler handler;
103        handler.pHandler = pHandler;
104        handler.current_only = current_only;
105        handlers.push_back(handler);
106}
107
108void CContextManager::UnregisterHandler(CStateEventHandler* pHandler, enum t_statechange_notifications notification)
109{
110        wxASSERT(pHandler);
111        wxASSERT(notification != STATECHANGE_MAX);
112
113        if (notification == STATECHANGE_NONE) {
114                for (int i = 0; i < STATECHANGE_MAX; ++i) {
115                        auto &handlers = m_handlers[i];
116                        for (auto iter = handlers.begin(); iter != handlers.end(); ++iter) {
117                                if (iter->pHandler == pHandler) {
118                                        handlers.erase(iter);
119                                        break;
120                                }
121                        }
122                }
123        }
124        else {
125                auto &handlers = m_handlers[notification];
126                for (auto iter = handlers.begin(); iter != handlers.end(); ++iter) {
127                        if (iter->pHandler == pHandler) {
128                                handlers.erase(iter);
129                                return;
130                        }
131                }
132        }
133}
134
135size_t CContextManager::HandlerCount(t_statechange_notifications notification) const
136{
137        wxASSERT(notification != STATECHANGE_NONE && notification != STATECHANGE_MAX);
138        return m_handlers[notification].size();
139}
140
141void CContextManager::NotifyHandlers(CState* pState, t_statechange_notifications notification, const wxString& data, const void* data2)
142{
143        wxASSERT(notification != STATECHANGE_NONE && notification != STATECHANGE_MAX);
144
145        auto const& handlers = m_handlers[notification];
146        for (auto const& handler : handlers) {
147                if (handler.current_only && pState != GetCurrentContext())
148                        continue;
149
150                handler.pHandler->OnStateChange(pState, notification, data, data2);
151        }
152}
153
154CState* CContextManager::GetCurrentContext()
155{
156        if (m_current_context == -1)
157                return 0;
158
159        return m_contexts[m_current_context];
160}
161
162void CContextManager::NotifyAllHandlers(enum t_statechange_notifications notification, const wxString& data /*=_T("")*/, const void* data2 /*=0*/)
163{
164        for (unsigned int i = 0; i < m_contexts.size(); i++)
165                m_contexts[i]->NotifyHandlers(notification, data, data2);
166}
167
168void CContextManager::NotifyGlobalHandlers(enum t_statechange_notifications notification, const wxString& data /*=_T("")*/, const void* data2 /*=0*/)
169{
170        auto const& handlers = m_handlers[notification];
171        for (auto const& handler : handlers) {
172                handler.pHandler->OnStateChange(0, notification, data, data2);
173        }
174}
175
176CState::CState(CMainFrame &mainFrame)
177        : m_mainFrame(mainFrame)
178{
179        m_title = _("Not connected");
180
181        m_pComparisonManager = new CComparisonManager(this);
182
183        m_pRecursiveOperation = new CRecursiveOperation(this);
184
185        m_sync_browse.is_changing = false;
186        m_sync_browse.compare = false;
187
188        m_localDir.SetPath(CLocalPath::path_separator);
189}
190
191CState::~CState()
192{
193        delete m_pServer;
194
195        delete m_pComparisonManager;
196        delete m_pCommandQueue;
197        delete m_pEngine;
198
199        // Unregister all handlers
200        for (int i = 0; i < STATECHANGE_MAX; i++)
201        {
202                for (auto iter = m_handlers[i].begin(); iter != m_handlers[i].end(); ++iter)
203                {
204                        iter->pHandler->m_pState = 0;
205                }
206        }
207
208        delete m_pRecursiveOperation;
209}
210
211CLocalPath CState::GetLocalDir() const
212{
213        return m_localDir;
214}
215
216
217bool CState::SetLocalDir(const wxString& dir, wxString *error, bool rememberPreviousSubdir)
218{
219        CLocalPath p(m_localDir);
220#ifdef __WXMSW__
221        if (dir == _T("..") && !p.HasParent() && p.HasLogicalParent())
222        {
223                // Parent of C:\ is drive list
224                if (!p.MakeParent())
225                        return false;
226        }
227        else
228#endif
229        if (!p.ChangePath(dir))
230                return false;
231
232        return SetLocalDir(p, error, rememberPreviousSubdir);
233}
234
235bool CState::SetLocalDir(CLocalPath const& dir, wxString *error, bool rememberPreviousSubdir)
236{
237        if (m_sync_browse.is_changing) {
238                wxMessageBoxEx(_T("Cannot change directory, there already is a synchronized browsing operation in progress."), _("Synchronized browsing"));
239                return false;
240        }
241
242        if (!dir.Exists(error))
243                return false;
244
245        if (!m_sync_browse.local_root.empty()) {
246                wxASSERT(m_pServer);
247
248                if (dir != m_sync_browse.local_root && !dir.IsSubdirOf(m_sync_browse.local_root)) {
249                        wxString msg = wxString::Format(_("The local directory '%s' is not below the synchronization root (%s).\nDisable synchronized browsing and continue changing the local directory?"),
250                                        dir.GetPath(),
251                                        m_sync_browse.local_root.GetPath());
252                        if (wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_QUESTION | wxYES_NO) != wxYES)
253                                return false;
254                        SetSyncBrowse(false);
255                }
256                else if (!IsRemoteIdle(true)) {
257                        wxString msg(_("A remote operation is in progress and synchronized browsing is enabled.\nDisable synchronized browsing and continue changing the local directory?"));
258                        if (wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_QUESTION | wxYES_NO) != wxYES)
259                                return false;
260                        SetSyncBrowse(false);
261                }
262                else {
263                        CServerPath remote_path = GetSynchronizedDirectory(dir);
264                        if (remote_path.empty()) {
265                                SetSyncBrowse(false);
266                                wxString msg = wxString::Format(_("Could not obtain corresponding remote directory for the local directory '%s'.\nSynchronized browsing has been disabled."),
267                                        dir.GetPath());
268                                wxMessageBoxEx(msg, _("Synchronized browsing"));
269                                return false;
270                        }
271
272                        m_sync_browse.is_changing = true;
273                        m_sync_browse.compare = m_pComparisonManager->IsComparing();
274                        m_sync_browse.target_path = remote_path;
275                        CListCommand *pCommand = new CListCommand(remote_path);
276                        m_pCommandQueue->ProcessCommand(pCommand);
277
278                        return true;
279                }
280        }
281
282        if (dir == m_localDir.GetParent() && rememberPreviousSubdir) {
283#ifdef __WXMSW__
284                if (dir.GetPath() == _T("\\")) {
285                        m_previouslyVisitedLocalSubdir = m_localDir.GetPath();
286                        m_previouslyVisitedLocalSubdir.RemoveLast();
287                }
288                else
289#endif
290                        m_previouslyVisitedLocalSubdir = m_localDir.GetLastSegment();
291        }
292        else
293                m_previouslyVisitedLocalSubdir = _T("");
294
295
296        m_localDir = dir;
297
298        COptions::Get()->SetOption(OPTION_LASTLOCALDIR, m_localDir.GetPath());
299
300        NotifyHandlers(STATECHANGE_LOCAL_DIR);
301
302        return true;
303}
304
305bool CState::SetRemoteDir(std::shared_ptr<CDirectoryListing> const& pDirectoryListing, bool modified)
306{
307        if (!pDirectoryListing) {
308                SetSyncBrowse(false);
309                if (modified)
310                        return false;
311
312                if (m_pDirectoryListing) {
313                        m_pDirectoryListing = 0;
314                        NotifyHandlers(STATECHANGE_REMOTE_DIR, wxString(), &modified);
315                }
316                m_previouslyVisitedRemoteSubdir = _T("");
317                return true;
318        }
319
320        wxASSERT(pDirectoryListing->m_firstListTime);
321
322        if (pDirectoryListing && m_pDirectoryListing &&
323                pDirectoryListing->path == m_pDirectoryListing->path.GetParent())
324                m_previouslyVisitedRemoteSubdir = m_pDirectoryListing->path.GetLastSegment();
325        else
326                m_previouslyVisitedRemoteSubdir = _T("");
327
328        if (modified) {
329                if (!m_pDirectoryListing || m_pDirectoryListing->path != pDirectoryListing->path) {
330                        // We aren't interested in these listings
331                        return true;
332                }
333        }
334        else
335                m_last_path = pDirectoryListing->path;
336
337        if (m_pDirectoryListing && m_pDirectoryListing->path == pDirectoryListing->path &&
338                pDirectoryListing->failed())
339        {
340                // We still got an old listing, no need to display the new one
341                return true;
342        }
343
344        m_pDirectoryListing = pDirectoryListing;
345
346        NotifyHandlers(STATECHANGE_REMOTE_DIR, wxString(), &modified);
347
348        if (m_sync_browse.is_changing && !modified) {
349                m_sync_browse.is_changing = false;
350                if (m_pDirectoryListing->path != m_sync_browse.remote_root && !m_pDirectoryListing->path.IsSubdirOf(m_sync_browse.remote_root, false)) {
351                        SetSyncBrowse(false);
352                        wxString msg = wxString::Format(_("Current remote directory (%s) is not below the synchronization root (%s).\nSynchronized browsing has been disabled."),
353                                        m_pDirectoryListing->path.GetPath(),
354                                        m_sync_browse.remote_root.GetPath());
355                        wxMessageBoxEx(msg, _("Synchronized browsing"));
356                }
357                else {
358                        CLocalPath local_path = GetSynchronizedDirectory(m_pDirectoryListing->path);
359                        if (local_path.empty()) {
360                                SetSyncBrowse(false);
361                                wxString msg = wxString::Format(_("Could not obtain corresponding local directory for the remote directory '%s'.\nSynchronized browsing has been disabled."),
362                                        m_pDirectoryListing->path.GetPath());
363                                wxMessageBoxEx(msg, _("Synchronized browsing"));
364                                return true;
365                        }
366
367                        wxString error;
368                        if (!local_path.Exists(&error)) {
369                                SetSyncBrowse(false);
370                                wxString msg = error + _T("\n") + _("Synchronized browsing has been disabled.");
371                                wxMessageBoxEx(msg, _("Synchronized browsing"));
372                                return true;
373                        }
374
375                        m_localDir = local_path;
376
377                        COptions::Get()->SetOption(OPTION_LASTLOCALDIR, m_localDir.GetPath());
378
379                        NotifyHandlers(STATECHANGE_LOCAL_DIR);
380
381                        if (m_sync_browse.compare)
382                                m_pComparisonManager->CompareListings();
383                }
384        }
385        return true;
386}
387
388std::shared_ptr<CDirectoryListing> CState::GetRemoteDir() const
389{
390        return m_pDirectoryListing;
391}
392
393const CServerPath CState::GetRemotePath() const
394{
395        if (!m_pDirectoryListing)
396                return CServerPath();
397
398        return m_pDirectoryListing->path;
399}
400
401void CState::RefreshLocal()
402{
403        NotifyHandlers(STATECHANGE_LOCAL_DIR);
404}
405
406void CState::RefreshLocalFile(wxString file)
407{
408        wxString file_name;
409        CLocalPath path(file, &file_name);
410        if (path.empty())
411                return;
412
413        if (file_name.empty())
414        {
415                if (!path.HasParent())
416                        return;
417                path.MakeParent(&file_name);
418                wxASSERT(!file_name.empty());
419        }
420
421        if (path != m_localDir)
422                return;
423
424        NotifyHandlers(STATECHANGE_LOCAL_REFRESH_FILE, file_name);
425}
426
427void CState::LocalDirCreated(const CLocalPath& path)
428{
429        if (!path.IsSubdirOf(m_localDir))
430                return;
431
432        wxString next_segment = path.GetPath().Mid(m_localDir.GetPath().Len());
433        int pos = next_segment.Find(CLocalPath::path_separator);
434        if (pos <= 0)
435        {
436                // Shouldn't ever come true
437                return;
438        }
439
440        // Current local path is /foo/
441        // Called with /foo/bar/baz/
442        // -> Refresh /foo/bar/
443        next_segment = next_segment.Left(pos);
444        NotifyHandlers(STATECHANGE_LOCAL_REFRESH_FILE, next_segment);
445}
446
447void CState::SetServer(const CServer* server, CServerPath const& path)
448{
449        if (m_pServer) {
450                if (server && *server == *m_pServer &&
451                        server->GetName() == m_pServer->GetName() &&
452                        server->MaximumMultipleConnections() == m_pServer->MaximumMultipleConnections())
453                {
454                        // Nothing changes
455                        return;
456                }
457
458                SetRemoteDir(0);
459                delete m_pServer;
460                m_pCertificate.reset();
461                m_pSftpEncryptionInfo.reset();
462        }
463        if (server) {
464                if (!path.empty()) {
465                        m_last_path = path;
466                }
467                else if (m_last_server != *server) {
468                        m_last_path.clear();
469                }
470                m_last_server = *server;
471
472                m_pServer = new CServer(*server);
473
474                const wxString& name = server->GetName();
475                if (!name.empty())
476                        m_title = name + _T(" - ") + server->FormatServer();
477                else
478                        m_title = server->FormatServer();
479        }
480        else {
481                m_pServer = 0;
482                m_title = _("Not connected");
483        }
484
485        m_successful_connect = false;
486
487        NotifyHandlers(STATECHANGE_SERVER);
488}
489
490const CServer* CState::GetServer() const
491{
492        return m_pServer;
493}
494
495wxString CState::GetTitle() const
496{
497        return m_title;
498}
499
500bool CState::Connect(const CServer& server, const CServerPath& path /*=CServerPath()*/)
501{
502        if (!m_pEngine)
503                return false;
504        if (m_pEngine->IsConnected() || m_pEngine->IsBusy() || !m_pCommandQueue->Idle())
505                m_pCommandQueue->Cancel();
506        m_pRecursiveOperation->StopRecursiveOperation();
507        SetSyncBrowse(false);
508
509        m_pCommandQueue->ProcessCommand(new CConnectCommand(server));
510        m_pCommandQueue->ProcessCommand(new CListCommand(path, _T(""), LIST_FLAG_FALLBACK_CURRENT));
511
512        SetServer(&server, path);
513
514        return true;
515}
516
517bool CState::Disconnect()
518{
519        if (!m_pEngine)
520                return false;
521
522        if (!IsRemoteConnected())
523                return true;
524
525        if (!IsRemoteIdle())
526                return false;
527
528        SetServer(0);
529        m_pCommandQueue->ProcessCommand(new CDisconnectCommand());
530
531        return true;
532}
533
534bool CState::CreateEngine()
535{
536        wxASSERT(!m_pEngine);
537        if (m_pEngine)
538                return true;
539
540        m_pEngine = new CFileZillaEngine(m_mainFrame.GetEngineContext());
541        m_pEngine->Init(&m_mainFrame);
542
543        m_pCommandQueue = new CCommandQueue(m_pEngine, &m_mainFrame, this);
544
545        return true;
546}
547
548void CState::DestroyEngine()
549{
550        delete m_pCommandQueue;
551        m_pCommandQueue = 0;
552        delete m_pEngine;
553        m_pEngine = 0;
554}
555
556void CState::RegisterHandler(CStateEventHandler* pHandler, enum t_statechange_notifications notification)
557{
558        wxASSERT(pHandler);
559        wxASSERT(pHandler->m_pState == this);
560        if (pHandler->m_pState != this)
561                return;
562        wxASSERT(notification != STATECHANGE_MAX && notification != STATECHANGE_NONE);
563
564        auto &handlers = m_handlers[notification];
565        for (auto const& it : handlers) {
566                if (it.pHandler == pHandler) {
567                        return;
568                }
569        }
570
571        t_handler handler;
572        handler.pHandler = pHandler;
573        handlers.push_back(handler);
574}
575
576void CState::UnregisterHandler(CStateEventHandler* pHandler, enum t_statechange_notifications notification)
577{
578        wxASSERT(pHandler);
579        wxASSERT(notification != STATECHANGE_MAX);
580
581        if (notification == STATECHANGE_NONE) {
582                for (int i = 0; i < STATECHANGE_MAX; ++i) {
583                        auto &handlers = m_handlers[i];
584                        for (auto iter = handlers.begin(); iter != handlers.end(); ++iter) {
585                                if (iter->pHandler == pHandler) {
586                                        handlers.erase(iter);
587                                        break;
588                                }
589                        }
590                }
591        }
592        else {
593                auto &handlers = m_handlers[notification];
594                for (auto iter = handlers.begin(); iter != handlers.end(); ++iter) {
595                        if (iter->pHandler == pHandler) {
596                                handlers.erase(iter);
597                                return;
598                        }
599                }
600        }
601}
602
603void CState::NotifyHandlers(enum t_statechange_notifications notification, const wxString& data, const void* data2)
604{
605        wxASSERT(notification != STATECHANGE_NONE && notification != STATECHANGE_MAX);
606
607        auto const& handlers = m_handlers[notification];
608        for (auto const& handler : handlers) {
609                handler.pHandler->OnStateChange(this, notification, data, data2);
610        }
611
612        CContextManager::Get()->NotifyHandlers(this, notification, data, data2);
613}
614
615CStateEventHandler::CStateEventHandler(CState* pState)
616        : m_pState(pState)
617{
618}
619
620CStateEventHandler::~CStateEventHandler()
621{
622        CContextManager::Get()->UnregisterHandler(this, STATECHANGE_NONE);
623
624        const std::vector<CState*> *states = CContextManager::Get()->GetAllStates();
625        for (std::vector<CState*>::const_iterator iter = states->begin(); iter != states->end(); ++iter)
626                (*iter)->UnregisterHandler(this, STATECHANGE_NONE);
627}
628
629void CState::UploadDroppedFiles(const wxFileDataObject* pFileDataObject, const wxString& subdir, bool queueOnly)
630{
631        if (!m_pServer || !m_pDirectoryListing)
632                return;
633
634        CServerPath path = m_pDirectoryListing->path;
635        if (subdir == _T("..") && path.HasParent())
636                path = path.GetParent();
637        else if (!subdir.empty())
638                path.AddSegment(subdir);
639
640        UploadDroppedFiles(pFileDataObject, path, queueOnly);
641}
642
643void CState::UploadDroppedFiles(const wxFileDataObject* pFileDataObject, const CServerPath& path, bool queueOnly)
644{
645        if (!m_pServer)
646                return;
647
648        const wxArrayString& files = pFileDataObject->GetFilenames();
649
650        for (unsigned int i = 0; i < files.Count(); i++)
651        {
652                int64_t size;
653                bool is_link;
654                CLocalFileSystem::local_fileType type = CLocalFileSystem::GetFileInfo(files[i], is_link, &size, 0, 0);
655                if (type == CLocalFileSystem::file)
656                {
657                        wxString localFile;
658                        const CLocalPath localPath(files[i], &localFile);
659                        m_mainFrame.GetQueue()->QueueFile(queueOnly, false, localFile, wxEmptyString, localPath, path, *m_pServer, size);
660                        m_mainFrame.GetQueue()->QueueFile_Finish(!queueOnly);
661                }
662                else if (type == CLocalFileSystem::dir)
663                {
664                        CLocalPath localPath(files[i]);
665                        if (localPath.HasParent())
666                        {
667                                CServerPath target = path;
668                                target.AddSegment(localPath.GetLastSegment());
669                                m_mainFrame.GetQueue()->QueueFolder(queueOnly, false, localPath, target, *m_pServer);
670                        }
671                }
672        }
673}
674
675void CState::HandleDroppedFiles(const wxFileDataObject* pFileDataObject, const CLocalPath& path, bool copy)
676{
677        const wxArrayString &files = pFileDataObject->GetFilenames();
678        if (!files.Count())
679                return;
680
681#ifdef __WXMSW__
682        int len = 1;
683
684        for (unsigned int i = 0; i < files.Count(); i++)
685                len += files[i].Len() + 1;
686
687        // SHFILEOPSTRUCT's pTo and pFrom accept null-terminated lists
688        // of null-terminated filenames.
689        wxChar* from = new wxChar[len];
690        wxChar* p = from;
691        for (unsigned int i = 0; i < files.Count(); i++)
692        {
693                wxStrcpy(p, files[i]);
694                p += files[i].Len() + 1;
695        }
696        *p = 0; // End of list
697
698        wxChar* to = new wxChar[path.GetPath().Len() + 2];
699        wxStrcpy(to, path.GetPath());
700        to[path.GetPath().Len() + 1] = 0; // End of list
701
702        SHFILEOPSTRUCT op = {0};
703        op.pFrom = from;
704        op.pTo = to;
705        op.wFunc = copy ? FO_COPY : FO_MOVE;
706        op.hwnd = (HWND)m_mainFrame.GetHandle();
707        SHFileOperation(&op);
708
709        delete [] to;
710        delete [] from;
711#else
712        wxString error;
713        for (unsigned int i = 0; i < files.Count(); i++)
714        {
715                const wxString& file(files[i]);
716
717                int64_t size;
718                bool is_link;
719                CLocalFileSystem::local_fileType type = CLocalFileSystem::GetFileInfo(file, is_link, &size, 0, 0);
720                if (type == CLocalFileSystem::file)
721                {
722                        wxString name;
723                        CLocalPath sourcePath(file, &name);
724                        if (name.empty())
725                                continue;
726                        wxString target = path.GetPath() + name;
727                        if (file == target)
728                                continue;
729
730                        if (copy)
731                                wxCopyFile(file, target);
732                        else
733                                wxRenameFile(file, target);
734                }
735                else if (type == CLocalFileSystem::dir)
736                {
737                        CLocalPath sourcePath(file);
738                        if (sourcePath == path || sourcePath.GetParent() == path)
739                                continue;
740                        if (sourcePath.IsParentOf(path))
741                        {
742                                error = _("A directory cannot be dragged into one of its subdirectories.");
743                                continue;
744                        }
745
746                        if (copy)
747                                RecursiveCopy(sourcePath, path);
748                        else
749                        {
750                                if (!sourcePath.HasParent())
751                                        continue;
752                                wxRenameFile(file, path.GetPath() + sourcePath.GetLastSegment());
753                        }
754                }
755        }
756        if (!error.empty())
757                wxMessageBoxEx(error, _("Could not complete operation"));
758#endif
759
760        RefreshLocal();
761}
762
763bool CState::RecursiveCopy(CLocalPath source, const CLocalPath& target)
764{
765        if (source.empty() || target.empty())
766                return false;
767
768        if (source == target)
769                return false;
770
771        if (source.IsParentOf(target))
772                return false;
773
774        if (!source.HasParent())
775                return false;
776
777        wxString last_segment;
778        if (!source.MakeParent(&last_segment))
779                return false;
780
781        std::list<wxString> dirsToVisit;
782        dirsToVisit.push_back(last_segment + CLocalPath::path_separator);
783
784        // Process any subdirs which still have to be visited
785        while (!dirsToVisit.empty())
786        {
787                wxString dirname = dirsToVisit.front();
788                dirsToVisit.pop_front();
789                wxMkdir(target.GetPath() + dirname);
790
791                CLocalFileSystem fs;
792                if (!fs.BeginFindFiles(source.GetPath() + dirname, false))
793                        continue;
794
795                bool is_dir, is_link;
796                wxString file;
797                while (fs.GetNextFile(file, is_link, is_dir, 0, 0, 0))
798                {
799                        if (file.empty())
800                        {
801                                wxGetApp().DisplayEncodingWarning();
802                                continue;
803                        }
804
805                        if (is_dir)
806                        {
807                                if (is_link)
808                                        continue;
809
810                                const wxString subDir = dirname + file + CLocalPath::path_separator;
811                                dirsToVisit.push_back(subDir);
812                        }
813                        else
814                                wxCopyFile(source.GetPath() + dirname + file, target.GetPath() + dirname + file);
815                }
816        }
817
818        return true;
819}
820
821bool CState::DownloadDroppedFiles(const CRemoteDataObject* pRemoteDataObject, const CLocalPath& path, bool queueOnly /*=false*/)
822{
823        bool hasDirs = false;
824        bool hasFiles = false;
825        const std::list<CRemoteDataObject::t_fileInfo>& files = pRemoteDataObject->GetFiles();
826        for (std::list<CRemoteDataObject::t_fileInfo>::const_iterator iter = files.begin(); iter != files.end(); ++iter)
827        {
828                if (iter->dir)
829                        hasDirs = true;
830                else
831                        hasFiles = true;
832        }
833
834        if (hasDirs) {
835                if (!IsRemoteConnected() || !IsRemoteIdle())
836                        return false;
837        }
838
839        if (hasFiles)
840                m_mainFrame.GetQueue()->QueueFiles(queueOnly, path, *pRemoteDataObject);
841
842        if (!hasDirs)
843                return true;
844
845        for (std::list<CRemoteDataObject::t_fileInfo>::const_iterator iter = files.begin(); iter != files.end(); ++iter) {
846                if (!iter->dir)
847                        continue;
848
849                CLocalPath newPath(path);
850                newPath.AddSegment(CQueueView::ReplaceInvalidCharacters(iter->name));
851                m_pRecursiveOperation->AddDirectoryToVisit(pRemoteDataObject->GetServerPath(), iter->name, newPath, iter->link);
852        }
853
854        if (m_pComparisonManager->IsComparing())
855                m_pComparisonManager->ExitComparisonMode();
856
857        CFilterManager filter;
858        m_pRecursiveOperation->StartRecursiveOperation(queueOnly ? CRecursiveOperation::recursive_addtoqueue : CRecursiveOperation::recursive_download, pRemoteDataObject->GetServerPath(), filter.GetActiveFilters(false));
859
860        return true;
861}
862
863bool CState::IsRemoteConnected() const
864{
865        if (!m_pEngine)
866                return false;
867
868        return m_pServer != 0;
869}
870
871bool CState::IsRemoteIdle(bool ignore_recursive) const
872{
873        if (!ignore_recursive && m_pRecursiveOperation->GetOperationMode() != CRecursiveOperation::recursive_none)
874                return false;
875
876        if (!m_pCommandQueue)
877                return true;
878
879        return m_pCommandQueue->Idle(ignore_recursive ? CCommandQueue::normal : CCommandQueue::any);
880}
881
882void CState::ListingFailed(int error)
883{
884        if (m_sync_browse.is_changing && !m_sync_browse.target_path.empty()) {
885                wxDialogEx dlg;
886                if (!dlg.Load(0, _T("ID_SYNCBROWSE_NONEXISTING"))) {
887                        SetSyncBrowse(false);
888                        return;
889                }
890
891                xrc_call(dlg, "ID_SYNCBROWSE_NONEXISTING_LABEL", &wxStaticText::SetLabel, wxString::Format(_("The remote directory '%s' does not exist."), m_sync_browse.target_path.GetPath()));
892                xrc_call(dlg, "ID_SYNCBROWSE_CREATE", &wxRadioButton::SetLabel, _("Create &missing remote directory and enter it"));
893                xrc_call(dlg, "ID_SYNCBROWSE_DISABLE", &wxRadioButton::SetLabel, _("&Disable synchronized browsing and continue changing the local directory"));
894                dlg.GetSizer()->Fit(&dlg);
895                if (dlg.ShowModal() == wxID_OK) {
896
897                        if (xrc_call(dlg, "ID_SYNCBROWSE_CREATE", &wxRadioButton::GetValue)) {
898                                m_pCommandQueue->ProcessCommand(new CMkdirCommand(m_sync_browse.target_path));
899                                m_pCommandQueue->ProcessCommand(new CListCommand(m_sync_browse.target_path));
900                                m_sync_browse.target_path.clear();
901                                return;
902                        }
903                        else {
904                                CLocalPath local = GetSynchronizedDirectory(m_sync_browse.target_path);
905                                SetSyncBrowse(false);
906                                SetLocalDir(local);
907                        }
908                }
909        }
910
911        m_sync_browse.is_changing = false;
912}
913
914void CState::LinkIsNotDir(const CServerPath& path, const wxString& subdir)
915{
916        m_sync_browse.is_changing = false;
917
918        NotifyHandlers(STATECHANGE_REMOTE_LINKNOTDIR, subdir, &path);
919}
920
921bool CState::ChangeRemoteDir(const CServerPath& path, const wxString& subdir /*=_T("")*/, int flags /*=0*/, bool ignore_busy /*=false*/)
922{
923        if (!m_pServer || !m_pCommandQueue)
924                return false;
925
926        if (!m_sync_browse.local_root.empty()) {
927                CServerPath p(path);
928                if (!subdir.empty() && !p.ChangePath(subdir)) {
929                        wxString msg = wxString::Format(_("Could not get full remote path."));
930                        wxMessageBoxEx(msg, _("Synchronized browsing"));
931                        return false;
932                }
933
934                if (p != m_sync_browse.remote_root && !p.IsSubdirOf(m_sync_browse.remote_root, false)) {
935                        wxString msg = wxString::Format(_("The remote directory '%s' is not below the synchronization root (%s).\nDisable synchronized browsing and continue changing the remote directory?"),
936                                        p.GetPath(),
937                                        m_sync_browse.remote_root.GetPath());
938                        if (wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_QUESTION | wxYES_NO) != wxYES)
939                                return false;
940                        SetSyncBrowse(false);
941                }
942                else if (!IsRemoteIdle(true) && !ignore_busy) {
943                        wxString msg(_("Another remote operation is already in progress, cannot change directory now."));
944                        wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_EXCLAMATION);
945                        return false;
946                }
947                else {
948                        wxString error;
949                        CLocalPath local_path = GetSynchronizedDirectory(p);
950                        if (local_path.empty()) {
951                                wxString msg = wxString::Format(_("Could not obtain corresponding local directory for the remote directory '%s'.\nDisable synchronized browsing and continue changing the remote directory?"),
952                                        p.GetPath());
953                                if (wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_QUESTION | wxYES_NO) != wxYES)
954                                        return false;
955                                SetSyncBrowse(false);
956                        }
957                        else if (!local_path.Exists(&error)) {
958                                wxString msg = error + _T("\n") + _("Disable synchronized browsing and continue changing the remote directory?");
959
960                                wxDialogEx dlg;
961                                if (!dlg.Load(0, _T("ID_SYNCBROWSE_NONEXISTING"))) {
962                                        return false;
963                                }
964                                xrc_call(dlg, "ID_SYNCBROWSE_NONEXISTING_LABEL", &wxStaticText::SetLabel, wxString::Format(_("The local directory '%s' does not exist."), local_path.GetPath()));
965                                xrc_call(dlg, "ID_SYNCBROWSE_CREATE", &wxRadioButton::SetLabel, _("Create &missing local directory and enter it"));
966                                xrc_call(dlg, "ID_SYNCBROWSE_DISABLE", &wxRadioButton::SetLabel, _("&Disable synchronized browsing and continue changing the remote directory"));
967                                dlg.GetSizer()->Fit(&dlg);
968                                if (dlg.ShowModal() != wxID_OK) {
969                                        return false;
970                                }
971
972                                if (xrc_call(dlg, "ID_SYNCBROWSE_CREATE", &wxRadioButton::GetValue)) {
973                                        {
974                                                wxLogNull log;
975                                                wxMkdir(local_path.GetPath());
976                                        }
977
978                                        if (!local_path.Exists(&error)) {
979                                                wxMessageBox(wxString::Format(_("The local directory '%s' could not be created."), local_path.GetPath()), _("Synchronized browsing"), wxICON_EXCLAMATION);
980                                                return false;
981                                        }
982                                        m_sync_browse.is_changing = true;
983                                        m_sync_browse.compare = m_pComparisonManager->IsComparing();
984                                        m_sync_browse.target_path.clear();
985                                }
986                                else {
987                                        SetSyncBrowse(false);
988                                }
989                        }
990                        else {
991                                m_sync_browse.is_changing = true;
992                                m_sync_browse.compare = m_pComparisonManager->IsComparing();
993                                m_sync_browse.target_path.clear();
994                        }
995                }
996        }
997
998        CListCommand *pCommand = new CListCommand(path, subdir, flags);
999        m_pCommandQueue->ProcessCommand(pCommand);
1000
1001        return true;
1002}
1003
1004bool CState::SetSyncBrowse(bool enable, const CServerPath& assumed_remote_root /*=CServerPath()*/)
1005{
1006        if (enable != m_sync_browse.local_root.empty())
1007                return enable;
1008
1009        if (!enable) {
1010                wxASSERT(assumed_remote_root.empty());
1011                m_sync_browse.local_root.clear();
1012                m_sync_browse.remote_root.clear();
1013                m_sync_browse.is_changing = false;
1014
1015                NotifyHandlers(STATECHANGE_SYNC_BROWSE);
1016                return false;
1017        }
1018
1019        if (!m_pDirectoryListing && assumed_remote_root.empty()) {
1020                NotifyHandlers(STATECHANGE_SYNC_BROWSE);
1021                return false;
1022        }
1023
1024        m_sync_browse.is_changing = false;
1025        m_sync_browse.local_root = m_localDir;
1026
1027        if (assumed_remote_root.empty())
1028                m_sync_browse.remote_root = m_pDirectoryListing->path;
1029        else {
1030                m_sync_browse.remote_root = assumed_remote_root;
1031                m_sync_browse.is_changing = true;
1032                m_sync_browse.compare = false;
1033        }
1034
1035        while (m_sync_browse.local_root.HasParent() && m_sync_browse.remote_root.HasParent() &&
1036                m_sync_browse.local_root.GetLastSegment() == m_sync_browse.remote_root.GetLastSegment())
1037        {
1038                m_sync_browse.local_root.MakeParent();
1039                m_sync_browse.remote_root = m_sync_browse.remote_root.GetParent();
1040        }
1041
1042        NotifyHandlers(STATECHANGE_SYNC_BROWSE);
1043        return true;
1044}
1045
1046CLocalPath CState::GetSynchronizedDirectory(CServerPath remote_path)
1047{
1048        std::list<wxString> segments;
1049        while (remote_path.HasParent() && remote_path != m_sync_browse.remote_root) {
1050                segments.push_front(remote_path.GetLastSegment());
1051                remote_path = remote_path.GetParent();
1052        }
1053        if (remote_path != m_sync_browse.remote_root)
1054                return CLocalPath();
1055
1056        CLocalPath local_path = m_sync_browse.local_root;
1057        for (std::list<wxString>::const_iterator iter = segments.begin(); iter != segments.end(); ++iter)
1058                local_path.AddSegment(*iter);
1059
1060        return local_path;
1061}
1062
1063
1064CServerPath CState::GetSynchronizedDirectory(CLocalPath local_path)
1065{
1066        std::list<wxString> segments;
1067        while (local_path.HasParent() && local_path != m_sync_browse.local_root) {
1068                wxString last;
1069                local_path.MakeParent(&last);
1070                segments.push_front(last);
1071        }
1072        if (local_path != m_sync_browse.local_root)
1073                return CServerPath();
1074
1075        CServerPath remote_path = m_sync_browse.remote_root;
1076        for (std::list<wxString>::const_iterator iter = segments.begin(); iter != segments.end(); ++iter)
1077                remote_path.AddSegment(*iter);
1078
1079        return remote_path;
1080}
1081
1082bool CState::RefreshRemote()
1083{
1084        if (!m_pCommandQueue)
1085                return false;
1086
1087        if (!IsRemoteConnected() || !IsRemoteIdle(true))
1088                return false;
1089
1090        return ChangeRemoteDir(GetRemotePath(), _T(""), LIST_FLAG_REFRESH);
1091}
1092
1093bool CState::GetSecurityInfo(CCertificateNotification *& pInfo)
1094{
1095        pInfo = m_pCertificate.get();
1096        return m_pCertificate != 0;
1097}
1098
1099bool CState::GetSecurityInfo(CSftpEncryptionNotification *& pInfo)
1100{
1101        pInfo = m_pSftpEncryptionInfo.get();
1102        return m_pSftpEncryptionInfo != 0;
1103}
1104
1105void CState::SetSecurityInfo(CCertificateNotification const& info)
1106{
1107        m_pSftpEncryptionInfo.reset();
1108        m_pCertificate = std::make_unique<CCertificateNotification>(info);
1109        NotifyHandlers(STATECHANGE_ENCRYPTION);
1110}
1111
1112void CState::SetSecurityInfo(CSftpEncryptionNotification const& info)
1113{
1114        m_pCertificate.reset();
1115        m_pSftpEncryptionInfo = std::make_unique<CSftpEncryptionNotification>(info);
1116        NotifyHandlers(STATECHANGE_ENCRYPTION);
1117}
Note: See TracBrowser for help on using the repository browser.