1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 
19 #define RG_MODULE_STRING "[StartupTester]"
20 
21 #include "StartupTester.h"
22 
23 #include "misc/Strings.h"
24 #include "misc/Debug.h"
25 #include "gui/dialogs/LilyPondOptionsDialog.h"
26 #include "gui/editors/notation/NoteFontFactory.h"
27 
28 #include "rosegarden-version.h"
29 
30 #include <QNetworkAccessManager>
31 #include <QNetworkReply>
32 #include <QProcess>
33 #include <QMutex>
34 #include <QThread>
35 #include <QRegularExpression>
36 
37 
38 namespace Rosegarden
39 {
40 
StartupTester()41 StartupTester::StartupTester() :
42 //    m_proc(nullptr),
43     m_ready(false),
44     m_haveAudioFileImporter(false)
45 //    m_versionHttpFailed(false)
46 {
47     QUrl url;
48     url.setScheme("http");
49     url.setHost("www.rosegardenmusic.com");
50     url.setPath("/latest-version.txt");
51 
52     network = new QNetworkAccessManager(this);
53     network->get(QNetworkRequest(url));
54     RG_DEBUG << "StartupTester::StartupTester(): URL: " << url.toString();
55 
56     connect(network, &QNetworkAccessManager::finished,
57             this, &StartupTester::slotNetworkFinished);
58 }
59 
~StartupTester()60 StartupTester::~StartupTester()
61 {
62 }
63 
64 void
run()65 StartupTester::run() {
66     m_runningMutex.lock();
67     m_ready = true;
68 
69     m_haveAudioFileImporter = true;
70     NoteFontFactory::getFontNames(true);
71 
72     // unlock this as the very last thing we do in this thread,
73     // so the parent process knows the thread is completed
74     m_runningMutex.unlock();
75 }
76 
77 bool
isReady()78 StartupTester::isReady()
79 {
80     while (!m_ready) usleep(10000);
81     if (m_runningMutex.tryLock()) {
82         m_runningMutex.unlock();
83     } else {
84         return false;
85     }
86     return true;
87 }
88 
89 #if 0
90 void
91 StartupTester::stdoutReceived()
92 {
93     m_stdoutBuffer.append(m_proc->readAllStandardOutput());
94 }
95 
96 void
97 StartupTester::parseStdoutBuffer(QStringList &target)
98 {
99     QRegularExpression re("Required: ([^\n]*)");
100     QRegularExpressionMatch match = re.match(m_stdoutBuffer);
101     if (match.hasMatch()) {
102         target = match.captured(1).split(", ");
103     }
104 }
105 #endif
106 
107 bool
haveAudioFileImporter(QStringList * missing)108 StartupTester::haveAudioFileImporter(QStringList *missing)
109 {
110     while (!m_ready)
111         usleep(10000);
112     QMutexLocker locker(&m_audioFileImporterMutex);
113     if (missing) *missing = m_audioFileImporterMissing;
114     return m_haveAudioFileImporter;
115 }
116 
117 bool
isVersionNewerThan(QString a,QString b)118 StartupTester::isVersionNewerThan(QString a, QString b)
119 {
120     QRegularExpression re("[._-]");
121 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
122     QStringList alist = a.split(re, Qt::SkipEmptyParts);
123     QStringList blist = b.split(re, Qt::SkipEmptyParts);
124 #else
125     QStringList alist = a.split(re, QString::SkipEmptyParts);
126     QStringList blist = b.split(re, QString::SkipEmptyParts);
127 #endif
128     int ae = alist.size();
129     int be = blist.size();
130     int e = std::max(ae, be);
131     for (int i = 0; i < e; ++i) {
132     int an = 0, bn = 0;
133     if (i < ae) {
134         an = alist[i].toInt();
135         if (an == 0) an = -1; // non-numeric field -> "-pre1" etc
136     }
137     if (i < be) {
138         bn = blist[i].toInt();
139         if (bn == 0) bn = -1;
140     }
141     if (an < bn) return false;
142     if (an > bn) return true;
143     }
144     return false;
145 }
146 
147 void
slotNetworkFinished(QNetworkReply * reply)148 StartupTester::slotNetworkFinished(QNetworkReply *reply)
149 {
150     reply->deleteLater();
151     network->deleteLater();
152 
153     if (reply->error() != QNetworkReply::NoError) {
154 //        m_versionHttpFailed = true;
155         RG_WARNING << "StartupTester::slotNetworkFinished(): Connection failed: " << reply->errorString();
156         return;
157     }
158 
159     QByteArray responseData = reply->readAll();
160     QString str = QString::fromUtf8(responseData.data());
161 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
162     QStringList lines = str.split('\n', Qt::SkipEmptyParts);
163 #else
164     QStringList lines = str.split('\n', QString::SkipEmptyParts);
165 #endif
166     if (lines.empty()) return;
167 
168     QString latestVersion = lines[0];
169     RG_DEBUG << "StartupTester::slotNetworkFinished(): Comparing current version \"" << VERSION
170               << "\" with latest version \"" << latestVersion << "\"";
171     if (isVersionNewerThan(latestVersion, VERSION)) {
172         emit newerVersionAvailable(latestVersion);
173     }
174 }
175 
176 }
177 
178 
179