aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordsc <xmrdsc@protonmail.com>2019-07-03 05:13:51 +0200
committerdsc <xmrdsc@protonmail.com>2019-07-16 18:33:44 +0200
commit0b6132897101c4cd1618c79049d5685c5e9874fa (patch)
treee59e9bf4eaff9296b9c10a9d9a7207b565a2ae1c
parentcfec9dde968cb89f8fe5293958b82181348111ea (diff)
downloadmonzero-gui-0b6132897101c4cd1618c79049d5685c5e9874fa.tar.gz
monzero-gui-0b6132897101c4cd1618c79049d5685c5e9874fa.tar.xz
monzero-gui-0b6132897101c4cd1618c79049d5685c5e9874fa.zip
Detect tails, support data persistence
Co-authored-by: Thotbot <thotbot@protonmail.com> Co-authored-by: Selsta <selsta@sent.at>
-rw-r--r--Logger.cpp4
-rw-r--r--images/tails-grey.pngbin0 -> 7873 bytes
-rw-r--r--main.cpp41
-rw-r--r--main.qml6
-rw-r--r--monero-wallet-gui.pro6
-rw-r--r--pages/settings/SettingsInfo.qml35
-rw-r--r--qml.qrc1
-rw-r--r--src/qt/TailsOS.cpp100
-rw-r--r--src/qt/TailsOS.h23
-rw-r--r--src/qt/mime.cpp70
-rw-r--r--src/qt/mime.h36
-rw-r--r--src/qt/utils.cpp73
-rw-r--r--src/qt/utils.h5
13 files changed, 277 insertions, 123 deletions
diff --git a/Logger.cpp b/Logger.cpp
index f2e34552..ad356bcb 100644
--- a/Logger.cpp
+++ b/Logger.cpp
@@ -34,6 +34,7 @@
#include <QDebug>
#include "Logger.h"
+#include "src/qt/TailsOS.h"
#include "wallet/api/wallet2_api.h"
// default log path by OS (should be writable)
@@ -66,6 +67,9 @@ const QString getLogPath(const QString logPath)
{
const QFileInfo fi(logPath);
+ if(TailsOS::detect() && TailsOS::usePersistence)
+ return QDir::homePath() + "/Persistent/Monero/logs/" + defaultLogName;
+
if(!logPath.isEmpty() && !fi.isDir())
return fi.absoluteFilePath();
else {
diff --git a/images/tails-grey.png b/images/tails-grey.png
new file mode 100644
index 00000000..b2e18e42
--- /dev/null
+++ b/images/tails-grey.png
Binary files differ
diff --git a/main.cpp b/main.cpp
index a41b3c75..939b78f2 100644
--- a/main.cpp
+++ b/main.cpp
@@ -64,7 +64,7 @@
#include "MainApp.h"
#include "qt/ipc.h"
#include "qt/utils.h"
-#include "qt/mime.h"
+#include "src/qt/TailsOS.h"
#include "src/qt/KeysFiles.h"
#include "src/qt/MoneroSettings.h"
#include "qt/prices.h"
@@ -83,6 +83,7 @@ bool isAndroid = false;
bool isWindows = false;
bool isMac = false;
bool isLinux = false;
+bool isTails = false;
bool isDesktop = false;
bool isOpenGL = true;
@@ -102,6 +103,7 @@ int main(int argc, char *argv[])
bool isWindows = true;
#elif defined(Q_OS_LINUX)
bool isLinux = true;
+ bool isTails = TailsOS::detect();
#elif defined(Q_OS_MAC)
bool isMac = true;
#endif
@@ -123,25 +125,40 @@ int main(int argc, char *argv[])
// qDebug() << "High DPI auto scaling - enabled";
//#endif
+ MainApp app(argc, argv);
+
+ app.setApplicationName("monero-core");
+ app.setOrganizationDomain("getmonero.org");
+ app.setOrganizationName("monero-project");
+
+ // Ask to enable Tails OS persistence mode, it affects:
+ // - Log file location
+ // - QML Settings file location (monero-core.conf)
+ // - Default wallets path
+ // Target directory is: ~/Persistent/Monero
+ if (isTails) {
+ if (!TailsOS::detectDataPersistence())
+ TailsOS::showDataPersistenceDisabledWarning();
+ else
+ TailsOS::askPersistence();
+ }
+
QString moneroAccountsDir;
#if defined(Q_OS_WIN) || defined(Q_OS_IOS)
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
#else
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
#endif
- if (!moneroAccountsRootDir.empty()) {
+
+ if(isTails && TailsOS::usePersistence){
+ moneroAccountsDir = QDir::homePath() + "/Persistent/Monero/wallets";
+ } else if (!moneroAccountsRootDir.empty()) {
moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets";
} else {
qCritical() << "Error: accounts root directory could not be set";
return 1;
}
- MainApp app(argc, argv);
-
- app.setApplicationName("monero-core");
- app.setOrganizationDomain("getmonero.org");
- app.setOrganizationName("monero-project");
-
#if defined(Q_OS_LINUX)
if (isDesktop) app.setWindowIcon(QIcon(":/images/appicon.ico"));
#endif
@@ -174,9 +191,8 @@ int main(int argc, char *argv[])
}
qWarning().noquote() << "app startd" << "(log: " + logPath + ")";
-#ifdef Q_OS_LINUX
+ // Desktop entry
registerXdgMime(app);
-#endif
IPC *ipc = new IPC(&app);
QStringList posArgs = parser.positionalArguments();
@@ -317,6 +333,8 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("walletLogPath", logPath);
+ engine.rootContext()->setContextProperty("tailsUsePersistence", TailsOS::usePersistence);
+
// Exclude daemon manager from IOS
#ifndef Q_OS_IOS
const QStringList arguments = (QStringList) QCoreApplication::arguments().at(0);
@@ -330,7 +348,7 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("isIOS", isIOS);
engine.rootContext()->setContextProperty("isAndroid", isAndroid);
engine.rootContext()->setContextProperty("isOpenGL", isOpenGL);
- engine.rootContext()->setContextProperty("isLinux", isLinux);
+ engine.rootContext()->setContextProperty("isTails", isTails);
engine.rootContext()->setContextProperty("screenWidth", geo.width());
engine.rootContext()->setContextProperty("screenHeight", geo.height());
@@ -354,6 +372,7 @@ int main(int argc, char *argv[])
accountName = "My monero Account";
engine.rootContext()->setContextProperty("defaultAccountName", accountName);
+ engine.rootContext()->setContextProperty("homePath", QDir::homePath());
engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath());
engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount());
diff --git a/main.qml b/main.qml
index 1655456c..25536f79 100644
--- a/main.qml
+++ b/main.qml
@@ -1349,6 +1349,12 @@ ApplicationWindow {
MoneroSettings {
id: persistentSettings
+ fileName: {
+ if(isTails && tailsUsePersistence)
+ return homePath + "/Persistent/Monero/monero-core.conf";
+ return "";
+ }
+
property string language
property string locale
property string account_name
diff --git a/monero-wallet-gui.pro b/monero-wallet-gui.pro
index d832ee12..97286b05 100644
--- a/monero-wallet-gui.pro
+++ b/monero-wallet-gui.pro
@@ -65,12 +65,12 @@ HEADERS += \
MainApp.h \
src/qt/FutureScheduler.h \
src/qt/ipc.h \
- src/qt/mime.h \
src/qt/KeysFiles.h \
src/qt/utils.h \
src/qt/prices.h \
src/qt/macoshelper.h \
src/qt/MoneroSettings.h
+ src/qt/TailsOS.h
SOURCES += main.cpp \
filter.cpp \
@@ -101,11 +101,11 @@ SOURCES += main.cpp \
MainApp.cpp \
src/qt/FutureScheduler.cpp \
src/qt/ipc.cpp \
- src/qt/mime.cpp \
src/qt/KeysFiles.cpp \
src/qt/utils.cpp \
src/qt/prices.cpp \
- src/qt/MoneroSettings.cpp
+ src/qt/MoneroSettings.cpp \
+ src/qt/TailsOS.cpp
CONFIG(DISABLE_PASS_STRENGTH_METER) {
HEADERS -= src/zxcvbn-c/zxcvbn.h
diff --git a/pages/settings/SettingsInfo.qml b/pages/settings/SettingsInfo.qml
index 938bd122..80e6a129 100644
--- a/pages/settings/SettingsInfo.qml
+++ b/pages/settings/SettingsInfo.qml
@@ -326,6 +326,41 @@ Rectangle {
font.pixelSize: 14
text: isOpenGL ? "OpenGL" : "Low graphics mode"
}
+
+ Rectangle {
+ visible: isTails
+ height: 1
+ Layout.topMargin: 2
+ Layout.bottomMargin: 2
+ Layout.fillWidth: true
+ color: MoneroComponents.Style.dividerColor
+ opacity: MoneroComponents.Style.dividerOpacity
+ }
+
+ Rectangle {
+ visible: isTails
+ height: 1
+ Layout.topMargin: 2
+ Layout.bottomMargin: 2
+ Layout.fillWidth: true
+ color: MoneroComponents.Style.dividerColor
+ opacity: MoneroComponents.Style.dividerOpacity
+ }
+
+ MoneroComponents.TextBlock {
+ visible: isTails
+ Layout.fillWidth: true
+ font.pixelSize: 14
+ text: qsTr("Tails: ") + translationManager.emptyString
+ }
+
+ MoneroComponents.TextBlock {
+ visible: isTails
+ Layout.fillWidth: true
+ color: MoneroComponents.Style.dimmedFontColor
+ font.pixelSize: 14
+ text: tailsUsePersistence ? qsTr("persistent") + translationManager.emptyString : qsTr("persistence disabled") + translationManager.emptyString;
+ }
}
// Copy info to clipboard
diff --git a/qml.qrc b/qml.qrc
index 3bced000..29f68f1a 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -251,5 +251,6 @@
<file>images/copy.svg</file>
<file>images/edit.svg</file>
<file>images/arrow-right-in-circle-outline-medium-white.svg</file>
+ <file>images/tails-grey.png</file>
</qresource>
</RCC>
diff --git a/src/qt/TailsOS.cpp b/src/qt/TailsOS.cpp
new file mode 100644
index 00000000..df2fa92b
--- /dev/null
+++ b/src/qt/TailsOS.cpp
@@ -0,0 +1,100 @@
+#include <QRegExp>
+#include <QMessageBox>
+#include <QPixmap>
+#include <QTranslator>
+
+#include "TailsOS.h"
+#include "utils.h"
+
+bool TailsOS::usePersistence = false;
+QString TailsOS::tailsPathData = QString("/live/persistence/TailsData_unlocked/");
+
+bool TailsOS::detect()
+{
+ if (!fileExists("/etc/os-release"))
+ return false;
+
+ QByteArray data = fileOpen("/etc/os-release");
+ QRegularExpression re("TAILS_PRODUCT_NAME=\"Tails\"");
+ QRegularExpressionMatch os_match = re.match(data);
+ bool matched = os_match.hasMatch();
+
+#ifdef QT_DEBUG
+ if (matched)
+ qDebug() << "Tails OS detected";
+#endif
+
+ return matched;
+}
+
+bool TailsOS::detectDataPersistence()
+{
+ return QDir(QDir::homePath() + "/Persistent").exists();
+}
+
+bool TailsOS::detectDotPersistence()
+{
+ return QDir(tailsPathData + "dotfiles").exists();
+}
+
+void TailsOS::showDataPersistenceDisabledWarning()
+{
+ QMessageBox msgBox;
+ msgBox.setText(QObject::tr("Warning: persistence disabled"));
+ msgBox.setWindowTitle(QObject::tr("Warning: persistence disabled"));
+ msgBox.setInformativeText(
+ QObject::tr("Monero GUI has detected that Tails persistence is "
+ "currently disabled. Any configurations you make inside "
+ "the Monero GUI will not be saved."
+ "\n\n"
+ "In addition, make sure to not save your wallet on the "
+ "filesystem, as it will be lost at shutdown."
+ "\n\n"
+ "To enable Tails persistence, setup an encrypted volume "
+ "and restart Tails. To gain a startup menu item, "
+ "enable the Tails \"dotfiles\" feature."));
+
+ msgBox.setStandardButtons(QMessageBox::Ok);
+ msgBox.setDefaultButton(QMessageBox::Ok);
+ msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png"));
+ msgBox.exec();
+}
+
+void TailsOS::askPersistence()
+{
+ QMessageBox msgBox;
+ msgBox.setWindowTitle(QObject::tr("Monero GUI"));
+ msgBox.setText(QObject::tr("Use Tails persistence?"));
+ msgBox.setInformativeText(
+ QObject::tr("Persist wallet files and configuration on the encrypted volume?"
+ "\n\n"
+ "In addition, you can enable Tails dotfiles persistence "
+ "to gain a start menu entry.\n"));
+
+ msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ msgBox.setDefaultButton(QMessageBox::Yes);
+ msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png"));
+ TailsOS::usePersistence = (msgBox.exec() == QMessageBox::Yes);
+}
+
+void TailsOS::persistXdgMime(QString filePath, QString data)
+{
+ QFileInfo file(filePath);
+ QString tailsPath = tailsPathData + "dotfiles/.local/share/applications/";
+
+ // write to persistent volume
+#ifdef QT_DEBUG
+ qDebug() << "Writing xdg mime: " << tailsPath + file.fileName();
+#endif
+
+ QDir().mkpath(tailsPath); // ensure directory exists
+ fileWrite(tailsPath + file.fileName(), data);
+
+ // write to current session
+#ifdef QT_DEBUG
+ qDebug() << "Writing xdg mime: " << file.filePath();
+#endif
+
+ QDir().mkpath(file.path()); // ensure directory exists
+ fileWrite(file.filePath(), data);
+}
diff --git a/src/qt/TailsOS.h b/src/qt/TailsOS.h
new file mode 100644
index 00000000..05d5ebd1
--- /dev/null
+++ b/src/qt/TailsOS.h
@@ -0,0 +1,23 @@
+#ifndef TAILSOS_H
+#define TAILSOS_H
+
+#include <QApplication>
+
+
+class TailsOS
+{
+public:
+ TailsOS();
+ static bool detect();
+ static bool detectDataPersistence();
+ static bool detectDotPersistence();
+
+ static void showDataPersistenceDisabledWarning();
+ static void askPersistence();
+ static void persistXdgMime(QString filePath, QString data);
+
+ static bool usePersistence;
+ static QString tailsPathData;
+};
+
+#endif // TAILSOS_H
diff --git a/src/qt/mime.cpp b/src/qt/mime.cpp
deleted file mode 100644
index 6daf4de6..00000000
--- a/src/qt/mime.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2014-2019, The Monero Project
-//
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without modification, are
-// permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this list of
-// conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice, this list
-// of conditions and the following disclaimer in the documentation and/or other
-// materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its contributors may be
-// used to endorse or promote products derived from this software without specific
-// prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
-// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
-// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <QtCore>
-#include <QApplication>
-#include <QFile>
-#include <QTextStream>
-
-#include "mime.h"
-#include "utils.h"
-
-void registerXdgMime(QApplication &app){
- // MacOS handled via Info.plist
- // Windows handled in the installer by rbrunner7
-
- QString xdg = QString(
- "[Desktop Entry]\n"
- "Name=Monero GUI\n"
- "GenericName=Monero-GUI\n"
- "X-GNOME-FullName=Monero-GUI\n"
- "Comment=Monero GUI\n"
- "Keywords=Monero;\n"
- "Exec=%1 %u\n"
- "Terminal=false\n"
- "Type=Application\n"
- "Icon=monero\n"
- "Categories=Network;GNOME;Qt;\n"
- "MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n"
- "StartupNotify=true\n"
- "X-GNOME-Bugzilla-Bugzilla=GNOME\n"
- "X-GNOME-UsesNotifications=true\n"
- ).arg(app.applicationFilePath());
-
- QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
- QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
-
- qDebug() << QString("Writing %1").arg(filePath);
- QFile file(filePath);
- if(file.open(QIODevice::WriteOnly)){
- QTextStream out(&file); out << xdg << endl;
- file.close();
- }
- else
- file.close();
-}
diff --git a/src/qt/mime.h b/src/qt/mime.h
deleted file mode 100644
index b79d43a3..00000000
--- a/src/qt/mime.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2014-2019, The Monero Project
-//
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without modification, are
-// permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this list of
-// conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice, this list
-// of conditions and the following disclaimer in the documentation and/or other
-// materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its contributors may be
-// used to endorse or promote products derived from this software without specific
-// prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
-// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
-// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef MIME_H
-#define MIME_H
-
-#include <QApplication>
-
-void registerXdgMime(QApplication &app);
-
-#endif // MIME_H
diff --git a/src/qt/utils.cpp b/src/qt/utils.cpp
index 2407a50e..4418a050 100644
--- a/src/qt/utils.cpp
+++ b/src/qt/utils.cpp
@@ -27,15 +27,35 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore>
+#include <QApplication>
+#include "src/qt/TailsOS.h"
#include "utils.h"
bool fileExists(QString path) {
QFileInfo check_file(path);
- if (check_file.exists() && check_file.isFile())
+ return check_file.exists() && check_file.isFile();
+}
+
+QByteArray fileOpen(QString path) {
+ QFile file(path);
+ if(!file.open(QFile::ReadOnly | QFile::Text))
+ return QByteArray();
+
+ QByteArray data = file.readAll();
+ file.close();
+ return data;
+}
+
+bool fileWrite(QString path, QString data) {
+ QFile file(path);
+ if(file.open(QIODevice::WriteOnly)){
+ QTextStream out(&file); out << data << endl;
+ file.close();
return true;
- else
- return false;
+ }
+
+ return false;
}
QString getAccountName(){
@@ -47,6 +67,53 @@ QString getAccountName(){
return accountName;
}
+QString xdgMime(QApplication &app){
+ return QString(
+ "[Desktop Entry]\n"
+ "Name=Monero GUI\n"
+ "GenericName=Monero-GUI\n"
+ "X-GNOME-FullName=Monero-GUI\n"
+ "Comment=Monero GUI\n"
+ "Keywords=Monero;\n"
+ "Exec=%1 %u\n"
+ "Terminal=false\n"
+ "Type=Application\n"
+ "Icon=monero\n"
+ "Categories=Network;GNOME;Qt;\n"
+ "MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n"
+ "StartupNotify=true\n"
+ "X-GNOME-Bugzilla-Bugzilla=GNOME\n"
+ "X-GNOME-UsesNotifications=true\n"
+ ).arg(app.applicationFilePath());
+}
+
+void registerXdgMime(QApplication &app){
+#ifdef Q_OS_LINUX
+ // Register desktop entry
+ // - MacOS handled via Info.plist
+ // - Windows handled in the installer by rbrunner7
+ // - Linux written to `QStandardPaths::ApplicationsLocation`
+ // - Tails written to persistent dotfiles
+ QString mime = xdgMime(app);
+ QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
+ QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
+
+ if (TailsOS::detect() && TailsOS::detectDotPersistence() && TailsOS::usePersistence) {
+ TailsOS::persistXdgMime(filePath, mime);
+ return;
+ }
+
+ QFileInfo file(filePath);
+ QDir().mkpath(file.path()); // ensure directory exists
+
+#ifdef QT_DEBUG
+ qDebug() << "Writing xdg mime: " << filePath;
+#endif
+
+ fileWrite(filePath, mime);
+#endif
+}
+
QString randomUserAgent(){
QStringList urand;
urand << "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
diff --git a/src/qt/utils.h b/src/qt/utils.h
index c18ffdc1..f48dff97 100644
--- a/src/qt/utils.h
+++ b/src/qt/utils.h
@@ -31,9 +31,14 @@
#include <QtCore>
#include <QRegExp>
+#include <QApplication>
bool fileExists(QString path);
+QByteArray fileOpen(QString path);
+bool fileWrite(QString path, QString data);
QString getAccountName();
+QString xdgMime(QApplication &app);
+void registerXdgMime(QApplication &app);
const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)");
QString randomUserAgent();