/*
Copyright (C) ABRT Team
Copyright (C) RedHat inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <gio/gdesktopappinfo.h>
#include <string.h>
#include <stdlib.h>
#include "problem_utils.h"
char *
problem_get_argv0 (const char *cmdline)
{
char *ret;
char **items;
items = g_strsplit (cmdline, " ", -1);
ret = g_strdup (items[0]);
g_strfreev (items);
return ret;
}
static void
remove_quotes (char **args)
{
guint i;
for (i = 0; args[i] != NULL; i++)
{
char **items;
char *str;
items = g_strsplit (args[i], "\"", -1);
str = g_strjoinv (NULL, items);
g_strfreev (items);
g_free (args[i]);
args[i] = str;
}
}
static gboolean
_is_it_file_arg (const char *s)
{
if (s == NULL)
return FALSE;
if (*s == '-')
return FALSE;
return TRUE;
}
static gboolean
_is_it_url (const char *s)
{
if (s == NULL)
return FALSE;
if (strstr (s, "://"))
return TRUE;
return FALSE;
}
static gboolean
compare_args (char **cmdargs,
char **dcmdargs)
{
guint cargi, dargi;
gboolean ret;
/* Start at 1, as we already compared the binaries */
cargi = dargi = 1;
while (dargi < g_strv_length(dcmdargs))
{
if (g_str_equal (dcmdargs[dargi], "%f"))
{
if (cargi >= g_strv_length(cmdargs) || _is_it_file_arg(cmdargs[cargi]))
{
return FALSE;
} else {
dargi++;
cargi++;
}
}
else if (g_str_equal (dcmdargs[dargi], "%F"))
{
if (cargi >= g_strv_length(cmdargs) || _is_it_file_arg(cmdargs[cargi]))
dargi++;
else
cargi++;
}
else if (g_str_equal (dcmdargs[dargi], "%u"))
{
if (cargi >= g_strv_length(cmdargs) ||
(!_is_it_url(cmdargs[cargi]) && !_is_it_file_arg(cmdargs[cargi])))
{
return FALSE;
}
else
{
cargi++;
dargi++;
}
}
else if (g_str_equal (dcmdargs[dargi], "%U"))
{
if (cargi >= g_strv_length(cmdargs) ||
(!_is_it_url(cmdargs[cargi]) && !_is_it_file_arg(cmdargs[cargi])))
{
dargi++;
}
else
{
cargi++;
}
}
else if (g_str_equal (dcmdargs[dargi], "%i"))
{
//logging.debug("Unsupported Exec key %i");
dargi++;
cargi += 2;
}
else if (g_str_equal (dcmdargs[dargi], "%c") ||
g_str_equal (dcmdargs[dargi], "%k"))
{
//logging.debug("Unsupported Exec key %s", dcmdargs[dargi]);
dargi++;
cargi++;
}
else
{
if (cargi >= g_strv_length(cmdargs) || !g_str_equal (dcmdargs[dargi], cmdargs[cargi]))
return FALSE;
dargi++;
cargi++;
}
}
ret = (cargi == g_strv_length(cmdargs) && dargi == g_strv_length(dcmdargs));
return ret;
}
static gboolean
compare_binaries (char *cmd,
const char *dcmd)
{
char *basename, *dbasename;
gboolean ret = FALSE;
if (g_strcmp0 (cmd, dcmd) == 0)
return TRUE;
basename = g_path_get_basename (cmd);
dbasename = g_path_get_basename (dcmd);
if (g_strcmp0 (basename, dbasename) == 0)
ret = TRUE;
g_free (basename);
g_free (dbasename);
return ret;
}
GAppInfo *
problem_create_app_from_cmdline (const char *cmdline)
{
GAppInfo *app;
GList *apps, *l;
GList *shortlist;
char *binary;
char **cmdargs;
binary = problem_get_argv0(cmdline);
apps = g_app_info_get_all ();
shortlist = NULL;
app = NULL;
for (l = apps; l != NULL; l = l->next)
{
GAppInfo *a = l->data;
if (!g_app_info_should_show(a))
continue;
if (!compare_binaries (binary, g_app_info_get_executable (a)))
continue;
shortlist = g_list_prepend (shortlist, a);
}
if (shortlist == NULL)
{
g_list_free_full (apps, g_object_unref);
return NULL;
}
cmdargs = g_strsplit (cmdline, " ", -1);
remove_quotes (cmdargs);
for (l = shortlist; l != NULL; l = l->next)
{
GAppInfo *a = l->data;
char **dcmdargs;
const char *commandline = g_app_info_get_commandline (a);
if (commandline == NULL)
continue;
dcmdargs = g_strsplit (commandline, " ", -1);
remove_quotes (dcmdargs);
if (compare_args (cmdargs, dcmdargs))
app = g_object_ref (a);
g_strfreev (dcmdargs);
if (app != NULL)
break;
}
g_list_free (shortlist);
g_list_free_full (apps, g_object_unref);
return app;
}
#define GIO_LAUNCHED_DESKTOP_FILE_PREFIX "GIO_LAUNCHED_DESKTOP_FILE="
#define GIO_LAUNCHED_DESKTOP_FILE_PID_PREFIX "GIO_LAUNCHED_DESKTOP_FILE_PID="
GAppInfo *
problem_create_app_from_env (const char **envp,
pid_t pid)
{
GDesktopAppInfo *app;
guint i;
const char *desktop, *epid;
if (envp == NULL)
return NULL;
if (pid < 0)
return NULL;
desktop = epid = NULL;
for (i = 0; envp[i] != NULL; i++)
{
if (g_str_has_prefix (envp[i], GIO_LAUNCHED_DESKTOP_FILE_PREFIX))
desktop = envp[i] + strlen (GIO_LAUNCHED_DESKTOP_FILE_PREFIX);
else if (g_str_has_prefix (envp[i], GIO_LAUNCHED_DESKTOP_FILE_PID_PREFIX))
epid = envp[i] + strlen (GIO_LAUNCHED_DESKTOP_FILE_PID_PREFIX);
if (desktop && epid)
break;
}
if (!desktop || !epid)
return NULL;
/* Verify PID */
if (atoi (epid) != pid)
return NULL;
if (*desktop == '/')
app = g_desktop_app_info_new_from_filename (desktop);
else
app = g_desktop_app_info_new (desktop);
return (GAppInfo *) app;
}