Merge pull request #1 from owncloud/master

Merge with owncloud:master
This commit is contained in:
Tom Swartz 2013-11-25 12:29:22 -08:00
commit 738f026c41
70 changed files with 10707 additions and 11140 deletions

View file

@ -351,18 +351,13 @@ SectionEnd
SectionGroup "Shortcuts" SectionGroup "Shortcuts"
!ifdef OPTION_SECTION_SC_START_MENU !ifdef OPTION_SECTION_SC_START_MENU
${MementoSection} "Start Menu Program Group" SEC_START_MENU ${MementoSection} "Start Menu Program Shortcut" SEC_START_MENU
SectionIn 1 2 3 SectionIn 1 2 3
SetDetailsPrint textonly SetDetailsPrint textonly
DetailPrint "Adding shortcuts for the ${APPLICATION_NAME} program group to the Start Menu." DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
SetDetailsPrint listonly SetDetailsPrint listonly
SetShellVarContext all SetShellVarContext all
RMDir /r "$SMPROGRAMS\${APPLICATION_NAME}" CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_EXECUTABLE}"
CreateDirectory "$SMPROGRAMS\${APPLICATION_NAME}"
;CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\LICENSE.lnk" "$INSTDIR\LICENSE.txt"
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_EXECUTABLE}"
;CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Release notes.lnk" "$INSTDIR\NOTES.txt"
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe"
SetShellVarContext current SetShellVarContext current
${MementoSectionEnd} ${MementoSectionEnd}
!endif !endif
@ -395,7 +390,7 @@ ${MementoSectionDone}
;-------------------------------- ;--------------------------------
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APPLICATION} "${APPLICATION_NAME} essentials." !insertmacro MUI_DESCRIPTION_TEXT ${SEC_APPLICATION} "${APPLICATION_NAME} essentials."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} program group." !insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} shortcut."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for ${APPLICATION_NAME}." !insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for ${APPLICATION_NAME}."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for ${APPLICATION_NAME}." !insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for ${APPLICATION_NAME}."
!insertmacro MUI_FUNCTION_DESCRIPTION_END !insertmacro MUI_FUNCTION_DESCRIPTION_END
@ -503,7 +498,7 @@ Section Uninstall
;Start menu shortcuts. ;Start menu shortcuts.
!ifdef OPTION_SECTION_SC_START_MENU !ifdef OPTION_SECTION_SC_START_MENU
SetShellVarContext all SetShellVarContext all
RMDir /r "$SMPROGRAMS\${APPLICATION_NAME}" Delete "$SMPROGRAMS\${APPLICATION_NAME}.lnk"
SetShellVarContext current SetShellVarContext current
!endif !endif

View file

@ -70,9 +70,10 @@ Next, install the cross-compiler packages and the cross-compiled dependencies::
zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \ zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \ mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
mingw32-headers mingw32-runtime site-config \ mingw32-headers mingw32-runtime site-config mingw32-libqt4-sql
mingw32-libsqlite-devel mingw32-dlfcn-devel mingw32-libssh2-devel \ mingw32-libqt4-sql-sqlite mingw32-libsqlite-devel \
kdewin-png2ico mingw32-libqt4 mingw32-libqt4-devel mingw32-libgcrypt \ mingw32-dlfcn-devel mingw32-libssh2-devel kdewin-png2ico \
mingw32-libqt4 mingw32-libqt4-devel mingw32-libgcrypt \
mingw32-libgnutls mingw32-libneon-openssl mingw32-libneon-devel \ mingw32-libgnutls mingw32-libneon-openssl mingw32-libneon-devel \
mingw32-libbeecrypt mingw32-libopenssl mingw32-openssl \ mingw32-libbeecrypt mingw32-libopenssl mingw32-openssl \
mingw32-libpng-devel mingw32-libsqlite mingw32-qtkeychain \ mingw32-libpng-devel mingw32-libsqlite mingw32-qtkeychain \

View file

@ -343,7 +343,6 @@ else()
install(FILES ${qt_I18N} DESTINATION ${QM_DIR}) install(FILES ${qt_I18N} DESTINATION ${QM_DIR})
file(GLOB qtkeychain_I18N ${QT_TRANSLATIONS_DIR}/qtkeychain*.qm) file(GLOB qtkeychain_I18N ${QT_TRANSLATIONS_DIR}/qtkeychain*.qm)
install(FILES ${qtkeychain_I18N} DESTINATION ${QM_DIR}) install(FILES ${qtkeychain_I18N} DESTINATION ${QM_DIR})
list(APPEND dirs "/usr/local/lib")
endif() endif()
@ -365,7 +364,7 @@ install(TARGETS ${APPLICATION_EXECUTABLE}
# currently it needs to be done because the code right above needs to be executed no matter # currently it needs to be done because the code right above needs to be executed no matter
# if building a bundle or not and the install_qt4_executable needs to be called afterwards # if building a bundle or not and the install_qt4_executable needs to be called afterwards
if(BUILD_OWNCLOUD_OSX_BUNDLE) if(BUILD_OWNCLOUD_OSX_BUNDLE)
install_qt_executable(${OWNCLOUD_OSX_BUNDLE} "qsqlite" "" ${dirs}) install_qt_executable(${OWNCLOUD_OSX_BUNDLE} "qsqlite")
endif() endif()
find_program(KRAZY2_EXECUTABLE krazy2) find_program(KRAZY2_EXECUTABLE krazy2)

View file

@ -19,6 +19,7 @@
#include <csync.h> #include <csync.h>
class QNetworkAccessManager; class QNetworkAccessManager;
class QNetworkReply;
namespace Mirall namespace Mirall
{ {
class Account; class Account;
@ -37,7 +38,11 @@ public:
virtual QNetworkAccessManager* getQNAM() const = 0; virtual QNetworkAccessManager* getQNAM() const = 0;
virtual bool ready() const = 0; virtual bool ready() const = 0;
virtual void fetch(Account *account) = 0; virtual void fetch(Account *account) = 0;
virtual bool stillValid(QNetworkReply *reply) = 0;
virtual bool fetchFromUser(Account *account) = 0;
virtual void persist(Account *account) = 0; virtual void persist(Account *account) = 0;
/** Invalidates auth token, or password for basic auth */
virtual void invalidateToken(Account *account) = 0;
Q_SIGNALS: Q_SIGNALS:

View file

@ -50,6 +50,18 @@ bool DummyCredentials::ready() const
return true; return true;
} }
bool DummyCredentials::stillValid(QNetworkReply *reply)
{
Q_UNUSED(reply)
return true;
}
bool DummyCredentials::fetchFromUser(Account *account)
{
Q_UNUSED(account)
return false;
}
void DummyCredentials::fetch(Account*) void DummyCredentials::fetch(Account*)
{ {
Q_EMIT(fetched()); Q_EMIT(fetched());

View file

@ -31,8 +31,11 @@ public:
QString user() const; QString user() const;
QNetworkAccessManager* getQNAM() const; QNetworkAccessManager* getQNAM() const;
bool ready() const; bool ready() const;
bool stillValid(QNetworkReply *reply);
bool fetchFromUser(Account *account);
void fetch(Account*); void fetch(Account*);
void persist(Account*); void persist(Account*);
void invalidateToken(Account *) {}
}; };
} // ns Mirall } // ns Mirall

View file

@ -17,6 +17,7 @@
#include <QDebug> #include <QDebug>
#include <QNetworkReply> #include <QNetworkReply>
#include <QSettings> #include <QSettings>
#include <QInputDialog>
#include <qtkeychain/keychain.h> #include <qtkeychain/keychain.h>
@ -29,6 +30,8 @@
using namespace QKeychain; using namespace QKeychain;
Q_DECLARE_METATYPE(Mirall::Account*)
namespace Mirall namespace Mirall
{ {
@ -83,6 +86,7 @@ protected:
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64(); QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
QNetworkRequest req(request); QNetworkRequest req(request);
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash); req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
return MirallAccessManager::createRequest(op, req, outgoingData); return MirallAccessManager::createRequest(op, req, outgoingData);
} }
private: private:
@ -180,9 +184,28 @@ void HttpCredentials::fetch(Account *account)
job->setInsecureFallback(true); job->setInsecureFallback(true);
job->setKey(keychainKey(account->url().toString(), _user)); job->setKey(keychainKey(account->url().toString(), _user));
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*))); connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->setProperty("account", QVariant::fromValue(account));
job->start(); job->start();
} }
} }
bool HttpCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
// returned if user or password is incorrect
&& (reply->error() != QNetworkReply::OperationCanceledError));
}
bool HttpCredentials::fetchFromUser(Account *account)
{
bool ok = false;
QString password = queryPassword(&ok);
if (ok) {
_password = password;
_ready = true;
persist(account);
}
return ok;
}
void HttpCredentials::slotReadJobDone(QKeychain::Job *job) void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
{ {
@ -196,9 +219,43 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
Q_EMIT fetched(); Q_EMIT fetched();
break; break;
default: default:
if (!_user.isEmpty()) {
bool ok;
QString pwd = queryPassword(&ok);
if (ok) {
_password = pwd;
_ready = true;
persist(qvariant_cast<Account*>(readJob->property("account")));
Q_EMIT fetched();
break;
}
}
qDebug() << "Error while reading password" << job->errorString(); qDebug() << "Error while reading password" << job->errorString();
} }
}
QString HttpCredentials::queryPassword(bool *ok)
{
qDebug() << AccountManager::instance()->account()->state();
if (ok) {
QString str = QInputDialog::getText(0, tr("Enter Password"),
tr("Please enter %1 password for user '%2':")
.arg(Theme::instance()->appNameGUI(), _user),
QLineEdit::Password, QString(), ok);
qDebug() << AccountManager::instance()->account()->state();
return str;
} else {
return QString();
}
}
void HttpCredentials::invalidateToken(Account *account)
{
_password = QString();
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setKey(keychainKey(account->url().toString(), _user));
job->start();
_ready = false;
} }
void HttpCredentials::persist(Account *account) void HttpCredentials::persist(Account *account)

View file

@ -24,7 +24,7 @@ class QNetworkReply;
class QAuthenticator; class QAuthenticator;
namespace QKeychain { namespace QKeychain {
class Job; class Job;
} }
namespace Mirall namespace Mirall
@ -45,9 +45,13 @@ public:
QNetworkAccessManager* getQNAM() const; QNetworkAccessManager* getQNAM() const;
bool ready() const; bool ready() const;
void fetch(Account *account); void fetch(Account *account);
bool stillValid(QNetworkReply *reply);
bool fetchFromUser(Account *account);
void persist(Account *account); void persist(Account *account);
QString user() const; QString user() const;
QString password() const; QString password() const;
QString queryPassword(bool *ok);
void invalidateToken(Account *account);
private Q_SLOTS: private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*); void slotAuthentication(QNetworkReply*, QAuthenticator*);

View file

@ -13,14 +13,16 @@
#include <QEventLoop> #include <QEventLoop>
#include "mirall/account.h"
#include "creds/shibboleth/shibbolethrefresher.h" #include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h" #include "creds/shibbolethcredentials.h"
namespace Mirall namespace Mirall
{ {
ShibbolethRefresher::ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent) ShibbolethRefresher::ShibbolethRefresher(Account *account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
: QObject(parent), : QObject(parent),
_account(account),
_creds(creds), _creds(creds),
_csync_ctx(csync_ctx) _csync_ctx(csync_ctx)
{} {}
@ -33,7 +35,8 @@ void ShibbolethRefresher::refresh()
this, SLOT(onInvalidatedAndFetched(QByteArray))); this, SLOT(onInvalidatedAndFetched(QByteArray)));
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)), connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit())); &loop, SLOT(quit()));
QMetaObject::invokeMethod(_creds, "invalidateAndFetch", Qt::QueuedConnection); QMetaObject::invokeMethod(_creds, "invalidateAndFetch",Qt::QueuedConnection,
Q_ARG(Account*, _account));
loop.exec(); loop.exec();
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)), disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit())); &loop, SLOT(quit()));

View file

@ -23,6 +23,7 @@ class QByteArray;
namespace Mirall namespace Mirall
{ {
class Account;
class ShibbolethCredentials; class ShibbolethCredentials;
class ShibbolethRefresher : public QObject class ShibbolethRefresher : public QObject
@ -30,7 +31,7 @@ class ShibbolethRefresher : public QObject
Q_OBJECT Q_OBJECT
public: public:
ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0); ShibbolethRefresher(Account *account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
void refresh(); void refresh();
@ -38,6 +39,7 @@ private Q_SLOTS:
void onInvalidatedAndFetched(const QByteArray& cookieData); void onInvalidatedAndFetched(const QByteArray& cookieData);
private: private:
Account* _account;
ShibbolethCredentials* _creds; ShibbolethCredentials* _creds;
CSYNC* _csync_ctx; CSYNC* _csync_ctx;
}; };

View file

