1 /**
2  * UGENE - Integrated Bioinformatics Tools.
3  * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4  * http://ugene.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21 
22 #include "CheckUpdatesTask.h"
23 
24 #include <QMainWindow>
25 #include <QMessageBox>
26 #include <QNetworkReply>
27 #include <QPushButton>
28 
29 #include <U2Core/AppContext.h>
30 #include <U2Core/AppSettings.h>
31 #include <U2Core/NetworkConfiguration.h>
32 #include <U2Core/Settings.h>
33 #include <U2Core/SyncHttp.h>
34 #include <U2Core/U2SafePoints.h>
35 
36 #include <U2Gui/MainWindow.h>
37 
38 #include "update/UgeneUpdater.h"
39 
40 namespace U2 {
41 
CheckUpdatesTask(bool startUp)42 CheckUpdatesTask::CheckUpdatesTask(bool startUp)
43     : Task(tr("Check for updates"), TaskFlag_SilentCancelOnShutdown) {
44     runOnStartup = startUp;
45     setVerboseLogMode(true);
46     startError = false;
47 }
48 
49 #define SITE_URL QString("ugene.net")
50 #ifdef Q_OS_WIN
51 #    define PAGE_NAME QString("/current_version_win.html")
52 #elif defined(Q_OS_DARWIN)
53 #    define PAGE_NAME QString("/current_version_mac.html")
54 #elif defined(Q_OS_LINUX)
55 #    define PAGE_NAME QString("/current_version_linux.html")
56 #else
57 #    define PAGE_NAME QString("/current_version.html")
58 #endif
59 
run()60 void CheckUpdatesTask::run() {
61     stateInfo.setDescription(tr("Connecting to updates server"));
62     NetworkConfiguration *nc = AppContext::getAppSettings()->getNetworkConfiguration();
63     SAFE_POINT(nc != nullptr, "Network configuration is null", );
64 
65     bool isProxy = nc->isProxyUsed(QNetworkProxy::HttpProxy);
66     bool isException = nc->getExceptionsList().contains(SITE_URL);
67     SyncHttp http(stateInfo);
68     if (isProxy && !isException) {
69         http.setProxy(nc->getProxy(QNetworkProxy::HttpProxy));
70     }
71     // The following call blocks some UI tasks (Close project), so don't make it run long.
72     QString siteVersionText = http.syncGet(QUrl("http://" + SITE_URL + PAGE_NAME), 5000);
73     if (siteVersionText.isEmpty()) {
74         if (!runOnStartup) {
75             stateInfo.setError(tr("Cannot load the current version."));
76         } else {
77             uiLog.error(tr("Cannot load the current version."));
78             startError = true;
79         }
80     }
81     siteVersion = Version::parseVersion(siteVersionText);
82     stateInfo.setDescription(QString());
83 
84     if (http.error() != QNetworkReply::NoError) {
85         if (!runOnStartup) {
86             stateInfo.setError(tr("Connection error while checking for updates: %1").arg(http.errorString()));
87         } else {
88             uiLog.error(tr("Connection error while checking for updates: %1").arg(http.errorString()));
89             startError = true;
90         }
91         return;
92     }
93 }
94 
report()95 Task::ReportResult CheckUpdatesTask::report() {
96     if (hasError() || startError) {
97         return ReportResult_Finished;
98     }
99 
100     Version thisVersion = Version::appVersion();
101 
102     Answer answer = DoNothing;
103     if (runOnStartup) {
104         if (siteVersion > thisVersion && !UgeneUpdater::isUpdateSkipped(siteVersion)) {
105             UpdateMessage message(siteVersion.text);
106             answer = message.getAnswer();
107         }
108     } else {
109         VersionMessage message(siteVersion);
110         answer = message.getAnswer();
111     }
112 
113     switch (answer) {
114         case Update:
115             UgeneUpdater::getInstance()->update();
116             break;
117         case Skip:
118             UgeneUpdater::skipUpdate(siteVersion);
119             break;
120         case DoNothing:
121         default:
122             break;
123     }
124     return ReportResult_Finished;
125 }
126 
sl_registerInTaskScheduler()127 void CheckUpdatesTask::sl_registerInTaskScheduler() {
128     AppContext::getTaskScheduler()->registerTopLevelTask(this);
129 }
130 
131 /************************************************************************/
132 /* UpdateMessage */
133 /************************************************************************/
UpdateMessage(const QString & newVersion)134 UpdateMessage::UpdateMessage(const QString &newVersion) {
135     QWidget *parent = AppContext::getMainWindow()->getQMainWindow();
136     const QString message = tr("UGENE %1 is available for downloading.\nWould you like to download and install it?").arg(newVersion);
137     const QString title = tr("New Updates");
138 
139     dialog = new QMessageBox(QMessageBox::Question, title, message, QMessageBox::NoButton, parent);
140 
141     updateButton = dialog->addButton(tr("Update now"), QMessageBox::ActionRole);
142     postponeButton = dialog->addButton(tr("Ask later"), QMessageBox::ActionRole);
143     dialog->addButton(tr("Skip this update"), QMessageBox::ActionRole);
144 }
145 
getAnswer() const146 CheckUpdatesTask::Answer UpdateMessage::getAnswer() const {
147     dialog->exec();
148     CHECK(!dialog.isNull(), CheckUpdatesTask::DoNothing);
149 
150     if (updateButton == dialog->clickedButton()) {
151         return CheckUpdatesTask::Update;
152     }
153     if (postponeButton == dialog->clickedButton()) {
154         return CheckUpdatesTask::DoNothing;
155     }
156     return CheckUpdatesTask::Skip;
157 }
158 
159 /************************************************************************/
160 /* VersionMessage */
161 /************************************************************************/
VersionMessage(const Version & newVersion)162 VersionMessage::VersionMessage(const Version &newVersion) {
163     QWidget *parent = AppContext::getMainWindow()->getQMainWindow();
164     const QString message = getMessageText(Version::appVersion(), newVersion);
165     const QString title = tr("Version Information");
166 
167     dialog = new QMessageBox(QMessageBox::Information, title, message, QMessageBox::NoButton, parent);
168     dialog->addButton(QMessageBox::Ok);
169     updateButton = nullptr;
170     if (Version::appVersion() < newVersion) {
171         updateButton = dialog->addButton(tr("Update Now"), QMessageBox::ActionRole);
172     }
173 }
174 
getAnswer() const175 CheckUpdatesTask::Answer VersionMessage::getAnswer() const {
176     dialog->exec();
177     CHECK(!dialog.isNull(), CheckUpdatesTask::DoNothing);
178 
179     if (dialog->clickedButton() == updateButton) {
180         return CheckUpdatesTask::Update;
181     }
182     return CheckUpdatesTask::DoNothing;
183 }
184 
getMessageText(const Version & thisVersion,const Version & newVersion) const185 QString VersionMessage::getMessageText(const Version &thisVersion, const Version &newVersion) const {
186     QString message = QString("<table>"
187                               " <tr><td>%1</td><td><b>&nbsp;%2</b></td></tr>"
188                               " <tr><td>%3</td><td><b>&nbsp;%4</b></td></tr>"
189                               "</table>")
190                           .arg(tr("Your version:"), thisVersion.text, tr("Latest version:"), newVersion.text);
191 
192     if (thisVersion >= newVersion) {
193         message += "<p>" + tr("You have the latest version") + "</p>";
194     }
195     return message;
196 }
197 
198 }  // namespace U2
199