diff --git a/NEXTCLOUD.cmake b/NEXTCLOUD.cmake index 7cc321c140..b6bc79c6bd 100644 --- a/NEXTCLOUD.cmake +++ b/NEXTCLOUD.cmake @@ -3,10 +3,10 @@ set( APPLICATION_SHORTNAME "Nextcloud" ) set( APPLICATION_EXECUTABLE "nextcloud" ) set( APPLICATION_DOMAIN "nextcloud.com" ) set( APPLICATION_VENDOR "Nextcloud GmbH" ) -set( APPLICATION_UPDATE_URL "https://updates.nextcloud.org/client/" CACHE string "URL for updater" ) -set( APPLICATION_HELP_URL "" CACHE string "URL for the help menu" ) +set( APPLICATION_UPDATE_URL "https://updates.nextcloud.org/client/" CACHE STRING "URL for updater" ) +set( APPLICATION_HELP_URL "" CACHE STRING "URL for the help menu" ) set( APPLICATION_ICON_NAME "Nextcloud" ) -set( APPLICATION_SERVER_URL "" CACHE string "URL for the server to use. If entered the server can only connect to this instance" ) +set( APPLICATION_SERVER_URL "" CACHE STRING "URL for the server to use. If entered the server can only connect to this instance" ) set( LINUX_PACKAGE_SHORTNAME "nextcloud" ) @@ -20,14 +20,14 @@ set( MAC_INSTALLER_BACKGROUND_FILE "${CMAKE_SOURCE_DIR}/admin/osx/installer-back # set( APPLICATION_LICENSE "${OEM_THEME_DIR}/license.txt ) option( WITH_CRASHREPORTER "Build crashreporter" OFF ) -#set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE string "URL for crash reporter" ) +#set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE STRING "URL for crash reporter" ) #set( CRASHREPORTER_ICON ":/owncloud-icon.png" ) option( WITH_PROVIDERS "Build with providers list" ON ) ## Theming options -set( APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR "#0082c9" CACHE string "Hex color of the wizard header background") -set( APPLICATION_WIZARD_HEADER_TITLE_COLOR "#ffffff" CACHE string "Hex color of the text in the wizard header") +set( APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR "#0082c9" CACHE STRING "Hex color of the wizard header background") +set( APPLICATION_WIZARD_HEADER_TITLE_COLOR "#ffffff" CACHE STRING "Hex color of the text in the wizard header") option( APPLICATION_WIZARD_USE_CUSTOM_LOGO "Use the logo from ':/client/theme/colored/wizard_logo.png' else the default application icon is used" ON ) diff --git a/src/csync/csync_exclude.cpp b/src/csync/csync_exclude.cpp index e3146a099b..9a4f196ed9 100644 --- a/src/csync/csync_exclude.cpp +++ b/src/csync/csync_exclude.cpp @@ -236,13 +236,29 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const char *path, bool excludeC return match; } +static QByteArray leftIncludeLast(const QByteArray & arr, char c) +{ + // left up to and including `c` + return arr.left(arr.lastIndexOf(c, arr.size() - 2) + 1); +} using namespace OCC; -ExcludedFiles::ExcludedFiles() +ExcludedFiles::ExcludedFiles(QString localPath) + : _localPath(std::move(localPath)) { + Q_ASSERT(_localPath.endsWith("/")); // Windows used to use PathMatchSpec which allows *foo to match abc/deffoo. _wildcardsMatchSlash = Utility::isWindows(); + + // We're in a detached exclude probably coming from a partial sync or test + if (_localPath.isEmpty()) + return; + + // Load exclude file from base dir + QFileInfo fi(_localPath + ".sync-exclude.lst"); + if (fi.isReadable()) + addInTreeExcludeFilePath(fi.absoluteFilePath()); } ExcludedFiles::~ExcludedFiles() @@ -251,7 +267,13 @@ ExcludedFiles::~ExcludedFiles() void ExcludedFiles::addExcludeFilePath(const QString &path) { - _excludeFiles.insert(path); + _excludeFiles[_localPath.toUtf8()].append(path); +} + +void ExcludedFiles::addInTreeExcludeFilePath(const QString &path) +{ + BasePathByteArray basePath = leftIncludeLast(path.toUtf8(), '/'); + _excludeFiles[basePath].append(path); } void ExcludedFiles::setExcludeConflictFiles(bool onoff) @@ -261,9 +283,18 @@ void ExcludedFiles::setExcludeConflictFiles(bool onoff) void ExcludedFiles::addManualExclude(const QByteArray &expr) { - _manualExcludes.append(expr); - _allExcludes.append(expr); - prepare(); + addManualExclude(expr, _localPath.toUtf8()); +} + +void ExcludedFiles::addManualExclude(const QByteArray &expr, const QByteArray &basePath) +{ + Q_ASSERT(basePath.startsWith('/')); + Q_ASSERT(basePath.endsWith('/')); + + auto key = basePath; + _manualExcludes[key].append(expr); + _allExcludes[key].append(expr); + prepare(key); } void ExcludedFiles::clearManualExcludes() @@ -278,26 +309,47 @@ void ExcludedFiles::setWildcardsMatchSlash(bool onoff) prepare(); } +bool ExcludedFiles::loadExcludeFile(const QByteArray & basePath, const QString & file) +{ + QFile f(file); + if (!f.open(QIODevice::ReadOnly)) + return false; + + while (!f.atEnd()) { + QByteArray line = f.readLine().trimmed(); + if (line.isEmpty() || line.startsWith('#')) + continue; + csync_exclude_expand_escapes(line); + _allExcludes[basePath].append(line); + } + prepare(basePath); + return true; +} + bool ExcludedFiles::reloadExcludeFiles() { _allExcludes.clear(); + // clear all regex + _bnameTraversalRegexFile.clear(); + _bnameTraversalRegexDir.clear(); + _fullTraversalRegexFile.clear(); + _fullTraversalRegexDir.clear(); + _fullRegexFile.clear(); + _fullRegexDir.clear(); + bool success = true; - foreach (const QString &file, _excludeFiles) { - QFile f(file); - if (!f.open(QIODevice::ReadOnly)) { - success = false; - continue; - } - while (!f.atEnd()) { - QByteArray line = f.readLine().trimmed(); - if (line.isEmpty() || line.startsWith('#')) - continue; - csync_exclude_expand_escapes(line); - _allExcludes.append(line); + for (auto basePath : _excludeFiles.keys()) { + for (auto file : _excludeFiles.value(basePath)) { + success = loadExcludeFile(basePath, file); } } - _allExcludes.append(_manualExcludes); - prepare(); + + auto endManual = _manualExcludes.cend(); + for (auto kv = _manualExcludes.cbegin(); kv != endManual; ++kv) { + _allExcludes[kv.key()].append(kv.value()); + prepare(kv.key()); + } + return success; } @@ -311,13 +363,15 @@ bool ExcludedFiles::isExcluded( return true; } + //TODO this seems a waste, hidden files are ignored before hitting this function it seems if (excludeHidden) { QString path = filePath; // Check all path subcomponents, but to *not* check the base path: // We do want to be able to sync with a hidden folder as the target. while (path.size() > basePath.size()) { QFileInfo fi(path); - if (fi.isHidden() || fi.fileName().startsWith(QLatin1Char('.'))) { + if (fi.fileName() != ".sync-exclude.lst" + && (fi.isHidden() || fi.fileName().startsWith(QLatin1Char('.')))) { return true; } @@ -340,7 +394,7 @@ bool ExcludedFiles::isExcluded( return fullPatternMatch(relativePath.toUtf8(), type) != CSYNC_NOT_EXCLUDED; } -CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemType filetype) const +CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemType filetype) { auto match = _csync_excluded_common(path, _excludeConflictFiles); if (match != CSYNC_NOT_EXCLUDED) @@ -348,6 +402,15 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy if (_allExcludes.isEmpty()) return CSYNC_NOT_EXCLUDED; + // Directories are guaranteed to be visited before their files + if (filetype == ItemTypeDirectory) { + QFileInfo fi = QFileInfo(_localPath + path + "/.sync-exclude.lst"); + if (fi.isReadable()) { + addInTreeExcludeFilePath(fi.absoluteFilePath()); + loadExcludeFile(fi.absolutePath().toUtf8(), fi.absoluteFilePath()); + } + } + // Check the bname part of the path to see whether the full // regex should be run. @@ -359,35 +422,53 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy } QString bnameStr = QString::fromUtf8(bname); - QRegularExpressionMatch m; - if (filetype == ItemTypeDirectory) { - m = _bnameTraversalRegexDir.match(bnameStr); - } else { - m = _bnameTraversalRegexFile.match(bnameStr); - } - if (!m.hasMatch()) - return CSYNC_NOT_EXCLUDED; - if (m.capturedStart(QStringLiteral("exclude")) != -1) { - return CSYNC_FILE_EXCLUDE_LIST; - } else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) { - return CSYNC_FILE_EXCLUDE_AND_REMOVE; - } + QByteArray basePath(_localPath.toUtf8() + path); + while (basePath.size() > _localPath.size()) { + basePath = leftIncludeLast(basePath, '/'); + QRegularExpressionMatch m; + if (filetype == ItemTypeDirectory + && _bnameTraversalRegexDir.contains(basePath)) { + m = _bnameTraversalRegexDir[basePath].match(bnameStr); + } else if (filetype == ItemTypeFile + && _bnameTraversalRegexFile.contains(basePath)) { + m = _bnameTraversalRegexFile[basePath].match(bnameStr); + } else { + continue; + } - // third capture: full path matching is triggered - QString pathStr = QString::fromUtf8(path); - - if (filetype == ItemTypeDirectory) { - m = _fullTraversalRegexDir.match(pathStr); - } else { - m = _fullTraversalRegexFile.match(pathStr); - } - if (m.hasMatch()) { + if (!m.hasMatch()) + return CSYNC_NOT_EXCLUDED; if (m.capturedStart(QStringLiteral("exclude")) != -1) { return CSYNC_FILE_EXCLUDE_LIST; } else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) { return CSYNC_FILE_EXCLUDE_AND_REMOVE; } } + + // third capture: full path matching is triggered + QString pathStr = QString::fromUtf8(path); + basePath = _localPath.toUtf8() + path; + while (basePath.size() > _localPath.size()) { + basePath = leftIncludeLast(basePath, '/'); + QRegularExpressionMatch m; + if (filetype == ItemTypeDirectory + && _fullTraversalRegexDir.contains(basePath)) { + m = _fullTraversalRegexDir[basePath].match(pathStr); + } else if (filetype == ItemTypeFile + && _fullTraversalRegexFile.contains(basePath)) { + m = _fullTraversalRegexFile[basePath].match(pathStr); + } else { + continue; + } + + if (m.hasMatch()) { + if (m.capturedStart(QStringLiteral("exclude")) != -1) { + return CSYNC_FILE_EXCLUDE_LIST; + } else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) { + return CSYNC_FILE_EXCLUDE_AND_REMOVE; + } + } + } return CSYNC_NOT_EXCLUDED; } @@ -400,23 +481,38 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::fullPatternMatch(const char *path, ItemType fi return CSYNC_NOT_EXCLUDED; QString p = QString::fromUtf8(path); - QRegularExpressionMatch m; - if (filetype == ItemTypeDirectory) { - m = _fullRegexDir.match(p); - } else { - m = _fullRegexFile.match(p); - } - if (m.hasMatch()) { - if (m.capturedStart(QStringLiteral("exclude")) != -1) { - return CSYNC_FILE_EXCLUDE_LIST; - } else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) { - return CSYNC_FILE_EXCLUDE_AND_REMOVE; + // `path` seems to always be relative to `_localPath`, the tests however have not been + // written that way... this makes the tests happy for now. TODO Fix the tests at some point + if (path[0] == '/') + ++path; + + QByteArray basePath(_localPath.toUtf8() + path); + while (basePath.size() > _localPath.size()) { + basePath = leftIncludeLast(basePath, '/'); + QRegularExpressionMatch m; + if (filetype == ItemTypeDirectory + && _fullRegexDir.contains(basePath)) { + m = _fullRegexDir[basePath].match(p); + } else if (filetype == ItemTypeFile + && _fullRegexFile.contains(basePath)) { + m = _fullRegexFile[basePath].match(p); + } else { + continue; + } + + if (m.hasMatch()) { + if (m.capturedStart(QStringLiteral("exclude")) != -1) { + return CSYNC_FILE_EXCLUDE_LIST; + } else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) { + return CSYNC_FILE_EXCLUDE_AND_REMOVE; + } } } + return CSYNC_NOT_EXCLUDED; } -auto ExcludedFiles::csyncTraversalMatchFun() const +auto ExcludedFiles::csyncTraversalMatchFun() -> std::function { return [this](const char *path, ItemType filetype) { return this->traversalPatternMatch(path, filetype); }; @@ -555,6 +651,22 @@ static QString extractBnameTrigger(const QString &exclude, bool wildcardsMatchSl void ExcludedFiles::prepare() { + // clear all regex + _bnameTraversalRegexFile.clear(); + _bnameTraversalRegexDir.clear(); + _fullTraversalRegexFile.clear(); + _fullTraversalRegexDir.clear(); + _fullRegexFile.clear(); + _fullRegexDir.clear(); + + for (auto const & basePath : _allExcludes.keys()) + prepare(basePath); +} + +void ExcludedFiles::prepare(const BasePathByteArray & basePath) +{ + Q_ASSERT(_allExcludes.contains(basePath)); + // Build regular expressions for the different cases. // // To compose the _bnameTraversalRegex, _fullTraversalRegex and _fullRegex @@ -596,7 +708,7 @@ void ExcludedFiles::prepare() pattern.append(appendMe); }; - for (auto exclude : _allExcludes) { + for (auto exclude : _allExcludes.value(basePath)) { if (exclude[0] == '\n') continue; // empty line if (exclude[0] == '\r') @@ -618,6 +730,15 @@ void ExcludedFiles::prepare() auto &fullFileDir = removeExcluded ? fullFileDirRemove : fullFileDirKeep; auto &fullDir = removeExcluded ? fullDirRemove : fullDirKeep; + if (fullPath) { + // The full pattern is matched against a path relative to _localPath, however exclude is + // relative to basePath at this point. + // We know for sure that both _localPath and basePath are absolute and that basePath is + // contained in _localPath. So we can simply remove it from the begining. + auto relPath = basePath.mid(_localPath.size()); + // Make exclude relative to _localPath + exclude.prepend(relPath); + } auto regexExclude = convertToRegexpSyntax(QString::fromUtf8(exclude), _wildcardsMatchSlash); if (!fullPath) { regexAppend(bnameFileDir, bnameDir, regexExclude, matchDirOnly); @@ -654,11 +775,11 @@ void ExcludedFiles::prepare() // (exclude)|(excluderemove)|(bname triggers). // If the third group matches, the fullActivatedRegex needs to be applied // to the full path. - _bnameTraversalRegexFile.setPattern( + _bnameTraversalRegexFile[basePath].setPattern( "^(?P" + bnameFileDirKeep + ")$|" + "^(?P" + bnameFileDirRemove + ")$|" + "^(?P" + bnameTriggerFileDir + ")$"); - _bnameTraversalRegexDir.setPattern( + _bnameTraversalRegexDir[basePath].setPattern( "^(?P" + bnameFileDirKeep + "|" + bnameDirKeep + ")$|" + "^(?P" + bnameFileDirRemove + "|" + bnameDirRemove + ")$|" + "^(?P" + bnameTriggerFileDir + "|" + bnameTriggerDir + ")$"); @@ -667,13 +788,13 @@ void ExcludedFiles::prepare() // the bname regex matches. Its basic form is (exclude)|(excluderemove)". // This pattern can be much simpler than fullRegex since we can assume a traversal // situation and doesn't need to look for bname patterns in parent paths. - _fullTraversalRegexFile.setPattern( + _fullTraversalRegexFile[basePath].setPattern( QLatin1String("") // Full patterns are anchored to the beginning + "^(?P" + fullFileDirKeep + ")(?:$|/)" + "|" + "^(?P" + fullFileDirRemove + ")(?:$|/)"); - _fullTraversalRegexDir.setPattern( + _fullTraversalRegexDir[basePath].setPattern( QLatin1String("") + "^(?P" + fullFileDirKeep + "|" + fullDirKeep + ")(?:$|/)" + "|" @@ -681,7 +802,7 @@ void ExcludedFiles::prepare() // The full regex is applied to the full path and incorporates both bname and // full-path patterns. It has the form "(exclude)|(excluderemove)". - _fullRegexFile.setPattern( + _fullRegexFile[basePath].setPattern( QLatin1String("(?P") // Full patterns are anchored to the beginning + "^(?:" + fullFileDirKeep + ")(?:$|/)" + "|" @@ -697,7 +818,7 @@ void ExcludedFiles::prepare() + "(?:^|/)(?:" + bnameFileDirRemove + ")(?:$|/)" + "|" + "(?:^|/)(?:" + bnameDirRemove + ")/" + ")"); - _fullRegexDir.setPattern( + _fullRegexDir[basePath].setPattern( QLatin1String("(?P") + "^(?:" + fullFileDirKeep + "|" + fullDirKeep + ")(?:$|/)" + "|" + "(?:^|/)(?:" + bnameFileDirKeep + "|" + bnameDirKeep + ")(?:$|/)" @@ -711,16 +832,16 @@ void ExcludedFiles::prepare() QRegularExpression::PatternOptions patternOptions = QRegularExpression::NoPatternOption; if (OCC::Utility::fsCasePreserving()) patternOptions |= QRegularExpression::CaseInsensitiveOption; - _bnameTraversalRegexFile.setPatternOptions(patternOptions); - _bnameTraversalRegexFile.optimize(); - _bnameTraversalRegexDir.setPatternOptions(patternOptions); - _bnameTraversalRegexDir.optimize(); - _fullTraversalRegexFile.setPatternOptions(patternOptions); - _fullTraversalRegexFile.optimize(); - _fullTraversalRegexDir.setPatternOptions(patternOptions); - _fullTraversalRegexDir.optimize(); - _fullRegexFile.setPatternOptions(patternOptions); - _fullRegexFile.optimize(); - _fullRegexDir.setPatternOptions(patternOptions); - _fullRegexDir.optimize(); + _bnameTraversalRegexFile[basePath].setPatternOptions(patternOptions); + _bnameTraversalRegexFile[basePath].optimize(); + _bnameTraversalRegexDir[basePath].setPatternOptions(patternOptions); + _bnameTraversalRegexDir[basePath].optimize(); + _fullTraversalRegexFile[basePath].setPatternOptions(patternOptions); + _fullTraversalRegexFile[basePath].optimize(); + _fullTraversalRegexDir[basePath].setPatternOptions(patternOptions); + _fullTraversalRegexDir[basePath].optimize(); + _fullRegexFile[basePath].setPatternOptions(patternOptions); + _fullRegexFile[basePath].optimize(); + _fullRegexDir[basePath].setPatternOptions(patternOptions); + _fullRegexDir[basePath].optimize(); } diff --git a/src/csync/csync_exclude.h b/src/csync/csync_exclude.h index 249ec7bff6..0b11477917 100644 --- a/src/csync/csync_exclude.h +++ b/src/csync/csync_exclude.h @@ -66,7 +66,7 @@ class OCSYNC_EXPORT ExcludedFiles : public QObject { Q_OBJECT public: - ExcludedFiles(); + ExcludedFiles(QString localPath = "/"); ~ExcludedFiles(); /** @@ -75,6 +75,7 @@ public: * Does not load the file. Use reloadExcludeFiles() afterwards. */ void addExcludeFilePath(const QString &path); + void addInTreeExcludeFilePath(const QString &path); /** * Whether conflict files shall be excluded. @@ -95,12 +96,13 @@ public: bool excludeHidden) const; /** - * Adds an exclude pattern. + * Adds an exclude pattern anchored to base path * * Primarily used in tests. Patterns added this way are preserved when * reloadExcludeFiles() is called. */ void addManualExclude(const QByteArray &expr); + void addManualExclude(const QByteArray &expr, const QByteArray &basePath); /** * Removes all manually added exclude patterns. @@ -121,7 +123,7 @@ public: * Careful: The function will only be valid for as long as this * ExcludedFiles instance stays alive. */ - auto csyncTraversalMatchFun() const + auto csyncTraversalMatchFun() -> std::function; public slots: @@ -129,6 +131,10 @@ public slots: * Reloads the exclude patterns from the registered paths. */ bool reloadExcludeFiles(); + /** + * Loads the exclude patterns from file the registered base paths. + */ + bool loadExcludeFile(const QByteArray & basePath, const QString & file); private: /** @@ -156,10 +162,32 @@ private: * Note that this only matches patterns. It does not check whether the file * or directory pointed to is hidden (or whether it even exists). */ - CSYNC_EXCLUDE_TYPE traversalPatternMatch(const char *path, ItemType filetype) const; + CSYNC_EXCLUDE_TYPE traversalPatternMatch(const char *path, ItemType filetype); + + // Our BasePath need to end with '/' + class BasePathByteArray : public QByteArray + { + public: + BasePathByteArray(QByteArray && other) + : QByteArray(std::move(other)) + { + Q_ASSERT(this->endsWith('/')); + } + + BasePathByteArray(const QByteArray & other) + : QByteArray(other) + { + Q_ASSERT(this->endsWith('/')); + } + + BasePathByteArray(const char * data, int size = -1) + : BasePathByteArray(QByteArray(data, size)) + { + } + }; /** - * Generate optimized regular expressions for the exclude patterns. + * Generate optimized regular expressions for the exclude patterns anchored to basePath. * * The optimization works in two steps: First, all supported patterns are put * into _fullRegexFile/_fullRegexDir. These regexes can be applied to the full @@ -187,24 +215,28 @@ private: * full matcher would exclude. Example: "b" is excluded. traversal("b/c") * returns not-excluded because "c" isn't a bname activation pattern. */ + void prepare(const BasePathByteArray & basePath); + void prepare(); + + QString _localPath; /// Files to load excludes from - QSet _excludeFiles; + QMap> _excludeFiles; /// Exclude patterns added with addManualExclude() - QList _manualExcludes; + QMap> _manualExcludes; /// List of all active exclude patterns - QList _allExcludes; + QMap> _allExcludes; /// see prepare() - QRegularExpression _bnameTraversalRegexFile; - QRegularExpression _bnameTraversalRegexDir; - QRegularExpression _fullTraversalRegexFile; - QRegularExpression _fullTraversalRegexDir; - QRegularExpression _fullRegexFile; - QRegularExpression _fullRegexDir; + QMap _bnameTraversalRegexFile; + QMap _bnameTraversalRegexDir; + QMap _fullTraversalRegexFile; + QMap _fullTraversalRegexDir; + QMap _fullRegexFile; + QMap _fullRegexDir; bool _excludeConflictFiles = true; diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp index fd6c6ec958..ecea21cae0 100644 --- a/src/csync/csync_update.cpp +++ b/src/csync/csync_update.cpp @@ -124,7 +124,9 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr f * because it's a hidden file that should not be synced. * This code should probably be in csync_exclude, but it does not have the fs parameter. * Keep it here for now */ - if (ctx->ignore_hidden_files && (fs->is_hidden)) { + if (ctx->ignore_hidden_files + && fs->is_hidden + && !fs->path.endsWith(".sync-exclude.lst")) { qCInfo(lcUpdate, "file excluded because it is a hidden file: %s", fs->path.constData()); excluded = CSYNC_FILE_EXCLUDE_HIDDEN; } diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 4e9d09ea71..d94b19813e 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -22,6 +22,7 @@ set(client_UI_SRCS generalsettings.ui legalnotice.ui ignorelisteditor.ui + ignorelisttablewidget.ui networksettings.ui activitywidget.ui synclogdialog.ui @@ -61,6 +62,7 @@ set(client_SRCS generalsettings.cpp legalnotice.cpp ignorelisteditor.cpp + ignorelisttablewidget.cpp lockwatcher.cpp logbrowser.cpp navigationpanehelper.cpp diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 5e96ac2261..2fc324573c 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -35,10 +35,12 @@ #include "filesystem.h" #include "clientsideencryptionjobs.h" #include "syncresult.h" +#include "ignorelisttablewidget.h" #include #include +#include #include #include #include @@ -422,7 +424,7 @@ bool AccountSettings::canEncryptOrDecrypt (const FolderStatusModel::SubFolderInf return true; } -void AccountSettings::slotMarkSubfolderEncrpted(const FolderStatusModel::SubFolderInfo* folderInfo) +void AccountSettings::slotMarkSubfolderEncrypted(const FolderStatusModel::SubFolderInfo* folderInfo) { if (!canEncryptOrDecrypt(folderInfo)) { return; @@ -539,6 +541,51 @@ void AccountSettings::slotLockForDecryptionError(const QByteArray& fileId, int h qDebug() << "Error Locking for decryption"; } +void AccountSettings::slotEditCurrentIgnoredFiles() +{ + Folder *f = FolderMan::instance()->folder(selectedFolderAlias()); + if (f == nullptr) + return; + openIgnoredFilesDialog(f->path()); +} + +void AccountSettings::slotEditCurrentLocalIgnoredFiles() +{ + QModelIndex selected = ui->_folderList->selectionModel()->currentIndex(); + if (!selected.isValid() || _model->classify(selected) != FolderStatusModel::SubFolder) + return; + QString fileName = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString(); + openIgnoredFilesDialog(fileName); +} + +void AccountSettings::openIgnoredFilesDialog(const QString & absFolderPath) +{ + Q_ASSERT(absFolderPath.startsWith('/')); + Q_ASSERT(absFolderPath.endsWith('/')); + + const QString ignoreFile = absFolderPath + ".sync-exclude.lst"; + auto layout = new QVBoxLayout(); + auto ignoreListWidget = new IgnoreListTableWidget(this); + ignoreListWidget->readIgnoreFile(ignoreFile); + layout->addWidget(ignoreListWidget); + + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + layout->addWidget(buttonBox); + + auto dialog = new QDialog(); + dialog->setLayout(layout); + + connect(buttonBox, &QDialogButtonBox::clicked, [=](QAbstractButton * button) { + if (buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) + ignoreListWidget->slotWriteIgnoreFile(ignoreFile); + dialog->close(); + }); + connect(buttonBox, &QDialogButtonBox::rejected, + dialog, &QDialog::close); + + dialog->open(); +} + void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index, const QPoint& pos) { Q_UNUSED(pos); @@ -561,12 +608,16 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index if (!isEncrypted) { ac = menu.addAction(tr("Encrypt")); - connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderEncrpted(info); }); + connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderEncrypted(info); }); } else { // Ingore decrypting for now since it only works with an empty folder // connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info); }); } } + + ac = menu.addAction(tr("Edit Ignored Files")); + connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentLocalIgnoredFiles); + menu.exec(QCursor::pos()); } @@ -600,6 +651,9 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos) QAction *ac = menu->addAction(tr("Open folder")); connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenCurrentFolder); + ac = menu->addAction(tr("Edit Ignored Files")); + connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles); + if (!ui->_folderList->isExpanded(index)) { ac = menu->addAction(tr("Choose what to sync")); ac->setEnabled(folderConnected); diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index eb6a78b17c..ce1885d2df 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -80,6 +80,8 @@ protected slots: void slotRemoveCurrentFolder(); void slotOpenCurrentFolder(); // sync folder void slotOpenCurrentLocalSubFolder(); // selected subfolder in sync folder + void slotEditCurrentIgnoredFiles(); + void slotEditCurrentLocalIgnoredFiles(); void slotFolderWizardAccepted(); void slotFolderWizardRejected(); void slotDeleteAccount(); @@ -87,7 +89,7 @@ protected slots: void slotOpenAccountWizard(); void slotAccountAdded(AccountState *); void refreshSelectiveSyncStatus(); - void slotMarkSubfolderEncrpted(const FolderStatusModel::SubFolderInfo* folderInfo); + void slotMarkSubfolderEncrypted(const FolderStatusModel::SubFolderInfo* folderInfo); void slotMarkSubfolderDecrypted(const FolderStatusModel::SubFolderInfo* folderInfo); void slotSubfolderContextMenuRequested(const QModelIndex& idx, const QPoint& point); void slotCustomContextMenuRequested(const QPoint &); @@ -110,7 +112,7 @@ protected slots: void slotUploadMetadataSuccess(const QByteArray& folderId); void slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode); - // Remove Encryotion Bit. + // Remove Encryption Bit. void slotLockForDecryptionSuccess(const QByteArray& folderId, const QByteArray& token); void slotLockForDecryptionError(const QByteArray& folderId, int httpReturnCode); void slotDeleteMetadataSuccess(const QByteArray& folderId); @@ -125,6 +127,7 @@ private: QStringList errors = QStringList()); bool event(QEvent *) override; void createAccountToolbox(); + void openIgnoredFilesDialog(const QString & absFolderPath); /// Returns the alias of the selected folder, empty string if none QString selectedFolderAlias() const; diff --git a/src/gui/generalsettings.cpp b/src/gui/generalsettings.cpp index b8c10d5921..dd42358349 100644 --- a/src/gui/generalsettings.cpp +++ b/src/gui/generalsettings.cpp @@ -184,6 +184,7 @@ void GeneralSettings::slotShowInExplorerNavigationPane(bool checked) void GeneralSettings::slotIgnoreFilesEditor() { if (_ignoreEditor.isNull()) { + ConfigFile cfgFile; _ignoreEditor = new IgnoreListEditor(this); _ignoreEditor->setAttribute(Qt::WA_DeleteOnClose, true); _ignoreEditor->open(); diff --git a/src/gui/ignorelisteditor.cpp b/src/gui/ignorelisteditor.cpp index 9b44c25a08..6e5a3d784d 100644 --- a/src/gui/ignorelisteditor.cpp +++ b/src/gui/ignorelisteditor.cpp @@ -14,8 +14,9 @@ #include "configfile.h" -#include "ignorelisteditor.h" #include "folderman.h" +#include "generalsettings.h" +#include "ignorelisteditor.h" #include "ui_ignorelisteditor.h" #include @@ -27,10 +28,6 @@ namespace OCC { -static int patternCol = 0; -static int deletableCol = 1; -static int readOnlyRows = 3; - IgnoreListEditor::IgnoreListEditor(QWidget *parent) : QDialog(parent) , ui(new Ui::IgnoreListEditor) @@ -39,28 +36,28 @@ IgnoreListEditor::IgnoreListEditor(QWidget *parent) ui->setupUi(this); ConfigFile cfgFile; - ui->descriptionLabel->setText(tr("Files or folders matching a pattern will not be synchronized.\n\n" - "Items where deletion is allowed will be deleted if they prevent a " - "directory from being removed. " - "This is useful for meta data.")); + //FIXME This is not true. The entries are hardcoded below in setupTableReadOnlyItems readOnlyTooltip = tr("This entry is provided by the system at '%1' " "and cannot be modified in this view.") .arg(QDir::toNativeSeparators(cfgFile.excludeFile(ConfigFile::SystemScope))); setupTableReadOnlyItems(); - readIgnoreFile(cfgFile.excludeFile(ConfigFile::UserScope), false); + const auto userConfig = cfgFile.excludeFile(ConfigFile::Scope::UserScope); + ui->ignoreTableWidget->readIgnoreFile(userConfig); - connect(this, &QDialog::accepted, this, &IgnoreListEditor::slotUpdateLocalIgnoreList); - ui->removePushButton->setEnabled(false); - connect(ui->tableWidget, &QTableWidget::itemSelectionChanged, this, &IgnoreListEditor::slotItemSelectionChanged); - connect(ui->removePushButton, &QAbstractButton::clicked, this, &IgnoreListEditor::slotRemoveCurrentItem); - connect(ui->addPushButton, &QAbstractButton::clicked, this, &IgnoreListEditor::slotAddPattern); - connect(ui->removeAllPushButton, &QAbstractButton::clicked, this, &IgnoreListEditor::slotRemoveAllItems); - connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &IgnoreListEditor::slotRestoreDefaults); + connect(this, &QDialog::accepted, [=]() { + ui->ignoreTableWidget->slotWriteIgnoreFile(userConfig); + /* handle the hidden file checkbox */ - ui->tableWidget->resizeColumnsToContents(); - ui->tableWidget->horizontalHeader()->setSectionResizeMode(patternCol, QHeaderView::Stretch); - ui->tableWidget->verticalHeader()->setVisible(false); + /* the ignoreHiddenFiles flag is a folder specific setting, but for now, it is + * handled globally. Save it to every folder that is defined. + * TODO this can now be fixed, simply attach this IgnoreListEditor to top-level account + * settings + */ + FolderMan::instance()->setIgnoreHiddenFiles(ignoreHiddenFiles()); + }); + connect(ui->buttonBox, &QDialogButtonBox::clicked, + this, &IgnoreListEditor::slotRestoreDefaults); ui->syncHiddenFilesCheckBox->setChecked(!FolderMan::instance()->ignoreHiddenFiles()); } @@ -70,12 +67,11 @@ IgnoreListEditor::~IgnoreListEditor() delete ui; } -void IgnoreListEditor::setupTableReadOnlyItems(){ - ui->tableWidget->setRowCount(0); - addPattern(".csync_journal.db*", /*deletable=*/false, /*readonly=*/true); - addPattern("._sync_*.db*", /*deletable=*/false, /*readonly=*/true); - addPattern(".sync_*.db*", /*deletable=*/false, /*readonly=*/true); - ui->removeAllPushButton->setEnabled(false); +void IgnoreListEditor::setupTableReadOnlyItems() +{ + ui->ignoreTableWidget->addPattern(".csync_journal.db*", /*deletable=*/false, /*readonly=*/true); + ui->ignoreTableWidget->addPattern("._sync_*.db*", /*deletable=*/false, /*readonly=*/true); + ui->ignoreTableWidget->addPattern(".sync_*.db*", /*deletable=*/false, /*readonly=*/true); } bool IgnoreListEditor::ignoreHiddenFiles() @@ -83,140 +79,16 @@ bool IgnoreListEditor::ignoreHiddenFiles() return !ui->syncHiddenFilesCheckBox->isChecked(); } -void IgnoreListEditor::slotItemSelectionChanged() +void IgnoreListEditor::slotRestoreDefaults(QAbstractButton *button) { - QTableWidgetItem *item = ui->tableWidget->currentItem(); - if (!item) { - ui->removePushButton->setEnabled(false); + if(ui->buttonBox->buttonRole(button) != QDialogButtonBox::ResetRole) return; - } - bool enable = item->flags() & Qt::ItemIsEnabled; - ui->removePushButton->setEnabled(enable); -} + ui->ignoreTableWidget->slotRemoveAllItems(); -void IgnoreListEditor::slotRemoveCurrentItem() -{ - ui->tableWidget->removeRow(ui->tableWidget->currentRow()); - if(ui->tableWidget->rowCount() == readOnlyRows) - ui->removeAllPushButton->setEnabled(false); -} - -void IgnoreListEditor::slotRemoveAllItems() -{ - ui->tableWidget->clearContents(); - setupTableReadOnlyItems(); -} - -void IgnoreListEditor::slotUpdateLocalIgnoreList() -{ ConfigFile cfgFile; - QString ignoreFile = cfgFile.excludeFile(ConfigFile::UserScope); - QFile ignores(ignoreFile); - if (ignores.open(QIODevice::WriteOnly)) { - // rewrites the whole file since now the user can also remove system patterns - QFile::resize(ignoreFile, 0); - for (int row = 0; row < ui->tableWidget->rowCount(); ++row) { - QTableWidgetItem *patternItem = ui->tableWidget->item(row, patternCol); - QTableWidgetItem *deletableItem = ui->tableWidget->item(row, deletableCol); - if (patternItem->flags() & Qt::ItemIsEnabled) { - QByteArray prepend; - if (deletableItem->checkState() == Qt::Checked) { - prepend = "]"; - } else if (patternItem->text().startsWith('#')) { - prepend = "\\"; - } - ignores.write(prepend + patternItem->text().toUtf8() + '\n'); - } - } - } else { - QMessageBox::warning(this, tr("Could not open file"), - tr("Cannot write changes to '%1'.").arg(ignoreFile)); - } - ignores.close(); //close the file before reloading stuff. - - FolderMan *folderMan = FolderMan::instance(); - - /* handle the hidden file checkbox */ - - /* the ignoreHiddenFiles flag is a folder specific setting, but for now, it is - * handled globally. Save it to every folder that is defined. - */ - folderMan->setIgnoreHiddenFiles(ignoreHiddenFiles()); - - // We need to force a remote discovery after a change of the ignore list. - // Otherwise we would not download the files/directories that are no longer - // ignored (because the remote etag did not change) (issue #3172) - foreach (Folder *folder, folderMan->map()) { - folder->journalDb()->forceRemoteDiscoveryNextSync(); - folderMan->scheduleFolder(folder); - } -} - -void IgnoreListEditor::slotAddPattern() -{ - bool okClicked; - QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"), - tr("Add a new ignore pattern:"), - QLineEdit::Normal, QString(), &okClicked); - - if (!okClicked || pattern.isEmpty()) - return; - - addPattern(pattern, false, false); - ui->tableWidget->scrollToBottom(); -} - -void IgnoreListEditor::slotRestoreDefaults(QAbstractButton *button){ - if(ui->buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole){ - ConfigFile cfgFile; - setupTableReadOnlyItems(); - readIgnoreFile(cfgFile.excludeFile(ConfigFile::SystemScope), false); - } -} - -void IgnoreListEditor::readIgnoreFile(const QString &file, bool readOnly) -{ - QFile ignores(file); - if (ignores.open(QIODevice::ReadOnly)) { - while (!ignores.atEnd()) { - QString line = QString::fromUtf8(ignores.readLine()); - line.chop(1); - if (!line.isEmpty() && !line.startsWith("#")) { - bool deletable = false; - if (line.startsWith(']')) { - deletable = true; - line = line.mid(1); - } - addPattern(line, deletable, readOnly); - } - } - } -} - -int IgnoreListEditor::addPattern(const QString &pattern, bool deletable, bool readOnly) -{ - int newRow = ui->tableWidget->rowCount(); - ui->tableWidget->setRowCount(newRow + 1); - - QTableWidgetItem *patternItem = new QTableWidgetItem; - patternItem->setText(pattern); - ui->tableWidget->setItem(newRow, patternCol, patternItem); - - QTableWidgetItem *deletableItem = new QTableWidgetItem; - deletableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); - deletableItem->setCheckState(deletable ? Qt::Checked : Qt::Unchecked); - ui->tableWidget->setItem(newRow, deletableCol, deletableItem); - - if (readOnly) { - patternItem->setFlags(patternItem->flags() ^ Qt::ItemIsEnabled); - patternItem->setToolTip(readOnlyTooltip); - deletableItem->setFlags(deletableItem->flags() ^ Qt::ItemIsEnabled); - } - - ui->removeAllPushButton->setEnabled(true); - - return newRow; + setupTableReadOnlyItems(); + ui->ignoreTableWidget->readIgnoreFile(cfgFile.excludeFile(ConfigFile::SystemScope), false); } } // namespace OCC diff --git a/src/gui/ignorelisteditor.h b/src/gui/ignorelisteditor.h index 74137a7363..39c38d74d4 100644 --- a/src/gui/ignorelisteditor.h +++ b/src/gui/ignorelisteditor.h @@ -35,23 +35,16 @@ class IgnoreListEditor : public QDialog Q_OBJECT public: - explicit IgnoreListEditor(QWidget *parent = nullptr); + IgnoreListEditor(QWidget *parent = nullptr); ~IgnoreListEditor(); bool ignoreHiddenFiles(); private slots: - void slotItemSelectionChanged(); - void slotRemoveCurrentItem(); - void slotUpdateLocalIgnoreList(); - void slotAddPattern(); void slotRestoreDefaults(QAbstractButton *button); - void slotRemoveAllItems(); private: - void readIgnoreFile(const QString &file, bool readOnly); void setupTableReadOnlyItems(); - int addPattern(const QString &pattern, bool deletable, bool readOnly); QString readOnlyTooltip; Ui::IgnoreListEditor *ui; }; diff --git a/src/gui/ignorelisteditor.ui b/src/gui/ignorelisteditor.ui index 8e544a9113..891fbc6e9b 100644 --- a/src/gui/ignorelisteditor.ui +++ b/src/gui/ignorelisteditor.ui @@ -36,96 +36,8 @@ Files Ignored by Patterns - - - - true - - - - 0 - 0 - - - - - - - Qt::PlainText - - - true - - - - - - - true - - - Qt::Vertical - - - - 20 - 213 - - - - - - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - 2 - - - - Pattern - - - - - Allow Deletion - - - - - - - - true - - - Remove - - - - - - - true - - - Add - - - - - - - Remove all - - + + @@ -139,6 +51,14 @@ + + + IgnoreListTableWidget + QWidget +
ignorelisttablewidget.h
+ 1 +
+
diff --git a/src/gui/ignorelisttablewidget.cpp b/src/gui/ignorelisttablewidget.cpp new file mode 100644 index 0000000000..67c8ab4f2f --- /dev/null +++ b/src/gui/ignorelisttablewidget.cpp @@ -0,0 +1,167 @@ +#include "ignorelisttablewidget.h" +#include "ui_ignorelisttablewidget.h" + +#include "folderman.h" + +#include +#include +#include +#include + +namespace OCC { + +static constexpr int patternCol = 0; +static constexpr int deletableCol = 1; +static constexpr int readOnlyRows = 3; + +IgnoreListTableWidget::IgnoreListTableWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::IgnoreListTableWidget) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + ui->setupUi(this); + + ui->descriptionLabel->setText(tr("Files or folders matching a pattern will not be synchronized.\n\n" + "Items where deletion is allowed will be deleted if they prevent a " + "directory from being removed. " + "This is useful for meta data.")); + + ui->removePushButton->setEnabled(false); + connect(ui->tableWidget, &QTableWidget::itemSelectionChanged, + this, &IgnoreListTableWidget::slotItemSelectionChanged); + connect(ui->removePushButton, &QAbstractButton::clicked, + this, &IgnoreListTableWidget::slotRemoveCurrentItem); + connect(ui->addPushButton, &QAbstractButton::clicked, + this, &IgnoreListTableWidget::slotAddPattern); + connect(ui->removeAllPushButton, &QAbstractButton::clicked, + this, &IgnoreListTableWidget::slotRemoveAllItems); + + ui->tableWidget->resizeColumnsToContents(); + ui->tableWidget->horizontalHeader()->setSectionResizeMode(patternCol, QHeaderView::Stretch); + ui->tableWidget->verticalHeader()->setVisible(false); +} + +IgnoreListTableWidget::~IgnoreListTableWidget() +{ + delete ui; +} + +void IgnoreListTableWidget::slotItemSelectionChanged() +{ + QTableWidgetItem *item = ui->tableWidget->currentItem(); + if (!item) { + ui->removePushButton->setEnabled(false); + return; + } + + bool enable = item->flags() & Qt::ItemIsEnabled; + ui->removePushButton->setEnabled(enable); +} + +void IgnoreListTableWidget::slotRemoveCurrentItem() +{ + ui->tableWidget->removeRow(ui->tableWidget->currentRow()); + if(ui->tableWidget->rowCount() == readOnlyRows) + ui->removeAllPushButton->setEnabled(false); +} + +void IgnoreListTableWidget::slotRemoveAllItems() +{ + ui->tableWidget->setRowCount(0); +} + +void IgnoreListTableWidget::slotWriteIgnoreFile(const QString & file) +{ + QFile ignores(file); + if (ignores.open(QIODevice::WriteOnly)) { + // rewrites the whole file since now the user can also remove system patterns + QFile::resize(file, 0); + for (int row = 0; row < ui->tableWidget->rowCount(); ++row) { + QTableWidgetItem *patternItem = ui->tableWidget->item(row, patternCol); + QTableWidgetItem *deletableItem = ui->tableWidget->item(row, deletableCol); + if (patternItem->flags() & Qt::ItemIsEnabled) { + QByteArray prepend; + if (deletableItem->checkState() == Qt::Checked) { + prepend = "]"; + } else if (patternItem->text().startsWith('#')) { + prepend = "\\"; + } + ignores.write(prepend + patternItem->text().toUtf8() + '\n'); + } + } + } else { + QMessageBox::warning(this, tr("Could not open file"), + tr("Cannot write changes to '%1'.").arg(file)); + } + ignores.close(); //close the file before reloading stuff. + + FolderMan *folderMan = FolderMan::instance(); + + // We need to force a remote discovery after a change of the ignore list. + // Otherwise we would not download the files/directories that are no longer + // ignored (because the remote etag did not change) (issue #3172) + foreach (Folder *folder, folderMan->map()) { + folder->journalDb()->forceRemoteDiscoveryNextSync(); + folderMan->scheduleFolder(folder); + } +} + +void IgnoreListTableWidget::slotAddPattern() +{ + bool okClicked; + QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"), + tr("Add a new ignore pattern:"), + QLineEdit::Normal, QString(), &okClicked); + + if (!okClicked || pattern.isEmpty()) + return; + + addPattern(pattern, false, false); + ui->tableWidget->scrollToBottom(); +} + +void IgnoreListTableWidget::readIgnoreFile(const QString &file, bool readOnly) +{ + QFile ignores(file); + if (ignores.open(QIODevice::ReadOnly)) { + while (!ignores.atEnd()) { + QString line = QString::fromUtf8(ignores.readLine()); + line.chop(1); + if (!line.isEmpty() && !line.startsWith("#")) { + bool deletable = false; + if (line.startsWith(']')) { + deletable = true; + line = line.mid(1); + } + addPattern(line, deletable, readOnly); + } + } + } +} + +int IgnoreListTableWidget::addPattern(const QString &pattern, bool deletable, bool readOnly) +{ + int newRow = ui->tableWidget->rowCount(); + ui->tableWidget->setRowCount(newRow + 1); + + QTableWidgetItem *patternItem = new QTableWidgetItem; + patternItem->setText(pattern); + ui->tableWidget->setItem(newRow, patternCol, patternItem); + + QTableWidgetItem *deletableItem = new QTableWidgetItem; + deletableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + deletableItem->setCheckState(deletable ? Qt::Checked : Qt::Unchecked); + ui->tableWidget->setItem(newRow, deletableCol, deletableItem); + + if (readOnly) { + patternItem->setFlags(patternItem->flags() ^ Qt::ItemIsEnabled); + patternItem->setToolTip(readOnlyTooltip); + deletableItem->setFlags(deletableItem->flags() ^ Qt::ItemIsEnabled); + } + + ui->removeAllPushButton->setEnabled(true); + + return newRow; +} + +} // namespace OCC diff --git a/src/gui/ignorelisttablewidget.h b/src/gui/ignorelisttablewidget.h new file mode 100644 index 0000000000..3bded0462a --- /dev/null +++ b/src/gui/ignorelisttablewidget.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +class QAbstractButton; + +namespace OCC { + +namespace Ui { + class IgnoreListTableWidget; +} + +class IgnoreListTableWidget : public QWidget +{ + Q_OBJECT + +public: + IgnoreListTableWidget(QWidget *parent = nullptr); + ~IgnoreListTableWidget(); + + void readIgnoreFile(const QString &file, bool readOnly = false); + int addPattern(const QString &pattern, bool deletable, bool readOnly); + +public slots: + void slotRemoveAllItems(); + void slotWriteIgnoreFile(const QString & file); + +private slots: + void slotItemSelectionChanged(); + void slotRemoveCurrentItem(); + void slotAddPattern(); + +private: + void setupTableReadOnlyItems(); + QString readOnlyTooltip; + Ui::IgnoreListTableWidget *ui; +}; +} // namespace OCC diff --git a/src/gui/ignorelisttablewidget.ui b/src/gui/ignorelisttablewidget.ui new file mode 100644 index 0000000000..2a618395a9 --- /dev/null +++ b/src/gui/ignorelisttablewidget.ui @@ -0,0 +1,112 @@ + + + OCC::IgnoreListTableWidget + + + + 0 + 0 + 342 + 378 + + + + IgnoreListTableWidget + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + 2 + + + + Pattern + + + + + Allow Deletion + + + + + + + + true + + + Add + + + + + + + true + + + Remove + + + + + + + Remove all + + + + + + + true + + + Qt::Vertical + + + + 20 + 322 + + + + + + + + true + + + + 0 + 0 + + + + + + + Qt::PlainText + + + true + + + + + + + + diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index d9c240a931..3e2624a21e 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -91,7 +91,7 @@ SyncEngine::SyncEngine(AccountPtr account, const QString &localPath, _csync_ctx.reset(new CSYNC(localPath.toUtf8().data(), journal)); - _excludedFiles.reset(new ExcludedFiles); + _excludedFiles.reset(new ExcludedFiles(localPath)); _csync_ctx->exclude_traversal_fn = _excludedFiles->csyncTraversalMatchFun(); _syncFileStatusTracker.reset(new SyncFileStatusTracker(this)); diff --git a/test/csync/csync_tests/check_csync_exclude.cpp b/test/csync/csync_tests/check_csync_exclude.cpp index 95b6e9a31d..07ec665a8c 100644 --- a/test/csync/csync_tests/check_csync_exclude.cpp +++ b/test/csync/csync_tests/check_csync_exclude.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #define CSYNC_TEST 1 #include "csync_exclude.cpp" @@ -115,16 +116,32 @@ static void check_csync_exclude_add(void **) excludedFiles->addManualExclude("/tmp/check_csync1/*"); assert_int_equal(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST); assert_int_equal(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED); - assert_true(excludedFiles->_allExcludes.contains("/tmp/check_csync1/*")); + assert_true(excludedFiles->_allExcludes["/"].contains("/tmp/check_csync1/*")); - assert_true(excludedFiles->_fullRegexFile.pattern().contains("csync1")); - assert_true(excludedFiles->_fullTraversalRegexFile.pattern().contains("csync1")); - assert_false(excludedFiles->_bnameTraversalRegexFile.pattern().contains("csync1")); + assert_true(excludedFiles->_fullRegexFile["/"].pattern().contains("csync1")); + assert_true(excludedFiles->_fullTraversalRegexFile["/"].pattern().contains("csync1")); + assert_false(excludedFiles->_bnameTraversalRegexFile["/"].pattern().contains("csync1")); excludedFiles->addManualExclude("foo"); - assert_true(excludedFiles->_bnameTraversalRegexFile.pattern().contains("foo")); - assert_true(excludedFiles->_fullRegexFile.pattern().contains("foo")); - assert_false(excludedFiles->_fullTraversalRegexFile.pattern().contains("foo")); + assert_true(excludedFiles->_bnameTraversalRegexFile["/"].pattern().contains("foo")); + assert_true(excludedFiles->_fullRegexFile["/"].pattern().contains("foo")); + assert_false(excludedFiles->_fullTraversalRegexFile["/"].pattern().contains("foo")); +} + +static void check_csync_exclude_add_per_dir(void **) +{ + excludedFiles->addManualExclude("*", "/tmp/check_csync1/"); + assert_int_equal(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST); + assert_int_equal(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED); + assert_true(excludedFiles->_allExcludes["/tmp/check_csync1/"].contains("*")); + + excludedFiles->addManualExclude("foo"); + assert_true(excludedFiles->_fullRegexFile["/"].pattern().contains("foo")); + + excludedFiles->addManualExclude("foo/bar", "/tmp/check_csync1/"); + assert_true(excludedFiles->_fullRegexFile["/tmp/check_csync1/"].pattern().contains("bar")); + assert_true(excludedFiles->_fullTraversalRegexFile["/tmp/check_csync1/"].pattern().contains("bar")); + assert_false(excludedFiles->_bnameTraversalRegexFile["/tmp/check_csync1/"].pattern().contains("foo")); } static void check_csync_excluded(void **) @@ -232,6 +249,58 @@ static void check_csync_excluded(void **) assert_int_equal(check_file_full("c [d]"), CSYNC_FILE_EXCLUDE_LIST); } +static void check_csync_excluded_per_dir(void **) +{ + excludedFiles->addManualExclude("A"); + excludedFiles->reloadExcludeFiles(); + + assert_int_equal(check_file_full("A"), CSYNC_FILE_EXCLUDE_LIST); + + excludedFiles->clearManualExcludes(); + excludedFiles->addManualExclude("A", "/B/"); + excludedFiles->reloadExcludeFiles(); + + assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED); + assert_int_equal(check_file_full("B/A"), CSYNC_FILE_EXCLUDE_LIST); + + excludedFiles->clearManualExcludes(); + excludedFiles->addManualExclude("A/a1", "/B/"); + excludedFiles->reloadExcludeFiles(); + + assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED); + assert_int_equal(check_file_full("B/A/a1"), CSYNC_FILE_EXCLUDE_LIST); + +#define FOO_DIR "/tmp/check_csync1/foo" +#define FOO_EXCLUDE_LIST FOO_DIR "/.sync-exclude.lst" + int rc; + rc = system("mkdir -p " FOO_DIR); + assert_int_equal(rc, 0); + FILE *fh = fopen(FOO_EXCLUDE_LIST, "w"); + assert_non_null(fh); + rc = fprintf(fh, "bar"); + assert_int_not_equal(rc, 0); + rc = fclose(fh); + assert_int_equal(rc, 0); + + excludedFiles->addInTreeExcludeFilePath(FOO_EXCLUDE_LIST); + excludedFiles->reloadExcludeFiles(); + assert_int_equal(check_file_full(FOO_DIR), CSYNC_NOT_EXCLUDED); + assert_int_equal(check_file_full(FOO_DIR "/bar"), CSYNC_FILE_EXCLUDE_LIST); + assert_int_equal(check_file_full(FOO_DIR "/baz"), CSYNC_NOT_EXCLUDED); +#undef FOO_DIR +#undef FOO_EXCLUDE_LIST +} + +static void check_csync_excluded_traversal_per_dir(void **) +{ + assert_int_equal(check_file_traversal("/"), CSYNC_NOT_EXCLUDED); + + /* path wildcards */ + excludedFiles->addManualExclude("*/*.tex.tmp", "/latex/"); + assert_int_equal(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); + assert_int_equal(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); +} + static void check_csync_excluded_traversal(void **) { assert_int_equal(check_file_traversal(""), CSYNC_NOT_EXCLUDED); @@ -633,8 +702,11 @@ int torture_run_tests(void) const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(T::check_csync_exclude_add, T::setup, T::teardown), + cmocka_unit_test_setup_teardown(T::check_csync_exclude_add_per_dir, T::setup, T::teardown), cmocka_unit_test_setup_teardown(T::check_csync_excluded, T::setup_init, T::teardown), + cmocka_unit_test_setup_teardown(T::check_csync_excluded_per_dir, T::setup, T::teardown), cmocka_unit_test_setup_teardown(T::check_csync_excluded_traversal, T::setup_init, T::teardown), + cmocka_unit_test_setup_teardown(T::check_csync_excluded_traversal_per_dir, T::setup, T::teardown), cmocka_unit_test_setup_teardown(T::check_csync_dir_only, T::setup, T::teardown), cmocka_unit_test_setup_teardown(T::check_csync_pathes, T::setup_init, T::teardown), cmocka_unit_test_setup_teardown(T::check_csync_wildcards, T::setup, T::teardown), diff --git a/translations/client_bg.ts b/translations/client_bg.ts index ff8cf7f176..2f90c312fc 100644 --- a/translations/client_bg.ts +++ b/translations/client_bg.ts @@ -3114,44 +3114,49 @@ It is not advisable to use it. - + Organization: %1 Организация: %1 - + Unit: %1 Отдел: %1 - + Country: %1 Държава: %1 - Fingerprint (MD5): <tt>%1</tt> - Отпечатък (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Отпечатък (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Валиден от: %1 - + Expiration Date: %1 Валиден до: %1 - + Issuer: %1 Издател: %1 diff --git a/translations/client_ca.ts b/translations/client_ca.ts index bf1fa79d82..38c0d3d664 100644 --- a/translations/client_ca.ts +++ b/translations/client_ca.ts @@ -3133,44 +3133,49 @@ No és aconsellable fer-la servir. - + Organization: %1 Organització %1 - + Unit: %1 Unitat: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Empremta digital (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Empremta digital (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Data d'efectivitat: %1 - + Expiration Date: %1 Data de venciment: %1 - + Issuer: %1 Emissor: %1 diff --git a/translations/client_cs.ts b/translations/client_cs.ts index 4f2766b7c0..46e479dbdd 100644 --- a/translations/client_cs.ts +++ b/translations/client_cs.ts @@ -3130,44 +3130,49 @@ Nedoporučuje se jí používat. - + Organization: %1 Organizace: %1 - + Unit: %1 Jednotka: %1 - + Country: %1 Země: %1 - Fingerprint (MD5): <tt>%1</tt> - Otisk (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Otisk (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Datum účinnosti: %1 - + Expiration Date: %1 Datum skončení platnosti: %1 - + Issuer: %1 Vydavatel: %1 diff --git a/translations/client_da.ts b/translations/client_da.ts index bbc6c954f2..36fe5ae2a8 100644 --- a/translations/client_da.ts +++ b/translations/client_da.ts @@ -3108,44 +3108,49 @@ It is not advisable to use it. - + Organization: %1 - + Unit: %1 - + Country: %1 Land: %1 - Fingerprint (MD5): <tt>%1</tt> - - - - Fingerprint (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 - + Expiration Date: %1 Udløbsdato: %1 - + Issuer: %1 diff --git a/translations/client_de.ts b/translations/client_de.ts index e721ec0571..e88946ba48 100644 --- a/translations/client_de.ts +++ b/translations/client_de.ts @@ -3130,44 +3130,49 @@ Es ist nicht ratsam, sie zu benutzen. - + Organization: %1 Organisation: %1 - + Unit: %1 Einheit: %1 - + Country: %1 Land: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingerabdruck (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingerabdruck (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Aktuelles Datum: %1 - + Expiration Date: %1 Ablaufdatum: %1 - + Issuer: %1 Aussteller: %1 diff --git a/translations/client_el.ts b/translations/client_el.ts index 9270368780..2f76a2bab6 100644 --- a/translations/client_el.ts +++ b/translations/client_el.ts @@ -3120,44 +3120,49 @@ It is not advisable to use it. - + Organization: %1 Οργανισμός: %1 - + Unit: %1 Μονάδα: %1 - + Country: %1 Χώρα: %1 - Fingerprint (MD5): <tt>%1</tt> - Αποτύπωμα (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Αποτύπωμα (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Ημερομηνία Έναρξης: 1% - + Expiration Date: %1 Ημερομηνία Λήξης: %1 - + Issuer: %1 Εκδότης: %1 diff --git a/translations/client_en.ts b/translations/client_en.ts index b7536abef5..9a7462169d 100644 --- a/translations/client_en.ts +++ b/translations/client_en.ts @@ -3134,44 +3134,49 @@ It is not advisable to use it. - + Organization: %1 - + Unit: %1 - + Country: %1 - Fingerprint (MD5): <tt>%1</tt> - - - - Fingerprint (SHA1): <tt>%1</tt> - - Effective Date: %1 + + Fingerprint (SHA-256): <tt>%1</tt> - - Expiration Date: %1 + + Fingerprint (SHA-512): <tt>%1</tt> + Effective Date: %1 + + + + + Expiration Date: %1 + + + + Issuer: %1 diff --git a/translations/client_en_GB.ts b/translations/client_en_GB.ts index 2e234e6389..8b0804d2b5 100644 --- a/translations/client_en_GB.ts +++ b/translations/client_en_GB.ts @@ -3131,44 +3131,49 @@ It is not advisable to use it. - + Organization: %1 Organisation: %1 - + Unit: %1 Unit: %1 - + Country: %1 Country: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingerprint (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingerprint (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Effective Date: %1 - + Expiration Date: %1 Expiration Date: %1 - + Issuer: %1 Issuer: %1 diff --git a/translations/client_eo.ts b/translations/client_eo.ts index 0f7c717264..2d54cbf23e 100644 --- a/translations/client_eo.ts +++ b/translations/client_eo.ts @@ -3129,44 +3129,49 @@ Uzi ĝin ne konsilindas. - + Organization: %1 Organizaĵo: - + Unit: %1 Unuo: %1 - + Country: %1 Lando: %1 - Fingerprint (MD5): <tt>%1</tt> - MD5-fingrospuro: <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> SHA1-fingrospuro: <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Ekvalida dato: %1 - + Expiration Date: %1 Limdato: %1 - + Issuer: %1 Eldonanto: %1 diff --git a/translations/client_es.ts b/translations/client_es.ts index cd60d6db6c..b6e2b2e284 100644 --- a/translations/client_es.ts +++ b/translations/client_es.ts @@ -3130,44 +3130,49 @@ No se recomienda usarla. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huella dactilar (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha de vigencia: %1 - + Expiration Date: %1 Fecha de caducidad: %1 - + Issuer: %1 Emisor: %1 diff --git a/translations/client_es_AR.ts b/translations/client_es_AR.ts index cdce7f1983..746ebe28c4 100644 --- a/translations/client_es_AR.ts +++ b/translations/client_es_AR.ts @@ -3108,44 +3108,49 @@ It is not advisable to use it. - + Organization: %1 Empresa: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huella (SHA1): <tt>%1</tt> - - Effective Date: %1 - Desde: %1 + + Fingerprint (SHA-256): <tt>%1</tt> + - - Expiration Date: %1 + + Fingerprint (SHA-512): <tt>%1</tt> + Effective Date: %1 + Desde: %1 + + + + Expiration Date: %1 + + + + Issuer: %1 Generado por: %1 diff --git a/translations/client_es_CL.ts b/translations/client_es_CL.ts index ab15c667ed..cd907ec8ae 100644 --- a/translations/client_es_CL.ts +++ b/translations/client_es_CL.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_CO.ts b/translations/client_es_CO.ts index 521e6a5778..b87e5ce74a 100644 --- a/translations/client_es_CO.ts +++ b/translations/client_es_CO.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_CR.ts b/translations/client_es_CR.ts index 6047084ad2..031ad60b96 100644 --- a/translations/client_es_CR.ts +++ b/translations/client_es_CR.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_DO.ts b/translations/client_es_DO.ts index 6bf6632867..b36c8edc5b 100644 --- a/translations/client_es_DO.ts +++ b/translations/client_es_DO.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_EC.ts b/translations/client_es_EC.ts index 65d4183366..9c7defb640 100644 --- a/translations/client_es_EC.ts +++ b/translations/client_es_EC.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_GT.ts b/translations/client_es_GT.ts index ab3028f301..53f93628e8 100644 --- a/translations/client_es_GT.ts +++ b/translations/client_es_GT.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_HN.ts b/translations/client_es_HN.ts index 903d9ed353..63bfa3402b 100644 --- a/translations/client_es_HN.ts +++ b/translations/client_es_HN.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_MX.ts b/translations/client_es_MX.ts index ba2e2e76a7..fbfa7a5fb1 100644 --- a/translations/client_es_MX.ts +++ b/translations/client_es_MX.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_es_SV.ts b/translations/client_es_SV.ts index e77961607b..72e0a5f77d 100644 --- a/translations/client_es_SV.ts +++ b/translations/client_es_SV.ts @@ -3121,44 +3121,49 @@ No es recomendable usarlo. - + Organization: %1 Organización: %1 - + Unit: %1 Unidad: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Huella (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Huekka (SHA1):<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Fecha Efectiva: %1 - + Expiration Date: %1 Fecha de Expiración: %1 - + Issuer: %1 Emitido por: %1 diff --git a/translations/client_et.ts b/translations/client_et.ts index 0cbce95d39..c9b8c9e09d 100644 --- a/translations/client_et.ts +++ b/translations/client_et.ts @@ -3111,44 +3111,49 @@ Selle kasutamine pole soovitatav. - + Organization: %1 Organisatsioon: %1 - + Unit: %1 Ühik: %1 - + Country: %1 Riik: %1 - Fingerprint (MD5): <tt>%1</tt> - Sõrmejälg (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Sõrmejälg (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Efektiivne kuupäev: %1 - + Expiration Date: %1 Aegumise kuupäev: %1 - + Issuer: %1 Esitaja: %1 diff --git a/translations/client_eu.ts b/translations/client_eu.ts index 560b61ae84..4fda65c830 100644 --- a/translations/client_eu.ts +++ b/translations/client_eu.ts @@ -3129,44 +3129,49 @@ Ez da gomendagarria erabltzea. - + Organization: %1 Erakundea: %1 - + Unit: %1 Unitatea: %1 - + Country: %1 Herrialdea: %1 - Fingerprint (MD5): <tt>%1</tt> - Hatz-marka (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Hatz-marka (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Balio-data: %1 - + Expiration Date: %1 Iraungitze data: %1 - + Issuer: %1 Jaulkitzailea: %1 diff --git a/translations/client_fa.ts b/translations/client_fa.ts index dece5db29b..7e55ccaddf 100644 --- a/translations/client_fa.ts +++ b/translations/client_fa.ts @@ -3117,44 +3117,49 @@ It is not advisable to use it. - + Organization: %1 سازماندهی : %1 - + Unit: %1 واحد: %1 - + Country: %1 کشور: %1 - Fingerprint (MD5): <tt>%1</tt> - اثر انگشت (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> اثرانگشت (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 تاریخ موثر: %1 - + Expiration Date: %1 تاریخ انقضا: %1 - + Issuer: %1 صادرکننده: %1 diff --git a/translations/client_fi.ts b/translations/client_fi.ts index e496d7f9d9..a42c6b9ace 100644 --- a/translations/client_fi.ts +++ b/translations/client_fi.ts @@ -3115,44 +3115,49 @@ Osoitteen käyttäminen ei ole suositeltavaa. - + Organization: %1 Organisaatio: %1 - + Unit: %1 Yksikkö: %1 - + Country: %1 Maa: %1 - Fingerprint (MD5): <tt>%1</tt> - Sormenjälki (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Sormenjälki (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Voimassa oleva päivämäärä: %1 - + Expiration Date: %1 Vanhenemispäivä: %1 - + Issuer: %1 Myöntäjä: %1 diff --git a/translations/client_fr.ts b/translations/client_fr.ts index 99abfa78df..8561bea039 100644 --- a/translations/client_fr.ts +++ b/translations/client_fr.ts @@ -130,7 +130,7 @@ Re-open Browser (or right-click to copy link) - + Ré-ouvrez le navigateur web (ou copiez le lien par clic droit) @@ -153,7 +153,7 @@ Re-open Browser (or right-click to copy link) - + Ré-ouvrez le navigateur web (ou copiez le lien par clic droit) @@ -754,7 +754,7 @@ Error returned from the server: <em>%1</em> - + Erreur retournée par le serveur : <em>%1</em> @@ -785,7 +785,7 @@ Login in your browser (Login Flow v2) - + Connectez-vous avec votre navigateur web (Login Flow v2) @@ -3134,44 +3134,49 @@ Il est déconseillé de l'utiliser. - + Organization: %1 Organisation : %1 - + Unit: %1 Unité : %1 - + Country: %1 Pays : %1 - Fingerprint (MD5): <tt>%1</tt> - Empreinte (MD5) : <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Empreinte (SHA1) : <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Date de début de validité : %1 - + Expiration Date: %1 Date d'expiration : %1 - + Issuer: %1 Émetteur : %1 diff --git a/translations/client_gl.ts b/translations/client_gl.ts index 575af87b0d..dbc53095d3 100644 --- a/translations/client_gl.ts +++ b/translations/client_gl.ts @@ -3132,44 +3132,49 @@ Recomendámoslle que non o use. - + Organization: %1 Organización: %1 - + Unit: %1 Unidade: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Pegada dixital (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Pegada dixital (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Data de aplicación: %1 - + Expiration Date: %1 Data de caducidade: %1 - + Issuer: %1 Emisor: %1 diff --git a/translations/client_he.ts b/translations/client_he.ts index 3fad01b257..888cee6456 100644 --- a/translations/client_he.ts +++ b/translations/client_he.ts @@ -3110,44 +3110,49 @@ It is not advisable to use it. - + Organization: %1 - + Unit: %1 - + Country: %1 - Fingerprint (MD5): <tt>%1</tt> - - - - Fingerprint (SHA1): <tt>%1</tt> - - Effective Date: %1 + + Fingerprint (SHA-256): <tt>%1</tt> - - Expiration Date: %1 + + Fingerprint (SHA-512): <tt>%1</tt> + Effective Date: %1 + + + + + Expiration Date: %1 + + + + Issuer: %1 diff --git a/translations/client_hr.ts b/translations/client_hr.ts index ca39e9c297..826c2f7e9f 100644 --- a/translations/client_hr.ts +++ b/translations/client_hr.ts @@ -3131,44 +3131,49 @@ Nije preporučljivo koristiti ga. - + Organization: %1 Organizacija: %1 - + Unit: %1 Jedinica: %1 - + Country: %1 Država: %1 - Fingerprint (MD5): <tt>%1</tt> - Otisak prsta (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Otisak prsta (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Datum stupanja na snagu: %1 - + Expiration Date: %1 Datum isteka: %1 - + Issuer: %1 Izdavatelj: %1 diff --git a/translations/client_hu.ts b/translations/client_hu.ts index b0546cbbe5..f6d962195d 100644 --- a/translations/client_hu.ts +++ b/translations/client_hu.ts @@ -3130,44 +3130,49 @@ Használata nem ajánlott. - + Organization: %1 Szervezet: %1 - + Unit: %1 Egység: %1 - + Country: %1 Ország: %1 - Fingerprint (MD5): <tt>%1</tt> - Ellenőrzőkód (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Ellenőrzőkód (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Érvényességi dátum: %1 - + Expiration Date: %1 Lejárati dátum: %1 - + Issuer: %1 Kibocsátó: %1 diff --git a/translations/client_id.ts b/translations/client_id.ts index dee61c4fcd..452a464024 100644 --- a/translations/client_id.ts +++ b/translations/client_id.ts @@ -3128,44 +3128,49 @@ Tidak disarankan untuk digunakan. - + Organization: %1 - + Unit: %1 - + Country: %1 - Fingerprint (MD5): <tt>%1</tt> - - - - Fingerprint (SHA1): <tt>%1</tt> - - Effective Date: %1 + + Fingerprint (SHA-256): <tt>%1</tt> - - Expiration Date: %1 + + Fingerprint (SHA-512): <tt>%1</tt> + Effective Date: %1 + + + + + Expiration Date: %1 + + + + Issuer: %1 diff --git a/translations/client_is.ts b/translations/client_is.ts index 4ccb38815a..5156cc8131 100644 --- a/translations/client_is.ts +++ b/translations/client_is.ts @@ -3128,44 +3128,49 @@ Ekki er mælt með því að hún sé notuð. - + Organization: %1 Stofnun/Fyrirtæki/Félag (O): %1 - + Unit: %1 Eining: %1 - + Country: %1 Land: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingrafar (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingrafar (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Virkt þann: %1 - + Expiration Date: %1 Gildir til dags: %1 - + Issuer: %1 Útgefandi: %1 diff --git a/translations/client_it.ts b/translations/client_it.ts index 497b9c223d..97d3445797 100644 --- a/translations/client_it.ts +++ b/translations/client_it.ts @@ -3132,44 +3132,49 @@ Non è consigliabile utilizzarlo. - + Organization: %1 Organizzazione: %1 - + Unit: %1 Reparto: %1 - + Country: %1 Nazione: %1 - Fingerprint (MD5): <tt>%1</tt> - Impronta digitale (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Impronta digitale (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Data effettiva: %1 - + Expiration Date: %1 Data di scadenza: %1 - + Issuer: %1 Emittente: %1 diff --git a/translations/client_ja.ts b/translations/client_ja.ts index faf227a739..9900d18ceb 100644 --- a/translations/client_ja.ts +++ b/translations/client_ja.ts @@ -3125,44 +3125,49 @@ It is not advisable to use it. - + Organization: %1 組織名: %1 - + Unit: %1 部門名: %1 - + Country: %1 国: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingerprint (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingerprint (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 発効日: %1 - + Expiration Date: %1 有効期限: %1 - + Issuer: %1 発行者: %1 diff --git a/translations/client_lt_LT.ts b/translations/client_lt_LT.ts index d3480e2e4c..bd05c7aa68 100644 --- a/translations/client_lt_LT.ts +++ b/translations/client_lt_LT.ts @@ -3125,44 +3125,49 @@ Patariama jo nenaudoti. - + Organization: %1 Organizacija: %1 - + Unit: %1 Vienetas: %1 - + Country: %1 Šalis: %1 - Fingerprint (MD5): <tt>%1</tt> - Kontrolinis kodas (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Kontrolinis kodas (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Įsigalioja nuo: %1 - + Expiration Date: %1 Galioja iki: %1 - + Issuer: %1 Leidėjas: %! diff --git a/translations/client_lv.ts b/translations/client_lv.ts index 20b76e773d..a446f76774 100644 --- a/translations/client_lv.ts +++ b/translations/client_lv.ts @@ -3110,44 +3110,49 @@ It is not advisable to use it. - + Organization: %1 - + Unit: %1 - + Country: %1 - Fingerprint (MD5): <tt>%1</tt> - - - - Fingerprint (SHA1): <tt>%1</tt> - - Effective Date: %1 + + Fingerprint (SHA-256): <tt>%1</tt> - - Expiration Date: %1 + + Fingerprint (SHA-512): <tt>%1</tt> + Effective Date: %1 + + + + + Expiration Date: %1 + + + + Issuer: %1 @@ -3323,7 +3328,7 @@ It is not advisable to use it. Filename is too long. - Faila nosaukums ir pārāk garš. + Datnes nosaukums ir pārāk garš. diff --git a/translations/client_nb_NO.ts b/translations/client_nb_NO.ts index 2a3dd9e7b0..ac024b3aeb 100644 --- a/translations/client_nb_NO.ts +++ b/translations/client_nb_NO.ts @@ -3121,44 +3121,49 @@ Det er ikke tilrådelig å bruke den. - + Organization: %1 Organisasjon: %1 - + Unit: %1 Enhet: %1 - + Country: %1 Land: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingeravtrykk (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingeravtrykk (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Gyldig fra dato: %1 - + Expiration Date: %1 Utløpsdato: %1 - + Issuer: %1 Utsteder: %1 diff --git a/translations/client_nl.ts b/translations/client_nl.ts index a1a78b5ce9..90cb7bc8d5 100644 --- a/translations/client_nl.ts +++ b/translations/client_nl.ts @@ -3135,44 +3135,49 @@ We adviseren deze site niet te gebruiken. - + Organization: %1 Organisatie: %1 - + Unit: %1 Unit: %1 - + Country: %1 Land: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingerprint (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingerprint (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Ingangsdatum: %1 - + Expiration Date: %1 Vervaldatum: %1 - + Issuer: %1 Uitgever: %1 diff --git a/translations/client_pl.ts b/translations/client_pl.ts index c67e9f1e7a..d51083e459 100644 --- a/translations/client_pl.ts +++ b/translations/client_pl.ts @@ -3131,44 +3131,49 @@ Niezalecane jest jego użycie. - + Organization: %1 Organizacja: %1 - + Unit: %1 Jednostka: %1 - + Country: %1 Kraj: %1 - Fingerprint (MD5): <tt>%1</tt> - Odcisk (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Odcisk (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Data wejścia w życie: %1 - + Expiration Date: %1 Data wygaśnięcia: %1 - + Issuer: %1 Wystawca: %1 diff --git a/translations/client_pt.ts b/translations/client_pt.ts index b163b6a35e..7232d05e24 100644 --- a/translations/client_pt.ts +++ b/translations/client_pt.ts @@ -3120,44 +3120,49 @@ Não é aconselhada a sua utilização. - + Organization: %1 Organização: %1 - + Unit: %1 Unidade: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Chave(MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Chave(SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Data efectiva: %1 - + Expiration Date: %1 Data de Expiração: %1 - + Issuer: %1 Emissor: %1 diff --git a/translations/client_pt_BR.ts b/translations/client_pt_BR.ts index 99b7cff498..9b7dbb0f45 100644 --- a/translations/client_pt_BR.ts +++ b/translations/client_pt_BR.ts @@ -3131,44 +3131,49 @@ Não é aconselhável usá-la. - + Organization: %1 Organização: %1 - + Unit: %1 Unidade: %1 - + Country: %1 País: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingerprint (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingerprint (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Data Efetiva: %1 - + Expiration Date: %1 Data de Expiração: %1 - + Issuer: %1 Emissor: %1 diff --git a/translations/client_ru.ts b/translations/client_ru.ts index 8260aa8138..55d53340b7 100644 --- a/translations/client_ru.ts +++ b/translations/client_ru.ts @@ -3125,44 +3125,49 @@ It is not advisable to use it. - + Organization: %1 Организация: %1 - + Unit: %1 Подразделение: %1 - + Country: %1 Страна: %1 - Fingerprint (MD5): <tt>%1</tt> - Отпечаток (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Отпечаток (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Дата вступления в силу: %1 - + Expiration Date: %1 Дата окончания: %1 - + Issuer: %1 Издатель: %1 diff --git a/translations/client_sk.ts b/translations/client_sk.ts index 049c545151..c227e68867 100644 --- a/translations/client_sk.ts +++ b/translations/client_sk.ts @@ -3124,44 +3124,49 @@ Nie je vhodné ju používať. - + Organization: %1 Organizácia: %1 - + Unit: %1 Jednotka: %1 - + Country: %1 Krajina: %1 - Fingerprint (MD5): <tt>%1</tt> - Odtlačok (MD5 hash): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Odtlačok (SHA1 hash): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Dátum účinnosti: %1 - + Expiration Date: %1 Koniec platnosti: %1 - + Issuer: %1 Vydavateľ: %1 diff --git a/translations/client_sl.ts b/translations/client_sl.ts index 576fd4307e..e44ff91059 100644 --- a/translations/client_sl.ts +++ b/translations/client_sl.ts @@ -3120,44 +3120,49 @@ Uporaba ni priporočljiva. - + Organization: %1 Ustanova: %1 - + Unit: %1 Enota: %1 - + Country: %1 Država: %1 - Fingerprint (MD5): <tt>%1</tt> - Prstni odtis (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Prstni odtis (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Začetek veljavnosti: %1 - + Expiration Date: %1 Datum preteka: %1 - + Issuer: %1 Izdajatelj: %1 diff --git a/translations/client_sr.ts b/translations/client_sr.ts index 12dbb5f87c..88a9be1946 100644 --- a/translations/client_sr.ts +++ b/translations/client_sr.ts @@ -3131,44 +3131,49 @@ It is not advisable to use it. - + Organization: %1 Организација: %1 - + Unit: %1 Јединица: %1 - + Country: %1 Држава: %1 - Fingerprint (MD5): <tt>%1</tt> - Отисак (МД5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Отисак (СХА1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Важи од: %1 - + Expiration Date: %1 Истиче : %1 - + Issuer: %1 Издавач: %1 diff --git a/translations/client_sv.ts b/translations/client_sv.ts index 83ab899bef..bafc84fe05 100644 --- a/translations/client_sv.ts +++ b/translations/client_sv.ts @@ -3131,44 +3131,49 @@ Det är inte lämpligt använda den. - + Organization: %1 Organisation: %1 - + Unit: %1 Enhet: %1 - + Country: %1 Land: %1 - Fingerprint (MD5): <tt>%1</tt> - Fingeravtryck (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Fingeravtryck (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Giltigt datum: %1 - + Expiration Date: %1 Utgångsdatum: %1 - + Issuer: %1 Utfärdare: %1 diff --git a/translations/client_th.ts b/translations/client_th.ts index 0d1ed422d4..5f9e40876d 100644 --- a/translations/client_th.ts +++ b/translations/client_th.ts @@ -3118,44 +3118,49 @@ It is not advisable to use it. - + Organization: %1 หน่วยงาน: %1 - + Unit: %1 หน่วย: %1 - + Country: %1 ประเทศ: %1 - Fingerprint (MD5): <tt>%1</tt> - ลายนิ้วมือ (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> ลายนิ้วมือ (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 วันที่บังคับใช้: %1 - + Expiration Date: %1 หมดอายุวันที่: %1 - + Issuer: %1 ผู้รับรอง: %1 diff --git a/translations/client_tr.ts b/translations/client_tr.ts index bc69291012..8b751826c1 100644 --- a/translations/client_tr.ts +++ b/translations/client_tr.ts @@ -3130,44 +3130,49 @@ Kullanmanız önerilmez. - + Organization: %1 Kuruluş: %1 - + Unit: %1 Birim: %1 - + Country: %1 Ülke: %1 - Fingerprint (MD5): <tt>%1</tt> - Parmak izi (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Parmak izi (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Geçerlilik Tarihi: %1 - + Expiration Date: %1 Son Kullanım Tarihi: %1 - + Issuer: %1 Veren: %1 diff --git a/translations/client_uk.ts b/translations/client_uk.ts index 6b01b3d9fa..287eb80b1a 100644 --- a/translations/client_uk.ts +++ b/translations/client_uk.ts @@ -3111,44 +3111,49 @@ It is not advisable to use it. - + Organization: %1 Організація: %1 - + Unit: %1 Підрозділ: %1 - + Country: %1 Країна: %1 - Fingerprint (MD5): <tt>%1</tt> - Відбиток (MD5): <tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> Відбиток (SHA1): <tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 Дата введення в дію: %1 - + Expiration Date: %1 Термін Дії: %1 - + Issuer: %1 Емітент: %1 diff --git a/translations/client_zh_CN.ts b/translations/client_zh_CN.ts index 7b0a8b6646..347f955d30 100644 --- a/translations/client_zh_CN.ts +++ b/translations/client_zh_CN.ts @@ -3129,44 +3129,49 @@ It is not advisable to use it. - + Organization: %1 组织:%1 - + Unit: %1 单位:%1 - + Country: %1 国家:%1 - Fingerprint (MD5): <tt>%1</tt> - MD5 指纹:<tt>%1</tt> - - - Fingerprint (SHA1): <tt>%1</tt> SHA1 指纹:<tt>%1</tt> - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 有效日期:%1 - + Expiration Date: %1 过期日期:%1 - + Issuer: %1 签发人:%1 diff --git a/translations/client_zh_TW.ts b/translations/client_zh_TW.ts index e3503dc197..df3e9aa611 100644 --- a/translations/client_zh_TW.ts +++ b/translations/client_zh_TW.ts @@ -3117,44 +3117,49 @@ It is not advisable to use it. - + Organization: %1 組織:%1 - + Unit: %1 單位:%1 - + Country: %1 國家:%1 - Fingerprint (MD5): <tt>%1</tt> - 指紋 (MD5): &lt;tt&gt;%1&lt;/tt&gt; - - - Fingerprint (SHA1): <tt>%1</tt> 指紋 (SHA1): &lt;tt&gt;%1&lt;/tt&gt; - + + Fingerprint (SHA-256): <tt>%1</tt> + + + + + Fingerprint (SHA-512): <tt>%1</tt> + + + + Effective Date: %1 有效日期:%1 - + Expiration Date: %1 到期日: %1 - + Issuer: %1 簽發者: %1