@ -46,7 +46,8 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
QMutex mutex; QMutex mutex;
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(AccountManager::instance()->account()->credentials()); Account *account = AccountManager::instance()->account();
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
if (!creds) { if (!creds) {
@ -54,7 +55,7 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
return 1; return 1;
} }
ShibbolethRefresher refresher(creds, csync_ctx); ShibbolethRefresher refresher(account, creds, csync_ctx);
// blocks // blocks
refresher.refresh(); refresher.refresh();
@ -191,6 +192,18 @@ void ShibbolethCredentials::fetch(Account *account)
} }
} }
bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
{
Q_UNUSED(reply)
return true;
}
bool ShibbolethCredentials::fetchFromUser(Account *account)
{
Q_UNUSED(account)
return false;
}
void ShibbolethCredentials::persist(Account* /*account*/) void ShibbolethCredentials::persist(Account* /*account*/)
{ {
ShibbolethConfigFile cfg; ShibbolethConfigFile cfg;
@ -198,6 +211,14 @@ void ShibbolethCredentials::persist(Account* /*account*/)
cfg.storeCookies(_otherCookies); cfg.storeCookies(_otherCookies);
} }
void ShibbolethCredentials::invalidateToken(Account *account)
{
Q_UNUSED(account)
_shibCookie.setValue("");
// ### access to ctx missing, but might not be required at all
//csync_set_module_property(ctx, "session_key", "");
}
void ShibbolethCredentials::disposeBrowser() void ShibbolethCredentials::disposeBrowser()
{ {
disconnect(_browser, SIGNAL(viewHidden()), disconnect(_browser, SIGNAL(viewHidden()),
@ -226,7 +247,7 @@ void ShibbolethCredentials::slotBrowserHidden()
Q_EMIT fetched(); Q_EMIT fetched();
} }
void ShibbolethCredentials::invalidateAndFetch() void ShibbolethCredentials::invalidateAndFetch(Account* account)
{ {
_ready = false; _ready = false;
connect (this, SIGNAL(fetched()), connect (this, SIGNAL(fetched()),
@ -234,7 +255,7 @@ void ShibbolethCredentials::invalidateAndFetch()
// small hack to support the ShibbolethRefresher hack // small hack to support the ShibbolethRefresher hack
// we already rand fetch() with a valid account object, // we already rand fetch() with a valid account object,
// and hence know the url on refresh // and hence know the url on refresh
fetch(0); fetch(account);
} }
void ShibbolethCredentials::onFetched() void ShibbolethCredentials::onFetched()

View file

@ -42,12 +42,15 @@ public:
QNetworkAccessManager* getQNAM() const; QNetworkAccessManager* getQNAM() const;
bool ready() const; bool ready() const;
void fetch(Account *account); void fetch(Account *account);
bool stillValid(QNetworkReply *reply);
virtual bool fetchFromUser(Account *account);
void persist(Account *account); void persist(Account *account);
void invalidateToken(Account *account);
QNetworkCookie cookie() const; QNetworkCookie cookie() const;
public Q_SLOTS: public Q_SLOTS:
void invalidateAndFetch(); void invalidateAndFetch(Account *account);
private Q_SLOTS: private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie& cookie); void onShibbolethCookieReceived(const QNetworkCookie& cookie);

View file

@ -40,12 +40,10 @@ AccountManager *AccountManager::instance()
static QMutex mutex; static QMutex mutex;
if (!_instance) if (!_instance)
{ {
mutex.lock(); QMutexLocker lock(&mutex);
if (!_instance) { if (!_instance) {
_instance = new AccountManager; _instance = new AccountManager;
} }
mutex.unlock();
} }
return _instance; return _instance;
@ -65,7 +63,7 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
, _am(0) , _am(0)
, _credentials(0) , _credentials(0)
, _treatSslErrorsAsFailure(false) , _treatSslErrorsAsFailure(false)
, _isOnline(false) , _state(Account::Disconnected)
{ {
} }
@ -285,17 +283,17 @@ void Account::setCredentialSetting(const QString &key, const QVariant &value)
} }
} }
bool Account::isOnline() const int Account::state() const
{ {
return _isOnline; return _state;
} }
void Account::setOnline(bool online) void Account::setState(int state)
{ {
if (_isOnline != online) { if (_state != state) {
emit onlineStateChanged(online); _state = state;
emit stateChanged(state);
} }
_isOnline = online;
} }
void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors) void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)

View file

@ -64,6 +64,11 @@ public:
class Account : public QObject { class Account : public QObject {
Q_OBJECT Q_OBJECT
public: public:
enum State { Connected = 0, /// account is online
Disconnected = 1, /// no network connection
SignedOut = 2 /// Disconnected + credential token has been discarded
};
static QString davPath() { return "remote.php/webdav/"; } static QString davPath() { return "remote.php/webdav/"; }
Account(AbstractSslErrorHandler *sslErrorHandler = 0, QObject *parent = 0); Account(AbstractSslErrorHandler *sslErrorHandler = 0, QObject *parent = 0);
@ -133,10 +138,10 @@ public:
QVariant credentialSetting(const QString& key) const; QVariant credentialSetting(const QString& key) const;
void setCredentialSetting(const QString& key, const QVariant &value); void setCredentialSetting(const QString& key, const QVariant &value);
bool isOnline() const; int state() const;
void setOnline(bool online); void setState(int state);
signals: signals:
void onlineStateChanged(bool online); void stateChanged(int state);
protected Q_SLOTS: protected Q_SLOTS:
void slotHandleErrors(QNetworkReply*,QList<QSslError>); void slotHandleErrors(QNetworkReply*,QList<QSslError>);
@ -150,7 +155,7 @@ private:
QNetworkAccessManager *_am; QNetworkAccessManager *_am;
AbstractCredentials* _credentials; AbstractCredentials* _credentials;
bool _treatSslErrorsAsFailure; bool _treatSslErrorsAsFailure;
bool _isOnline; int _state;
static QString _configFileName; static QString _configFileName;
}; };

View file

@ -104,8 +104,8 @@ AccountSettings::AccountSettings(QWidget *parent) :
ui->connectLabel->setText(tr("No account configured.")); ui->connectLabel->setText(tr("No account configured."));
ui->_buttonAdd->setEnabled(false); ui->_buttonAdd->setEnabled(false);
if (_account) { if (_account) {
connect(_account, SIGNAL(onlineStateChanged(bool)), SLOT(slotOnlineStateChanged(bool))); connect(_account, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int)));
slotOnlineStateChanged(_account->isOnline()); slotAccountStateChanged(_account->state());
} }
setFolderList(FolderMan::instance()->map()); setFolderList(FolderMan::instance()->map());
@ -115,7 +115,16 @@ void AccountSettings::slotFolderActivated( const QModelIndex& indx )
{ {
bool state = indx.isValid(); bool state = indx.isValid();
ui->_buttonRemove->setEnabled( state ); bool haveFolders = ui->_folderList->model()->rowCount() > 0;
ui->_buttonRemove->setEnabled(state);
if( Theme::instance()->singleSyncFolder() ) {
// only one folder synced folder allowed.
ui->_buttonAdd->setVisible(!haveFolders);
} else {
ui->_buttonAdd->setVisible(true);
ui->_buttonAdd->setEnabled( state );
}
ui->_buttonEnable->setEnabled( state ); ui->_buttonEnable->setEnabled( state );
ui->_buttonInfo->setEnabled( state ); ui->_buttonInfo->setEnabled( state );
@ -168,7 +177,7 @@ void AccountSettings::slotFolderWizardAccepted()
folderMan->slotScheduleAllFolders(); folderMan->slotScheduleAllFolders();
emit folderChanged(); emit folderChanged();
} }
buttonsSetEnabled(); slotButtonsSetEnabled();
} }
void AccountSettings::slotFolderWizardRejected() void AccountSettings::slotFolderWizardRejected()
@ -193,30 +202,18 @@ void AccountSettings::slotAddFolder( Folder *folder )
folderToModelItem( item, folder ); folderToModelItem( item, folder );
_model->appendRow( item ); _model->appendRow( item );
// in order to update the enabled state of the "Sync now" button // in order to update the enabled state of the "Sync now" button
connect(folder, SIGNAL(syncStateChange()), this, SLOT(buttonsSetEnabled()), Qt::UniqueConnection); connect(folder, SIGNAL(syncStateChange()), this, SLOT(slotButtonsSetEnabled()), Qt::UniqueConnection);
} }
void AccountSettings::buttonsSetEnabled() void AccountSettings::slotButtonsSetEnabled()
{ {
bool haveFolders = ui->_folderList->model()->rowCount() > 0;
ui->_buttonRemove->setEnabled(false);
if( Theme::instance()->singleSyncFolder() ) {
// only one folder synced folder allowed.
ui->_buttonAdd->setVisible(!haveFolders);
} else {
ui->_buttonAdd->setVisible(true);
ui->_buttonAdd->setEnabled(true);
}
QModelIndex selected = ui->_folderList->currentIndex(); QModelIndex selected = ui->_folderList->currentIndex();
bool isSelected = selected.isValid(); bool isSelected = selected.isValid();
if (isSelected) {
ui->_buttonEnable->setEnabled(isSelected); slotFolderActivated(selected);
ui->_buttonRemove->setEnabled(isSelected); }
ui->_buttonInfo->setEnabled(isSelected);
} }
void AccountSettings::setGeneralErrors( const QStringList& errors ) void AccountSettings::setGeneralErrors( const QStringList& errors )
@ -248,8 +245,12 @@ void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
} // we keep the previous icon for the SyncPrepare state. } // we keep the previous icon for the SyncPrepare state.
} else { } else {
// kepp the previous icon for the prepare phase. // kepp the previous icon for the prepare phase.
if( status == SyncResult::Problem) {
item->setData( theme->syncStateIcon( SyncResult::Success), FolderStatusDelegate::FolderStatusIconRole );
} else {
item->setData( theme->syncStateIcon( status ), FolderStatusDelegate::FolderStatusIconRole ); item->setData( theme->syncStateIcon( status ), FolderStatusDelegate::FolderStatusIconRole );
} }
}
} else { } else {
item->setData( theme->folderDisabledIcon( ), FolderStatusDelegate::FolderStatusIconRole ); // size 48 before item->setData( theme->folderDisabledIcon( ), FolderStatusDelegate::FolderStatusIconRole ); // size 48 before
_wasDisabledBefore = false; _wasDisabledBefore = false;
@ -379,7 +380,7 @@ void AccountSettings::setFolderList( const Folder::Map &folders )
if (idx.isValid()) { if (idx.isValid()) {
ui->_folderList->setCurrentIndex(idx); ui->_folderList->setCurrentIndex(idx);
} }
buttonsSetEnabled(); slotButtonsSetEnabled();
} }
@ -672,7 +673,9 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
case Progress::Download: case Progress::Download:
case Progress::Upload: case Progress::Upload:
case Progress::Inactive: case Progress::Inactive:
case Progress::Error: case Progress::SoftError:
case Progress::NormalError:
case Progress::FatalError:
break; break;
} }
@ -771,13 +774,13 @@ void AccountSettings::slotIgnoreFilesEditor()
} }
} }
void AccountSettings::slotOnlineStateChanged(bool online) void AccountSettings::slotAccountStateChanged(int state)
{ {
if (_account) { if (_account) {
QUrl safeUrl(_account->url()); QUrl safeUrl(_account->url());
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
ui->_buttonAdd->setEnabled(online); ui->_buttonAdd->setEnabled(state == Account::Connected);
if (online) { if (state == Account::Connected) {
QString user; QString user;
if (AbstractCredentials *cred = _account->credentials()) { if (AbstractCredentials *cred = _account->credentials()) {
user = cred->user(); user = cred->user();

View file

@ -49,7 +49,6 @@ public:
~AccountSettings(); ~AccountSettings();
void setFolderList( const Folder::Map& ); void setFolderList( const Folder::Map& );
void buttonsSetEnabled();
signals: signals:
void folderChanged(); void folderChanged();
@ -65,10 +64,11 @@ public slots:
void slotFolderOpenAction( const QString& ); void slotFolderOpenAction( const QString& );
void slotSetProgress(const QString&, const Progress::Info& progress); void slotSetProgress(const QString&, const Progress::Info& progress);
void slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem); void slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem);
void slotButtonsSetEnabled();
void slotUpdateQuota( qint64,qint64 ); void slotUpdateQuota( qint64,qint64 );
void slotIgnoreFilesEditor(); void slotIgnoreFilesEditor();
void slotOnlineStateChanged(bool online = true); void slotAccountStateChanged(int state);
void setGeneralErrors( const QStringList& errors ); void setGeneralErrors( const QStringList& errors );

View file

@ -111,6 +111,7 @@ Application::Application(int &argc, char **argv) :
qRegisterMetaType<Progress::Kind>("Progress::Kind"); qRegisterMetaType<Progress::Kind>("Progress::Kind");
qRegisterMetaType<Progress::Info>("Progress::Info"); qRegisterMetaType<Progress::Info>("Progress::Info");
qRegisterMetaType<Progress::SyncProblem>("Progress::SyncProblem");
MirallConfigFile cfg; MirallConfigFile cfg;
_theme->setSystrayUseMonoIcons(cfg.monoIcons()); _theme->setSystrayUseMonoIcons(cfg.monoIcons());
@ -124,6 +125,11 @@ Application::Application(int &argc, char **argv) :
_gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions. _gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions.
} }
connect( _gui, SIGNAL(setupProxy()), SLOT(slotSetupProxy())); connect( _gui, SIGNAL(setupProxy()), SLOT(slotSetupProxy()));
if (account) {
connect(account, SIGNAL(stateChanged(int)), _gui, SLOT(slotAccountStateChanged()));
}
connect(AccountManager::instance(), SIGNAL(accountChanged(Account*,Account*)),
this, SLOT(slotAccountChanged(Account*,Account*)));
// startup procedure. // startup procedure.
QTimer::singleShot( 0, this, SLOT( slotCheckConnection() )); QTimer::singleShot( 0, this, SLOT( slotCheckConnection() ));
@ -135,6 +141,7 @@ Application::Application(int &argc, char **argv) :
connect (this, SIGNAL(aboutToQuit()), SLOT(slotCleanup())); connect (this, SIGNAL(aboutToQuit()), SLOT(slotCleanup()));
_socketApi = new SocketApi(this, cfg.configPathWithAppName().append(QLatin1String("socket"))); _socketApi = new SocketApi(this, cfg.configPathWithAppName().append(QLatin1String("socket")));
} }
Application::~Application() Application::~Application()
@ -142,6 +149,39 @@ Application::~Application()
// qDebug() << "* Mirall shutdown"; // qDebug() << "* Mirall shutdown";
} }
void Application::slotLogin()
{
Account *a = AccountManager::instance()->account();
if (a) {
FolderMan::instance()->setupFolders();
slotCheckConnection();
}
}
void Application::slotLogout()
{
Account *a = AccountManager::instance()->account();
if (a) {
// invalidate & forget token/password
a->credentials()->invalidateToken(a);
// terminate all syncs and unload folders
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(false);
folderMan->terminateSyncProcess();
folderMan->unloadAllFolders();
a->setState(Account::SignedOut);
// show result
_gui->slotComputeOverallSyncStatus();
}
}
void Application::slotAccountChanged(Account *newAccount, Account *oldAccount)
{
disconnect(oldAccount, SIGNAL(stateChanged(int)), _gui, SLOT(slotOnlineStateChanged()));
connect(newAccount, SIGNAL(stateChanged(int)), _gui, SLOT(slotOnlineStateChanged()));
}
void Application::slotCleanup() void Application::slotCleanup()
{ {
// explicitly close windows. This is somewhat of a hack to ensure // explicitly close windows. This is somewhat of a hack to ensure

View file

@ -73,7 +73,11 @@ protected slots:
void slotSetupProxy(); void slotSetupProxy();
void slotUseMonoIconsChanged( bool ); void slotUseMonoIconsChanged( bool );
void slotCredentialsFetched(); void slotCredentialsFetched();
void slotLogin();
void slotLogout();
void slotCleanup(); void slotCleanup();
void slotAccountChanged(Account *newAccount, Account *oldAccount);
private: private:
void setHelp(); void setHelp();
void runValidator(); void runValidator();

View file

@ -82,6 +82,7 @@ void ConnectionValidator::checkConnection()
{ {
if( _account ) { if( _account ) {
CheckServerJob *checkJob = new CheckServerJob(_account, false, this); CheckServerJob *checkJob = new CheckServerJob(_account, false, this);
checkJob->setIgnoreCredentialFailure(true);
connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap))); connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap)));
connect(checkJob, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*))); connect(checkJob, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*)));
checkJob->start(); checkJob->start();
@ -113,7 +114,7 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
// status.php could not be loaded. // status.php could not be loaded.
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply) void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
{ {
_account->setOnline(false); _account->setState(false);
// ### TODO // ### TODO
_errors.append(tr("Unable to connect to %1").arg(_account->url().toString())); _errors.append(tr("Unable to connect to %1").arg(_account->url().toString()));
@ -127,11 +128,12 @@ void ConnectionValidator::slotCheckAuthentication()
{ {
// simply GET the webdav root, will fail if credentials are wrong. // simply GET the webdav root, will fail if credentials are wrong.
// continue in slotAuthCheck here :-) // continue in slotAuthCheck here :-)
PropfindJob *propFind = new PropfindJob(_account, "/", this); PropfindJob *job = new PropfindJob(_account, "/", this);
propFind->setProperties(QList<QByteArray>() << "getlastmodified"); job->setIgnoreCredentialFailure(true);
connect(propFind, SIGNAL(result(QVariantMap)), SLOT(slotAuthSuccess())); job->setProperties(QList<QByteArray>() << "getlastmodified");
connect(propFind, SIGNAL(networkError(QNetworkReply*)), SLOT(slotAuthFailed(QNetworkReply*))); connect(job, SIGNAL(result(QVariantMap)), SLOT(slotAuthSuccess()));
propFind->start(); connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotAuthFailed(QNetworkReply*)));
job->start();
qDebug() << "# checking for authentication settings."; qDebug() << "# checking for authentication settings.";
} }
@ -140,11 +142,19 @@ void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
Status stat = StatusNotFound; Status stat = StatusNotFound;
if( reply->error() == QNetworkReply::AuthenticationRequiredError || if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
reply->error() == QNetworkReply::OperationCanceledError ) { // returned if the user is wrong. reply->error() == QNetworkReply::OperationCanceledError ) { // returned if the user/pwd is wrong.
qDebug() << reply->error() << reply->errorString();
qDebug() << "******** Password is wrong!"; qDebug() << "******** Password is wrong!";
_errors << tr("The provided credentials are not correct"); _errors << tr("The provided credentials are not correct");
stat = CredentialsWrong; stat = CredentialsWrong;
_account->setOnline(false); switch (_account->state()) {
case Account::SignedOut:
_account->setState(Account::SignedOut);
break;
default:
_account->setState(Account::Disconnected);
}
} else if( reply->error() != QNetworkReply::NoError ) { } else if( reply->error() != QNetworkReply::NoError ) {
_errors << reply->errorString(); _errors << reply->errorString();
} }
@ -154,7 +164,7 @@ void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
void ConnectionValidator::slotAuthSuccess() void ConnectionValidator::slotAuthSuccess()
{ {
_account->setOnline(true); _account->setState(Account::Connected);
emit connectionResult(Connected); emit connectionResult(Connected);
} }

