#!/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
-# Received: field if this field resides in one line. Otherwise, it will
-# take the file modification time (using a RFC 2822-compliant form).
-# If no X-Original-Date already exist, the former Date value will be set
-# in such field.
+# 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: add a switch to replace only non RFC-compliant Date: headers
+# TODO: fallback to X-OriginalArrivalTime: ?
-VERSION="0.0.3"
+VERSION="0.1.2"
-function version()
+version()
{
echo "$VERSION"
exit 0
}
-function usage()
+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 force writting of Date: header even if it already exists"
+ 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=$?
+}
-# use --force to always write the Date header
-# otherwise, the Date header will be written if only it doesn't already
-# exist
+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
--version) version;;
--force) FORCE=1;;
--debug) DEBUG=1;;
+ --rfc) RFC=1;;
+ --strict) STRICT=1;;
--) shift
break;;
-*) echo "error: unrecognized switch '$1'"
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
shift
continue
fi
+ SKIP=0
- X_ORIGINAL_DATE=$(grep -Eim 1 '^X-Original-Date: ' "$1" | cut -d ':' -f 2)
- DATE=$(grep -Eim 1 '^Date: ' "$1" | cut -d ':' -f 2)
- RECEIVED_DATE=$(grep -Eim 1 ';( (Mon|Tue|Wed|Thu|Fri|Sat|Sun),)? [0-9]+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dev) [0-9]+ [0-9]+:[0-9]+:[0-9}+ [-+][0-9]+' "$1" | cut -d ';' -f 2)
-# strict, day of week needed
-# RECEIVED_DATE=$(grep -Eim 1 '; (Mon|Tue|Wed|Thu|Fri|Sat|Sun), [0-9]+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dev) [0-9]+ [0-9]+:[0-9]+:[0-9}+ [-+][0-9]+' "$1" | cut -d ';' -f 2)
- FILE_DATE=$(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 "$RECEIVED_DATE" ]
+ # 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
- # don't forget the leading whitespace here
- REPLACEMENT_DATE=" $FILE_DATE"
- REPLACEMENT="file date"
-# REPLACEMENT_DATE=" $SYSTEM_DATE"
-# REPLACEMENT="system date"
+ cp -f "$1" "$HEADERS"
+ :> "$BODY"
else
- REPLACEMENT_DATE="$RECEIVED_DATE"
- REPLACEMENT="received date"
+ sed -n '1,'`expr $SEP - 1`'p' "$1" > "$HEADERS"
+ sed '1,'`expr $SEP - 1`'d' "$1" > "$BODY"
fi
- # ensure that a X-Original-Date is set (but don't override it)
- if [ -z "$X_ORIGINAL_DATE" ]
+ # 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 "$DATE" ]
+ if [ -z "$RECEIVED_DATE" ]
then
- echo "X-Original-Date:$REPLACEMENT_DATE" > "$TMP"
+ # don't forget the leading whitespace here
+ REPLACEMENT_DATE=" $FILE_DATE"
+ REPLACEMENT="file date"
+# REPLACEMENT_DATE=" $SYSTEM_DATE"
+# REPLACEMENT="system date"
else
- test $FORCE -eq 1 && \
- echo "X-Original-Date:$DATE" > "$TMP"
+ REPLACEMENT_DATE="$RECEIVED_DATE"
+ REPLACEMENT="received date"
fi
else
- :> "$TMP"
+ # 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"
- echo "Date:$REPLACEMENT_DATE" >> "$TMP"
- cat "$1" >> "$TMP"
+ dump_date_fields
else
if [ $FORCE -eq 1 ]
then
test $DEBUG -eq 1 && \
echo "$1: date already found, replacing with $REPLACEMENT"
- sed "s/^Date: .*/Date:$REPLACEMENT_DATE/" "$1" >> "$TMP"
+ dump_date_fields
else
- test $DEBUG -eq 1 && \
- echo "$1: date already found, skipping"
- cat "$1" >> "$TMP"
+ 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
- # uncomment the following line to backup the original file
- #mv -f "$1" "$1.bak"
-
- mv -f "$TMP" "$1"
- if [ $? -ne 0 ]
+ if [ $SKIP -eq 0 ]
then
- echo "error while moving '$TMP' to '$1'"
- exit 1
+ # 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