Add license and copyright to 9b3fd2b5
[claws.git] / tools / fix_date.sh
old mode 100644 (file)
new mode 100755 (executable)
index 1271841..2c2344d
 #!/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: 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"
+}
 
-if [ $# -lt 1 ]
+# 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 "usage: ${0##*/} <filename> [<filename> ..]"
-       exit 1
+       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
-       test ! -s "$1" && \
+       # 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
 
-       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)
+       # 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)"
+       SYSTEM_DATE="`date -R`"
 
        # determine which replacement date to use
-       if [ -z "$RECEIVED_DATE" ]
+       if [ -z "$FETCH_DATE" ]
        then
-               # don't forget to add the leading whitespace
-               REPLACEMENT_DATE=" $FILE_DATE"
+               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
-               REPLACEMENT_DATE="$RECEIVED_DATE"
+               # don't forget the leading whitespace here
+               REPLACEMENT_DATE=" $FETCH_DATE"
+               REPLACEMENT="Fetchinfo time header"
        fi
 
-       # ensure that a X-Original-Date is set
-       if [ -z "$X_ORIGINAL_DATE" ]
+       # ensure that the original X-Original-Date is kept
+       :> "$TMP"
+       if [ -n "$X_ORIGINAL_DATE" ]
        then
-               test -z "$DATE" && \
-                       echo "X-Original-Date:$REPLACEMENT_DATE" > "$TMP" || \
-                       echo "X-Original-Date:$DATE" > "$TMP"
-       else
-               :> "$TMP"
+               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
-               echo "Date:$REPLACEMENT_DATE" >> "$TMP"
-               cat "$1" >> "$TMP"
+               test $DEBUG -eq 1 && \
+                       echo "$1: date not found, using $REPLACEMENT now"
+               dump_date_fields
        else
-               sed "s/^Date: .*/Date:$REPLACEMENT_DATE/" "$1" >> "$TMP"
+               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
 
-       # 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