3 # * Copyright 2004 Tristan Chabredier <wwp@claws-mail.org>
5 # * This file is free software; you can redistribute it and/or modify it
6 # * under the terms of the GNU General Public License as published by
7 # * the Free Software Foundation; either version 3 of the License, or
8 # * (at your option) any later version.
10 # * This program is distributed in the hope that it will be useful, but
11 # * WITHOUT ANY WARRANTY; without even the implied warranty of
12 # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # * General Public License for more details.
15 # * You should have received a copy of the GNU General Public License
16 # * along with this program; if not, write to the Free Software
17 # * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # fix_date.sh helper script to fix non-standard date or add missing
20 # date header to emails
22 # usage: fix_date.sh <filename> [<filename> ..]
23 # It will replace the Date: value w/ the one picked up from more recent
24 # Fetchinfo time header, Received: field.. Otherwise, it will take the file
25 # modification time (using a RFC 2822-compliant form).
26 # Any already existing X-Original-Date is kept, if missing we're adding it
27 # if the Date: was set (even if set w/ non conform value)
29 # TODO: fallback to X-OriginalArrivalTime: ?
43 echo " ${0##*/} [<switches>] <filename> [<filename> ..]"
45 echo " -h --help display this help then exit"
46 echo " -v --version display version information then exit"
47 echo " -d --debug turn on debug information (be more verbose)"
48 echo " -f --force always force (re-)writing of Date: header"
49 echo " -r --rfc force re-writing of Date: header when it's not RFC-compliant"
50 echo " -s --strict use RFC-strict matching patterns for dates"
51 echo " -- end of switches (in case a filename starts with a -)"
52 echo "this script requires coreutils (cat, cut, head, tr), dos2unix, grep and set"
53 echo "in PATH to work"
59 test $STRICT -eq 1 && \
60 REGEXP
="$DATE_REGEXP_STRICT" || \
63 echo "$1" |
grep -qEim 1 "$REGEXP"
69 test -z "$X_ORIGINAL_DATE" -a -n "$DATE" && \
70 echo "X-Original-Date:$DATE" >> "$TMP"
71 echo "Date:$REPLACEMENT_DATE" >> "$TMP"
75 # use --force to always (re-)write the Date header
76 # otherwise, the Date header will be written if only it doesn't exist
78 # use --rfc to (re-)write the Date header when it's not RFC-compliant
79 # otherwise, the Date header will be written if only it doesn't exist
81 # use --debug to display more information about what's performed
83 # use --strict to use strict matching patterns for date validation
85 # 0 = valid, always valid until --strict is used, then date_valid overrides this value
87 # max header lines (300 is a reasonable minimum value but 600 has already been encountered, set to 1000 by security)
94 -v|
--version) version
;;
98 -s|
--strict) STRICT
=1;;
101 -*) echo "error: unrecognized switch '$1'"
108 if [ $FORCE -eq 1 -a $RFC -eq 1 ]
110 echo "error: use either --force or --rfc, but not both at the same time"
117 for PROG
in dos2unix
grep sed
119 type "$PROG" >/dev
/null
2>&1 || \
120 { echo "error: $PROG not found in PATH"; exit 1; }
124 TMP
="$TMPDIR/${0##*/}.$$.tmp"
125 echo > "$TMP" >/dev
/null
2>&1
128 rm -f "$TMP" >/dev
/null
2>&1
131 TMP
="$TMPDIR/${0##*/}.$$.tmp"
133 HEADERS
="$TMPDIR/${0##*/}.$$.headers.tmp"
134 BODY
="$TMPDIR/${0##*/}.$$.body.tmp"
136 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]+'
137 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]+'
141 # skip if file is empty or doesn't exist
144 test $DEBUG -eq 1 && \
145 echo "$1: no found or empty, skipping"
151 # split headers and body
152 # find the empty line that separates body (if any) from headers,
153 # work on a temporary dos2unix'ed copy because body might
154 # contain DOS CRLF and grep '^$' won't work
155 head -$MAX_HEADER_LINES "$1" | dos2unix
> "$TMP"
156 SEP
=`grep -nEm1 "^$" "$TMP" 2>/dev/null | cut -d ':' -f 1`
158 if [ -z "$SEP" -o "$SEP" = "0" -o $?
-ne 0 ]
160 cp -f "$1" "$HEADERS"
162 test $DEBUG -eq 1 && \
163 echo "$1: no body part could be found before line $MAX_HEADER_LINES"
165 sed -n '1,'`expr $SEP - 1`'p' "$1" > "$HEADERS"
166 sed '1,'`expr $SEP - 1`'d' "$1" > "$BODY"
169 # work on headers only
171 # get the Date and X-Original-Date
172 X_ORIGINAL_DATE
=`sed -n '/^X-Original-Date:/,/^[^\t]/p' "$HEADERS" | head -n -1 | cut -d ':' -f 2-`
173 DATE
=`sed -n '/^Date:/,/^[^\t]/p' "$HEADERS" | head -n -1 | cut -d ':' -f 2-`
175 # work on headers, minus Date and X-Original-Date
176 test -n "$X_ORIGINAL_DATE" && \
177 sed -i '/^X-Original-Date:/,/^[^\t]/d' "$HEADERS"
179 sed -i '/^Date:/,/^[^\t]/d' "$HEADERS"
181 # find a replacement date in Fetchinfo: header
182 FETCH_DATE
=`grep -im1 'X-FETCH-TIME: ' "$HEADERS" | cut -d ' ' -f 2-`
184 # or in Received: headers ..
185 test $STRICT -eq 1 && \
186 REGEXP
="$DATE_REGEXP" || \
187 REGEXP
="$DATE_REGEXP_STRICT"
188 RECEIVED_DATE
=`sed -n '/^Received:/,/^[^\t]/p' "$HEADERS" | head -n -1 | grep -Eoim 1 "$REGEXP"`
190 # .. or from file properties
191 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`
192 # we could also use the system date as a possible replacement
193 SYSTEM_DATE
="`date -R`"
195 # determine which replacement date to use
196 if [ -z "$FETCH_DATE" ]
198 if [ -z "$RECEIVED_DATE" ]
200 # don't forget the leading whitespace here
201 REPLACEMENT_DATE
=" $FILE_DATE"
202 REPLACEMENT
="file date"
203 # REPLACEMENT_DATE=" $SYSTEM_DATE"
204 # REPLACEMENT="system date"
206 REPLACEMENT_DATE
="$RECEIVED_DATE"
207 REPLACEMENT
="received date"
210 # don't forget the leading whitespace here
211 REPLACEMENT_DATE
=" $FETCH_DATE"
212 REPLACEMENT
="Fetchinfo time header"
215 # ensure that the original X-Original-Date is kept
217 if [ -n "$X_ORIGINAL_DATE" ]
219 echo "X-Original-Date:$X_ORIGINAL_DATE" >> "$TMP"
222 # replace/set the date and write all lines
227 test $DEBUG -eq 1 && \
228 echo "$1: date not found, using $REPLACEMENT now"
233 test $DEBUG -eq 1 && \
234 echo "$1: date already found, replacing with $REPLACEMENT"
239 if [ $DATE_VALID -ne 0 ]
241 test $DEBUG -eq 1 && \
242 echo "$1: date already found but not RFC-compliant, replacing with $REPLACEMENT"
245 test $DEBUG -eq 1 && \
246 echo "$1: date already found and RFC-compliant, skipping"
250 test $DEBUG -eq 1 && \
251 echo "$1: date already found, skipping"
259 # uncomment the following line to backup the original file
262 cat "$HEADERS" >> "$TMP"
263 cat "$BODY" >> "$TMP"
267 echo "error while moving '$TMP' to '$1'"
271 rm -f "$HEADERS" "$BODY" "$TMP" >/dev
/null
2>&1