From: Thibault Godouet Date: Sun, 12 Oct 2014 10:20:04 +0000 (+0100) Subject: Set From: header on emails. Added mailfrom() option. X-Git-Tag: ver3_3_0~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d15e6df82f7986b1225fcaa38fff2b4c7c2d30eb;p=thirdparty%2Ffcron.git Set From: header on emails. Added mailfrom() option. --- diff --git a/cl.c b/cl.c index a02c9bc..3280b98 100644 --- a/cl.c +++ b/cl.c @@ -51,7 +51,9 @@ dups_cl(cl_t * orig) debug("%s: Set cl->cl_runas=%s", __func__, (cl->cl_runas == NULL) ? "null" : cl->cl_runas); + cl->cl_mailfrom = NULL; cl->cl_mailto = NULL; + Set(cl->cl_mailfrom, orig->cl_mailfrom); Set(cl->cl_mailto, orig->cl_mailto); cl->cl_tz = NULL; @@ -67,6 +69,7 @@ free_line(cl_t * cl) if (cl != NULL) { Free_safe(cl->cl_shell); Free_safe(cl->cl_runas); + Free_safe(cl->cl_mailfrom); Free_safe(cl->cl_mailto); Free_safe(cl->cl_tz); Free_safe(cl); diff --git a/cl.h b/cl.h index 0dde2d5..1a2def5 100644 --- a/cl.h +++ b/cl.h @@ -41,6 +41,7 @@ typedef struct cl_t { struct cf_t *cl_file; /* the file in which the line is */ char *cl_shell; /* shell command */ char *cl_runas; /* determine permissions of the job */ + char *cl_mailfrom; /* use this as email From header */ char *cl_mailto; /* mail output to cl_mailto */ char *cl_tz; /* time zone of the line */ unsigned long cl_id; /* line's unique id number */ diff --git a/conf.c b/conf.c index 5f808d1..1ac0ba8 100644 --- a/conf.c +++ b/conf.c @@ -652,6 +652,11 @@ read_file(const char *file_name, cf_t * cf, int is_system_startup) Read_strn(cl->cl_runas, size, "Error while reading runas field"); break; + case S_MAILFROM_T: + Read_strn(cl->cl_mailfrom, size, + "Error while reading mailfrom field"); + break; + case S_MAILTO_T: Read_strn(cl->cl_mailto, size, "Error while reading mailto field"); break; @@ -781,6 +786,7 @@ read_file(const char *file_name, cf_t * cf, int is_system_startup) /* line is not yet in the line list of the file : free it */ Free_safe(cl->cl_shell); Free_safe(cl->cl_runas); + Free_safe(cl->cl_mailfrom); Free_safe(cl->cl_mailto); Free_safe(cl); } @@ -830,11 +836,19 @@ add_line_to_file(cl_t * cl, cf_t * cf, uid_t runas, char *runas_str, * struct cf_t may be required */ cl->cl_file = cf; - /* check if the mailto field is valid */ + /* check if the mailfrom and mailto fields are safe */ + if (cl->cl_mailfrom && (*(cl->cl_mailfrom) == '-' || + strcspn(cl->cl_mailfrom, + " \t\n;|") != strlen(cl->cl_mailfrom))) { + error + ("mailfrom field \'%s\' is not safe : unsetting to use default value.", + cl->cl_mailfrom); + Free_safe(cl->cl_mailfrom); + } if (cl->cl_mailto && (*(cl->cl_mailto) == '-' || strcspn(cl->cl_mailto, - " \t\n") != strlen(cl->cl_mailto))) { - error("mailto field \'%s\' is not valid : set to owner %s.", + " \t\n;|") != strlen(cl->cl_mailto))) { + error("mailto field \'%s\' is not safe : setting to owner %s.", cl->cl_mailto, cl->cl_file->cf_user); Set(cl->cl_mailto, cl->cl_file->cf_user); } diff --git a/convert-fcrontab.c b/convert-fcrontab.c index c40c62e..a06cfe0 100644 --- a/convert-fcrontab.c +++ b/convert-fcrontab.c @@ -116,6 +116,7 @@ delete_file(cf_t * file) while ((line = cur_line) != NULL) { cur_line = line->cl_next; Free_safe(line->cl_shell); + Free_safe(line->cl_mailfrom); Free_safe(line->cl_mailto); Free_safe(line->cl_runas); Free_safe(line); diff --git a/doc/en/changes.sgml b/doc/en/changes.sgml index 0f78fe2..d8d43ce 100644 --- a/doc/en/changes.sgml +++ b/doc/en/changes.sgml @@ -13,7 +13,15 @@ A copy of the license is included in gfdl.sgml. Changes - From version 3.1.3 to 3.2.0 + From version 3.2.0 to 3.2.1 + + add From: header to emails. Similarly to other crons, use: "From: %s (fcron)" with %s + being either the user the job is run as or the value of MAILFROM. + + + + + From version 3.1.3 to 3.2.0 Print date as %Y-%m-%d (the ISO 8601 date format), to avoid being ambiguous in international context. Also always use the ':' as hour:minute separator (there was a couple of 'h' instead). diff --git a/doc/en/fcrontab.5.sgml b/doc/en/fcrontab.5.sgml index d66b830..907101d 100644 --- a/doc/en/fcrontab.5.sgml +++ b/doc/en/fcrontab.5.sgml @@ -72,11 +72,11 @@ overridden by settings in the &fcrontabf;, but USER may not. Every other environment assignments defined in the user &fcrontabf; are then made, and the command is executed. By default, fcron will send emails using the email "Content-Type:" header of "text/plain" with the "charset=" parameter set to the charmap / codeset of the locale in which &fcron;(8) is started up - i.e. either the default system locale, if no LC_* environment variables are set, or the locale specified by the LC_* environment variables (see locale(7)). You can use different character encodings for emailed fcron job output by setting the CONTENT_TYPE and CONTENT_TRANSFER_ENCODING variables in fcrontabs, to the correct values of the mail headers of those names. - Plus, the special variable MAILTO allows -you to tell &fcron; to whom it has to mail the command's output. Note that -MAILTO is in fact equivalent to a global declaration of the -option &optmailto; (see below). It is only used for backward compatibility, so -you should use the option &optmailto; directly. + Additionally, the special variables MAILFROM and +MAILTO allow you to tell &fcron; from/to whom it should email +the command's output. Note that these are in fact equivalent to global declarations of the +options &optmailfrom; and &optmailto; (see below). They are used for backward compatibility, +and it is recommended that you use the options &optmailfrom; and &optmailto; directly instead. @@ -666,6 +666,20 @@ system load average values. + + mailfrom + + email-address(user job is run as) + Use this as the 'From:' address when mailing job outputs. + It can be either a single user-name or a fully qualified email address. + In the former case, &fcron; will add the hostname automatically. + Setting &optmailfrom; to an empty value is equivalent to +resetting it to the default value of the name of the user the job is run as. + &seealso; options &optmail;, &optforcemail;, +&opterroronlymail;, &optnolog;, &optmailto;. + + + mailto @@ -673,10 +687,11 @@ system load average values. of file's owner) Mail output (if needed) to "email-address". It can be either a single user-name -or a fully qualified email address. A &optmailto; declared and empty (string +or a fully qualified email address. In the former case, &fcron; will add the hostname automatically. +A &optmailto; declared and empty (string "") is equivalent to "mail(false)". &seealso; options &optmail;, &optforcemail;, -&opterroronlymail;, &optnolog;. +&opterroronlymail;, &optnolog;, &optmailfrom;. diff --git a/doc/en/todo.sgml b/doc/en/todo.sgml index 0c439e5..6c5956f 100644 --- a/doc/en/todo.sgml +++ b/doc/en/todo.sgml @@ -23,10 +23,6 @@ A copy of the license is included in gfdl.sgml. High priority - - add From: to emails. Similarly to other crons, use: "From: %s (fcron Daemon)" with %s - being either the user fcron runs at (typically 'fcron') or the value of MAILFROM. - Option to compile and install from git sources without generating the doc diff --git a/doc/fcron-doc.mod.in b/doc/fcron-doc.mod.in index 572e166..dee0081 100644 --- a/doc/fcron-doc.mod.in +++ b/doc/fcron-doc.mod.in @@ -94,6 +94,7 @@ lavgonce'> lavgor'> mail'> +mailfrom'> mailto'> nice'> nolog'> diff --git a/fileconf.c b/fileconf.c index 9de85c7..49a1c80 100644 --- a/fileconf.c +++ b/fileconf.c @@ -283,6 +283,7 @@ read_file(char *filename, int fd) error_e("could not fflush() file_name"); Free_safe(default_line.cl_runas); + Free_safe(default_line.cl_mailfrom); Free_safe(default_line.cl_mailto); Free_safe(default_line.cl_tz); @@ -345,10 +346,15 @@ read_env(char *ptr, cf_t * cf) return; } - /* the MAILTO assignment is, in fact, an fcron option : + /* the MAILFROM/MAILTO assignment is, in fact, an fcron option : * we don't store it in the same way. */ /* please note that we check if the mailto is valid in conf.c */ - if (strcmp(name, "MAILTO") == 0) { + if (strcmp(name, "MAILFROM") == 0) { + Set(default_line.cl_mailfrom, val); + } + else if (strcmp(name, "MAILTO") == 0) { + /* cl_mailto must not be NULL (as expected in + * conf.c:add_line_to_file()), so we check if the length is >= 0 */ if (strcmp(val, "\0") == 0) { clear_mail(default_line.cl_option); clear_mailzerolength(default_line.cl_option); @@ -868,6 +874,27 @@ read_opt(char *ptr, cl_t * cl) fprintf(stderr, " Opt : \"%s\" %d\n", opt_name, i); } + else if (strcmp(opt_name, "mailfrom") == 0) { + int len = -1; + + if (!in_brackets) { + Handle_err; + } + + /* Also please note that we check if the mailfrom is valid in conf.c */ + len = assign_option_string(&(cl->cl_mailfrom), ptr); + if (len < 0) { + Handle_err; + } + else { + ptr += len; + } + + if (debug_opt) + fprintf(stderr, " Opt : \"%s\" \"%s\"\n", opt_name, + cl->cl_mailfrom); + } + else if (strcmp(opt_name, "mailto") == 0) { int len = -1; diff --git a/job.c b/job.c index abb0405..c0f271e 100644 --- a/job.c +++ b/job.c @@ -286,42 +286,49 @@ create_mail(cl_t * line, char *subject, char *content_type, char *encoding, int mailfd = temp_file(NULL); FILE *mailf = fdopen(mailfd, "r+"); char hostname[USER_NAME_LEN]; - /* is this a complete mail address ? (ie. with a "@", not only a username) */ - char add_hostname = 0; + char *mailfrom = line->cl_runas; /* default value if not explicitely defined for that cl */ + /* hostname to add to email addresses (depending on if they have a '@') */ + char *hostname_from = ""; + char *hostname_to = ""; int i = 0; if (mailf == NULL) die_e("Could not fdopen() mailfd"); + if (line->cl_mailfrom != NULL) { + mailfrom = line->cl_mailfrom; + } + #ifdef HAVE_GETHOSTNAME - if (gethostname(hostname, sizeof(hostname)) != 0) { + /* first letter will be '@' if hostname is defined */ + if (gethostname((hostname + 1), sizeof(hostname) - 1) != 0) { error_e("Could not get hostname"); hostname[0] = '\0'; } else { /* it is unspecified whether a truncated hostname is NUL-terminated */ - hostname[USER_NAME_LEN - 1] = '\0'; + hostname[0] = '@'; + hostname[sizeof(hostname) - 1] = '\0'; - /* check if mailto is a complete mail address */ - add_hostname = (strchr(line->cl_mailto, '@') == NULL) ? 1 : 0; + /* check if mailfrom/mailto are complete email addresses */ + hostname_from = (strchr(mailfrom, '@') == NULL) ? hostname : ""; + hostname_to = (strchr(line->cl_mailto, '@') == NULL) ? hostname : ""; } #else /* HAVE_GETHOSTNAME */ hostname[0] = '\0'; #endif /* HAVE_GETHOSTNAME */ /* write mail header */ - if (add_hostname) - fprintf(mailf, "To: %s@%s\n", line->cl_mailto, hostname); - else - fprintf(mailf, "To: %s\n", line->cl_mailto); + fprintf(mailf, "From: %s%s (fcron)\n", mailfrom, hostname_from); + fprintf(mailf, "To: %s%s\n", line->cl_mailto, hostname_to); if (subject) - fprintf(mailf, "Subject: fcron <%s@%s> %s: %s\n", - line->cl_file->cf_user, (hostname[0] != '\0') ? hostname : "?", + fprintf(mailf, "Subject: fcron <%s%s> %s: %s\n", + line->cl_file->cf_user, (hostname[0] != '\0') ? hostname : "@?", subject, line->cl_shell); else - fprintf(mailf, "Subject: fcron <%s@%s> %s\n", line->cl_file->cf_user, - (hostname[0] != '\0') ? hostname : "?", line->cl_shell); + fprintf(mailf, "Subject: fcron <%s%s> %s\n", line->cl_file->cf_user, + (hostname[0] != '\0') ? hostname : "@?", line->cl_shell); if (content_type == NULL) { fprintf(mailf, "Content-Type: text/plain; charset=%s\n", diff --git a/save.c b/save.c index 7e4fe87..1311a3b 100644 --- a/save.c +++ b/save.c @@ -273,6 +273,10 @@ write_file_to_disk(int fd, struct cf_t *file, time_t time_date) Save_lint(fd, S_JITTER_T, line->cl_jitter, write_buf, &write_buf_used); } + if (line->cl_mailfrom != NULL && line->cl_mailfrom[0] != '\0') { + Save_str(fd, S_MAILFROM_T, line->cl_mailfrom, write_buf, + &write_buf_used); + } if (is_freq(line->cl_option)) { /* save the frequency to run the line */ diff --git a/save.h b/save.h index 162e9ba..883de1b 100644 --- a/save.h +++ b/save.h @@ -81,5 +81,6 @@ extern int save_file_safe(cf_t * file, char *final_path, char *prog_name, #define S_FIRST_T 2018 /* wait time before first execution */ #define S_TZ_T 2019 /* time zone of the line */ #define S_JITTER_T 2020 /* jitter of the line */ +#define S_MAILFROM_T 2021 /* use as email From header */ #endif /* __SAVE_H__ */