#!/usr/bin/env bash

#--------------------------------------------------------------
#
#  msmtpQ : queue funtions to use the msmtp queue,
#             as it was defined by Martin Lambers
#  Copyright (C) 2008 Chris Gianniotis
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or (at
#  your option) any later version.
#
#--------------------------------------------------------------

# msmtpQ is meant to be used directly by an email client - in 'sendmail' mode
# there is a separate log file for all events & operations on the msmtp
#   queue that is defined below

# msmtpq is meant to be used to maintain the msmtp queue

# mutt users should make the following setting in their .muttrc
# in addition to the set sendmail ... line
#   set sendmail_wait = -1

#--------------------------------------------------------------
# the msmtp queue contains unique filenames of the following form :
#   two for each mail in the queue
#
# create new unique filenames of the form :
#   MLF: ccyy-mm-dd-hh.mm.ss[-x].mail   -- mail file
#   MSF: ccyy-mm-dd-hh.mm.ss[-x].msmtp  -- msmtp command line file
# where x is a consecutive number only appended for uniqueness
#   if you send more than one mail per second
#--------------------------------------------------------------

## ======================================================================================
## !!!   please define the following vars before using the msmtpq & msmtpQ routines   !!!
## ======================================================================================

# set the queue var to the location of the msmtp queue directory
#   if the queue dir doesn't yet exist, better to create it (0700)
#     before using this routine (it will only complain ...)
#
Q=~/.msmtp.queue                     # the queue - modify this to reflect where you'd like it to be
[ -d "$Q" ] || {\
  echo ;\
  echo "  msmtpq : can't find msmtp queue directory [ $Q ]" ;\
  echo "  quitting" ;\
  echo ;\
  exit 1 ; \
}                                    # if queue dir not present - complain ; quit

# set the queue log file var to the location of the msmtp queue log file
#   where it is or where you'd like it to be
#     ( note that the LOG setting could be the same as the )
#     ( 'logfile' setting in .msmtprc - but there may be   )
#     ( some advantage in keeping the two logs separate    )
#   if you don't want the log at all please unset (comment out) this var
#
LOG=~/log/msmtp.queue.log            # the log   - modify to taste ...
[ -w "$LOG" ] || {\
  echo ;\
  echo "  msmtpq : can't find msmtp queue log file [ $LOG ]" ;\
  echo "  quitting" ;\
  echo ;\
  exit 1 ; \
}                                    # if queue log not present - complain ; quit

# the location of the msmtp executable
MSMTP='/usr/local/bin/msmtp'
[ -w "$LOG" ] || {\
  echo ;\
  echo "  msmtpq : can't find msmtp executable [ $MSMTP ]" ;\
  echo "  quitting" ;\
  echo ;\
  exit 1 ; \
}                                    # if queue log not present - complain ; quit
## ======================================================================================

umask 077                            # set secure permissions on created directories and files

usage() {
  echo
  echo '  usage : msmtpQ'
  echo '          msmtpQ -h   this helpful (?) blurt'
  echo
  echo '  any/all args on the msmtpQ command'
  echo '    line are passed through to msmtp'
  echo '    (not to mention the mail body text'
  echo '     passed via standard in ...)'
  echo
  exit 0
}

# log a message, possibly an error
# usage : log_msg [ -e ] msg [ msg ] ...
#  opts : -e <exit code>  an error ; log msg & terminate w/prejudice
#
log_msg() {
  local ERR ARG RC PFX

  if [ "$1" == '-e' ] ; then
    ERR='t'                          # set error flag
    RC="$2"                          # take error exit code
    shift 2                          # shift opt & its arg off
  fi

  if [ -n "$LOG" ] ; then            # logging not suppressed
    PFX="$(/bin/date +'%Y %d %b %H:%M:%S')"  # time stamp prefix - "2008 13 Mar 03:59:45 "
    for ARG ; do                     # each msg line out
      echo "$PFX : $ARG" >> "$LOG"   # send it to log
    done
  fi

  if [ -n "$ERR" ] ; then            # an error ; leave w/error return
    if [ "$RC" != 0 ] ; then         # exit code != 0 => display the exit code
      [ -n "$LOG" ] && \
        echo "    exit code = $RC" >> "$LOG" # logging ok ; send exit code to log
      exit $RC                       # exit w/exit code
    else                             # exit code == 0 => don't display an exit code
      exit 1
    fi
  fi
}

# make base filename
make_base() {
  local -i INC                       # increment counter for basename collision

  #BASE="${Q}/$(/bin/date +%Y-%m-%d-%H.%M.%S)"  # make base filename for queue
  ID="$(/bin/date +%Y-%m-%d-%H.%M.%S)"     # make filename id for queue
  BASE="${Q}/$ID"                    # make base filename for queue
  if [ -f "$BASE.*" ] ; then         # ensure base filename is unique
    INC=1                            # initial increment
	  while [ -f "${BASE}-${INC}.*" ] ; do   # base filename exists
      (( ++INC ))                    # bump increment
	  done
	  ID="${ID}-${INC}"                # unique ; set id
	  BASE="${BASE}-${INC}"            # unique ; set base filename
  fi
}

# enqueue a mail
enqueue_mail() { # <-- all mail args ; mail text via TMP
  local -i RC

  # write msmtp command line to queue .msmtp file (queue .mail file is already there)
  echo "$@" > "${BASE}.msmtp"
  RC=$?                              # take exit code
  if (( $RC == 0 )) ; then           # queueing was successful
    #log_msg "enqueued mail as : $BASE [ $* ] : successful"
    log_msg "enqueued mail as : [ $ID ] ( $* ) : successful"
  else                               # write failed
    log_msg -e "$RC" "queueing - writing msmtp cmd line { $* }"\
                     "           to [ ${ID}.msmtp ] : failed"
  fi
}

# send a mail (if possible, otherwise enqueue it)
# if send is successful, msmtp will also log it (if enabled in ~/.msmtprc)
send_mail() {    # <-- all mail args ; mail text via TMP
  local -i RC                        # msmtp return code

  if /bin/ping -qnc 1 -w 2 www.google.com &> /dev/null ; then  # ping www.google.com
    #*#*#/bin/cat "${BASE}.mail" | /usr/bin/msmtp "$@" > /dev/null  # send mail using queue .mail fil
    #*#*#/bin/cat "${BASE}.mail" | /usr/local/bin/msmtp "$@" > /dev/null  # send mail using queue .mail fil
    ##/bin/cat "${BASE}.mail" | $MSMTP "$@" > /dev/null  # send mail using queue .mail fil
    $MSMTP "$@" < "${BASE}.mail" > /dev/null  # send mail using queue .mail fil
    RC=$?                            # take exit code
    if (( $RC == 0 )) ; then         # send was successful
      log_msg "mail for [ $* ] : send was successful"
      /bin/rm -f "${BASE}.mail"      # remove queue .mail file
      exit 0                         # msmtp will log it
    else                             # send not ok - log msg
      log_msg "mail for [ $* ] : send was unsuccessful ; msmtp exit code was $RC"
      enqueue_mail "$@"              # enqueue the mail
    fi
  else                               # not connected to net ; log msg
    log_msg "mail for [ $* ] : couldn't be sent - host not connected"
    enqueue_mail "$@"                # enqueue the mail
  fi
}

#
## -- entry point
#

[ -z "$1" ] && log_msg 'msmtpQ was invoked with no cmd line args ; why was that ?'

[ "$1" == '-h' ] && usage

make_base                            # make base queue filename for this mail
/bin/cat > "${BASE}.mail"            # take piped mail into queue .mail fil
RC=$?                                # take exit code
[ $RC != 0 ] && \
  log_msg -e "$RC" "creating mail body file [ ${BASE}.mail ] : failed" # test for error

send_mail "$@"                       # send the mail if possible, queue it if not
