|
Packit |
4f15d5 |
/*
|
|
Packit |
4f15d5 |
Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
|
|
Packit |
4f15d5 |
Copyright (C) 2009 RedHat inc.
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
4f15d5 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
4f15d5 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
4f15d5 |
(at your option) any later version.
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
4f15d5 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4f15d5 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
4f15d5 |
GNU General Public License for more details.
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
You should have received a copy of the GNU General Public License along
|
|
Packit |
4f15d5 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
4f15d5 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
4f15d5 |
*/
|
|
Packit |
4f15d5 |
#include "internal_libreport.h"
|
|
Packit |
4f15d5 |
#include "client.h"
|
|
Packit |
4f15d5 |
#include "problem_report.h"
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
#define PR_DEFAULT_SUBJECT \
|
|
Packit |
4f15d5 |
"[abrt] %pkg_name%[[: %crash_function%()]][[: %reason%]][[: TAINTED %tainted_short%]]"
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
#define PR_MAILX_TEMPLATE \
|
|
Packit |
4f15d5 |
"%%summary:: %s\n" \
|
|
Packit |
4f15d5 |
"\n" \
|
|
Packit |
4f15d5 |
"::" \
|
|
Packit |
4f15d5 |
FILENAME_REASON","FILENAME_CRASH_FUNCTION"," \
|
|
Packit |
4f15d5 |
FILENAME_CMDLINE","FILENAME_EXECUTABLE"," \
|
|
Packit |
4f15d5 |
FILENAME_PACKAGE","FILENAME_COMPONENT","FILENAME_PID","FILENAME_PWD"," \
|
|
Packit |
4f15d5 |
FILENAME_HOSTNAME","FILENAME_COUNT", %%oneline\n" \
|
|
Packit |
4f15d5 |
"\n" \
|
|
Packit |
4f15d5 |
"::" \
|
|
Packit |
4f15d5 |
FILENAME_COMMENT","FILENAME_REPORTED_TO","FILENAME_BACKTRACE"," \
|
|
Packit |
4f15d5 |
FILENAME_CORE_BACKTRACE", %%multiline"
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
#define PR_ATTACH_BINARY "\n%attach:: %binary"
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
enum {
|
|
Packit |
4f15d5 |
RM_FLAG_NOTIFY = (1 << 0),
|
|
Packit |
4f15d5 |
RM_FLAG_DEBUG = (1 << 1)
|
|
Packit |
4f15d5 |
};
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
static void exec_and_feed_input(const char* text, char **args)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
int pipein[2];
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
pid_t child = fork_execv_on_steroids(
|
|
Packit |
4f15d5 |
EXECFLG_INPUT | EXECFLG_QUIET,
|
|
Packit |
4f15d5 |
args,
|
|
Packit |
4f15d5 |
pipein,
|
|
Packit |
4f15d5 |
/*env_vec:*/ NULL,
|
|
Packit |
4f15d5 |
/*dir:*/ NULL,
|
|
Packit |
4f15d5 |
/*uid (ignored):*/ 0
|
|
Packit |
4f15d5 |
);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
full_write_str(pipein[1], text);
|
|
Packit |
4f15d5 |
close(pipein[1]);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
int status;
|
|
Packit |
4f15d5 |
safe_waitpid(child, &status, 0); /* wait for command completion */
|
|
Packit |
4f15d5 |
if (status != 0)
|
|
Packit |
4f15d5 |
error_msg_and_die("Error running '%s'", args[0]);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
static char** append_str_to_vector(char **vec, unsigned *size_p, const char *str)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
//log_warning("old vec: %p", vec);
|
|
Packit |
4f15d5 |
unsigned size = *size_p;
|
|
Packit |
4f15d5 |
vec = (char**) xrealloc(vec, (size+2) * sizeof(vec[0]));
|
|
Packit |
4f15d5 |
vec[size] = xstrdup(str);
|
|
Packit |
4f15d5 |
//log_warning("new vec: %p, added [%d] %p", vec, size, vec[size]);
|
|
Packit |
4f15d5 |
size++;
|
|
Packit |
4f15d5 |
vec[size] = NULL;
|
|
Packit |
4f15d5 |
*size_p = size;
|
|
Packit |
4f15d5 |
return vec;
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
static char *ask_email_address(const char *type, const char *def_address)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
char *ask_text = xasprintf(_("Email address of %s was not specified. Would you like to do so now? If not, '%s' is to be used"), type, def_address);
|
|
Packit |
4f15d5 |
const int ret = ask_yes_no(ask_text);
|
|
Packit |
4f15d5 |
free(ask_text);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (!ret)
|
|
Packit |
4f15d5 |
return xstrdup(def_address);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
ask_text = xasprintf(_("Please, type email address of %s:"), type);
|
|
Packit |
4f15d5 |
char *address = ask(ask_text);
|
|
Packit |
4f15d5 |
free(ask_text);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (address == NULL || address[0] == '\0')
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
|
|
Packit |
4f15d5 |
error_msg_and_die(_("Can't continue without email address of %s"), type);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
return address;
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
static void create_and_send_email(
|
|
Packit |
4f15d5 |
const char *dump_dir_name,
|
|
Packit |
4f15d5 |
map_string_t *settings,
|
|
Packit |
4f15d5 |
const char *fmt_file,
|
|
Packit |
4f15d5 |
int flag)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
|
|
Packit |
4f15d5 |
if (!problem_data)
|
|
Packit |
4f15d5 |
xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
char* env;
|
|
Packit |
4f15d5 |
env = getenv("Mailx_EmailFrom");
|
|
Packit |
4f15d5 |
char *email_from = (env ? xstrdup(env) : xstrdup(get_map_string_item_or_NULL(settings, "EmailFrom")) ? : ask_email_address("sender", "ABRT Daemon <DoNotReply>"));
|
|
Packit |
4f15d5 |
env = getenv("Mailx_EmailTo");
|
|
Packit |
4f15d5 |
char *email_to = (env ? xstrdup(env) : xstrdup(get_map_string_item_or_NULL(settings, "EmailTo")) ? : ask_email_address("receiver", "root@localhost"));
|
|
Packit |
4f15d5 |
env = getenv("Mailx_SendBinaryData");
|
|
Packit |
4f15d5 |
bool send_binary_data = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SendBinaryData"));
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
problem_formatter_t *pf = problem_formatter_new();
|
|
Packit |
4f15d5 |
/* formatting file is not set */
|
|
Packit |
4f15d5 |
if (fmt_file == NULL)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
env = getenv("Mailx_Subject");
|
|
Packit |
4f15d5 |
const char *subject = (env ? env : get_map_string_item_or_NULL(settings, "Subject") ? : PR_DEFAULT_SUBJECT);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
char *format_string = xasprintf(PR_MAILX_TEMPLATE, subject);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
/* attaching binary file to the email */
|
|
Packit |
4f15d5 |
if (send_binary_data)
|
|
Packit |
4f15d5 |
format_string = append_to_malloced_string(format_string, PR_ATTACH_BINARY);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (problem_formatter_load_string(pf, format_string))
|
|
Packit |
4f15d5 |
error_msg_and_die("BUG: Invalid default problem report format string");
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
free(format_string);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
else
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
if (problem_formatter_load_file(pf, fmt_file))
|
|
Packit |
4f15d5 |
error_msg_and_die("Invalid format file: %s", fmt_file);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
problem_report_t *pr = NULL;
|
|
Packit |
4f15d5 |
if (problem_formatter_generate_report(pf, problem_data, &pr))
|
|
Packit |
4f15d5 |
error_msg_and_die("Failed to format bug report from problem data");
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
const char *subject = problem_report_get_summary(pr);
|
|
Packit |
4f15d5 |
const char *dsc = problem_report_get_description(pr);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (flag & RM_FLAG_DEBUG)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
printf("subject: %s\n"
|
|
Packit |
4f15d5 |
"\n"
|
|
Packit |
4f15d5 |
"%s"
|
|
Packit |
4f15d5 |
"\n"
|
|
Packit |
4f15d5 |
, subject
|
|
Packit |
4f15d5 |
, dsc);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
puts("attachments:");
|
|
Packit |
4f15d5 |
for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
|
|
Packit |
4f15d5 |
printf(" %s\n", (const char *)a->data);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
problem_report_free(pr);
|
|
Packit |
4f15d5 |
problem_formatter_free(pf);
|
|
Packit |
4f15d5 |
free(email_from);
|
|
Packit |
4f15d5 |
free(email_to);
|
|
Packit |
4f15d5 |
exit(0);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
char **args = NULL;
|
|
Packit |
4f15d5 |
unsigned arg_size = 0;
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, "/bin/mailx");
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
/* attaching files to the email */
|
|
Packit |
4f15d5 |
for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, "-a");
|
|
Packit |
4f15d5 |
char *full_name = concat_path_file(realpath(dump_dir_name, NULL), a->data);
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, full_name);
|
|
Packit |
4f15d5 |
free(full_name);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, "-s");
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, subject);
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, "-r");
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, email_from);
|
|
Packit |
4f15d5 |
args = append_str_to_vector(args, &arg_size, email_to);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
free(email_from);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
/* This makes (some versions of) mailx to wait for child process to finish,
|
|
Packit |
4f15d5 |
* and to report its exit code, not useless "always 0" exit code.
|
|
Packit |
4f15d5 |
* Sadly, usually this still doesn't help. See:
|
|
Packit |
4f15d5 |
* https://bugzilla.redhat.com/show_bug.cgi?id=740895
|
|
Packit |
4f15d5 |
*/
|
|
Packit |
4f15d5 |
putenv((char*)"sendwait=1");
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
/* Prevent mailx from creating dead.letter if sending fails. The file is
|
|
Packit |
4f15d5 |
* useless in our case and if the reporter is called from abrtd, SELinux
|
|
Packit |
4f15d5 |
* complains a lot about mailx touching ABRT data.
|
|
Packit |
4f15d5 |
*/
|
|
Packit |
4f15d5 |
putenv((char*)"DEAD=/dev/null");
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (flag & RM_FLAG_NOTIFY)
|
|
Packit |
4f15d5 |
log_warning(_("Sending a notification email to: %s"), email_to);
|
|
Packit |
4f15d5 |
else
|
|
Packit |
4f15d5 |
log_warning(_("Sending an email..."));
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
exec_and_feed_input(dsc, args);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
problem_report_free(pr);
|
|
Packit |
4f15d5 |
problem_formatter_free(pf);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
while (*args)
|
|
Packit |
4f15d5 |
free(*args++);
|
|
Packit |
4f15d5 |
args -= arg_size;
|
|
Packit |
4f15d5 |
free(args);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
problem_data_free(problem_data);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (!(flag & RM_FLAG_NOTIFY))
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
|
|
Packit |
4f15d5 |
if (dd)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
report_result_t rr = { .label = (char *)"email" };
|
|
Packit |
4f15d5 |
rr.url = xasprintf("mailto:%s", email_to);
|
|
Packit |
4f15d5 |
add_reported_to_entry(dd, &rr);
|
|
Packit |
4f15d5 |
free(rr.url);
|
|
Packit |
4f15d5 |
dd_close(dd);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
log_warning(_("Email was sent to: %s"), email_to);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
free(email_to);
|
|
Packit |
4f15d5 |
}
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
int main(int argc, char **argv)
|
|
Packit |
4f15d5 |
{
|
|
Packit |
4f15d5 |
abrt_init(argv);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
/* I18n */
|
|
Packit |
4f15d5 |
setlocale(LC_ALL, "");
|
|
Packit |
4f15d5 |
#if ENABLE_NLS
|
|
Packit |
4f15d5 |
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
Packit |
4f15d5 |
textdomain(PACKAGE);
|
|
Packit |
4f15d5 |
#endif
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
const char *dump_dir_name = ".";
|
|
Packit |
4f15d5 |
const char *conf_file = CONF_DIR"/plugins/mailx.conf";
|
|
Packit |
4f15d5 |
const char *fmt_file = NULL;
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
/* Can't keep these strings/structs static: _() doesn't support that */
|
|
Packit |
4f15d5 |
const char *program_usage_string = _(
|
|
Packit |
4f15d5 |
"& [-v] -d DIR [-c CONFFILE] [-F FMTFILE]"
|
|
Packit |
4f15d5 |
"\n"
|
|
Packit |
4f15d5 |
"\n""Sends contents of a problem directory DIR via email"
|
|
Packit |
4f15d5 |
"\n"
|
|
Packit |
4f15d5 |
"\n""If not specified, CONFFILE defaults to "CONF_DIR"/plugins/mailx.conf"
|
|
Packit |
4f15d5 |
"\n""Its lines should have 'PARAM = VALUE' format."
|
|
Packit |
4f15d5 |
"\n""Recognized string parameters: Subject, EmailFrom, EmailTo."
|
|
Packit |
4f15d5 |
"\n""Recognized boolean parameter (VALUE should be 1/0, yes/no): SendBinaryData."
|
|
Packit |
4f15d5 |
"\n""Parameters can be overridden via $Mailx_PARAM environment variables."
|
|
Packit |
4f15d5 |
);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
enum {
|
|
Packit |
4f15d5 |
OPT_v = 1 << 0,
|
|
Packit |
4f15d5 |
OPT_d = 1 << 1,
|
|
Packit |
4f15d5 |
OPT_c = 1 << 2,
|
|
Packit |
4f15d5 |
OPT_F = 1 << 3,
|
|
Packit |
4f15d5 |
OPT_n = 1 << 4,
|
|
Packit |
4f15d5 |
OPT_D = 1 << 5,
|
|
Packit |
4f15d5 |
};
|
|
Packit |
4f15d5 |
/* Keep enum above and order of options below in sync! */
|
|
Packit |
4f15d5 |
struct options program_options[] = {
|
|
Packit |
4f15d5 |
OPT__VERBOSE(&g_verbose),
|
|
Packit |
4f15d5 |
OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Problem directory")),
|
|
Packit |
4f15d5 |
OPT_STRING('c', NULL, &conf_file , "CONFFILE", _("Config file")),
|
|
Packit |
4f15d5 |
OPT_STRING('F', NULL, &fmt_file , "FILE" , _("Formatting file for an email")),
|
|
Packit |
4f15d5 |
OPT_BOOL('n', "notify-only", NULL , _("Notify only (Do not mark the report as sent)")),
|
|
Packit |
4f15d5 |
OPT_BOOL( 'D', NULL, NULL , _("Debug")),
|
|
Packit |
4f15d5 |
OPT_END()
|
|
Packit |
4f15d5 |
};
|
|
Packit |
4f15d5 |
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
export_abrt_envvars(0);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
map_string_t *settings = new_map_string();
|
|
Packit |
4f15d5 |
load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
int flag = 0;
|
|
Packit |
4f15d5 |
if (opts & OPT_n)
|
|
Packit |
4f15d5 |
flag |= RM_FLAG_NOTIFY;
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
if (opts & OPT_D)
|
|
Packit |
4f15d5 |
flag |= RM_FLAG_DEBUG;
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
create_and_send_email(dump_dir_name, settings, fmt_file, flag);
|
|
Packit |
4f15d5 |
|
|
Packit |
4f15d5 |
free_map_string(settings);
|
|
Packit |
4f15d5 |
return 0;
|
|
Packit |
4f15d5 |
}
|