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