Kaidan.cpp 7.62 KB
Newer Older
1
/*
2
 *  Kaidan - A user-friendly XMPP client for every device!
3
 *
Linus Jahn's avatar
Linus Jahn committed
4 5
 *  Copyright (C) 2016-2018 Kaidan developers and contributors
 *  (see the LICENSE file for a full list of copyright authors)
6 7 8 9 10 11
 *
 *  Kaidan 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 3 of the License, or
 *  (at your option) any later version.
 *
Linus Jahn's avatar
Linus Jahn committed
12 13 14 15 16 17 18 19 20 21
 *  In addition, as a special exception, the author of Kaidan gives
 *  permission to link the code of its release with the OpenSSL
 *  project's "OpenSSL" library (or with modified versions of it that
 *  use the same license as the "OpenSSL" library), and distribute the
 *  linked executables. You must obey the GNU General Public License in
 *  all respects for all of the code used other than "OpenSSL". If you
 *  modify this file, you may extend this exception to your version of
 *  the file, but you are not obligated to do so.  If you do not wish to
 *  do so, delete this exception statement from your version.
 *
22 23 24 25 26 27
 *  Kaidan 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
Linus Jahn's avatar
Linus Jahn committed
28
 *  along with Kaidan.  If not, see <http://www.gnu.org/licenses/>.
29 30
 */

31
#include "Kaidan.h"
Georg's avatar
Georg committed
32

33 34
// Qt
#include <QDebug>
35
#include <QDir>
36 37
#include <QSettings>
#include <QString>
38
#include <QStandardPaths>
39
#include <QCoreApplication>
40
// Kaidan
41
#include "AvatarFileStorage.h"
42
#include "RosterModel.h"
43
#include "MessageModel.h"
44
#include "Database.h"
Georg's avatar
Georg committed
45

46
Kaidan::Kaidan(QGuiApplication *app, QObject *parent) : QObject(parent)
Georg's avatar
Georg committed
47
{
48 49 50
	//
	// Database and components
	//
51 52

	// setup database
53 54
	database = new Database();
	database->openDatabase();
55 56
	if (database->needToConvert())
		database->convertDatabase();
57 58

	// setup components
59 60 61
	messageModel = new MessageModel(database->getDatabase(), this);
	rosterModel = new RosterModel(database->getDatabase(), this);
	avatarStorage = new AvatarFileStorage(this);
62 63
	// Connect the avatar changed signal of the avatarStorage with the NOTIFY signal
	// of the Q_PROPERTY for the avatar storage (so all avatars are updated in QML)
64 65
	connect(avatarStorage, &AvatarFileStorage::avatarIdsChanged,
	        this, &Kaidan::avatarStorageChanged);
66

67
	//
68
	// Load settings data
69 70
	//

71 72
	// init settings (-> "kaidan/kaidan.conf")
	settings = new QSettings(QString(APPLICATION_NAME), QString(APPLICATION_NAME));
73

74 75
	creds.jid = settings->value("auth/jid").toString();
	creds.jidResource = settings->value("auth/resource").toString();
76
	creds.password = QString(QByteArray::fromBase64(settings->value("auth/password").toString().toUtf8()));
77
	// use Kaidan as resource, if no set
78
	if (creds.jidResource == "")
79
		setJidResource(QString(APPLICATION_NAME));
80 81 82 83

	creds.isFirstTry = false;

	// create new client and start thread's main loop (won't connect until requested)
84 85
	client = new ClientThread(rosterModel, messageModel, avatarStorage, creds,
	                          settings, app);
86
	client->start();
Linus Jahn's avatar
Linus Jahn committed
87

88 89 90 91 92 93 94 95
	connect(client, &ClientThread::connectionStateChanged, [=](ConnectionState state) {
		emit this->connectionStateChanged((quint8) state);
	});
	connect(client, &ClientThread::disconnReasonChanged, [=](DisconnReason reason) {
		emit this->disconnReasonChanged((quint8) reason);
	});
	connect(client, &ClientThread::newCredentialsNeeded, this, &Kaidan::newCredentialsNeeded);
	connect(client, &ClientThread::logInWorked, this, &Kaidan::logInWorked);
Linus Jahn's avatar
Linus Jahn committed
96
	connect(this, &Kaidan::chatPartnerChanged, client, &ClientThread::chatPartnerChanged);
Marzanna's avatar
Marzanna committed
97 98 99 100
}

Kaidan::~Kaidan()
{
101
	delete client;
102 103 104
	delete rosterModel;
	delete messageModel;
	delete database;
105
	delete avatarStorage;
106
	delete settings;
Marzanna's avatar
Marzanna committed
107 108
}

109
void Kaidan::start()
110
{
111 112 113 114
	if (creds.jid.isEmpty() || creds.password.isEmpty())
		emit newCredentialsNeeded();
	else
		mainConnect();
Georg's avatar
Georg committed
115 116
}

