summaryrefslogtreecommitdiff
path: root/src/app/main.cpp
blob: 3e650a4dc4ae5a511fcbc3a31693fe45076f0eaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/* Copyright (C) 2014-2016 Dan Chapman <dpniel@ubuntu.com>

   This file is part of Dekko mail client

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
// NOTE: uncomment to enable profiling
//#define QML_COMPILER_STATS
#include <QApplication>
#include <QtQuick>
#include <QDebug>
#include <QQmlContext>
#include <QSettings>
#include <QtGui/QGuiApplication>
#include <QtQml/QtQml>
#include <QtQuick/QQuickView>
#include <QTranslator>
#include <QLocale>
#include <QScopedPointer>
#include "AppVersion/SetCoreApplication.h"
#include "Common/Application.h"
#include "Common/MetaTypes.h"
#include "Common/SettingsNames.h"
#include "static_plugins.h"
#include "DekkoGlobal.h"
#include "app/Settings/SettingsFileBase.h"
#include "app/Settings/MailboxSettings.h"
#include "app/Settings/NotificationSettings.h"
#include "app/Settings/ViewSettings.h"
#include "app/Utils/Path.h"
#include "app/Utils/CustomQQuickViewFactory.h"
#include "app/Network/MsgPartNetAccessManagerFactory.h"
#include "configure.cmake.h"

#ifdef UNCONFINED
#include <QCommandLineParser>
#endif

static bool checkForStaleLockFile(QLockFile **lockFile, QString &filePath, QString &errorMessage);

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    Q_INIT_RESOURCE(actionicons);
    Q_INIT_RESOURCE(providericons);

    //Install translations
    QTranslator dekkoTranslator;
    QTranslator dekkoBuildTranslator;
    // It would appear Qt has a real problem loading translations for anywhere but in the same directory
    // as the executable. I have no idea if this is click package related or a bug in Qt but this works
    // so i'm not going to complain.... (*much*)
    QString trPath;
#ifdef CLICK_MODE
    trPath = app.applicationDirPath();
#else
    trPath = QStringLiteral(DESKTOP_TR_PATH);
#endif
    qDebug() << "LOCATION: " << QLibraryInfo::location(QLibraryInfo::TranslationsPath);
    if (dekkoTranslator.load(QLocale::system().name(), trPath)) {
        qDebug() << "Translation loaded: " << !dekkoTranslator.isEmpty();
        app.installTranslator(&dekkoTranslator);
    } else if (dekkoBuildTranslator.load(QLocale::system().name(), QCoreApplication::applicationDirPath() + QStringLiteral("/locale/"))) {
        qDebug() << "Installing translations in build dir";
        app.installTranslator(&dekkoBuildTranslator);
    } else {
        qWarning() << "Failed loading translations";
    }

#ifdef UNCONFINED
    QCommandLineParser parser;
    parser.setApplicationDescription(QStringLiteral("Dekko email client"));
    parser.addVersionOption();
    parser.addHelpOption();
    parser.addPositionalArgument(QStringLiteral("mailto"), QStringLiteral("Start a compose session using the mailto: url scheme"));
    parser.process(app);
#endif

    Common::registerMetaTypes();
#ifdef CLICK_MODE
    Common::Application::name = QStringLiteral(APP_ID);
    // If the organization is set, QStandardPaths::DataLocation will be
    // $PREFIX/$APPNAME/$ORGANIZATION e.g.:
    // /usr/share/dekko.dekkoproject/dekko.dekkoproject
    Common::Application::organization = QStringLiteral(APP_ID);
#else
    Common::Application::name = QStringLiteral(APP_NAME);
    // If the organization is set, QStandardPaths::DataLocation will be
    // $PREFIX/$APPNAME/$ORGANIZATION e.g.:
    // /usr/share/dekko.dekkoproject/dekko.dekkoproject
    Common::Application::organization = QStringLiteral(APP_ORGANIZATION);
#endif

    AppVersion::setVersion();
    AppVersion::setCoreApplicationData();

    QString error;
    // Configure mbox settings
    QScopedPointer<Dekko::Settings::SettingsFileBase> mboxSettings(new Dekko::Settings::SettingsFileBase);
    Dekko::Settings::MailboxSettings::setDefaultFile(mboxSettings.data());
    QLockFile *mboxLock = 0;
    QString mlPath = Dekko::configLocation(QStringLiteral("mailboxConfig.json.lock"));
    if (!checkForStaleLockFile(&mboxLock, mlPath , error)) {
        qCritical() << error;
        return 1;
    }
    mboxSettings.data()->setPath(Dekko::configLocation(QStringLiteral("mailboxConfig.json")));
    QScopedPointer<QLockFile> mboxLockFile(mboxLock);
    // Notification settings
    QScopedPointer<Dekko::Settings::SettingsFileBase> notificationSettings(new Dekko::Settings::SettingsFileBase);
    Dekko::Settings::NotificationSettings::setSettingsFile(notificationSettings.data());
    QLockFile *notifyLock = 0;
    QString nlPath = Dekko::configLocation(QStringLiteral("notifications.json.lock"));
    if (!checkForStaleLockFile(&notifyLock, nlPath, error)) {
        qCritical() << error;
        return 1;
    }
    notificationSettings.data()->setPath(Dekko::configLocation(QStringLiteral("notifications.json")));
    QScopedPointer<QLockFile> notifyLockFile(notifyLock);
    // View settings
    QScopedPointer<Dekko::Settings::SettingsFileBase> viewSettings(new Dekko::Settings::SettingsFileBase);
    Dekko::Settings::ViewSettings::setViewSettingsFile(viewSettings.data());
    QLockFile *viewLock = 0;
    QString vlPath = Dekko::configLocation(QStringLiteral("viewSettings.json.lock"));
    if (!checkForStaleLockFile(&viewLock, vlPath, error)) {
        qCritical() << error;
        return 1;
    }
    viewSettings.data()->setPath(Dekko::configLocation(QStringLiteral("viewSettings.json")));
    QScopedPointer<QLockFile> viewLockFile(viewLock);

    QSharedPointer<QQuickView> qQuickViewer = Dekko::Utils::CustomQQuickViewFactory::instance();
    qQuickViewer->setResizeMode(QQuickView::SizeRootObjectToView);
    app.addLibraryPath(QCoreApplication::applicationDirPath());


    // let's first check all standard locations
    QString qmlFile = Dekko::findQmlFile(QStringLiteral("qml/main.qml"));
    QUrl addressbookStoreLocation(QStringLiteral(
                                      "file://%1/.local/share/dekko.dekkoproject/addressbook.vcard")
                                  .arg(QDir::homePath()));
    qQuickViewer->engine()->rootContext()->setContextProperty(QStringLiteral("addressbookStoreLocation"), QVariant::fromValue(addressbookStoreLocation));

    Dekko::Network::MsgPartNetAccessManagerFactory msgPartNetAccessManagerFactory;
    qQuickViewer->engine()->setNetworkAccessManagerFactory(&msgPartNetAccessManagerFactory);
    qQuickViewer->engine()->rootContext()->setContextProperty(QStringLiteral("msgPartNetAccessManagerFactory"), &msgPartNetAccessManagerFactory);
    qQuickViewer->engine()->rootContext()->setContextProperty(QStringLiteral("appUris"), QString::fromLatin1(qgetenv("APP_URIS")));

#ifdef WITH_CONVERGENCE
    qQuickViewer->engine()->rootContext()->setContextProperty(QStringLiteral("convergenceEnabled"), QVariant(true));
#else
    qQuickViewer->engine()->rootContext()->setContextProperty(QLatin1String("convergenceEnabled"), QVariant(false));
#endif
    QStringList mailToArgs;
#ifdef UNCONFINED
    mailToArgs << parser.positionalArguments();
#endif
    qQuickViewer->engine()->rootContext()->setContextProperty(QStringLiteral("mailToArgs"), mailToArgs);
    // Context property to figure out if we are on unity8/mir or not
    qQuickViewer->engine()->rootContext()->setContextProperty(QStringLiteral("isRunningOnMir"), QVariant(qgetenv("QT_QPA_PLATFORM") == "ubuntumirclient"));

    DekkoGlobal::registerDekkoTypes("DekkoCore");
    DekkoGlobal::registerTrojitaCoreTypes("TrojitaCore");

    qQuickViewer->setTitle(QObject::trUtf8("Dekko"));
    qQuickViewer->setSource(QUrl::fromLocalFile(qmlFile));
    qQuickViewer->show();
    return app.exec();
}

static bool checkForStaleLockFile(QLockFile **lockFile, QString &filePath, QString &errorMessage)
{
    QDir dir(Dekko::configLocation(QString()));
    if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
        errorMessage = QStringLiteral("Cannot create directory: %1").arg(dir.path());
        return false;
    }

    // Reset to config directory for consistency; avoid depending on this behavior for paths
    if (QDir::setCurrent(dir.absolutePath()) && dir.isRelative()) {
        dir.setPath(QStringLiteral("."));
    }
    QLockFile *lock = new QLockFile(filePath);
    *lockFile = lock;
    lock->setStaleLockTime(0);
    if (!lock->tryLock()) {
        if (lock->error() == QLockFile::LockFailedError) {
            // This happens if a stale lock file exists and another process uses that PID.
            // Try removing the stale file, which will fail if a real process is holding a
            // file-level lock. A false error is more problematic than not locking properly
            // on corner-case systems.
            if (!lock->removeStaleLockFile() || !lock->tryLock()) {
                errorMessage = QStringLiteral("Configuration file is already in use");
                return false;
            } else
                qDebug() << "Removed stale lock file";
        } else {
            errorMessage = QStringLiteral("Cannot write configuration file (failed to acquire lock)");
            return false;
        }
    }
    return true;
}