1 // This file is part of Qt Bitcoin Trader
2 // https://github.com/JulyIGHOR/QtBitcoinTrader
3 // Copyright (C) 2013-2021 July Ighor <julyighor@gmail.com>
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // In addition, as a special exception, the copyright holders give
11 // permission to link the code of portions of this program with the
12 // OpenSSL library under certain conditions as described in each
13 // individual source file, and distribute linked combinations including
14 // the two.
15 //
16 // You must obey the GNU General Public License in all respects for all
17 // of the code used other than OpenSSL. If you modify file(s) with this
18 // exception, you may extend this exception to your version of the
19 // file(s), but you are not obligated to do so. If you do not wish to do
20 // so, delete this exception statement from your version. If you delete
21 // this exception statement from all source files in the program, then
22 // also delete it here.
23 //
24 // This program is distributed in the hope that it will be useful,
25 // but WITHOUT ANY WARRANTY; without even the implied warranty of
26 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 // GNU General Public License for more details.
28 //
29 // You should have received a copy of the GNU General Public License
30 // along with this program. If not, see <http://www.gnu.org/licenses/>.
31
32 #include "main.h"
33 #include "config/config_manager.h"
34 #include "datafolderchusedialog.h"
35 #include "exchange/exchange.h"
36 #include "iniengine.h"
37 #include "julyaes256.h"
38 #include "julylockfile.h"
39 #include "login/allexchangesdialog.h"
40 #include "login/featuredexchangesdialog.h"
41 #include "login/newpassworddialog.h"
42 #include "login/passworddialog.h"
43 #include "login/qttraderinform.h"
44 #include "qsystemdetection.h"
45 #include "timesync.h"
46 #include "translationdialog.h"
47 #include "updaterdialog.h"
48 #include "utils/utils.h"
49 #include <QApplication>
50 #include <QDesktopServices>
51 #include <QDir>
52 #include <QFileInfo>
53 #include <QLibraryInfo>
54 #include <QLoggingCategory>
55 #include <QMessageBox>
56 #include <QMetaEnum>
57 #include <QNetworkProxy>
58 #include <QNetworkProxyFactory>
59 #include <QProcess>
60 #include <QSettings>
61 #include <QStandardPaths>
62 #include <QStyle>
63 #include <QStyleFactory>
64 #include <QThread>
65 #include <QTranslator>
66 #include <QUrl>
67 #include <QUuid>
68
69 #ifdef Q_OS_WIN
70 #include <windows.h>
71 #endif
72
73 #ifdef Q_OS_UNIX
74 #include <initializer_list>
75 #include <signal.h>
quitOnSignals(std::initializer_list<int> quitSignals)76 void quitOnSignals(std::initializer_list<int> quitSignals)
77 {
78 auto handler = [](int sig) -> void
79 {
80 qDebug().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") << "Shutdown signal received" << sig;
81 QCoreApplication::quit();
82 };
83
84 sigset_t blocking_mask;
85 sigemptyset(&blocking_mask);
86
87 for (auto sig : quitSignals)
88 sigaddset(&blocking_mask, sig);
89
90 struct sigaction sa;
91 sa.sa_handler = handler;
92 sa.sa_mask = blocking_mask;
93 sa.sa_flags = 0;
94
95 for (auto sig : quitSignals)
96 sigaction(sig, &sa, nullptr);
97 }
98 #endif
99
100 BaseValues* baseValues_;
101
BaseValues()102 BaseValues::BaseValues()
103 {
104 forceDotInSpinBoxes = true;
105 scriptsThatUseOrderBookCount = 0;
106 trafficSpeed = 0;
107 trafficTotal = 0;
108 trafficTotalType = 0;
109 feeDecimals = 2;
110 currentExchange_ = nullptr;
111 currentTheme = 0;
112 gzipEnabled = true;
113 appVerIsBeta = false;
114 jlScriptVersion = 1.0;
115 appVerStr = "1.4055";
116 appVerReal = appVerStr.toDouble();
117
118 if (appVerStr.size() > 4)
119 {
120 if (appVerStr.size() == 7)
121 appVerStr.remove(6, 1);
122
123 appVerStr.insert(4, ".");
124 }
125
126 appVerLastReal = appVerReal;
127
128 logThread_ = nullptr;
129
130 highResolutionDisplay = true;
131 timeFormat = QLocale().timeFormat(QLocale::LongFormat).replace(" ", "").replace("t", "");
132 dateTimeFormat = QLocale().dateFormat(QLocale::ShortFormat) + " " + timeFormat;
133 depthCountLimit = 100;
134 depthCountLimitStr = "100";
135 uiUpdateInterval = 100;
136 supportsUtfUI = true;
137 debugLevel_ = 0;
138
139 #ifdef Q_WS_WIN
140
141 if (QSysInfo::windowsVersion() <= QSysInfo::WV_XP)
142 supportsUtfUI = false;
143
144 #endif
145
146 upArrow = QByteArray::fromBase64("4oaR");
147 downArrow = QByteArray::fromBase64("4oaT");
148
149 if (supportsUtfUI)
150 {
151 upArrowNoUtf8 = upArrow;
152 downArrowNoUtf8 = downArrow;
153 }
154 else
155 {
156 upArrowNoUtf8 = ">";
157 downArrowNoUtf8 = "<";
158 }
159
160 httpRequestInterval = 400;
161 minimumRequestInterval = 400;
162 httpRequestTimeout = 5000;
163 minimumRequestTimeout = 5000;
164 httpRetryCount = 5;
165 apiDownCount = 0;
166 groupPriceValue = 0.0;
167 defaultHeightForRow_ = 22;
168
169 tempLocation = QStandardPaths::standardLocations(QStandardPaths::TempLocation).first().replace('\\', '/') + "/";
170 desktopLocation = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first().replace('\\', '/') + "/";
171 logFileName = QLatin1String("QtBitcoinTrader.log");
172 iniFileName = QLatin1String("QtBitcoinTrader.ini");
173
174 selectSystemLanguage();
175 }
176
selectSystemLanguage()177 void BaseValues::selectSystemLanguage()
178 {
179 QString sysLocale = QLocale().name().toLower();
180
181 if (sysLocale.startsWith("de"))
182 defaultLangFile = ":/Resources/Language/German.lng";
183 else if (sysLocale.startsWith("fr"))
184 defaultLangFile = ":/Resources/Language/French.lng";
185 else if (sysLocale.startsWith("zh"))
186 defaultLangFile = ":/Resources/Language/Chinese.lng";
187 else if (sysLocale.startsWith("ru"))
188 defaultLangFile = ":/Resources/Language/Russian.lng";
189 else if (sysLocale.startsWith("uk"))
190 defaultLangFile = ":/Resources/Language/Ukrainian.lng";
191 else if (sysLocale.startsWith("pl"))
192 defaultLangFile = ":/Resources/Language/Polish.lng";
193 else if (sysLocale.startsWith("nl"))
194 defaultLangFile = ":/Resources/Language/Dutch.lng";
195 else if (sysLocale.startsWith("es"))
196 defaultLangFile = ":/Resources/Language/Spanish.lng";
197 else if (sysLocale.startsWith("nb"))
198 defaultLangFile = ":/Resources/Language/Norwegian.lng";
199 else if (sysLocale.startsWith("bg"))
200 defaultLangFile = ":/Resources/Language/Bulgarian.lng";
201 else if (sysLocale.startsWith("cs"))
202 defaultLangFile = ":/Resources/Language/Czech.lng";
203 else if (sysLocale.startsWith("tr"))
204 defaultLangFile = ":/Resources/Language/Turkish.lng";
205 else if (sysLocale.startsWith("it"))
206 defaultLangFile = ":/Resources/Language/Italiano.lng";
207 else
208 defaultLangFile = ":/Resources/Language/English.lng";
209 }
210
initHiDpi()211 void BaseValues::initHiDpi()
212 {
213 #ifdef Q_OS_LINUX
214 defaultEnableHiDPI = false;
215 #else
216 defaultEnableHiDPI = true;
217 #endif
218
219 QSettings hiDpiSettings("Centrabit", "Qt Bitcoin Trader");
220
221 if (hiDpiSettings.value("HiDPI", defaultEnableHiDPI).toBool())
222 {
223 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
224 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
225 }
226 else
227 QApplication::setAttribute(Qt::AA_Use96Dpi);
228 }
229
initAppDataDir(QApplication & a)230 bool BaseValues::initAppDataDir(QApplication& a)
231 {
232 bool portableModeSupported(false);
233 #ifdef Q_OS_MAC
234
235 if (!a.applicationDirPath().startsWith("/Applications/"))
236 portableModeSupported = true;
237
238 #endif
239 #ifdef Q_OS_WIN
240 portableModeSupported = true;
241 #endif
242 #ifdef QTBUILDTARGETLINUX64
243 portableModeSupported = true;
244 #endif
245 QString systemAppDataDir(QStandardPaths::standardLocations(QStandardPaths::DataLocation).first());
246 #ifdef Q_OS_WIN
247 systemAppDataDir.replace('\\', '/');
248 #endif
249
250 if (portableModeSupported)
251 {
252 QString portableAppDataDir(a.applicationDirPath() + QLatin1String("/QtBitcoinTrader.data"));
253 #ifdef Q_OS_WIN
254
255 if (QFile::exists(a.applicationDirPath() + QLatin1String("/QtBitcoinTrader")) &&
256 QFileInfo(a.applicationDirPath() + QLatin1String("/QtBitcoinTrader")).isDir())
257 QFile::rename(a.applicationDirPath() + QLatin1String("/QtBitcoinTrader"), portableAppDataDir);
258
259 #endif
260 appDataDir = systemAppDataDir;
261
262 if (!QFile::exists(portableAppDataDir) && !QFile::exists(appDataDir))
263 {
264 julyTranslator.loadFromFile(defaultLangFile);
265 DataFolderChuseDialog chuseStorageLocation(appDataDir, portableAppDataDir);
266
267 if (chuseStorageLocation.exec() == QDialog::Rejected)
268 return false;
269
270 if (chuseStorageLocation.isPortable)
271 QDir().mkdir(portableAppDataDir);
272 else
273 {
274 QDir().mkdir(systemAppDataDir);
275 QString installedBin = systemAppDataDir + "/QtBitcoinTrader";
276 const QString desktopLocation(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
277 #ifdef Q_OS_WIN
278 installedBin.append(".exe");
279 #else
280 installedBin.append(".bin");
281 #endif
282
283 QFile::Permissions selfPerms = QFile(a.applicationFilePath()).permissions();
284
285 if (a.applicationFilePath().startsWith(desktopLocation))
286 QFile::rename(a.applicationFilePath(), installedBin);
287 else
288 QFile::copy(a.applicationFilePath(), installedBin);
289
290 if (QFile::exists(installedBin))
291 {
292 QFile(installedBin).setPermissions(selfPerms);
293 #ifdef Q_OS_WIN
294 {
295 QString desktopFile(desktopLocation + "/Qt Bitcoin Trader.lnk");
296 QFile::link(installedBin, desktopFile);
297 QProcess proc;
298 proc.startDetached(installedBin, QStringList() << "/installed");
299 proc.waitForStarted(3000);
300 return false;
301 }
302 #endif
303 #ifdef Q_OS_LINUX
304 {
305 QString desktopFile(desktopLocation + "/Qt Bitcoin Trader.desktop");
306 QString desktopIconFile(systemAppDataDir + "/QtBitcoinTrader.png");
307 {
308 QByteArray iconData;
309 QFile rF(":/Resources/QtBitcoinTrader.png");
310 rF.open(QFile::ReadOnly);
311 QFile wF(desktopIconFile);
312
313 if (wF.open(QFile::WriteOnly))
314 {
315 wF.write(rF.readAll());
316 wF.close();
317 }
318
319 rF.close();
320 }
321 {
322 QFile wF(desktopFile);
323
324 if (wF.open(QFile::WriteOnly))
325 {
326 wF.write("[Desktop Entry]\n"
327 "Encoding=UTF-8\n"
328 "Name=Qt Bitcoin Trader\n"
329 "GenericName=Secure Multi Trading Client\n"
330 "Exec=\"" +
331 installedBin.toUtf8() +
332 "\"\n"
333 "Icon=" +
334 desktopIconFile.toUtf8() +
335 "\n"
336 "Terminal=false\n"
337 "Type=Application\n"
338 "Categories=Qt;Office;Finance;\n");
339 wF.close();
340 }
341 }
342 QProcess proc;
343 proc.startDetached(installedBin, QStringList() << "/installed");
344 proc.waitForStarted(3000);
345 return false;
346 }
347 #endif
348 }
349 }
350 }
351
352 if (QFile::exists(portableAppDataDir))
353 {
354 portableMode = true;
355 appDataDir = portableAppDataDir;
356 }
357
358 if (!QFile::exists(appDataDir + "/Language"))
359 QDir().mkpath(appDataDir + "/Language");
360
361 if (!QFile::exists(appDataDir))
362 {
363 QMessageBox::warning(
364 nullptr, "Qt Bitcoin Trader", julyTr("CAN_NOT_WRITE_TO_FOLDER", "Can not write to folder") + ": \"" + appDataDir + "\"");
365 return false;
366 }
367 }
368 else
369 {
370 appDataDir = systemAppDataDir;
371 QString oldAppDataDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first() + "/.config/QtBitcoinTrader";
372
373 if (!QFile::exists(appDataDir) && oldAppDataDir != appDataDir && QFile::exists(oldAppDataDir))
374 {
375 QFile::rename(oldAppDataDir, appDataDir);
376
377 if (QFile::exists(oldAppDataDir))
378 {
379 if (!QFile::exists(appDataDir))
380 QDir().mkpath(appDataDir);
381
382 QStringList fileList = QDir(oldAppDataDir).entryList();
383
384 for (int n = 0; n < fileList.size(); n++)
385 if (fileList.at(n).length() > 2)
386 {
387 QFile::copy(oldAppDataDir + fileList.at(n), appDataDir + fileList.at(n));
388
389 if (QFile::exists(oldAppDataDir + fileList.at(n)))
390 QFile::remove(oldAppDataDir + fileList.at(n));
391 }
392 }
393 }
394
395 if (!QFile::exists(appDataDir))
396 QDir().mkpath(appDataDir);
397
398 if (!QFile::exists(appDataDir))
399 {
400 QMessageBox::warning(
401 nullptr, "Qt Bitcoin Trader", julyTr("CAN_NOT_WRITE_TO_FOLDER", "Can not write to folder") + ": \"" + appDataDir + "\"");
402 return false;
403 }
404 }
405
406 return true;
407 }
408
initValues(QApplication & a)409 void BaseValues::initValues(QApplication& a)
410 {
411 qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
412 qRegisterMetaType<QList<QSslError>>("QList<QSslError>");
413
414 QThread::currentThread()->setObjectName("Main Thread");
415
416 a.setWindowIcon(QIcon(":/Resources/QtBitcoinTrader.png"));
417 a.setApplicationVersion(appVerStr);
418
419 QTranslator qTranslator;
420 qTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
421 a.installTranslator(&qTranslator);
422
423 #ifdef Q_OS_WIN // DPI Fix
424 QFont font = a.font();
425 font.setPixelSize(11);
426 a.setFont(font);
427 #endif
428
429 fontMetrics_ = new QFontMetrics(a.font());
430 scriptFolder = appDataDir + "/Scripts/";
431
432 if (QFile::exists(a.applicationFilePath() + ".upd"))
433 QFile::remove(a.applicationFilePath() + ".upd");
434
435 if (QFile::exists(a.applicationFilePath() + ".bkp"))
436 QFile::remove(a.applicationFilePath() + ".bkp");
437 }
438
initThemes(QApplication & a)439 void BaseValues::initThemes(QApplication& a)
440 {
441 a.setStyle(QStyleFactory::create("Fusion"));
442
443 if (QFile::exists(appDataDir + "/Themes"))
444 {
445 themeFolder = appDataDir + "/Themes";
446
447 if (!QFile::exists(themeFolder + "/Dark.thm"))
448 QFile::copy("://Resources/Themes/Dark.thm", themeFolder + "/Dark.thm");
449
450 if (!QFile::exists(themeFolder + "/Light.thm"))
451 QFile::copy("://Resources/Themes/Light.thm", themeFolder + "/Light.thm");
452
453 if (!QFile::exists(themeFolder + "/Gray.thm"))
454 QFile::copy("://Resources/Themes/Gray.thm", themeFolder + "/Gray.thm");
455 }
456 else
457 themeFolder = "://Resources/Themes";
458
459 appThemeLight.palette = a.palette();
460 appThemeDark.palette = a.palette();
461 appThemeGray.palette = a.palette();
462
463 appThemeLight.loadTheme("Light");
464 appThemeDark.loadTheme("Dark");
465 appThemeGray.loadTheme("Gray");
466 appTheme = appThemeLight;
467
468 osStyle = a.style()->objectName();
469
470 a.setPalette(appTheme.palette);
471 a.setStyleSheet(appTheme.styleSheet);
472 }
473
initSettings()474 void BaseValues::initSettings()
475 {
476 QSettings settingsMain(appDataDir + "/QtBitcoinTrader.cfg", QSettings::IniFormat);
477
478 settingsMain.beginGroup("Proxy");
479 bool proxyEnabled = settingsMain.value("Enabled", true).toBool();
480 bool proxyAuto = settingsMain.value("Auto", true).toBool();
481 QString proxyHost = settingsMain.value("Host", "127.0.0.1").toString();
482 quint16 proxyPort = static_cast<quint16>(settingsMain.value("Port", 1234).toUInt());
483 QString proxyUser = settingsMain.value("User", "username").toString();
484 QString proxyPassword = settingsMain.value("Password", "password").toString();
485 QNetworkProxy::ProxyType proxyType;
486
487 if (settingsMain.value("Type", "HttpProxy").toString() == "Socks5Proxy")
488 proxyType = QNetworkProxy::Socks5Proxy;
489 else
490 proxyType = QNetworkProxy::HttpProxy;
491
492 settingsMain.setValue("Enabled", proxyEnabled);
493 settingsMain.setValue("Auto", proxyAuto);
494 settingsMain.setValue("Host", proxyHost);
495 settingsMain.setValue("Port", proxyPort);
496 settingsMain.setValue("User", proxyUser);
497 settingsMain.setValue("Password", proxyPassword);
498 settingsMain.endGroup();
499
500 QNetworkProxy proxy;
501
502 if (proxyEnabled)
503 {
504 if (proxyAuto)
505 {
506 QList<QNetworkProxy> proxyList = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(QUrl("https://")));
507
508 if (!proxyList.empty())
509 proxy = proxyList.first();
510 }
511 else
512 {
513 proxy.setHostName(proxyHost);
514 proxy.setUser(proxyUser);
515 proxy.setPort(proxyPort);
516 proxy.setPassword(proxyPassword);
517 proxy.setType(proxyType);
518 }
519
520 QNetworkProxy::setApplicationProxy(proxy);
521 }
522
523 appVerLastReal = settingsMain.value("Version", 1.0).toDouble();
524
525 if (!qFuzzyCompare(appVerLastReal + 1.0, appVerReal + 1.0))
526 {
527 settingsMain.setValue("Version", appVerReal);
528 QStringList cacheFiles = QDir(appDataDir + "/cache").entryList(QStringList("*.cache"), QDir::Files);
529
530 for (int i = 0; i < cacheFiles.size(); ++i)
531 QFile(appDataDir + "/cache/" + cacheFiles.at(i)).remove();
532
533 if (qFuzzyIsNull(appVerLastReal))
534 appVerLastReal = appVerReal;
535 }
536
537 appVerIsBeta = settingsMain.value("CheckForUpdatesBeta", false).toBool();
538 use24HourTimeFormat = settingsMain.value("Use24HourTimeFormat", true).toBool();
539
540 settingsMain.beginGroup("Decimals");
541 decimalsAmountMyTransactions = settingsMain.value("AmountMyTransactions", 8).toInt();
542 decimalsPriceMyTransactions = settingsMain.value("PriceMyTransactions", 8).toInt();
543 decimalsTotalMyTransactions = settingsMain.value("TotalMyTransactions", 8).toInt();
544 decimalsAmountOrderBook = settingsMain.value("AmountOrderBook", 8).toInt();
545 decimalsPriceOrderBook = settingsMain.value("PriceOrderBook", 8).toInt();
546 decimalsTotalOrderBook = settingsMain.value("TotalOrderBook", 8).toInt();
547 decimalsAmountLastTrades = settingsMain.value("AmountLastTrades", 8).toInt();
548 decimalsPriceLastTrades = settingsMain.value("PriceLastTrades", 8).toInt();
549 decimalsTotalLastTrades = settingsMain.value("TotalLastTrades", 8).toInt();
550 settingsMain.endGroup();
551
552 {
553 if (!QFile::exists(appDataDir + "/Language"))
554 QDir().mkpath(appDataDir + "/Language");
555
556 QString langFile = settingsMain.value("LanguageFile", "").toString();
557
558 if (langFile.isEmpty() || !QFile::exists(langFile))
559 langFile = defaultLangFile;
560
561 julyTranslator.loadFromFile(langFile);
562 }
563 }
564
main(int argc,char * argv[])565 int main(int argc, char* argv[])
566 {
567 if (QSslSocket::sslLibraryVersionString().isEmpty())
568 {
569 QMessageBox::critical(nullptr, "Qt Bitcoin Trader", julyTr("CANT_LOAD_OPENSSL", "Can't load OpenSSL libraries"));
570 return 0;
571 }
572
573 QScopedPointer<JulyLockFile> julyLock(nullptr);
574 QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
575 baseValues_ = new BaseValues();
576 baseValues.initHiDpi();
577 QApplication a(argc, argv);
578
579 if (argc > 1)
580 {
581 #ifdef Q_OS_LINUX
582
583 if (a.arguments().contains("/test"))
584 {
585 qDebug().noquote() << "(-: OK :-)";
586 return 0;
587 }
588
589 #endif
590
591 if (a.arguments().contains("/uninstall"))
592 {
593 QThread::msleep(2000);
594 #ifndef Q_OS_MAC
595 QString tmpDir = QStandardPaths::standardLocations(QStandardPaths::TempLocation).first();
596
597 if (!a.applicationFilePath().startsWith(tmpDir))
598 return 0;
599
600 #ifdef Q_OS_WIN
601 QString desktopShortcut = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first() + "/Qt Bitcoin Trader.lnk";
602
603 if (QFile::exists(desktopShortcut))
604 DeleteFile(reinterpret_cast<LPCWSTR>(desktopShortcut.replace('/', '\\').utf16()));
605
606 #else
607 QString desktopShortcut =
608 QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first() + "/Qt Bitcoin Trader.desktop";
609
610 if (!desktopShortcut.isEmpty() && QFile::exists(desktopShortcut))
611 QFile::remove(desktopShortcut);
612
613 #endif
614
615 #endif
616 QDir appdataDir(QStandardPaths::standardLocations(QStandardPaths::DataLocation).first());
617
618 if (appdataDir.exists())
619 appdataDir.removeRecursively();
620
621 QMessageBox::information(
622 nullptr, "Qt Bitcoin Trader", julyTr("QT_BITCOIN_TRADER_UNINSTALLED", "Qt Bitcoin Trader completely uninstalled"));
623 #ifndef Q_OS_MAC
624 QFile::remove(a.applicationFilePath());
625 #endif
626 return 0;
627 }
628
629 if (a.arguments().contains("/installed"))
630 {
631 QMessageBox::information(nullptr,
632 "Qt Bitcoin Trader",
633 julyTr("QT_BITCOIN_TRADER_INSTALLED",
634 "Qt Bitcoin Trader installed into system folder<br>"
635 "Launch shortcut have been placed in your Desktop folder<br>"
636 "To uninstall it you can use menu Help->Uninstall<br>"
637 "You can now delete installation file")
638 .replace("<br>", "<br><br>"));
639 }
640 }
641
642 a.setApplicationName("QtBitcoinTrader");
643
644 if (!baseValues.initAppDataDir(a))
645 return 0;
646
647 baseValues.initValues(a);
648 baseValues.initThemes(a);
649 baseValues.initSettings();
650
651 if (argc > 1)
652 {
653 if (a.arguments().last().startsWith("/checkupdate"))
654 {
655 QSettings settings(appDataDir + "/QtBitcoinTrader.cfg", QSettings::IniFormat);
656 QString langFile = settings.value("LanguageFile", "").toString();
657
658 if (langFile.isEmpty() || !QFile::exists(langFile))
659 langFile = baseValues.defaultLangFile;
660
661 julyTranslator.loadFromFile(langFile);
662 QTimer::singleShot(1000000, &a, &QCoreApplication::quit);
663 UpdaterDialog updater(a.arguments().last() != "/checkupdate");
664 #ifdef Q_OS_UNIX
665 quitOnSignals({SIGHUP, SIGQUIT, SIGABRT, SIGTERM, SIGXCPU, SIGXFSZ, SIGINT});
666 #endif
667 return a.exec();
668 }
669 }
670
671 IniEngine::global();
672 TimeSync::global();
673
674 {
675 bool tryDecrypt = true;
676 bool showNewPasswordDialog = false;
677
678 while (tryDecrypt)
679 {
680 QString tryPassword;
681 baseValues.restKey.clear();
682 baseValues.restSign.clear();
683 bool noProfiles = QDir(appDataDir, "*.ini").entryList().isEmpty();
684
685 if (noProfiles || showNewPasswordDialog)
686 {
687 FeaturedExchangesDialog featuredExchanges;
688
689 if (featuredExchanges.exchangeNum != -3)
690 {
691 int execResult = featuredExchanges.exec();
692
693 if (noProfiles && execResult == QDialog::Rejected)
694 return 0;
695
696 if (featuredExchanges.exchangeNum != -2)
697 if (execResult == QDialog::Rejected || featuredExchanges.exchangeNum == -1)
698 {
699 showNewPasswordDialog = false;
700 continue;
701 }
702 }
703
704 qint32 exchangeNumber = 0;
705
706 if (featuredExchanges.exchangeNum >= 0)
707 exchangeNumber = featuredExchanges.exchangeNum;
708 else
709 {
710 AllExchangesDialog allExchanges(featuredExchanges.exchangeNum);
711
712 if (allExchanges.exec() == QDialog::Rejected)
713 {
714 showNewPasswordDialog = false;
715 continue;
716 }
717
718 if (allExchanges.exchangeNum == -1)
719 {
720 showNewPasswordDialog = false;
721 continue;
722 }
723
724 if (allExchanges.exchangeNum == -2)
725 continue;
726
727 exchangeNumber = allExchanges.exchangeNum;
728 }
729
730 if (exchangeNumber == 0)
731 {
732 QMessageBox msgBox;
733 msgBox.setIcon(QMessageBox::Question);
734 msgBox.setWindowTitle("Qt Bitcoin Trader");
735 msgBox.setText(julyTr("AGREE_CLOSED_SOURCE", "Do you agree to download the enclosed application?"));
736 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
737 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
738 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
739
740 if (msgBox.exec() == QMessageBox::No)
741 continue;
742 }
743
744 NewPasswordDialog newPassword(exchangeNumber);
745
746 if (newPassword.exec() == QDialog::Accepted)
747 {
748 tryPassword = newPassword.getPassword();
749 newPassword.updateIniFileName();
750 baseValues.restKey = newPassword.getRestKey().toLatin1();
751 QSettings settings(baseValues.iniFileName, QSettings::IniFormat);
752 settings.setValue("Profile/ExchangeId", newPassword.getExchangeId());
753 settings.sync();
754
755 if (!QFile::exists(baseValues.iniFileName))
756 QMessageBox::warning(nullptr, "Qt Bitcoin Trader", "Can't write file: \"" + baseValues.iniFileName + "\"");
757
758 QByteArray encryptedData;
759
760 switch (newPassword.getExchangeId())
761 {
762 case 0:
763 {
764 // Qt Trader Exchange
765 baseValues.restSign = newPassword.getRestSign().toLatin1();
766 encryptedData =
767 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
768 "\r\n" + QUuid::createUuid().toString().toLatin1(),
769 tryPassword.toUtf8());
770 }
771 break;
772
773 case 2:
774 {
775 // Bitstamp
776 baseValues.restSign = newPassword.getRestSign().toLatin1();
777 encryptedData =
778 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
779 "\r\n" + QUuid::createUuid().toString().toLatin1(),
780 tryPassword.toUtf8());
781 }
782 break;
783
784 case 4:
785 {
786 // Bitfinex
787 baseValues.restSign = newPassword.getRestSign().toLatin1();
788 encryptedData =
789 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
790 "\r\n" + QUuid::createUuid().toString().toLatin1(),
791 tryPassword.toUtf8());
792 }
793 break;
794
795 case 6:
796 {
797 // Indacoin
798 baseValues.restSign = newPassword.getRestSign().toLatin1();
799 encryptedData =
800 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
801 "\r\n" + QUuid::createUuid().toString().toLatin1(),
802 tryPassword.toUtf8());
803 }
804 break;
805
806 case 10:
807 {
808 // YObit
809 baseValues.restSign = newPassword.getRestSign().toLatin1();
810 encryptedData =
811 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
812 "\r\n" + QUuid::createUuid().toString().toLatin1(),
813 tryPassword.toUtf8());
814 }
815 break;
816
817 case 11:
818 {
819 // Binance
820 baseValues.restSign = newPassword.getRestSign().toLatin1();
821 encryptedData =
822 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
823 "\r\n" + QUuid::createUuid().toString().toLatin1(),
824 tryPassword.toUtf8());
825 }
826 break;
827
828 case 12:
829 {
830 // Bittrex
831 baseValues.restSign = newPassword.getRestSign().toLatin1();
832 encryptedData =
833 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
834 "\r\n" + QUuid::createUuid().toString().toLatin1(),
835 tryPassword.toUtf8());
836 }
837 break;
838
839 case 13:
840 {
841 // HitBTC
842 baseValues.restSign = newPassword.getRestSign().toLatin1();
843 encryptedData =
844 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
845 "\r\n" + QUuid::createUuid().toString().toLatin1(),
846 tryPassword.toUtf8());
847 }
848 break;
849
850 case 14:
851 {
852 // Poloniex
853 baseValues.restSign = newPassword.getRestSign().toLatin1();
854 encryptedData =
855 JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + baseValues.restKey + "\r\n" + baseValues.restSign.toBase64() +
856 "\r\n" + QUuid::createUuid().toString().toLatin1(),
857 tryPassword.toUtf8());
858 }
859 break;
860
861 default:
862 break;
863 }
864
865 settings.setValue("Profile/Name", newPassword.selectedProfileName());
866 settings.setValue("EncryptedData/ApiKeySign", QString(encryptedData.toBase64()));
867 settings.sync();
868
869 showNewPasswordDialog = false;
870 }
871 else if (noProfiles)
872 continue;
873 }
874
875 PasswordDialog enterPassword;
876
877 if (enterPassword.exec() == QDialog::Rejected)
878 return 0;
879
880 if (enterPassword.resetData)
881 continue;
882
883 if (enterPassword.newProfile)
884 {
885 showNewPasswordDialog = true;
886 continue;
887 }
888
889 tryPassword = enterPassword.getPassword();
890
891 if (!tryPassword.isEmpty())
892 {
893 baseValues.iniFileName = enterPassword.getIniFilePath();
894 baseValues.logFileName = baseValues.iniFileName;
895 baseValues.logFileName.replace(".ini", ".log", Qt::CaseInsensitive);
896
897 if (julyLock)
898 julyLock->free();
899
900 julyLock.reset(new JulyLockFile(baseValues.iniFileName, appDataDir));
901 bool profileLocked = julyLock->isLocked();
902
903 if (profileLocked)
904 {
905 QMessageBox msgBox(nullptr);
906 msgBox.setIcon(QMessageBox::Question);
907 msgBox.setWindowTitle("Qt Bitcoin Trader");
908 msgBox.setText(julyTr(
909 "THIS_PROFILE_ALREADY_USED",
910 "This profile is already used by another instance.<br>API does not allow to run two instances with same key sign pair.<br>Please create new profile if you want to use two instances."));
911 msgBox.setStandardButtons(QMessageBox::Ok);
912 msgBox.setDefaultButton(QMessageBox::Ok);
913 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
914 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
915
916 msgBox.exec();
917
918 tryPassword.clear();
919 }
920
921 if (!profileLocked)
922 {
923 QSettings settings(baseValues.iniFileName, QSettings::IniFormat);
924 QStringList decryptedList =
925 QString(JulyAES256::decrypt(
926 QByteArray::fromBase64(settings.value("EncryptedData/ApiKeySign", "").toString().toLatin1()),
927 tryPassword.toUtf8()))
928 .split("\r\n");
929
930 if (decryptedList.size() < 3 || decryptedList.first() != "Qt Bitcoin Trader")
931 {
932 decryptedList =
933 QString(JulyAES256::decrypt(
934 QByteArray::fromBase64(settings.value("EncryptedData/ApiKeySign", "").toString().toLatin1()),
935 tryPassword.toLatin1()))
936 .split("\r\n");
937 }
938
939 if (decryptedList.size() >= 3 && decryptedList.first() == "Qt Bitcoin Trader")
940 {
941 baseValues.restKey = decryptedList.at(1).toLatin1();
942 baseValues.restSign = QByteArray::fromBase64(decryptedList.at(2).toLatin1());
943
944 if (decryptedList.size() == 3)
945 {
946 decryptedList << QUuid::createUuid().toString().toLatin1();
947 settings.setValue(
948 "EncryptedData/ApiKeySign",
949 QString(JulyAES256::encrypt("Qt Bitcoin Trader\r\n" + decryptedList.at(1).toLatin1() + "\r\n" +
950 decryptedList.at(2).toLatin1() + "\r\n" + decryptedList.at(3).toLatin1(),
951 tryPassword.toUtf8())
952 .toBase64()));
953 settings.sync();
954 }
955
956 baseValues.randomPassword = decryptedList.at(3).toLatin1();
957 tryDecrypt = false;
958 }
959 }
960 }
961 }
962
963 baseValues.scriptFolder += QFileInfo(baseValues.iniFileName).completeBaseName() + "/";
964
965 QSettings iniSettings(baseValues.iniFileName, QSettings::IniFormat);
966
967 if (iniSettings.value("Debug/LogEnabled", false).toBool())
968 debugLevel = 1;
969
970 iniSettings.setValue("Debug/LogEnabled", debugLevel > 0);
971 baseValues.logThread_ = nullptr;
972
973 if (debugLevel)
974 {
975 baseValues.logThread_ = new LogThread;
976 logThread->writeLog("Proxy settings: " + QNetworkProxy::applicationProxy().hostName().toUtf8() + ":" +
977 QByteArray::number(QNetworkProxy::applicationProxy().port()) + " " +
978 QNetworkProxy::applicationProxy().user().toUtf8());
979 }
980
981 QSettings settingsMain(appDataDir + "/QtBitcoinTrader.cfg", QSettings::IniFormat);
982
983 if (settingsMain.value("ShowQtTraderInform2", true).toBool())
984 {
985 QtTraderInform inform;
986 int informRez = inform.exec();
987
988 if (inform.dontShowAgain())
989 {
990 settingsMain.setValue("ShowQtTraderInform2", false);
991 settingsMain.sync();
992 }
993
994 if (informRez == QDialog::Accepted)
995 QDesktopServices::openUrl(QUrl("https://qttrader.com/"));
996 }
997
998 ::config = new ConfigManager(slash(appDataDir, "QtBitcoinTrader.ws.cfg"), &a);
999 baseValues.mainWindow_ = new QtBitcoinTrader;
1000 }
1001
1002 baseValues.mainWindow_->setupClass();
1003
1004 #ifdef Q_OS_UNIX
1005 quitOnSignals({SIGHUP, SIGQUIT, SIGABRT, SIGTERM, SIGXCPU, SIGXFSZ, SIGINT});
1006 #endif
1007 int rezult = a.exec();
1008 return rezult;
1009 }
1010