2011-04-06 13:48:02 +04:00
/*
* Copyright ( C ) by Duncan Mac - Vicar P . < duncan @ kde . org >
2013-07-22 22:27:42 +04:00
* Copyright ( C ) by Daniel Molkentin < danimo @ owncloud . com >
* Copyright ( C ) by Klaas Freitag < freitag @ owncloud . com >
2011-04-06 13:48:02 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*/
2013-02-25 12:54:19 +04:00
# include "config.h"
2012-07-20 19:13:23 +04:00
2014-07-11 02:31:24 +04:00
# include "account.h"
2014-12-17 16:09:57 +03:00
# include "accountstate.h"
2014-07-11 02:31:24 +04:00
# include "folder.h"
# include "folderman.h"
# include "logger.h"
2014-11-10 01:25:57 +03:00
# include "configfile.h"
2014-07-11 02:31:24 +04:00
# include "networkjobs.h"
# include "syncjournalfilerecord.h"
# include "syncresult.h"
# include "utility.h"
# include "clientproxy.h"
# include "syncengine.h"
# include "syncrunfilelog.h"
2015-10-23 18:24:45 +03:00
# include "socketapi.h"
2014-09-18 19:08:53 +04:00
# include "theme.h"
2015-02-25 12:51:05 +03:00
# include "filesystem.h"
2015-10-02 10:40:44 +03:00
# include "excludedfiles.h"
2013-10-21 23:42:52 +04:00
2013-07-30 13:19:22 +04:00
# include "creds/abstractcredentials.h"
2013-10-21 23:42:52 +04:00
2012-05-21 18:48:49 +04:00
# include <QTimer>
# include <QUrl>
2012-06-25 17:31:13 +04:00
# include <QDir>
2015-04-24 11:18:33 +03:00
# include <QSettings>
2014-04-06 21:34:56 +04:00
2013-07-22 22:27:42 +04:00
# include <QMessageBox>
# include <QPushButton>
2012-05-21 18:48:49 +04:00
2014-11-10 00:34:07 +03:00
namespace OCC {
2011-02-17 02:21:45 +03:00
2017-05-09 15:24:11 +03:00
Q_LOGGING_CATEGORY ( lcFolder , " gui.folder " , QtInfoMsg )
2017-05-17 11:55:42 +03:00
Folder : : Folder ( const FolderDefinition & definition ,
AccountState * accountState ,
QObject * parent )
2013-07-22 22:27:42 +04:00
: QObject ( parent )
2017-05-17 11:55:42 +03:00
, _accountState ( accountState )
, _definition ( definition )
, _csyncUnavail ( false )
, _proxyDirty ( true )
, _lastSyncDuration ( 0 )
, _consecutiveFailingSyncs ( 0 )
, _consecutiveFollowUpSyncs ( 0 )
, _journal ( _definition . absoluteJournalPath ( ) )
, _fileLog ( new SyncRunFileLog )
, _saveBackwardsCompatible ( false )
2011-02-17 02:21:45 +03:00
{
2012-03-13 18:42:29 +04:00
qsrand ( QTime : : currentTime ( ) . msec ( ) ) ;
2015-01-16 12:52:26 +03:00
_timeSinceLastSyncStart . start ( ) ;
_timeSinceLastSyncDone . start ( ) ;
2012-03-08 14:39:31 +04:00
2015-06-17 16:55:48 +03:00
SyncResult : : Status status = SyncResult : : NotYetStarted ;
if ( definition . paused ) {
status = SyncResult : : Paused ;
}
_syncResult . setStatus ( status ) ;
2012-02-20 19:45:27 +04:00
2012-10-30 15:42:17 +04:00
// check if the local path exists
checkLocalPath ( ) ;
2013-08-05 19:01:08 +04:00
2015-04-27 18:33:59 +03:00
_syncResult . setFolder ( _definition . alias ) ;
2016-03-09 19:53:18 +03:00
2016-11-15 20:47:04 +03:00
_engine . reset ( new SyncEngine ( _accountState - > account ( ) , path ( ) , remotePath ( ) , & _journal ) ) ;
2016-03-09 19:53:18 +03:00
// pass the setting if hidden files are to be ignored, will be read in csync_update
_engine - > setIgnoreHiddenFiles ( _definition . ignoreHiddenFiles ) ;
if ( ! setIgnoredFiles ( ) )
2017-05-09 15:24:11 +03:00
qCWarning ( lcFolder , " Could not read system exclude file " ) ;
2016-03-09 19:53:18 +03:00
2016-04-28 23:43:53 +03:00
connect ( _accountState . data ( ) , SIGNAL ( isConnectedChanged ( ) ) , this , SIGNAL ( canSyncChanged ( ) ) ) ;
2016-03-09 19:53:18 +03:00
connect ( _engine . data ( ) , SIGNAL ( rootEtag ( QString ) ) , this , SLOT ( etagRetreivedFromSyncEngine ( QString ) ) ) ;
2017-05-17 11:55:42 +03:00
connect ( _engine . data ( ) , SIGNAL ( started ( ) ) , SLOT ( slotSyncStarted ( ) ) , Qt : : QueuedConnection ) ;
2016-03-09 19:53:18 +03:00
connect ( _engine . data ( ) , SIGNAL ( finished ( bool ) ) , SLOT ( slotSyncFinished ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( _engine . data ( ) , SIGNAL ( csyncError ( QString ) ) , SLOT ( slotSyncError ( QString ) ) , Qt : : QueuedConnection ) ;
connect ( _engine . data ( ) , SIGNAL ( csyncUnavailable ( ) ) , SLOT ( slotCsyncUnavailable ( ) ) , Qt : : QueuedConnection ) ;
//direct connection so the message box is blocking the sync.
2017-05-17 11:55:42 +03:00
connect ( _engine . data ( ) , SIGNAL ( aboutToRemoveAllFiles ( SyncFileItem : : Direction , bool * ) ) ,
SLOT ( slotAboutToRemoveAllFiles ( SyncFileItem : : Direction , bool * ) ) ) ;
connect ( _engine . data ( ) , SIGNAL ( aboutToRestoreBackup ( bool * ) ) ,
SLOT ( slotAboutToRestoreBackup ( bool * ) ) ) ;
connect ( _engine . data ( ) , SIGNAL ( folderDiscovered ( bool , QString ) ) , this , SLOT ( slotFolderDiscovered ( bool , QString ) ) ) ;
2016-03-09 19:53:18 +03:00
connect ( _engine . data ( ) , SIGNAL ( transmissionProgress ( ProgressInfo ) ) , this , SLOT ( slotTransmissionProgress ( ProgressInfo ) ) ) ;
2017-01-25 13:12:38 +03:00
connect ( _engine . data ( ) , SIGNAL ( itemCompleted ( const SyncFileItemPtr & ) ) ,
2017-05-17 11:55:42 +03:00
this , SLOT ( slotItemCompleted ( const SyncFileItemPtr & ) ) ) ;
connect ( _engine . data ( ) , SIGNAL ( newBigFolder ( QString , bool ) ) ,
this , SLOT ( slotNewBigFolderDiscovered ( QString , bool ) ) ) ;
2016-04-29 17:14:18 +03:00
connect ( _engine . data ( ) , SIGNAL ( seenLockedFile ( QString ) ) , FolderMan : : instance ( ) , SLOT ( slotSyncOnceFileUnlocks ( QString ) ) ) ;
2017-05-17 11:55:42 +03:00
connect ( _engine . data ( ) , SIGNAL ( aboutToPropagate ( SyncFileItemVector & ) ) ,
SLOT ( slotLogPropagationStart ( ) ) ) ;
2016-10-18 17:04:25 +03:00
_scheduleSelfTimer . setSingleShot ( true ) ;
_scheduleSelfTimer . setInterval ( SyncEngine : : minimumFileAgeForUpload ) ;
connect ( & _scheduleSelfTimer , SIGNAL ( timeout ( ) ) ,
2017-05-17 11:55:42 +03:00
SLOT ( slotScheduleThisFolder ( ) ) ) ;
2011-02-17 02:21:45 +03:00
}
Folder : : ~ Folder ( )
{
2016-06-17 20:04:24 +03:00
// Reset then engine first as it will abort and try to access members of the Folder
_engine . reset ( ) ;
2011-02-17 02:21:45 +03:00
}
2016-09-02 13:29:21 +03:00
2012-10-30 15:42:17 +04:00
void Folder : : checkLocalPath ( )
{
2015-04-27 18:33:59 +03:00
const QFileInfo fi ( _definition . localPath ) ;
2016-09-12 16:17:21 +03:00
_canonicalLocalPath = fi . canonicalFilePath ( ) ;
2016-09-15 15:56:37 +03:00
if ( _canonicalLocalPath . isEmpty ( ) ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolder ) < < " Broken symlink: " < < _definition . localPath ;
2016-09-15 15:56:37 +03:00
_canonicalLocalPath = _definition . localPath ;
2017-05-17 11:55:42 +03:00
} else if ( ! _canonicalLocalPath . endsWith ( ' / ' ) ) {
2016-09-12 16:17:21 +03:00
_canonicalLocalPath . append ( ' / ' ) ;
}
2017-05-17 11:55:42 +03:00
if ( fi . isDir ( ) & & fi . isReadable ( ) ) {
2017-05-09 15:24:11 +03:00
qCDebug ( lcFolder ) < < " Checked local path ok " ;
2012-10-30 15:42:17 +04:00
} else {
2012-10-30 17:37:15 +04:00
// Check directory again
2017-05-17 11:55:42 +03:00
if ( ! FileSystem : : fileExists ( _definition . localPath , fi ) ) {
2017-01-25 13:28:18 +03:00
_syncResult . appendErrorString ( tr ( " Local folder %1 does not exist. " ) . arg ( _definition . localPath ) ) ;
2017-05-17 11:55:42 +03:00
_syncResult . setStatus ( SyncResult : : SetupError ) ;
} else if ( ! fi . isDir ( ) ) {
2017-01-25 13:28:18 +03:00
_syncResult . appendErrorString ( tr ( " %1 should be a folder but is not. " ) . arg ( _definition . localPath ) ) ;
2017-05-17 11:55:42 +03:00
_syncResult . setStatus ( SyncResult : : SetupError ) ;
} else if ( ! fi . isReadable ( ) ) {
2017-01-25 13:28:18 +03:00
_syncResult . appendErrorString ( tr ( " %1 is not readable. " ) . arg ( _definition . localPath ) ) ;
2017-05-17 11:55:42 +03:00
_syncResult . setStatus ( SyncResult : : SetupError ) ;
2012-10-30 17:37:15 +04:00
}
2012-10-30 15:42:17 +04:00
}
}
2016-04-26 17:38:03 +03:00
QString Folder : : shortGuiRemotePathOrAppName ( ) const
2015-08-11 16:12:43 +03:00
{
if ( remotePath ( ) . length ( ) > 0 & & remotePath ( ) ! = QLatin1String ( " / " ) ) {
QString a = QFile ( remotePath ( ) ) . fileName ( ) ;
if ( a . startsWith ( ' / ' ) ) {
a = a . remove ( 0 , 1 ) ;
}
return a ;
} else {
return Theme : : instance ( ) - > appNameGUI ( ) ;
}
}
2011-04-06 11:52:02 +04:00
QString Folder : : alias ( ) const
{
2015-04-27 18:33:59 +03:00
return _definition . alias ;
2011-04-06 11:52:02 +04:00
}
2011-02-17 17:10:06 +03:00
QString Folder : : path ( ) const
{
2016-09-12 16:17:21 +03:00
return _canonicalLocalPath ;
2011-02-17 17:10:06 +03:00
}
2016-04-26 17:38:03 +03:00
QString Folder : : shortGuiLocalPath ( ) const
2015-08-17 12:39:45 +03:00
{
QString p = _definition . localPath ;
QString home = QDir : : homePath ( ) ;
2017-05-17 11:55:42 +03:00
if ( ! home . endsWith ( ' / ' ) ) {
2015-08-17 12:39:45 +03:00
home . append ( ' / ' ) ;
}
if ( p . startsWith ( home ) ) {
p = p . mid ( home . length ( ) ) ;
}
if ( p . length ( ) > 1 & & p . endsWith ( ' / ' ) ) {
p . chop ( 1 ) ;
}
return QDir : : toNativeSeparators ( p ) ;
}
2015-07-14 17:56:55 +03:00
bool Folder : : ignoreHiddenFiles ( )
{
bool re ( _definition . ignoreHiddenFiles ) ;
return re ;
}
void Folder : : setIgnoreHiddenFiles ( bool ignore )
{
_definition . ignoreHiddenFiles = ignore ;
}
2016-11-22 17:30:12 +03:00
QString Folder : : cleanPath ( ) const
2015-05-03 14:34:23 +03:00
{
2016-09-12 16:17:21 +03:00
QString cleanedPath = QDir : : cleanPath ( _canonicalLocalPath ) ;
2015-05-03 14:34:23 +03:00
2017-05-17 11:55:42 +03:00
if ( cleanedPath . length ( ) = = 3 & & cleanedPath . endsWith ( " :/ " ) )
cleanedPath . remove ( 2 , 1 ) ;
2015-05-03 14:34:23 +03:00
return cleanedPath ;
}
2013-07-22 22:27:42 +04:00
bool Folder : : isBusy ( ) const
{
2016-03-09 19:53:18 +03:00
return _engine - > isSyncRunning ( ) ;
2013-07-22 22:27:42 +04:00
}
2013-10-21 23:42:52 +04:00
QString Folder : : remotePath ( ) const
{
2015-04-27 18:33:59 +03:00
return _definition . targetPath ;
2013-10-21 23:42:52 +04:00
}
QUrl Folder : : remoteUrl ( ) const
2012-03-26 15:20:15 +04:00
{
2016-10-25 13:04:22 +03:00
return Utility : : concatUrlPath ( _accountState - > account ( ) - > davUrl ( ) , remotePath ( ) ) ;
2012-03-26 15:20:15 +04:00
}
2014-08-19 15:58:20 +04:00
bool Folder : : syncPaused ( ) const
2011-10-13 18:41:24 +04:00
{
2017-05-17 11:55:42 +03:00
return _definition . paused ;
2011-10-13 18:41:24 +04:00
}
2015-07-01 12:39:57 +03:00
bool Folder : : canSync ( ) const
{
2016-04-28 23:43:53 +03:00
return ! syncPaused ( ) & & accountState ( ) - > isConnected ( ) ;
2015-07-01 12:39:57 +03:00
}
2017-05-17 11:55:42 +03:00
void Folder : : setSyncPaused ( bool paused )
2011-10-13 18:41:24 +04:00
{
2016-03-02 13:06:03 +03:00
if ( paused = = _definition . paused ) {
return ;
2015-04-24 11:18:33 +03:00
}
2016-03-02 13:06:03 +03:00
_definition . paused = paused ;
saveToSettings ( ) ;
2017-05-17 11:55:42 +03:00
if ( ! paused ) {
2016-03-01 18:07:11 +03:00
setSyncState ( SyncResult : : NotYetStarted ) ;
2015-04-24 11:18:33 +03:00
} else {
setSyncState ( SyncResult : : Paused ) ;
}
2016-03-02 13:06:03 +03:00
emit syncPausedChanged ( this , paused ) ;
2016-03-01 18:07:11 +03:00
emit syncStateChange ( ) ;
2016-04-28 23:43:53 +03:00
emit canSyncChanged ( ) ;
2011-10-13 18:41:24 +04:00
}
2013-02-18 17:56:21 +04:00
void Folder : : setSyncState ( SyncResult : : Status state )
{
_syncResult . setStatus ( state ) ;
}
2012-02-20 19:45:27 +04:00
SyncResult Folder : : syncResult ( ) const
2011-10-13 18:41:24 +04:00
{
2017-05-17 11:55:42 +03:00
return _syncResult ;
2011-10-13 18:41:24 +04:00
}
2014-01-11 23:35:16 +04:00
void Folder : : prepareToSync ( )
2011-04-06 17:57:18 +04:00
{
2017-01-25 13:28:18 +03:00
_syncResult . reset ( ) ;
2017-05-17 11:55:42 +03:00
_syncResult . setStatus ( SyncResult : : NotYetStarted ) ;
2012-03-31 14:44:22 +04:00
}
2014-12-03 00:32:54 +03:00
void Folder : : slotRunEtagJob ( )
2011-04-05 14:16:24 +04:00
{
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Trying to check " < < remoteUrl ( ) . toString ( ) < < " for changes via ETag check. (time since last sync: " < < ( _timeSinceLastSyncDone . elapsed ( ) / 1000 ) < < " s) " ;
2013-08-05 21:53:58 +04:00
2014-12-18 14:09:48 +03:00
AccountPtr account = _accountState - > account ( ) ;
2014-12-03 00:32:54 +03:00
2016-10-18 17:04:25 +03:00
if ( _requestEtagJob ) {
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < remoteUrl ( ) . toString ( ) < < " has ETag job queued, not trying to sync " ;
2014-09-02 16:51:03 +04:00
return ;
}
2016-03-01 18:07:11 +03:00
if ( ! canSync ( ) ) {
2017-05-17 11:55:42 +03:00
qCInfo ( lcFolder ) < < " Not syncing. : " < < remoteUrl ( ) . toString ( ) < < _definition . paused < < AccountState : : stateString ( _accountState - > state ( ) ) ;
2014-08-26 18:23:19 +04:00
return ;
}
2016-10-18 17:04:25 +03:00
// Do the ordinary etag check for the root folder and schedule a
// sync if it's different.
2014-10-24 14:52:24 +04:00
2016-10-18 17:04:25 +03:00
_requestEtagJob = new RequestEtagJob ( account , remotePath ( ) , this ) ;
2017-05-17 11:55:42 +03:00
_requestEtagJob - > setTimeout ( 60 * 1000 ) ;
2016-10-18 17:04:25 +03:00
// check if the etag is different when retrieved
QObject : : connect ( _requestEtagJob , SIGNAL ( etagRetreived ( QString ) ) , this , SLOT ( etagRetreived ( QString ) ) ) ;
FolderMan : : instance ( ) - > slotScheduleETagJob ( alias ( ) , _requestEtagJob ) ;
// The _requestEtagJob is auto deleting itself on finish. Our guard pointer _requestEtagJob will then be null.
2013-08-05 21:53:58 +04:00
}
2017-05-17 11:55:42 +03:00
void Folder : : etagRetreived ( const QString & etag )
2013-08-05 21:53:58 +04:00
{
2013-08-14 14:59:56 +04:00
// re-enable sync if it was disabled because network was down
FolderMan : : instance ( ) - > setSyncEnabled ( true ) ;
2013-08-05 21:53:58 +04:00
if ( _lastEtag ! = etag ) {
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Compare etag with previous etag: last: " < < _lastEtag < < " , received: " < < etag < < " -> CHANGED " ;
2013-08-05 21:53:58 +04:00
_lastEtag = etag ;
2016-10-18 17:04:25 +03:00
slotScheduleThisFolder ( ) ;
2013-08-05 21:53:58 +04:00
}
2015-10-19 12:50:26 +03:00
2016-03-16 21:07:40 +03:00
_accountState - > tagLastSuccessfullETagRequest ( ) ;
2011-04-06 17:57:18 +04:00
}
2017-05-17 11:55:42 +03:00
void Folder : : etagRetreivedFromSyncEngine ( const QString & etag )
2015-01-23 17:30:00 +03:00
{
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Root etag from during sync: " < < etag ;
2015-11-18 16:50:43 +03:00
accountState ( ) - > tagLastSuccessfullETagRequest ( ) ;
2015-01-23 17:30:00 +03:00
_lastEtag = etag ;
}
2017-01-25 13:28:18 +03:00
void Folder : : showSyncResultPopup ( )
{
2017-05-17 11:55:42 +03:00
if ( _syncResult . firstItemNew ( ) ) {
createGuiLog ( _syncResult . firstItemNew ( ) - > _file , LogStatusNew , _syncResult . numNewItems ( ) ) ;
2015-01-15 22:48:04 +03:00
}
2017-05-17 11:55:42 +03:00
if ( _syncResult . firstItemDeleted ( ) ) {
createGuiLog ( _syncResult . firstItemDeleted ( ) - > _file , LogStatusRemove , _syncResult . numRemovedItems ( ) ) ;
2015-01-15 22:48:04 +03:00
}
2017-05-17 11:55:42 +03:00
if ( _syncResult . firstItemUpdated ( ) ) {
createGuiLog ( _syncResult . firstItemUpdated ( ) - > _file , LogStatusUpdated , _syncResult . numUpdatedItems ( ) ) ;
2015-01-15 22:48:04 +03:00
}
2013-11-28 13:57:49 +04:00
2017-05-17 11:55:42 +03:00
if ( _syncResult . firstItemRenamed ( ) ) {
2016-03-24 20:20:49 +03:00
LogStatus status ( LogStatusRename ) ;
2013-11-28 13:57:49 +04:00
// if the path changes it's rather a move
2017-01-25 13:28:18 +03:00
QDir renTarget = QFileInfo ( _syncResult . firstItemRenamed ( ) - > _renameTarget ) . dir ( ) ;
QDir renSource = QFileInfo ( _syncResult . firstItemRenamed ( ) - > _file ) . dir ( ) ;
2017-05-17 11:55:42 +03:00
if ( renTarget ! = renSource ) {
2016-03-24 20:20:49 +03:00
status = LogStatusMove ;
2013-11-28 13:57:49 +04:00
}
2017-05-17 11:55:42 +03:00
createGuiLog ( _syncResult . firstItemRenamed ( ) - > _originalFile , status ,
_syncResult . numRenamedItems ( ) , _syncResult . firstItemRenamed ( ) - > _renameTarget ) ;
2013-11-28 13:57:49 +04:00
}
2013-11-08 19:21:59 +04:00
2017-05-17 11:55:42 +03:00
if ( _syncResult . firstConflictItem ( ) ) {
createGuiLog ( _syncResult . firstConflictItem ( ) - > _file , LogStatusConflict , _syncResult . numConflictItems ( ) ) ;
2016-04-05 17:37:54 +03:00
}
2017-03-16 18:30:28 +03:00
if ( int errorCount = _syncResult . numErrorItems ( ) ) {
2017-05-17 11:55:42 +03:00
createGuiLog ( _syncResult . firstItemError ( ) - > _file , LogStatusError , errorCount ) ;
2017-03-16 18:30:28 +03:00
}
2014-09-19 17:58:27 +04:00
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Folder sync result: " < < int ( _syncResult . status ( ) ) ;
2013-11-08 19:21:59 +04:00
}
2017-05-17 11:55:42 +03:00
void Folder : : createGuiLog ( const QString & filename , LogStatus status , int count ,
const QString & renameTarget )
2013-11-08 19:21:59 +04:00
{
2017-05-17 11:55:42 +03:00
if ( count > 0 ) {
2013-11-08 19:21:59 +04:00
Logger * logger = Logger : : instance ( ) ;
QString file = QDir : : toNativeSeparators ( filename ) ;
2014-03-11 13:55:20 +04:00
QString text ;
2016-03-24 20:20:49 +03:00
switch ( status ) {
case LogStatusRemove :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 and %n other file(s) have been removed. " , " " , count - 1 ) . arg ( file ) ;
2014-03-11 13:55:20 +04:00
} else {
text = tr ( " %1 has been removed. " , " %1 names a file. " ) . arg ( file ) ;
}
break ;
2016-03-24 20:20:49 +03:00
case LogStatusNew :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 and %n other file(s) have been downloaded. " , " " , count - 1 ) . arg ( file ) ;
2014-03-11 13:55:20 +04:00
} else {
text = tr ( " %1 has been downloaded. " , " %1 names a file. " ) . arg ( file ) ;
}
break ;
2016-03-24 20:20:49 +03:00
case LogStatusUpdated :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 and %n other file(s) have been updated. " , " " , count - 1 ) . arg ( file ) ;
2014-03-11 13:55:20 +04:00
} else {
text = tr ( " %1 has been updated. " , " %1 names a file. " ) . arg ( file ) ;
}
break ;
2016-03-24 20:20:49 +03:00
case LogStatusRename :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 has been renamed to %2 and %n other file(s) have been renamed. " , " " , count - 1 ) . arg ( file , renameTarget ) ;
2014-03-11 13:55:20 +04:00
} else {
2017-02-23 16:54:17 +03:00
text = tr ( " %1 has been renamed to %2. " , " %1 and %2 name files. " ) . arg ( file , renameTarget ) ;
2014-03-11 13:55:20 +04:00
}
break ;
2016-03-24 20:20:49 +03:00
case LogStatusMove :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 has been moved to %2 and %n other file(s) have been moved. " , " " , count - 1 ) . arg ( file , renameTarget ) ;
2014-03-11 13:55:20 +04:00
} else {
2017-02-23 16:54:17 +03:00
text = tr ( " %1 has been moved to %2. " ) . arg ( file , renameTarget ) ;
2014-03-11 13:55:20 +04:00
}
break ;
2016-04-05 17:37:54 +03:00
case LogStatusConflict :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 has and %n other file(s) have sync conflicts. " , " " , count - 1 ) . arg ( file ) ;
2016-04-05 17:37:54 +03:00
} else {
text = tr ( " %1 has a sync conflict. Please check the conflict file! " ) . arg ( file ) ;
}
break ;
2016-03-24 20:20:49 +03:00
case LogStatusError :
2017-05-17 11:55:42 +03:00
if ( count > 1 ) {
text = tr ( " %1 and %n other file(s) could not be synced due to errors. See the log for details. " , " " , count - 1 ) . arg ( file ) ;
2014-09-19 17:58:27 +04:00
} else {
text = tr ( " %1 could not be synced due to an error. See the log for details. " ) . arg ( file ) ;
}
break ;
2014-03-11 13:55:20 +04:00
}
2017-05-17 11:55:42 +03:00
if ( ! text . isEmpty ( ) ) {
logger - > postOptionalGuiLog ( tr ( " Sync Activity " ) , text ) ;
2013-11-08 19:21:59 +04:00
}
2013-08-14 18:55:43 +04:00
}
2011-02-17 17:10:06 +03:00
}
2011-02-17 02:21:45 +03:00
2014-11-05 16:52:57 +03:00
int Folder : : slotDiscardDownloadProgress ( )
{
// Delete from journal and from filesystem.
2015-04-27 18:33:59 +03:00
QDir folderpath ( _definition . localPath ) ;
2014-11-05 16:52:57 +03:00
QSet < QString > keep_nothing ;
const QVector < SyncJournalDb : : DownloadInfo > deleted_infos =
2017-05-17 11:55:42 +03:00
_journal . getAndDeleteStaleDownloadInfos ( keep_nothing ) ;
foreach ( const SyncJournalDb : : DownloadInfo & deleted_info , deleted_infos ) {
2014-11-05 16:52:57 +03:00
const QString tmppath = folderpath . filePath ( deleted_info . _tmpfile ) ;
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Deleting temporary file: " < < tmppath ;
2016-01-05 13:58:18 +03:00
FileSystem : : remove ( tmppath ) ;
2014-11-05 16:52:57 +03:00
}
return deleted_infos . size ( ) ;
}
int Folder : : downloadInfoCount ( )
{
return _journal . downloadInfoCount ( ) ;
}
2015-01-16 12:17:19 +03:00
int Folder : : errorBlackListEntryCount ( )
2013-12-03 17:47:32 +04:00
{
2015-01-16 12:17:19 +03:00
return _journal . errorBlackListEntryCount ( ) ;
2013-12-03 17:47:32 +04:00
}
2015-01-16 12:17:19 +03:00
int Folder : : slotWipeErrorBlacklist ( )
2013-12-03 17:02:44 +04:00
{
2015-01-16 12:17:19 +03:00
return _journal . wipeErrorBlacklist ( ) ;
2013-12-03 17:02:44 +04:00
}
2017-05-17 11:55:42 +03:00
void Folder : : slotWatchedPathChanged ( const QString & path )
2014-11-07 13:41:21 +03:00
{
2017-05-17 11:55:42 +03:00
// The folder watcher fires a lot of bogus notifications during
// a sync operation, both for actual user files and the database
// and log. Therefore we check notifications against operations
// the sync is doing to filter out our own changes.
2014-11-07 13:41:21 +03:00
# ifdef Q_OS_MAC
2015-06-16 17:37:04 +03:00
Q_UNUSED ( path )
2017-05-17 11:55:42 +03:00
// On OSX the folder watcher does not report changes done by our
// own process. Therefore nothing needs to be done here!
2014-11-07 13:41:21 +03:00
# else
// Use the path to figure out whether it was our own change
2017-05-17 11:55:42 +03:00
const auto maxNotificationDelay = 15 * 1000 ;
2014-11-07 13:41:21 +03:00
qint64 time = _engine - > timeSinceFileTouched ( path ) ;
if ( time ! = - 1 & & time < maxNotificationDelay ) {
2016-06-03 14:06:11 +03:00
return ;
2014-11-07 13:41:21 +03:00
}
# endif
2016-06-03 14:06:11 +03:00
// Check that the mtime actually changed.
if ( path . startsWith ( this - > path ( ) ) ) {
auto relativePath = path . mid ( this - > path ( ) . size ( ) ) ;
auto record = _journal . getFileRecord ( relativePath ) ;
2017-05-17 11:55:42 +03:00
if ( record . isValid ( ) & & ! FileSystem : : fileChanged ( path , record . _fileSize , Utility : : qDateTimeToTime_t ( record . _modtime ) ) ) {
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Ignoring spurious notification for file " < < relativePath ;
2017-05-17 11:55:42 +03:00
return ; // probably a spurious notification
2016-06-03 14:06:11 +03:00
}
2014-11-07 13:41:21 +03:00
}
2016-06-03 14:06:11 +03:00
emit watchedFileChangedExternally ( path ) ;
2016-10-18 17:04:25 +03:00
// Also schedule this folder for a sync, but only after some delay:
// The sync will not upload files that were changed too recently.
scheduleThisFolderSoon ( ) ;
2014-11-07 13:41:21 +03:00
}
2015-04-24 11:18:33 +03:00
void Folder : : saveToSettings ( ) const
{
2016-11-22 17:30:12 +03:00
// Remove first to make sure we don't get duplicates
removeFromSettings ( ) ;
2015-06-15 16:04:39 +03:00
auto settings = _accountState - > settings ( ) ;
2016-11-22 17:30:12 +03:00
// The folder is saved to backwards-compatible "Folders"
// section only if it has the migrate flag set (i.e. was in
// there before) or if the folder is the only one for the
// given target path.
// This ensures that older clients will not read a configuration
// where two folders for different accounts point at the same
// local folders.
bool oneAccountOnly = true ;
2017-05-17 11:55:42 +03:00
foreach ( Folder * other , FolderMan : : instance ( ) - > map ( ) ) {
2016-11-22 17:30:12 +03:00
if ( other ! = this & & other - > cleanPath ( ) = = this - > cleanPath ( ) ) {
oneAccountOnly = false ;
break ;
}
}
2016-11-23 12:40:17 +03:00
bool compatible = _saveBackwardsCompatible | | oneAccountOnly ;
2016-11-22 17:30:12 +03:00
2016-11-23 12:40:17 +03:00
if ( compatible ) {
2016-11-22 17:30:12 +03:00
settings - > beginGroup ( QLatin1String ( " Folders " ) ) ;
} else {
settings - > beginGroup ( QLatin1String ( " Multifolders " ) ) ;
}
2015-04-24 11:18:33 +03:00
FolderDefinition : : save ( * settings , _definition ) ;
2015-09-17 14:48:05 +03:00
settings - > sync ( ) ;
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Saved folder " < < _definition . alias < < " to settings, status " < < settings - > status ( ) ;
2015-04-24 11:18:33 +03:00
}
void Folder : : removeFromSettings ( ) const
{
2016-11-22 17:30:12 +03:00
auto settings = _accountState - > settings ( ) ;
2015-04-24 11:18:33 +03:00
settings - > beginGroup ( QLatin1String ( " Folders " ) ) ;
2016-06-03 14:10:01 +03:00
settings - > remove ( FolderMan : : escapeAlias ( _definition . alias ) ) ;
2016-11-22 17:30:12 +03:00
settings - > endGroup ( ) ;
settings - > beginGroup ( QLatin1String ( " Multifolders " ) ) ;
settings - > remove ( FolderMan : : escapeAlias ( _definition . alias ) ) ;
2015-04-24 11:18:33 +03:00
}
2017-05-17 11:55:42 +03:00
bool Folder : : isFileExcludedAbsolute ( const QString & fullPath ) const
2016-09-12 16:02:54 +03:00
{
return _engine - > excludedFiles ( ) . isExcluded ( fullPath , path ( ) , _definition . ignoreHiddenFiles ) ;
}
2017-05-17 11:55:42 +03:00
bool Folder : : isFileExcludedRelative ( const QString & relativePath ) const
2015-10-13 13:53:38 +03:00
{
2016-03-09 19:53:18 +03:00
return _engine - > excludedFiles ( ) . isExcluded ( path ( ) + relativePath , path ( ) , _definition . ignoreHiddenFiles ) ;
2015-10-13 13:53:38 +03:00
}
2014-05-13 15:39:00 +04:00
void Folder : : slotTerminateSync ( )
2011-10-18 12:22:24 +04:00
{
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " folder " < < alias ( ) < < " Terminating! " ;
2013-07-22 22:27:42 +04:00
2017-05-17 11:55:42 +03:00
if ( _engine - > isSyncRunning ( ) ) {
2014-03-17 14:47:23 +04:00
_engine - > abort ( ) ;
2013-11-25 01:26:50 +04:00
2014-05-13 15:39:00 +04:00
setSyncState ( SyncResult : : SyncAbortRequested ) ;
2013-07-22 22:27:42 +04:00
}
2011-10-18 12:22:24 +04:00
}
2014-03-28 13:23:09 +04:00
// This removes the csync File database
// This is needed to provide a clean startup again in case another
2013-07-22 22:27:42 +04:00
// local folder is synced to the same ownCloud.
2012-06-11 12:10:07 +04:00
void Folder : : wipe ( )
{
2016-07-10 13:52:47 +03:00
QString stateDbFile = _engine - > journal ( ) - > databaseFilePath ( ) ;
2013-07-22 22:27:42 +04:00
2014-11-06 14:49:02 +03:00
// Delete files that have been partially downloaded.
slotDiscardDownloadProgress ( ) ;
2016-11-22 15:17:04 +03:00
//Unregister the socket API so it does not keep the ._sync_journal file open
2015-10-23 18:24:45 +03:00
FolderMan : : instance ( ) - > socketApi ( ) - > slotUnregisterPath ( alias ( ) ) ;
2013-12-05 19:06:03 +04:00
_journal . close ( ) ; // close the sync journal
2013-07-22 22:27:42 +04:00
QFile file ( stateDbFile ) ;
2017-05-17 11:55:42 +03:00
if ( file . exists ( ) ) {
if ( ! file . remove ( ) ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolder ) < < " Failed to remove existing csync StateDB " < < stateDbFile ;
2013-07-22 22:27:42 +04:00
} else {
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " wipe: Removed csync StateDB " < < stateDbFile ;
2013-07-22 22:27:42 +04:00
}
} else {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolder ) < < " statedb is empty, can not remove. " ;
2013-07-22 22:27:42 +04:00
}
2014-11-06 14:49:02 +03:00
// Also remove other db related files
2017-05-17 11:55:42 +03:00
QFile : : remove ( stateDbFile + " .ctmp " ) ;
QFile : : remove ( stateDbFile + " -shm " ) ;
QFile : : remove ( stateDbFile + " -wal " ) ;
QFile : : remove ( stateDbFile + " -journal " ) ;
2015-10-23 18:24:45 +03:00
2016-04-28 23:43:53 +03:00
if ( canSync ( ) )
FolderMan : : instance ( ) - > socketApi ( ) - > slotRegisterPath ( alias ( ) ) ;
2013-07-22 22:27:42 +04:00
}
2014-09-03 16:25:14 +04:00
bool Folder : : setIgnoredFiles ( )
2013-07-22 22:27:42 +04:00
{
2016-06-20 16:14:13 +03:00
// Note: Doing this on each sync run and on Folder construction is
// unnecessary, because _engine->excludedFiles() persists between
// sync runs. This is not a big problem because ExcludedFiles maintains
// a QSet of files to load.
2016-02-10 23:55:16 +03:00
ConfigFile cfg ;
QString systemList = cfg . excludeFile ( ConfigFile : : SystemScope ) ;
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Adding system ignore list to csync: " < < systemList ;
2017-01-24 19:57:52 +03:00
_engine - > excludedFiles ( ) . addExcludeFilePath ( systemList ) ;
2016-02-10 23:55:16 +03:00
QString userList = cfg . excludeFile ( ConfigFile : : UserScope ) ;
2017-05-17 11:55:42 +03:00
if ( QFile : : exists ( userList ) ) {
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Adding user defined ignore list to csync: " < < userList ;
2016-02-10 23:55:16 +03:00
_engine - > excludedFiles ( ) . addExcludeFilePath ( userList ) ;
2013-07-22 22:27:42 +04:00
}
2014-09-03 16:25:14 +04:00
2016-02-10 23:55:16 +03:00
return _engine - > excludedFiles ( ) . reloadExcludes ( ) ;
2013-07-22 22:27:42 +04:00
}
2013-10-14 18:11:15 +04:00
void Folder : : setProxyDirty ( bool value )
{
_proxyDirty = value ;
}
bool Folder : : proxyDirty ( )
{
return _proxyDirty ;
}
2013-07-22 22:27:42 +04:00
void Folder : : startSync ( const QStringList & pathList )
{
Q_UNUSED ( pathList )
2016-02-10 23:55:16 +03:00
if ( proxyDirty ( ) ) {
2014-01-16 15:07:58 +04:00
setProxyDirty ( false ) ;
2013-07-22 22:27:42 +04:00
}
2014-02-05 23:18:03 +04:00
if ( isBusy ( ) ) {
2017-05-09 15:24:11 +03:00
qCCritical ( lcFolder ) < < " ERROR csync is still running and new sync requested. " ;
2013-07-22 22:27:42 +04:00
return ;
}
_csyncUnavail = false ;
2017-05-29 11:48:21 +03:00
_timeSinceLastSyncStart . start ( ) ;
2017-05-17 11:55:42 +03:00
_syncResult . setStatus ( SyncResult : : SyncPrepare ) ;
2013-07-22 22:27:42 +04:00
emit syncStateChange ( ) ;
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " *** Start syncing " < < remoteUrl ( ) . toString ( ) < < " - client version "
2017-05-17 11:55:42 +03:00
< < qPrintable ( Theme : : instance ( ) - > version ( ) ) ;
2014-09-03 16:25:14 +04:00
2017-01-24 19:57:52 +03:00
_fileLog - > start ( path ( ) ) ;
2017-05-17 11:55:42 +03:00
if ( ! setIgnoredFiles ( ) ) {
2014-09-03 16:25:14 +04:00
slotSyncError ( tr ( " Could not read system exclude file " ) ) ;
2016-01-04 18:46:53 +03:00
QMetaObject : : invokeMethod ( this , " slotSyncFinished " , Qt : : QueuedConnection , Q_ARG ( bool , false ) ) ;
2014-09-03 16:25:14 +04:00
return ;
}
2013-07-22 22:27:42 +04:00
2014-06-07 13:49:41 +04:00
setDirtyNetworkLimits ( ) ;
2017-03-24 17:01:50 +03:00
setSyncOptions ( ) ;
2014-06-07 13:49:41 +04:00
2017-03-24 17:01:50 +03:00
_engine - > setIgnoreHiddenFiles ( _definition . ignoreHiddenFiles ) ;
QMetaObject : : invokeMethod ( _engine . data ( ) , " startSync " , Qt : : QueuedConnection ) ;
emit syncStarted ( ) ;
}
void Folder : : setSyncOptions ( )
{
2017-01-24 12:16:10 +03:00
SyncOptions opt ;
2015-07-07 17:28:48 +03:00
ConfigFile cfgFile ;
2017-03-24 17:01:50 +03:00
2015-07-27 10:54:20 +03:00
auto newFolderLimit = cfgFile . newBigFolderSizeLimit ( ) ;
2017-01-24 12:16:10 +03:00
opt . _newBigFolderSizeLimit = newFolderLimit . first ? newFolderLimit . second * 1000LL * 1000LL : - 1 ; // convert from MB to B
opt . _confirmExternalStorage = cfgFile . confirmExternalStorage ( ) ;
2015-06-11 16:54:39 +03:00
2017-03-24 17:01:50 +03:00
QByteArray chunkSizeEnv = qgetenv ( " OWNCLOUD_CHUNK_SIZE " ) ;
if ( ! chunkSizeEnv . isEmpty ( ) ) {
opt . _initialChunkSize = chunkSizeEnv . toUInt ( ) ;
} else {
opt . _initialChunkSize = cfgFile . chunkSize ( ) ;
}
QByteArray minChunkSizeEnv = qgetenv ( " OWNCLOUD_MIN_CHUNK_SIZE " ) ;
if ( ! minChunkSizeEnv . isEmpty ( ) ) {
opt . _minChunkSize = minChunkSizeEnv . toUInt ( ) ;
} else {
opt . _minChunkSize = cfgFile . minChunkSize ( ) ;
}
QByteArray maxChunkSizeEnv = qgetenv ( " OWNCLOUD_MAX_CHUNK_SIZE " ) ;
if ( ! maxChunkSizeEnv . isEmpty ( ) ) {
opt . _maxChunkSize = maxChunkSizeEnv . toUInt ( ) ;
} else {
opt . _maxChunkSize = cfgFile . maxChunkSize ( ) ;
}
2016-04-12 12:49:52 +03:00
2017-03-24 17:01:50 +03:00
// Previously min/max chunk size values didn't exist, so users might
// have setups where the chunk size exceeds the new min/max default
// values. To cope with this, adjust min/max to always include the
// initial chunk size value.
opt . _minChunkSize = qMin ( opt . _minChunkSize , opt . _initialChunkSize ) ;
opt . _maxChunkSize = qMax ( opt . _maxChunkSize , opt . _initialChunkSize ) ;
2013-08-05 16:35:01 +04:00
2017-03-24 17:01:50 +03:00
QByteArray targetChunkUploadDurationEnv = qgetenv ( " OWNCLOUD_TARGET_CHUNK_UPLOAD_DURATION " ) ;
if ( ! targetChunkUploadDurationEnv . isEmpty ( ) ) {
opt . _targetChunkUploadDuration = targetChunkUploadDurationEnv . toUInt ( ) ;
} else {
opt . _targetChunkUploadDuration = cfgFile . targetChunkUploadDuration ( ) ;
}
_engine - > setSyncOptions ( opt ) ;
2012-06-11 12:10:07 +04:00
}
2014-01-31 20:29:50 +04:00
void Folder : : setDirtyNetworkLimits ( )
{
2016-03-09 19:53:18 +03:00
ConfigFile cfg ;
int downloadLimit = - 75 ; // 75%
int useDownLimit = cfg . useDownloadLimit ( ) ;
if ( useDownLimit > = 1 ) {
downloadLimit = cfg . downloadLimit ( ) * 1000 ;
} else if ( useDownLimit = = 0 ) {
downloadLimit = 0 ;
}
2014-06-07 13:49:41 +04:00
2016-03-09 19:53:18 +03:00
int uploadLimit = - 75 ; // 75%
int useUpLimit = cfg . useUploadLimit ( ) ;
2017-05-17 11:55:42 +03:00
if ( useUpLimit > = 1 ) {
2016-03-09 19:53:18 +03:00
uploadLimit = cfg . uploadLimit ( ) * 1000 ;
} else if ( useUpLimit = = 0 ) {
uploadLimit = 0 ;
2014-01-31 20:29:50 +04:00
}
2016-03-09 19:53:18 +03:00
_engine - > setNetworkLimits ( uploadLimit , downloadLimit ) ;
2014-01-31 20:29:50 +04:00
}
2014-10-22 15:29:59 +04:00
2017-05-17 11:55:42 +03:00
void Folder : : slotSyncError ( const QString & err )
2013-07-22 22:27:42 +04:00
{
2017-01-25 13:28:18 +03:00
_syncResult . appendErrorString ( err ) ;
2013-07-22 22:27:42 +04:00
}
2014-03-17 14:47:23 +04:00
void Folder : : slotSyncStarted ( )
2013-07-22 22:27:42 +04:00
{
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " #### Propagation start #################################################### " ;
2013-07-22 22:27:42 +04:00
_syncResult . setStatus ( SyncResult : : SyncRunning ) ;
emit syncStateChange ( ) ;
}
void Folder : : slotCsyncUnavailable ( )
{
_csyncUnavail = true ;
}
2015-10-29 18:43:30 +03:00
void Folder : : slotSyncFinished ( bool success )
2013-07-22 22:27:42 +04:00
{
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " Client version " < < qPrintable ( Theme : : instance ( ) - > version ( ) )
2017-05-17 11:55:42 +03:00
< < " Qt " < < qVersion ( )
# if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
< < " SSL " < < QSslSocket : : sslLibraryVersionString ( ) . toUtf8 ( ) . data ( )
2015-07-30 15:11:29 +03:00
# endif
2017-05-17 11:55:42 +03:00
;
2015-07-30 15:11:29 +03:00
2017-01-25 13:28:18 +03:00
bool syncError = ! _syncResult . errorStrings ( ) . isEmpty ( ) ;
2017-05-17 11:55:42 +03:00
if ( syncError ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolder ) < < " SyncEngine finished with ERROR " ;
2014-10-10 12:12:30 +04:00
} else {
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " SyncEngine finished without problem. " ;
2014-10-10 12:12:30 +04:00
}
2016-06-09 15:10:47 +03:00
_fileLog - > finish ( ) ;
2017-01-25 13:28:18 +03:00
showSyncResultPopup ( ) ;
2014-03-26 21:10:59 +04:00
2016-12-06 15:18:59 +03:00
auto anotherSyncNeeded = _engine - > isAnotherSyncNeeded ( ) ;
2013-07-22 22:27:42 +04:00
2017-01-25 13:28:18 +03:00
if ( syncError ) {
2013-07-22 22:27:42 +04:00
_syncResult . setStatus ( SyncResult : : Error ) ;
} else if ( _csyncUnavail ) {
2014-08-15 17:01:01 +04:00
_syncResult . setStatus ( SyncResult : : Error ) ;
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolder ) < < " csync not available. " ;
2017-05-17 11:55:42 +03:00
} else if ( _syncResult . foundFilesNotSynced ( ) ) {
2013-08-02 16:22:01 +04:00
_syncResult . setStatus ( SyncResult : : Problem ) ;
2017-05-17 11:55:42 +03:00
} else if ( _definition . paused ) {
2016-11-29 11:56:45 +03:00
// Maybe the sync was terminated because the user paused the folder
_syncResult . setStatus ( SyncResult : : Paused ) ;
2013-07-22 22:27:42 +04:00
} else {
_syncResult . setStatus ( SyncResult : : Success ) ;
}
2014-10-24 12:57:16 +04:00
// Count the number of syncs that have failed in a row.
if ( _syncResult . status ( ) = = SyncResult : : Success
2017-05-17 11:55:42 +03:00
| | _syncResult . status ( ) = = SyncResult : : Problem ) {
2014-10-24 12:57:16 +04:00
_consecutiveFailingSyncs = 0 ;
2017-05-17 11:55:42 +03:00
} else {
2014-10-24 12:57:16 +04:00
_consecutiveFailingSyncs + + ;
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " the last " < < _consecutiveFailingSyncs < < " syncs failed " ;
2014-10-24 12:57:16 +04:00
}
2015-10-29 18:43:30 +03:00
if ( _syncResult . status ( ) = = SyncResult : : Success & & success ) {
2015-10-05 07:21:19 +03:00
// Clear the white list as all the folders that should be on that list are sync-ed
2015-06-11 16:46:01 +03:00
journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncWhiteList , QStringList ( ) ) ;
}
2013-08-14 18:55:43 +04:00
emit syncStateChange ( ) ;
2014-05-27 13:33:08 +04:00
// The syncFinished result that is to be triggered here makes the folderman
2015-10-05 07:21:19 +03:00
// clear the current running sync folder marker.
2014-05-27 13:33:08 +04:00
// Lets wait a bit to do that because, as long as this marker is not cleared,
// file system change notifications are ignored for that folder. And it takes
// some time under certain conditions to make the file system notifications
// all come in.
2017-05-17 11:55:42 +03:00
QTimer : : singleShot ( 200 , this , SLOT ( slotEmitFinishedDelayed ( ) ) ) ;
2014-05-27 13:33:08 +04:00
2015-01-16 12:52:26 +03:00
_lastSyncDuration = _timeSinceLastSyncStart . elapsed ( ) ;
2017-05-29 11:48:21 +03:00
_timeSinceLastSyncDone . start ( ) ;
2014-10-24 14:52:24 +04:00
// Increment the follow-up sync counter if necessary.
2016-12-06 15:18:59 +03:00
if ( anotherSyncNeeded = = ImmediateFollowUp ) {
2014-10-24 14:52:24 +04:00
_consecutiveFollowUpSyncs + + ;
2017-03-30 14:46:20 +03:00
qCInfo ( lcFolder ) < < " another sync was requested by the finished sync, this has "
2017-05-17 11:55:42 +03:00
< < " happened " < < _consecutiveFollowUpSyncs < < " times " ;
2014-09-10 19:25:13 +04:00
} else {
2014-10-24 14:52:24 +04:00
_consecutiveFollowUpSyncs = 0 ;
2014-09-10 19:25:13 +04:00
}
2014-10-24 14:52:24 +04:00
// Maybe force a follow-up sync to take place, but only a couple of times.
2017-05-17 11:55:42 +03:00
if ( anotherSyncNeeded = = ImmediateFollowUp & & _consecutiveFollowUpSyncs < = 3 ) {
2016-10-18 17:04:25 +03:00
// Sometimes another sync is requested because a local file is still
// changing, so wait at least a small amount of time before syncing
// the folder again.
scheduleThisFolderSoon ( ) ;
2014-10-24 14:52:24 +04:00
}
2014-05-27 13:33:08 +04:00
}
void Folder : : slotEmitFinishedDelayed ( )
{
2017-05-17 11:55:42 +03:00
emit syncFinished ( _syncResult ) ;
2013-07-22 22:27:42 +04:00
}
2014-05-27 13:33:08 +04:00
2014-08-19 16:08:31 +04:00
void Folder : : slotFolderDiscovered ( bool , QString folderName )
2014-08-15 17:00:10 +04:00
{
2015-01-30 15:36:20 +03:00
ProgressInfo pi ;
2014-08-15 17:00:10 +04:00
pi . _currentDiscoveredFolder = folderName ;
2015-06-02 20:45:23 +03:00
emit progressInfo ( pi ) ;
2014-08-15 17:00:10 +04:00
ProgressDispatcher : : instance ( ) - > setProgressInfo ( alias ( ) , pi ) ;
}
2014-05-27 13:33:08 +04:00
2013-11-25 19:16:33 +04:00
// the progress comes without a folder and the valid path set. Add that here
// and hand the result over to the progress dispatcher.
2015-01-30 15:36:20 +03:00
void Folder : : slotTransmissionProgress ( const ProgressInfo & pi )
2013-07-22 22:27:42 +04:00
{
2015-06-02 20:45:23 +03:00
emit progressInfo ( pi ) ;
2014-03-14 16:03:16 +04:00
ProgressDispatcher : : instance ( ) - > setProgressInfo ( alias ( ) , pi ) ;
2013-07-22 22:27:42 +04:00
}
2015-08-11 14:45:02 +03:00
// a item is completed: count the errors and forward to the ProgressDispatcher
2017-01-25 13:12:38 +03:00
void Folder : : slotItemCompleted ( const SyncFileItemPtr & item )
2014-06-06 17:52:55 +04:00
{
2017-01-25 13:28:18 +03:00
// add new directories or remove gone away dirs to the watcher
2017-05-17 11:55:42 +03:00
if ( item - > _isDirectory & & item - > _instruction = = CSYNC_INSTRUCTION_NEW ) {
FolderMan : : instance ( ) - > addMonitorPath ( alias ( ) , path ( ) + item - > _file ) ;
2017-01-25 13:28:18 +03:00
}
2017-05-17 11:55:42 +03:00
if ( item - > _isDirectory & & item - > _instruction = = CSYNC_INSTRUCTION_REMOVE ) {
FolderMan : : instance ( ) - > removeMonitorPath ( alias ( ) , path ( ) + item - > _file ) ;
2014-06-06 17:52:55 +04:00
}
2017-01-25 13:28:18 +03:00
_syncResult . processCompletedItem ( item ) ;
2017-01-25 13:12:38 +03:00
_fileLog - > logItem ( * item ) ;
2017-01-25 16:09:44 +03:00
emit ProgressDispatcher : : instance ( ) - > itemCompleted ( alias ( ) , item ) ;
2014-06-06 17:52:55 +04:00
}
2017-01-26 11:03:01 +03:00
void Folder : : slotNewBigFolderDiscovered ( const QString & newF , bool isExternal )
2015-06-11 16:46:01 +03:00
{
auto newFolder = newF ;
if ( ! newFolder . endsWith ( QLatin1Char ( ' / ' ) ) ) {
newFolder + = QLatin1Char ( ' / ' ) ;
}
auto journal = journalDb ( ) ;
// Add the entry to the blacklist if it is neither in the blacklist or whitelist already
2016-04-06 16:01:28 +03:00
bool ok1 , ok2 ;
auto blacklist = journal - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , & ok1 ) ;
auto whitelist = journal - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncWhiteList , & ok2 ) ;
if ( ok1 & & ok2 & & ! blacklist . contains ( newFolder ) & & ! whitelist . contains ( newFolder ) ) {
2015-06-11 16:46:01 +03:00
blacklist . append ( newFolder ) ;
journal - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , blacklist ) ;
}
// And add the entry to the undecided list and signal the UI
2016-04-06 16:01:28 +03:00
auto undecidedList = journal - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , & ok1 ) ;
2017-05-17 11:55:42 +03:00
if ( ok1 ) {
2016-04-06 16:01:28 +03:00
if ( ! undecidedList . contains ( newFolder ) ) {
undecidedList . append ( newFolder ) ;
journal - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , undecidedList ) ;
emit newBigFolderDiscovered ( newFolder ) ;
}
2017-05-17 11:55:42 +03:00
QString message = ! isExternal ? ( tr ( " A new folder larger than %1 MB has been added: %2. \n " )
. arg ( ConfigFile ( ) . newBigFolderSizeLimit ( ) . second )
. arg ( newF ) )
: ( tr ( " A folder from an external storage has been added. \n " ) ) ;
2017-01-26 11:03:01 +03:00
message + = tr ( " Please go in the settings to select it if you wish to download it. " ) ;
2015-07-27 11:33:05 +03:00
2016-04-06 16:01:28 +03:00
auto logger = Logger : : instance ( ) ;
logger - > postOptionalGuiLog ( Theme : : instance ( ) - > appNameGUI ( ) , message ) ;
}
2015-06-11 16:46:01 +03:00
}
2016-06-09 15:28:15 +03:00
void Folder : : slotLogPropagationStart ( )
{
_fileLog - > logLap ( " Propagation starts " ) ;
}
2016-10-18 17:04:25 +03:00
void Folder : : slotScheduleThisFolder ( )
{
2016-10-19 12:03:13 +03:00
FolderMan : : instance ( ) - > scheduleFolder ( this ) ;
2016-10-18 17:04:25 +03:00
}
2015-06-11 16:46:01 +03:00
2016-10-18 17:04:25 +03:00
void Folder : : scheduleThisFolderSoon ( )
{
if ( ! _scheduleSelfTimer . isActive ( ) ) {
_scheduleSelfTimer . start ( ) ;
}
}
2014-06-06 17:52:55 +04:00
2016-11-23 12:40:17 +03:00
void Folder : : setSaveBackwardsCompatible ( bool save )
{
_saveBackwardsCompatible = save ;
}
2017-02-08 14:33:46 +03:00
void Folder : : slotAboutToRemoveAllFiles ( SyncFileItem : : Direction dir , bool * cancel )
2013-07-22 22:27:42 +04:00
{
2016-02-22 18:14:22 +03:00
ConfigFile cfgFile ;
if ( ! cfgFile . promptDeleteFiles ( ) )
return ;
2017-05-17 11:55:42 +03:00
QString msg = dir = = SyncFileItem : : Down ? tr ( " All files in the sync folder '%1' folder were deleted on the server. \n "
" These deletes will be synchronized to your local sync folder, making such files "
" unavailable unless you have a right to restore. \n "
" If you decide to keep the files, they will be re-synced with the server if you have rights to do so. \n "
" If you decide to delete the files, they will be unavailable to you, unless you are the owner. " )
: tr ( " All the files in your local sync folder '%1' were deleted. These deletes will be "
" synchronized with your server, making such files unavailable unless restored. \n "
" Are you sure you want to sync those actions with the server? \n "
" If this was an accident and you decide to keep your files, they will be re-synced from the server. " ) ;
2013-07-22 22:27:42 +04:00
QMessageBox msgBox ( QMessageBox : : Warning , tr ( " Remove All Files? " ) ,
2017-05-17 11:55:42 +03:00
msg . arg ( shortGuiLocalPath ( ) ) ) ;
2017-02-20 15:58:35 +03:00
msgBox . setWindowFlags ( msgBox . windowFlags ( ) | Qt : : WindowStaysOnTopHint ) ;
2013-07-22 22:27:42 +04:00
msgBox . addButton ( tr ( " Remove all files " ) , QMessageBox : : DestructiveRole ) ;
2017-05-17 11:55:42 +03:00
QPushButton * keepBtn = msgBox . addButton ( tr ( " Keep files " ) , QMessageBox : : AcceptRole ) ;
2013-07-22 22:27:42 +04:00
if ( msgBox . exec ( ) = = - 1 ) {
* cancel = true ;
return ;
}
* cancel = msgBox . clickedButton ( ) = = keepBtn ;
if ( * cancel ) {
2017-04-10 17:15:28 +03:00
FileSystem : : setFolderMinimumPermissions ( path ( ) ) ;
2017-02-15 15:27:41 +03:00
journalDb ( ) - > clearFileTable ( ) ;
2014-10-08 12:41:03 +04:00
_lastEtag . clear ( ) ;
2016-10-18 17:04:25 +03:00
slotScheduleThisFolder ( ) ;
2013-07-22 22:27:42 +04:00
}
}
2015-04-24 11:18:33 +03:00
2016-01-05 13:47:17 +03:00
void Folder : : slotAboutToRestoreBackup ( bool * restore )
{
QString msg =
2016-05-27 18:13:18 +03:00
tr ( " This sync would reset the files to an earlier time in the sync folder '%1'. \n "
2016-01-05 13:47:17 +03:00
" This might be because a backup was restored on the server. \n "
" Continuing the sync as normal will cause all your files to be overwritten by an older "
" file in an earlier state. "
" Do you want to keep your local most recent files as conflict files? " ) ;
QMessageBox msgBox ( QMessageBox : : Warning , tr ( " Backup detected " ) ,
2017-05-17 11:55:42 +03:00
msg . arg ( shortGuiLocalPath ( ) ) ) ;
2017-02-20 15:58:35 +03:00
msgBox . setWindowFlags ( msgBox . windowFlags ( ) | Qt : : WindowStaysOnTopHint ) ;
2016-01-05 13:47:17 +03:00
msgBox . addButton ( tr ( " Normal Synchronisation " ) , QMessageBox : : DestructiveRole ) ;
2017-05-17 11:55:42 +03:00
QPushButton * keepBtn = msgBox . addButton ( tr ( " Keep Local Files as Conflict " ) , QMessageBox : : AcceptRole ) ;
2016-01-05 13:47:17 +03:00
if ( msgBox . exec ( ) = = - 1 ) {
* restore = true ;
return ;
}
* restore = msgBox . clickedButton ( ) = = keepBtn ;
}
2015-04-24 11:18:33 +03:00
2017-05-17 11:55:42 +03:00
void FolderDefinition : : save ( QSettings & settings , const FolderDefinition & folder )
2015-04-24 11:18:33 +03:00
{
2015-09-02 17:05:58 +03:00
settings . beginGroup ( FolderMan : : escapeAlias ( folder . alias ) ) ;
2015-04-24 11:18:33 +03:00
settings . setValue ( QLatin1String ( " localPath " ) , folder . localPath ) ;
2016-11-23 12:40:17 +03:00
settings . setValue ( QLatin1String ( " journalPath " ) , folder . journalPath ) ;
2015-04-24 11:18:33 +03:00
settings . setValue ( QLatin1String ( " targetPath " ) , folder . targetPath ) ;
settings . setValue ( QLatin1String ( " paused " ) , folder . paused ) ;
2015-07-13 23:15:02 +03:00
settings . setValue ( QLatin1String ( " ignoreHiddenFiles " ) , folder . ignoreHiddenFiles ) ;
2015-04-24 11:18:33 +03:00
settings . endGroup ( ) ;
}
2017-05-17 11:55:42 +03:00
bool FolderDefinition : : load ( QSettings & settings , const QString & alias ,
FolderDefinition * folder )
2015-04-24 11:18:33 +03:00
{
settings . beginGroup ( alias ) ;
2015-09-02 17:05:58 +03:00
folder - > alias = FolderMan : : unescapeAlias ( alias ) ;
2015-04-24 11:18:33 +03:00
folder - > localPath = settings . value ( QLatin1String ( " localPath " ) ) . toString ( ) ;
2016-11-23 12:40:17 +03:00
folder - > journalPath = settings . value ( QLatin1String ( " journalPath " ) ) . toString ( ) ;
2015-04-24 11:18:33 +03:00
folder - > targetPath = settings . value ( QLatin1String ( " targetPath " ) ) . toString ( ) ;
folder - > paused = settings . value ( QLatin1String ( " paused " ) ) . toBool ( ) ;
2015-07-13 23:15:02 +03:00
folder - > ignoreHiddenFiles = settings . value ( QLatin1String ( " ignoreHiddenFiles " ) , QVariant ( true ) ) . toBool ( ) ;
2015-04-24 11:18:33 +03:00
settings . endGroup ( ) ;
2015-09-17 13:14:35 +03:00
// Old settings can contain paths with native separators. In the rest of the
// code we assum /, so clean it up now.
folder - > localPath = prepareLocalPath ( folder - > localPath ) ;
2016-11-23 12:40:17 +03:00
// Target paths also have a convention
folder - > targetPath = prepareTargetPath ( folder - > targetPath ) ;
2015-04-24 11:18:33 +03:00
return true ;
}
2017-05-17 11:55:42 +03:00
QString FolderDefinition : : prepareLocalPath ( const QString & path )
2015-09-17 13:14:35 +03:00
{
QString p = QDir : : fromNativeSeparators ( path ) ;
if ( ! p . endsWith ( QLatin1Char ( ' / ' ) ) ) {
p . append ( QLatin1Char ( ' / ' ) ) ;
}
return p ;
}
2016-11-23 12:40:17 +03:00
QString FolderDefinition : : prepareTargetPath ( const QString & path )
{
QString p = path ;
if ( p . endsWith ( QLatin1Char ( ' / ' ) ) ) {
p . chop ( 1 ) ;
}
// Doing this second ensures the empty string or "/" come
// out as "/".
if ( ! p . startsWith ( QLatin1Char ( ' / ' ) ) ) {
p . prepend ( QLatin1Char ( ' / ' ) ) ;
}
return p ;
}
QString FolderDefinition : : absoluteJournalPath ( ) const
{
return QDir ( localPath ) . filePath ( journalPath ) ;
}
QString FolderDefinition : : defaultJournalPath ( AccountPtr account )
{
2017-06-16 16:43:21 +03:00
return SyncJournalDb : : makeDbName ( localPath , account - > url ( ) , targetPath , account - > credentials ( ) - > user ( ) ) ;
2016-11-23 12:40:17 +03:00
}
2014-11-10 00:34:07 +03:00
} // namespace OCC