117
bool Kaidan::mainConnect()
Marzanna's avatar
Marzanna committed
118
{
119 120 121 122 123
	if (client->isConnected()) {
		qWarning() << "[main] Tried to connect, even if still connected!"
		           << "Requesting disconnect.";
		emit client->disconnectRequested();
		return false;
Marzanna's avatar
Marzanna committed
124
	}
Georg's avatar
Georg committed
125

126 127 128
	// TODO: check if jid is valid first
	client->setCredentials(creds);
	emit client->connectRequested();
129 130 131
	return true;
}

132
void Kaidan::mainDisconnect(bool openLogInPage)
133
{
134 135 136
	// disconnect the client if connected or connecting
	if (client->isConnected())
		emit client->disconnectRequested();
137

138 139 140
	// trigger the gui to open the log in page in case the was wanted:
	if (openLogInPage)
		emit newCredentialsNeeded();
Linus Jahn's avatar
Linus Jahn committed
141 142
}

143
void Kaidan::setJid(QString jid)
Linus Jahn's avatar
Linus Jahn committed
144
{
145 146 147
	creds.jid = jid;
	// credentials were modified -> first try
	creds.isFirstTry = true;
Linus Jahn's avatar
Linus Jahn committed
148 149
}

150
void Kaidan::setJidResource(QString jidResource)
151
{
152 153 154 155
	// JID resource won't influence the authentication, so we don't need
	// to set the first try flag and can save it.
	creds.jidResource = jidResource;
	settings->setValue("auth/resource", jidResource);
156 157
}

158
void Kaidan::setPassword(QString password)
Linus Jahn's avatar
Linus Jahn committed
159
{
160 161 162
	creds.password = password;
	// credentials were modified -> first try
	creds.isFirstTry = true;
Linus Jahn's avatar
Linus Jahn committed
163 164 165 166 167 168 169 170 171
}

void Kaidan::setChatPartner(QString chatPartner)
{
	// check if different
	if (this->chatPartner == chatPartner)
		return;

	this->chatPartner = chatPartner;
Linus Jahn's avatar
Linus Jahn committed
172 173
	emit chatPartnerChanged(chatPartner); // -> connected to client
	messageModel->applyRecipientFilter(chatPartner);
Linus Jahn's avatar
Linus Jahn committed
174 175
}

176 177 178 179 180 181 182 183 184 185 186
quint8 Kaidan::getConnectionState() const
{
	return (quint8) client->getConnectionState();
}

quint8 Kaidan::getDisconnReason() const
{
	// gloox::ConnectionError -> (Kaidan) Enums::DisconnReason
	return (quint8) client->getConnectionError();
}

Linus Jahn's avatar
Linus Jahn committed
187 188
void Kaidan::sendMessage(QString jid, QString message)
{
189
	if (client->isConnected()) {
190
		emit client->sendMessageRequested(jid, message);
191 192 193 194
	} else {
		emit passiveNotificationRequested(tr("Could not send message, because not being connected."));
		qWarning() << "[main] Could not send message, because not being connected.";
	}
195 196 197 198
}

void Kaidan::addContact(QString jid, QString nick)
{
199
	if (client->isConnected()) {
200
		emit client->addContactRequested(jid, nick);
201 202 203 204
	} else {
		emit passiveNotificationRequested(tr("Could not add contact, because not being connected."));
		qWarning() << "[main] Could not add contact, because not being connected.";
	}
205 206 207 208
}

void Kaidan::removeContact(QString jid)
{
209
	if (client->isConnected()) {
210
		emit client->removeContactRequested(jid);
211 212 213 214
	} else {
		emit passiveNotificationRequested(tr("Could not remove contact, because not being connected."));
		qWarning() << "[main] Could not remove contact, because not being connected.";
	}
Linus Jahn's avatar
Linus Jahn committed
215 216
}

217
QString Kaidan::getResourcePath(QString name) const
218
{
219 220 221 222
	// list of file paths where to search for the resource file
	QStringList pathList;
	// add relative path from binary (only works if installed)
	pathList << QCoreApplication::applicationDirPath() + QString("/../share/") + QString(APPLICATION_NAME);
223
	// get the standard app data locations for current platform
224
	pathList << QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
225
#ifndef NDEBUG
Ilya Bizyaev's avatar
Ilya Bizyaev committed
226
#ifdef DEBUG_SOURCE_PATH
227
	// add source directory (only for debug builds)
228
	pathList << QString(DEBUG_SOURCE_PATH) + QString("/data");
Ilya Bizyaev's avatar
Ilya Bizyaev committed
229
#endif
230
#endif
231 232

	// search for file in directories
233
	for (int i = 0; i < pathList.size(); i++) {
234 235 236
		// open directory
		QDir directory(pathList.at(i));
		// look up the file
237
		if (directory.exists(name)) {
238
			// found the file, return the path
239
			return QString("file://") + directory.absoluteFilePath(name);
240 241
		}
	}
242

Ilya Bizyaev's avatar
Ilya Bizyaev committed
243
	// on Android, we want to fetch images from the application resources
244 245
	if (QFile::exists(":/" + name))
		return QString("qrc:/" + name);
246 247

	// no file found
248
	qWarning() << "[main] Could NOT find media file:" << name;
249 250
	return QString("");
}