View file

@ -225,6 +225,8 @@ bool CSyncThread::checkBlacklisting( SyncFileItem *item )
qDebug() << "Item is on blacklist: " << entry._file << "retries:" << entry._retryCount; qDebug() << "Item is on blacklist: " << entry._file << "retries:" << entry._retryCount;
item->_blacklistedInDb = true; item->_blacklistedInDb = true;
item->_instruction = CSYNC_INSTRUCTION_IGNORE; item->_instruction = CSYNC_INSTRUCTION_IGNORE;
item->_errorString = tr("The item is not synced because it is on the blacklist.");
slotProgressProblem( Progress::SoftError, *item );
} }
} }
@ -316,6 +318,8 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CSYNC_INSTRUCTION_CONFLICT: case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_IGNORE: case CSYNC_INSTRUCTION_IGNORE:
case CSYNC_INSTRUCTION_ERROR: case CSYNC_INSTRUCTION_ERROR:
//
slotProgressProblem(Progress::SoftError, item );
dir = SyncFileItem::None; dir = SyncFileItem::None;
break; break;
case CSYNC_INSTRUCTION_EVAL: case CSYNC_INSTRUCTION_EVAL:
@ -349,7 +353,7 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
} }
void CSyncThread::handleSyncError(CSYNC *ctx, const char *state) { void CSyncThread::handleSyncError(CSYNC *ctx, const char *state) {
CSYNC_STATUS err = CSYNC_STATUS(csync_get_status( ctx )); CSYNC_STATUS err = csync_get_status( ctx );
const char *errMsg = csync_get_status_string( ctx ); const char *errMsg = csync_get_status_string( ctx );
QString errStr = csyncErrorToString(err); QString errStr = csyncErrorToString(err);
if( errMsg ) { if( errMsg ) {
@ -357,7 +361,9 @@ void CSyncThread::handleSyncError(CSYNC *ctx, const char *state) {
} }
qDebug() << " #### ERROR during "<< state << ": " << errStr; qDebug() << " #### ERROR during "<< state << ": " << errStr;
if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_SERVICE_UNAVAILABLE ) || if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_ABORTED) ) {
qDebug() << "Update phase was aborted by user!";
} else if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_SERVICE_UNAVAILABLE ) ||
CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_CONNECT_ERROR )) { CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_CONNECT_ERROR )) {
emit csyncUnavailable(); emit csyncUnavailable();
} else { } else {
@ -472,6 +478,8 @@ void CSyncThread::startSync()
return; return;
} }
slotProgress(Progress::StartSync, SyncFileItem(), 0, 0);
_progressInfo = Progress::Info(); _progressInfo = Progress::Info();
_hasFiles = false; _hasFiles = false;
@ -516,8 +524,8 @@ void CSyncThread::startSync()
_journal, &_abortRequested)); _journal, &_abortRequested));
connect(_propagator.data(), SIGNAL(completed(SyncFileItem)), connect(_propagator.data(), SIGNAL(completed(SyncFileItem)),
this, SLOT(transferCompleted(SyncFileItem)), Qt::QueuedConnection); this, SLOT(transferCompleted(SyncFileItem)), Qt::QueuedConnection);
connect(_propagator.data(), SIGNAL(progress(Progress::Kind,QString,quint64,quint64)), connect(_propagator.data(), SIGNAL(progress(Progress::Kind,SyncFileItem,quint64,quint64)),
this, SLOT(slotProgress(Progress::Kind,QString,quint64,quint64))); this, SLOT(slotProgress(Progress::Kind,SyncFileItem,quint64,quint64)));
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished())); connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()));
int downloadLimit = 0; int downloadLimit = 0;
@ -535,7 +543,6 @@ void CSyncThread::startSync()
} }
_propagator->_uploadLimit = uploadLimit; _propagator->_uploadLimit = uploadLimit;
slotProgress(Progress::StartSync, QString(), 0, 0);
_propagator->start(_syncedItems); _propagator->start(_syncedItems);
} }
@ -549,6 +556,9 @@ void CSyncThread::transferCompleted(const SyncFileItem &item)
_syncedItems[idx]._instruction = item._instruction; _syncedItems[idx]._instruction = item._instruction;
_syncedItems[idx]._errorString = item._errorString; _syncedItems[idx]._errorString = item._errorString;
_syncedItems[idx]._status = item._status; _syncedItems[idx]._status = item._status;
} else {
qWarning() << Q_FUNC_INFO << "Could not find index in synced items!";
} }
if (item._status == SyncFileItem::FatalError) { if (item._status == SyncFileItem::FatalError) {
@ -562,34 +572,59 @@ void CSyncThread::slotFinished()
if( ! _journal->postSyncCleanup( _seenFiles ) ) { if( ! _journal->postSyncCleanup( _seenFiles ) ) {
qDebug() << "Cleaning of synced "; qDebug() << "Cleaning of synced ";
} }
_journal->commit(); _journal->commit("All Finished.", false);
emit treeWalkResult(_syncedItems); emit treeWalkResult(_syncedItems);
csync_commit(_csync_ctx); csync_commit(_csync_ctx);
qDebug() << "CSync run took " << _syncTime.elapsed() << " Milliseconds"; qDebug() << "CSync run took " << _syncTime.elapsed() << " Milliseconds";
slotProgress(Progress::EndSync,QString(), 0 , 0); slotProgress(Progress::EndSync,SyncFileItem(), 0 , 0);
emit finished(); emit finished();
_propagator.reset(0); _propagator.reset(0);
_syncMutex.unlock(); _syncMutex.unlock();
thread()->quit(); thread()->quit();
} }
void CSyncThread::slotProgressProblem(Progress::Kind kind, const SyncFileItem& item)
void CSyncThread::slotProgress(Progress::Kind kind, const QString &file, quint64 curr, quint64 total)
{ {
Progress::SyncProblem problem;
problem.kind = kind;
problem.current_file = item._file;
problem.error_message = item._errorString;
problem.error_code = item._httpErrorCode;
problem.timestamp = QDateTime::currentDateTime();
// connected to something in folder.
emit transmissionProblem( problem );
}
void CSyncThread::slotProgress(Progress::Kind kind, const SyncFileItem& item, quint64 curr, quint64 total)
{
if( kind == Progress::StartSync ) {
QMutexLocker lock(&_mutex);
_currentFileNo = 0;
}
if( kind == Progress::StartDelete ||
kind == Progress::StartDownload ||
kind == Progress::StartRename ||
kind == Progress::StartUpload ) {
QMutexLocker lock(&_mutex);
_currentFileNo += 1;
}
Progress::Info pInfo = _progressInfo; Progress::Info pInfo = _progressInfo;
pInfo.kind = kind; pInfo.kind = kind;
pInfo.current_file = file; pInfo.current_file = item._file;
pInfo.file_size = total; pInfo.file_size = total;
pInfo.current_file_bytes = curr; pInfo.current_file_bytes = curr;
pInfo.current_file_no = _currentFileNo;
pInfo.overall_current_bytes += curr; pInfo.overall_current_bytes += curr;
pInfo.timestamp = QDateTime::currentDateTime(); pInfo.timestamp = QDateTime::currentDateTime();
// Connect to something in folder! // Connect to something in folder!
transmissionProgress( pInfo ); emit transmissionProgress( pInfo );
} }
/* Given a path on the remote, give the path as it is when the rename is done */ /* Given a path on the remote, give the path as it is when the rename is done */

View file

@ -68,6 +68,8 @@ signals:
void treeWalkResult(const SyncFileItemVector&); void treeWalkResult(const SyncFileItemVector&);
void transmissionProgress( const Progress::Info& progress ); void transmissionProgress( const Progress::Info& progress );
void transmissionProblem( const Progress::SyncProblem& problem );
void csyncStateDbFile( const QString& ); void csyncStateDbFile( const QString& );
void wipeDb(); void wipeDb();
@ -79,7 +81,8 @@ signals:
private slots: private slots:
void transferCompleted(const SyncFileItem& item); void transferCompleted(const SyncFileItem& item);
void slotFinished(); void slotFinished();
void slotProgress(Progress::Kind kind, const QString& file, quint64, quint64); void slotProgress(Progress::Kind kind, const SyncFileItem &item, quint64, quint64);
void slotProgressProblem(Progress::Kind kind, const SyncFileItem& item);
private: private:
void handleSyncError(CSYNC *ctx, const char *state); void handleSyncError(CSYNC *ctx, const char *state);
@ -112,6 +115,7 @@ private:
Progress::Info _progressInfo; Progress::Info _progressInfo;
int _downloadLimit; int _downloadLimit;
int _uploadLimit; int _uploadLimit;
int _currentFileNo;
QAtomicInt _abortRequested; QAtomicInt _abortRequested;

View file

