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 61 && entry->SymlinkPath() != NULL) { 62 HDINFO("found deskbar entry: %s -> %s", 63 path.String(), entry->SymlinkPath()); 64 fDeskbarLinks.push_back(DeskbarLink(path, entry->SymlinkPath())); 65 } 66 return B_OK; 67 } 68 69 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 70 BPackageEntryAttribute* attribute) 71 { 72 return B_OK; 73 } 74 75 virtual status_t HandleEntryDone(BPackageEntry* entry) 76 { 77 return B_OK; 78 } 79 80 virtual status_t HandlePackageAttribute( 81 const BPackageInfoAttributeValue& value) 82 { 83 return B_OK; 84 } 85 86 virtual void HandleErrorOccurred() 87 { 88 } 89 90 BString MakePath(const BPackageEntry* entry) 91 { 92 BString path; 93 while (entry != NULL) { 94 if (!path.IsEmpty()) 95 path.Prepend('/', 1); 96 path.Prepend(entry->Name()); 97 entry = entry->Parent(); 98 } 99 return path; 100 } 101 102 private: 103 std::vector<DeskbarLink>& fDeskbarLinks; 104 }; 105 106 107 // #pragma mark - OpenPackageProcess 108 109 110 OpenPackageProcess::OpenPackageProcess(PackageInfoRef package, Model* model, 111 const DeskbarLink& link) 112 : 113 AbstractPackageProcess(package, model), 114 fDeskbarLink(link) 115 { 116 fDescription = _DeriveDescription(); 117 } 118 119 120 OpenPackageProcess::~OpenPackageProcess() 121 { 122 } 123 124 125 const char* 126 OpenPackageProcess::Name() const 127 { 128 return "OpenPackageProcess"; 129 } 130 131 132 const char* 133 OpenPackageProcess::Description() const 134 { 135 return fDescription; 136 } 137 138 139 status_t 140 OpenPackageProcess::RunInternal() 141 { 142 status_t status; 143 BPath path; 144 if (fDeskbarLink.Link().FindFirst('/') == 0) { 145 status = path.SetTo(fDeskbarLink.Link()); 146 HDINFO("trying to launch (absolute link): %s", path.Path()); 147 } else { 148 int32 location = InstallLocation(); 149 if (location == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) { 150 status = find_directory(B_SYSTEM_DIRECTORY, &path); 151 if (status != B_OK) 152 return status; 153 } else if (location == B_PACKAGE_INSTALLATION_LOCATION_HOME) { 154 status = find_directory(B_USER_DIRECTORY, &path); 155 if (status != B_OK) 156 return status; 157 } else { 158 return B_ERROR; 159 } 160 161 status = path.Append(fDeskbarLink.Path()); 162 if (status == B_OK) 163 status = path.GetParent(&path); 164 if (status == B_OK) { 165 status = path.Append(fDeskbarLink.Link(), true); 166 HDINFO("trying to launch: %s", path.Path()); 167 } 168 } 169 170 entry_ref ref; 171 if (status == B_OK) 172 status = get_ref_for_path(path.Path(), &ref); 173 174 if (status == B_OK) 175 status = be_roster->Launch(&ref); 176 177 return status; 178 } 179 180 181 BString 182 OpenPackageProcess::_DeriveDescription() 183 { 184 BString target = fDeskbarLink.Link(); 185 int32 lastPathSeparator = target.FindLast('/'); 186 if (lastPathSeparator > 0 && lastPathSeparator + 1 < target.Length()) 187 target.Remove(0, lastPathSeparator + 1); 188 189 BString result = B_TRANSLATE("Opening \"%DeskbarLink%\""); 190 result.ReplaceAll("%DeskbarLink%", target); 191 return result; 192 } 193 194 195 /*static*/ bool 196 OpenPackageProcess::FindAppToLaunch(const PackageInfoRef& package, 197 std::vector<DeskbarLink>& foundLinks) 198 { 199 if (!package.IsSet()) 200 return false; 201 202 BPath packagePath; 203 if (PackageUtils::DeriveLocalFilePath(package, packagePath) != B_OK) { 204 HDDEBUG("unable to derive local file path for package"); 205 return false; 206 } 207 208 BNoErrorOutput errorOutput; 209 BPackageReader reader(&errorOutput); 210 211 status_t status = reader.Init(packagePath.Path()); 212 if (status != B_OK) { 213 HDINFO("OpenPackageAction::FindAppToLaunch(): " 214 "failed to init BPackageReader(%s): %s", 215 packagePath.Path(), strerror(status)); 216 return false; 217 } 218 219 // Scan package contents for Deskbar links 220 DeskbarLinkFinder contentHandler(foundLinks); 221 status = reader.ParseContent(&contentHandler); 222 if (status != B_OK) { 223 HDINFO("OpenPackageAction::FindAppToLaunch(): " 224 "failed parse package contents (%s): %s", 225 packagePath.Path(), strerror(status)); 226 return false; 227 } 228 229 return !foundLinks.empty(); 230 } 231