1 /* 2 * Copyright 2013-2022, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold <ingo_weinhold@gmx.de> 7 * Stephan Aßmus <superstippi@gmx.de> 8 * Rene Gollent <rene@gollent.com> 9 * Julian Harnath <julian.harnath@rwth-aachen.de> 10 * Andrew Lindesay <apl@lindesay.co.nz> 11 * 12 * Note that this file has been re-factored from `PackageManager.cpp` and 13 * authors have been carried across in 2021. 14 */ 15 16 17 #include "OpenPackageProcess.h" 18 19 #include <Catalog.h> 20 #include <FindDirectory.h> 21 #include <Roster.h> 22 23 #include <package/PackageDefs.h> 24 #include <package/hpkg/NoErrorOutput.h> 25 #include <package/hpkg/PackageContentHandler.h> 26 #include <package/hpkg/PackageEntry.h> 27 #include <package/hpkg/PackageEntryAttribute.h> 28 #include <package/hpkg/PackageInfoAttributeValue.h> 29 #include <package/hpkg/PackageReader.h> 30 31 #include "Logger.h" 32 #include "PackageUtils.h" 33 34 #undef B_TRANSLATION_CONTEXT 35 #define B_TRANSLATION_CONTEXT "OpenPackageProcess" 36 37 using namespace BPackageKit; 38 39 using BPackageKit::BHPKG::BNoErrorOutput; 40 using BPackageKit::BHPKG::BPackageContentHandler; 41 using BPackageKit::BHPKG::BPackageEntry; 42 using BPackageKit::BHPKG::BPackageEntryAttribute; 43 using BPackageKit::BHPKG::BPackageInfoAttributeValue; 44 using BPackageKit::BHPKG::BPackageReader; 45 46 // #pragma mark - DeskbarLinkFinder 47 48 49 class DeskbarLinkFinder : public BPackageContentHandler { 50 public: 51 DeskbarLinkFinder(std::vector<DeskbarLink>& foundLinks) 52 : 53 fDeskbarLinks(foundLinks) 54 { 55 } 56 57 virtual status_t HandleEntry(BPackageEntry* entry) 58 { 59 BString path = MakePath(entry); 60 if (path.FindFirst("data/deskbar/menu") == 0 && entry->SymlinkPath() != NULL) { 61 HDINFO("found deskbar entry: %s -> %s", path.String(), entry->SymlinkPath()); 62 fDeskbarLinks.push_back(DeskbarLink(path, entry->SymlinkPath())); 63 } 64 return B_OK; 65 } 66 67 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 68 BPackageEntryAttribute* attribute) 69 { 70 return B_OK; 71 } 72 73 virtual status_t HandleEntryDone(BPackageEntry* entry) 74 { 75 return B_OK; 76 } 77 78 virtual status_t HandlePackageAttribute( 79 const BPackageInfoAttributeValue& value) 80 { 81 return B_OK; 82 } 83 84 virtual void HandleErrorOccurred() 85 { 86 } 87 88 BString MakePath(const BPackageEntry* entry) 89 { 90 BString path; 91 while (entry != NULL) { 92 if (!path.IsEmpty()) 93 path.Prepend('/', 1); 94 path.Prepend(entry->Name()); 95 entry = entry->Parent(); 96 } 97 return path; 98 } 99 100 private: 101 std::vector<DeskbarLink>& fDeskbarLinks; 102 }; 103 104 105 // #pragma mark - OpenPackageProcess 106 107 108 OpenPackageProcess::OpenPackageProcess(PackageInfoRef package, Model* model, 109 const DeskbarLink& link) 110 : 111 AbstractPackageProcess(package, model), 112 fDeskbarLink(link) 113 { 114 fDescription = _DeriveDescription(); 115 } 116 117 118 OpenPackageProcess::~OpenPackageProcess() 119 { 120 } 121 122 123 const char* 124 OpenPackageProcess::Name() const 125 { 126 return "OpenPackageProcess"; 127 } 128 129 130 const char* 131 OpenPackageProcess::Description() const 132 { 133 return fDescription; 134 } 135 136 137 status_t 138 OpenPackageProcess::RunInternal() 139 { 140 status_t status; 141 BPath path; 142 if (fDeskbarLink.Link().FindFirst('/') == 0) { 143 status = path.SetTo(fDeskbarLink.Link()); 144 HDINFO("trying to launch (absolute link): %s", path.Path()); 145 } else { 146 int32 location = InstallLocation(); 147 if (location == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) { 148 status = find_directory(B_SYSTEM_DIRECTORY, &path); 149 if (status != B_OK) 150 return status; 151 } else if (location == B_PACKAGE_INSTALLATION_LOCATION_HOME) { 152 status = find_directory(B_USER_DIRECTORY, &path); 153 if (status != B_OK) 154 return status; 155 } else { 156 return B_ERROR; 157 } 158 159 status = path.Append(fDeskbarLink.Path()); 160 if (status == B_OK) 161 status = path.GetParent(&path); 162 if (status == B_OK) { 163 status = path.Append(fDeskbarLink.Link(), true); 164 HDINFO("trying to launch: %s", path.Path()); 165 } 166 } 167 168 entry_ref ref; 169 if (status == B_OK) 170 status = get_ref_for_path(path.Path(), &ref); 171 172 if (status == B_OK) 173 status = be_roster->Launch(&ref); 174 175 return status; 176 } 177 178 179 BString 180 OpenPackageProcess::_DeriveDescription() 181 { 182 BString target = fDeskbarLink.Link(); 183 int32 lastPathSeparator = target.FindLast('/'); 184 if (lastPathSeparator > 0 && lastPathSeparator + 1 < target.Length()) 185 target.Remove(0, lastPathSeparator + 1); 186 187 BString result = B_TRANSLATE("Opening \"%DeskbarLink%\""); 188 result.ReplaceAll("%DeskbarLink%", target); 189 return result; 190 } 191 192 193 /*static*/ bool 194 OpenPackageProcess::FindAppToLaunch(const PackageInfoRef& package, 195 std::vector<DeskbarLink>& foundLinks) 196 { 197 if (!package.IsSet()) 198 return false; 199 200 BPath packagePath; 201 if (PackageUtils::DeriveLocalFilePath(package, packagePath) != B_OK) { 202 HDDEBUG("unable to derive local file path for package"); 203 return false; 204 } 205 206 BNoErrorOutput errorOutput; 207 BPackageReader reader(&errorOutput); 208 209 status_t status = reader.Init(packagePath.Path()); 210 if (status != B_OK) { 211 HDINFO("OpenPackageAction::FindAppToLaunch(): " 212 "failed to init BPackageReader(%s): %s", 213 packagePath.Path(), strerror(status)); 214 return false; 215 } 216 217 // Scan package contents for Deskbar links 218 DeskbarLinkFinder contentHandler(foundLinks); 219 status = reader.ParseContent(&contentHandler); 220 if (status != B_OK) { 221 HDINFO("OpenPackageAction::FindAppToLaunch(): " 222 "failed parse package contents (%s): %s", 223 packagePath.Path(), strerror(status)); 224 return false; 225 } 226 227 return !foundLinks.empty(); 228 } 229