@ -299,7 +299,7 @@ void Folder::etagRetreived(const QString& etag)
void Folder::slotNetworkUnavailable() void Folder::slotNetworkUnavailable()
{ {
AccountManager::instance()->account()->setOnline(false); AccountManager::instance()->account()->setState(Account::Disconnected);
_syncResult.setStatus(SyncResult::Unavailable); _syncResult.setStatus(SyncResult::Unavailable);
emit syncStateChange(); emit syncStateChange();
} }
@ -452,8 +452,10 @@ void Folder::slotTerminateSync(bool block)
if( _thread && _csync ) { if( _thread && _csync ) {
_csync->abort(); _csync->abort();
_errors.append( tr("The CSync thread terminated.") );
_csyncError = true; // Do not display an error message, user knows his own actions.
// _errors.append( tr("The CSync thread terminated.") );
// _csyncError = true;
if (!block) { if (!block) {
setSyncState(SyncResult::SyncAbortRequested); setSyncState(SyncResult::SyncAbortRequested);
return; return;
@ -625,6 +627,7 @@ void Folder::startSync(const QStringList &pathList)
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection); SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
connect(_csync, SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info))); connect(_csync, SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
connect(_csync, SIGNAL(transmissionProblem(Progress::SyncProblem)), this, SLOT(slotTransmissionProblem(Progress::SyncProblem)));
_thread->start(); _thread->start();
_thread->setPriority(QThread::LowPriority); _thread->setPriority(QThread::LowPriority);
@ -657,7 +660,7 @@ void Folder::slotCsyncUnavailable()
void Folder::slotCSyncFinished() void Folder::slotCSyncFinished()
{ {
qDebug() << "-> CSync Finished slot with error " << _csyncError; qDebug() << "-> CSync Finished slot with error " << _csyncError << "warn count" << _syncResult.warnCount();
_watcher->setEventsEnabledDelayed(2000); _watcher->setEventsEnabledDelayed(2000);
_pollTimer.start(); _pollTimer.start();
_timeSinceLastSync.restart(); _timeSinceLastSync.restart();
@ -685,6 +688,32 @@ void Folder::slotCSyncFinished()
emit syncFinished( _syncResult ); emit syncFinished( _syncResult );
} }
// the problem comes without a folder and the valid path set. Add that here
// and hand the result over to the progress dispatcher.
void Folder::slotTransmissionProblem( const Progress::SyncProblem& problem )
{
Progress::SyncProblem newProb = problem;
newProb.folder = alias();
if(newProb.current_file.startsWith(QLatin1String("ownclouds://")) ||
newProb.current_file.startsWith(QLatin1String("owncloud://")) ) {
// rip off the whole ownCloud URL.
newProb.current_file.remove(Utility::toCSyncScheme(remoteUrl().toString()));
}
QString localPath = path();
if( newProb.current_file.startsWith(localPath) ) {
// remove the local dir.
newProb.current_file = newProb.current_file.right( newProb.current_file.length() - localPath.length());
}
// Count all error conditions.
_syncResult.setWarnCount( _syncResult.warnCount()+1 );
ProgressDispatcher::instance()->setProgressProblem(alias(), newProb);
}
// the progress comes without a folder and the valid path set. Add that here
// and hand the result over to the progress dispatcher.
void Folder::slotTransmissionProgress(const Progress::Info& progress) void Folder::slotTransmissionProgress(const Progress::Info& progress)
{ {
Progress::Info newInfo = progress; Progress::Info newInfo = progress;
@ -705,9 +734,6 @@ void Folder::slotTransmissionProgress(const Progress::Info& progress)
if( newInfo.kind == Progress::StartSync ) { if( newInfo.kind == Progress::StartSync ) {
_syncResult.setWarnCount(0); _syncResult.setWarnCount(0);
} }
if( newInfo.kind == Progress::Error ) {
_syncResult.setWarnCount( _syncResult.warnCount()+1 );
}
ProgressDispatcher::instance()->setProgressInfo(alias(), newInfo); ProgressDispatcher::instance()->setProgressInfo(alias(), newInfo);
} }

View file

@ -174,6 +174,7 @@ private slots:
void slotCSyncFinished(); void slotCSyncFinished();
void slotTransmissionProgress(const Progress::Info& progress); void slotTransmissionProgress(const Progress::Info& progress);
void slotTransmissionProblem( const Progress::SyncProblem& problem );
void slotPollTimerTimeout(); void slotPollTimerTimeout();
void etagRetreived(const QString &); void etagRetreived(const QString &);

View file

@ -23,7 +23,7 @@
#include <QStringList> #include <QStringList>
#include <QStack> #include <QStack>
#include <QTimer> #include <QTimer>
#include <QMutex>
#include <QDebug> #include <QDebug>
#include "json.h" #include "json.h"
@ -32,11 +32,13 @@
#include "mirall/account.h" #include "mirall/account.h"
#include "creds/credentialsfactory.h" #include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
namespace Mirall { namespace Mirall {
AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QObject *parent) AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QObject *parent)
: QObject(parent) : QObject(parent)
, _ignoreCredentialFailure(false)
, _reply(0) , _reply(0)
, _account(account) , _account(account)
, _path(path) , _path(path)
@ -70,6 +72,11 @@ void AbstractNetworkJob::resetTimeout()
_timer->start(interval); _timer->start(interval);
} }
void AbstractNetworkJob::setIgnoreCredentialFailure(bool ignore)
{
_ignoreCredentialFailure = ignore;
}
void AbstractNetworkJob::setAccount(Account *account) void AbstractNetworkJob::setAccount(Account *account)
{ {
_account = account; _account = account;
@ -80,14 +87,10 @@ void AbstractNetworkJob::setPath(const QString &path)
_path = path; _path = path;
} }
void AbstractNetworkJob::slotError(QNetworkReply::NetworkError error) void AbstractNetworkJob::slotError(QNetworkReply::NetworkError)
{ {
if (error == QNetworkReply::ContentAccessDenied) {
// ### ask for password, retry job, needs refactoring to use start()
}
qDebug() << metaObject()->className() << "Error:" << _reply->errorString(); qDebug() << metaObject()->className() << "Error:" << _reply->errorString();
emit networkError(_reply); emit networkError(_reply);
deleteLater();
} }
void AbstractNetworkJob::setupConnections(QNetworkReply *reply) void AbstractNetworkJob::setupConnections(QNetworkReply *reply)
@ -128,10 +131,38 @@ QNetworkReply *AbstractNetworkJob::headRequest(const QUrl &url)
return _account->headRequest(url); return _account->headRequest(url);
} }
void AbstractNetworkJob::slotFinished()
{
static QMutex mutex;
AbstractCredentials *creds = _account->credentials();
if (creds->stillValid(_reply) || _ignoreCredentialFailure) {
finished();
} else {
// If other jobs that still were created from before
// the account was put offline by the code below,
// we do want them to fail silently while we
// query the user
if (mutex.tryLock()) {
Account *a = account();
bool fetched = creds->fetchFromUser(a);
if (fetched) {
a->setState(Account::Connected);
}
mutex.unlock();
}
}
deleteLater();
}
AbstractNetworkJob::~AbstractNetworkJob() { AbstractNetworkJob::~AbstractNetworkJob() {
_reply->deleteLater(); _reply->deleteLater();
} }
void AbstractNetworkJob::start()
{
qDebug() << "!!!" << metaObject()->className() << "created for" << account()->url() << "querying" << path();
}
/*********************************************************************************************/ /*********************************************************************************************/
RequestEtagJob::RequestEtagJob(Account *account, const QString &path, QObject *parent) RequestEtagJob::RequestEtagJob(Account *account, const QString &path, QObject *parent)
@ -167,9 +198,10 @@ void RequestEtagJob::start()
if( reply()->error() != QNetworkReply::NoError ) { if( reply()->error() != QNetworkReply::NoError ) {
qDebug() << "getting etag: request network error: " << reply()->errorString(); qDebug() << "getting etag: request network error: " << reply()->errorString();
} }
AbstractNetworkJob::start();
} }
void RequestEtagJob::slotFinished() void RequestEtagJob::finished()
{ {
if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response // Parse DAV response
@ -188,7 +220,6 @@ void RequestEtagJob::slotFinished()
} }
emit etagRetreived(etag); emit etagRetreived(etag);
} }
deleteLater();
} }
/*********************************************************************************************/ /*********************************************************************************************/
@ -204,12 +235,12 @@ void MkColJob::start()
QNetworkReply *reply = davRequest("MKCOL", path()); QNetworkReply *reply = davRequest("MKCOL", path());
setReply(reply); setReply(reply);
setupConnections(reply); setupConnections(reply);
AbstractNetworkJob::start();
} }
void MkColJob::slotFinished() void MkColJob::finished()
{ {
emit finished(reply()->error()); emit finished(reply()->error());
deleteLater();
} }
/*********************************************************************************************/ /*********************************************************************************************/
@ -236,9 +267,10 @@ void LsColJob::start()
buf->setParent(reply); buf->setParent(reply);
setReply(reply); setReply(reply);
setupConnections(reply); setupConnections(reply);
AbstractNetworkJob::start();
} }
void LsColJob::slotFinished() void LsColJob::finished()
{ {
if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response // Parse DAV response
@ -264,8 +296,6 @@ void LsColJob::slotFinished()
} }
emit directoryListing(folders); emit directoryListing(folders);
} }
deleteLater();
} }
/*********************************************************************************************/ /*********************************************************************************************/
@ -281,6 +311,7 @@ void CheckServerJob::start()
{ {
setReply(getRequest(path())); setReply(getRequest(path()));
setupConnections(reply()); setupConnections(reply());
AbstractNetworkJob::start();
} }
void CheckServerJob::slotTimeout() void CheckServerJob::slotTimeout()
@ -305,7 +336,7 @@ bool CheckServerJob::installed(const QVariantMap &info)
return info.value(QLatin1String("installed")).toBool(); return info.value(QLatin1String("installed")).toBool();
} }
void CheckServerJob::slotFinished() void CheckServerJob::finished()
{ {
account()->setCertificateChain(reply()->sslConfiguration().peerCertificateChain()); account()->setCertificateChain(reply()->sslConfiguration().peerCertificateChain());
@ -343,7 +374,6 @@ void CheckServerJob::slotFinished()
} else { } else {
qDebug() << "No proper answer on " << requestedUrl; qDebug() << "No proper answer on " << requestedUrl;
} }
deleteLater();
} }
/*********************************************************************************************/ /*********************************************************************************************/
@ -380,6 +410,7 @@ void PropfindJob::start()
setReply(davRequest("PROPFIND", path(), req, buf)); setReply(davRequest("PROPFIND", path(), req, buf));
buf->setParent(reply()); buf->setParent(reply());
setupConnections(reply()); setupConnections(reply());
AbstractNetworkJob::start();
} }
void PropfindJob::setProperties(QList<QByteArray> properties) void PropfindJob::setProperties(QList<QByteArray> properties)
@ -392,7 +423,7 @@ QList<QByteArray> PropfindJob::properties() const
return _properties; return _properties;
} }
void PropfindJob::slotFinished() void PropfindJob::finished()
{ {
int http_result_code = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); int http_result_code = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@ -426,8 +457,6 @@ void PropfindJob::slotFinished()
} else { } else {
qDebug() << "Quota request *not* successful, http result code is " << http_result_code; qDebug() << "Quota request *not* successful, http result code is " << http_result_code;
} }
deleteLater();
} }
/*********************************************************************************************/ /*********************************************************************************************/
@ -441,9 +470,10 @@ void EntityExistsJob::start()
{ {
setReply(headRequest(path())); setReply(headRequest(path()));
setupConnections(reply()); setupConnections(reply());
AbstractNetworkJob::start();
} }
void EntityExistsJob::slotFinished() void EntityExistsJob::finished()
{ {
emit exists(reply()); emit exists(reply());
} }
@ -473,9 +503,10 @@ void CheckQuotaJob::start()
setReply(davRequest("PROPFIND", path(), req, buf)); setReply(davRequest("PROPFIND", path(), req, buf));
buf->setParent(reply()); buf->setParent(reply());
setupConnections(reply()); setupConnections(reply());
AbstractNetworkJob::start();
} }
void CheckQuotaJob::slotFinished() void CheckQuotaJob::finished()
{ {
if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response // Parse DAV response
@ -498,7 +529,6 @@ void CheckQuotaJob::slotFinished()
qint64 total = quotaUsedBytes + quotaAvailableBytes; qint64 total = quotaUsedBytes + quotaAvailableBytes;
emit quotaRetrieved(total, quotaUsedBytes); emit quotaRetrieved(total, quotaUsedBytes);
} }
deleteLater();
} }
} // namespace Mirall } // namespace Mirall

View file

