]> granicus.if.org Git - fcron/commitdiff
Added Content-Type and Content-Transfer-Encoding to output emails
authorThibault Godouet <fcron@free.fr>
Sat, 25 Sep 2010 12:39:14 +0000 (13:39 +0100)
committerThibault Godouet <fcron@free.fr>
Sat, 25 Sep 2010 12:41:18 +0000 (13:41 +0100)
database.c
doc/en/fcrontab.5.sgml
doc/en/todo.sgml
fcron.c
fcron.h
global.h
job.c
job.h

index c48687ed579dcd6a473c4465f97759f4f8923787..4639ed6f93c3dc0cef54492ec84fa923be9a806a 100644 (file)
@@ -1360,7 +1360,7 @@ mail_notrun(cl_t *line, char context, struct tm *since)
     memcpy(&time, time2, sizeof(time));
 
     /* create a temp file, and write in it the message to send */
-    mailf = create_mail(line, "Non-execution of fcron job", NULL);
+    mailf = create_mail(line, "Non-execution of fcron job", NULL, NULL, NULL);
 
     switch ( context ) {
     case SYSDOWN:
@@ -1400,7 +1400,7 @@ mail_notrun(cl_t *line, char context, struct tm *since)
     }
     
     /* become user (for security reasons) */
-    change_user_setup_env(line, &sendmailenv, NULL, NULL, NULL);
+    change_user_setup_env(line, &sendmailenv, NULL, NULL, NULL, NULL, NULL);
 
     /* then, send mail */
     launch_mailer(line, mailf, sendmailenv);
index 8f1f57a9e61974a17c9cc46c8c814413580626be..89c93f9765a3d54eebe1ea5ee27b4a3283e6ab33 100644 (file)
@@ -72,6 +72,7 @@ command is extracted. TZ is also defined to the value of the option timezone whe
 overridden by settings in the &fcrontabf;, but <envar>USER</envar> may not.
 Every other environment assignments defined in the user &fcrontabf; are then
 made, and the command is executed.</para>
+            <para>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 <link linkend="fcron.8">&fcron;(8)</link> 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.</para>
            <para>Plus, the special variable <varname>MAILTO</varname> allows
 you to tell &fcron; to whom it has to mail the command's output. Note that
 <varname>MAILTO</varname> is in fact equivalent to a global declaration of the
index 28ff39374761d2298d7efd1956916f2ed27dd9e0..d336187f69ea21b90cc250ed4bf3e1e42c3c275a 100644 (file)
@@ -25,13 +25,19 @@ A copy of the license is included in gfdl.sgml.
         <title>High priority</title>
         <itemizedlist>
            <listitem>
-              <para>could be worth checking fcron for memory leaks using specialized library (just in case...)</para>
+              <para>add audit (libaudit)</para>
            </listitem>
            <listitem>
-              <para>option to put a maximum limit on the execution time of a task + terminate it if not finished yet + send email to let the user know</para>
+              <para>Use directory notifications (FAM) / inotify, and support a fcrontab
+              and a cron.d as Vixie cron does (directly included in fcron itself, not thanks to a script as now).
+               However the parsing work is done by fcrontab, and should probably keep on being done by fcrontab for
+               security and stability reasons: have fcron call fcrontab to do that job?</para>
            </listitem>
            <listitem>
-              <para>jitter feature: if 100 jobs to be started at the same minute, then make them start at a random second of that minute to limit load spikes (see BSD cron jitter feature)</para>
+              <para>could be worth checking fcron for memory leaks using specialized library (just in case...)</para>
+           </listitem>
+           <listitem>
+              <para>option to put a maximum limit on the execution time of a task + terminate it if not finished yet + send email to let the user know</para>
            </listitem>
            <listitem>
               <para>setting to limit the number of jobs of a single user in the serialq/lavgq to X jobs + make sure root always has Y slots that it can use in those queues (i.e. number of slots used by root + number of free slots >= Y)</para>
@@ -47,6 +53,9 @@ A copy of the license is included in gfdl.sgml.
       <sect2>
         <title>Low priority</title>
         <itemizedlist>
+           <listitem>
+              <para>use readline (if available) for fcrondyn.</para>
+           </listitem>
            <listitem>
               <para>add logging to a file (instead of syslog) with configuration in fcron.conf</para>
            </listitem>
@@ -67,10 +76,6 @@ A copy of the license is included in gfdl.sgml.
               <para>add a return code for jobs which would mean that they
                  should not be run again (in case of an error, etc...).</para>
            </listitem>
