procmail
[Top] [All Lists]

Re: Sorting Archived Mail by Source Folder and Date

2001-12-27 00:19:22
On Fri, Dec 21, 2001 at 10:36:45AM -0800, Gary Funck wrote:

I have a fair number of maildir folders of archived mail that I would
like to sort on a monthly basis. 

This is likely not a problem to be handled with procmail, but one that
is more easily handled with formail, and other tools.  I needed to solve
a similar problem a while ago, and came up with this solution:

http://www.rosat.mpe-garching.mpg.de/mailing-lists/procmail/1997-02/msg0
0178.html

I developed a simple program called 'mdate', which takes a date in free
form, and tries to convert it into a canonical form. This, combined with
"formail" as the tool of choice for extracting the Date: header
information should get you what you need.  

<snip>

Here's a shell script that accepts a list of file names as arguments,
and that uses formail and the mdate utility to extract the date field
from each file (which is presumed to be a single mail message), and to
then copy the file into a directory named as YEAR/MONTH in CCYY/MM
format.  If you want to use month names or some other encoding, the
scipt will need to be modified.

Gary,

Your solution worked very well, indeed. I noted the following problems on my
platform ( Red Hat Linux 7.1, glibc-2.2.4-19) :

 - mdate uses 'cftime()' to format the output date. The corresponding
   function for me is strftime().

 - GNU touch uses a different time format.

I modified mdate (three cheers for open source! :-)) to use strftime() and
output dates with a runtime definable format. Use mdate -f or mdate --format
for this. I've included the diff.

I also modified your shell script to process and output the maildir format.

I have included the script and the diff ... hope this is acceptable on this
list.

Thanks a ton for the solution and I hope my diffs are useful.

-- Biju

---8<--cut here-----

#!/bin/bash
#
# sortmaildir : sorts Maildir files on the basis of date and dumps into
#               new maildirs
#
#

for i in $*; do
    if [ -d $i ]; then
        if [ -d $i/cur ] && [ -d $i/new ] && [ -d $i/tmp ]; then
            for curdir in cur new tmp; do
                for file in $i/$curdir/*; do
                    filename=`echo $file | sed -e "s/$i\/$curdir\///"`
                    if d=`formail -x Date: < $file` ; then
                        if m=`./mdate $d` ; then
                            Y=`echo $m | sed -e 's/^........//'`
                            M=`echo $m | sed -e 's/..........$//'`
                            parent_dir="$i-$Y/$M"
                            if [ ! -d $parent_dir ] ; then
                                mkdir -p $parent_dir/cur
                                mkdir -p $parent_dir/new
                                mkdir -p $parent_dir/tmp
                            fi
                            dir="$i-$Y/$M/$curdir"
                            if [ ! -d $dir ] ; then
                                mkdir -p $dir
                            fi
                            cp $file $dir
                            f='%Y%m%d%H%M'
                            touch -t `./mdate -f$f $d` $dir/$filename
                            echo "$i: copied to $dir/$filename"
                        else
                            echo "Unable to parse date: $d -> $m"
                            if [ ! -d $i-unsorted ] ; then
                                mkdir -p $i-unsorted/cur
                                mkdir -p $i-unsorted/new
                                mkdir -p $i-unsorted/tmp
                            fi
                            dir="$i-unsorted/$curdir"
                            if [ ! -d $dir ] ; then
                                mkdir -p $dir
                            fi
                            cp $file $dir
                            echo "$i: copied to $dir/$filename"
                        fi
                    else
                        echo "No Date in mail"
                        if [ ! -d $i-unsorted ] ; then
                            mkdir -p $i-unsorted/cur
                            mkdir -p $i-unsorted/new
                            mkdir -p $i-unsorted/tmp
                        fi
                        dir="$i-unsorted/$curdir"
                        if [ ! -d $dir ] ; then
                            mkdir -p $dir
                        fi
                        cp $file $dir
                        f='%Y%m%d%H%M'
                        echo "$i: copied to $dir/$filename"
                    fi
                done
            done
        fi
    fi
done


---8<--cut here-----

--- ../mdate/mdate.y    Sat Dec 22 09:42:38 2001
+++ mdate.y     Sat Dec 22 15:49:35 2001
@@ -836,26 +836,72 @@
 {
 }
 
-main(argc, argv)
-int argc;
-char *argv[];
+
+#include <getopt.h>
+
+int main(int argc, char *argv[])
 {
+    static struct option long_options[] = {
+       {"format", required_argument, 0, 'f'}
+    };
+    int option_index = 0;
+    int c;
+    char format_string[32] = "";
+    char dbuf[1024] = "";
+    char mbuf[1024] = "";
     time_t t;
-    int i;
-    char dbuf[1024];
-    char mbuf[1024];
-    if (argc <= 1) exit(0);
-    strcpy(dbuf, argv[1]);
-    for (i = 2; i < argc; ++i) {
-       strcat(dbuf, " ");
-       strcat(dbuf, argv[i]);
+
+    if (argc <= 1)
+       exit(1);
+
+    opterr=0;
+    do {
+       c = getopt_long(argc, argv, "f:", long_options, &option_index);
+       switch (c) {
+       case 'f':
+           strcpy(format_string, optarg);
+           break;
+           /*
+            * add more options here 
+            */
+       case -1:
+       default:
+           /*
+            * do nothing 
+            */
+       }
+    }
+    while (c != -1);
+
+    if (optind < argc) {
+       while (optind < argc) {
+           strcat(dbuf, argv[optind++]);
+           strcat(dbuf, " ");
+       }
     }
+
     t = mdate(dbuf);
     if (t < 0) {
        fprintf(stderr, "%s: invalid date: '%s'\n", argv[0], dbuf);
        exit(2);
     }
-    cftime(mbuf, "%m%d%H%M%Y", &t);
+
+    /*
+     * If there is no format spec then output the default.
+     * otherwise output according to the spec.
+     *
+     */
+    if (strlen(format_string) > 0) {
+       /*
+        * use format spec: DOES NOT CHECK VALIDITY 
+        */
+       strftime(mbuf, 1024, format_string, localtime(&t));
+    } else {
+       strftime(mbuf, 1024, "%m%d%H%M%Y", localtime(&t));
+    }
+
     puts(mbuf);
+
     exit(0);
+
 }



-- 
-------------------------------------------------
Biju Chacko        | biju(_at_)exocore(_dot_)com (work)            
Exocore Consulting | biju_chacko(_at_)yahoo(_dot_)com (play)
Bangalore, India   | http://www.exocore.com
-------------------------------------------------
The chief enemy of creativity is "good" sense
                -- Picasso
_______________________________________________
procmail mailing list
procmail(_at_)lists(_dot_)RWTH-Aachen(_dot_)DE
http://MailMan.RWTH-Aachen.DE/mailman/listinfo/procmail

<Prev in Thread] Current Thread [Next in Thread>