1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00
qTox/src/main.cpp

286 lines
9.3 KiB
C++
Raw Normal View History

2014-07-07 00:19:45 +08:00
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
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.
*/
2014-06-27 06:32:08 +08:00
#include "widget/widget.h"
2014-09-30 02:28:59 +08:00
#include "misc/settings.h"
#include "src/nexus.h"
#include "src/ipc.h"
#include "src/widget/toxuri.h"
#include "src/widget/toxsave.h"
#include "src/autoupdate.h"
2014-06-25 04:11:11 +08:00
#include <QApplication>
#include <QCommandLineParser>
#include <QDateTime>
2014-09-11 21:44:34 +08:00
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFontDatabase>
2014-11-07 12:53:05 +08:00
#include <QMutexLocker>
2015-03-04 11:23:54 +08:00
#include <QProcess>
#include <opencv2/core/core_c.h>
#include <sodium.h>
2015-01-30 00:36:22 +08:00
#include "toxme.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
#ifdef LOG_TO_FILE
static QtMessageHandler dflt;
static QTextStream* logFile {nullptr};
2014-11-07 12:53:05 +08:00
static QMutex mutex;
void myMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QString& msg)
{
if (!logFile)
return;
// 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;
2014-11-07 12:53:05 +08:00
QMutexLocker locker(&mutex);
2014-11-08 06:06:37 +08:00
dflt(type, ctxt, msg);
*logFile << QTime::currentTime().toString("HH:mm:ss' '") << msg << '\n';
logFile->flush();
}
#endif
2014-06-25 04:11:11 +08:00
int opencvErrorHandler(int status, const char* func_name, const char* err_msg,
const char* file_name, int line, void*)
{
qWarning() << "OpenCV: ERROR ("<<status<<") in "
<<file_name<<":"<<line<<":"<<func_name<<": "<<err_msg;
return 0;
}
2014-06-25 04:11:11 +08:00
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("qTox");
2014-06-25 04:11:11 +08:00
a.setOrganizationName("Tox");
a.setApplicationVersion("\nGit commit: " + QString(GIT_VERSION));
#ifdef HIGH_DPI
a.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
#endif
// 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"));
parser.addOption(QCommandLineOption("p", QObject::tr("Starts new instance and loads specified profile."), QObject::tr("profile")));
parser.process(a);
#ifndef Q_OS_ANDROID
IPC::getInstance();
#endif
Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before
if (parser.isSet("p"))
{
QString profile = parser.value("p");
if (QDir(Settings::getSettingsDirPath()).exists(profile + ".tox"))
{
qDebug() << "Setting profile to" << profile;
Settings::getInstance().switchProfile(profile);
}
else
{
qWarning() << "Error: -p profile" << profile + ".tox" << "doesn't exist";
return EXIT_FAILURE;
}
}
sodium_init(); // For the auto-updater
#ifdef LOG_TO_FILE
logFile = new QTextStream;
dflt = qInstallMessageHandler(nullptr);
QFile logfile(QDir(Settings::getSettingsDirPath()).filePath("qtox.log"));
2014-11-04 09:08:02 +08:00
if (logfile.open(QIODevice::Append))
{
logFile->setDevice(&logfile);
*logFile << QDateTime::currentDateTime().toString("\nyyyy-MM-dd HH:mm:ss' file logger starting\n'");
2014-11-04 09:08:02 +08:00
qInstallMessageHandler(myMessageHandler);
}
else
{
2015-03-04 11:23:54 +08:00
fprintf(stderr, "Couldn't open log file!\n");
2014-11-04 09:08:02 +08:00
delete logFile;
logFile = nullptr;
}
#endif
// Windows platform plugins DLL hell fix
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
a.addLibraryPath("platforms");
qDebug() << "built on: " << __TIME__ << __DATE__ << "(" << TIMESTAMP << ")";
qDebug() << "commit: " << GIT_VERSION << "\n";
cvSetErrMode(CV_ErrModeParent);
cvRedirectError(opencvErrorHandler);
2015-03-04 11:23:54 +08:00
#ifdef Q_OS_MACX
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?");
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
if (old_app.removeRecursively()) { //We've just deleted the running program
qDebug() << "OS X: Cleaned up old directory";
} else {
qDebug() << "OS X: This should never happen, the directory failed to delete";
}
if (fork() != 0) { //Forking is required otherwise it won't actually cleanly launch
return EXIT_UPDATE_MACX;
}
2015-03-04 11:23:54 +08:00
qtoxprocess->start(qtox);
return 0; //Actually kills it
2015-03-04 11:23:54 +08:00
}
}
#endif
// Install Unicode 6.1 supporting font
QFontDatabase::addApplicationFont("://DejaVuSans.ttf");
// Check whether we have an update waiting to be installed
#if AUTOUPDATE_ENABLED
if (AutoUpdater::isLocalUpdateReady())
AutoUpdater::installLocalUpdate(); ///< NORETURN
#endif
2015-02-06 08:27:07 +08:00
#ifndef Q_OS_ANDROID
// Inter-process communication
IPC& ipc = IPC::getInstance();
ipc.registerEventHandler("uri", &toxURIEventHandler);
ipc.registerEventHandler("save", &toxSaveEventHandler);
ipc.registerEventHandler("activate", &toxActivateEventHandler);
2014-06-25 04:11:11 +08:00
if (parser.positionalArguments().size() > 0)
{
QString firstParam(parser.positionalArguments()[0]);
// 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
{
time_t event = ipc.postEvent("uri", firstParam.toUtf8());
ipc.waitUntilAccepted(event);
// If someone else processed it, we're done here, no need to actually start qTox
if (!ipc.isCurrentOwner())
return EXIT_SUCCESS;
}
}
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
{
time_t event = ipc.postEvent("save", firstParam.toUtf8());
ipc.waitUntilAccepted(event);
// 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;
}
}
2015-02-21 00:17:30 +08:00
else if (!ipc.isCurrentOwner())
{
2015-02-21 00:17:30 +08:00
uint32_t dest = 0;
if (parser.isSet("p"))
dest = Settings::getInstance().getCurrentProfileId();
time_t event = ipc.postEvent("activate", QByteArray(), dest);
if (ipc.waitUntilAccepted(event, 2))
2015-02-21 00:17:30 +08:00
{
if (!ipc.isCurrentOwner())
return EXIT_SUCCESS;
}
}
2015-02-06 08:27:07 +08:00
#endif
Nexus::getInstance().start();
// Run
a.setQuitOnLastWindowClosed(false);
2014-06-25 04:11:11 +08:00
int errorcode = a.exec();
#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;
}