-           <listitem>
-              <para>Use directory notifications (FAM), and support a fcrontab 
-              and a cron.d as Vixie cron does (directly included in fcron itself, not thanks to a script as now).</para>
-           </listitem>
            <listitem>
               <para>PAM support (included in fcron, but needs more tests by
                  people using PAM - not implemented in fcrondyn: is it needed
@@ -79,9 +84,6 @@ A copy of the license is included in gfdl.sgml.
            <listitem>
               <para>support for per user serial queue (especially for root)</para>
            </listitem>
-           <listitem>
-              <para>use readline (if available) for fcrondyn.</para>
-           </listitem>
            <listitem>
               <para>add a mailsubject option, for custom mail subjects (for instance, in case of a job containing something secret -- password, etc -- in the command line).</para>
            </listitem>
diff --git a/fcron.c b/fcron.c
index 7363063dac68600f71328e1c03ad91c50bb29782..380020e72893953aa13a26b63c54c8cdbb4925d4 100644 (file)
--- a/fcron.c
+++ b/fcron.c
@@ -65,6 +65,10 @@ char once = 0;      /* set to 1 if fcron shall return immediately after running
                     * all jobs that are due at the time when fcron is started */
 char dosyslog = 1;  /* set to 1 when we log messages to syslog, else 0 */
 
+/* Get the default locale character set for the mail
+ * "Content-Type: ...; charset=" header */
+char default_mail_charset[TERM_LEN] = "";
+
 /* used in temp_file() : create it in current dir (normally spool dir) */
 char *tmp_path = "";
 
@@ -505,6 +509,7 @@ sigusr2_handler(int x)
 int
 main(int argc, char **argv)
 {
+    char *codeset = NULL;
 
     rootuid = get_user_uid_safe(ROOTNAME);
     rootgid = get_group_gid_safe(ROOTGROUP);
@@ -541,6 +546,17 @@ main(int argc, char **argv)
     if (chdir(fcrontabs) != 0)
        die_e("Could not change dir to %s", fcrontabs);
     
+    /* Get the default locale character set for the mail
+     * "Content-Type: ...; charset=" header */
+    setlocale(LC_ALL,""); /* set locale to system defaults or to
+                             that specified by any  LC_* env vars */
+    /* Except that "US-ASCII" is preferred to "ANSI_x3.4-1968" in MIME,
+     * even though "ANSI_x3.4-1968" is the official charset name. */
+    if ( (codeset = nl_langinfo(CODESET)) != 0L &&
+            strcmp(codeset, "ANSI_x3.4-1968") != 0 )
+        strncpy(default_mail_charset, codeset, sizeof(default_mail_charset));
+    else
+        strcpy(default_mail_charset, "US-ASCII");
 
     if ( freopen("/dev/null", "r", stdin) == NULL )
         error_e("Could not open /dev/null as stdin");
diff --git a/fcron.h b/fcron.h
index d2abe88b28e9c04a5289029b64cef7a93dcf0706..00527f4e616a471e36d2cc86c51baecaa9a576bc 100644 (file)
--- a/fcron.h
+++ b/fcron.h
@@ -65,6 +65,7 @@
 extern time_t now;
 extern char foreground;
 extern char dosyslog;
+extern char default_mail_charset[TERM_LEN];
 extern time_t first_sleep;
 extern char *cdir;
 extern pid_t daemon_pid;
index 25e631615e15459d716ac5d394e3f116beb99780..3c2491f789d95b0add730d22a4eb3639f40d7399 100644 (file)
--- a/global.h
+++ b/global.h
@@ -62,6 +62,9 @@
 #include <limits.h>
 #endif
 
+#include <locale.h>
+#include <nl_types.h>
+#include <langinfo.h>
 #include <pwd.h>
 #include <signal.h>
 
diff --git a/job.c b/job.c
index e7f1b8fe46c81eb182b804e4c97ea3b675954dde..1e7e49671dea47e2fda640631481137181a34d78 100644 (file)
--- a/job.c
+++ b/job.c
@@ -56,7 +56,7 @@ die_mail_pame(cl_t *cl, int pamerrno, struct passwd *pas, char *str, env_list_t
 
     if (is_mail(cl->cl_option)) {
         char **envp = env_list_export_envp(env);
-       FILE *mailf = create_mail(cl, "Could not run fcron job", envp);
+       FILE *mailf = create_mail(cl, "Could not run fcron job", NULL, NULL, envp);
 
        /* print the error in both syslog and a file, in order to mail it to user */
        if (dup2(fileno(mailf), 1) != 1 || dup2(1, 2) != 2)
@@ -111,7 +111,8 @@ become_user(struct cl_t *cl, struct passwd *pas, char *home)
 
 void
 setup_user_and_env(struct cl_t *cl, struct passwd *pas,
-                   char ***sendmailenv, char ***jobenv, char **curshell, char **curhome)
+                   char ***sendmailenv, char ***jobenv, char **curshell,
+                   char **curhome, char **content_type, char **encoding)
 /* Check PAM authorization, and setup the environment variables
  * to run sendmail and to run the job itself. Change dir to HOME and check if SHELL is ok */
 /* (*curshell) and (*curhome) will be allocated and should thus be freed
@@ -223,18 +224,25 @@ setup_user_and_env(struct cl_t *cl, struct passwd *pas,
         if  ( curshell != NULL )
             *curshell = strdup2(myshell);
 
-        if (jobenv != NULL)
-            *jobenv = env_list_export_envp(env_list);
+        *jobenv = env_list_export_envp(env_list);
 
-        env_list_destroy(env_list);
+    }
 
+    if ( content_type != NULL ) {
+        (*content_type) = strdup2(env_list_getenv(env_list, "CONTENT_TYPE"));
+    }
+    if ( encoding != NULL ) {
+        (*encoding) = strdup2(env_list_getenv(env_list, "CONTENT_TRANSFER_ENCODING"));
     }
 
+    env_list_destroy(env_list);
+
 }
 
 void
 change_user_setup_env(struct cl_t *cl,
-                   char ***sendmailenv, char ***jobenv, char **curshell, char **curhome)
+                   char ***sendmailenv, char ***jobenv, char **curshell,
+                   char **curhome, char **content_type, char **encoding)
 /* call setup_user_and_env() and become_user().
  * As a result, *curshell and *curhome will be allocated and should thus be freed
  * if curshell and curhome are not NULL. */
@@ -246,7 +254,8 @@ change_user_setup_env(struct cl_t *cl,
     if ( pas == NULL )
         die_e("failed to get passwd fields for user \"%s\"", cl->cl_runas);
 
-    setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome);
+    setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome,
+                       content_type, encoding);
     become_user(cl, pas, *curhome);
     free_safe(*curhome);
 }
@@ -265,7 +274,8 @@ sig_dfl(void)
 
 
 FILE *
-create_mail(cl_t *line, char *subject, char **env)
+create_mail(cl_t *line, char *subject, char *content_type, char *encoding,
+            char **env)
     /* create a temp file and write in it a mail header */
 {
     /* create temporary file for stdout and stderr of the job */
@@ -308,6 +318,35 @@ create_mail(cl_t *line, char *subject, char **env)
        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",
+                default_mail_charset);
+    }
+    else {
+        /* user specified Content-Type header. */
+        char *c = NULL;
+
+        /* Remove new-lines or users could specify arbitrary mail headers!
+         * (fcrontab should already prevent that, but better safe than sorry) */
+        for (c=content_type; *c != '\0'; c++) {
+            if (*c == '\n')
+                *c = ' ';
+        }
+        fprintf(mailf, "Content-Type: %s\n", content_type);
+    }
+
+    if (encoding != NULL) {
+        char *c = NULL;
+
+        /* Remove new-lines or users could specify arbitrary mail headers!
+         * (fcrontab should already prevent that, but better safe than sorry) */
+        for (c=encoding; *c != '\0'; c++) {
+            if (*c == '\n')
+                *c = ' ';
+        }
+        fprintf(mailf, "Content-Transfer-Encoding: %s\n", encoding);
+    }
+
     /* Add headers so as automated systems can identify that this message
      * is an automated one sent by fcron.
      * That's useful for example for vacation auto-reply systems: no need
@@ -489,6 +528,8 @@ run_job(struct exe_t *exeent)
         char **sendmailenv = NULL;
         char *curshell = NULL;
         char *curhome = NULL;
+        char *content_type = NULL;
+        char *encoding = NULL;
         FILE *mailf = NULL;
         int status = 0;
         int to_stdout = foreground && is_stdout(line->cl_option);
@@ -511,7 +552,8 @@ run_job(struct exe_t *exeent)
         if ( pas == NULL )
             die_e("failed to get passwd fields for user \"%s\"", line->cl_runas);
 
-        setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell, &curhome);
+        setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell,
+                           &curhome, &content_type, &encoding);
 
        /* close unneeded READ fd */
        if ( close(pipe_pid_fd[0]) < 0 )
