Update authors lists
[claws.git] / tools / fix_date.sh
1 #!/bin/sh
2
3 #  * Copyright 2004 Tristan Chabredier <wwp@claws-mail.org>
4 #  *
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.
9 #  *
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.
14 #  *
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.
18 #
19 # fix_date.sh           helper script to fix non-standard date or add missing
20 #                                       date header to emails
21
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)
28
29 # TODO: fallback to X-OriginalArrivalTime: ?
30
31 VERSION="0.1.2"
32
33
34 version()
35 {
36         echo "$VERSION"
37         exit 0
38 }
39
40 usage()
41 {
42         echo "usage:"
43         echo "  ${0##*/} [<switches>] <filename> [<filename> ..]"
44         echo "switches:"
45         echo "  --help     display this help then exit"
46         echo "  --version  display version information then exit"
47         echo "  --force    always force (re-)writing of Date: header"
48         echo "  --rfc      force re-writing of Date: header when it's not RFC-compliant"
49         echo "  --debug    turn on debug information (be more verbose)"
50         echo "  --strict   use RFC-strict matching patterns for dates"
51         echo "  --         end of switches (in case a filename starts with a -)"
52         exit $1
53 }
54
55 date_valid()
56 {
57         test $STRICT -eq 1 && \
58                 REGEXP="$DATE_REGEXP_STRICT" || \
59                 REGEXP="$DATE_REGEXP"
60                 
61         echo "$1" | grep -qEim 1 "$REGEXP"
62         DATE_VALID=$?
63 }
64
65 dump_date_fields()
66 {
67         test -z "$X_ORIGINAL_DATE" -a -n "$DATE" && \
68                 echo "X-Original-Date:$DATE" >> "$TMP"
69         echo "Date:$REPLACEMENT_DATE" >> "$TMP"
70 }
71
72 # use --force to always (re-)write the Date header
73 # otherwise, the Date header will be written if only it doesn't exist
74 FORCE=0
75 # use --rfc to (re-)write the Date header when it's not RFC-compliant
76 # otherwise, the Date header will be written if only it doesn't exist
77 RFC=0
78 # use --debug to display more information about what's performed
79 DEBUG=0
80 # use --strict to use strict matching patterns for date validation
81 STRICT=0
82 # 0 = valid, always valid until --strict is used, then date_valid overrides this value
83 DATE_VALID=0
84
85 while [ -n "$1" ]
86 do
87         case "$1" in
88         --help)         usage 0;;
89         --version)      version;;
90         --force)        FORCE=1;;
91         --debug)        DEBUG=1;;
92         --rfc)          RFC=1;;
93         --strict)       STRICT=1;;
94         --)                     shift
95                                 break;;
96         -*)                     echo "error: unrecognized switch '$1'"
97                                 usage 1;;
98         *)                      break;;
99         esac
100         shift
101 done
102
103 if [ $FORCE -eq 1 -a $RFC -eq 1 ]
104 then
105         echo "error: use either --force or --rfc, but not both at the same time"
106         usage 1
107 fi
108
109 test $# -lt 1 && \
110         usage 1
111
112 TMP="/tmp/${0##*/}.tmp"
113 HEADERS="/tmp/${0##*/}.headers.tmp"
114 BODY="/tmp/${0##*/}.body.tmp"
115
116 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]+'
117 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]+'
118
119 while [ -n "$1" ]
120 do
121         # skip if file is empty or doesn't exist
122         if [ ! -s "$1" ]
123         then
124                 shift
125                 continue
126         fi
127         SKIP=0
128
129         # split headers and body
130         # get the empty line (separation between headers and body)
131         SEP=`grep -nEm1 "^$" "$1" 2>/dev/null | cut -d ':' -f 1`
132         if [ -z "$SEP" -o "$SEP" = "0" ]
133         then
134                 cp -f "$1" "$HEADERS"
135                 :> "$BODY"
136         else
137                 sed -n '1,'`expr $SEP - 1`'p' "$1" > "$HEADERS"
138                 sed '1,'`expr $SEP - 1`'d' "$1" > "$BODY"
139         fi
140
141         # work on headers only
142
143         # get the Date and X-Original-Date
144         X_ORIGINAL_DATE=`sed -n '/^X-Original-Date:/,/^[^\t]/p' "$HEADERS" | head -n -1 | cut -d ':' -f 2-`
145         DATE=`sed -n '/^Date:/,/^[^\t]/p' "$HEADERS" | head -n -1 | cut -d ':' -f 2-`
146
147         # work on headers, minus Date and X-Original-Date
148         test -n "$X_ORIGINAL_DATE" && \
149                 sed -i '/^X-Original-Date:/,/^[^\t]/d' "$HEADERS"
150         test -n "$DATE" && \
151                 sed -i '/^Date:/,/^[^\t]/d' "$HEADERS"
152
153         # found a replacement date in Fetchinfo headers
154         FETCH_DATE=`grep -im1 'X-FETCH-TIME: ' "$HEADERS" | cut -d ' ' -f 2-`
155         
156         # or in Received: headers ..
157         test $STRICT -eq 1 && \
158                 REGEXP="$DATE_REGEXP" || \
159                 REGEXP="$DATE_REGEXP_STRICT"
160         RECEIVED_DATE=`sed -n '/^Received:/,/^[^\t]/p' "$HEADERS" | head -n -1 | grep -Eoim 1 "$REGEXP"`
161
162         # .. or from FS
163         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`
164         # we could also use the system date as a possible replacement
165         SYSTEM_DATE="`date -R`"
166
167         # determine which replacement date to use
168         if [ -z "$FETCH_DATE" ]
169         then
170                 if [ -z "$RECEIVED_DATE" ]
171                 then
172                         # don't forget the leading whitespace here
173                         REPLACEMENT_DATE=" $FILE_DATE"
174                         REPLACEMENT="file date"
175 #                       REPLACEMENT_DATE=" $SYSTEM_DATE"
176 #                       REPLACEMENT="system date"
177                 else
178                         REPLACEMENT_DATE="$RECEIVED_DATE"
179                         REPLACEMENT="received date"
180                 fi
181         else
182                 # don't forget the leading whitespace here
183                 REPLACEMENT_DATE=" $FETCH_DATE"
184                 REPLACEMENT="Fetchinfo time header"
185         fi
186
187         # ensure that the original X-Original-Date is kept
188         :> "$TMP"
189         if [ -n "$X_ORIGINAL_DATE" ]
190         then
191                 echo "X-Original-Date:$X_ORIGINAL_DATE" >> "$TMP"
192         fi
193
194         # replace/set the date and write all lines
195         test $RFC -eq 1 && \
196                 date_valid "$DATE"
197         if [ -z "$DATE" ]
198         then
199                 test $DEBUG -eq 1 && \
200                         echo "$1: date not found, using $REPLACEMENT now"
201                 dump_date_fields
202         else
203                 if [ $FORCE -eq 1 ]
204                 then
205                         test $DEBUG -eq 1 && \
206                                 echo "$1: date already found, replacing with $REPLACEMENT"
207                         dump_date_fields
208                 else
209                         if [ $RFC -eq 1 ]
210                         then
211                                 if [ $DATE_VALID -ne 0 ]
212                                 then
213                                         test $DEBUG -eq 1 && \
214                                                 echo "$1: date already found but not RFC-compliant, replacing with $REPLACEMENT"
215                                         dump_date_fields
216                                 else
217                                         test $DEBUG -eq 1 && \
218                                                 echo "$1: date already found and RFC-compliant, skipping"
219                                         SKIP=1
220                                 fi
221                         else
222                                 test $DEBUG -eq 1 && \
223                                         echo "$1: date already found, skipping"
224                                 SKIP=1
225                         fi
226                 fi
227         fi
228
229         if [ $SKIP -eq 0 ]
230         then
231                 # uncomment the following line to backup the original file
232                 #mv -f "$1" "$1.bak"
233
234                 cat "$HEADERS" >> "$TMP"
235                 cat "$BODY" >> "$TMP"
236                 mv -f "$TMP" "$1"
237                 if [ $? -ne 0 ]
238                 then
239                         echo "error while moving '$TMP' to '$1'"
240                         exit 1
241                 fi
242         fi
243         rm -f "$HEADERS" "$BODY" "$TMP" >/dev/null 2>&1
244
245         shift
246 done
247 exit 0