2
* Copyright © 2015 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Ted Gould <ted.gould@canonical.com>
20
#include <json-glib/json-glib.h>
23
#include "ubuntu-app-launch.h"
26
/* Try and get a manifest and do a couple sanity checks on it */
28
get_manifest (const gchar * pkg, gchar ** pkgpath)
30
/* Get the directory from click */
31
GError * error = NULL;
33
ClickDB * db = click_db_new();
34
/* If TEST_CLICK_DB is unset, this reads the system database. */
35
click_db_read(db, g_getenv("TEST_CLICK_DB"), &error);
37
g_warning("Unable to read Click database: %s", error->message);
42
/* If TEST_CLICK_USER is unset, this uses the current user name. */
43
ClickUser * user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error);
45
g_warning("Unable to read Click database: %s", error->message);
51
JsonObject * manifest = click_user_get_manifest(user, pkg, &error);
53
g_warning("Unable to get manifest for '%s' package: %s", pkg, error->message);
59
if (pkgpath != NULL) {
60
*pkgpath = click_user_get_path(user, pkg, &error);
62
g_warning("Unable to get the Click package directory for %s: %s", pkg, error->message);
70
if (!json_object_has_member(manifest, "version")) {
71
g_warning("Manifest file for package '%s' does not have a version", pkg);
72
json_object_unref(manifest);
79
/* Types of search we can do for an app name */
80
typedef enum _app_name_t app_name_t;
87
/* Figure out the app name if it's one of the keywords */
89
manifest_app_name (JsonObject ** manifest, const gchar * pkg, const gchar * original_app)
91
app_name_t app_type = APP_NAME_FIRST;
93
if (original_app == NULL) {
95
} else if (g_strcmp0(original_app, "first-listed-app") == 0) {
97
} else if (g_strcmp0(original_app, "last-listed-app") == 0) {
98
app_type = APP_NAME_LAST;
99
} else if (g_strcmp0(original_app, "only-listed-app") == 0) {
100
app_type = APP_NAME_ONLY;
105
if (*manifest == NULL) {
106
*manifest = get_manifest(pkg, NULL);
109
JsonObject * hooks = json_object_get_object_member(*manifest, "hooks");
115
GList * apps = json_object_get_members(hooks);
120
const gchar * retapp = NULL;
124
if (g_list_length(apps) == 1) {
125
retapp = (const gchar *)apps->data;
129
retapp = (const gchar *)apps->data;
132
retapp = (const gchar *)(g_list_last(apps)->data);
143
/* Figure out the app version using the manifest */
145
manifest_version (JsonObject ** manifest, const gchar * pkg, const gchar * original_ver)
147
if (original_ver != NULL && g_strcmp0(original_ver, "current-user-version") != 0) {
150
if (*manifest == NULL) {
151
*manifest = get_manifest(pkg, NULL);
153
g_return_val_if_fail(*manifest != NULL, NULL);
155
return g_strdup(json_object_get_string_member(*manifest, "version"));
161
/* A click triplet can require using the Click DB and getting a
162
manifest. This code does that to look up the versions */
164
click_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver)
166
const gchar * version = NULL;
167
const gchar * application = NULL;
168
JsonObject * manifest = NULL;
170
version = manifest_version(&manifest, pkg, ver);
171
g_return_val_if_fail(version != NULL, NULL);
173
application = manifest_app_name(&manifest, pkg, app);
174
g_return_val_if_fail(application != NULL, NULL);
176
gchar * retval = g_strdup_printf("%s_%s_%s", pkg, application, version);
178
/* The object may hold allocation for some of our strings used above */
180
json_object_unref(manifest);
185
/* Build an appid how we think it should exist and then make sure
186
we can find it. Then pull it together. */
188
libertine_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver)
194
gchar * synthappid = g_strdup_printf("%s_%s_0.0", pkg, app);
195
if (app_info_libertine(synthappid, NULL, NULL)) {
203
/* Look to see if the app id results in a desktop file, if so, fill in the params */
205
evaluate_dir (const gchar * dir, const gchar * desktop, gchar ** appdir, gchar ** appdesktop)
207
char * fulldir = g_build_filename(dir, "applications", desktop, NULL);
208
gboolean found = FALSE;
210
if (g_file_test(fulldir, G_FILE_TEST_EXISTS)) {
211
if (appdir != NULL) {
212
*appdir = g_strdup(dir);
215
if (appdesktop != NULL) {
216
*appdesktop = g_strdup_printf("applications/%s", desktop);
226
/* Handle the legacy case where we look through the data directories */
228
app_info_legacy (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
230
gchar * desktop = g_strdup_printf("%s.desktop", appid);
232
/* Special case the user's dir */
233
if (evaluate_dir(g_get_user_data_dir(), desktop, appdir, appdesktop)) {
238
const char * const * data_dirs = g_get_system_data_dirs();
240
for (i = 0; data_dirs[i] != NULL; i++) {
241
if (evaluate_dir(data_dirs[i], desktop, appdir, appdesktop)) {
250
/* Handle the libertine case where we look in the container */
252
app_info_libertine (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
254
char * container = NULL;
257
if (!ubuntu_app_launch_app_id_parse(appid, &container, &app, NULL)) {
261
gchar * desktopname = g_strdup_printf("%s.desktop", app);
263
gchar * desktopdir = g_build_filename(g_get_user_cache_dir(), "libertine-container", container, "rootfs", "usr", "share", NULL);
264
gchar * desktopfile = g_build_filename(desktopdir, "applications", desktopname, NULL);
266
if (!g_file_test(desktopfile, G_FILE_TEST_EXISTS)) {
270
desktopdir = g_build_filename(g_get_user_data_dir(), "libertine-container", "user-data", container, ".local", "share", NULL);
271
desktopfile = g_build_filename(desktopdir, "applications", desktopname, NULL);
273
if (!g_file_test(desktopfile, G_FILE_TEST_EXISTS)) {
285
if (appdir != NULL) {
286
*appdir = desktopdir;
291
if (appdesktop != NULL) {
292
*appdesktop = g_build_filename("applications", desktopname, NULL);
303
/* Get the information on where the desktop file is from libclick */
305
app_info_click (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
307
gchar * package = NULL;
308
gchar * application = NULL;
310
if (!ubuntu_app_launch_app_id_parse(appid, &package, &application, NULL)) {
314
JsonObject * manifest = get_manifest(package, appdir);
315
if (manifest == NULL) {
323
if (appdesktop != NULL) {
324
JsonObject * hooks = json_object_get_object_member(manifest, "hooks");
326
json_object_unref(manifest);
331
JsonObject * appobj = json_object_get_object_member(hooks, application);
334
if (appobj == NULL) {
335
json_object_unref(manifest);
339
const gchar * desktop = json_object_get_string_member(appobj, "desktop");
340
if (desktop == NULL) {
341
json_object_unref(manifest);
345
*appdesktop = g_strdup(desktop);
350
json_object_unref(manifest);