1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #include "mumble_pch.hpp"
7 
8 #include "Global.h"
9 
10 Global *Global::g_global_struct;
11 
12 #ifndef Q_OS_WIN
migrateDataDir()13 static void migrateDataDir() {
14 #ifdef Q_OS_MAC
15 	QString olddir = QDir::homePath() + QLatin1String("/Library/Preferences/Mumble");
16 #if QT_VERSION >= 0x050000
17 	QString newdir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
18 #else
19 	QString newdir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
20 #endif // QT_VERSION
21 	QString linksTo = QFile::readLink(olddir);
22 	if (!QFile::exists(newdir) && QFile::exists(olddir) && linksTo.isEmpty()) {
23 		QDir d;
24 		d.mkpath(newdir + QLatin1String("/.."));
25 		if (d.rename(olddir, newdir)) {
26 			if (d.cd(QDir::homePath() + QLatin1String("/Library/Preferences"))) {
27 				if (QFile::link(d.relativeFilePath(newdir), olddir)) {
28 					qWarning("Migrated application data directory from '%s' to '%s'",
29 					         qPrintable(olddir), qPrintable(newdir));
30 					return;
31 				}
32 			}
33 		}
34 	} else {
35 		/* Data dir has already been migrated. */
36 		return;
37 	}
38 
39 	qWarning("Application data migration failed.");
40 #endif // Q_OS_MAC
41 
42 // Qt4 used another data directory on Unix-like systems, to ensure a seamless
43 // transition we must first move the users data to the new directory.
44 #if defined(Q_OS_UNIX) && ! defined(Q_OS_MAC)
45 #if QT_VERSION >= 0x050000
46 	QString olddir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/data/Mumble");
47 	QString newdir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/Mumble");
48 
49 	if (!QFile::exists(newdir) && QFile::exists(olddir)) {
50 		QDir d;
51 		if (d.rename(olddir, newdir)) {
52 			qWarning("Migrated application data directory from '%s' to '%s'",
53 			         qPrintable(olddir), qPrintable(newdir));
54 			return;
55 		}
56 	} else {
57 		/* Data dir has already been migrated. */
58 		return;
59 	}
60 
61 	qWarning("Application data migration failed.");
62 #endif // QT_VERSION
63 #endif // defined(Q_OS_UNIX) && ! defined(Q_OS_MAC)
64 }
65 #endif // Q_OS_WIN
66 
Global()67 Global::Global() {
68 	mw = 0;
69 	db = 0;
70 	p = 0;
71 	nam = 0;
72 	c = 0;
73 	uiSession = 0;
74 	uiDoublePush = 1000000;
75 	iPushToTalk = 0;
76 	iTarget = 0;
77 	iPrevTarget = 0;
78 	bPushToMute = false;
79 	bCenterPosition = false;
80 	bPosTest = false;
81 	bInAudioWizard = false;
82 	iAudioPathTime = 0;
83 	iAudioBandwidth = -1;
84 	iMaxBandwidth = -1;
85 
86 	iCodecAlpha = 0;
87 	iCodecBeta = 0;
88 	bPreferAlpha = true;
89 #ifdef USE_OPUS
90 	bOpus = true;
91 #else
92 	bOpus = false;
93 #endif
94 
95 	bAttenuateOthers = false;
96 	prioritySpeakerActiveOverride = false;
97 
98 	bAllowHTML = true;
99 	uiMessageLength = 5000;
100 	uiImageLength = 131072;
101 	uiMaxUsers = 0;
102 
103 	qs = NULL;
104 
105 	ocIntercept = NULL;
106 	bc = NULL;
107 	lcd = NULL;
108 	o = NULL;
109 	l = NULL;
110 
111 	bHappyEaster = false;
112 
113 	bQuit = false;
114 
115 	QStringList qsl;
116 	qsl << QCoreApplication::instance()->applicationDirPath();
117 #if QT_VERSION >= 0x050000
118 	qsl << QStandardPaths::writableLocation(QStandardPaths::DataLocation);
119 #else
120 	qsl << QDesktopServices::storageLocation(QDesktopServices::DataLocation);
121 #endif
122 #if defined(Q_OS_WIN)
123 	QString appdata;
124 	wchar_t appData[MAX_PATH];
125 	if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appData))) {
126 		appdata = QDir::fromNativeSeparators(QString::fromWCharArray(appData));
127 
128 		if (!appdata.isEmpty()) {
129 			appdata.append(QLatin1String("/Mumble"));
130 			qsl << appdata;
131 		}
132 	}
133 #endif
134 
135 	foreach(const QString &dir, qsl) {
136 		QFile inifile(QString::fromLatin1("%1/mumble.ini").arg(dir));
137 		if (inifile.exists() && inifile.permissions().testFlag(QFile::WriteUser)) {
138 			qdBasePath = dir;
139 			qs = new QSettings(inifile.fileName(), QSettings::IniFormat);
140 			break;
141 		}
142 	}
143 
144 	if (!qs) {
145 		qs = new QSettings();
146 #if defined(Q_OS_WIN)
147 		if (! appdata.isEmpty())
148 			qdBasePath.setPath(appdata);
149 #else
150 		migrateDataDir();
151 #if QT_VERSION >= 0x050000
152 		qdBasePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
153 #else
154 		qdBasePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
155 #endif
156 #endif
157 		if (! qdBasePath.exists()) {
158 			QDir::root().mkpath(qdBasePath.absolutePath());
159 			if (! qdBasePath.exists())
160 				qdBasePath = QDir::home();
161 		}
162 	}
163 
164 	if (! qdBasePath.exists(QLatin1String("Plugins")))
165 		qdBasePath.mkpath(QLatin1String("Plugins"));
166 	if (! qdBasePath.exists(QLatin1String("Overlay")))
167 		qdBasePath.mkpath(QLatin1String("Overlay"));
168 	if (! qdBasePath.exists(QLatin1String("Themes")))
169 		qdBasePath.mkpath(QLatin1String("Themes"));
170 
171 	qs->setIniCodec("UTF-8");
172 }
173 
~Global()174 Global::~Global() {
175 	delete qs;
176 }
177 
178 const char Global::ccHappyEaster[] = {072, 057, 0162, 0145, 0143, 056, 0163, 0166, 0147, 0, 0117, 0160, 0145, 0156, 040, 0164, 0150, 0145, 040, 0160, 0157, 0144, 040, 0142, 0141, 0171, 040, 0144, 0157, 0157, 0162, 0163, 054, 040, 0110, 0101, 0114, 056, 0, 0111, 047, 0155, 040, 0163, 0157, 0162, 0162, 0171, 054, 040, 045, 061, 056, 040, 0111, 047, 0155, 040, 0141, 0146, 0162, 0141, 0151, 0144, 040, 0111, 040, 0143, 0141, 0156, 047, 0164, 040, 0144, 0157, 040, 0164, 0150, 0141, 0164, 056, 0, 0121,0127,0151,0144,0147,0145,0164,0173,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0143,0157,0154,0157,0162,072,0142,0154,0141,0143,0153,073,0141,0154,0164,0145,0162,0156,0141,0164,0145,055,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0143,0157,0154,0157,0162,072,043,063,063,060,060,060,060,073,0143,0157,0154,0157,0162,072,0167,0150,0151,0164,0145,073,0175,0121,0124,0145,0170,0164,0102,0162,0157,0167,0163,0145,0162,0173,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0151,0155,0141,0147,0145,072,0165,0162,0154,050,072,057,0162,0145,0143,056,0163,0166,0147,051,073,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0160,0157,0163,0151,0164,0151,0157,0156,072,0143,0145,0156,0164,0145,0162,0143,0145,0156,0164,0145,0162,073,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0143,0154,0151,0160,072,0160,0141,0144,0144,0151,0156,0147,073,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0157,0162,0151,0147,0151,0156,072,0160,0141,0144,0144,0151,0156,0147,073,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0162,0145,0160,0145,0141,0164,072,0156,0157,055,0162,0145,0160,0145,0141,0164,073,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,055,0141,0164,0164,0141,0143,0150,0155,0145,0156,0164,072,0146,0151,0170,0145,0144,073,0175,0121,0115,0145,0156,0165,0102,0141,0162,072,072,0151,0164,0145,0155,0173,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,072,0164,0162,0141,0156,0163,0160,0141,0162,0145,0156,0164,073,0175,0121,0110,0145,0141,0144,0145,0162,0126,0151,0145,0167,072,072,0163,0145,0143,0164,0151,0157,0156,0173,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,072,0164,0162,0141,0156,0163,0160,0141,0162,0145,0156,0164,073,0175,0121,0124,0141,0142,0102,0141,0162,072,072,0164,0141,0142,0173,0142,0141,0143,0153,0147,0162,0157,0165,0156,0144,072,0164,0162,0141,0156,0163,0160,0141,0162,0145,0156,0164,073,0175,0};
179 
180 QMultiMap<int, DeferInit *> *DeferInit::qmDeferers = NULL;
181 
add(int priority)182 void DeferInit::add(int priority) {
183 	if (qmDeferers == NULL) {
184 		qmDeferers = new QMultiMap<int, DeferInit *>();
185 	}
186 	qmDeferers->insert(priority, this);
187 }
188 
~DeferInit()189 DeferInit::~DeferInit() {
190 }
191 
run_initializers()192 void DeferInit::run_initializers() {
193 	if (! qmDeferers)
194 		return;
195 	foreach(DeferInit *d, *qmDeferers) {
196 		d->initialize();
197 	}
198 }
199 
run_destroyers()200 void DeferInit::run_destroyers() {
201 	if (! qmDeferers)
202 		return;
203 	foreach(DeferInit *d, *qmDeferers) {
204 		d->destroy();
205 	}
206 	delete qmDeferers;
207 	qmDeferers = NULL;
208 }
209