File indexing completed on 2024-04-14 05:41:10
0001 /** 0002 * SPDX-FileCopyrightText: (C) 2003 by Sébastien Laoût <slaout@linux62.org> 0003 * SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "common.h" 0007 0008 #include <QApplication> 0009 #include <QByteArray> 0010 #include <QFile> 0011 #include <QSaveFile> 0012 #include <QString> 0013 0014 #include <KLocalizedString> 0015 0016 #include "bnpview.h" 0017 #include "global.h" 0018 0019 0020 bool FileStorage::loadFromFile(const QString &fullPath, QString *string) 0021 { 0022 QByteArray array; 0023 0024 if (loadFromFile(fullPath, &array)) { 0025 *string = QString::fromUtf8(array.data(), array.size()); 0026 return true; 0027 } else 0028 return false; 0029 } 0030 0031 0032 bool FileStorage::loadFromFile(const QString &fullPath, QByteArray *array) 0033 { 0034 QFile file(fullPath); 0035 bool encrypted = false; 0036 0037 if (file.open(QIODevice::ReadOnly)) { 0038 *array = file.readAll(); 0039 const QByteArray magic = "-----BEGIN PGP MESSAGE-----"; 0040 int i = 0; 0041 0042 if (array->size() > magic.size()) 0043 for (i = 0; array->at(i) == magic[i]; ++i) 0044 ; 0045 if (i == magic.size()) { 0046 encrypted = true; 0047 } 0048 file.close(); 0049 #ifdef HAVE_LIBGPGME 0050 if (encrypted) { 0051 QByteArray tmp(*array); 0052 0053 tmp.detach(); 0054 // Only use gpg-agent for private key encryption since it doesn't 0055 // cache password used in symmetric encryption. 0056 m_gpg->setUseGnuPGAgent(Settings::useGnuPGAgent() && m_encryptionType == PrivateKeyEncryption); 0057 if (m_encryptionType == PrivateKeyEncryption) 0058 m_gpg->setText(i18n("Please enter the password for the following private key:"), false); 0059 else 0060 m_gpg->setText(i18n("Please enter the password for the basket <b>%1</b>:", basketName()), false); // Used when decrypting 0061 return m_gpg->decrypt(tmp, array); 0062 } 0063 #else 0064 if (encrypted) { 0065 return false; 0066 } 0067 #endif 0068 return true; 0069 } else 0070 return false; 0071 } 0072 0073 bool FileStorage::saveToFile(const QString &fullPath, const QString &string, bool isEncrypted) 0074 { 0075 const QByteArray array = string.toUtf8(); 0076 return saveToFile(fullPath, array, isEncrypted); 0077 } 0078 0079 bool FileStorage::saveToFile(const QString &fullPath, const QByteArray &array, bool isEncrypted) 0080 { 0081 ulong length = array.size(); 0082 0083 bool success = true; 0084 QByteArray tmp; 0085 0086 #ifdef HAVE_LIBGPGME 0087 if (isEncrypted) { 0088 QString key; 0089 0090 // We only use gpg-agent for private key encryption and saving without 0091 // public key doesn't need one. 0092 m_gpg->setUseGnuPGAgent(false); 0093 if (m_encryptionType == PrivateKeyEncryption) { 0094 key = m_encryptionKey; 0095 // public key doesn't need password 0096 m_gpg->setText(QString(), false); 0097 } else 0098 m_gpg->setText(i18n("Please assign a password to the basket <b>%1</b>:", basketName()), true); // Used when defining a new password 0099 0100 success = m_gpg->encrypt(array, length, &tmp, key); 0101 length = tmp.size(); 0102 } else 0103 tmp = array; 0104 0105 #else 0106 success = !isEncrypted; 0107 if (success) 0108 tmp = array; 0109 #endif 0110 /*if (success && (success = file.open(QIODevice::WriteOnly))){ 0111 success = (file.write(tmp) == (Q_LONG)tmp.size()); 0112 file.close(); 0113 }*/ 0114 0115 if (success) 0116 return safelySaveToFile(fullPath, tmp, length); 0117 else 0118 return false; 0119 } 0120 0121 /** 0122 * A safer version of saveToFile, that doesn't perform encryption. To save a 0123 * file owned by a basket (i.e. a basket or a note file), use saveToFile(), but 0124 * to save to another file, (e.g. the basket hierarchy), use this function 0125 * instead. 0126 */ 0127 bool FileStorage::safelySaveToFile(const QString &fullPath, const QByteArray &array, unsigned long length) 0128 { 0129 // Modulus operandi: 0130 // 1. Use QSaveFile to try and save the file 0131 // 2. Show a modal dialog (with the error) when bad things happen 0132 // 3. We keep trying (at increasing intervals, up until every minute) 0133 // until we finally save the file. 0134 0135 // The error dialog is static to make sure we never show the dialog twice, 0136 static const uint maxDelay = 60 * 1000; // ms 0137 uint retryDelay = 1000; // ms 0138 bool success = false; 0139 do { 0140 QSaveFile saveFile(fullPath); 0141 if (saveFile.open(QIODevice::WriteOnly)) { 0142 saveFile.write(array, length); 0143 if (saveFile.commit()) 0144 success = true; 0145 } 0146 0147 if (!success) { 0148 Q_EMIT Global::bnpView->showErrorMessage(i18n("Error while saving: ") + saveFile.errorString()); 0149 0150 static const uint sleepDelay = 50; // ms 0151 for (uint i = 0; i < retryDelay / sleepDelay; ++i) { 0152 qApp->processEvents(); 0153 } 0154 0155 // Double the retry delay, but don't go over the max. 0156 retryDelay = qMin(maxDelay, retryDelay * 2); // ms 0157 } 0158 } while (!success); 0159 0160 return true; // Guess we can't really return a fail 0161 } 0162 0163 bool FileStorage::safelySaveToFile(const QString &fullPath, const QString &string) 0164 { 0165 QByteArray bytes = string.toUtf8(); 0166 return safelySaveToFile(fullPath, bytes, bytes.length()); 0167 }