@ -37,7 +37,7 @@ public:
explicit AbstractNetworkJob(Account *account, const QString &path, QObject* parent = 0); explicit AbstractNetworkJob(Account *account, const QString &path, QObject* parent = 0);
virtual ~AbstractNetworkJob(); virtual ~AbstractNetworkJob();
virtual void start() = 0; virtual void start();
void setAccount(Account *account); void setAccount(Account *account);
Account* account() const { return _account; } Account* account() const { return _account; }
@ -50,6 +50,9 @@ public:
void setTimeout(qint64 msec); void setTimeout(qint64 msec);
void resetTimeout(); void resetTimeout();
void setIgnoreCredentialFailure(bool ignore);
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
signals: signals:
void networkError(QNetworkReply *reply); void networkError(QNetworkReply *reply);
protected: protected:
@ -66,13 +69,15 @@ protected:
QNetworkReply* headRequest(const QUrl &url); QNetworkReply* headRequest(const QUrl &url);
int maxRedirects() const { return 10; } int maxRedirects() const { return 10; }
virtual void finished() = 0;
private slots: private slots:
virtual void slotFinished() = 0; void slotFinished();
void slotError(QNetworkReply::NetworkError); void slotError(QNetworkReply::NetworkError);
virtual void slotTimeout() {} virtual void slotTimeout() {}
private: private:
bool _ignoreCredentialFailure;
QNetworkReply *_reply; QNetworkReply *_reply;
Account *_account; Account *_account;
QString _path; QString _path;
@ -92,7 +97,7 @@ signals:
void exists(QNetworkReply*); void exists(QNetworkReply*);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
}; };
/** /**
@ -108,7 +113,7 @@ signals:
void directoryListing(const QStringList &items); void directoryListing(const QStringList &items);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
}; };
/** /**
@ -126,7 +131,7 @@ signals:
void result(const QVariantMap &values); void result(const QVariantMap &values);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
private: private:
QList<QByteArray> _properties; QList<QByteArray> _properties;
@ -145,11 +150,11 @@ signals:
void finished(QNetworkReply::NetworkError); void finished(QNetworkReply::NetworkError);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
}; };
/** /**
* @brief The CheckOwncloudJob class * @brief The CheckServerJob class
*/ */
class CheckServerJob : public AbstractNetworkJob { class CheckServerJob : public AbstractNetworkJob {
Q_OBJECT Q_OBJECT
@ -166,7 +171,7 @@ signals:
void timeout(const QUrl&url); void timeout(const QUrl&url);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
virtual void slotTimeout(); virtual void slotTimeout();
private: private:
@ -188,7 +193,7 @@ signals:
void etagRetreived(const QString &etag); void etagRetreived(const QString &etag);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
}; };
/** /**
@ -204,7 +209,7 @@ signals:
void quotaRetrieved(qint64 totalBytes, qint64 availableBytes); void quotaRetrieved(qint64 totalBytes, qint64 availableBytes);
private slots: private slots:
virtual void slotFinished(); virtual void finished();
}; };
} // namespace Mirall } // namespace Mirall

View file

@ -23,6 +23,7 @@
#include "mirall/logger.h" #include "mirall/logger.h"
#include "mirall/logbrowser.h" #include "mirall/logbrowser.h"
#include "mirall/account.h" #include "mirall/account.h"
#include "creds/abstractcredentials.h"
#include <QDesktopServices> #include <QDesktopServices>
#include <QMessageBox> #include <QMessageBox>
@ -140,6 +141,11 @@ void ownCloudGui::slotOpenPath(const QString &path)
Utility::showInFileManager(path); Utility::showInFileManager(path);
} }
void ownCloudGui::slotAccountStateChanged()
{
setupContextMenu();
}
void ownCloudGui::startupConnected( bool connected, const QStringList& fails ) void ownCloudGui::startupConnected( bool connected, const QStringList& fails )
{ {
FolderMan *folderMan = FolderMan::instance(); FolderMan *folderMan = FolderMan::instance();
@ -161,6 +167,13 @@ void ownCloudGui::startupConnected( bool connected, const QStringList& fails )
void ownCloudGui::slotComputeOverallSyncStatus() void ownCloudGui::slotComputeOverallSyncStatus()
{ {
if (Account *a = AccountManager::instance()->account()) {
if (a->state() == Account::SignedOut) {
_tray->setIcon(Theme::instance()->syncStateIcon( SyncResult::Unavailable, true));
_tray->setToolTip(tr("Please sign in"));
return;
}
}
// display the info of the least successful sync (eg. not just display the result of the latest sync // display the info of the least successful sync (eg. not just display the result of the latest sync
QString trayMessage; QString trayMessage;
FolderMan *folderMan = FolderMan::instance(); FolderMan *folderMan = FolderMan::instance();
@ -208,17 +221,23 @@ void ownCloudGui::setupContextMenu()
{ {
FolderMan *folderMan = FolderMan::instance(); FolderMan *folderMan = FolderMan::instance();
bool isConfigured = (AccountManager::instance()->account() != 0); Account *a = AccountManager::instance()->account();
_actionOpenoC->setEnabled(isConfigured);
if( _contextMenu ) { bool isConfigured = (a != 0);
_actionOpenoC->setEnabled(isConfigured);
bool isConnected = false;
if (isConfigured) {
isConnected = (a->state() == Account::Connected);
}
if ( _contextMenu ) {
_contextMenu->clear(); _contextMenu->clear();
_recentActionsMenu->clear(); _recentActionsMenu->clear();
_recentActionsMenu->addAction(tr("None.")); _recentActionsMenu->addAction(tr("None."));
_recentActionsMenu->addAction(_actionRecent); _recentActionsMenu->addAction(_actionRecent);
} else { } else {
_contextMenu = new QMenu(); _contextMenu = new QMenu(_contextMenu);
_recentActionsMenu = _contextMenu->addMenu(tr("Recent Changes")); _recentActionsMenu = new QMenu(tr("Recent Changes"));
// this must be called only once after creating the context menu, or // this must be called only once after creating the context menu, or
// it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04). // it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04).
_tray->setContextMenu(_contextMenu); _tray->setContextMenu(_contextMenu);
@ -255,19 +274,25 @@ void ownCloudGui::setupContextMenu()
_contextMenu->addAction(action); _contextMenu->addAction(action);
} }
} }
_contextMenu->addSeparator(); _contextMenu->addSeparator();
if (isConfigured && isConnected) {
_contextMenu->addAction(_actionQuota); _contextMenu->addAction(_actionQuota);
_contextMenu->addSeparator(); _contextMenu->addSeparator();
_contextMenu->addAction(_actionStatus); _contextMenu->addAction(_actionStatus);
_contextMenu->addMenu(_recentActionsMenu); _contextMenu->addMenu(_recentActionsMenu);
_contextMenu->addSeparator(); _contextMenu->addSeparator();
}
_contextMenu->addAction(_actionSettings); _contextMenu->addAction(_actionSettings);
if (!Theme::instance()->helpUrl().isEmpty()) { if (!Theme::instance()->helpUrl().isEmpty()) {
_contextMenu->addAction(_actionHelp); _contextMenu->addAction(_actionHelp);
} }
_contextMenu->addSeparator(); _contextMenu->addSeparator();
if (isConfigured && isConnected) {
_contextMenu->addAction(_actionLogout);
} else {
_contextMenu->addAction(_actionLogin);
}
_contextMenu->addAction(_actionQuit); _contextMenu->addAction(_actionQuit);
// Populate once at start // Populate once at start
@ -334,6 +359,11 @@ void ownCloudGui::setupActions()
_actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this); _actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this);
QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit())); QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit()));
_actionLogin = new QAction(tr("Sign in..."), this);
connect(_actionLogin, SIGNAL(triggered()), _app, SLOT(slotLogin()));
_actionLogout = new QAction(tr("Sign out"), this);
connect(_actionLogout, SIGNAL(triggered()), _app, SLOT(slotLogout()));
_quotaInfo = new QuotaInfo(this); _quotaInfo = new QuotaInfo(this);
connect(_quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)), SLOT(slotRefreshQuotaDisplay(qint64,qint64))); connect(_quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)), SLOT(slotRefreshQuotaDisplay(qint64,qint64)));
} }
@ -451,6 +481,7 @@ void ownCloudGui::slotSettings()
_settingsDialog->setGeneralErrors( _startupFails ); _settingsDialog->setGeneralErrors( _startupFails );
Utility::raiseDialog(_settingsDialog.data()); Utility::raiseDialog(_settingsDialog.data());
_settingsDialog->slotRefreshResultList();
} }
// open sync protocol widget // open sync protocol widget

View file

@ -67,6 +67,7 @@ public slots:
void slotOpenOwnCloud(); void slotOpenOwnCloud();
void slotHelp(); void slotHelp();
void slotOpenPath(const QString& path); void slotOpenPath(const QString& path);
void slotAccountStateChanged();
private slots: private slots:
void slotDisplayIdle(); void slotDisplayIdle();
@ -81,6 +82,9 @@ private:
QMenu *_contextMenu; QMenu *_contextMenu;
QMenu *_recentActionsMenu; QMenu *_recentActionsMenu;
QAction *_actionLogin;
QAction *_actionLogout;
QAction *_actionOpenoC; QAction *_actionOpenoC;
QAction *_actionSettings; QAction *_actionSettings;
QAction *_actionQuota; QAction *_actionQuota;

View file

@ -176,7 +176,7 @@ void PropagateLocalRemove::start()
} }
} }
_propagator->_journal->deleteFileRecord(_item._originalFile); _propagator->_journal->deleteFileRecord(_item._originalFile);
_propagator->_journal->commit(); _propagator->_journal->commit("Local remove");
done(SyncFileItem::Success); done(SyncFileItem::Success);
} }
@ -205,7 +205,7 @@ void PropagateRemoteRemove::start()
return; return;
} }
_propagator->_journal->deleteFileRecord(_item._originalFile, _item._isDirectory); _propagator->_journal->deleteFileRecord(_item._originalFile, _item._isDirectory);
_propagator->_journal->commit(); _propagator->_journal->commit("Remote Remove");
done(SyncFileItem::Success); done(SyncFileItem::Success);
} }
@ -257,7 +257,7 @@ private:
pi._transferid = trans->transfer_id; pi._transferid = trans->transfer_id;
pi._modtime = QDateTime::fromTime_t(trans->modtime); pi._modtime = QDateTime::fromTime_t(trans->modtime);
that->_propagator->_journal->setUploadInfo(that->_item._file, pi); that->_propagator->_journal->setUploadInfo(that->_item._file, pi);
that->_propagator->_journal->commit(); that->_propagator->_journal->commit("Upload info");
} }
} }
@ -267,7 +267,7 @@ private:
PropagateUploadFile* that = reinterpret_cast<PropagateUploadFile*>(userdata); PropagateUploadFile* that = reinterpret_cast<PropagateUploadFile*>(userdata);
if (status == ne_status_sending && info->sr.total > 0) { if (status == ne_status_sending && info->sr.total > 0) {
emit that->progress(Progress::Context, that->_item._file , emit that->progress(Progress::Context, that->_item,
that->_chunked_done + info->sr.progress, that->_chunked_done + info->sr.progress,
that->_chunked_total_size ? that->_chunked_total_size : info->sr.total ); that->_chunked_total_size ? that->_chunked_total_size : info->sr.total );
@ -281,7 +281,7 @@ private:
void PropagateUploadFile::start() void PropagateUploadFile::start()
{ {
emit progress(Progress::StartUpload, _item._file, 0, _item._size); emit progress(Progress::StartUpload, _item, 0, _item._size);
QFile file(_propagator->_localDir + _item._file); QFile file(_propagator->_localDir + _item._file);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
@ -299,6 +299,8 @@ void PropagateUploadFile::start()
* If the file has changed, retry. * If the file has changed, retry.
*/ */
qDebug() << "** PUT request to" << uri.data(); qDebug() << "** PUT request to" << uri.data();
const SyncJournalDb::UploadInfo progressInfo = _propagator->_journal->getUploadInfo(_item._file);
do { do {
Hbf_State state = HBF_SUCCESS; Hbf_State state = HBF_SUCCESS;
QScopedPointer<hbf_transfer_t, ScopedPointerHelpers> trans(hbf_init_transfer(uri.data())); QScopedPointer<hbf_transfer_t, ScopedPointerHelpers> trans(hbf_init_transfer(uri.data()));
@ -309,7 +311,6 @@ void PropagateUploadFile::start()
Q_ASSERT(trans); Q_ASSERT(trans);
state = hbf_splitlist(trans.data(), file.handle()); state = hbf_splitlist(trans.data(), file.handle());
const SyncJournalDb::UploadInfo progressInfo = _propagator->_journal->getUploadInfo(_item._file);
if (progressInfo._valid) { if (progressInfo._valid) {
if (progressInfo._modtime.toTime_t() == _item._modtime) { if (progressInfo._modtime.toTime_t() == _item._modtime) {
trans->start_id = progressInfo._chunk; trans->start_id = progressInfo._chunk;
@ -342,8 +343,6 @@ void PropagateUploadFile::start()
if( !fid.isEmpty() ) { if( !fid.isEmpty() ) {
if( !_item._fileId.isEmpty() && _item._fileId != fid ) { if( !_item._fileId.isEmpty() && _item._fileId != fid ) {
qDebug() << "WARN: File ID changed!" << _item._fileId << fid; qDebug() << "WARN: File ID changed!" << _item._fileId << fid;
} else {
qDebug() << "FileID is" << fid;
} }
_item._fileId = fid; _item._fileId = fid;
} }
@ -353,15 +352,29 @@ void PropagateUploadFile::start()
/* If the source file changed during submission, lets try again */ /* If the source file changed during submission, lets try again */
if( state == HBF_SOURCE_FILE_CHANGE ) { if( state == HBF_SOURCE_FILE_CHANGE ) {
if( attempts++ < 30 ) { /* FIXME: How often do we want to try? */ if( attempts++ < 5 ) { /* FIXME: How often do we want to try? */
qDebug("SOURCE file has changed during upload, retry #%d in two seconds!", attempts); qDebug("SOURCE file has changed during upload, retry #%d in %d seconds!", attempts, 2*attempts);
sleep(2); sleep(2*attempts);
continue; continue;
} }
}
const QString errMsg = tr("Local file changed during sync, syncing once it arrived completely");
done( SyncFileItem::SoftError, errMsg );
_item._errorString = errMsg;
emit progressProblem( Progress::SoftError, _item );
return;
} else if( state == HBF_USER_ABORTED ) {
const QString errMsg = tr("Sync was aborted by user.");
done( SyncFileItem::SoftError, errMsg);
_item._errorString = errMsg;
emit progressProblem( Progress::SoftError, _item );
} else {
// Other HBF error conditions.
// FIXME: find out the error class. // FIXME: find out the error class.
_item._httpErrorCode = hbf_fail_http_code(trans.data()); _item._httpErrorCode = hbf_fail_http_code(trans.data());
done(SyncFileItem::NormalError, hbf_error_string(trans.data(), state)); done(SyncFileItem::NormalError, hbf_error_string(trans.data(), state));
emit progressProblem(Progress::NormalError, _item);
}
return; return;
} }
@ -369,6 +382,10 @@ void PropagateUploadFile::start()
if( trans->modtime_accepted ) { if( trans->modtime_accepted ) {
_item._etag = QByteArray(hbf_transfer_etag( trans.data() )); _item._etag = QByteArray(hbf_transfer_etag( trans.data() ));
if (_item._etag.endsWith("-gzip")) {
// https://github.com/owncloud/mirall/issues/1195
_item._etag.chop(5);
}
} else { } else {
updateMTimeAndETag(uri.data(), _item._modtime); updateMTimeAndETag(uri.data(), _item._modtime);
} }
@ -376,8 +393,43 @@ void PropagateUploadFile::start()
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, _propagator->_localDir + _item._file)); _propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, _propagator->_localDir + _item._file));
// Remove from the progress database: // Remove from the progress database:
_propagator->_journal->setUploadInfo(_item._file, SyncJournalDb::UploadInfo()); _propagator->_journal->setUploadInfo(_item._file, SyncJournalDb::UploadInfo());
_propagator->_journal->commit(); _propagator->_journal->commit("upload file start");
emit progress(Progress::EndUpload, _item._file, 0, _item._size);
if (hbf_validate_source_file(trans.data()) == HBF_SOURCE_FILE_CHANGE) {
/* Did the source file changed since the upload ?
This is different from the previous check because the previous check happens between
chunks while this one happens when the whole file has been uploaded.
The new etag is already stored in the database in the previous lines so in case of
crash, we won't have a conflict but we will properly do a new upload
*/
if( attempts++ < 5 ) { /* FIXME: How often do we want to try? */
qDebug("SOURCE file has changed after upload, retry #%d in %d seconds!", attempts, 2*attempts);
sleep(2*attempts);
continue;
}
// Still the file change error, but we tried a couple of times.
// Ignore this file for now.
// Lets remove the file from the server (at least if it is new) as it is different
// from our file here.
if( _item._instruction == CSYNC_INSTRUCTION_NEW ) {
QScopedPointer<char, QScopedPointerPodDeleter> uri(
ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8()));
int rc = ne_delete(_propagator->_session, uri.data());
qDebug() << "Remove the invalid file from server:" << rc;
}
const QString errMsg = tr("Local file changed during sync, syncing once it arrived completely");
done( SyncFileItem::SoftError, errMsg );
return;
}
emit progress(Progress::EndUpload, _item, 0, _item._size);
done(SyncFileItem::Success); done(SyncFileItem::Success);
return; return;
@ -386,11 +438,17 @@ void PropagateUploadFile::start()
static QByteArray parseEtag(ne_request *req) { static QByteArray parseEtag(ne_request *req) {
const char *header = ne_get_response_header(req, "etag"); const char *header = ne_get_response_header(req, "etag");
QByteArray arr;
if(header && header [0] == '"' && header[ strlen(header)-1] == '"') { if(header && header [0] == '"' && header[ strlen(header)-1] == '"') {
return QByteArray(header + 1, strlen(header)-2); arr = QByteArray(header + 1, strlen(header)-2);
} else { } else {
return header; arr = header;
} }
if (arr.endsWith("-gzip")) {
// https://github.com/owncloud/mirall/issues/1195
arr.chop(5);
}
return arr;
} }
static QString parseFileId(ne_request *req) { static QString parseFileId(ne_request *req) {
@ -482,9 +540,10 @@ public:
void start(); void start();
private: private:
QIODevice *_file; QFile *_file;
QScopedPointer<ne_decompress, ScopedPointerHelpers> _decompress; QScopedPointer<ne_decompress, ScopedPointerHelpers> _decompress;
QString errorString; QString errorString;
QByteArray _expectedEtagForResume;
static int content_reader(void *userdata, const char *buf, size_t len) static int content_reader(void *userdata, const char *buf, size_t len)
{ {
@ -498,8 +557,9 @@ private:
if(buf) { if(buf) {
written = that->_file->write(buf, len); written = that->_file->write(buf, len);
if( len != written ) { if( len != written || that->_file->error() != QFile::NoError) {
qDebug() << "WRN: content_reader wrote wrong num of bytes:" << len << "," << written; qDebug() << "WRN: content_reader wrote wrong num of bytes:" << len << "," << written;
return NE_ERROR;
} }
return NE_OK; return NE_OK;
} }
@ -540,17 +600,28 @@ private:
return; return;
} }
const char *etag = ne_get_response_header( req, "ETag" ); QByteArray etag = parseEtag(req);
if (!etag) { if (etag.isEmpty()) {
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid"; qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid" << ne_get_response_header(req, "etag");
that->errorString = QLatin1String("No E-Tag received from server, check Proxy/Gateway"); that->errorString = QLatin1String("No E-Tag received from server, check Proxy/Gateway");
ne_set_error(that->_propagator->_session, "No E-Tag received from server, check Proxy/Gateway"); ne_set_error(that->_propagator->_session, "No E-Tag received from server, check Proxy/Gateway");
ne_add_response_body_reader( req, do_not_accept, ne_add_response_body_reader( req, do_not_accept,
do_not_download_content_reader, do_not_download_content_reader,
(void*) that ); (void*) that );
return; return;
} else if (!that->_expectedEtagForResume.isEmpty() && that->_expectedEtagForResume != etag) {
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
<< QString::fromLatin1(that->_expectedEtagForResume.data()) << "vs"
<< QString::fromLatin1(etag.data());
that->errorString = QLatin1String("We received a different E-Tag for resuming. Retrying next time.");
ne_set_error(that->_propagator->_session, "We received a different E-Tag for resuming. Retrying next time.");
ne_add_response_body_reader( req, do_not_accept,
do_not_download_content_reader,
(void*) that );
return;
} }
const char *enc = ne_get_response_header( req, "Content-Encoding" ); const char *enc = ne_get_response_header( req, "Content-Encoding" );
qDebug("Content encoding ist <%s> with status %d", enc ? enc : "empty", qDebug("Content encoding ist <%s> with status %d", enc ? enc : "empty",
status ? status->code : -1 ); status ? status->code : -1 );
@ -571,7 +642,7 @@ private:
{ {
PropagateDownloadFile* that = reinterpret_cast<PropagateDownloadFile*>(userdata); PropagateDownloadFile* that = reinterpret_cast<PropagateDownloadFile*>(userdata);
if (status == ne_status_recving && info->sr.total > 0) { if (status == ne_status_recving && info->sr.total > 0) {
emit that->progress(Progress::Context, that->_item._file, info->sr.progress, info->sr.total ); emit that->progress(Progress::Context, that->_item, info->sr.progress, info->sr.total );
that->limitBandwidth(info->sr.progress, that->_propagator->_downloadLimit); that->limitBandwidth(info->sr.progress, that->_propagator->_downloadLimit);
} }
} }
@ -579,7 +650,7 @@ private:
void PropagateDownloadFile::start() void PropagateDownloadFile::start()
{ {
emit progress(Progress::StartDownload, _item._file, 0, _item._size); emit progress(Progress::StartDownload, _item, 0, _item._size);
QString tmpFileName; QString tmpFileName;
const SyncJournalDb::DownloadInfo progressInfo = _propagator->_journal->getDownloadInfo(_item._file); const SyncJournalDb::DownloadInfo progressInfo = _propagator->_journal->getDownloadInfo(_item._file);
@ -590,6 +661,7 @@ void PropagateDownloadFile::start()
_propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo());
} else { } else {
tmpFileName = progressInfo._tmpfile; tmpFileName = progressInfo._tmpfile;
_expectedEtagForResume = progressInfo._etag;
} }
} }
@ -605,7 +677,7 @@ void PropagateDownloadFile::start()
QFile tmpFile(_propagator->_localDir + tmpFileName); QFile tmpFile(_propagator->_localDir + tmpFileName);
_file = &tmpFile; _file = &tmpFile;
if (!tmpFile.open(QIODevice::Append)) { if (!tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) {
done(SyncFileItem::NormalError, tmpFile.errorString()); done(SyncFileItem::NormalError, tmpFile.errorString());
return; return;
} }
@ -618,7 +690,7 @@ void PropagateDownloadFile::start()
pi._tmpfile = tmpFileName; pi._tmpfile = tmpFileName;
pi._valid = true; pi._valid = true;
_propagator->_journal->setDownloadInfo(_item._file, pi); _propagator->_journal->setDownloadInfo(_item._file, pi);
_propagator->_journal->commit(); _propagator->_journal->commit("download file start");
} }
/* actually do the request */ /* actually do the request */
@ -752,8 +824,8 @@ void PropagateDownloadFile::start()
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn)); _propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn));
_propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo());
_propagator->_journal->commit(); _propagator->_journal->commit("download file start2");
emit progress(Progress::EndDownload, _item._file, 0, _item._size); emit progress(Progress::EndDownload, _item, 0, _item._size);
done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success); done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
} }
@ -761,7 +833,7 @@ DECLARE_JOB(PropagateLocalRename)
void PropagateLocalRename::start() void PropagateLocalRename::start()
{ {
emit progress(Progress::StartRename, _item._file, 0, _item._size); emit progress(Progress::StartRename, _item, 0, _item._size);
if (_item._file != _item._renameTarget) { if (_item._file != _item._renameTarget) {
qDebug() << "MOVE " << _propagator->_localDir + _item._file << " => " << _propagator->_localDir + _item._renameTarget; qDebug() << "MOVE " << _propagator->_localDir + _item._file << " => " << _propagator->_localDir + _item._renameTarget;
QFile::rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget); QFile::rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget);
@ -777,9 +849,9 @@ void PropagateLocalRename::start()
record._path = _item._renameTarget; record._path = _item._renameTarget;
_propagator->_journal->setFileRecord(record); _propagator->_journal->setFileRecord(record);
_propagator->_journal->commit(); _propagator->_journal->commit("localRename");
emit progress(Progress::EndRename, _item._file, 0, _item._size); emit progress(Progress::EndRename, _item, 0, _item._size);
done(SyncFileItem::Success); done(SyncFileItem::Success);
} }
@ -807,7 +879,7 @@ void PropagateRemoteRename::start()
} }
return; return;
} else { } else {
emit progress(Progress::StartRename, _item._file, 0, _item._size); emit progress(Progress::StartRename, _item, 0, _item._size);
QScopedPointer<char, QScopedPointerPodDeleter> uri1(ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); QScopedPointer<char, QScopedPointerPodDeleter> uri1(ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8()));
QScopedPointer<char, QScopedPointerPodDeleter> uri2(ne_path_escape((_propagator->_remoteDir + _item._renameTarget).toUtf8())); QScopedPointer<char, QScopedPointerPodDeleter> uri2(ne_path_escape((_propagator->_remoteDir + _item._renameTarget).toUtf8()));
@ -819,7 +891,7 @@ void PropagateRemoteRename::start()
} }
updateMTimeAndETag(uri2.data(), _item._modtime); updateMTimeAndETag(uri2.data(), _item._modtime);
emit progress(Progress::EndRename, _item._file, 0, _item._size); emit progress(Progress::EndRename, _item, 0, _item._size);
} }
@ -828,7 +900,7 @@ void PropagateRemoteRename::start()
record._path = _item._renameTarget; record._path = _item._renameTarget;
_propagator->_journal->setFileRecord(record); _propagator->_journal->setFileRecord(record);
_propagator->_journal->commit(); _propagator->_journal->commit("Remote Rename");
done(SyncFileItem::Success); done(SyncFileItem::Success);
} }
@ -873,7 +945,8 @@ bool PropagateItemJob::updateErrorFromSession(int neon_code, ne_request* req, in
// Check if we don't need to ignore that error. // Check if we don't need to ignore that error.
httpStatusCode = errorString.mid(0, errorString.indexOf(QChar(' '))).toInt(); httpStatusCode = errorString.mid(0, errorString.indexOf(QChar(' '))).toInt();
_item._httpErrorCode = httpStatusCode; _item._httpErrorCode = httpStatusCode;
if (httpStatusCode == ignoreHttpCode) qDebug() << Q_FUNC_INFO << "NE_ERROR" << errorString << httpStatusCode << ignoreHttpCode;
if (ignoreHttpCode && httpStatusCode == ignoreHttpCode)
return false; return false;
done(SyncFileItem::NormalError, errorString); done(SyncFileItem::NormalError, errorString);
@ -972,8 +1045,10 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
} }
connect(_rootJob.data(), SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem))); connect(_rootJob.data(), SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem)));
connect(_rootJob.data(), SIGNAL(progress(Progress::Kind,QString,quint64,quint64)), this, SIGNAL(progress(Progress::Kind,QString,quint64,quint64))); connect(_rootJob.data(), SIGNAL(progress(Progress::Kind,SyncFileItem,quint64,quint64)), this,
SIGNAL(progress(Progress::Kind,SyncFileItem,quint64,quint64)));
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SIGNAL(finished())); connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SIGNAL(finished()));
_rootJob->start(); _rootJob->start();
} }

