xref: /haiku/src/apps/haikudepot/packagemanagement/OpenPackageProcess.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
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 "PackageKitUtils.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 (PackageKitUtils::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