]> git.ipfire.org Git - thirdparty/fcron.git/commitdiff
Feature/fix email From: w/ configurable "displayname" (#17)
authorMarco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
Sat, 24 Aug 2024 15:36:38 +0000 (17:36 +0200)
committerGitHub <noreply@github.com>
Sat, 24 Aug 2024 15:36:38 +0000 (16:36 +0100)
* WIP: add displayname option

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
* Fix configure.in

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
* Restored orig configure.in + displayname opt

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
* job.c: create_mail():

Process 'displayname', etc. via new function 'make_mailbox()' as per RFC5322.

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
* Fixed wrong formatting (tabs => spaces)

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
* dev(code, doc, test): displayname handling refactored over two functions.

* code: config handling of displayname moved to a new function
  'format_displayname()' in 'fcronconf.c'; buffer overflow check added. In
  'job.c': restored old "From:" mail header behavior if no displayname; buffer
  overflow check added.
* test: added prototype support in 'Makefile' and 'test/'
* doc: reviewed and cleaned 'en/fcron.conf.5.sgml'

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
* dev(code, test): @PR #17, 3rd round.

* Makefile(s): fixed alignement with spaces
* config.in: moved displayname in "Check for fcron..." section. Removed test
    install code.
* fcronconf.c: changed format_displayname()'s arg to avoid confusion with
    globals. Use stdbool. Use aux var when assigning from
    format_displayname().
* crondyn_svr.c, fileconf.c: minimal fixes to avoid conflict with stdbool.
* fcron.conf.in: added comment for possible displayname's future default value.
* global.h: added stdbool.
* job.c: changed make_mailbox_addr()'s arg to avoid confusion with
    globals. Use stdbool.
* test/mailbox_addr.c: rewritten with simpler explicit logic -- valgrinded
    again ;-)

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
---------

Signed-off-by: Marco Emilio "sphakka" Poleggi <7766137+sphakka@users.noreply.github.com>
14 files changed:
Makefile.in
configure.in
doc/en/fcron.conf.5.sgml
doc/fcron-doc.mod.in
fcronconf.c
fcronconf.h
fcrondyn_svr.c
fileconf.c
files/fcron.conf.in
global.h
job.c
job.h
test/Makefile.in [new file with mode: 0644]
test/mailbox_addr.c [new file with mode: 0644]

index b0082dcb6af6ffe522d8877d5e29851c3256e8ea..79b1583b82cf27c5ffcd0d26cbff2e1f3b2ae490 100644 (file)
@@ -4,95 +4,96 @@
 
 # @configure_input@
 
-
 # The following should not be edited manually (use configure options)
 # If you must do it, BEWARE : some of the following is also defined
 # in config.h, so you must modify config.h AND Makefile in order
 # to set the same values in the two files.
 
-FCRON_ALLOW    = fcron.allow
-FCRON_DENY     = fcron.deny
-FCRON_CONF     = fcron.conf
+# Please, keep assignments aligned with spaces.
+FCRON_ALLOW    = fcron.allow
+FCRON_DENY     = fcron.deny
+FCRON_CONF     = fcron.conf
 
-SRCDIR         := @srcdir@
+SRCDIR        := @srcdir@
 # Useful to build packages
 # you may want to use this var with a : 'make DESTDIR=dir install'
-DESTDIR                :=
+DESTDIR       :=
 
 # Where should we install it ?
-prefix         = @prefix@
-exec_prefix    = @exec_prefix@
-DESTSBIN       = @sbindir@
-DESTBIN                = @bindir@
-ETC            = @sysconfdir@
-FCRONTABS      = @FCRONTABS@
-PIDDIR         = @PIDDIR@
-FIFODIR                = @FIFODIR@
-PIDFILE                = @PIDFILE@
-REBOOT_LOCK    = @REBOOT_LOCK@
-SUSPEND_FILE   = @SUSPEND_FILE@
-FIFOFILE       = @FIFOFILE@
-FCRON_SHELL    = @FCRON_SHELL@
-SENDMAIL       = @SENDMAIL@
-FCRON_EDITOR   = @FCRON_EDITOR@
-OPTIM          := @CFLAGS@
-LDFLAGS                := @LDFLAGS@
-CPPFLAGS       := @CPPFLAGS@ -I. -I${SRCDIR}
-LIBS           := @LIBS@
-LIBOBJS                := @LIBOBJS@
-DEFS           := @DEFS@ 
-CC             := @CC@
-INSTALL                := @INSTALL@
-STRIP          := @STRIP@
-ROOTNAME       := @ROOTNAME@
-ROOTGROUP      := @ROOTGROUP@
-USERNAME       := @USERNAME@
-GROUPNAME      := @GROUPNAME@
-SYSFCRONTAB    := @SYSFCRONTAB@
-DEBUG          := @DEBUG@
-BOOTINSTALL    := @BOOTINSTALL@
-ANSWERALL      := @ANSWERALL@
-USEPAM         := @USEPAM@
-FCRONDYN       := @FCRONDYN@
-SYSTEMD_DIR     := @SYSTEMD_DIR@
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+DESTSBIN       = @sbindir@
+DESTBIN        = @bindir@
+ETC            = @sysconfdir@
+FCRONTABS      = @FCRONTABS@
+PIDDIR         = @PIDDIR@
+FIFODIR        = @FIFODIR@
+PIDFILE        = @PIDFILE@
+REBOOT_LOCK    = @REBOOT_LOCK@
+SUSPEND_FILE   = @SUSPEND_FILE@
+FIFOFILE       = @FIFOFILE@
+FCRON_SHELL    = @FCRON_SHELL@
+SENDMAIL       = @SENDMAIL@
+FCRON_EDITOR   = @FCRON_EDITOR@
+OPTIM         := @CFLAGS@
+LDFLAGS       := @LDFLAGS@
+CPPFLAGS      := @CPPFLAGS@ -I. -I${SRCDIR}
+LIBS          := @LIBS@
+LIBOBJS       := @LIBOBJS@
+DEFS          := @DEFS@
+CC            := @CC@
+INSTALL       := @INSTALL@
+STRIP         := @STRIP@
+ROOTNAME      := @ROOTNAME@
+ROOTGROUP     := @ROOTGROUP@
+USERNAME      := @USERNAME@
+GROUPNAME     := @GROUPNAME@
+SYSFCRONTAB   := @SYSFCRONTAB@
+DEBUG         := @DEBUG@
+BOOTINSTALL   := @BOOTINSTALL@
+ANSWERALL     := @ANSWERALL@
+USEPAM        := @USEPAM@
+FCRONDYN      := @FCRONDYN@
+SYSTEMD_DIR   := @SYSTEMD_DIR@
+DISPLAYNAME   := @DISPLAYNAME@
 
 # Options
-#      -DDEBUG         even more verbose
-#      -DCHECKJOBS     send a mail containing the exact shell command
-#                      for each execution of each job.
-#      -DFOREGROUND=[0|1]    default run in foreground ?
-#OPTION=       -DCHECKJOBS
-#OPTION=       -O3 -mcpu=i686
-OPTION := 
+#   -DDEBUG             even more verbose
+#   -DCHECKJOBS         send a mail containing the exact shell command
+#                       for each execution of each job.
+#   -DFOREGROUND=[0|1]  default run in foreground ?
+#OPTION        = -DCHECKJOBS
+#OPTION        = -O3 -mcpu=i686
+OPTION        :=
 
 
 ####################################
 # Should not be changed under this #
 ####################################
 
-VERSION := @VERSION@
-CFLAGS += $(OPTIM) $(OPTION) $(DEFS) $(CPPFLAGS) $(LDFLAGS)
+VERSION       := @VERSION@
+CFLAGS        += $(OPTIM) $(OPTION) $(DEFS) $(CPPFLAGS) $(LDFLAGS)
 ifeq ($(FCRONDYN), 1)
-LIBOBJS := $(LIBOBJS)
+       LIBOBJS   := $(LIBOBJS)
 endif
-OBJSD := fcron.o cl.o subs.o mem.o save.o temp_file.o log.o database.o job.o conf.o u_list.o exe_list.o lavg_list.o env_list.o fcronconf.o filesubs.o select.o fcrondyn_svr.o suspend.o $(LIBOBJS)
-OBJSTAB := fcrontab.o cl.o subs.o mem.o save.o temp_file.o  log.o fileconf.o allow.o read_string.o u_list.o env_list.o fcronconf.o filesubs.o
-OBJSDYN := fcrondyn.o subs.o mem.o log.o allow.o read_string.o fcronconf.o filesubs.o
-OBJCONV := convert-fcrontab.o cl.o subs.o mem.o save.o log.o u_list.o env_list.o fcronconf.o filesubs.o
-OBJSIG := fcronsighup.o subs.o mem.o log.o allow.o fcronconf.o filesubs.o
-HEADERSALL := config.h $(SRCDIR)/global.h $(SRCDIR)/cl.h $(SRCDIR)/log.h $(SRCDIR)/subs.h $(SRCDIR)/mem.h $(SRCDIR)/save.h $(SRCDIR)/option.h $(SRCDIR)/dyncom.h
+OBJSD         := fcron.o cl.o subs.o mem.o save.o temp_file.o log.o database.o job.o conf.o u_list.o exe_list.o lavg_list.o env_list.o fcronconf.o filesubs.o select.o fcrondyn_svr.o suspend.o $(LIBOBJS)
+OBJSTAB       := fcrontab.o cl.o subs.o mem.o save.o temp_file.o  log.o fileconf.o allow.o read_string.o u_list.o env_list.o fcronconf.o filesubs.o
+OBJSDYN       := fcrondyn.o subs.o mem.o log.o allow.o read_string.o fcronconf.o filesubs.o
+OBJCONV       := convert-fcrontab.o cl.o subs.o mem.o save.o log.o u_list.o env_list.o fcronconf.o filesubs.o
+OBJSIG        := fcronsighup.o subs.o mem.o log.o allow.o fcronconf.o filesubs.o
+HEADERSALL    := config.h $(SRCDIR)/global.h $(SRCDIR)/cl.h $(SRCDIR)/log.h $(SRCDIR)/subs.h $(SRCDIR)/mem.h $(SRCDIR)/save.h $(SRCDIR)/option.h $(SRCDIR)/dyncom.h
 
 # this is a regular expression :
 # do not ci automaticaly generated files and doc (done by doc's Makefile)
-RCSNOCI:=.*\(.html\|VERSION\|MANIFEST\|configure\|install.sh\|config.log\|config.status\|config.h\|config.cache\|Makefile\|doc.*\|CVS.*\|.git.*\)
+RCSNOCI       := .*\(.html\|VERSION\|MANIFEST\|configure\|install.sh\|config.log\|config.status\|config.h\|config.cache\|Makefile\|doc.*\|CVS.*\|.git.*\)
 
 RUN_NON_PRIVILEGED := @RUN_NON_PRIVILEGED@
 ifeq ($(RUN_NON_PRIVILEGED), 1)
-       BINMODE:=711
-       BINMODESIGHUP:=711
+       BINMODE        := 711
+       BINMODESIGHUP  := 711
 else
-       BINMODE:=6711
-       BINMODESIGHUP:=4710
+       BINMODE        := 6711
+       BINMODESIGHUP  := 4710
 endif
 
 ifeq ($(FCRONDYN), 1)
@@ -126,7 +127,7 @@ exe_list_test: exe_list.o u_list.o exe_list_test.o log.o subs.o
        -DFCRONTABS="\"${FCRONTABS}\"" \
        -DFCRON_ALLOW="\"${FCRON_ALLOW}\"" -DFCRON_DENY="\"${FCRON_DENY}\"" \
        -DFCRON_SHELL="\"${FCRON_SHELL}\"" -DSENDMAIL="\"${SENDMAIL}\"" \
-       -DFCRON_EDITOR="\"${FCRON_EDITOR}\"" -DBINDIREX="\"${DESTBIN}\"" \
+       -DFCRON_EDITOR="\"${FCRON_EDITOR}\"" \-DDISPLAYNAME="\"${DISPLAYNAME}\"" -DBINDIREX="\"${DESTBIN}\"" \
        -c $<
 
 initscripts:
@@ -138,7 +139,12 @@ initscripts:
 documentation:
        $(MAKE) -C doc doc-if-none
 
-install: install-staged strip perms 
+.PHONY: test
+test:
+       $(MAKE) -C test tests
+
+
+install: install-staged strip perms
 ifeq ($(BOOTINSTALL), 1)
        $(SRCDIR)/script/boot-install "$(INSTALL) -o $(ROOTNAME)" $(DESTSBIN) $(DEBUG) $(FCRONTABS) $(ANSWERALL) $(SRCDIR)
 endif
@@ -180,16 +186,16 @@ endif
 perms: install-staged strip
 # Note : we don't use "chown user:group file" because some systems use ":"
 #        and others "." as separator.
-       chown $(ROOTNAME) $(DESTDIR)$(DESTSBIN) 
-       chgrp $(ROOTGROUP) $(DESTDIR)$(DESTSBIN) 
-       chown $(ROOTNAME) $(DESTDIR)$(DESTBIN) 
-       chgrp $(ROOTGROUP) $(DESTDIR)$(DESTBIN) 
-       chown $(ROOTNAME) $(DESTDIR)$(ETC) 
-       chgrp $(ROOTGROUP) $(DESTDIR)$(ETC) 
-       chown $(ROOTNAME) $(DESTDIR)$(FIFODIR) 
-       chgrp $(ROOTGROUP) $(DESTDIR)$(FIFODIR) 
-       chown $(ROOTNAME) $(DESTDIR)$(PIDDIR) 
-       chgrp $(ROOTGROUP) $(DESTDIR)$(PIDDIR) 
+       chown $(ROOTNAME) $(DESTDIR)$(DESTSBIN)
+       chgrp $(ROOTGROUP) $(DESTDIR)$(DESTSBIN)
+       chown $(ROOTNAME) $(DESTDIR)$(DESTBIN)
+       chgrp $(ROOTGROUP) $(DESTDIR)$(DESTBIN)
+       chown $(ROOTNAME) $(DESTDIR)$(ETC)
+       chgrp $(ROOTGROUP) $(DESTDIR)$(ETC)
+       chown $(ROOTNAME) $(DESTDIR)$(FIFODIR)
+       chgrp $(ROOTGROUP) $(DESTDIR)$(FIFODIR)
+       chown $(ROOTNAME) $(DESTDIR)$(PIDDIR)
+       chgrp $(ROOTGROUP) $(DESTDIR)$(PIDDIR)
 
 # change spool dir mode
        chown $(USERNAME) $(DESTDIR)$(FCRONTABS)
@@ -245,7 +251,7 @@ ifeq ($(FCRONDYN), 1)
 endif
 endif
 
-install-boot: install 
+install-boot: install
        $(SRCDIR)/script/boot-install "$(INSTALL) -o $(ROOTNAME)" $(DESTSBIN) $(DEBUG) $(FCRONTABS)  $(ANSWERALL) $(SRCDIR)
 
 install-restart: install
@@ -266,6 +272,7 @@ clean:
        rm -f *.o core
        rm -f fcron fcrontab fcrondyn fcronsighup convert-fcrontab files/fcron.conf
        $(MAKE) -C doc clean
+       $(MAKE) -C test clean
 
 ciclean: clean
        find ./ -name "*~" -exec rm -f {} \;
@@ -276,6 +283,7 @@ vclean: ciclean
             files/fcron.conf script/fcron.init.suse script/fcron.init.systemd script/fcron.init.systemd.reboot \
             script/fcron.sh script/sysVinit-launcher
        $(MAKE) -C doc clean
+       $(MAKE) -C test clean
 
 
 files/fcron.conf: $(SRCDIR)/files/fcron.conf.in config.h
@@ -291,7 +299,7 @@ indent:
             --dont-cuddle-else *.c *.h
 
 configure: configure.in
-# update configure script, then Makefile and config.h, and finally 
+# update configure script, then Makefile and config.h, and finally
 # run make tar using the new Makefile (needed because the version
 # is set in the configure.in file)
        autoconf
index 6fc44e155f9cf78b6669132584083748dff16270..7ef4b45c2b707ee1bf655b7040ab54e2b5cccc00 100644 (file)
@@ -94,10 +94,10 @@ AC_CHECK_LIB(kstat, kstat_open, [kstat=1], [kstat=0])
 if test $getloadavg -eq 1; then
 dnl Nothing to do ...
   AC_FUNC_GETLOADAVG
-  AC_MSG_CHECKING(function to use for lavg* options)  
+  AC_MSG_CHECKING(function to use for lavg* options)
   AC_MSG_RESULT(getloadavg())
 elif test $kstat -eq 1;  then
-  AC_MSG_CHECKING(function to use for lavg* options)  
+  AC_MSG_CHECKING(function to use for lavg* options)
   LIBS="$LIBS -lkstat"
   AC_LIBOBJ([getloadavg])
   AC_DEFINE_UNQUOTED(HAVE_KSTAT, 1)
@@ -105,7 +105,7 @@ elif test $kstat -eq 1;  then
 else
 dnl Try to use the /proc/loadavg file ...
   AC_FUNC_GETLOADAVG
-  AC_MSG_CHECKING(function to use for lavg* options)  
+  AC_MSG_CHECKING(function to use for lavg* options)
   AC_MSG_RESULT(/proc/loadavg)
 fi
 AC_CHECK_FUNCS(getcwd gettimeofday mktime putenv strerror setenv unsetenv gethostname)
@@ -167,7 +167,7 @@ dnl ---------------------------------------------------------------------
 fcron_enable_checks=yes
 AC_ARG_ENABLE(checks,
 [  --disable-checks   Don't verify that programs exist on the host ], dnl '
-[ case "$enableval" in 
+[ case "$enableval" in
    no)
      fcron_enable_checks=no
      ;;
@@ -179,7 +179,11 @@ AC_ARG_ENABLE(checks,
      ;;
   esac
 ])
-     
+
+DISPLAYNAME=
+AC_MSG_RESULT([$DISPLAYNAME])
+AC_SUBST([DISPLAYNAME])
+
 
 dnl ---------------------------------------------------------------------
 dnl Programs ...
@@ -287,6 +291,7 @@ fi
 AC_MSG_RESULT([$FCRON_EDITOR])
 AC_SUBST([FCRON_EDITOR])
 
+
 dnl ---------------------------------------------------------------------
 dnl Paths ...
 
@@ -364,7 +369,7 @@ AC_ARG_WITH(proc,
 [ case "$withval" in
   no)
     AC_MSG_WARN([
-Without proc, you won't be able to use the lavg* options 
+Without proc, you won't be able to use the lavg* options
 ])
     AC_DEFINE(NOLOADAVG)
     ;;
@@ -450,7 +455,7 @@ AC_ARG_WITH(run-non-privileged,
     AC_MSG_WARN([
 
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-WARNING : 
+WARNING :
        This option allows a non privileged user to run fcron. When used,
        fcron does not change its rights before running a job (i.e.,
        if joe runs fcron, every job will run as joe).
@@ -558,7 +563,7 @@ AC_ARG_WITH(rootname,
   *)
        rootname=$withval
     ;;
-  esac 
+  esac
 ])
 
 if test $fcron_enable_checks = 'yes'; then
@@ -891,13 +896,13 @@ AC_ARG_WITH(pam,
     AC_MSG_ERROR(Must be set to either "yes" or "no".)
     ;;
   esac ],
-  if test "$usepam" = "1"; then 
+  if test "$usepam" = "1"; then
     AC_MSG_RESULT(yes)
     AC_CHECK_LIB(pam, pam_acct_mgmt)
   else
     usepam=0
     AC_MSG_RESULT(no)
-  fi    
+  fi
 )
 if test "$usepam" != "0" && echo "$LIBS" | grep -- "-lpam" > /dev/null ; then
   usepam=1
@@ -926,7 +931,7 @@ AC_ARG_WITH(selinux,
     else
        AC_MSG_RESULT(not available)
         AC_MSG_ERROR([
-  You requested the use of SELinux, but SELinux is considered 
+  You requested the use of SELinux, but SELinux is considered
   as not available by configure script.
 ])
     fi
@@ -966,7 +971,7 @@ AC_MSG_CHECKING(Looking for docbook2man converter)
 AC_ARG_WITH(db2man,
 [ --with-db2man=PATH(or 'no')  set PATH to a docbook2man converter.],
 [ case "$withval" in
-  no) 
+  no)
     DB2MAN=""
     AC_MSG_RESULT(none)
     ;;
@@ -995,7 +1000,7 @@ AC_ARG_WITH(db2man-spec,
 [ --with-db2man-spec=PATH      set the PATH to docbook2man-spec file
                                (needed if no db2man converter is set).],
 [ case "$withval" in
-  no) 
+  no)
     DB2MAN_SPEC=""
     AC_MSG_RESULT(none)
     ;;
@@ -1037,7 +1042,7 @@ AC_MSG_CHECKING(Looking for dsssl stylsheets)
 AC_ARG_WITH(dsssl-dir,
 [ --with-dsssl-dir=DIR change the default location of DSSSL stylesheets.],
 [ case "$withval" in
-  no) 
+  no)
     DSSSL_DIR=""
     AC_MSG_RESULT(none)
     ;;
@@ -1069,7 +1074,7 @@ dnl Final settings
 dnl ---------------------------------------------------------------------
 
 
-AC_OUTPUT(Makefile doc/Makefile doc/stylesheets/fcron-doc.dsl)
+AC_OUTPUT(Makefile doc/Makefile test/Makefile doc/stylesheets/fcron-doc.dsl)
 
 
 dnl ---------------------------------------------------------------------
@@ -1169,8 +1174,7 @@ echo "sbin dir:                           $sbindir"
 echo "spool dir:                          $sp"
 echo "etc dir:                            $sysconfdir"
 echo "doc dir:                            $docdir"
-echo "man dir:                            $mandir "
-
+echo "man dir:                            $mandir"
 
 echo
 echo "You can now run '$MAKE' to compile"
index 69c25e62a3169b08036d418e4cb4b5199dd7f70d..8f1d00d41917236504552f2d705577dbcaaa0bf3 100644 (file)
@@ -1,4 +1,4 @@
-<!-- 
+<!--
 Fcron documentation
 Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
 Permission is granted to copy, distribute and/or modify this
@@ -10,154 +10,228 @@ A copy of the license is included in gfdl.sgml.
 
 
 <refentry id="fcron.conf.5">
-    <refmeta>
-       <refentrytitle>fcron.conf</refentrytitle>
-       <manvolnum>5</manvolnum>
-       <refmiscinfo>Fcron &version; <![%devrelease; [
-(<emphasis>development</emphasis> release)]]></refmiscinfo>
-       <refmiscinfo>&date;</refmiscinfo>
-    </refmeta>
-    <refnamediv>
-       <refname>fcron.conf</refname>
-       <refpurpose>configuration file for fcron and fcrontab</refpurpose>
-    </refnamediv>
+       <refmeta>
+               <refentrytitle>fcron.conf</refentrytitle>
+               <manvolnum>5</manvolnum>
+               <refmiscinfo>Fcron &version;
+                       <![%devrelease; [(<emphasis>development</emphasis> release)]]>
+               </refmiscinfo>
+               <refmiscinfo>&date;</refmiscinfo>
+       </refmeta>
+       <refnamediv>
+               <refname>fcron.conf</refname>
+               <refpurpose>configuration file for fcron and fcrontab</refpurpose>
+       </refnamediv>
 
-    <refsect1>
-       <title>Description</title>
-       <abstract>
-           <para>This page describes the syntax used for the configuration file
-of <link linkend="fcrontab.1">&fcrontab;</link>(1), <link
-linkend="fcrondyn.1">&fcrondyn;</link>(1) and <link
-linkend="fcron.8">&fcron;</link>(8).</para>
-       </abstract>
-       <para>Blank lines, line beginning by a hash sign (#) (which are
-considered comments), leading blanks and tabs are ignored. Each line in a
-&fcron.conf; file is of the form
- <blockquote>
-               <para>name = value</para>
-           </blockquote> where the blanks around equal-sign (=) are ignored and
-optional. Trailing blanks are also ignored.
-</para>
-       <para>The following names are recognized (default value in parentheses):
-<variablelist>
-               <title>Valid variables in a fcron.conf file</title>
-               <varlistentry>
-                   <term><varname>fcrontabs</varname>=<replaceable>directory</replaceable>
-(<filename>&fcrontabsdir;</filename>)</term>
-                   <listitem>
-                       <para>&Fcron; spool directory.</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>pidfile</varname>=<replaceable>file-path</replaceable>
-(<filename>&fcron.pid;</filename>)</term>
-                   <listitem>
-                       <para>Location of &fcron; pid file (needed by &fcrontab;
-to work properly).</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>suspendfile</varname>=<replaceable>file-path</replaceable>
-(<filename>&suspendfile;</filename>)</term>
-                   <listitem>
-                       <para>Location of &fcron; suspend file. On non-Linux systems, this should be used to let fcron know how long the system was suspended (to memory or disk), so as task schedules can be updated accordingly.</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>fifofile</varname>=<replaceable>file-path</replaceable> 
-(<filename>&fcron.fifo;</filename>)</term>
-                   <listitem>
-                       <para>Location of &fcron; fifo file (needed by
-&fcrondyn; to communicate with &fcron;).</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>fcronallow</varname>=<replaceable>file-path</replaceable> 
-(<filename>&etc;/&fcron.allow;</filename>)</term>
-                   <listitem>
-                       <para>Location of fcron.allow file.</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>fcrondeny</varname>=<replaceable>file-path</replaceable> 
-(<filename>&etc;/&fcron.deny;</filename>)</term>
-                   <listitem>
-                       <para>Location of fcron.deny file.</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>shell</varname>=<replaceable>file-path</replaceable> 
-(<filename>&shell;</filename>)</term>
-                   <listitem>
-                       <para>Location of default shell called by &fcron; when
-running a job. When &fcron; runs a job, &fcron; uses the value of <envar>SHELL</envar> from the fcrontab if any, otherwise it uses the value from <filename>fcron.conf</filename> if any, or in last resort the value from <filename>/etc/passwd</filename>.</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>sendmail</varname>=<replaceable>file-path</replaceable> 
-(<filename>&sendmail;</filename>)</term>
-                   <listitem>
-                       <para>Location of mailer program called by &fcron; to
-send job output.</para>
-                   </listitem>
-               </varlistentry>
-               <varlistentry>
-                   <term><varname>editor</varname>=<replaceable>file-path</replaceable> 
-(<filename>&editor;</filename>)</term>
-                   <listitem>
-                       <para>Location of default editor used when invoking
-"fcrontab -e".</para>
-                   </listitem>
-               </varlistentry>
-           </variablelist> File-paths and directories are complete and absolute
-(i.e. beginning by a "/").</para>
-       <para>To run several instances of &fcron; simultaneously on the same
-system, you must use a different configuration file for each instance. Each
-instance must have a different <varname>fcrontabs</varname>,
-<varname>pidfile</varname> and <varname>fifofile</varname>. Then, use <link
-linkend="fcron.8">&fcron;</link>(8)'s command line option
-<parameter>-c</parameter> to select which config file (so which instance) you
-refer to.</para>
-    </refsect1>
+       <refsect1>
+               <title>Description</title>
+               <abstract>
+                       <para>
+                               This page describes the syntax used for the configuration file
+                               of <link linkend="fcrontab.1">&fcrontab;</link>(1),
+                               <link linkend="fcrondyn.1">&fcrondyn;</link>(1) and
+                               <link linkend="fcron.8">&fcron;</link>(8).
+                       </para>
+               </abstract>
+               <para>
+                       Blank lines, line beginning by a hash sign (#) (which are
+                       considered comments), leading blanks and tabs are ignored. Each line in a
+                       &fcron.conf; file is of the form
+                       <blockquote>
+                               <para>name = value</para>
+                       </blockquote>
+                       where the blanks around equal-sign (=) are ignored and
+                       optional. Trailing blanks are also ignored.
+               </para>
+               <para>
+                       The following names are recognized (default value in parentheses):
+                       <variablelist>
+                               <title>Valid variables in a fcron.conf file</title>
+                               <varlistentry>
+                                       <term>
+                                               <varname>fcrontabs</varname>=<replaceable>directory</replaceable>
+                                               (<filename>&fcrontabsdir;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>&Fcron; spool directory.</para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>pidfile</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&fcron.pid;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>
+                                                       Location of &fcron; pid file (needed by &fcrontab;
+                                                       to work properly).
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>suspendfile</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&suspendfile;</filename>)</term>
+                                       <listitem>
+                                               <para>
+                                                       Location of &fcron; suspend file. On non-Linux
+                                                       systems, this should be used to let fcron know how
+                                                       long the system was suspended (to memory or disk),
+                                                       so as task schedules can be updated accordingly.
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>fifofile</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&fcron.fifo;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>
+                                                       Location of &fcron; fifo file (needed by
+                                                       &fcrondyn; to communicate with &fcron;).
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>fcronallow</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&etc;/&fcron.allow;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>Location of fcron.allow file.</para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>fcrondeny</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&etc;/&fcron.deny;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>Location of fcron.deny file.</para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>shell</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&shell;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>
+                                                       Location of default shell called by &fcron; when
+                                                       running a job. When &fcron; runs a job, &fcron;
+                                                       uses the value of <envar>SHELL</envar> from the
+                                                       fcrontab if any, otherwise it uses the value from
+                                                       <filename>fcron.conf</filename> if any, or in last
+                                                       resort the value from
+                                                       <filename>/etc/passwd</filename>.
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>sendmail</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&sendmail;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>
+                                                       Location of mailer program called by &fcron; to
+                                                       send job output.
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>editor</varname>=<replaceable>file-path</replaceable>
+                                               (<filename>&editor;</filename>)
+                                       </term>
+                                       <listitem>
+                                               <para>
+                                                       Location of default editor used when invoking
+                                                       "fcrontab -e".
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                               <varlistentry>
+                                       <term>
+                                               <varname>displayname</varname>=<replaceable>string</replaceable>
+                                               (<option>&displayname;</option>)
+                                       </term>
+                                       <listitem>
+                                               <para>
+                                                       Display name for the "From: " header of mails sent
+                                                       by us. N.B. &fcron has been following Vixie cron's
+                                                       default email header format which is not fully
+                                                       compliant with RFC 5322 (see <ulink
+                                                       url="https://github.com/yo8192/fcron/issues/15">Issue
+                                                       #15 </ulink>).  During this transition phase, to
+                                                       achieve full RFC compliance, you may set a display
+                                                       name. Leaving it empty will preserve the old
+                                                       behavior.
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
+                       </variablelist>
+                       File-paths and directories are complete and absolute
+                       (i.e. beginning by a "/").
+               </para>
+               <para>
+                       To run several instances of &fcron; simultaneously on the same
+                       system, you must use a different configuration file for each
+                       instance. Each instance must have a different
+                       <varname>fcrontabs</varname>, <varname>pidfile</varname> and
+                       <varname>fifofile</varname>. Then, use <link
+                       linkend="fcron.8">&fcron;</link>(8)'s command line option
+                       <parameter>-c</parameter> to select which config file (so which
+                       instance) you refer to.
+               </para>
+       </refsect1>
 
-    <refsect1>
-       <title>Files</title>
-       <variablelist>
-           <varlistentry>
-               <term><filename>&etc;/&fcron.conf.location;</filename></term>
-               <listitem>
-                   <para>Configuration file for &fcron;, &fcrontab; and
-&fcrondyn;: contains paths (spool dir, pid file) and default programs to use
-(editor, shell, etc). See <link linkend="fcron.conf.5">&fcron.conf;</link>(5) for
-more details.</para>
-               </listitem>
-           </varlistentry>
-           <varlistentry>
-               <term><filename>&etc;/&fcron.allow;</filename></term>
-               <listitem>
-                   <para>Users allowed to use &fcrontab; and &fcrondyn; (one
-name per line, special name "all" acts for everyone)</para>
-               </listitem>
-           </varlistentry>
-           <varlistentry>
-               <term><filename>&etc;/&fcron.deny;</filename></term>
-               <listitem>
-                   <para>Users who are not allowed to use &fcrontab; and
-&fcrondyn; (same format as allow file)</para>
-               </listitem>
-           </varlistentry>
-           <varlistentry>
-               <term><filename>&etc;/pam.d/fcron</filename> (or
-<filename>&etc;/pam.conf</filename>)</term>
-               <listitem>
-                   <para><productname>PAM</productname> configuration file for
-&fcron;. Take a look at &pam;(8) for more details.</para>
-               </listitem>
-           </varlistentry>
-       </variablelist>
-    </refsect1>
+       <refsect1>
+               <title>Files</title>
+               <variablelist>
+                       <varlistentry>
+                               <term><filename>&etc;/&fcron.conf.location;</filename></term>
+                               <listitem>
+                                       <para>
+                                               Configuration file for &fcron;, &fcrontab; and
+                                               &fcrondyn;: contains paths (spool dir, pid file) and
+                                               default programs to use (editor, shell, etc). See
+                                               <link linkend="fcron.conf.5">&fcron.conf;</link>(5)
+                                               for more details.
+                                       </para>
+                               </listitem>
+                       </varlistentry>
+                       <varlistentry>
+                               <term><filename>&etc;/&fcron.allow;</filename></term>
+                               <listitem>
+                                       <para>Users allowed to use &fcrontab; and &fcrondyn; (one
+                                               name per line, special name "all" acts for everyone)</para>
+                               </listitem>
+                       </varlistentry>
+                       <varlistentry>
+                               <term><filename>&etc;/&fcron.deny;</filename></term>
+                               <listitem>
+                                       <para>
+                                               Users who are not allowed to use &fcrontab; and
+                                               &fcrondyn; (same format as allow file)
+                                       </para>
+                               </listitem>
+                       </varlistentry>
+                       <varlistentry>
+                               <term><filename>&etc;/pam.d/fcron</filename> (or
+                                       <filename>&etc;/pam.conf</filename>)</term>
+                               <listitem>
+                                       <para>
+                                               <productname>PAM</productname> configuration file for
+                                               &fcron;. Take a look at &pam;(8) for more details.
+                                       </para>
+                               </listitem>
+                       </varlistentry>
+               </variablelist>
+       </refsect1>
 
-    &manpage-foot;
+       &manpage-foot;
 
 </refentry>
 
index 2963b76eef9c1b14dcfb81391ab1556a439239fa..74344b9940bf835fff4888fb17591b30517bc45f 100644 (file)
@@ -42,6 +42,7 @@
 <!ENTITY sysfcrontab "@@SYSFCRONTAB@">
 <!ENTITY rootname "@@ROOTNAME@">
 <!ENTITY rootgroup "@@ROOTGROUP@">
+<!ENTITY displayname "@@DISPLAYNAME@">
 
 <!-- shortcuts -->
 
index b19dd31cd6a7cb33ec551be4a88504b1d4cdaf13..a1c5a442ddeb8fc84c0cf32206ee97e397657e76 100644 (file)
@@ -44,6 +44,69 @@ char *fcrondeny = NULL;
 char *shell = NULL;
 char *sendmail = NULL;
 char *editor = NULL;
+char *displayname = NULL;
+
+char
+*format_displayname(char *conf_value)
+    /* Format the input string `conf_value` according to RFC5322 sec. 3.2.3.
+     * <https://datatracker.ietf.org/doc/html/rfc5322#section-3.2.3>.
+     * Returns: either the formatted displayname (possibly unchanged or empty)
+     * as a new dynamically allocated string (must be properly freed by the
+     * caller) or NULL on errors like buffer overflow. */
+{
+    bool need_quotes = false;
+    char c = '\0';
+    char *bpos = NULL, *dpos = NULL;
+    char *buf1 = NULL, *buf2 = NULL;
+
+    /* Shorter than max because of the option prefix "displayname = " */
+    const uint buf_len = LINE_LEN - 14;
+    uint cwritten = 0;
+
+    if (strlen(conf_value) == 0) return strdup2("");
+
+    buf1 = (char *)alloc_safe(buf_len * sizeof(char), "1st buffer");
+    buf2 = (char *)alloc_safe(buf_len * sizeof(char), "2nd buffer");
+
+    /* walk the conf_value and rebuild it in buf1 */
+    bpos = buf1;
+    for (dpos = conf_value; *dpos; *dpos++) {
+        c = *dpos;
+        if (strchr(SPECIAL_MBOX_CHARS, c)) {
+            /* insert escape */
+            if (c == DQUOTE) {
+                *bpos++ = BSLASH;
+                ++cwritten;
+            }
+            need_quotes = true;
+        }
+        if (cwritten >= buf_len) {
+            error("Formatted 'displayname' exceeds %u chars", buf_len);
+            Free_safe(buf1);
+            Free_safe(buf2);
+            return NULL;
+        }
+        *bpos++ = c;
+        ++cwritten;
+    }
+
+    if (need_quotes) {
+        if (snprintf(buf2, buf_len, "\"%s\"", buf1) >= buf_len){
+            error("Formatted 'displayname' exceeds %u chars", buf_len);
+            Free_safe(buf1);
+            Free_safe(buf2);
+            return NULL;
+        }
+        Free_safe(buf1);
+
+        return buf2;
+    }
+
+    /* unchanged */
+    Free_safe(buf2);
+
+    return buf1;
+}
 
 void
 init_conf(void)
@@ -66,6 +129,7 @@ init_conf(void)
     sendmail = strdup2(SENDMAIL);
 #endif
     editor = strdup2(FCRON_EDITOR);
+    displayname = strdup2(DISPLAYNAME);
 }
 
 void
@@ -82,6 +146,7 @@ free_conf(void)
     Free_safe(shell);
     Free_safe(sendmail);
     Free_safe(editor);
+    Free_safe(displayname);
 }
 
 void
@@ -188,6 +253,11 @@ read_conf(void)
         else if (strncmp(ptr1, "editor", namesize) == 0) {
             Set(editor, ptr2);
         }
+        else if (strncmp(ptr1, "displayname", namesize) == 0) {
+            char *output = format_displayname(ptr2);
+            Set(displayname, output ? output : "");
+            Free_safe(output);
+        }
         else
             error("Unknown var name at line %s : line ignored", buf);
 
index e97694c5a5be612285000a0d7635de4b6b2f8c9c..d3b03ce6b42ed33b35744e3f608b617083df5465 100644 (file)
 #ifndef __FCRONCONF_H__
 #define __FCRONCONF_H__
 
+/* RFC5322's special mailbox address charcters */
+#define DQUOTE '\"'
+#define BSLASH '\\'
+#define SPECIAL_MBOX_CHARS "()<>[].,:;@\"\\"
 
 /* global variables */
 
@@ -39,6 +43,7 @@ extern char *fifofile;
 extern char *editor;
 extern char *shell;
 extern char *sendmail;
+extern char *displayname;
 /* end of global variables */
 
 /* functions prototypes */
index 99ca08f54e8859417c0ef424959a9b6206871e85..11e74757cf038e5155eab73166a6ccd120c8bf9f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * FCRON - periodic command scheduler 
+ * FCRON - periodic command scheduler
  *
  *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
  *
  *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  *  The GNU General Public License can also be found in the file
  *  `LICENSE' that comes with the fcron source distribution.
  */
@@ -251,7 +251,9 @@ auth_client_so_peercred(struct fcrondyn_cl *client)
      * Sets client->fcl_user on success, don't do anything on failure
      * so that the client stays unauthenticated */
 {
-    const int true = 1;
+    /* [@PR #17] renamed (previously called 'true') to avoid conflict with
+       stdbool */
+    const int value = 1;
     /* There is no ucred.h (or equivalent) on linux to define struct ucred (!!)
      * so we do it here */
 #if ! ( defined(HAVE_CRED_H) && defined(HAVE_UCRED_H) \
@@ -266,8 +268,8 @@ auth_client_so_peercred(struct fcrondyn_cl *client)
     socklen_t cred_size = sizeof(cred);
     struct passwd *p_entry = NULL;
 
-    setsockopt(client->fcl_sock_fd, SOL_SOCKET, SO_PASSCRED, &true,
-               sizeof(true));
+    setsockopt(client->fcl_sock_fd, SOL_SOCKET, SO_PASSCRED, &value,
+               sizeof(value));
     if (getsockopt
         (client->fcl_sock_fd, SOL_SOCKET, SO_PEERCRED, &cred,
          &cred_size) != 0) {
@@ -861,7 +863,7 @@ exe_cmd(struct fcrondyn_cl *client)
 void
 remove_connection(struct fcrondyn_cl **client, struct fcrondyn_cl *prev_client,
                   select_instance * si)
-/* close the connection, remove it from the list 
+/* close the connection, remove it from the list
 and make client points to the next entry */
 {
     debug("closing connection : fd : %d", (*client)->fcl_sock_fd);
index 99ee08f011c341aa5b5f49b853fccea8f91abee0..99b7923853e0ccc719da265caa1d0d92b48ff96e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * FCRON - periodic command scheduler 
+ * FCRON - periodic command scheduler
  *
  *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
  *
  *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  *  The GNU General Public License can also be found in the file
  *  `LICENSE' that comes with the fcron source distribution.
  */
@@ -458,41 +458,43 @@ assign_option_string(char **var, char *value)
 }
 
 
+/* [@PR #17] renamed labels 'true' and 'false' to avoid conflict with
+   stdbool */
 char *
 get_bool(char *ptr, int *i)
     /* get a bool value : either true (1) or false (0)
      * return NULL on error */
 {
     if (*ptr == '1')
-        goto true;
+        goto conf_true;
     else if (*ptr == '0')
-        goto false;
+        goto conf_false;
     else if (strncmp(ptr, "true", 4) == 0) {
         ptr += 3;
-        goto true;
+        goto conf_true;
     }
     else if (strncmp(ptr, "yes", 3) == 0) {
         ptr += 2;
-        goto true;
+        goto conf_true;
     }
     else if (strncmp(ptr, "false", 5) == 0) {
         ptr += 4;
-        goto false;
+        goto conf_false;
     }
     else if (strncmp(ptr, "no", 2) == 0) {
         ptr += 1;
-        goto false;
+        goto conf_false;
     }
     else
         return NULL;
 
- true:
-    *i = 1;
conf_true:
+    *i = true;
     ptr++;
     return ptr;
 
- false:
-    *i = 0;
conf_false:
+    *i = false;
     ptr++;
     return ptr;
 
@@ -1423,7 +1425,7 @@ read_shortcut(char *ptr, cf_t * cf)
     }
 
     /* The next char must be a space (no other option allowed when using
-     * a shortcut: if the user wants to use options, they should use the 
+     * a shortcut: if the user wants to use options, they should use the
      * native fcron lines */
     if (!isspace((int)*ptr)) {
         fprintf(stderr, "%s:%d: No space after shortcut: skipping line.\n",
@@ -1674,7 +1676,7 @@ read_period(char *ptr, cf_t * cf)
     /* skip the % */
     ptr++;
 
-    /* a runfreq set to 1 means : this is a periodical line 
+    /* a runfreq set to 1 means : this is a periodical line
      * (runfreq cannot be changed by read_opt() if already set to 1) */
     cl->cl_remain = cl->cl_runfreq = 1;
 
@@ -2028,7 +2030,7 @@ read_field(char *ptr, bitstr_t * ary, int max, const char **names)
 
 void
 delete_file(const char *user_name)
-    /* free a file if user_name is not null 
+    /* free a file if user_name is not null
      *   otherwise free all files */
 {
     cf_t *file = NULL;
index f3bee225fa40b00823c58f69ea284faae4780185..14436133167cc593045e14fb1442ccfea217bdb9 100644 (file)
@@ -23,3 +23,13 @@ sendmail     =       @@SENDMAIL@
 
 # Location of the default editor for "fcrontab -e"
 editor         =       @@FCRON_EDITOR@
+
+# Display name for the "From: " header of mails sent by us. Default is
+# unset/empty, which keeps the "From: " header as it was before this feature
+# was added -- not RFC5322-compliant, though. A sane RFC5322-compliant setting,
+# could be:
+#
+#   displayname = Fcron Deamon
+#
+# Please read fcron.conf(5) before setting it!
+displayname =   @@DISPLAYNAME@
index 6409ddc0b779f93ff79bc2f6232232fda858f55a..0a1160ef9fe9d912059ae3d80cae45a3210751e7 100644 (file)
--- a/global.h
+++ b/global.h
@@ -1,5 +1,5 @@
 /*
- * FCRON - periodic command scheduler 
+ * FCRON - periodic command scheduler
  *
  *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
  *
  *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  *  The GNU General Public License can also be found in the file
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
 
 
-/* 
+/*
    WARNING : this file should not be modified.
    Compilation's options are in config.h
 */
@@ -31,7 +31,7 @@
 #ifndef __GLOBAL_H__
 #define __GLOBAL_H__
 
-/* config.h must be included before every other includes 
+/* config.h must be included before every other includes
  * (contains the compilation options) */
 #include "config.h"
 
@@ -69,6 +69,7 @@
 #include <stdarg.h>
 #endif
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/job.c b/job.c
index 584d5f0192493daf943234427e4050578fede862..71a0ee923feb748a8faeb5f7aafa5f71b115b919 100644 (file)
--- a/job.c
+++ b/job.c
@@ -1,5 +1,5 @@
 /*
- * FCRON - periodic command scheduler 
+ * FCRON - periodic command scheduler
  *
  *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
  *
  *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  *  The GNU General Public License can also be found in the file
  *  `LICENSE' that comes with the fcron source distribution.
  */
@@ -27,6 +27,7 @@
 #include "job.h"
 #include "temp_file.h"
 
+
 void sig_dfl(void);
 void end_job(cl_t * line, int status, FILE * mailf, short mailpos,
              char **sendmailenv);
@@ -276,6 +277,42 @@ sig_dfl(void)
     signal(SIGPIPE, SIG_DFL);
 }
 
+char *
+make_mailbox_addr(char *displayname_conf, char *mail_from, char *hostname)
+    /* Produce a "mailbox" header as per RFC5322 sec. 3.2.3
+     * <https://datatracker.ietf.org/doc/html/rfc5322#section-3.2.3>.
+     * Returns: either the formatted mailbox header as a new dynamically
+     * allocated string (must be properly freed by the caller) or NULL on
+     * errors like buffer overflow. */
+{
+    char *buf = NULL;
+    uint written = 0;
+    bool need_anglebrackets = false;
+
+    /* Shorter than max because the header prefix "From: " are added
+       downstream. */
+    const uint buf_len = MAIL_LINE_LEN_MAX - 6;
+
+    buf = (char *)alloc_safe(buf_len * sizeof(char), "mailbox addr buffer");
+
+    /* == strlen(),but faster */
+    need_anglebrackets = displayname_conf[0] != '\0';
+
+    /* no @ here, it's handled upstream */
+    if (need_anglebrackets)
+        written = snprintf(buf, buf_len, "%s %c%s%s%c",
+                           displayname_conf, '<', mail_from, hostname, '>');
+    else
+        written = snprintf(buf, buf_len, "%s%s", mail_from, hostname);
+
+    if (written >= buf_len) {
+        error("Mailbox addr exceeds %u chars", buf_len);
+        Free_safe(buf);
+        return NULL;
+    }
+
+    return buf;
+}
 
 FILE *
 create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
@@ -290,6 +327,7 @@ create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
     /* hostname to add to email addresses (depending on if they have a '@') */
     char *hostname_from = "";
     char *hostname_to = "";
+    char *mailbox_addr = "";
     int i = 0;
 
     if (mailf == NULL)
@@ -318,8 +356,23 @@ create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
     hostname[0] = '\0';
 #endif                          /* HAVE_GETHOSTNAME */
 
-    /* write mail header */
-    fprintf(mailf, "From: %s%s (fcron)\n", mailfrom, hostname_from);
+    /* write mail header. Global 'displayname' comes from fcronconf.h */
+    if (strlen(displayname) > 0){
+        /* New behavior -- RFC-compliant */
+        mailbox_addr = make_mailbox_addr(displayname, mailfrom, hostname_from);
+        if (mailbox_addr) {
+            fprintf(mailf, "From: %s\n", mailbox_addr);
+            Free_safe(mailbox_addr);
+        }
+        else {
+            error("could not make the mailbox address");
+            fprintf(mailf, "From: %s%s\n", mailfrom, hostname_from);
+        }
+    }
+    else
+        /* Old behavior */
+        fprintf(mailf, "From: %s%s (fcron)\n", mailfrom, hostname_from);
+
     fprintf(mailf, "To: %s%s\n", line->cl_mailto, hostname_to);
 
     if (subject)
@@ -447,7 +500,7 @@ read_write_pipe(int fd, void *buf, size_t size, int action)
 
 int
 read_pipe(int fd, void *buf, size_t size)
-    /* Read data from pipe. 
+    /* Read data from pipe.
      * Handles signal interruptions, and read in several passes.
      * Returns ERR in case of a closed pipe, the errno from read
      * for other errors, and OK if everything was read successfully */
@@ -457,7 +510,7 @@ read_pipe(int fd, void *buf, size_t size)
 
 int
 write_pipe(int fd, void *buf, size_t size)
-    /* Read data from pipe. 
+    /* Read data from pipe.
      * Handles signal interruptions, and read in several passes.
      * Returns ERR in case of a closed pipe, the errno from write
      * for other errors, and OK if everything was read successfully */
diff --git a/job.h b/job.h
index ec135aa26d78604a668ee536b81774eae28bf6e3..a83c46bb127c33cf42c870d20db763b3bce9d8b5 100644 (file)
--- a/job.h
+++ b/job.h
@@ -1,5 +1,5 @@
 /*
- * FCRON - periodic command scheduler 
+ * FCRON - periodic command scheduler
  *
  *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
  *
  *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  *  The GNU General Public License can also be found in the file
  *  `LICENSE' that comes with the fcron source distribution.
  */
@@ -25,6 +25,8 @@
 #ifndef __JOB_H__
 #define __JOB_H__
 
+#define MAIL_LINE_LEN_MAX 998 /* RFC5322's max line length */
+
 /* functions prototypes */
 extern void change_user_setup_env(struct cl_t *cl, char ***sendmailenv,
                                   char ***jobenv, char **curshell,
diff --git a/test/Makefile.in b/test/Makefile.in
new file mode 100644 (file)
index 0000000..accc772
--- /dev/null
@@ -0,0 +1,18 @@
+# Prototype makefile, while waiting for integration of a test framework
+SRCDIR := ..
+LIBS   := @LIBS@
+SRCST  := mailbox_addr.c
+OBJST  := $(patsubst %.c,%.o,$(SRCST))
+EXEST  := $(patsubst %.c,%,$(SRCST))
+OBJSD  := $(addprefix $(SRCDIR)/,log.o job.o mem.o filesubs.o subs.o fcronconf.o temp_file.o env_list.o u_list.o)
+
+CFLAGS += -I$(SRCDIR)
+
+.PHONY: clean tests
+
+tests: $(OBJSD)
+       $(CC) $(CFLAGS) $(OBJSD) $(LIBS) $(SRCST) -o $(EXEST)
+       ./$(EXEST)
+
+clean:
+       rm -f *.o core $(EXEST)
diff --git a/test/mailbox_addr.c b/test/mailbox_addr.c
new file mode 100644 (file)
index 0000000..cb3cbeb
--- /dev/null
@@ -0,0 +1,130 @@
+/* Prototype test harness, while waiting for integration of a test framework */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "fcron.h"
+#include "job.h"
+#include "fcronconf.h"
+
+#define dasserteq(DESCR, RETURNED, EXPECTED) \
+{ \
+    printf("%s: %ld ?= %ld\n", (DESCR), (long)(RETURNED), (long)(EXPECTED)); \
+    assert((RETURNED) == (EXPECTED)); \
+}
+
+/* These globals should maybe come from a lib instead of the various exes? */
+char *prog_name = NULL;
+pid_t daemon_pid = 0;
+char foreground = 1;
+char default_mail_charset[TERM_LEN] = "";
+pam_handle_t *pamh = NULL;
+const struct pam_conv apamconv = { NULL };
+mode_t saved_umask;
+uid_t rootuid = 0;
+char *tmp_path = "";
+
+char *format_displayname(char *displayname);
+char *make_mailbox_addr(char *displayname, char *mail_from, char *hostname);
+
+
+void _test_format_displayname(char *test_desc, char *arg, char *expected)
+{
+    char *output = NULL;
+
+    output = format_displayname(arg);
+    printf("%s: format_displayname('%s'): '%s' ?= '%s'\n",
+           test_desc, arg, output, expected);
+    assert(strcmp(output, expected) == 0);
+    Free_safe(output);
+}
+
+
+void _test_make_mailbox_addr(char *test_desc, char *displayname,
+                             char *mailfrom, char *hostname, char *expected)
+{
+    char *output = NULL;
+
+    output = make_mailbox_addr(displayname, mailfrom, hostname);
+    printf("%s: make_mailbox_addr('%s', '%s', '%s'): '%s' ?= '%s'\n",
+           test_desc, displayname, mailfrom, hostname, output, expected);
+    assert(strcmp(output, expected) == 0);
+    Free_safe(output);
+}
+
+int main(int argc, char* argv[])
+{
+    char *displayname = NULL;
+    char *output = NULL;
+
+    /* Mind that format_displayname() might modify input displayname, thus all
+       special characters must be tested */
+    _test_format_displayname("empty displayname", "", "");
+    _test_format_displayname("displayname with no special char",
+                             "Foo Bar", "Foo Bar");
+    _test_format_displayname("displayname with no special char",
+                             "Foo'Bar", "Foo'Bar");
+
+    /* Make sure to extend this series, should SPECIAL_MBOX_CHARS change. All
+       those require quoting */
+    _test_format_displayname("displayname with special char",
+                             "(Foo Bar", "\"(Foo Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo Bar)", "\"Foo Bar)\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo B<ar", "\"Foo B<ar\"");
+    _test_format_displayname("displayname with special char",
+                             "Fo>o Bar", "\"Fo>o Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "F[oo Bar", "\"F[oo Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo] Bar", "\"Foo] Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo . Bar", "\"Foo . Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo, Bar", "\"Foo, Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo B:ar", "\"Foo B:ar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo ;Bar", "\"Foo ;Bar\"");
+    _test_format_displayname("displayname with special char",
+                             "Foo@Bar", "\"Foo@Bar\"");
+    _test_format_displayname("displayname with double quote",
+                             "Foo \" Bar", "\"Foo \\\" Bar\"");
+    _test_format_displayname("displayname with backslash",
+                             "Foo \\Bar", "\"Foo \\Bar\"");
+
+    /* make_mailbox_addr() only composes the "mailbox" address header: it's
+       agnostic of any special character */
+    _test_make_mailbox_addr("empty displayname => no angle brackets",
+                            "", "baz", "@quux", "baz@quux");
+    _test_make_mailbox_addr("displayname => needs angle brackets",
+                            "Foo Bar", "baz", "@quux", "Foo Bar <baz@quux>");
+
+
+    /* overflow tests */
+    displayname = (char *)realloc_safe(displayname,
+                                       LINE_LEN + 1 * sizeof(char),
+                                       "displayname buffer");
+    memset(displayname, 'a', LINE_LEN);
+    displayname[LINE_LEN] = '\0';
+    displayname[0] = DQUOTE;
+
+    output = format_displayname(displayname);
+    dasserteq("format_displayname: overflow", output, NULL);
+    Free_safe(output);
+
+    output = make_mailbox_addr(displayname, "baz", "@quux");
+    dasserteq("make_mailbox_addr: overflow", output, NULL);
+    Free_safe(output);
+
+    Free_safe(displayname);
+
+    return 0;
+}
+
+/* Local Variables:  */
+/* mode: c           */
+/* indent-tabs-mode: nil */
+/* End:              */