Subject: Expire and purge old messages

From: John Kelly <[email-masked]>
Date: Mon, 16 Apr 2001 23:33:18 -0400

I needed a program to expire and purge old messages, and could not
find anything.  So I had to hack something up.  And now I have some
questions:

  a) When freeing the searchpgm memory I think I was supposed to use
the address of the pointer like so:  mail_free_searchpgm (&sp);  The
prototype says **, so I think the "&" is correct.  But the program
seems to run with or without the "&", so I just want to be sure I got
this right.  Right?

  b) I found this in the archive:

> Sniffing at elt->searched is one of the few instances where it
> is correct to use mail_elt() without any mail_fetchstructure()
> or mail_fetchflags() call first.

In the hope of getting maximum performance, I open the mailbox with
OP_SHORTCACHE and run a search with SE_NOPREFETCH.  Test results
indicate that the  elt->searched flags are set by the search, giving
me the expired messages I'm looking for.  Does that sound like the
correct approach?

  c) After reading locking.txt, I concluded that c-client handles all
the locking for me.  But I still wonder ... is it possible for another
process to expunge the same file and alter the message numbers I found
in my search, before I complete my expunge?  I'm not sure I understand
the implications of the kiss-of-death feature described in locking.txt
as it might apply to my code below.

>/*
> * Program:     Expire and purge old messages
> *
> * Usage:       {program} mailbox days
> *
> * Notes:       The days parameter means the number of days to keep
> *              messages, in whole days.  Days = 1 means keep today's
> *              messages and yesterday's too, since today can never
> *              be a whole day until tomorrow.  Most inscrutably so!
> *
> *
> * Copyright 2001 by the University of Washington
> *
> * Permission to use, copy, modify, and distribute this software and its
> * documentation for any purpose and without fee is hereby granted, provided
> * that the above copyright notice appears in all copies and that both the
> * above copyright notice and this permission notice appear in supporting
> * documentation, and that the name of the University of Washington not be
> * used in advertising or publicity pertaining to distribution of the software
> * without specific, written prior permission.  This software is made
> * available "as is", and
> * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
> * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
> * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
> * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
> * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
> * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
> * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
> * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> *
> */
>#include <stdio.h>
>#include <ctype.h>
>#include <signal.h>
>#include <time.h>
>#include <errno.h>
>#include "mail.h"
>#include "osdep.h"
>#include "misc.h"
>#include "linkage.h"
>
>int debug = NIL;
>int verbose = NIL;
>int critical = NIL;
>
>int main (int argc, char *argv[]) {
>
>	char *pgm;
>	time_t ts;
>	struct tm tl;
>	long int days_to_keep;
>	unsigned long int ic, ix, pc;
>	MAILSTREAM *ms;
>	SEARCHPGM *sp;
>	char tmp[MAILTMPLEN];
>
>	pc = 0;
>	ms = NULL;
>	sp = NULL;
>	
>#include "linkage.c"
>
>	if (argc != 3) {
>		pgm = strrchr (argv[0], '/');
>		if (pgm == NULL) pgm = argv[0]; else pgm++;
>		printf ("Usage: %s mailbox days\n", pgm);
>		return (1);
>	}
>
>	ic = sscanf (argv[2], "%ld", &days_to_keep);
>	if (ic != 1 || days_to_keep < 1 || days_to_keep > 7000) {
>		printf ("Input: days must range from 1 to 7000\n");
>		return (1);
>	}
>
>	sp = mail_newsearchpgm ();
>	if (sp == NULL) {
>		printf ("Not enough memory for search program\n");
>		return (1);
>	}
>
>	if (!(ms = mail_open (NULL, argv[1], OP_SHORTCACHE)))
>		return (1);
>
>	if (!ms->nmsgs) {
>		if (verbose)
>			printf ("%s is empty\n", ms->mailbox);
>		mail_close (ms);
>		return (0);
>	}
>
>	if (verbose)
>		printf ("%s has %lu message(s)\n", ms->mailbox, ms->nmsgs);
>	ts = time (NULL);
>	ts -= days_to_keep * 86400;
>	tl = *(localtime (&ts));
>	sp->before = (((tl.tm_year + 1900) - BASEYEAR << 9) | ((tl.tm_mon + 1) << 5) | tl.tm_mday);
>	mail_search_full (ms, NULL, sp, SE_NOPREFETCH);
>	mail_free_searchpgm (&sp);
>	for (ix = 1; ix <= ms->nmsgs; ix++) {
>		if (mail_elt (ms, ix)->searched) {
>			pc++;
>			snprintf (tmp, sizeof tmp, "%lu", ix);
>			mail_setflag (ms, tmp, "\\Deleted");
>		}
>	}
>	if (verbose)
>		printf ("%s has %lu message(s) to expunge\n", ms->mailbox, pc);
>	mail_expunge (ms);
>	mail_close (ms);
>	return 0;
>}
>
>void mm_searched (MAILSTREAM *stream, unsigned long number)
>{
>	if (verbose && debug)
>		printf ("Message %lu flagged for delete\n", number);
>}
>
>void mm_exists (MAILSTREAM *stream, unsigned long number)
>{
>}
>
>void mm_expunged (MAILSTREAM *stream, unsigned long number)
>{
>}
>
>void mm_flags (MAILSTREAM *stream, unsigned long number)
>{
>}
>
>void mm_notify (MAILSTREAM *stream, char *string, long errflg)
>{
>	mm_log (string, errflg);
>}
>
>void mm_list (MAILSTREAM *stream, int delimiter, char *mailbox, long attributes)
>{
>}
>
>void mm_lsub (MAILSTREAM *stream, int delimiter, char *mailbox, long attributes)
>{
>}
>
>void mm_status (MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
>{
>}
>
>void mm_log (char *string, long errflg)
>{
>	switch ((short) errflg) {
>		case BYE:
>		case NIL:
>			if (verbose) printf ("[%s]\n", string);
>			break;
>		case PARSE:
>			break;
>		case WARN:
>			fprintf (stderr, "%%%s\n", string);
>			break;
>		case ERROR:
>		default:
>			fprintf (stderr, "?%s\n", string);
>		break;
>	}
>}
>
>void mm_dlog (char *string)
>{
>	fprintf (stderr, "%s\n",string);
>}
>
>void mm_critical (MAILSTREAM *stream)
>{
>	critical = T;
>}
>
>void mm_nocritical (MAILSTREAM *stream)
>{
>	critical = NIL;
>}
>
>long mm_diskerror (MAILSTREAM *stream, long errcode, long serious)
>{
>	kill (getpid (), SIGSTOP);
>	return (1);
>}
>
>void mm_fatal (char *string)
>{
>	fprintf (stderr,"?%s\n", string);
>}
>
>void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
>{
>}

-- 
------------------------------------------------------------------
 For information about this mailing list, and its archives, see: 
 http://www.washington.edu/imap/c-client-list.html
------------------------------------------------------------------