247 lines
6.7 KiB
Bash
Executable file
247 lines
6.7 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
# * Copyright 2004 Tristan Chabredier <wwp@claws-mail.org>
|
|
# *
|
|
# * This file 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, write to the Free Software
|
|
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# fix_date.sh helper script to fix non-standard date or add missing
|
|
# date header to emails
|
|
|
|
# usage: fix_date.sh <filename> [<filename>..]
|
|
# It will replace the Date: value w/ the one picked up from more recent
|
|
# Fetchinfo time header, Received: field.. Otherwise, it will take the file
|
|
# modification time (using a RFC 2822-compliant form).
|
|
# Any already existing X-Original-Date is kept, if missing we're adding it
|
|
# if the Date: was set (even if set w/ non conform value)
|
|
|
|
# TODO: fallback to X-OriginalArrivalTime: ?
|
|
|
|
VERSION="0.1.2"
|
|
|
|
|
|
version()
|
|
{
|
|
echo "$VERSION"
|
|
exit 0
|
|
}
|
|
|
|
usage()
|
|
{
|
|
echo "usage:"
|
|
echo " ${0##*/} [<switches>] <filename> [<filename> ..]"
|
|
echo "switches:"
|
|
echo " --help display this help then exit"
|
|
echo " --version display version information then exit"
|
|
echo " --force always force (re-)writing of Date: header"
|
|
echo " --rfc force re-writing of Date: header when it's not RFC-compliant"
|
|
echo " --debug turn on debug information (be more verbose)"
|
|
echo " --strict use RFC-strict matching patterns for dates"
|
|
echo " -- end of switches (in case a filename starts with a -)"
|
|
exit $1
|
|
}
|
|
|
|
date_valid()
|
|
{
|
|
test $STRICT -eq 1 && \
|
|
REGEXP="$DATE_REGEXP_STRICT" || \
|
|
REGEXP="$DATE_REGEXP"
|
|
|
|
echo "$1" | grep -qEim 1 "$REGEXP"
|
|
DATE_VALID=$?
|
|
}
|
|
|
|
dump_date_fields()
|
|
{
|
|
test -z "$X_ORIGINAL_DATE" -a -n "$DATE" && \
|
|
echo "X-Original-Date:$DATE" >> "$TMP"
|
|
echo "Date:$REPLACEMENT_DATE" >> "$TMP"
|
|
}
|
|
|
|
# use --force to always (re-)write the Date header
|
|
# otherwise, the Date header will be written if only it doesn't exist
|
|
FORCE=0
|
|
# use --rfc to (re-)write the Date header when it's not RFC-compliant
|
|
# otherwise, the Date header will be written if only it doesn't exist
|
|
RFC=0
|
|
# use --debug to display more information about what's performed
|
|
DEBUG=0
|
|
# use --strict to use strict matching patterns for date validation
|
|
STRICT=0
|
|
# 0 = valid, always valid until --strict is used, then date_valid overrides this value
|
|
DATE_VALID=0
|
|
|
|
while [ -n "$1" ]
|
|
do
|
|
case "$1" in
|
|
--help) usage 0;;
|
|
--version) version;;
|
|
--force) FORCE=1;;
|
|
--debug) DEBUG=1;;
|
|
--rfc) RFC=1;;
|
|
--strict) STRICT=1;;
|
|
--) shift
|
|
break;;
|
|
-*) echo "error: unrecognized switch '$1'"
|
|
usage 1;;
|
|
*) break;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ $FORCE -eq 1 -a $RFC -eq 1 ]
|
|
then
|
|
echo "error: use either --force or --rfc, but not both at the same time"
|
|
usage 1
|
|
fi
|
|
|
|
test $# -lt 1 && \
|
|
usage 1
|
|
|
|
TMP="/tmp/${0##*/}.tmp"
|
|
HEADERS="/tmp/${0##*/}.headers.tmp"
|
|
BODY="/tmp/${0##*/}.body.tmp"
|
|
|
|
DATE_REGEXP='( (Mon|Tue|Wed|Thu|Fri|Sat|Sun),)? [0-9]+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]+ [0-9]+:[0-9]+:[0-9]+ [-+]?[0-9]+'
|
|
DATE_REGEXP_STRICT='(Mon|Tue|Wed|Thu|Fri|Sat|Sun), [0-9]+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]+ [0-9]+:[0-9]+:[0-9]+ [-+]?[0-9]+'
|
|
|
|
while [ -n "$1" ]
|
|
do
|
|
# skip if file is empty or doesn't exist
|
|
if [ ! -s "$1" ]
|
|
then
|
|
shift
|
|
continue
|
|
fi
|
|
SKIP=0
|
|
|
|
# split headers and body
|
|
# get the empty line (separation between headers and body)
|
|
SEP=`grep -nEm1 "^$" "$1" 2>/dev/null | cut -d ':' -f 1`
|
|
if [ -z "$SEP" -o "$SEP" = "0" ]
|
|
then
|
|
cp -f "$1" "$HEADERS"
|
|
:> "$BODY"
|
|
else
|
|
sed -n '1,'`expr $SEP - 1`'p' "$1" > "$HEADERS"
|
|
sed '1,'`expr $SEP - 1`'d' "$1" > "$BODY"
|
|
fi
|
|
|
|
# work on headers only
|
|
|
|
# get the Date and X-Original-Date
|
|
X_ORIGINAL_DATE=`sed -n '/^X-Original-Date:/,/^[^\t]/p' "$HEADERS" | head -n -1 | cut -d ':' -f 2-`
|
|
DATE=`sed -n '/^Date:/,/^[^\t]/p' "$HEADERS" | head -n -1 | cut -d ':' -f 2-`
|
|
|
|
# work on headers, minus Date and X-Original-Date
|
|
test -n "$X_ORIGINAL_DATE" && \
|
|
sed -i '/^X-Original-Date:/,/^[^\t]/d' "$HEADERS"
|
|
test -n "$DATE" && \
|
|
sed -i '/^Date:/,/^[^\t]/d' "$HEADERS"
|
|
|
|
# found a replacement date in Fetchinfo headers
|
|
FETCH_DATE=`grep -im1 'X-FETCH-TIME: ' "$HEADERS" | cut -d ' ' -f 2-`
|
|
|
|
# or in Received: headers ..
|
|
test $STRICT -eq 1 && \
|
|
REGEXP="$DATE_REGEXP" || \
|
|
REGEXP="$DATE_REGEXP_STRICT"
|
|
RECEIVED_DATE=`sed -n '/^Received:/,/^[^\t]/p' "$HEADERS" | head -n -1 | grep -Eoim 1 "$REGEXP"`
|
|
|
|
# .. or from FS
|
|
FILE_DATE=`LC_ALL=POSIX LANG=POSIX ls -l --time-style="+%a, %d %b %Y %X %z" "$1" | tr -s ' ' | cut -d ' ' -f 6-11`
|
|
# we could also use the system date as a possible replacement
|
|
SYSTEM_DATE="`date -R`"
|
|
|
|
# determine which replacement date to use
|
|
if [ -z "$FETCH_DATE" ]
|
|
then
|
|
if [ -z "$RECEIVED_DATE" ]
|
|
then
|
|
# don't forget the leading whitespace here
|
|
REPLACEMENT_DATE=" $FILE_DATE"
|
|
REPLACEMENT="file date"
|
|
# REPLACEMENT_DATE=" $SYSTEM_DATE"
|
|
# REPLACEMENT="system date"
|
|
else
|
|
REPLACEMENT_DATE="$RECEIVED_DATE"
|
|
REPLACEMENT="received date"
|
|
fi
|
|
else
|
|
# don't forget the leading whitespace here
|
|
REPLACEMENT_DATE=" $FETCH_DATE"
|
|
REPLACEMENT="Fetchinfo time header"
|
|
fi
|
|
|
|
# ensure that the original X-Original-Date is kept
|
|
:> "$TMP"
|
|
if [ -n "$X_ORIGINAL_DATE" ]
|
|
then
|
|
echo "X-Original-Date:$X_ORIGINAL_DATE" >> "$TMP"
|
|
fi
|
|
|
|
# replace/set the date and write all lines
|
|
test $RFC -eq 1 && \
|
|
date_valid "$DATE"
|
|
if [ -z "$DATE" ]
|
|
then
|
|
test $DEBUG -eq 1 && \
|
|
echo "$1: date not found, using $REPLACEMENT now"
|
|
dump_date_fields
|
|
else
|
|
if [ $FORCE -eq 1 ]
|
|
then
|
|
test $DEBUG -eq 1 && \
|
|
echo "$1: date already found, replacing with $REPLACEMENT"
|
|
dump_date_fields
|
|
else
|
|
if [ $RFC -eq 1 ]
|
|
then
|
|
if [ $DATE_VALID -ne 0 ]
|
|
then
|
|
test $DEBUG -eq 1 && \
|
|
echo "$1: date already found but not RFC-compliant, replacing with $REPLACEMENT"
|
|
dump_date_fields
|
|
else
|
|
test $DEBUG -eq 1 && \
|
|
echo "$1: date already found and RFC-compliant, skipping"
|
|
SKIP=1
|
|
fi
|
|
else
|
|
test $DEBUG -eq 1 && \
|
|
echo "$1: date already found, skipping"
|
|
SKIP=1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ $SKIP -eq 0 ]
|
|
then
|
|
# uncomment the following line to backup the original file
|
|
#mv -f "$1" "$1.bak"
|
|
|
|
cat "$HEADERS" >> "$TMP"
|
|
cat "$BODY" >> "$TMP"
|
|
mv -f "$TMP" "$1"
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "error while moving '$TMP' to '$1'"
|
|
exit 1
|
|
fi
|
|
fi
|
|
rm -f "$HEADERS" "$BODY" "$TMP" >/dev/null 2>&1
|
|
|
|
shift
|
|
done
|
|
exit 0
|