View file

@ -43,7 +43,8 @@ public slots:
signals: signals:
void finished(SyncFileItem::Status); void finished(SyncFileItem::Status);
void completed(const SyncFileItem &); void completed(const SyncFileItem &);
void progress(Progress::Kind, const QString &filename, quint64 bytes, quint64 total); void progress(Progress::Kind, const SyncFileItem& item, quint64 bytes, quint64 total);
void progressProblem( Progress::Kind, const SyncFileItem& );
}; };
/* /*
@ -84,7 +85,7 @@ private slots:
void startJob(PropagatorJob *next) { void startJob(PropagatorJob *next) {
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(proceedNext(SyncFileItem::Status)), Qt::QueuedConnection); connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(proceedNext(SyncFileItem::Status)), Qt::QueuedConnection);
connect(next, SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem))); connect(next, SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem)));
connect(next, SIGNAL(progress(Progress::Kind,QString,quint64,quint64)), this, SIGNAL(progress(Progress::Kind,QString,quint64,quint64))); connect(next, SIGNAL(progress(Progress::Kind,SyncFileItem,quint64,quint64)), this, SIGNAL(progress(Progress::Kind,SyncFileItem,quint64,quint64)));
next->start(); next->start();
} }
@ -170,8 +171,10 @@ public:
signals: signals:
void completed(const SyncFileItem &); void completed(const SyncFileItem &);
void progress(Progress::Kind, const QString &filename, quint64 bytes, quint64 total); void progress(Progress::Kind kind, const SyncFileItem&, quint64 bytes, quint64 total);
void progressProblem( Progress::Kind, const SyncFileItem& );
void finished(); void finished();
}; };
} }

View file

@ -125,6 +125,7 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
Account *account = _ocWizard->account(); Account *account = _ocWizard->account();
account->setUrl(url); account->setUrl(url);
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), false, this); CheckServerJob *job = new CheckServerJob(_ocWizard->account(), false, this);
job->setIgnoreCredentialFailure(true);
connect(job, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotOwnCloudFoundAuth(QUrl,QVariantMap))); connect(job, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotOwnCloudFoundAuth(QUrl,QVariantMap)));
connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*))); connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*)));
connect(job, SIGNAL(timeout(const QUrl&)), SLOT(slotNoOwnCloudFoundAuthTimeout(const QUrl&))); connect(job, SIGNAL(timeout(const QUrl&)), SLOT(slotNoOwnCloudFoundAuthTimeout(const QUrl&)));
@ -149,6 +150,7 @@ void OwncloudSetupWizard::slotOwnCloudFoundAuth(const QUrl& url, const QVariantM
} }
DetermineAuthTypeJob *job = new DetermineAuthTypeJob(_ocWizard->account(), this); DetermineAuthTypeJob *job = new DetermineAuthTypeJob(_ocWizard->account(), this);
job->setIgnoreCredentialFailure(true);
connect(job, SIGNAL(authType(WizardCommon::AuthType)), connect(job, SIGNAL(authType(WizardCommon::AuthType)),
_ocWizard, SLOT(setAuthType(WizardCommon::AuthType))); _ocWizard, SLOT(setAuthType(WizardCommon::AuthType)));
job->start(); job->start();
@ -184,6 +186,7 @@ void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
void OwncloudSetupWizard::testOwnCloudConnect() void OwncloudSetupWizard::testOwnCloudConnect()
{ {
ValidateDavAuthJob *job = new ValidateDavAuthJob(_ocWizard->account(), this); ValidateDavAuthJob *job = new ValidateDavAuthJob(_ocWizard->account(), this);
job->setIgnoreCredentialFailure(true);
connect(job, SIGNAL(authResult(QNetworkReply*)), SLOT(slotConnectionCheck(QNetworkReply*))); connect(job, SIGNAL(authResult(QNetworkReply*)), SLOT(slotConnectionCheck(QNetworkReply*)));
job->start(); job->start();
} }
@ -430,9 +433,10 @@ void DetermineAuthTypeJob::start()
QNetworkReply *reply = getRequest(Account::davPath()); QNetworkReply *reply = getRequest(Account::davPath());
setReply(reply); setReply(reply);
setupConnections(reply); setupConnections(reply);
AbstractNetworkJob::start();
} }
void DetermineAuthTypeJob::slotFinished() void DetermineAuthTypeJob::finished()
{ {
QUrl redirection = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); QUrl redirection = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << redirection.toString(); qDebug() << redirection.toString();
@ -458,7 +462,6 @@ void DetermineAuthTypeJob::slotFinished()
emit authType(WizardCommon::HttpCreds); emit authType(WizardCommon::HttpCreds);
} }
} }
deleteLater();
} }
ValidateDavAuthJob::ValidateDavAuthJob(Account *account, QObject *parent) ValidateDavAuthJob::ValidateDavAuthJob(Account *account, QObject *parent)
@ -471,12 +474,12 @@ void ValidateDavAuthJob::start()
QNetworkReply *reply = getRequest(Account::davPath()); QNetworkReply *reply = getRequest(Account::davPath());
setReply(reply); setReply(reply);
setupConnections(reply); setupConnections(reply);
AbstractNetworkJob::start();
} }
void ValidateDavAuthJob::slotFinished() void ValidateDavAuthJob::finished()
{ {
emit authResult(reply()); emit authResult(reply());
deleteLater();
} }
} // ns Mirall } // ns Mirall

View file

@ -39,7 +39,7 @@ public:
signals: signals:
void authResult(QNetworkReply*); void authResult(QNetworkReply*);
private slots: private slots:
void slotFinished(); void finished();
}; };
class DetermineAuthTypeJob : public AbstractNetworkJob { class DetermineAuthTypeJob : public AbstractNetworkJob {
@ -50,7 +50,7 @@ public:
signals: signals:
void authType(WizardCommon::AuthType); void authType(WizardCommon::AuthType);
private slots: private slots:
void slotFinished(); void finished();
private: private:
int _redirects; int _redirects;
}; };

View file

@ -124,6 +124,15 @@ QString Progress::asActionString( Kind kind )
return re; return re;
} }
bool Progress::isErrorKind( Kind kind )
{
bool re = false;
if( kind == SoftError || kind == NormalError || kind == FatalError ) {
re = true;
}
return re;
}
ProgressDispatcher* ProgressDispatcher::instance() { ProgressDispatcher* ProgressDispatcher::instance() {
if (!_instance) { if (!_instance) {
_instance = new ProgressDispatcher(); _instance = new ProgressDispatcher();
@ -159,28 +168,26 @@ QList<Progress::SyncProblem> ProgressDispatcher::recentProblems(int count)
return _recentProblems; return _recentProblems;
} }
void ProgressDispatcher::setProgressProblem(const QString& folder, const Progress::SyncProblem &problem)
{
Q_ASSERT( Progress::isErrorKind(problem.kind));
_recentProblems.prepend( problem );
if( _recentProblems.size() > _QueueSize ) {
_recentProblems.removeLast();
}
emit progressSyncProblem( folder, problem );
}
void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress) void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress)
{ {
if( folder.isEmpty() ) { if( folder.isEmpty() ) {
return; return;
} }
Progress::Info newProgress = progress; Progress::Info newProgress(progress);
if( newProgress.kind == Progress::Error ) { Q_ASSERT( !Progress::isErrorKind(progress.kind));
Progress::SyncProblem err;
err.folder = folder;
err.current_file = newProgress.current_file;
// its really
err.error_message = QString::fromLocal8Bit( (const char*)newProgress.file_size );
err.error_code = newProgress.current_file_bytes;
err.timestamp = QDateTime::currentDateTime();
_recentProblems.prepend( err );
if( _recentProblems.size() > _QueueSize ) {
_recentProblems.removeLast();
}
emit progressSyncProblem( folder, err );
} else {
if( newProgress.kind == Progress::StartSync ) { if( newProgress.kind == Progress::StartSync ) {
_recentProblems.clear(); _recentProblems.clear();
_timer.start(); _timer.start();
@ -211,7 +218,7 @@ void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::
} }
emit progressInfo( folder, newProgress ); emit progressInfo( folder, newProgress );
}
} }
Progress::Kind ProgressDispatcher::currentFolderContext( const QString& folder ) Progress::Kind ProgressDispatcher::currentFolderContext( const QString& folder )

View file

@ -44,7 +44,9 @@ namespace Progress
EndDelete, EndDelete,
StartRename, StartRename,
EndRename, EndRename,
Error SoftError,
NormalError,
FatalError
}; };
struct Info { struct Info {
@ -67,15 +69,20 @@ namespace Progress
}; };
struct SyncProblem { struct SyncProblem {
Kind kind;
QString folder; QString folder;
QString current_file; QString current_file;
QString error_message; QString error_message;
int error_code; int error_code;
QDateTime timestamp; QDateTime timestamp;
SyncProblem() : kind(Invalid), error_code(0) {}
}; };
QString asActionString( Kind ); QString asActionString( Kind );
QString asResultString( Kind ); QString asResultString( Kind );
bool isErrorKind( Kind );
} }
/** /**
@ -100,6 +107,7 @@ public:
QList<Progress::SyncProblem> recentProblems(int count); QList<Progress::SyncProblem> recentProblems(int count);
Progress::Kind currentFolderContext( const QString& folder ); Progress::Kind currentFolderContext( const QString& folder );
signals: signals:
/** /**
@brief Signals the progress of data transmission. @brief Signals the progress of data transmission.
@ -113,7 +121,8 @@ signals:
void progressSyncProblem( const QString& folder, const Progress::SyncProblem& problem ); void progressSyncProblem( const QString& folder, const Progress::SyncProblem& problem );
protected: protected:
void setProgressInfo(const QString &folder, const Progress::Info& progress); void setProgressInfo(const QString& folder, const Progress::Info& progress);
void setProgressProblem( const QString& folder, const Progress::SyncProblem& problem);
private: private:
ProgressDispatcher(QObject* parent = 0); ProgressDispatcher(QObject* parent = 0);

View file

@ -111,7 +111,8 @@ void ProtocolWidget::setSyncResult( const SyncResult& result )
// handle ignored files here. // handle ignored files here.
if( item._status == SyncFileItem::FileIgnored if( item._status == SyncFileItem::FileIgnored
|| item._status == SyncFileItem::Conflict ) { || item._status == SyncFileItem::Conflict
|| item._status == SyncFileItem::SoftError ) {
QStringList columns; QStringList columns;
QString timeStr = timeString(dt); QString timeStr = timeString(dt);
QString longTimeStr = timeString(dt, QLocale::LongFormat); QString longTimeStr = timeString(dt, QLocale::LongFormat);
@ -120,7 +121,10 @@ void ProtocolWidget::setSyncResult( const SyncResult& result )
columns << item._file; columns << item._file;
columns << folder; columns << folder;
if( item._status == SyncFileItem::FileIgnored ) { if( item._status == SyncFileItem::FileIgnored ) {
if( item._type == SyncFileItem::SoftLink ) { if( item._blacklistedInDb ) {
errMsg = tr("Blacklisted");
tooltip = tr("The file is blacklisted because of previous error conditions.");
}else if( item._type == SyncFileItem::SoftLink ) {
errMsg = tr("Soft Link ignored"); errMsg = tr("Soft Link ignored");
tooltip = tr("Softlinks break the semantics of synchronization.\nPlease do not " tooltip = tr("Softlinks break the semantics of synchronization.\nPlease do not "
"use them in synced directories"); "use them in synced directories");
@ -149,6 +153,8 @@ void ProtocolWidget::setSyncResult( const SyncResult& result )
"created a so called conflict. The local change is copied to the conflict\n" "created a so called conflict. The local change is copied to the conflict\n"
"file while the file from the server side is available under the original\n" "file while the file from the server side is available under the original\n"
"name"); "name");
} else if( item._status == SyncFileItem::SoftError ) {
errMsg = item._errorString;
} else { } else {
Q_ASSERT(!"unhandled instruction."); Q_ASSERT(!"unhandled instruction.");
} }
@ -181,7 +187,6 @@ void ProtocolWidget::setupList()
haveSyncResult = true; haveSyncResult = true;
} }
if( haveSyncResult ) { if( haveSyncResult ) {
setSyncResult(lastResult); setSyncResult(lastResult);
} }
@ -285,7 +290,7 @@ void ProtocolWidget::slotProgressProblem( const QString& folder, const Progress:
columns << timeStr; columns << timeStr;
columns << problem.current_file; columns << problem.current_file;
columns << folder; columns << folder;
QString errMsg = tr("Problem: %1").arg(problem.error_message); QString errMsg = problem.error_message;
#if 0 #if 0
if( problem.error_code == 507 ) { if( problem.error_code == 507 ) {
errMsg = tr("No more storage space available on server."); errMsg = tr("No more storage space available on server.");
@ -297,7 +302,11 @@ void ProtocolWidget::slotProgressProblem( const QString& folder, const Progress:
item->setData(0, ErrorIndicatorRole, QVariant(true) ); item->setData(0, ErrorIndicatorRole, QVariant(true) );
// Maybe we should not set the error icon for all problems but distinguish // Maybe we should not set the error icon for all problems but distinguish
// by error_code. A quota problem is considered an error, others might not?? // by error_code. A quota problem is considered an error, others might not??
if( problem.kind == Progress::SoftError ) {
item->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Problem, true));
} else {
item->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Error, true)); item->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Error, true));
}
item->setToolTip(0, longTimeStr); item->setToolTip(0, longTimeStr);
_ui->_treeWidget->insertTopLevelItem(0, item); _ui->_treeWidget->insertTopLevelItem(0, item);
Q_UNUSED(item); Q_UNUSED(item);

View file

@ -17,6 +17,7 @@
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#include <QTimer> #include <QTimer>
#include <QDebug>
namespace Mirall { namespace Mirall {
@ -28,6 +29,7 @@ static const int initialTimeT = 1*1000;
QuotaInfo::QuotaInfo(QObject *parent) QuotaInfo::QuotaInfo(QObject *parent)
: QObject(parent) : QObject(parent)
, _account(AccountManager::instance()->account())
, _lastQuotaTotalBytes(0) , _lastQuotaTotalBytes(0)
, _lastQuotaUsedBytes(0) , _lastQuotaUsedBytes(0)
, _refreshTimer(new QTimer(this)) , _refreshTimer(new QTimer(this))
@ -41,8 +43,18 @@ QuotaInfo::QuotaInfo(QObject *parent)
void QuotaInfo::slotAccountChanged(Account *newAccount, Account *oldAccount) void QuotaInfo::slotAccountChanged(Account *newAccount, Account *oldAccount)
{ {
Q_UNUSED(oldAccount);
_account = newAccount; _account = newAccount;
disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int)));
connect(newAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int)));
}
void QuotaInfo::slotAccountStateChanged(int state)
{
if (state == Account::Connected) {
slotCheckQuota();
} else {
_refreshTimer->stop();
}
} }
void QuotaInfo::slotCheckQuota() void QuotaInfo::slotCheckQuota()

View file

@ -34,6 +34,7 @@ public Q_SLOTS:
private Q_SLOTS: private Q_SLOTS:
void slotAccountChanged(Account *newAccount, Account *oldAccount); void slotAccountChanged(Account *newAccount, Account *oldAccount);
void slotAccountStateChanged(int state);
Q_SIGNALS: Q_SIGNALS:
void quotaUpdated(qint64 total, qint64 used); void quotaUpdated(qint64 total, qint64 used);

View file

@ -57,8 +57,8 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) :
QListWidgetItem *protocol= new QListWidgetItem(protocolIcon, tr("Status"), _ui->labelWidget); QListWidgetItem *protocol= new QListWidgetItem(protocolIcon, tr("Status"), _ui->labelWidget);
protocol->setSizeHint(QSize(0, 32)); protocol->setSizeHint(QSize(0, 32));
_ui->labelWidget->addItem(protocol); _ui->labelWidget->addItem(protocol);
ProtocolWidget *protocolWidget = new ProtocolWidget; _protocolWidget = new ProtocolWidget;
_protocolIdx = _ui->stack->addWidget(protocolWidget); _protocolIdx = _ui->stack->addWidget(_protocolWidget);
QIcon generalIcon(QLatin1String(":/mirall/resources/settings.png")); QIcon generalIcon(QLatin1String(":/mirall/resources/settings.png"));
QListWidgetItem *general = new QListWidgetItem(generalIcon, tr("General"), _ui->labelWidget); QListWidgetItem *general = new QListWidgetItem(generalIcon, tr("General"), _ui->labelWidget);
@ -179,4 +179,9 @@ void SettingsDialog::accept() {
QDialog::accept(); QDialog::accept();
} }
void SettingsDialog::slotRefreshResultList() {
if( _protocolWidget ) {
_protocolWidget->setupList();
}
}
} // namespace Mirall } // namespace Mirall

View file

@ -28,6 +28,7 @@ namespace Ui {
class SettingsDialog; class SettingsDialog;
} }
class AccountSettings; class AccountSettings;
class ProtocolWidget;
class Application; class Application;
class FolderMan; class FolderMan;
class ownCloudGui; class ownCloudGui;
@ -46,6 +47,7 @@ public:
public slots: public slots:
void slotSyncStateChange(const QString& alias); void slotSyncStateChange(const QString& alias);
void slotShowProtocol(); void slotShowProtocol();
void slotRefreshResultList();
protected: protected:
void reject(); void reject();
@ -55,6 +57,7 @@ private:
Ui::SettingsDialog *_ui; Ui::SettingsDialog *_ui;
AccountSettings *_accountSettings; AccountSettings *_accountSettings;
QListWidgetItem *_accountItem; QListWidgetItem *_accountItem;
ProtocolWidget *_protocolWidget;
int _protocolIdx; int _protocolIdx;
}; };

View file

@ -24,12 +24,11 @@
#include "syncjournalfilerecord.h" #include "syncjournalfilerecord.h"
#define QSQLITE "QSQLITE" #define QSQLITE "QSQLITE"
#define SYNCJOURNALDB_CONNECTION_NAME "SyncJournalDbConnection"
namespace Mirall { namespace Mirall {
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) : SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
QObject(parent) QObject(parent), _transaction(0)
{ {
_dbFile = path; _dbFile = path;
@ -47,6 +46,42 @@ bool SyncJournalDb::exists()
return (!_dbFile.isEmpty() && QFile::exists(_dbFile)); return (!_dbFile.isEmpty() && QFile::exists(_dbFile));
} }
void SyncJournalDb::startTransaction()
{
if( _transaction == 0 ) {
if( !_db.transaction() ) {
qDebug() << "ERROR commiting to the database: " << _db.lastError().text();
return;
}
_transaction = 1;
// qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Transaction start!";
} else {
qDebug() << "Database Transaction is running, do not starting another one!";
}
}
void SyncJournalDb::commitTransaction()
{
if( _transaction == 1 ) {
if( ! _db.commit() ) {
qDebug() << "ERROR commiting to the database: " << _db.lastError().text();
return;
}
_transaction = 0;
// qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Transaction END!";
} else {
qDebug() << "No database Transaction to commit";
}
}
bool SyncJournalDb::sqlFail( const QString& log, const QSqlQuery& query )
{
commitTransaction();
qWarning() << "Error" << log << query.lastError().text();
return false;
}
bool SyncJournalDb::checkConnect() bool SyncJournalDb::checkConnect()
{ {
if( _db.isOpen() ) { if( _db.isOpen() ) {
@ -69,8 +104,7 @@ bool SyncJournalDb::checkConnect()
} }
// Add the connection // Add the connection
if (!QSqlDatabase::connectionNames().contains(SYNCJOURNALDB_CONNECTION_NAME)) _db = QSqlDatabase::addDatabase( QSQLITE, _dbFile);
_db = QSqlDatabase::addDatabase( QSQLITE, SYNCJOURNALDB_CONNECTION_NAME );
// Open the file // Open the file
_db.setDatabaseName(_dbFile); _db.setDatabaseName(_dbFile);
@ -86,18 +120,15 @@ bool SyncJournalDb::checkConnect()
QSqlQuery pragma1(_db); QSqlQuery pragma1(_db);
pragma1.prepare("PRAGMA synchronous = 1;"); pragma1.prepare("PRAGMA synchronous = 1;");
if (!pragma1.exec()) { if (!pragma1.exec()) {
qWarning() << "Error setting pragma: " << pragma1.lastError().text(); return sqlFail("Set PRAGMA synchronous", pragma1);
return false;
} }
pragma1.prepare("PRAGMA case_sensitive_like = ON;"); pragma1.prepare("PRAGMA case_sensitive_like = ON;");
if (!pragma1.exec()) { if (!pragma1.exec()) {
qWarning() << "Error setting pragma: " << pragma1.lastError().text(); return sqlFail("Set PRAGMA case_sensitivity", pragma1);
return false;
} }
/* Because insert are so slow, e do everything in a transaction, and one need to call commit */ /* Because insert are so slow, e do everything in a transaction, and one need to call commit */
_db.transaction(); startTransaction();
QSqlQuery createQuery(_db); QSqlQuery createQuery(_db);
createQuery.prepare("CREATE TABLE IF NOT EXISTS metadata(" createQuery.prepare("CREATE TABLE IF NOT EXISTS metadata("
@ -115,8 +146,7 @@ bool SyncJournalDb::checkConnect()
");"); ");");
if (!createQuery.exec()) { if (!createQuery.exec()) {
qWarning() << "Error creating table metadata : " << createQuery.lastError().text(); return sqlFail("Create table metadata", createQuery);
return false;
} }
createQuery.prepare("CREATE TABLE IF NOT EXISTS downloadinfo(" createQuery.prepare("CREATE TABLE IF NOT EXISTS downloadinfo("
@ -128,8 +158,7 @@ bool SyncJournalDb::checkConnect()
");"); ");");
if (!createQuery.exec()) { if (!createQuery.exec()) {
qWarning() << "Error creating table downloadinfo : " << createQuery.lastError().text(); return sqlFail("Create table downloadinfo", createQuery);
return false;
} }
createQuery.prepare("CREATE TABLE IF NOT EXISTS uploadinfo(" createQuery.prepare("CREATE TABLE IF NOT EXISTS uploadinfo("
@ -143,8 +172,7 @@ bool SyncJournalDb::checkConnect()
");"); ");");
if (!createQuery.exec()) { if (!createQuery.exec()) {
qWarning() << "Error creating table downloadinfo : " << createQuery.lastError().text(); return sqlFail("Create table uploadinfo", createQuery);
return false;
} }
// create the blacklist table. // create the blacklist table.
@ -152,16 +180,17 @@ bool SyncJournalDb::checkConnect()
"path VARCHAR(4096)," "path VARCHAR(4096),"
"lastTryEtag VARCHAR[32]," "lastTryEtag VARCHAR[32],"
"lastTryModtime INTEGER[8]," "lastTryModtime INTEGER[8],"
"retrycount INTEGER default 0," "retrycount INTEGER,"
"errorstring VARCHAR[4096]," "errorstring VARCHAR[4096],"
"PRIMARY KEY(path)" "PRIMARY KEY(path)"
");"); ");");
if (!createQuery.exec()) { if (!createQuery.exec()) {
qWarning() << "Error creating table blacklist: " << createQuery.lastError().text(); return sqlFail("Create table blacklist", createQuery);
return false;
} }
commitInternal("checkConnect");
bool rc = updateDatabaseStructure(); bool rc = updateDatabaseStructure();
if( rc ) { if( rc ) {
_getFileRecordQuery.reset(new QSqlQuery(_db)); _getFileRecordQuery.reset(new QSqlQuery(_db));
@ -215,6 +244,8 @@ void SyncJournalDb::close()
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
commitTransaction();
_getFileRecordQuery.reset(0); _getFileRecordQuery.reset(0);
_setFileRecordQuery.reset(0); _setFileRecordQuery.reset(0);
_getDownloadInfoQuery.reset(0); _getDownloadInfoQuery.reset(0);
@ -226,7 +257,10 @@ void SyncJournalDb::close()
_deleteFileRecordPhash.reset(0); _deleteFileRecordPhash.reset(0);
_deleteFileRecordRecursively.reset(0); _deleteFileRecordRecursively.reset(0);
_blacklistQuery.reset(0); _blacklistQuery.reset(0);
_db.close(); _db.close();
_db = QSqlDatabase(); // avoid the warning QSqlDatabasePrivate::removeDatabase: connection [...] still in use
QSqlDatabase::removeDatabase(_dbFile);
} }
@ -236,13 +270,19 @@ bool SyncJournalDb::updateDatabaseStructure()
bool re = true; bool re = true;
// check if the file_id column is there and create it if not // check if the file_id column is there and create it if not
if( !checkConnect() ) {
return false;
}
if( columns.indexOf(QLatin1String("fileid")) == -1 ) { if( columns.indexOf(QLatin1String("fileid")) == -1 ) {
QSqlQuery query(_db); QSqlQuery query(_db);
query.prepare("ALTER TABLE metadata ADD COLUMN fileid VARCHAR(128);"); query.prepare("ALTER TABLE metadata ADD COLUMN fileid VARCHAR(128);");
re = query.exec(); re = query.exec();
query.prepare("CREATE INDEX metadata_file_id ON metadata(fileid);"); query.prepare("CREATE INDEX metadata_file_id ON metadata(fileid);");
re = re && query.exec(); re = re && query.exec();
commitInternal("update database structure");
} }
return re; return re;
@ -253,6 +293,7 @@ QStringList SyncJournalDb::tableColumns( const QString& table )
QStringList columns; QStringList columns;
if( !table.isEmpty() ) { if( !table.isEmpty() ) {
if( checkConnect() ) {
QString q = QString("PRAGMA table_info(%1);").arg(table); QString q = QString("PRAGMA table_info(%1);").arg(table);
QSqlQuery query(_db); QSqlQuery query(_db);
query.prepare(q); query.prepare(q);
@ -266,7 +307,7 @@ QStringList SyncJournalDb::tableColumns( const QString& table )
while( query.next() ) { while( query.next() ) {
columns.append( query.value(1).toString() ); columns.append( query.value(1).toString() );
} }
query.finish(); }
} }
qDebug() << "Columns in the current journal: " << columns; qDebug() << "Columns in the current journal: " << columns;
@ -418,8 +459,9 @@ bool SyncJournalDb::postSyncCleanup(const QHash<QString, QString> &items )
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
if( !checkConnect() ) if( !checkConnect() ) {
return false; return false;
}
QSqlQuery query(_db); QSqlQuery query(_db);
query.prepare("SELECT phash, path FROM metadata order by path"); query.prepare("SELECT phash, path FROM metadata order by path");
@ -458,8 +500,9 @@ int SyncJournalDb::getFileRecordCount()
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
if( !checkConnect() ) if( !checkConnect() ) {
return -1; return -1;
}
QSqlQuery query(_db); QSqlQuery query(_db);
query.prepare("SELECT COUNT(*) FROM metadata"); query.prepare("SELECT COUNT(*) FROM metadata");
@ -509,8 +552,9 @@ void SyncJournalDb::setDownloadInfo(const QString& file, const SyncJournalDb::Do
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
if( !checkConnect() ) if( !checkConnect() ) {
return; return;
}
if (i._valid) { if (i._valid) {
_setDownloadInfoQuery->bindValue(0, file); _setDownloadInfoQuery->bindValue(0, file);
@ -572,8 +616,9 @@ void SyncJournalDb::setUploadInfo(const QString& file, const SyncJournalDb::Uplo
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
if( !checkConnect() ) if( !checkConnect() ) {
return; return;
}
if (i._valid) { if (i._valid) {
_setUploadInfoQuery->bindValue(0, file); _setUploadInfoQuery->bindValue(0, file);
@ -635,30 +680,35 @@ SyncJournalBlacklistRecord SyncJournalDb::blacklistEntry( const QString& file )
void SyncJournalDb::wipeBlacklistEntry( const QString& file ) void SyncJournalDb::wipeBlacklistEntry( const QString& file )
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
if( checkConnect() ) {
QSqlQuery query; QSqlQuery query(_db);
query.prepare("DELETE FROM blacklist WHERE path=:path"); query.prepare("DELETE FROM blacklist WHERE path=:path");
query.bindValue(":path", file); query.bindValue(":path", file);
if( ! query.exec() ) { if( ! query.exec() ) {
qDebug() << "Deletion of blacklist item failed."; qDebug() << "Deletion of blacklist item failed.";
} }
}
} }
void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item ) void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item )
{ {
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);
QSqlQuery query; QSqlQuery query(_db);
if( !checkConnect() ) {
return;
}
query.prepare("SELECT retrycount FROM blacklist WHERE path=:path"); query.prepare("SELECT retrycount FROM blacklist WHERE path=:path");
query.bindValue(":path", item._file); query.bindValue(":path", item._file);
if( !query.exec() ) { if( !query.exec() ) {
qDebug() << "SQL exec blacklistitem failed."; qDebug() << "SQL exec blacklistitem failed:" << query.lastError().text();
return; return;
} }
QSqlQuery iQuery; QSqlQuery iQuery(_db);
if( query.next() ) { if( query.next() ) {
int retries = query.value(0).toInt(); int retries = query.value(0).toInt();
retries--; retries--;
@ -685,20 +735,29 @@ void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item
if( !iQuery.exec() ) { if( !iQuery.exec() ) {
qDebug() << "SQL exec blacklistitem insert/update failed: "<< iQuery.lastError().text(); qDebug() << "SQL exec blacklistitem insert/update failed: "<< iQuery.lastError().text();
} }
} }
void SyncJournalDb::commit() void SyncJournalDb::commit(const QString& context, bool startTrans)
{ {
QMutexLocker locker(&_mutex); QMutexLocker lock(&_mutex);
if (!_db.commit()) { commitInternal(context, startTrans);
qDebug() << "ERROR commiting to the database: " << _db.lastError().text(); }
void SyncJournalDb::commitInternal(const QString& context, bool startTrans )
{
qDebug() << "Transaction Start " << context;
commitTransaction();
if( startTrans ) {
startTransaction();
} }
_db.transaction();
} }
SyncJournalDb::~SyncJournalDb() SyncJournalDb::~SyncJournalDb()
{ {
_db.commit(); close();
} }

View file

@ -36,7 +36,6 @@ public:
bool deleteFileRecord( const QString& filename, bool recursively = false ); bool deleteFileRecord( const QString& filename, bool recursively = false );
int getFileRecordCount(); int getFileRecordCount();
bool exists(); bool exists();
QStringList tableColumns( const QString& table );
void updateBlacklistEntry( const SyncJournalBlacklistRecord& item ); void updateBlacklistEntry( const SyncJournalBlacklistRecord& item );
void wipeBlacklistEntry(const QString& file); void wipeBlacklistEntry(const QString& file);
@ -68,9 +67,11 @@ public:
/* Because sqlite transactions is really slow, we encapsulate everything in big transactions /* Because sqlite transactions is really slow, we encapsulate everything in big transactions
* Commit will actually commit the transaction and create a new one. * Commit will actually commit the transaction and create a new one.
*/ */
void commit(); void commit(const QString &context, bool startTrans = true);
void close(); void close();
signals: signals:
public slots: public slots:
@ -78,11 +79,17 @@ public slots:
private: private:
qint64 getPHash(const QString& ) const; qint64 getPHash(const QString& ) const;
bool updateDatabaseStructure(); bool updateDatabaseStructure();
bool sqlFail(const QString& log, const QSqlQuery &query );
void commitInternal(const QString &context, bool startTrans = true);
void startTransaction();
void commitTransaction();
QStringList tableColumns( const QString& table );
bool checkConnect(); bool checkConnect();
QSqlDatabase _db; QSqlDatabase _db;
QString _dbFile; QString _dbFile;
QMutex _mutex; // Public functions are protected with the mutex. QMutex _mutex; // Public functions are protected with the mutex.
int _transaction;
QScopedPointer<QSqlQuery> _getFileRecordQuery; QScopedPointer<QSqlQuery> _getFileRecordQuery;
QScopedPointer<QSqlQuery> _setFileRecordQuery; QScopedPointer<QSqlQuery> _setFileRecordQuery;
QScopedPointer<QSqlQuery> _getDownloadInfoQuery; QScopedPointer<QSqlQuery> _getDownloadInfoQuery;

View file

@ -13,6 +13,7 @@
*/ */
#include "systray.h" #include "systray.h"
#include "mirall/theme.h"
#ifdef USE_FDO_NOTIFICATIONS #ifdef USE_FDO_NOTIFICATIONS
#include <QDBusConnection> #include <QDBusConnection>
@ -43,4 +44,9 @@ void Systray::showMessage(const QString & title, const QString & message, Messag
} }
} }
void Systray::setToolTip(const QString &tip)
{
QSystemTrayIcon::setToolTip(tr("%1: %2").arg(Theme::instance()->appNameGUI(), tip));
}
} // namespace Mirall } // namespace Mirall

View file

@ -26,7 +26,7 @@ class Systray : public QSystemTrayIcon
Q_OBJECT Q_OBJECT
public: public:
void showMessage(const QString & title, const QString & message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000); void showMessage(const QString & title, const QString & message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000);
void setToolTip(const QString &tip);
}; };
} // namespace Mirall } // namespace Mirall

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff