#!/bin/sh # # Extract files from mail. # # File: hpcm_extract # Author: Bob Walton # Date: Fri Feb 2 09:11:37 EST 2007 # # The authors have placed this program in the public # domain; they make no warranty and accept no liability # for this program. # # RCS Info (may not be true date or author): # # $Author: walton $ # $Date: 2007/02/02 18:25:16 $ # $RCSfile: hpcm_extract,v $ # $Revision: 1.19 $ # If this is not bash and bash is available, switch # to using bash. Note that `which bash` may output # a grubby error message and no error code if bash # does not exist. Non-bash sh'es cannot handle the # -r option to read and perform unwanted backslash # interpretation in echo. # bash=`which bash 2>/dev/null` if test "$BASH" = "" -a "$bash" != "" -a -x "$bash" then exec bash "$0" "$@" fi # Print documentation if -... argument. # case "$1" in -*) echo " hpcm_extract [directory] Reads mail from the standard input and extracts files in mail sent by HPCM in response to \`get' requests. More specifically, any files surrounded by lines beginning with: ---<>--<>---<>--<>---<>----- are extracted, if the last line beginning with Subject: before the file is of the form: Subject: get ... Note that this line will NOT be the subject line of the reply message, but the subject line of the request message that is quoted in the reply message just before the files: the difference being that there is no \` RE:' in the request message subject. The extracted files are placed in the directory specified by the single argument, or if no argument is given, in the first directory found by searching the current directory and its ancestors for a dir- ectory that contains a readable HPCM_ADDRESS file. If a file that might be extracted already exists in that directory, the file is not extracted, but is compared against the existing file. When this program extracts a file, it makes the file read only. If the extracted file has a name of the form \`xxx.ISF' (ISF stands for \`initial submit- table file'), and the file \`xxx' does not exist, then this program copies the \`xxx.ISF' file to a file named \`xxx' and makes the latter writable. The \`xxx' file will in general be (optionally) sub- mittable. The standard output records what was done. It does not include the file contents. The standard output is formatted as one or more email messages that can be stored in a mailbox or piped into a mailer program such as UNIX \`procmail'." exit 1 ;; esac # Compute directory into which to place files. # if test "$1" != "" then home="$1" elif test -r HPCM_ADDRESS then home=. elif test -r ../HPCM_ADDRESS then home=.. elif test -r ../../HPCM_ADDRESS then home=../.. elif test -r ../../../HPCM_ADDRESS then home=../../.. elif test -r ../../../../HPCM_ADDRESS then home=../../../.. else echo "ERROR: Cannot find HPCM_ADDRESS file." exit 1 fi if test ! -d "$home" then echo "ERROR: \`$home' is not a directory." exit 1 fi # Mode is one of: # # header Look for Subject: lines # extract Extract lines # diff Diff lines # skip Skip lines (due to error) # look Look at the current line # to choose between header, # extract, or diff. Line # must begin with ---<>... # mode=header subject_ok=no subject= test_subject= test_subject_continue=no From= from= date= # Loop through lines of stdin. # while test x = x do # Read puts line in '$REPLY' and sets '$?' non-zero # iff there is an eof. # read -r if test $? -ne 0 then if test $mode != finish -a $mode != begin then # Create fake missing end of file. # echo "" echo "ERROR: missing end of file line." echo "" has_errors=yes REPLY="---<>--<>---<>--<>---<>----- end of files" else # Real end of file, end loop and program. # break fi fi case $mode in header) # For headers, save parts of header. # continue=`expr "$REPLY" : "[ ]"` if test $continue -ne 0 then if test $test_subject_continue = yes then test_subject="$test_subject $REPLY" fi else test_subject_continue=no fi # For headers, save parts of header. # case "$REPLY" in From\ *) From="$REPLY" from= date= subject= subject_ok=no ;; From:*) from="$REPLY" ;; Date:*) date="$REPLY" ;; Subject:*) subject="$REPLY" ;; X-HPCM-Test-Subject:*) test_subject="$REPLY" test_subject_continue=yes ;; '') # Start of body. # Print output message header. # if test "$from" != "" then echo "$from"; fi if test "$date" != "" then echo "$date"; fi if test "$subject" != "" then echo "$subject"; fi if test "$test_subject" != "" then echo "$test_subject"; fi echo "X-HPCM-Subject:" \ "output of hpcm_extract" mode=begin echo "" ;; esac ;; begin) case "$REPLY" in Subject:*) subject="$REPLY" # Set subject_ok according to whether # subject is `get ...'. This Subject # line is not that of the message proper, # but it that quoted in the message # just before the files. Thus there is # no ` RE:' in this subject. # SUBJECT="[Ss][Uu][Bb][Jj][Ee][Cc][Tt]" WS="[ ]*" GET="[Gg][Ee][Tt]" ok=`expr "$REPLY" : \ "${SUBJECT}:${WS}${GET}" ` if test $ok -ne 0 then subject_ok=yes else subject_ok=no fi ;; esac case "$REPLY" in '---<>--<>---<>--<>---<>-----'*) # Print hpcm_extact subheader. # echo "" echo "Output of: hpcm_extract $home" if test "$From" != "" then echo "Input $From"; fi echo "In directory $home" echo "" mode=look has_errors=no ;; *) echo "$REPLY" ;; esac ;; finish) echo "$REPLY" ;; extract) case "$REPLY" in '---<>--<>---<>--<>---<>-----'*) # End of file being extracted. Close fd 3. # exec 3>&- chmod a-w "$home/$file" echo "\`$file' extracted successfully." # Make copy of .ISF files if appropriate. # base=` expr "$file" : '\(.*\)\.ISF$' ` if test "$base" != "" then if test ! -e "$home/$base" then cp -p "$home/$file" "$home/$base" chmod u+w "$home/$base" echo "\`$file' copied to \`$base'." else echo "" echo WARNING: \ "\`$file' NOT copied to" \ "\`$base'," echo "as \`$base' already exists." echo "" has_errors=yes fi fi # Set mode and continue. # mode=look ;; *) # Line in file being extacted. # echo "$REPLY" >&3 ;; esac ;; diff) case "$REPLY" in '---<>--<>---<>--<>---<>-----'*) # End of file being diffed. Check existing # file for end of file. # reply="$REPLY" read -r <&3 if test $? -eq 0 then diff=yes fi REPLY="$reply" # Close fd 3. # exec 3<&- if test $diff = yes then echo "" echo "WARNING: received new \`$file'" echo "that is different" \ "from previous version." echo "Left previous version intact." echo "" has_errors=yes else echo "\`$file' matched existing file." fi mode=look ;; *) # Line in file being diffed. # line="$REPLY" read -r <&3 if test $? -ne 0 then diff=yes elif test "$REPLY" != "$line" then diff=yes fi ;; esac ;; skip) case "$REPLY" in '---<>--<>---<>--<>---<>-----'*) # End of file being skipped. # mode=look ;; esac ;; esac case $mode in look) # Line in $REPLY begins with `---<>...'. # Extract file name from line. # file=`expr "$REPLY" : \ '---<>--<>---<>--<>---<>-----\(.*\)$' ` file=`expr "$file" : \ '[ ]*\([^ ].*\)$' ` file=`expr "$file" : \ '\(.*[^ ]\)[ ]*$' ` case "$file" in *:) file=`expr "$file" : \ '\(.*\):$' ` ;; esac case "$file<$subject_ok>" in "end of files" ) echo "" if test $has_errors = no then echo NO ERRORS or WARNINGS in extraction else echo There were ERRORS or WARNINGS \ in extraction fi echo "" mode=finish ;; "end of files" ) echo BAD SUBJECT: no files extracted echo "" mode=done ;; *"" ) mode=skip ;; "" ) echo "" echo WARNING: empty file name echo "" has_errors=yes mode=skip ;; /* | .* | */.* | -* | */-* ) echo "" echo WARNING: illegal file name \ '(skipped):' "$file" echo "" has_errors=yes mode=skip ;; *"" ) # Make directories required by file name. # dirs="" dir=`dirname "$file"` while test "$dir" != "." do dirs="$dir $dirs" dir=`dirname "$dir"` done for dir in $dirs do if test -d "$home/$dir" then do_nothing= elif mkdir "$home/$dir" then echo "\`$dir' made" \ "successfully." else echo "ERROR: could not make" \ "\`$dir'." has_errors=yes break fi done if test -r "$home/$file" then if exec 3<"$home/$file" then mode=diff diff=no else echo "ERROR: could not read" \ "\`$file'." has_errors=yes mode=skip fi elif test ! -e "$home/$file" then if exec 3>"$home/$file" then mode=extract else echo "ERROR: could not write" \ "\`$file'." has_errors=yes mode=skip fi else echo "ERROR: unreadable" \ "\`$file' already exists." mode=skip has_errors=yes fi ;; esac ;; esac done exit 0