@@ -523,7 +565,7 @@ run_job(struct exe_t *exeent)
             * as temp_file() needs root privileges */
            /* if we run in foreground, stdout and stderr point to the console.
             * Otherwise, stdout and stderr point to /dev/null . */
-           mailf = create_mail(line, NULL, jobenv);
+           mailf = create_mail(line, NULL, content_type, encoding, jobenv);
            mailpos = ftell(mailf);
            if (pipe(pipe_fd) != 0) 
                die_e("could not pipe() (job not executed)");
diff --git a/job.h b/job.h
index ff90a19839d15c83590fe5961f6d2fe6e5d8bf5c..3ed051b69286b1be39afbb2473050b058489ae43 100644 (file)
--- a/job.h
+++ b/job.h
 
 /* functions prototypes */
 extern void change_user_setup_env(struct cl_t *cl, char ***sendmailenv,
-                        char ***jobenv, char **curshell, char **curhome);
+                        char ***jobenv, char **curshell, char **curhome,
+                        char **content_type, char **encoding);
 extern int run_job(struct exe_t *exeent);
-extern FILE *create_mail(struct cl_t *line, char *subject, char **env);
+extern FILE *create_mail(struct cl_t *line, char *subject, char *content_type,
+                         char *encoding, char **env);
 extern void launch_mailer(struct cl_t *line, FILE *mailf, char **env);
 
 #endif /* __JOB_H__ */