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

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 3 years ago

Update new version: 3.15.02

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