/* * Copyright 2013-2017, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler * Rene Gollent * Ingo Weinhold * Brian Hill */ #include "CheckManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "constants.h" using namespace BPackageKit; using namespace BPackageKit::BManager::BPrivate; #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "CheckManager" CheckManager::CheckManager(BPackageInstallationLocation location, bool verbose) : BPackageManager(location, &fClientInstallationInterface, this), BPackageManager::UserInteractionHandler(), fClientInstallationInterface(), fVerbose(verbose), fNotificationId("") { if (verbose) { app_info info; if (be_app->GetAppInfo(&info)!= B_OK) fVerbose = false; else fNotificationId << info.team; } fHeaderChecking = B_TRANSLATE("Checking for updates"); fTextContacting = B_TRANSLATE("Contacting software repositories to check " "for package updates."); } void CheckManager::CheckNetworkConnection() { BNetworkRoster& roster = BNetworkRoster::Default(); BNetworkInterface interface; uint32 cookie = 0; while (roster.GetNextInterface(&cookie, interface) == B_OK) { uint32 flags = interface.Flags(); if ((flags & IFF_LOOPBACK) == 0 && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) { return; } } // No network connection detected, cannot continue fputs(B_TRANSLATE("No active network connection was found.\n"), stderr); throw BAbortedByUserException(); } void CheckManager::JobFailed(BSupportKit::BJob* job) { BString error = job->ErrorString(); if (error.Length() > 0) { error.ReplaceAll("\n", "\n*** "); fprintf(stderr, "%s", error.String()); } } void CheckManager::JobAborted(BSupportKit::BJob* job) { puts("Job aborted"); BString error = job->ErrorString(); if (error.Length() > 0) { error.ReplaceAll("\n", "\n*** "); fprintf(stderr, "%s", error.String()); } } void CheckManager::NoUpdatesNotification() { if (fVerbose) { BString header = B_TRANSLATE("No updates available"); BString text = B_TRANSLATE("There were no updates found."); _SendNotification(header.String(), text.String()); } } void CheckManager::HandleProblems() { puts("Encountered problems:"); int32 problemCount = fSolver->CountProblems(); for (int32 i = 0; i < problemCount; i++) { BSolverProblem* problem = fSolver->ProblemAt(i); printf("problem %" B_PRId32 ": %s\n", i + 1, problem->ToString().String()); } BString title(B_TRANSLATE("Available updates found")); BString text(B_TRANSLATE("Click here to run SoftwareUpdater. Some updates " "will require a problem solution to be selected.")); _SendNotification(title, text); throw BAbortedByUserException(); } void CheckManager::ConfirmChanges(bool fromMostSpecific) { int32 count = fInstalledRepositories.CountItems(); int32 updateCount = 0; if (fromMostSpecific) { for (int32 i = count - 1; i >= 0; i--) _CountUpdates(*fInstalledRepositories.ItemAt(i), updateCount); } else { for (int32 i = 0; i < count; i++) _CountUpdates(*fInstalledRepositories.ItemAt(i), updateCount); } printf("Update count=%" B_PRId32 "\n", updateCount); if (updateCount > 0) { BString title; static BStringFormat formatTitle(B_TRANSLATE( "Software {0, plural, one{update} other{updates}} available")); formatTitle.Format(title, updateCount); BString text; static BStringFormat formatText(B_TRANSLATE("Click here to " "install {0, plural, one{# updated package} " "other{# updated packages}}.")); formatText.Format(text, updateCount); _SendNotification(title.String(), text.String()); } throw BAbortedByUserException(); } void CheckManager::Warn(status_t error, const char* format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); if (error == B_OK) puts(""); else printf(": %s\n", strerror(error)); } void CheckManager::ProgressPackageDownloadStarted(const char* packageName) { if (fVerbose) _SendNotification(fHeaderChecking.String(), fTextContacting.String()); printf("Downloading %s...\n", packageName); } void CheckManager::ProgressPackageDownloadActive(const char* packageName, float completionPercentage, off_t bytes, off_t totalBytes) { static const char* progressChars[] = { "\xE2\x96\x8F", "\xE2\x96\x8E", "\xE2\x96\x8D", "\xE2\x96\x8C", "\xE2\x96\x8B", "\xE2\x96\x8A", "\xE2\x96\x89", "\xE2\x96\x88", }; int width = 70; struct winsize winSize; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winSize) == 0 && winSize.ws_col < 77) { // We need 7 characters for the percent display width = winSize.ws_col - 7; } int position; int ipart = (int)(completionPercentage * width); int fpart = (int)(((completionPercentage * width) - ipart) * 8); fputs("\r", stdout); // return to the beginning of the line for (position = 0; position < width; position++) { if (position < ipart) { // This part is fully downloaded, show a full block fputs(progressChars[7], stdout); } else if (position > ipart) { // This part is not downloaded, show a space fputs(" ", stdout); } else { // This part is partially downloaded fputs(progressChars[fpart], stdout); } } // Also print the progress percentage printf(" %3d%%", (int)(completionPercentage * 100)); fflush(stdout); } void CheckManager::ProgressPackageDownloadComplete(const char* packageName) { // Overwrite the progress bar with whitespace fputs("\r", stdout); struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); for (int i = 0; i < (w.ws_col); i++) fputs(" ", stdout); fputs("\r\x1b[1A", stdout); // Go to previous line. printf("Downloading %s...done.\n", packageName); } void CheckManager::ProgressPackageChecksumStarted(const char* title) { if (fVerbose) _SendNotification(fHeaderChecking.String(), title); printf("%s...", title); } void CheckManager::ProgressPackageChecksumComplete(const char* title) { puts("done."); } void CheckManager::_CountUpdates(InstalledRepository& installationRepository, int32& updateCount) { if (!installationRepository.HasChanges()) return; PackageList& packagesToActivate = installationRepository.PackagesToActivate(); PackageList& packagesToDeactivate = installationRepository.PackagesToDeactivate(); for (int32 i = 0; BSolverPackage* installPackage = packagesToActivate.ItemAt(i); i++) { for (int32 j = 0; BSolverPackage* uninstallPackage = packagesToDeactivate.ItemAt(j); j++) { if (installPackage->Info().Name() == uninstallPackage->Info().Name()) { updateCount++; break; } } } } void CheckManager::_SendNotification(const char* title, const char* text) { BNotification notification(B_INFORMATION_NOTIFICATION); notification.SetGroup(B_TRANSLATE_SYSTEM_NAME("SoftwareUpdater")); notification.SetTitle(title); notification.SetContent(text); notification.SetOnClickApp(kAppSignature); if(fVerbose) notification.SetMessageID(fNotificationId); notification.Send(); }