1 /*
2 * Copyright 2013-2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Axel Dörfler <axeld@pinc-software.de>
7 * Rene Gollent <rene@gollent.com>
8 * Ingo Weinhold <ingo_weinhold@gmx.de>
9 * Brian Hill <supernova@tycho.email>
10 */
11
12
13 #include "CheckManager.h"
14
15 #include <sys/ioctl.h>
16 #include <unistd.h>
17
18 #include <Application.h>
19 #include <Catalog.h>
20 #include <Message.h>
21 #include <Messenger.h>
22 #include <NetworkInterface.h>
23 #include <NetworkRoster.h>
24 #include <NodeInfo.h>
25 #include <Notification.h>
26 #include <Roster.h>
27 #include <StringFormat.h>
28
29 #include <package/manager/Exceptions.h>
30 #include <package/solver/SolverPackage.h>
31 #include <package/solver/SolverProblem.h>
32 #include <package/solver/SolverProblemSolution.h>
33
34 #include "constants.h"
35
36 using namespace BPackageKit;
37 using namespace BPackageKit::BManager::BPrivate;
38
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "CheckManager"
41
42
CheckManager(BPackageInstallationLocation location,bool verbose)43 CheckManager::CheckManager(BPackageInstallationLocation location,
44 bool verbose)
45 :
46 BPackageManager(location, &fClientInstallationInterface, this),
47 BPackageManager::UserInteractionHandler(),
48 fClientInstallationInterface(),
49 fVerbose(verbose),
50 fNotificationId("")
51 {
52 if (verbose) {
53 app_info info;
54 if (be_app->GetAppInfo(&info)!= B_OK)
55 fVerbose = false;
56 else
57 fNotificationId << info.team;
58 }
59 fHeaderChecking = B_TRANSLATE("Checking for updates");
60 fTextContacting = B_TRANSLATE("Contacting software repositories to check "
61 "for package updates.");
62 }
63
64
65 void
CheckNetworkConnection()66 CheckManager::CheckNetworkConnection()
67 {
68 BNetworkRoster& roster = BNetworkRoster::Default();
69 BNetworkInterface interface;
70 uint32 cookie = 0;
71 while (roster.GetNextInterface(&cookie, interface) == B_OK) {
72 uint32 flags = interface.Flags();
73 if ((flags & IFF_LOOPBACK) == 0
74 && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) {
75 return;
76 }
77 }
78
79 // No network connection detected, cannot continue
80 fputs(B_TRANSLATE("No active network connection was found.\n"), stderr);
81 throw BAbortedByUserException();
82 }
83
84
85 void
JobFailed(BSupportKit::BJob * job)86 CheckManager::JobFailed(BSupportKit::BJob* job)
87 {
88 BString error = job->ErrorString();
89 if (error.Length() > 0) {
90 error.ReplaceAll("\n", "\n*** ");
91 fprintf(stderr, "%s", error.String());
92 }
93 }
94
95
96 void
JobAborted(BSupportKit::BJob * job)97 CheckManager::JobAborted(BSupportKit::BJob* job)
98 {
99 puts("Job aborted");
100 BString error = job->ErrorString();
101 if (error.Length() > 0) {
102 error.ReplaceAll("\n", "\n*** ");
103 fprintf(stderr, "%s", error.String());
104 }
105 }
106
107
108 void
NoUpdatesNotification()109 CheckManager::NoUpdatesNotification()
110 {
111 if (fVerbose) {
112 BString header = B_TRANSLATE("No updates available");
113 BString text = B_TRANSLATE("There were no updates found.");
114 _SendNotification(header.String(), text.String());
115 }
116 }
117
118
119 void
HandleProblems()120 CheckManager::HandleProblems()
121 {
122 puts("Encountered problems:");
123
124 int32 problemCount = fSolver->CountProblems();
125 for (int32 i = 0; i < problemCount; i++) {
126 BSolverProblem* problem = fSolver->ProblemAt(i);
127 printf("problem %" B_PRId32 ": %s\n", i + 1,
128 problem->ToString().String());
129 }
130
131 BString title(B_TRANSLATE("Available updates found"));
132 BString text(B_TRANSLATE("Click here to run SoftwareUpdater. Some updates "
133 "will require a problem solution to be selected."));
134 _SendNotification(title, text);
135
136 throw BAbortedByUserException();
137 }
138
139
140 void
ConfirmChanges(bool fromMostSpecific)141 CheckManager::ConfirmChanges(bool fromMostSpecific)
142 {
143 int32 count = fInstalledRepositories.CountItems();
144 int32 updateCount = 0;
145
146 if (fromMostSpecific) {
147 for (int32 i = count - 1; i >= 0; i--)
148 _CountUpdates(*fInstalledRepositories.ItemAt(i), updateCount);
149 } else {
150 for (int32 i = 0; i < count; i++)
151 _CountUpdates(*fInstalledRepositories.ItemAt(i), updateCount);
152 }
153
154 printf("Update count=%" B_PRId32 "\n", updateCount);
155 if (updateCount > 0) {
156 BString title;
157 static BStringFormat formatTitle(B_TRANSLATE(
158 "Software {0, plural, one{update} other{updates}} available"));
159 formatTitle.Format(title, updateCount);
160 BString text;
161 static BStringFormat formatText(B_TRANSLATE("Click here to "
162 "install {0, plural, one{# updated package} "
163 "other{# updated packages}}."));
164 formatText.Format(text, updateCount);
165
166 _SendNotification(title.String(), text.String());
167 }
168 throw BAbortedByUserException();
169 }
170
171
172 void
Warn(status_t error,const char * format,...)173 CheckManager::Warn(status_t error, const char* format, ...)
174 {
175 va_list args;
176 va_start(args, format);
177 vfprintf(stderr, format, args);
178 va_end(args);
179
180 if (error == B_OK)
181 puts("");
182 else
183 printf(": %s\n", strerror(error));
184 }
185
186
187 void
ProgressPackageDownloadStarted(const char * packageName)188 CheckManager::ProgressPackageDownloadStarted(const char* packageName)
189 {
190 if (fVerbose)
191 _SendNotification(fHeaderChecking.String(), fTextContacting.String());
192
193 printf("Downloading %s...\n", packageName);
194 }
195
196
197 void
ProgressPackageDownloadActive(const char * packageName,float completionPercentage,off_t bytes,off_t totalBytes)198 CheckManager::ProgressPackageDownloadActive(const char* packageName,
199 float completionPercentage, off_t bytes, off_t totalBytes)
200 {
201 static const char* progressChars[] = {
202 "\xE2\x96\x8F",
203 "\xE2\x96\x8E",
204 "\xE2\x96\x8D",
205 "\xE2\x96\x8C",
206 "\xE2\x96\x8B",
207 "\xE2\x96\x8A",
208 "\xE2\x96\x89",
209 "\xE2\x96\x88",
210 };
211
212 int width = 70;
213
214 struct winsize winSize;
215 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winSize) == 0
216 && winSize.ws_col < 77) {
217 // We need 7 characters for the percent display
218 width = winSize.ws_col - 7;
219 }
220
221 int position;
222 int ipart = (int)(completionPercentage * width);
223 int fpart = (int)(((completionPercentage * width) - ipart) * 8);
224
225 fputs("\r", stdout); // return to the beginning of the line
226
227 for (position = 0; position < width; position++) {
228 if (position < ipart) {
229 // This part is fully downloaded, show a full block
230 fputs(progressChars[7], stdout);
231 } else if (position > ipart) {
232 // This part is not downloaded, show a space
233 fputs(" ", stdout);
234 } else {
235 // This part is partially downloaded
236 fputs(progressChars[fpart], stdout);
237 }
238 }
239
240 // Also print the progress percentage
241 printf(" %3d%%", (int)(completionPercentage * 100));
242
243 fflush(stdout);
244
245 }
246
247
248 void
ProgressPackageDownloadComplete(const char * packageName)249 CheckManager::ProgressPackageDownloadComplete(const char* packageName)
250 {
251 // Overwrite the progress bar with whitespace
252 fputs("\r", stdout);
253 struct winsize w;
254 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
255 for (int i = 0; i < (w.ws_col); i++)
256 fputs(" ", stdout);
257 fputs("\r\x1b[1A", stdout); // Go to previous line.
258
259 printf("Downloading %s...done.\n", packageName);
260 }
261
262
263 void
ProgressPackageChecksumStarted(const char * title)264 CheckManager::ProgressPackageChecksumStarted(const char* title)
265 {
266 if (fVerbose)
267 _SendNotification(fHeaderChecking.String(), title);
268
269 printf("%s...", title);
270 }
271
272
273 void
ProgressPackageChecksumComplete(const char * title)274 CheckManager::ProgressPackageChecksumComplete(const char* title)
275 {
276 puts("done.");
277 }
278
279
280 void
_CountUpdates(InstalledRepository & installationRepository,int32 & updateCount)281 CheckManager::_CountUpdates(InstalledRepository& installationRepository,
282 int32& updateCount)
283 {
284 if (!installationRepository.HasChanges())
285 return;
286
287 PackageList& packagesToActivate
288 = installationRepository.PackagesToActivate();
289 PackageList& packagesToDeactivate
290 = installationRepository.PackagesToDeactivate();
291
292 for (int32 i = 0;
293 BSolverPackage* installPackage = packagesToActivate.ItemAt(i);
294 i++) {
295 for (int32 j = 0;
296 BSolverPackage* uninstallPackage = packagesToDeactivate.ItemAt(j);
297 j++) {
298 if (installPackage->Info().Name() == uninstallPackage->Info().Name()) {
299 updateCount++;
300 break;
301 }
302 }
303 }
304 }
305
306
307 void
_SendNotification(const char * title,const char * text)308 CheckManager::_SendNotification(const char* title, const char* text)
309 {
310 BNotification notification(B_INFORMATION_NOTIFICATION);
311 notification.SetGroup(B_TRANSLATE_SYSTEM_NAME("SoftwareUpdater"));
312 notification.SetTitle(title);
313 notification.SetContent(text);
314 notification.SetOnClickApp(kAppSignature);
315 if(fVerbose)
316 notification.SetMessageID(fNotificationId);
317 notification.Send();
318 }
319