2014-07-07 00:19:45 +08:00
|
|
|
/*
|
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
|
|
|
This program is libre 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 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
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 COPYING file for more details.
|
|
|
|
*/
|
|
|
|
|
2015-06-04 07:30:17 +08:00
|
|
|
#include "toxme.h"
|
2014-06-27 06:32:08 +08:00
|
|
|
#include "widget/widget.h"
|
2014-09-30 02:28:59 +08:00
|
|
|
#include "misc/settings.h"
|
2015-02-06 19:28:49 +08:00
|
|
|
#include "src/nexus.h"
|
2014-11-06 22:12:10 +08:00
|
|
|
#include "src/ipc.h"
|
|
|
|
#include "src/widget/toxuri.h"
|
2014-11-08 05:45:21 +08:00
|
|
|
#include "src/widget/toxsave.h"
|
2014-11-10 06:24:23 +08:00
|
|
|
#include "src/autoupdate.h"
|
2015-06-04 20:19:18 +08:00
|
|
|
#include "src/profile.h"
|
2015-04-25 00:53:19 +08:00
|
|
|
#include "src/profilelocker.h"
|
2015-06-04 07:30:17 +08:00
|
|
|
#include "src/widget/loginscreen.h"
|
2015-06-05 18:26:04 +08:00
|
|
|
#include "src/translator.h"
|
2014-06-25 04:11:11 +08:00
|
|
|
#include <QApplication>
|
2014-11-12 07:58:20 +08:00
|
|
|
#include <QCommandLineParser>
|
|
|
|
#include <QDateTime>
|
2014-09-11 21:44:34 +08:00
|
|
|
#include <QDebug>
|
2014-11-01 13:27:10 +08:00
|
|
|
#include <QDir>
|
2014-11-12 07:58:20 +08:00
|
|
|
#include <QFile>
|
|
|
|
#include <QFontDatabase>
|
2014-11-07 12:53:05 +08:00
|
|
|
#include <QMutexLocker>
|
2015-03-04 11:23:54 +08:00
|
|
|
#include <QProcess>
|
2014-11-01 13:27:10 +08:00
|
|
|
|
2014-11-09 22:51:00 +08:00
|
|
|
#include <sodium.h>
|
2015-03-04 11:23:54 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#define EXIT_UPDATE_MACX 218 //We track our state using unique exit codes when debugging
|
2015-03-06 02:16:59 +08:00
|
|
|
#define EXIT_UPDATE_MACX_FAIL 216
|
2015-03-04 11:23:54 +08:00
|
|
|
|
2014-11-01 13:27:10 +08:00
|
|
|
#ifdef LOG_TO_FILE
|
2014-11-02 15:55:11 +08:00
|
|
|
static QTextStream* logFile {nullptr};
|
2014-11-07 12:53:05 +08:00
|
|
|
static QMutex mutex;
|
2015-05-10 22:08:09 +08:00
|
|
|
#endif
|
2014-11-01 13:27:10 +08:00
|
|
|
|
2015-05-10 22:08:09 +08:00
|
|
|
void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QString& msg)
|
2014-11-01 13:27:10 +08:00
|
|
|
{
|
2014-11-02 21:17:50 +08:00
|
|
|
// Silence qWarning spam due to bug in QTextBrowser (trying to open a file for base64 images)
|
|
|
|
if (ctxt.function == QString("virtual bool QFSFileEngine::open(QIODevice::OpenMode)")
|
|
|
|
&& msg == QString("QFSFileEngine::open: No file name specified"))
|
|
|
|
return;
|
|
|
|
|
2015-05-10 22:08:09 +08:00
|
|
|
QString LogMsg = QString("[%1] %2:%3 : ")
|
|
|
|
.arg(QTime::currentTime().toString("HH:mm:ss.zzz")).arg(ctxt.file).arg(ctxt.line);
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case QtDebugMsg:
|
|
|
|
LogMsg += "Debug";
|
|
|
|
break;
|
|
|
|
case QtWarningMsg:
|
|
|
|
LogMsg += "Warning";
|
|
|
|
break;
|
|
|
|
case QtCriticalMsg:
|
|
|
|
LogMsg += "Critical";
|
|
|
|
break;
|
|
|
|
case QtFatalMsg:
|
|
|
|
LogMsg += "Fatal";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LogMsg += ": " + msg + "\n";
|
|
|
|
|
|
|
|
QTextStream out(stderr, QIODevice::WriteOnly);
|
|
|
|
out << LogMsg;
|
|
|
|
|
|
|
|
#ifdef LOG_TO_FILE
|
|
|
|
if (!logFile)
|
|
|
|
return;
|
|
|
|
|
2014-11-07 12:53:05 +08:00
|
|
|
QMutexLocker locker(&mutex);
|
2015-05-10 22:08:09 +08:00
|
|
|
*logFile << LogMsg;
|
2014-11-02 15:55:11 +08:00
|
|
|
logFile->flush();
|
2014-11-01 13:27:10 +08:00
|
|
|
#endif
|
2015-05-10 22:08:09 +08:00
|
|
|
}
|
2014-06-25 04:11:11 +08:00
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2015-05-10 22:08:09 +08:00
|
|
|
qInstallMessageHandler(logMessageHandler); // Enable log as early as possible
|
2014-06-25 04:11:11 +08:00
|
|
|
QApplication a(argc, argv);
|
2014-07-12 00:05:18 +08:00
|
|
|
a.setApplicationName("qTox");
|
2014-06-25 04:11:11 +08:00
|
|
|
a.setOrganizationName("Tox");
|
2014-11-12 07:58:20 +08:00
|
|
|
a.setApplicationVersion("\nGit commit: " + QString(GIT_VERSION));
|
2015-03-02 19:38:42 +08:00
|
|
|
|
|
|
|
#ifdef HIGH_DPI
|
|
|
|
a.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
|
|
|
#endif
|
2014-11-12 07:58:20 +08:00
|
|
|
|
2015-04-25 02:45:26 +08:00
|
|
|
qsrand(time(0));
|
|
|
|
|
2015-06-05 18:26:04 +08:00
|
|
|
Translator::translate();
|
|
|
|
|
2014-11-12 07:58:20 +08:00
|
|
|
// Process arguments
|
|
|
|
QCommandLineParser parser;
|
|
|
|
parser.setApplicationDescription("qTox, version: " + QString(GIT_VERSION) + "\nBuilt: " + __TIME__ + " " + __DATE__);
|
|
|
|
parser.addHelpOption();
|
|
|
|
parser.addVersionOption();
|
|
|
|
parser.addPositionalArgument("uri", QObject::tr("Tox URI to parse"));
|
2015-01-29 04:40:09 +08:00
|
|
|
parser.addOption(QCommandLineOption("p", QObject::tr("Starts new instance and loads specified profile."), QObject::tr("profile")));
|
2014-11-12 07:58:20 +08:00
|
|
|
parser.process(a);
|
2014-06-30 08:24:27 +08:00
|
|
|
|
2015-02-21 20:49:27 +08:00
|
|
|
#ifndef Q_OS_ANDROID
|
|
|
|
IPC::getInstance();
|
|
|
|
#endif
|
2014-11-12 06:21:16 +08:00
|
|
|
Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before
|
2015-02-06 19:28:49 +08:00
|
|
|
|
2015-01-29 04:40:09 +08:00
|
|
|
if (parser.isSet("p"))
|
2015-01-20 16:24:25 +08:00
|
|
|
{
|
2015-06-04 20:19:18 +08:00
|
|
|
QString profileName = parser.value("p");
|
|
|
|
if (QDir(Settings::getSettingsDirPath()).exists(profileName + ".tox"))
|
2015-01-20 16:24:25 +08:00
|
|
|
{
|
2015-06-04 20:19:18 +08:00
|
|
|
qDebug() << "Setting profile to" << profileName;
|
2015-06-04 21:16:25 +08:00
|
|
|
if (Profile::isEncrypted(profileName))
|
2015-06-04 20:19:18 +08:00
|
|
|
{
|
|
|
|
Settings::getInstance().setCurrentProfile(profileName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Profile* profile = Profile::loadProfile(profileName);
|
|
|
|
if (!profile)
|
|
|
|
{
|
|
|
|
qCritical() << "-p profile" << profileName + ".tox" << " couldn't be loaded";
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
Nexus::getInstance().setProfile(profile);
|
|
|
|
}
|
2015-01-20 16:24:25 +08:00
|
|
|
}
|
|
|
|
else
|
2015-01-29 04:33:41 +08:00
|
|
|
{
|
2015-06-04 20:19:18 +08:00
|
|
|
qCritical() << "-p profile" << profileName + ".tox" << "doesn't exist";
|
2015-01-29 04:33:41 +08:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2015-01-20 16:24:25 +08:00
|
|
|
}
|
2014-11-12 06:21:16 +08:00
|
|
|
|
2014-11-09 22:51:00 +08:00
|
|
|
sodium_init(); // For the auto-updater
|
|
|
|
|
2014-11-01 13:27:10 +08:00
|
|
|
#ifdef LOG_TO_FILE
|
2014-11-02 15:55:11 +08:00
|
|
|
logFile = new QTextStream;
|
2014-11-01 13:27:10 +08:00
|
|
|
QFile logfile(QDir(Settings::getSettingsDirPath()).filePath("qtox.log"));
|
2014-11-04 09:08:02 +08:00
|
|
|
if (logfile.open(QIODevice::Append))
|
|
|
|
{
|
|
|
|
logFile->setDevice(&logfile);
|
2015-01-28 20:43:32 +08:00
|
|
|
*logFile << QDateTime::currentDateTime().toString("\nyyyy-MM-dd HH:mm:ss' file logger starting\n'");
|
2014-11-04 09:08:02 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-10 22:08:09 +08:00
|
|
|
qWarning() << "Couldn't open log file!\n";
|
2014-11-04 09:08:02 +08:00
|
|
|
delete logFile;
|
|
|
|
logFile = nullptr;
|
|
|
|
}
|
2014-11-01 13:27:10 +08:00
|
|
|
#endif
|
|
|
|
|
2014-10-01 22:49:54 +08:00
|
|
|
// Windows platform plugins DLL hell fix
|
|
|
|
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
|
|
|
|
a.addLibraryPath("platforms");
|
2014-11-12 07:58:20 +08:00
|
|
|
|
2014-11-13 20:59:04 +08:00
|
|
|
qDebug() << "built on: " << __TIME__ << __DATE__ << "(" << TIMESTAMP << ")";
|
2014-10-18 15:47:42 +08:00
|
|
|
qDebug() << "commit: " << GIT_VERSION << "\n";
|
2014-10-01 22:49:54 +08:00
|
|
|
|
2015-05-11 05:40:08 +08:00
|
|
|
#if defined(Q_OS_MACX) && defined(QT_RELEASE)
|
2015-03-04 11:23:54 +08:00
|
|
|
if (qApp->applicationDirPath() != "/Applications/qtox.app/Contents/MacOS") {
|
|
|
|
qDebug() << "OS X: Not in Applications folder";
|
|
|
|
|
|
|
|
QMessageBox AskInstall;
|
|
|
|
AskInstall.setIcon(QMessageBox::Question);
|
|
|
|
AskInstall.setWindowModality(Qt::ApplicationModal);
|
|
|
|
AskInstall.setText("Move to Applications folder?");
|
2015-03-04 11:50:30 +08:00
|
|
|
AskInstall.setInformativeText("I can move myself to the Applications folder, keeping your downloads folder less cluttered.\r\n");
|
2015-03-04 11:23:54 +08:00
|
|
|
AskInstall.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
|
|
|
|
AskInstall.setDefaultButton(QMessageBox::Yes);
|
|
|
|
|
2015-03-05 04:29:12 +08:00
|
|
|
int AskInstallAttempt = AskInstall.exec(); //Actually ask the user
|
2015-03-04 11:23:54 +08:00
|
|
|
|
|
|
|
if (AskInstallAttempt == QMessageBox::Yes) {
|
|
|
|
QProcess *sudoprocess = new QProcess;
|
|
|
|
QProcess *qtoxprocess = new QProcess;
|
|
|
|
|
|
|
|
QString bindir = qApp->applicationDirPath();
|
|
|
|
QString appdir = bindir;
|
|
|
|
appdir.chop(15);
|
2015-03-06 02:16:59 +08:00
|
|
|
QString sudo = bindir + "/qtox_sudo rsync -avzhpltK " + appdir + " /Applications";
|
2015-03-04 11:23:54 +08:00
|
|
|
QString qtox = "open /Applications/qtox.app";
|
|
|
|
|
2015-03-06 02:16:59 +08:00
|
|
|
QString appdir_noqtox = appdir;
|
|
|
|
appdir_noqtox.chop(8);
|
|
|
|
|
|
|
|
if ((appdir_noqtox + "qtox.app") != appdir) //quick safety check
|
|
|
|
{
|
|
|
|
qDebug() << "OS X: Attmepted to delete non qTox directory!";
|
|
|
|
return EXIT_UPDATE_MACX_FAIL;
|
2015-03-04 11:23:54 +08:00
|
|
|
}
|
|
|
|
|
2015-03-06 02:16:59 +08:00
|
|
|
QDir old_app(appdir);
|
|
|
|
|
|
|
|
sudoprocess->start(sudo); //Where the magic actually happens, safety checks ^
|
2015-03-04 11:23:54 +08:00
|
|
|
sudoprocess->waitForFinished();
|
2015-03-06 02:16:59 +08:00
|
|
|
|
2015-03-21 16:59:28 +08:00
|
|
|
if (old_app.removeRecursively()) //We've just deleted the running program
|
|
|
|
{
|
2015-03-06 02:16:59 +08:00
|
|
|
qDebug() << "OS X: Cleaned up old directory";
|
2015-03-21 16:59:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-03-06 02:16:59 +08:00
|
|
|
qDebug() << "OS X: This should never happen, the directory failed to delete";
|
|
|
|
}
|
|
|
|
|
2015-03-21 16:59:28 +08:00
|
|
|
if (fork() != 0) //Forking is required otherwise it won't actually cleanly launch
|
2015-03-06 02:16:59 +08:00
|
|
|
return EXIT_UPDATE_MACX;
|
|
|
|
|
2015-03-04 11:23:54 +08:00
|
|
|
qtoxprocess->start(qtox);
|
|
|
|
|
2015-03-04 11:50:30 +08:00
|
|
|
return 0; //Actually kills it
|
2015-03-04 11:23:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-04 21:30:47 +08:00
|
|
|
// Install Unicode 6.1 supporting font
|
2014-06-30 08:24:27 +08:00
|
|
|
QFontDatabase::addApplicationFont("://DejaVuSans.ttf");
|
|
|
|
|
2014-11-10 06:24:23 +08:00
|
|
|
// Check whether we have an update waiting to be installed
|
|
|
|
#if AUTOUPDATE_ENABLED
|
|
|
|
if (AutoUpdater::isLocalUpdateReady())
|
|
|
|
AutoUpdater::installLocalUpdate(); ///< NORETURN
|
|
|
|
#endif
|
|
|
|
|
2015-02-06 19:28:49 +08:00
|
|
|
|
2015-02-06 08:27:07 +08:00
|
|
|
#ifndef Q_OS_ANDROID
|
2014-11-06 22:12:10 +08:00
|
|
|
// Inter-process communication
|
2015-02-21 20:49:27 +08:00
|
|
|
IPC& ipc = IPC::getInstance();
|
2015-02-20 20:26:41 +08:00
|
|
|
ipc.registerEventHandler("uri", &toxURIEventHandler);
|
|
|
|
ipc.registerEventHandler("save", &toxSaveEventHandler);
|
|
|
|
ipc.registerEventHandler("activate", &toxActivateEventHandler);
|
2014-06-25 04:11:11 +08:00
|
|
|
|
2015-04-25 00:53:19 +08:00
|
|
|
// If we're the IPC owner and we just started, then
|
|
|
|
// either we're the only running instance or any other instance
|
|
|
|
// is already so frozen it lost ownership.
|
|
|
|
// It's safe to remove any potential stale locks in this situation.
|
|
|
|
if (ipc.isCurrentOwner())
|
|
|
|
ProfileLocker::clearAllLocks();
|
|
|
|
|
2014-11-12 07:58:20 +08:00
|
|
|
if (parser.positionalArguments().size() > 0)
|
2014-11-06 22:12:10 +08:00
|
|
|
{
|
2014-11-12 07:58:20 +08:00
|
|
|
QString firstParam(parser.positionalArguments()[0]);
|
2014-11-06 22:12:10 +08:00
|
|
|
// Tox URIs. If there's already another qTox instance running, we ask it to handle the URI and we exit
|
|
|
|
// Otherwise we start a new qTox instance and process it ourselves
|
|
|
|
if (firstParam.startsWith("tox:"))
|
|
|
|
{
|
|
|
|
if (ipc.isCurrentOwner()) // Don't bother sending an event if we're going to process it ourselves
|
|
|
|
{
|
|
|
|
handleToxURI(firstParam.toUtf8());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-02-20 20:26:41 +08:00
|
|
|
time_t event = ipc.postEvent("uri", firstParam.toUtf8());
|
2015-03-19 18:06:05 +08:00
|
|
|
ipc.waitUntilAccepted(event);
|
2014-11-06 22:12:10 +08:00
|
|
|
// If someone else processed it, we're done here, no need to actually start qTox
|
|
|
|
if (!ipc.isCurrentOwner())
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2014-11-08 05:45:21 +08:00
|
|
|
else if (firstParam.endsWith(".tox"))
|
|
|
|
{
|
|
|
|
if (ipc.isCurrentOwner()) // Don't bother sending an event if we're going to process it ourselves
|
|
|
|
{
|
|
|
|
handleToxSave(firstParam.toUtf8());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-02-20 20:26:41 +08:00
|
|
|
time_t event = ipc.postEvent("save", firstParam.toUtf8());
|
2015-03-19 18:06:05 +08:00
|
|
|
ipc.waitUntilAccepted(event);
|
2014-11-08 05:45:21 +08:00
|
|
|
// If someone else processed it, we're done here, no need to actually start qTox
|
|
|
|
if (!ipc.isCurrentOwner())
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2014-11-13 08:46:17 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Invalid argument\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2014-11-06 22:12:10 +08:00
|
|
|
}
|
2015-04-25 01:43:39 +08:00
|
|
|
else if (!ipc.isCurrentOwner() && !parser.isSet("p"))
|
2014-11-26 01:11:05 +08:00
|
|
|
{
|
2015-02-21 00:17:30 +08:00
|
|
|
uint32_t dest = 0;
|
|
|
|
if (parser.isSet("p"))
|
|
|
|
dest = Settings::getInstance().getCurrentProfileId();
|
2015-03-21 16:59:28 +08:00
|
|
|
|
2015-02-21 00:17:30 +08:00
|
|
|
time_t event = ipc.postEvent("activate", QByteArray(), dest);
|
2015-03-19 18:06:05 +08:00
|
|
|
if (ipc.waitUntilAccepted(event, 2))
|
2015-02-21 00:17:30 +08:00
|
|
|
{
|
|
|
|
if (!ipc.isCurrentOwner())
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2014-11-26 01:11:05 +08:00
|
|
|
}
|
2015-02-06 08:27:07 +08:00
|
|
|
#endif
|
2014-11-06 22:12:10 +08:00
|
|
|
|
2015-02-20 20:26:41 +08:00
|
|
|
Nexus::getInstance().start();
|
|
|
|
|
2014-11-06 22:12:10 +08:00
|
|
|
// Run
|
2014-06-25 04:11:11 +08:00
|
|
|
int errorcode = a.exec();
|
|
|
|
|
2014-11-02 15:55:11 +08:00
|
|
|
#ifdef LOG_TO_FILE
|
|
|
|
delete logFile;
|
|
|
|
logFile = nullptr;
|
|
|
|
#endif
|
2014-06-25 04:11:11 +08:00
|
|
|
|
2015-02-07 02:38:08 +08:00
|
|
|
Nexus::destroyInstance();
|
|
|
|
|
2014-06-25 04:11:11 +08:00
|
|
|
return errorcode;
|
|
|
|
}
|