#!/usr/bin/env bash
#
# cred 1.0 (06-Sep-2022) - Copyright (C) 2016, 2022 Dario Niedermann
#
# Check REmote Document, report if it changed since last check
#
# $Id: cred.m4,v 1.11 2022-09-06 10:51:28+02 ndr Rel $
umask 077
myName="${0##*/}"; fNamePrefix="${myName}-"
myVerbosity=0; wgetVerbosity='q'
myVersion=`sed -ne 3p "$0" | tr ' \t' "\n\n" | grep '^[0-9]' | head -n1`
myPlatform=`uname -sm`
wgetVersion=`wget -V | head -n1 | tr ' ' '\n' | head -n3 | tail -n1`
userAgent="cred/$myVersion ($myPlatform) Wget/$wgetVersion"
unset urls reportUnchanged chkConnection
pingServer="${PINGSERVER:-www.pingtest.net}"
if [ -e /dev/stderr -a -w /dev/stderr ]; then
echoerr() { echo -e $myName: $@ >>/dev/stderr ; }
else
echoerr() { echo -e $myName: $@ ; }
fi
debugMsg() { [ $myVerbosity -gt 1 ] && echoerr $@ ; }
mkHomeCredDir()
{
echoerr "warning: creating 'cred/' in your home directory. See cred(1)"
echoerr ' section ENVIRONMENT, on how to use a different dir.'
mkdir ~/cred
if [ $? -ne 0 ]; then
echoerr 'could not create ~/cred -- giving up.'
exit 73
else
cd ~/cred
fi
}
pickSuitableWorkingDir()
{
local d dirFound
debugMsg "Picking a suitable working directory... "
unset dirFound
for d in "$CREDDIR" "$HOME/cred" "$TMPDIR" "$HOME/tmp" /tmp ; do
if [ -d "$d" -a -w "$d" ]; then
dirFound=1; cd "$d"
[ -d cred -a -w cred ] && cd cred
break
fi
done
# no suitable directory found? make your own in ~
[ -z "$dirFound" ] && mkHomeCredDir
[ "${PWD##*/}" = cred ] && unset fNamePrefix
debugMsg "'$PWD' will do"
}
findMailer()
{
local rc mailPrgCandidate
debugMsg "Looking for a 'mail' program..."
for mailPrgCandidate in /{,usr/{,local/}}bin/{m,M}ail{,x} ; do
debugMsg "Looking for $mailPrgCandidate ..."
mailPrg=`which $mailPrgCandidate`
rc=$? ; [ $rc -eq 0 ] && break
done
if [ $rc -ne 0 ]; then
echoerr 'The "mail" program was not found.' \
'Will report to stdout.'
fi
debugMsg "Found $mailPrg"
export MAILRC=/dev/null
export LC_ALL=en_US.utf8 # just so mailx won't complain of multibyte
# chars. Making the locale configurable
# might be a good idea, though
mailOpts="-n -S 'sendcharsets=iso-8859-1,utf-8,utf-16' \
-r ${myName}@localhost"
return $rc
}
sendMail()
{
if ! findMailer ; then return 1 ; fi
if [ $diffExit -gt 0 ]; then
echo "See: <${url}>" | $mailPrg $mailOpts \
-s "Changes at $remoteHostName !" "$USER"
else
if [ -n "$reportUnchanged" ]; then
echo "Unchanged: <${url}>" | $mailPrg $mailOpts \
-s "No changes at $remoteHostName" "$USER"
fi
fi
}
reportToStdout()
{
if [ $diffExit -ne 0 ]; then
echo "$myName: '$url' has changed"
else
[ -n "$reportUnchanged" ] && echo "$myName: '$url' is unchanged"
fi
}
sendMailOrReportToStdout()
{
local mailRc
[ -z "$noMail" ] && sendMail
mailRc=$?
[ -n "$noMail" -o $mailRc -ne 0 ] && reportToStdout
}
checkRequirements()
{
local p found
for p in wget openssl ping ; do
which $p > /dev/null 2>&1 ; found=$?
exitmsg="essential program '$p' not found -- exiting"
contmsg="program '$p' not found -- disabling connection check"
if [ $found -ne 0 ]; then # program not found
case $p in
wget|openssl) echoerr "$exitmsg"; exit 69 ;;
ping) [ -n "$chkConnection" ] && \
echoerr "$contmsg"
unset chkConnection ;;
esac
fi
done
}
checkConnection()
{
[ -z "$chkConnection" ] && return 0 # check unwanted, skip it
# else...
ping -q -c1 $pingServer > /dev/null 2>&1
[ $? -ne 0 ] && exit 0 # no connection? exit without errors
}
showLicenseOrVersion()
{
sed -n -e '3p' "$0" |sed -e 's/^#[[:blank:]]\+//'
if [ "$1" = '-L' -o "${1:0:-2}" = '--licen' ]; then
echo
sed -n -e '/^-----$/,$p' "$0" |sed -e 1d
fi
}
showHelp()
{
sed -n -e '/^Usage/,/^-----$/p' "$0" \
| sed -e "s/PROGNAME/$myName/;2d;"'$d'
}
showUsageAndExit()
{
[ -n "$1" ] && echoerr "$1" # print optional passed-in msg
grep -A1 '^Usage' "$0" |sed -e "s,PROGNAME,$myName,"
exit 64
}
incrementVerbosity()
{
myVerbosity=$((++myVerbosity))
wgetVerbosity=v
[ $myVerbosity -gt 1 ] && wgetVerbosity=d # >1 = debug cred & wget
}
warnDeprecated()
{
echoerr 'warning: the -c option is deprecated and ignored in this version'
echoerr 'warning: it will be removed in the future -- update your usage!'
}
mkFileNameFromUrl()
{
local temp suffix
unset fileName; temp="${url#*://}" # remove initial scheme://
remoteHostName="${temp%%/*}" # remove from 1st / to end
# a file name suffix is made from the URL's hash. This is to prevent
# 'a.com/index.html' and 'b.com/index.html' from ending up written
# to the same file
suffix=`echo -n "$url"| openssl dgst -md5|tr ' ' '\n' \
| tail -n1 | fold -w4 | head -n1`
fileName="${fNamePrefix}${remoteHostName}-$suffix"
}
checkForChangesAndReport()
{
if [ -e "$fileName" ]; then
mv "$fileName" "$fileName~"
mv "$fileName~~" "$fileName"
diff -q "$fileName" "$fileName~" > /dev/null 2>&1
diffExit=$?
sendMailOrReportToStdout
else # 1st download
mv "$fileName~~" "$fileName"
[ -n "$reportUnchanged" ] && \
echo "'$url' not previously checked"
fi
}
#--------------------------------------------------------------------------- CLI
[ $# -lt 1 ] && showUsageAndExit 'no arguments'
# else...
temp=$(getopt -n "$myName" -o chnsvLNV -l comment,help,licence,license,nomail,report-unchanged,verbose,only-if-connected,version -- "$@")
[ $? -ne 0 ] && showUsageAndExit
debugMsg 'Reading command line options...'
eval set -- "$temp"
debugMsg "Got command line options: $temp"
while true; do
debugMsg "Examining argument '$1'"
case "$1" in
-c|--comment) warnDeprecated; shift ;;
-v|--verbose) incrementVerbosity; shift ;;
-s|--report-unchanged) reportUnchanged=y; shift ;;
-n|--nomail) noMail=y; shift ;;
-N|--only-if-connected) chkConnection=y; shift ;;
-h|--help) showHelp; exit ;;
-L|-V|--licence|--license|--version)
showLicenseOrVersion $1; exit ;;
--) shift; break ;;
*) echoerr 'Internal error!'; exit 70 ;;
esac
done
[ $# -eq 0 ] && showUsageAndExit 'no URL specified'
#---------------------------------------------------------------------------/CLI
urls="$@"; debugMsg "URL(s) wanted: $urls"
checkRequirements
checkConnection
pickSuitableWorkingDir
for url in $urls ; do
mkFileNameFromUrl
wget -"$wgetVerbosity" -U "$userAgent" -O "${fileName}~~" "$url"
wgetErr=$?
if [ $wgetErr -eq 0 ]; then
checkForChangesAndReport
else
echoerr "wget returned error $wgetErr on '$url'"
fi
done
exit 0
Usage: PROGNAME [OPTION]... URL...
Try `PROGNAME --help' for more information.
Check document at URL, report if it has changed since last check
-v, --verbose output messages detailing program operation;
specify twice for extra verbosity
-n, --nomail do not send email; report results to STDOUT
-s, --report-unchanged also report when file at URL did not change
-N, --only-if-connected if no net connection, exit without errors
-V, --version display program version
-L, --licence, --license display program version and licence
-h, --help display this help and exit
Report bugs to: Dario Niedermann <dario@darioniedermann.it>
cred home page: <https://www.darioniedermann.it/sw/cred.html>
-----
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.
This program is distributed in the hope that it will be useful,
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, see <https://www.gnu.org/licenses/>.
“Cred” is Copyright © Dario Niedermann —
Released with no warranty under the terms of the
GPLv3 license. Written and tested on Linux using GNU tools.