diff -Nur pine3.96.dist/README.dg pine3.96.local/README.dg --- pine3.96.dist/README.dg Wed Dec 31 16:00:00 1969 +++ pine3.96.local/README.dg Sat Feb 7 20:22:57 1998 @@ -0,0 +1,39 @@ +version 4 + +- merge in maildir support from Eric Green . + +- fix maildir support for proper "new message" detection -- this makes it + useful for your inbox collection + +- add "Recipients" support to maildir + +- No more /tmp lockfiles, move them to $TMPDIR if defined or $HOME otherwise. + Nobody on my system uses shared folders, and bezerk is not a format I'd + advocate for shared folders anyhow. It'd be much better to get maildir + to work with correct permissions. So I'd rather not have the symlink + attacks. + +version 3 + +- (written by "Randall S. Winchester" ) Add a "Recipients" + option to the aggregate selection -- similar to doing a selection by To + and then broadening with a selction by Cc... useful when you want to + know all the messages that a certain address received. + +- defines ALLOW_CHANGING_FROM in pine/osdep/os-lnx.h so that From can be + changed + +- adds a new define ALLOW_DISABLE_SENDER which enables a new option + disable-sender, suppressing the generation of Sender: and X-Sender:. + (defined in pine/osdep/os-lnx.h as well) + +- adds a new define QMAIL_RETURN_PATH which enables a new option + qmail-return-path which uses the qmail feature whereby the envelope + sender can be set by putting a Return-Path header into the message. + By default the Return-Path: will contain a copy of the From:, but if + you add Return-Path to your customized headers you can use any + combination of From: and envelope sender you want. + (defined in pine/osdep/os-lnx.h as well) + +You will need to define those features in whatever osdep file is appropriate +for your system to make use of them. Binary files pine3.96.dist/bin/imapd and pine3.96.local/bin/imapd differ Binary files pine3.96.dist/bin/mtest and pine3.96.local/bin/mtest differ Binary files pine3.96.dist/bin/pico and pine3.96.local/bin/pico differ Binary files pine3.96.dist/bin/pilot and pine3.96.local/bin/pilot differ Binary files pine3.96.dist/bin/pine and pine3.96.local/bin/pine differ diff -Nur pine3.96.dist/imap/ANSI/c-client/Makefile pine3.96.local/imap/ANSI/c-client/Makefile --- pine3.96.dist/imap/ANSI/c-client/Makefile Tue Oct 15 15:28:55 1996 +++ pine3.96.local/imap/ANSI/c-client/Makefile Thu Jan 29 00:59:05 1998 @@ -35,10 +35,10 @@ ARRC=ar rc BINARIES=mail.o bezerk.o mtx.o tenex2.o mbox.o mh.o mmdf.o imap2.o pop3.o \ news.o nntpcunx.o phile.o dummy.o smtp.o nntp.o rfc822.o misc.o \ - osdep.o sm_unix.o newsrc.o + osdep.o sm_unix.o newsrc.o maildir.o CC=cc CFLAGS=$(EXTRACFLAGS) -DEFAULTDRIVERS=imap nntp pop3 mh tenex mtx mmdf bezerk news phile dummy +DEFAULTDRIVERS=maildir imap nntp pop3 mh tenex mtx mmdf bezerk news phile dummy LN=ln -s MAKE=make MV=mv @@ -427,6 +427,7 @@ smtp.o: mail.h smtp.h rfc822.h misc.h osdep.h rfc822.o: mail.h rfc822.h misc.h tenex2.o: mail.h tenex2.h rfc822.h misc.h dummy.h osdep.h +maildir.o: mail.h maildir.h misc.h osdep.h rfc822.h # OS-dependent module diff -Nur pine3.96.dist/imap/ANSI/c-client/bezerk.c pine3.96.local/imap/ANSI/c-client/bezerk.c --- pine3.96.dist/imap/ANSI/c-client/bezerk.c Tue Oct 15 15:21:57 1996 +++ pine3.96.local/imap/ANSI/c-client/bezerk.c Thu Jan 29 01:01:32 1998 @@ -774,6 +774,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = bezerk_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = bezerk_search_string (bezerk_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = bezerk_search_seen; @@ -2047,6 +2049,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char bezerk_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return bezerk_search_to (stream,msgno,d,n) || + bezerk_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/bezerk.h pine3.96.local/imap/ANSI/c-client/bezerk.h --- pine3.96.dist/imap/ANSI/c-client/bezerk.h Wed Apr 12 22:38:11 1995 +++ pine3.96.local/imap/ANSI/c-client/bezerk.h Thu Jan 29 01:01:32 1998 @@ -284,6 +284,7 @@ char bezerk_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char bezerk_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char bezerk_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char bezerk_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char bezerk_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); diff -Nur pine3.96.dist/imap/ANSI/c-client/env_unix.c pine3.96.local/imap/ANSI/c-client/env_unix.c --- pine3.96.dist/imap/ANSI/c-client/env_unix.c Fri Feb 21 10:17:11 1997 +++ pine3.96.local/imap/ANSI/c-client/env_unix.c Sat Feb 7 20:09:08 1998 @@ -46,7 +46,7 @@ static int blackBox = NIL; /* is a black box */ static long mbx_protection = 0600; static long sub_protection = 0600; -static long lock_protection = 0666; +static long lock_protection = 0600; static long disableFcntlLock = /* flock() emulator is a no-op */ #ifdef SVR4_DISABLE_FLOCK T @@ -393,9 +393,20 @@ { char *s = strrchr (fname,'/'); struct stat sbuf; + char *e, *e1; + + e = getenv("TMPDIR"); + if (!e) e = getenv("HOME"); + if (!e || *e == '\0') { + e = "/tmp/"; + e1 = ""; + } else { + e1 = e + strlen(e) - 1; + e1 = (*e1 == '/') ? "" : "/"; + } if (stat (fname,&sbuf)) /* get file status */ - sprintf (tmp,"/tmp/.%s",s ? s : fname); - else sprintf (tmp,"/tmp/.%hx.%lx",sbuf.st_dev,sbuf.st_ino); + sprintf (tmp,"%s%s.%s", e, e1, s ? s : fname); + else sprintf (tmp,"%s%s.%hx.%lx", e, e1, sbuf.st_dev, sbuf.st_ino); return chk_notsymlink (tmp,T) ? tmp : NIL; } diff -Nur pine3.96.dist/imap/ANSI/c-client/maildir.c pine3.96.local/imap/ANSI/c-client/maildir.c --- pine3.96.dist/imap/ANSI/c-client/maildir.c Wed Dec 31 16:00:00 1969 +++ pine3.96.local/imap/ANSI/c-client/maildir.c Sat Feb 7 19:44:34 1998 @@ -0,0 +1,1618 @@ +/* + * Program: Maildir routines + * + * Author: Eric Green + * Bloodhounds International Inc. + * thrytis@imaxx.net + * + * Additional contributions from: + * Aidas Kasparas (kaspar@soften.ktu.lt) + * + * Date: 27 April 1997 + * Last Edited: 13 June 1997 + * + * Based (heavily) on mh.c and other c-client library files by Mark Crispin: + * + * Mark Crispin + * Networks and Distributed Computing + * Computing & Communications + * University of Washington + * Administration Building, AG-44 + * Seattle, WA 98195 + * Internet: MRC@CAC.Washington.EDU + * + * Copyright 1995 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 +#include +#include +extern int errno; /* just in case */ +#include "mail.h" +#include "osdep.h" +#include +#include +#include +#include +#include "maildir.h" +#include "rfc822.h" +#include "misc.h" + +/* Maildir routines */ + + +/* Driver dispatch used by MAIL */ + +DRIVER maildirdriver = { + "maildir", /* driver name */ + (DRIVER *) NIL, /* next driver */ + maildir_valid, /* mailbox is valid for us */ + maildir_parameters, /* manipulate parameters */ + maildir_find, /* find mailboxes */ + maildir_find_bboards, /* find bboards */ + maildir_find_all, /* find all mailboxes */ + maildir_find_all_bboards, /* find all bboards */ + maildir_subscribe, /* subscribe to mailbox */ + maildir_unsubscribe, /* unsubscribe from mailbox */ + maildir_subscribe_bboard, /* subscribe to bboard */ + maildir_unsubscribe_bboard, /* unsubscribe from bboard */ + maildir_create, /* create mailbox */ + maildir_delete, /* delete mailbox */ + maildir_rename, /* rename mailbox */ + maildir_open, /* open mailbox */ + maildir_close, /* close mailbox */ + maildir_fetchfast, /* fetch message "fast" attributes */ + maildir_fetchflags, /* fetch message flags */ + maildir_fetchstructure, /* fetch message structure */ + maildir_fetchheader, /* fetch message header only */ + maildir_fetchtext, /* fetch message body only */ + maildir_fetchbody, /* fetch message body section */ + maildir_setflag, /* set message flag */ + maildir_clearflag, /* clear message flag */ + maildir_search, /* search for message based on criteria */ + maildir_ping, /* ping mailbox to see if still alive */ + maildir_check, /* check for new messages */ + maildir_expunge, /* expunge deleted messages */ + maildir_copy, /* copy messages to another mailbox */ + maildir_move, /* move messages to another mailbox */ + maildir_append, /* append string message to mailbox */ + maildir_gc /* garbage collect stream */ +}; + + /* prototype stream */ +MAILSTREAM maildirproto = {&maildirdriver}; + +/* Maildir validate mailbox + * Accepts: mailbox name + * Returns: our driver if name is valid, NIL otherwise + */ + +DRIVER *maildir_valid (char *name) +{ + return maildir_isvalid(name,T) ? &maildirdriver : NIL; +} + +/* Maildir test for valid mailbox + * Accepts: mailbox name + * name only test flag + * Returns: T if valid, NIL otherwise + */ + +int maildir_isvalid (char *name,long justname) +{ + char tmp[MAILTMPLEN]; + struct stat sbuf; + + if (!name || (!*name) || + ((*name == '#') && + (*(name+1) == 0 || + (*(name+1) != 'm' && *(name+1) != 'M') || + (*(name+2) != 'd' && *(name+1) != 'D') || + *(name+3) != '/'))) + return NIL; + + /* If we are requested only to check + if the name is appropriate then we + have done! */ + if (justname && *name == '#') return T; + + /* must be valid local mailbox */ + if ((*name != '*') && (*name != '{') && + maildir_file (tmp,name) && + /* assume its maildir if its a dir */ + stat (tmp,&sbuf) == 0 && S_ISDIR (sbuf.st_mode)) + return T; + + /* INBOX is for default Maildir */ + if (!strcmp (ucase (strcpy (tmp,name)), "INBOX") && + (stat (maildir_file (tmp,name),&sbuf) == 0) && + S_ISDIR (sbuf.st_mode)) + return T; + + return NIL; +} + + +/* Maildir manipulate driver parameters + * Accepts: function code + * function-dependent value + * Returns: function-dependent return value + */ + +void *maildir_parameters (long function,void *value) +{ + return NIL; +} + +/* Maildir find list of subscribed mailboxes + * Accepts: mail stream + * pattern to search + */ + +void maildir_find (MAILSTREAM *stream,char *pat) +{ + void *s = NIL; + char *t; + + /* read subscription database */ + if (stream) while (t = sm_read (&s)) + if (pmatch (t,pat) && maildir_isvalid (t,NIL)) mm_mailbox (t); +} + +/* Maildir find list of subscribed bboards + * Accepts: mail stream + * pattern to search + */ + +void maildir_find_bboards (MAILSTREAM *stream,char *pat) +{ + /* always a no-op */ +} + +/* Maildir find list of all mailboxes + * Accepts: mail stream + * pattern to search + */ + +void maildir_find_all (MAILSTREAM *stream,char *pat) +{ + DIR *dirp; + struct direct *d; + char file[MAILTMPLEN]; + char *s,*t; + int i = 0; + if (*pat == '{') return; /* local only */ + if (s = strrchr (pat,'/')) { /* directory specified in pattern? */ + strncpy (file,pat,i = (++s) - pat); + file[i] = '\0'; /* tie off prefix */ + t = file; + } + else t = myhomedir (); /* use home directory to search */ + if (dirp = opendir (t)) { /* now open that directory */ + while (d = readdir (dirp)) /* for each directory entry */ + if ((d->d_name[0] != '.') || + (d->d_name[1] && ((d->d_name[1] != '.') || d->d_name[2]))) { + strcpy (file + i,d->d_name); + if (pmatch (file,pat)) mm_mailbox (file); + } + closedir (dirp); /* flush directory */ + } + /* always an INBOX */ + if (pmatch ("INBOX",pat)) mm_mailbox ("INBOX"); +} + +/* Maildir find list of all bboards + * Accepts: mail stream + * pattern to search + */ + +void maildir_find_all_bboards (MAILSTREAM *stream,char *pat) +{ + /* Always a no-op */ +} + +/* Maildir subscribe to mailbox + * Accepts: mail stream + * mailbox to add to subscription list + * Returns: T on success, NIL on failure + */ + +long maildir_subscribe (MAILSTREAM *stream,char *mailbox) +{ + return sm_subscribe (mailbox); +} + + +/* Maildir unsubscribe to mailbox + * Accepts: mail stream + * mailbox to delete from subscription list + * Returns: T on success, NIL on failure + */ + +long maildir_unsubscribe (MAILSTREAM *stream,char *mailbox) +{ + return sm_unsubscribe (mailbox); +} + + +/* Maildir subscribe to bboard + * Accepts: mail stream + * bboard to add to subscription list + * Returns: T on success, NIL on failure + */ + +long maildir_subscribe_bboard (MAILSTREAM *stream,char *mailbox) +{ + return NIL; /* always fails */ +} + + +/* Maildir unsubscribe to bboard + * Accepts: mail stream + * bboard to delete from subscription list + * Returns: T on success, NIL on failure + */ + +long maildir_unsubscribe_bboard (MAILSTREAM *stream,char *mailbox) +{ + return NIL; /* always fails */ +} + +/* Maildir create mailbox + * Accepts: mail stream + * mailbox name to create + * driver type to use + * Returns: T on success, NIL on failure + */ + +long maildir_create (MAILSTREAM *stream,char *mailbox) +{ + char tmp[MAILTMPLEN]; + char err[MAILTMPLEN]; + int fnlen, i; + char *subdir_names[] = {"/cur","/new","/tmp",NULL}; + + /* must not already exist */ + if (access (maildir_file (tmp,mailbox),F_OK) == 0) { + sprintf (err,"Can't create mailbox %s: mailbox already exists",mailbox); + mm_log (err,ERROR); + return NIL; + } + + maildir_file (tmp,mailbox); /* get file name */ + fnlen = strlen (tmp); + tmp[fnlen - 4] = '\0'; /* making main directory's name */ + fnlen -= 4; + + if (mkdir (tmp,0700)) { /* try to make new dir */ + sprintf (err,"Can't create mailbox %s: %s %s", + mailbox,tmp,strerror (errno)); + mm_log (err,ERROR); + return NIL; + } + + for (i = 0; subdir_names[i]; i++) { + strcpy (tmp + fnlen,subdir_names[i]); + + if (mkdir (tmp,0700)) { /* try to make new dir */ + sprintf (err,"Can't create mailbox %s: %s %s", + mailbox,tmp,strerror (errno)); + mm_log (err,ERROR); + return NIL; + } + } + + return T; /* return success */ +} + + +/* Maildir delete mailbox + * Accepts: mail stream + * mailbox name to delete + * Returns: T on success, NIL on failure + */ + +long maildir_delete (MAILSTREAM *stream,char *mailbox) +{ + DIR *dirp; + struct direct *d; + int i,j; + char tmp[MAILTMPLEN],err[MAILTMPLEN]; + char *subdir_names[] = {"cur/","new/","tmp/",NULL}; + + /* check if mailbox even exists */ + if (!maildir_isvalid (mailbox,NIL)) { + sprintf (tmp,"Can't delete mailbox %s: no such mailbox",mailbox); + mm_log (tmp,ERROR); + return NIL; + } + + /* get name of directory */ + i = strlen (maildir_file (tmp,mailbox)) + 1; + for (j = 0; subdir_names[j]; j++) { + strcpy (tmp + i - 4,subdir_names[j]); + if (dirp = opendir (tmp)) { /* open directory */ + while (d = readdir (dirp)) /* empty the directory */ + if (strcmp (d->d_name,".") && strcmp (d->d_name,"..")) { + strcpy (tmp + i,d->d_name); + unlink (tmp); + } + closedir (dirp); /* flush directory */ + } + /* remove the subdir */ + tmp[i + 3] = '\0'; + if (rmdir (tmp)) { + sprintf (err,"Can't delete directory %s: %s",tmp,strerror (errno)); + mm_log (err,ERROR); + } + } + + /* try to remove the directory */ + *(tmp + i - 5) = '\0'; + if (rmdir (tmp)) { + sprintf (err,"Can't delete mailbox %s: %s",mailbox,strerror (errno)); + mm_log (err,ERROR); + return NIL; + } + return T; /* return success */ +} + + +/* Mail rename mailbox + * Accepts: mail stream + * old mailbox name + * new mailbox name + * Returns: T on success, NIL on failure + */ + +long maildir_rename (MAILSTREAM *stream,char *old,char *new) +{ + char tmp[MAILTMPLEN],tmpnew[MAILTMPLEN]; + + /* old mailbox name must be valid */ + if (!maildir_isvalid (old,NIL)) { + sprintf (tmp,"Can't rename mailbox %s: no such mailbox",old); + mm_log (tmp,ERROR); + return NIL; + } + + /* new mailbox name must not exist */ + if (access (maildir_file (tmp,new),F_OK) == 0) { + sprintf (tmp,"Can't rename to mailbox %s: destination already exists",new); + mm_log (tmp,ERROR); + return NIL; + } + + /* try to rename the directory */ + if (rename (maildir_file (tmp,old),maildir_file (tmpnew,new))) { + sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,new,strerror (errno)); + mm_log (tmp,ERROR); + return NIL; + } + return T; /* return success */ +} + +/* Maildir open + * Accepts: stream to open + * Returns: stream on success, NIL on failure + */ + +MAILSTREAM *maildir_open (MAILSTREAM *stream) +{ + int fd; + char tmp[MAILTMPLEN],tmp2[MAILTMPLEN]; + struct stat sbuf; + /* OP_PROTOTYPE call */ + if (!stream) return &maildirproto; + if (LOCAL) { /* close old file if stream being recycled */ + maildir_close (stream); /* dump and save the changes */ + stream->dtb = &maildirdriver; /* reattach this driver */ + mail_free_cache (stream); /* clean up cache */ + } + + stream->local = fs_get (sizeof (MAILDIRLOCAL)); + /* note if an INBOX or not */ + LOCAL->inbox = !strcmp (ucase (strcpy (tmp,stream->mailbox)),"INBOX") || + !strcmp (stream->mailbox,maildir_file (tmp2,"INBOX")); + LOCAL->dir = cpystr (maildir_file (tmp,stream->mailbox)); /* copy dir name */ + /* make temporary buffer */ + LOCAL->buf = (char *) fs_get ((LOCAL->buflen = MAXMESSAGESIZE) + 1); + LOCAL->scantime = 0; /* not scanned yet */ + LOCAL->hdr = NIL; + stream->sequence++; /* bump sequence number */ + stream->nmsgs = stream->recent = 0; + + /* do it twice so that we can check for new messages correctly */ + maildir_ping_core(stream); + if (maildir_ping (stream) && !(stream->nmsgs || stream->silent)) + mm_log ("Mailbox is empty",(long) NIL); + + maildir_clean (LOCAL->dir); /* clean out tmp qmail dir */ + return stream; /* return stream to caller */ +} + + +/* Maildir close + * Accepts: MAIL stream + */ + +void maildir_close (MAILSTREAM *stream) +{ + MESSAGECACHE *elt; + int i; + mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); + + /* clean out the cached paths */ + for (i = 1; i <= stream->nmsgs; i++) + if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) && elt->data1) + fs_give ((void **) &elt->data1); + + if (LOCAL) { /* only if a stream is open */ + if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); + maildir_gc (stream,GC_TEXTS); /* free local cache */ + /* free local scratch buffer */ + if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); + /* nuke the local data */ + fs_give ((void **) &stream->local); + stream->dtb = NIL; /* log out the DTB */ + } +} + +/* Maildir fetch fast information + * Accepts: MAIL stream + * sequence + */ + +void maildir_fetchfast (MAILSTREAM *stream,char *sequence) +{ + long i; + /* ugly and slow */ + if (stream && LOCAL && mail_sequence (stream,sequence)) + for (i = 1; i <= stream->nmsgs; i++) + if (mail_elt (stream,i)->sequence) + maildir_fetchheader (stream,i); +} + + +/* Maildir fetch flags + * Accepts: MAIL stream + * sequence + */ + +void maildir_fetchflags (MAILSTREAM *stream,char *sequence) +{ + return; /* no-op for local mail */ +} + + +/* Maildir fetch envelope + * Accepts: MAIL stream + * message # to fetch + * pointer to return body + * Returns: envelope of this message, body returned in body value + */ + +ENVELOPE *maildir_fetchstructure (MAILSTREAM *stream,long msgno,BODY **body) +{ + char *h,*t; + LONGCACHE *lelt; + ENVELOPE **env; + STRING bs; + BODY **b; + if (stream->scache) { /* short cache */ + if (msgno != stream->msgno){/* flush old poop if a different message */ + mail_free_envelope (&stream->env); + mail_free_body (&stream->body); + } + stream->msgno = msgno; + env = &stream->env; /* get pointers to envelope and body */ + b = &stream->body; + } + else { /* long cache */ + lelt = mail_lelt (stream,msgno); + env = &lelt->env; /* get pointers to envelope and body */ + b = &lelt->body; + } + if ((body && !*b) || !*env) { /* have the poop we need? */ + mail_free_envelope (env); /* flush old envelope and body */ + mail_free_body (b); + h = maildir_fetchheader (stream,msgno); + /* can't use fetchtext since it'll set seen */ + t = stream->text ? stream->text : ""; + INIT (&bs,mail_string,(void *) t,strlen (t)); + /* parse envelope and body */ + rfc822_parse_msg (env,body ? b : NIL,h,strlen (h),&bs,mylocalhost (), + LOCAL->buf); + } + if (body) *body = *b; /* return the body */ + return *env; /* return the envelope */ +} + + +/* Maildir fetch message header + * Accepts: MAIL stream + * message # to fetch + * Returns: message header in RFC822 format + */ + +char *maildir_fetchheader (MAILSTREAM *stream,long msgno) +{ + unsigned long i,hdrsize; + int fd; + char *s,*b; + char tmp[MAILTMPLEN]; + struct stat sbuf; + struct tm *tm; + MESSAGECACHE *elt = mail_elt (stream,msgno); + + if (stream->msgno != msgno) { + maildir_gc (stream,GC_TEXTS); /* invalidate current cache */ + /* build message file name */ + sprintf (tmp,"%s/%s",LOCAL->dir,(char *) elt->data1); + if ((fd = open (tmp,O_RDONLY,NIL)) >= 0) { + fstat (fd,&sbuf); /* get size of message */ + /* make plausible IMAPish date string */ + tm = gmtime (&sbuf.st_mtime); + elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; + elt->year = tm->tm_year + 1900 - BASEYEAR; + elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; + elt->seconds = tm->tm_sec; + elt->zhours = 0; elt->zminutes = 0; + /* slurp message */ + read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); + s[sbuf.st_size] = '\0'; /* tie off file */ + close (fd); /* close file */ + + for (i = 0,b = s; *b && !(i && (*b == '\n')); i = (*b++ == '\n')); + hdrsize = (*b ? ++b:b)-s; /* number of header bytes */ + elt->rfc822_size = /* size of entire message in CRLF form */ + strcrlfcpy (&LOCAL->hdr,&i,s,hdrsize) + + strcrlfcpy (&stream->text,&i,b,sbuf.st_size - hdrsize); + fs_give ((void **) &s); + } + } + + return LOCAL->hdr ? LOCAL->hdr : ""; +} + +/* Maildir fetch message text (body only) + * Accepts: MAIL stream + * message # to fetch + * Returns: message text in RFC822 format + */ + +char *maildir_fetchtext (MAILSTREAM *stream,long msgno) +{ + MESSAGECACHE *elt = mail_elt (stream,msgno); + /* snarf message if don't have it yet */ + if (stream->msgno != msgno) maildir_fetchheader (stream,msgno); + if (!elt->seen) maildir_elt_setflag(stream,elt,fSEEN); /* mark as seen */ + return stream->text ? stream->text : ""; +} + + +/* Maildir fetch message body as a structure + * Accepts: Mail stream + * message # to fetch + * section specifier + * Returns: pointer to section of message body + */ + +char *maildir_fetchbody (MAILSTREAM *stream,long m,char *s,unsigned long *len) +{ + BODY *b; + PART *pt; + unsigned long i; + char *base; + unsigned long offset = 0; + MESSAGECACHE *elt = mail_elt (stream,m); + /* make sure have a body */ + if (!(maildir_fetchstructure (stream,m,&b) && b && s && *s && + ((i = strtol (s,&s,10)) > 0) && (base = maildir_fetchtext (stream,m)))) + return NIL; + do { /* until find desired body part */ + /* multipart content? */ + if (b->type == TYPEMULTIPART) { + pt = b->contents.part; /* yes, find desired part */ + while (--i && (pt = pt->next)); + if (!pt) return NIL; /* bad specifier */ + /* note new body, check valid nesting */ + if (((b = &pt->body)->type == TYPEMULTIPART) && !*s) return NIL; + offset = pt->offset; /* get new offset */ + } + else if (i != 1) return NIL;/* otherwise must be section 1 */ + /* need to go down further? */ + if (i = *s) switch (b->type) { + case TYPEMESSAGE: /* embedded message */ + offset = b->contents.msg.offset; + b = b->contents.msg.body; /* get its body, drop into multipart case */ + case TYPEMULTIPART: /* multipart, get next section */ + if ((*s++ == '.') && (i = strtol (s,&s,10)) > 0) break; + default: /* bogus subpart specification */ + return NIL; + } + } while (i); + /* lose if body bogus */ + if ((!b) || b->type == TYPEMULTIPART) return NIL; + if (!elt->seen) maildir_elt_setflag(stream,elt,fSEEN); /* mark as seen */ + return rfc822_contents (&LOCAL->buf,&LOCAL->buflen,len,base + offset, + b->size.ibytes,b->encoding); +} + + +/* Maildir set flag + * Accepts: MAIL stream + * sequence + * flag(s) + */ + +void maildir_setflag (MAILSTREAM *stream,char *sequence,char *flag) +{ + MESSAGECACHE *elt; + long i; + short f = maildir_getflags (stream,flag); + if (!f) return; /* no-op if no flags to modify */ + /* get sequence and loop on it */ + + if (mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) + if ((elt = mail_elt (stream,i))->sequence) + /* set all requested flags */ + maildir_elt_setflag (stream,elt,f); +} + + +/* Maildir clear flag + * Accepts: MAIL stream + * sequence + * flag(s) + */ + +void maildir_clearflag (MAILSTREAM *stream,char *sequence,char *flag) +{ + MESSAGECACHE *elt; + long i = stream->nmsgs; + int changed = NIL; + short f = maildir_getflags (stream,flag); + if (!f) return; /* no-op if no flags to modify */ + /* get sequence and loop on it */ + if (mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) + if ((elt = mail_elt (stream,i))->sequence) { + /* clear all requested flags */ + if (f&fSEEN && elt->seen) { + elt->seen = NIL; + changed = T; + } + if (f&fDELETED && elt->deleted) { + elt->deleted = NIL; + changed = T; + } + if (f&fFLAGGED && elt->flagged) { + elt->flagged = NIL; + changed = T; + } + if (f&fANSWERED && elt->answered) { + elt->answered = NIL; + changed = T; + } + + if (changed) /* write new flags to disk */ + maildir_write_flags (stream,elt); + } +} + +/* Maildir search for messages + * Accepts: MAIL stream + * search criteria + */ + +void maildir_search (MAILSTREAM *stream,char *criteria) +{ + long i,n; + char *d; + search_t f; + /* initially all searched */ + for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = T; + /* get first criterion */ + if (criteria && (criteria = strtok (criteria," "))) { + /* for each criterion */ + for (; criteria; (criteria = strtok (NIL," "))) { + f = NIL; d = NIL; n = 0; /* init then scan the criterion */ + switch (*ucase (criteria)) { + case 'A': /* possible ALL, ANSWERED */ + if (!strcmp (criteria+1,"LL")) f = maildir_search_all; + else if (!strcmp (criteria+1,"NSWERED")) f = maildir_search_answered; + break; + case 'B': /* possible BCC, BEFORE, BODY */ + if (!strcmp (criteria+1,"CC")) + f = maildir_search_string (maildir_search_bcc,&d,&n); + else if (!strcmp (criteria+1,"EFORE")) + f = maildir_search_date (maildir_search_before,&n); + else if (!strcmp (criteria+1,"ODY")) + f = maildir_search_string (maildir_search_body,&d,&n); + break; + case 'C': /* possible CC */ + if (!strcmp (criteria+1,"C")) + f = maildir_search_string (maildir_search_cc,&d,&n); + break; + case 'D': /* possible DELETED */ + if (!strcmp (criteria+1,"ELETED")) f = maildir_search_deleted; + break; + case 'F': /* possible FLAGGED, FROM */ + if (!strcmp (criteria+1,"LAGGED")) f = maildir_search_flagged; + else if (!strcmp (criteria+1,"ROM")) + f = maildir_search_string (maildir_search_from,&d,&n); + break; + case 'K': /* possible KEYWORD */ + if (!strcmp (criteria+1,"EYWORD")) + f = maildir_search_flag (maildir_search_keyword,&d); + break; + case 'N': /* possible NEW */ + if (!strcmp (criteria+1,"EW")) f = maildir_search_new; + break; + + case 'O': /* possible OLD, ON */ + if (!strcmp (criteria+1,"LD")) f = maildir_search_old; + else if (!strcmp (criteria+1,"N")) + f = maildir_search_date (maildir_search_on,&n); + break; + case 'R': /* possible RECENT */ + if (!strcmp (criteria+1,"ECENT")) f = maildir_search_recent; + else if (!strcmp (criteria+1, "ECIPIENT")) + f = maildir_search_string (maildir_search_recipient,&d,&n); + break; + case 'S': /* possible SEEN, SINCE, SUBJECT */ + if (!strcmp (criteria+1,"EEN")) f = maildir_search_seen; + else if (!strcmp (criteria+1,"INCE")) + f = maildir_search_date (maildir_search_since,&n); + else if (!strcmp (criteria+1,"UBJECT")) + f = maildir_search_string (maildir_search_subject,&d,&n); + break; + case 'T': /* possible TEXT, TO */ + if (!strcmp (criteria+1,"EXT")) + f = maildir_search_string (maildir_search_text,&d,&n); + else if (!strcmp (criteria+1,"O")) + f = maildir_search_string (maildir_search_to,&d,&n); + break; + case 'U': /* possible UN* */ + if (criteria[1] == 'N') { + if (!strcmp (criteria+2,"ANSWERED")) f = maildir_search_unanswered; + else if (!strcmp (criteria+2,"DELETED")) f = maildir_search_undeleted; + else if (!strcmp (criteria+2,"FLAGGED")) f = maildir_search_unflagged; + else if (!strcmp (criteria+2,"KEYWORD")) + f = maildir_search_flag (maildir_search_unkeyword,&d); + else if (!strcmp (criteria+2,"SEEN")) f = maildir_search_unseen; + } + break; + default: /* we will barf below */ + break; + } + if (!f) { /* if can't determine any criteria */ + sprintf (LOCAL->buf,"Unknown search criterion: %s",criteria); + mm_log (LOCAL->buf,ERROR); + return; + } + /* run the search criterion */ + for (i = 1; i <= stream->nmsgs; ++i) + if (mail_elt (stream,i)->searched && !(*f) (stream,i,d,n)) + mail_elt (stream,i)->searched = NIL; + } + /* report search results to main program */ + for (i = 1; i <= stream->nmsgs; ++i) + if (mail_elt (stream,i)->searched) mail_searched (stream,i); + } +} + + +/* Maildir ping mailbox + * Accepts: MAIL stream + * Returns: T if stream alive, else NIL + * No-op for readonly files, since read/writer can expunge it from under us! + * + * Note: this depends on qmail naming of messages + */ + +long maildir_ping_core (MAILSTREAM *stream) +{ + char tmp[MAILTMPLEN]; + MESSAGECACHE *elt; + struct stat sbuf; + DIR *dir; + struct direct *d; + int reloadall = NIL; + long i; + long nmsgs = stream->nmsgs; + long recent = 0; + char *s; + mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); + + if (stat (LOCAL->dir,&sbuf) < 0) { + sprintf (tmp,"Unable to open maildir: %s",strerror (errno)); + mm_log (tmp,ERROR); + return NIL; + } + + if (sbuf.st_ctime != LOCAL->scantime) { + /* update the message list */ + struct direct **names = NIL; + nmsgs = scandir (LOCAL->dir,&names,maildir_select,maildir_namesort); + + mm_critical (stream); /* go critical */ + LOCAL->scantime = sbuf.st_ctime; + + /* check if old files same */ + for (i = 0; i < stream->nmsgs; i++) + if (strcmp ((char *) mail_elt (stream, i + 1)->data1, + names[i]->d_name)) { + reloadall = T; + break; + } + + if (reloadall) { /* files are out of order, rebuild cache */ + i = 1; + while (i <= stream->nmsgs) + /* clean out cache */ + if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT))) { + fs_give ((void **) &elt->data1); + mail_expunged (stream,i); + } + else + i++; + + mm_log ("Warning: Mailbox has changed in an unexpected way. Reloading.", + WARN); + stream->nmsgs = 0; + } + + for (i = stream->nmsgs; i < nmsgs; i++) { + /* if newly seen, add to list */ + (elt = mail_elt (stream, i + 1))->data1 = (long) cpystr (names[i]->d_name); + elt->valid = T; + elt->recent = T; + recent++; + + /* grab the flags */ + if ((s = strstr (names[i]->d_name,":2,"))) { + s += 3; + if (strchr (s,'F')) + elt->flagged = T; + if (strchr (s,'R')) + elt->answered = T; + if (strchr (s,'S')) + elt->seen = T; + if (strchr (s,'T')) + elt->deleted = T; + } + } + mm_nocritical (stream); /* release critical */ + /* free the names stuff */ + for (i = 0; i < nmsgs; i++) + fs_give ((void **) &names[i]); + if (names) + fs_give ((void **) &names); + } + mail_exists (stream,nmsgs); /* notify upper level of mailbox size */ + if (!reloadall) mail_recent (stream,recent); + return T; /* return that we are alive */ +} + +long maildir_ping (MAILSTREAM *stream) +{ + maildir_copynew (LOCAL->dir); + return maildir_ping_core(stream); +} + + +/* Maildir check mailbox + * Accepts: MAIL stream + * No-op for readonly files, since read/writer can expunge it from under us! + */ + +void maildir_check (MAILSTREAM *stream) +{ + /* Perhaps in the future this will preserve flags */ + if (maildir_ping (stream)) mm_log ("Check completed",(long) NIL); +} + + +/* Maildir expunge mailbox + * Accepts: MAIL stream + */ + +void maildir_expunge (MAILSTREAM *stream) +{ + MESSAGECACHE *elt; + unsigned long i = 1; + unsigned long n = 0; + unsigned long recent = stream->recent; + + maildir_gc (stream,GC_TEXTS); /* invalidate texts */ + mm_critical (stream); /* go critical */ + while (i <= stream->nmsgs) { /* for each message */ + /* if deleted, need to trash it */ + if ((elt = mail_elt (stream,i))->deleted) { + sprintf (LOCAL->buf,"%s/%s",LOCAL->dir,(char *) elt->data1); + if (unlink (LOCAL->buf)) {/* try to delete the message */ + sprintf (LOCAL->buf,"Expunge of message %ld failed, aborted: %s",i, + strerror (errno)); + mm_log (LOCAL->buf,WARN); + break; + } + /* free the cached filename */ + if (elt->data1) fs_give ((void **) &elt->data1); + if (elt->recent) --recent;/* if recent, note one less recent message */ + mail_expunged (stream,i); /* notify upper levels */ + n++; /* count up one more expunged message */ + } + else i++; /* otherwise try next message */ + } + if (n) { /* output the news if any expunged */ + sprintf (LOCAL->buf,"Expunged %ld messages",n); + mm_log (LOCAL->buf,(long) NIL); + } + else mm_log ("No messages deleted, so no update needed",(long) NIL); + mm_nocritical (stream); /* release critical */ + /* notify upper level of new mailbox size */ + mail_exists (stream,stream->nmsgs); + mail_recent (stream,recent); +} + +/* Maildir copy message(s) + * Accepts: MAIL stream + * sequence + * destination mailbox + * Returns: T if copy successful, else NIL + */ + +long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox) +{ + STRING st; + MESSAGECACHE *elt; + struct stat sbuf; + int fd; + long i; + char *s,tmp[MAILTMPLEN]; + /* copy the messages */ + if (mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) + if ((elt = mail_elt (stream,i))->sequence) { + sprintf (LOCAL->buf,"%s/%s",LOCAL->dir,(char *) elt->data1); + if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL; + fstat (fd,&sbuf); /* get size of message */ + /* slurp message */ + read (fd,s = (char *) fs_get (sbuf.st_size +1),sbuf.st_size); + s[sbuf.st_size] = '\0'; /* tie off file */ + close (fd); /* flush message file */ + INIT (&st,mail_string,(void *) s,sbuf.st_size); + sprintf (LOCAL->buf,"%s%s%s%s%s)", + elt->seen ? " \\Seen" : "", + elt->deleted ? " \\Deleted" : "", + elt->flagged ? " \\Flagged" : "", + elt->answered ? " \\Answered" : "", + (elt->seen || elt->deleted || elt->flagged || elt->answered) ? + "" : " "); + LOCAL->buf[0] = '('; /* open list */ + mail_date (tmp,elt); /* generate internal date */ + if (!maildir_append (stream,mailbox,LOCAL->buf,tmp,&st)) { + fs_give ((void **) &s); /* give back temporary space */ + return NIL; + } + fs_give ((void **) &s); /* give back temporary space */ + } + return T; /* return success */ +} + + +/* Maildir move message(s) + * Accepts: MAIL stream + * sequence + * destination mailbox + * Returns: T if move successful, else NIL + */ + +long maildir_move (MAILSTREAM *stream,char *sequence,char *mailbox) +{ + MESSAGECACHE *elt; + if (maildir_copy (stream,sequence,mailbox)) return NIL; + /* delete all requested messages */ + maildir_setflag (stream,sequence,"\\Deleted"); + return T; +} + +/* Maildir append message string + * Accepts: mail stream + * destination mailbox + * optional flags + * optional date + * stringstruct of message to append + * Returns: T on success, NIL on failure + */ + +long maildir_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date, + STRING *message) +{ + int fd; + char c,*s; + char tmp[MAILTMPLEN],file[MAILTMPLEN],path1[MAILTMPLEN],path2[MAILTMPLEN]; + MESSAGECACHE elt; + long i; + long size = 0; + long ret = LONGT; + short uf = 0; + + /* + This is intentionaly made static. Users can ask to save a LOT of messages + at once and this program can do that within one second. Dan's assumption + that time+pid+hostname always will be unique stops being true in this + case. So we will add yet another number to host part of message file's + name. Hostname is used only to make filename unique and Dan explicitly + says that "<...> Other than this [skipping filenames starting at dot] , + readers should not attempt to parse filenames. <...>". Therefore this + addition should be no problem. Am I right, Dan? --AK + */ + + static unsigned int transact = 0; + + if (flags) /* get flags if given */ + uf = maildir_getflags (user_flags (&maildirproto),flags); + + if (date) { /* want to preserve date? */ + /* yes, parse date into an elt */ + if (!mail_parse_date (&elt,date)) { + sprintf (tmp,"Bad date in append: %s",date); + mm_log (tmp,ERROR); + return NIL; + } + } + /* N.B.: can't use LOCAL->buf for tmp */ + /* make sure valid mailbox */ + if (!maildir_isvalid (mailbox, NIL)) { + sprintf (tmp,"Not a valid Maildir mailbox: %s",mailbox); + mm_log (tmp,ERROR); + return NIL; + } + /* build file name we will use */ + sprintf (file,"%u.%d.%09u.%s:2,%s%s%s%s", + time (0),getpid (),transact++,mylocalhost (), + uf&fFLAGGED ? "F" : "",uf&fANSWERED ? "R" : "", + uf&fSEEN ? "S" : "",uf&fDELETED ? "T" : ""); + /* build tmp file name */ + sprintf (path1,"%s/../tmp/%s",maildir_file (tmp,mailbox),file); + + if ((fd = open (path1,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) { + sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); + mm_log (tmp,ERROR); + return NIL; + } + i = SIZE (message); /* get size of message */ + s = (char *) fs_get (i + 1); /* get space for the data */ + /* copy the data w/o CR's */ + while (i--) if ((c = SNX (message)) != '\015') s[size++] = c; + mm_critical (stream); /* go critical */ + /* write the data */ + if ((write (fd,s,size) < 0) || fsync (fd)) { + unlink (path1); /* delete message */ + sprintf (tmp,"Message append failed: %s",strerror (errno)); + mm_log (tmp,ERROR); + ret = NIL; + } + /* build final filename to use */ + sprintf (path2,"%s/../new/%s",maildir_file (tmp,mailbox),file); + if (link (path1,path2) < 0) { + sprintf (tmp,"Message append failed: %s",strerror (errno)); + mm_log (tmp,ERROR); + ret = NIL; + } + unlink (path1); + + close (fd); /* close the file */ + mm_nocritical (stream); /* release critical */ + fs_give ((void **) &s); /* flush the buffer */ + return ret; +} + + +/* Maildir garbage collect stream + * Accepts: mail stream + * garbage collection flags + */ + +void maildir_gc (MAILSTREAM *stream,long gcflags) +{ + unsigned long i; + + if (gcflags & GC_TEXTS) { /* garbage collect texts? */ + /* flush texts from cache */ + if (LOCAL->hdr) fs_give ((void **) &LOCAL->hdr); + if (stream->text) fs_give ((void **) &stream->text); + stream->msgno = 0; /* invalidate stream text */ + } +} + +/* Internal routines */ + + +/* Maildir file name selection test + * Accepts: candidate directory entry + * Returns: T to use file name, NIL to skip it + */ + +int maildir_select (struct direct *name) +{ + if (name->d_name[0] != '.') + return T; + + return NIL; +} + + +/* Maildir file name comparision + * Accepts: first candidate directory entry + * second candidate directory entry + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 + */ + +int maildir_namesort (struct direct **d1,struct direct **d2) +{ + return strcmp ((*d1)->d_name,(*d2)->d_name); +} + + +/* Maildir mail generate file string + * Accepts: temporary buffer to write into (at least MAILTMPLEN long) + * mailbox name string + * Returns: local file string + */ + +char *maildir_file (char *dst,char *name) +{ + char tmp[MAILTMPLEN]; + + if (strlen (name) > 3 && /* safe do other comparisons */ + (*name == '#') && + (name[1] == 'm' || name[1] == 'M') && + (name[2] == 'd' || name[2] == 'D') && + (name[3] == '/')) + name += 4; + + if (*name == '/') { /* if absolute path given, just append /cur */ + strncpy (dst, name, MAILTMPLEN - 2); + strncat (dst, "/cur", MAILTMPLEN - 2); + dst[MAILTMPLEN - 1] = '\0'; + } + else + sprintf (dst,"%s/%s/cur",myhomedir (), + strcmp (ucase (strcpy (tmp, name)), "INBOX") ? name : MAILDIRPATH); + + return dst; +} + + +/* Parse flag list + * Accepts: MAIL stream + * flag list as a character string + * Returns: flag command list + */ + +short maildir_getflags (MAILSTREAM *stream,char *flag) +{ + return bezerk_getflags (stream,flag); /* nothing exciting, reuse old code */ +} + +/* Maildir clean out tmpdir + * Accepts: the INBOX mailbox + * Returns: nothing + */ + +void maildir_clean (const char *mailbox) +{ + DIR *dir; + struct direct *d; + time_t t; + struct stat sbuf; + char tmpname[MAILTMPLEN],file[MAILTMPLEN]; + + t = time (0); + + sprintf (tmpname,"%s/../tmp",mailbox); + if (!(dir = opendir (tmpname))) + return; + + while (d = readdir (dir)) { + if (!strcmp (d->d_name,".")) continue; + if (!strcmp (d->d_name,"..")) continue; + sprintf (file,"%s/%s",tmpname,d->d_name); + if (stat (file,&sbuf) == 0) + if (t > sbuf.st_atime + 129600) + unlink (file); /* delete the file */ + } + closedir (dir); +} + + +/* Maildir copy in new mail + * Accepts: the INBOX mailbox + * Returns: nothing + */ + +void maildir_copynew (const char *mailbox) +{ + char tmp[MAILTMPLEN],file[MAILTMPLEN],newfile[MAILTMPLEN]; + DIR *dir; + struct dirent *d; + struct stat sbuf; + + sprintf (tmp,"%s/../new",mailbox); + if (!(dir = opendir (tmp))) + return; + + while (d = readdir (dir)) { + if (d->d_name[0] == '.') + continue; /* skip .files */ + + sprintf (file,"%s/%s",tmp,d->d_name); + /* make sure this is a normal file */ + if (stat (file,&sbuf) == 0 && S_ISREG (sbuf.st_mode)) { + + if (strstr (d->d_name,":2,")) /* this message already has flags */ + sprintf (newfile,"%s/%s",mailbox,d->d_name); + else + sprintf (newfile,"%s/%s:2,",mailbox,d->d_name); + + /* move the new mail to the cur dir */ + if (link (file,newfile) == -1) + mm_log("Unable to read new mail!",WARN); + else + unlink (file); + } + } + closedir (dir); +} + + +/* Maildir set flags on message + * Accepts: MAIL stream + * message cache + * bitvector of flags to set + * Returns: nothing + */ + +void maildir_elt_setflag (MAILSTREAM *stream,MESSAGECACHE *elt,char flags) +{ + int changed = NIL; + + if (!flags) return; /* no-op if no flags to modify */ + + /* set all requested flags */ + if (flags&fSEEN && !elt->seen) { + elt->seen = T; + changed = T; + } + if (flags&fDELETED && !elt->deleted) { + elt->deleted = T; + changed = T; + } + if (flags&fFLAGGED && !elt->flagged) { + elt->flagged = T; + changed = T; + } + if (flags&fANSWERED && !elt->answered) { + elt->answered = T; + changed = T; + } + + if (changed) + maildir_write_flags (stream,elt); +} + + +/* Maildir write flags on message to disk + * Accepts: MAIL stream + * message cache + * Returns: nothing + */ + +void maildir_write_flags (MAILSTREAM *stream,MESSAGECACHE *elt) +{ + char oldfile[MAILTMPLEN],newfile[MAILTMPLEN],fn[MAILTMPLEN]; + char *s; + + /* build the new filename */ + sprintf (oldfile,"%s/%s",LOCAL->dir,(char *) elt->data1); + if ((s = strchr ((char *) elt->data1,':'))) *s = '\0'; + sprintf (fn,"%s:2,%s%s%s%s",(char *) elt->data1,elt->flagged ? "F" : "", + elt->answered ? "R" : "",elt->seen ? "S" : "", + elt->deleted ? "T" : ""); + sprintf (newfile,"%s/%s",LOCAL->dir,fn); + /* rename the file with new flags */ + if (rename (oldfile,newfile) < 0) { + sprintf(oldfile,"Unable to write flags to disk: %s",strerror (errno)); + mm_log(oldfile,ERROR); + return; + } + /* update the file name in cache */ + fs_give ((void **) &elt->data1); + elt->data1 = (long) cpystr (fn); +} + + +/* Search support routines + * Accepts: MAIL stream + * message number + * pointer to additional data + * pointer to temporary buffer + * Returns: T if search matches, else NIL + */ + +char maildir_search_all (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return T; /* ALL always succeeds */ +} + + +char maildir_search_answered (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->answered ? T : NIL; +} + + +char maildir_search_deleted (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->deleted ? T : NIL; +} + + +char maildir_search_flagged (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->flagged ? T : NIL; +} + + +char maildir_search_keyword (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return NIL; /* keywords not supported yet */ +} + + +char maildir_search_new (MAILSTREAM *stream,long msgno,char *d,long n) +{ + MESSAGECACHE *elt = mail_elt (stream,msgno); + return (elt->recent && !elt->seen) ? T : NIL; +} + +char maildir_search_old (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->recent ? NIL : T; +} + + +char maildir_search_recent (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->recent ? T : NIL; +} + + +char maildir_search_seen (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->seen ? T : NIL; +} + + +char maildir_search_unanswered (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->answered ? NIL : T; +} + + +char maildir_search_undeleted (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->deleted ? NIL : T; +} + + +char maildir_search_unflagged (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->flagged ? NIL : T; +} + + +char maildir_search_unkeyword (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return T; /* keywords not supported yet */ +} + + +char maildir_search_unseen (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mail_elt (stream,msgno)->seen ? NIL : T; +} + +char maildir_search_before (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return (char) (maildir_msgdate (stream,msgno) < n); +} + + +char maildir_search_on (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return (char) (maildir_msgdate (stream,msgno) == n); +} + + +char maildir_search_since (MAILSTREAM *stream,long msgno,char *d,long n) +{ + /* everybody interprets "since" as .GE. */ + return (char) (maildir_msgdate (stream,msgno) >= n); +} + + +unsigned long maildir_msgdate (MAILSTREAM *stream,long msgno) +{ + struct stat sbuf; + struct tm *tm; + MESSAGECACHE *elt = mail_elt (stream,msgno); + if (!elt->day) { /* get date if don't have it yet */ + /* build message file name */ + sprintf (LOCAL->buf,"%s/%s",LOCAL->dir,(char *) elt->data1); + stat (LOCAL->buf,&sbuf); /* get message date */ + tm = gmtime (&sbuf.st_mtime); + elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; + elt->year = tm->tm_year + 1900 - BASEYEAR; + elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; + elt->seconds = tm->tm_sec; + elt->zhours = 0; elt->zminutes = 0; + } + return (long) (elt->year << 9) + (elt->month << 5) + elt->day; +} + +char maildir_search_body (MAILSTREAM *stream,long msgno,char *d,long n) +{ + maildir_fetchheader (stream,msgno); + return stream->text ? search (stream->text,strlen (stream->text),d,n) : NIL; +} + + +char maildir_search_subject (MAILSTREAM *stream,long msgno,char *d,long n) +{ + char *t = maildir_fetchstructure (stream,msgno,NIL)->subject; + return t ? search (t,strlen (t),d,n) : NIL; +} + + +char maildir_search_text (MAILSTREAM *stream,long msgno,char *d,long n) +{ + char *t = maildir_fetchheader (stream,msgno); + return (t && search (t,strlen (t),d,n)) || + maildir_search_body (stream,msgno,d,n); +} + +char maildir_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n) +{ + ADDRESS *a = maildir_fetchstructure (stream,msgno,NIL)->bcc; + LOCAL->buf[0] = '\0'; /* initially empty string */ + /* get text for address */ + rfc822_write_address (LOCAL->buf,a); + return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char maildir_search_cc (MAILSTREAM *stream,long msgno,char *d,long n) +{ + ADDRESS *a = maildir_fetchstructure (stream,msgno,NIL)->cc; + LOCAL->buf[0] = '\0'; /* initially empty string */ + /* get text for address */ + rfc822_write_address (LOCAL->buf,a); + return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char maildir_search_from (MAILSTREAM *stream,long msgno,char *d,long n) +{ + ADDRESS *a = maildir_fetchstructure (stream,msgno,NIL)->from; + LOCAL->buf[0] = '\0'; /* initially empty string */ + /* get text for address */ + rfc822_write_address (LOCAL->buf,a); + return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char maildir_search_to (MAILSTREAM *stream,long msgno,char *d,long n) +{ + ADDRESS *a = maildir_fetchstructure (stream,msgno,NIL)->to; + LOCAL->buf[0] = '\0'; /* initially empty string */ + /* get text for address */ + rfc822_write_address (LOCAL->buf,a); + return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + +char maildir_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return maildir_search_to (stream,msgno,d,n) + || maildir_search_cc (stream,msgno,d,n); +} + +/* Search parsers */ + + +/* Parse a date + * Accepts: function to return + * pointer to date integer to return + * Returns: function to return + */ + +search_t maildir_search_date (search_t f,long *n) +{ + long i; + char *s; + MESSAGECACHE elt; + /* parse the date and return fn if OK */ + return (maildir_search_string (f,&s,&i) && mail_parse_date (&elt,s) && + (*n = (elt.year << 9) + (elt.month << 5) + elt.day)) ? f : NIL; +} + +/* Parse a flag + * Accepts: function to return + * pointer to string to return + * Returns: function to return + */ + +search_t maildir_search_flag (search_t f,char **d) +{ + /* get a keyword, return if OK */ + return (*d = strtok (NIL," ")) ? f : NIL; +} + + +/* Parse a string + * Accepts: function to return + * pointer to string to return + * pointer to string length to return + * Returns: function to return + */ + +search_t maildir_search_string (search_t f,char **d,long *n) +{ + char *end = " "; + char *c = strtok (NIL,""); /* remainder of criteria */ + if (!c) return NIL; /* missing argument */ + switch (*c) { /* see what the argument is */ + case '{': /* literal string */ + *n = strtol (c+1,d,10); /* get its length */ + if ((*(*d)++ == '}') && (*(*d)++ == '\015') && (*(*d)++ == '\012') && + (!(*(c = *d + *n)) || (*c == ' '))) { + char e = *--c; + *c = DELIM; /* make sure not a space */ + strtok (c," "); /* reset the strtok mechanism */ + *c = e; /* put character back */ + break; + } + case '\0': /* catch bogons */ + case ' ': + return NIL; + case '"': /* quoted string */ + if (strchr (c+1,'"')) end = "\""; + else return NIL; + default: /* atomic string */ + if (*d = strtok (c,end)) *n = strlen (*d); + else return NIL; + break; + } + return f; +} diff -Nur pine3.96.dist/imap/ANSI/c-client/maildir.h pine3.96.local/imap/ANSI/c-client/maildir.h --- pine3.96.dist/imap/ANSI/c-client/maildir.h Wed Dec 31 16:00:00 1969 +++ pine3.96.local/imap/ANSI/c-client/maildir.h Thu Jan 29 02:32:02 1998 @@ -0,0 +1,153 @@ +/* + * Program: Maildir routines + * + * Author: Eric Green + * Bloodhounds International Inc. + * thrytis@imaxx.net + * + * Additional contributions from: + * Aidas Kasparas (kaspar@soften.ktu.lt) + * + * Date: 27 April 1997 + * Last Edited: 13 June 1997 + * + * Based (heavily) on mh.c and other c-client library files by Mark Crispin: + * + * Mark Crispin + * Networks and Distributed Computing + * Computing & Communications + * University of Washington + * Administration Building, AG-44 + * Seattle, WA 98195 + * Internet: MRC@CAC.Washington.EDU + * + * Copyright 1994 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. + * + */ + +/* Build parameters */ + +#define MAILDIRPATH "Maildir" + +/* Command bits from maildir_getflags() */ + +#define fSEEN 1 +#define fDELETED 2 +#define fFLAGGED 4 +#define fANSWERED 8 + +/* Maildir I/O stream local data */ + +typedef struct maildir_local { + unsigned int inbox : 1; /* if it is an INBOX or not */ + char *dir; /* mail directory name */ + char *buf; /* temporary buffer */ + char *hdr; /* current header */ + unsigned long buflen; /* current size of temporary buffer */ + time_t scantime; /* last time directory scanned */ +} MAILDIRLOCAL; + +/* Convenient access to local data */ + +#define LOCAL ((MAILDIRLOCAL *) stream->local) + +/* Function prototypes */ + +DRIVER *maildir_valid (char *name); +int maildir_isvalid (char *name,long justname); +void *maildir_parameters (long function,void *value); +void maildir_find (MAILSTREAM *stream,char *pat); +void maildir_find_bboards (MAILSTREAM *stream,char *pat); +void maildir_find_all (MAILSTREAM *stream,char *pat); +void maildir_find_all_bboards (MAILSTREAM *stream,char *pat); +long maildir_subscribe (MAILSTREAM *stream,char *mailbox); +long maildir_unsubscribe (MAILSTREAM *stream,char *mailbox); +long maildir_subscribe_bboard (MAILSTREAM *stream,char *mailbox); +long maildir_unsubscribe_bboard (MAILSTREAM *stream,char *mailbox); +long maildir_create (MAILSTREAM *stream,char *mailbox); +long maildir_delete (MAILSTREAM *stream,char *mailbox); +long maildir_rename (MAILSTREAM *stream,char *old,char *new); +MAILSTREAM *maildir_open (MAILSTREAM *stream); +void maildir_close (MAILSTREAM *stream); +void maildir_fetchfast (MAILSTREAM *stream,char *sequence); +void maildir_fetchflags (MAILSTREAM *stream,char *sequence); +ENVELOPE *maildir_fetchstructure (MAILSTREAM *stream,long msgno,BODY **body); +char *maildir_fetchheader (MAILSTREAM *stream,long msgno); +char *maildir_fetchtext (MAILSTREAM *stream,long msgno); +char *maildir_fetchbody (MAILSTREAM *stream,long m,char *sec,unsigned long *len); +void maildir_setflag (MAILSTREAM *stream,char *sequence,char *flag); +void maildir_clearflag (MAILSTREAM *stream,char *sequence,char *flag); +void maildir_search (MAILSTREAM *stream,char *criteria); +long maildir_ping (MAILSTREAM *stream); +void maildir_check (MAILSTREAM *stream); +void maildir_expunge (MAILSTREAM *stream); +long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox); +long maildir_move (MAILSTREAM *stream,char *sequence,char *mailbox); +long maildir_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date, + STRING *message); +void maildir_gc (MAILSTREAM *stream,long gcflags); + + +/* maildir utility functions */ +int maildir_select (struct direct *name); +int maildir_namesort (struct direct **d1,struct direct **d2); +char *maildir_file (char *dst,char *name); +short maildir_getflags (MAILSTREAM *stream,char *flag); +void maildir_clean (const char *mailbox); +void maildir_copynew (const char *mailbox); +void maildir_elt_setflag (MAILSTREAM *stream,MESSAGECACHE *elt,char flags); +void maildir_write_flags (MAILSTREAM *stream,MESSAGECACHE *elt); + + +/* maildir search functions */ +char maildir_search_all (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_answered (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_deleted (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_flagged (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_keyword (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_new (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_old (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_recent (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_seen (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_unanswered (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_undeleted (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_unflagged (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_unkeyword (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_unseen (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_before (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_on (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_since (MAILSTREAM *stream,long msgno,char *d,long n); +unsigned long maildir_msgdate (MAILSTREAM *stream,long msgno); +char maildir_search_body (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_subject (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_text (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_to (MAILSTREAM *stream,long msgno,char *d,long n); +char maildir_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); +typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); +search_t maildir_search_date (search_t f,long *n); +search_t maildir_search_flag (search_t f,char **d); +search_t maildir_search_string (search_t f,char **d,long *n); + + +/* extern functions */ +short bezerk_getflags (MAILSTREAM *stream,char *flag); diff -Nur pine3.96.dist/imap/ANSI/c-client/mh.c pine3.96.local/imap/ANSI/c-client/mh.c --- pine3.96.dist/imap/ANSI/c-client/mh.c Wed May 15 11:49:54 1996 +++ pine3.96.local/imap/ANSI/c-client/mh.c Thu Jan 29 01:01:32 1998 @@ -746,6 +746,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = mh_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = mh_search_string (mh_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = mh_search_seen; @@ -1381,6 +1383,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char mh_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mh_search_to (stream,msgno,d,n) || + mh_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/mh.h pine3.96.local/imap/ANSI/c-client/mh.h --- pine3.96.dist/imap/ANSI/c-client/mh.h Sun Aug 14 21:42:59 1994 +++ pine3.96.local/imap/ANSI/c-client/mh.h Thu Jan 29 01:01:32 1998 @@ -127,6 +127,7 @@ char mh_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char mh_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char mh_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char mh_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char mh_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); search_t mh_search_date (search_t f,long *n); diff -Nur pine3.96.dist/imap/ANSI/c-client/mmdf.c pine3.96.local/imap/ANSI/c-client/mmdf.c --- pine3.96.dist/imap/ANSI/c-client/mmdf.c Tue Oct 15 15:20:50 1996 +++ pine3.96.local/imap/ANSI/c-client/mmdf.c Thu Jan 29 01:01:32 1998 @@ -707,6 +707,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = mmdf_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = mmdf_search_string (mmdf_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = mmdf_search_seen; @@ -1962,6 +1964,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char mmdf_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mmdf_search_to (stream,msgno,d,n) || + mmdf_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/mmdf.h pine3.96.local/imap/ANSI/c-client/mmdf.h --- pine3.96.dist/imap/ANSI/c-client/mmdf.h Fri Jun 17 01:40:23 1994 +++ pine3.96.local/imap/ANSI/c-client/mmdf.h Thu Jan 29 01:01:32 1998 @@ -157,6 +157,7 @@ char mmdf_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char mmdf_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char mmdf_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char mmdf_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char mmdf_search_to (MAILSTREAM *stream,long msgno,char *d,long n); search_t mmdf_search_date (search_t f,long *n); diff -Nur pine3.96.dist/imap/ANSI/c-client/mtx.c pine3.96.local/imap/ANSI/c-client/mtx.c --- pine3.96.dist/imap/ANSI/c-client/mtx.c Tue Oct 15 15:21:30 1996 +++ pine3.96.local/imap/ANSI/c-client/mtx.c Thu Jan 29 01:01:32 1998 @@ -771,6 +771,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = mtx_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = mtx_search_string (mtx_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = mtx_search_seen; @@ -1740,6 +1742,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char mtx_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return mtx_search_to (stream,msgno,d,n) || + mtx_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/mtx.h pine3.96.local/imap/ANSI/c-client/mtx.h --- pine3.96.dist/imap/ANSI/c-client/mtx.h Tue May 10 14:41:47 1994 +++ pine3.96.local/imap/ANSI/c-client/mtx.h Thu Jan 29 01:01:32 1998 @@ -133,6 +133,7 @@ char mtx_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char mtx_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char mtx_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char mtx_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char mtx_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); diff -Nur pine3.96.dist/imap/ANSI/c-client/news.c pine3.96.local/imap/ANSI/c-client/news.c --- pine3.96.dist/imap/ANSI/c-client/news.c Wed May 15 11:50:02 1996 +++ pine3.96.local/imap/ANSI/c-client/news.c Thu Jan 29 01:01:32 1998 @@ -676,6 +676,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = news_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = news_search_string (news_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = news_search_seen; @@ -1054,6 +1056,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char news_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return news_search_to (stream,msgno,d,n) || + news_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/news.h pine3.96.local/imap/ANSI/c-client/news.h --- pine3.96.dist/imap/ANSI/c-client/news.h Mon Sep 12 21:35:39 1994 +++ pine3.96.local/imap/ANSI/c-client/news.h Thu Jan 29 01:01:32 1998 @@ -120,6 +120,7 @@ char news_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char news_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char news_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char news_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char news_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); search_t news_search_date (search_t f,long *n); diff -Nur pine3.96.dist/imap/ANSI/c-client/nntpcunx.c pine3.96.local/imap/ANSI/c-client/nntpcunx.c --- pine3.96.dist/imap/ANSI/c-client/nntpcunx.c Wed May 15 11:50:10 1996 +++ pine3.96.local/imap/ANSI/c-client/nntpcunx.c Thu Jan 29 01:01:32 1998 @@ -734,6 +734,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = nntp_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = nntp_search_string (nntp_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = nntp_search_seen; @@ -1103,6 +1105,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char nntp_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return nntp_search_to (stream,msgno,d,n) || + nntp_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/nntpcunx.h pine3.96.local/imap/ANSI/c-client/nntpcunx.h --- pine3.96.dist/imap/ANSI/c-client/nntpcunx.h Mon Sep 12 21:37:18 1994 +++ pine3.96.local/imap/ANSI/c-client/nntpcunx.h Thu Jan 29 01:01:32 1998 @@ -130,6 +130,7 @@ char nntp_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char nntp_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char nntp_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char nntp_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char nntp_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); search_t nntp_search_date (search_t f,long *n); diff -Nur pine3.96.dist/imap/ANSI/c-client/phile.c pine3.96.local/imap/ANSI/c-client/phile.c --- pine3.96.dist/imap/ANSI/c-client/phile.c Wed May 15 11:50:12 1996 +++ pine3.96.local/imap/ANSI/c-client/phile.c Thu Jan 29 01:01:32 1998 @@ -625,6 +625,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = phile_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = phile_search_string (phile_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = phile_search_seen; @@ -978,6 +980,13 @@ /* get text for address */ rfc822_write_address (tmp,phile_fetchstructure (stream,m,NIL)->from); return search (tmp,strlen (tmp),d,n); +} + + +char phile_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return phile_search_to (stream,msgno,d,n) || + phile_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/phile.h pine3.96.local/imap/ANSI/c-client/phile.h --- pine3.96.dist/imap/ANSI/c-client/phile.h Wed Mar 2 20:01:33 1994 +++ pine3.96.local/imap/ANSI/c-client/phile.h Thu Jan 29 01:01:32 1998 @@ -130,6 +130,7 @@ char phile_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char phile_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char phile_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char phile_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char phile_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); diff -Nur pine3.96.dist/imap/ANSI/c-client/pop3.c pine3.96.local/imap/ANSI/c-client/pop3.c --- pine3.96.dist/imap/ANSI/c-client/pop3.c Tue Oct 22 13:04:29 1996 +++ pine3.96.local/imap/ANSI/c-client/pop3.c Thu Jan 29 01:01:32 1998 @@ -699,6 +699,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = pop3_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = pop3_search_string (pop3_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = pop3_search_seen; @@ -1149,6 +1151,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char pop3_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return pop3_search_to (stream,msgno,d,n) || + pop3_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/pop3.h pine3.96.local/imap/ANSI/c-client/pop3.h --- pine3.96.dist/imap/ANSI/c-client/pop3.h Mon Jun 6 21:57:20 1994 +++ pine3.96.local/imap/ANSI/c-client/pop3.h Thu Jan 29 01:01:32 1998 @@ -132,6 +132,7 @@ char pop3_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char pop3_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char pop3_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char pop3_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char pop3_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); search_t pop3_search_date (search_t f,long *n); diff -Nur pine3.96.dist/imap/ANSI/c-client/tenex2.c pine3.96.local/imap/ANSI/c-client/tenex2.c --- pine3.96.dist/imap/ANSI/c-client/tenex2.c Tue Oct 15 15:21:14 1996 +++ pine3.96.local/imap/ANSI/c-client/tenex2.c Thu Jan 29 01:01:32 1998 @@ -789,6 +789,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = tenex_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = tenex_search_string (tenex_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = tenex_search_seen; @@ -1767,6 +1769,13 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char tenex_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n) +{ + return tenex_search_to (stream,msgno,d,n) || + tenex_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/ANSI/c-client/tenex2.h pine3.96.local/imap/ANSI/c-client/tenex2.h --- pine3.96.dist/imap/ANSI/c-client/tenex2.h Sun Oct 2 22:08:39 1994 +++ pine3.96.local/imap/ANSI/c-client/tenex2.h Thu Jan 29 01:01:32 1998 @@ -140,6 +140,7 @@ char tenex_search_bcc (MAILSTREAM *stream,long msgno,char *d,long n); char tenex_search_cc (MAILSTREAM *stream,long msgno,char *d,long n); char tenex_search_from (MAILSTREAM *stream,long msgno,char *d,long n); +char tenex_search_recipient (MAILSTREAM *stream,long msgno,char *d,long n); char tenex_search_to (MAILSTREAM *stream,long msgno,char *d,long n); typedef char (*search_t) (MAILSTREAM *stream,long msgno,char *d,long n); diff -Nur pine3.96.dist/imap/OSTYPE pine3.96.local/imap/OSTYPE --- pine3.96.dist/imap/OSTYPE Wed Dec 31 16:00:00 1969 +++ pine3.96.local/imap/OSTYPE Sat Feb 7 20:03:16 1998 @@ -0,0 +1 @@ +lnx diff -Nur pine3.96.dist/imap/non-ANSI/c-client/bezerk.c pine3.96.local/imap/non-ANSI/c-client/bezerk.c --- pine3.96.dist/imap/non-ANSI/c-client/bezerk.c Tue Oct 15 15:20:17 1996 +++ pine3.96.local/imap/non-ANSI/c-client/bezerk.c Thu Jan 29 01:01:32 1998 @@ -833,6 +833,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = bezerk_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = bezerk_search_string (bezerk_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = bezerk_search_seen; @@ -2247,6 +2249,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char bezerk_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return bezerk_search_to (stream,msgno,d,n) || + bezerk_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/bezerk.h pine3.96.local/imap/non-ANSI/c-client/bezerk.h --- pine3.96.dist/imap/non-ANSI/c-client/bezerk.h Wed Apr 12 23:03:14 1995 +++ pine3.96.local/imap/non-ANSI/c-client/bezerk.h Thu Jan 29 01:01:32 1998 @@ -283,6 +283,7 @@ char bezerk_search_bcc (); char bezerk_search_cc (); char bezerk_search_from (); +char bezerk_search_recipient (); char bezerk_search_to (); typedef char (*search_t) (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/mh.c pine3.96.local/imap/non-ANSI/c-client/mh.c --- pine3.96.dist/imap/non-ANSI/c-client/mh.c Wed May 15 11:56:05 1996 +++ pine3.96.local/imap/non-ANSI/c-client/mh.c Thu Jan 29 01:01:32 1998 @@ -801,6 +801,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = mh_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = mh_search_string (mh_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = mh_search_seen; @@ -1556,6 +1558,16 @@ return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); } + +char mh_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return mh_search_to (stream,msgno,d,n) || + mh_search_cc (stream,msgno,d,n); +} char mh_search_to (stream,msgno,d,n) MAILSTREAM *stream; diff -Nur pine3.96.dist/imap/non-ANSI/c-client/mh.h pine3.96.local/imap/non-ANSI/c-client/mh.h --- pine3.96.dist/imap/non-ANSI/c-client/mh.h Sun Aug 14 21:44:49 1994 +++ pine3.96.local/imap/non-ANSI/c-client/mh.h Thu Jan 29 01:01:32 1998 @@ -127,6 +127,7 @@ char mh_search_cc (); char mh_search_from (); char mh_search_to (); +char mh_search_recipient (); typedef char (*search_t) (); search_t mh_search_date (); search_t mh_search_flag (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/mmdf.c pine3.96.local/imap/non-ANSI/c-client/mmdf.c --- pine3.96.dist/imap/non-ANSI/c-client/mmdf.c Tue Oct 15 15:20:35 1996 +++ pine3.96.local/imap/non-ANSI/c-client/mmdf.c Thu Jan 29 01:01:32 1998 @@ -761,6 +761,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = mmdf_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = mmdf_search_string (mmdf_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = mmdf_search_seen; @@ -2153,6 +2155,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char mmdf_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return mmdf_search_to (stream,msgno,d,n) || + mmdf_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/mmdf.h pine3.96.local/imap/non-ANSI/c-client/mmdf.h --- pine3.96.dist/imap/non-ANSI/c-client/mmdf.h Mon Sep 19 20:47:46 1994 +++ pine3.96.local/imap/non-ANSI/c-client/mmdf.h Thu Jan 29 01:01:32 1998 @@ -157,6 +157,7 @@ char mmdf_search_cc (); char mmdf_search_from (); char mmdf_search_to (); +char mmdf_search_recipient (); search_t mmdf_search_date (); search_t mmdf_search_flag (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/mtx.c pine3.96.local/imap/non-ANSI/c-client/mtx.c --- pine3.96.dist/imap/non-ANSI/c-client/mtx.c Tue Oct 15 15:21:55 1996 +++ pine3.96.local/imap/non-ANSI/c-client/mtx.c Thu Jan 29 01:01:32 1998 @@ -828,6 +828,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = mtx_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = mtx_search_string (mtx_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = mtx_search_seen; @@ -1928,6 +1930,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char mtx_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return mtx_search_to (stream,msgno,d,n) || + mtx_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/mtx.h pine3.96.local/imap/non-ANSI/c-client/mtx.h --- pine3.96.dist/imap/non-ANSI/c-client/mtx.h Tue May 10 14:58:40 1994 +++ pine3.96.local/imap/non-ANSI/c-client/mtx.h Thu Jan 29 01:01:32 1998 @@ -133,6 +133,7 @@ char mtx_search_cc (); char mtx_search_from (); char mtx_search_to (); +char mtx_search_recipient (); typedef char (*search_t) (); search_t mtx_search_date (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/news.c pine3.96.local/imap/non-ANSI/c-client/news.c --- pine3.96.dist/imap/non-ANSI/c-client/news.c Wed May 15 11:56:11 1996 +++ pine3.96.local/imap/non-ANSI/c-client/news.c Thu Jan 29 01:01:32 1998 @@ -731,6 +731,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = news_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = news_search_string (news_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = news_search_seen; @@ -1222,6 +1224,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char news_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return news_search_to (stream,msgno,d,n) || + news_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/news.h pine3.96.local/imap/non-ANSI/c-client/news.h --- pine3.96.dist/imap/non-ANSI/c-client/news.h Tue Sep 13 21:50:44 1994 +++ pine3.96.local/imap/non-ANSI/c-client/news.h Thu Jan 29 01:01:33 1998 @@ -120,6 +120,7 @@ char news_search_cc (); char news_search_from (); char news_search_to (); +char news_search_recipient (); typedef char (*search_t) (); search_t news_search_date (); search_t news_search_flag (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/nntpcunx.c pine3.96.local/imap/non-ANSI/c-client/nntpcunx.c --- pine3.96.dist/imap/non-ANSI/c-client/nntpcunx.c Wed May 15 11:56:13 1996 +++ pine3.96.local/imap/non-ANSI/c-client/nntpcunx.c Thu Jan 29 01:01:33 1998 @@ -789,6 +789,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = nntp_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = nntp_search_string (nntp_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = nntp_search_seen; @@ -1271,6 +1273,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char nntp_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return nntp_search_to (stream,msgno,d,n) || + nntp_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/nntpcunx.h pine3.96.local/imap/non-ANSI/c-client/nntpcunx.h --- pine3.96.dist/imap/non-ANSI/c-client/nntpcunx.h Tue Sep 13 21:50:50 1994 +++ pine3.96.local/imap/non-ANSI/c-client/nntpcunx.h Thu Jan 29 01:01:33 1998 @@ -130,6 +130,7 @@ char nntp_search_cc (); char nntp_search_from (); char nntp_search_to (); +char nntp_search_recipient (); typedef char (*search_t) (); search_t nntp_search_date (); search_t nntp_search_flag (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/phile.c pine3.96.local/imap/non-ANSI/c-client/phile.c --- pine3.96.dist/imap/non-ANSI/c-client/phile.c Wed May 15 11:56:14 1996 +++ pine3.96.local/imap/non-ANSI/c-client/phile.c Thu Jan 29 01:01:33 1998 @@ -682,6 +682,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = phile_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = phile_search_string (phile_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = phile_search_seen; @@ -1146,6 +1148,17 @@ /* get text for address */ rfc822_write_address (tmp,phile_fetchstructure (stream,m,NIL)->from); return search (tmp,strlen (tmp),d,n); +} + + +char phile_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return phile_search_to (stream,msgno,d,n) || + phile_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/phile.h pine3.96.local/imap/non-ANSI/c-client/phile.h --- pine3.96.dist/imap/non-ANSI/c-client/phile.h Thu Mar 3 23:24:51 1994 +++ pine3.96.local/imap/non-ANSI/c-client/phile.h Thu Jan 29 01:01:33 1998 @@ -130,6 +130,7 @@ char phile_search_cc (); char phile_search_from (); char phile_search_to (); +char phile_search_recipient (); typedef char (*search_t) (); search_t phile_search_date (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/pop3.c pine3.96.local/imap/non-ANSI/c-client/pop3.c --- pine3.96.dist/imap/non-ANSI/c-client/pop3.c Tue Oct 22 13:06:12 1996 +++ pine3.96.local/imap/non-ANSI/c-client/pop3.c Thu Jan 29 01:01:33 1998 @@ -753,6 +753,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = pop3_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = pop3_search_string (pop3_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = pop3_search_seen; @@ -1325,6 +1327,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char pop3_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return pop3_search_to (stream,msgno,d,n) || + pop3_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/pop3.h pine3.96.local/imap/non-ANSI/c-client/pop3.h --- pine3.96.dist/imap/non-ANSI/c-client/pop3.h Mon Jun 6 22:28:51 1994 +++ pine3.96.local/imap/non-ANSI/c-client/pop3.h Thu Jan 29 01:01:33 1998 @@ -132,6 +132,7 @@ char pop3_search_cc (); char pop3_search_from (); char pop3_search_to (); +char pop3_search_recipient (); typedef char (*search_t) (); search_t pop3_search_date (); search_t pop3_search_flag (); diff -Nur pine3.96.dist/imap/non-ANSI/c-client/tenex2.c pine3.96.local/imap/non-ANSI/c-client/tenex2.c --- pine3.96.dist/imap/non-ANSI/c-client/tenex2.c Tue Oct 15 15:21:44 1996 +++ pine3.96.local/imap/non-ANSI/c-client/tenex2.c Thu Jan 29 01:01:33 1998 @@ -852,6 +852,8 @@ break; case 'R': /* possible RECENT */ if (!strcmp (criteria+1,"ECENT")) f = tenex_search_recent; + else if (!strcmp (criteria+1,"ECIPIENT")) + f = tenex_search_string (tenex_search_recipient,&d,&n); break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criteria+1,"EEN")) f = tenex_search_seen; @@ -1963,6 +1965,17 @@ /* get text for address */ rfc822_write_address (LOCAL->buf,a); return search (LOCAL->buf,(long) strlen (LOCAL->buf),d,n); +} + + +char tenex_search_recipient (stream,msgno,d,n) + MAILSTREAM *stream; + long msgno; + char *d; + long n; +{ + return tenex_search_to (stream,msgno,d,n) || + tenex_search_cc (stream,msgno,d,n); } diff -Nur pine3.96.dist/imap/non-ANSI/c-client/tenex2.h pine3.96.local/imap/non-ANSI/c-client/tenex2.h --- pine3.96.dist/imap/non-ANSI/c-client/tenex2.h Sun Oct 2 22:44:05 1994 +++ pine3.96.local/imap/non-ANSI/c-client/tenex2.h Thu Jan 29 01:01:33 1998 @@ -140,6 +140,7 @@ char tenex_search_cc (); char tenex_search_from (); char tenex_search_to (); +char tenex_search_recipient (); typedef char (*search_t) (); search_t tenex_search_date (); diff -Nur pine3.96.dist/pico/makefile.lnx pine3.96.local/pico/makefile.lnx --- pine3.96.dist/pico/makefile.lnx Fri Apr 5 10:07:54 1996 +++ pine3.96.local/pico/makefile.lnx Thu Jan 29 01:01:33 1998 @@ -32,9 +32,9 @@ # #includes symbol for debugging -DASHO= -g +#DASHO= -g #for normal build -#DASHO= -O2 +DASHO= -O2 STDCFLAGS= -Dlnx -DPOSIX -DJOB_CONTROL -DMOUSE CFLAGS= $(EXTRACFLAGS) $(DASHO) $(STDCFLAGS) diff -Nur pine3.96.dist/pico/os_unix.c pine3.96.local/pico/os_unix.c --- pine3.96.dist/pico/os_unix.c Fri Jul 12 11:13:53 1996 +++ pine3.96.local/pico/os_unix.c Sat Feb 7 20:01:12 1998 @@ -1653,6 +1653,18 @@ tmpname(name) char *name; { + char *e, *e1; + + e = getenv("TMPDIR"); + if (!e) e = getenv("HOME"); + if (!e || *e == '\0') { + e = "/tmp/"; + e1 = ""; + } + else { + e1 = e + strlen(e) - 1; + e1 = (*e1 == '/') ? "" : "/"; + } sprintf(name, "/tmp/pico.%d", getpid()); /* tmp file name */ } diff -Nur pine3.96.dist/pine/date.c pine3.96.local/pine/date.c --- pine3.96.dist/pine/date.c Wed Dec 31 16:00:00 1969 +++ pine3.96.local/pine/date.c Sat Feb 7 20:03:21 1998 @@ -0,0 +1,2 @@ +char datestamp[]="Sat Feb 7 20:03:21 PST 1998"; +char hoststamp[]="benchlark.transmeta.com"; diff -Nur pine3.96.dist/pine/init.c pine3.96.local/pine/init.c --- pine3.96.dist/pine/init.c Wed Jul 10 16:05:31 1996 +++ pine3.96.local/pine/init.c Thu Jan 29 01:01:33 1998 @@ -1337,6 +1337,9 @@ {"disable-keymenu", F_BLANK_KEYMENU}, {"disable-password-cmd", F_DISABLE_PASSWORD_CMD}, {"disable-update-cmd", F_DISABLE_UPDATE_CMD}, +#ifdef ALLOW_DISABLE_SENDER + {"disable-sender", F_DISABLE_SENDER}, +#endif {"disable-signature-edit-cmd", F_DISABLE_SIGEDIT_CMD}, {"enable-8bit-esmtp-negotiation", F_ENABLE_8BIT}, {"enable-8bit-nntp-posting", F_ENABLE_8BIT_NNTP}, @@ -1381,6 +1384,9 @@ {"print-includes-from-line", F_FROM_DELIM_IN_PRINT}, {"print-index-enabled", F_PRINT_INDEX}, {"print-formfeed-between-messages", F_AGG_PRINT_FF}, +#if defined( QMAIL_RETURN_PATH ) + {"qmail-return-path", F_QMAIL_RETURN_PATH}, +#endif {"quell-dead-letter-on-cancel", F_QUELL_DEAD_LETTER}, {"quell-lock-failure-warnings", F_QUELL_LOCK_FAILURE_MSGS}, {"quell-status-message-beeping", F_QUELL_BEEPS}, diff -Nur pine3.96.dist/pine/mailcmd.c pine3.96.local/pine/mailcmd.c --- pine3.96.dist/pine/mailcmd.c Mon Feb 24 13:57:22 1997 +++ pine3.96.local/pine/mailcmd.c Thu Jan 29 01:01:33 1998 @@ -170,13 +170,14 @@ static char *sel_text = - "Select based on To, From, Cc, or Subject fields or All message text ? "; + "Select based on To, From, Cc, Subject, Recpients, or All message text ? "; static ESCKEY_S sel_text_opt[] = { {'f', 'f', "F", "From"}, {'s', 's', "S", "Subject"}, {'t', 't', "T", "To"}, {'a', 'a', "A", "All Text"}, {'c', 'c', "C", "Cc"}, + {'r', 'r', "R", "Recpients"}, {-1, 0, NULL, NULL} }; @@ -5391,7 +5392,7 @@ { int r, type, we_cancel = 0; char *sval = NULL, sstring[80], tmp[128]; - ESCKEY_S ekey[3]; + ESCKEY_S ekey[4]; ENVELOPE *env = NULL; HelpType help; @@ -5402,6 +5403,7 @@ */ ekey[1].ch = -1; ekey[2].ch = -1; + ekey[3].ch = -1; switch(type = radio_buttons(sel_text, -FOOTER_ROWS(ps_global), sel_text_opt, 's', 'x', NO_HELP, RB_NORM)){ case 't' : /* address fields, offer To or From */ @@ -5426,6 +5428,22 @@ ekey[0].label = "Cur Subject"; break; + case 'r' : + sval = "RECIPIENT"; + ekey[0].ch = ctrl('T'); + ekey[0].name = "^T"; + ekey[0].rval = 10; + ekey[0].label = "Cur To"; + ekey[1].ch = ctrl('R'); + ekey[1].name = "^R"; + ekey[1].rval = 11; + ekey[1].label = "Cur From"; + ekey[2].ch = ctrl('Y'); + ekey[2].name = "^Y"; + ekey[2].rval = 12; + ekey[2].label = "Cur Cc"; + break; + case 'a' : sval = "TEXT"; /* fall thru */ ekey[0].ch = -1; @@ -5458,7 +5476,8 @@ : (type == 'c') ? h_select_txt_cc : (type == 's') ? h_select_txt_subj : (type == 'a') ? h_select_txt_all - : NO_HELP) + : (type == 'r') ? h_select_txt_recipients + : NO_HELP) : NO_HELP; case 4 : continue; diff -Nur pine3.96.dist/pine/makefile.lnx pine3.96.local/pine/makefile.lnx --- pine3.96.dist/pine/makefile.lnx Fri Mar 15 12:29:39 1996 +++ pine3.96.local/pine/makefile.lnx Thu Jan 29 01:01:33 1998 @@ -50,9 +50,9 @@ RM= rm -f LN= ln -s MAKE= make -OPTIMIZE= # -O2 +OPTIMIZE= -O2 PROFILE= # -pg -DEBUG= -g -DDEBUG +DEBUG= #-g -DDEBUG IMAPDIR= ../c-client PICODIR= ../pico diff -Nur pine3.96.dist/pine/osdep/os-lnx.h pine3.96.local/pine/osdep/os-lnx.h --- pine3.96.dist/pine/osdep/os-lnx.h Wed Jun 5 10:13:29 1996 +++ pine3.96.local/pine/osdep/os-lnx.h Thu Jan 29 01:01:33 1998 @@ -52,6 +52,9 @@ ----*/ +#define ALLOW_DISABLE_SENDER +#define QMAIL_RETURN_PATH + /*---------------------------------------------------------------------- Define this if you want the disk quota to be checked on startup. Of course, this only makes sense if your system has quotas. If it doesn't, @@ -68,7 +71,7 @@ either default-composer-hdrs or customized-hdrs to get at the From header, even if this is set. ----*/ -/* #define ALLOW_CHANGING_FROM /* comment out to not allow changing From */ +#define ALLOW_CHANGING_FROM /* comment out to not allow changing From */ diff -Nur pine3.96.dist/pine/other.c pine3.96.local/pine/other.c --- pine3.96.dist/pine/other.c Wed Jul 10 16:05:59 1996 +++ pine3.96.local/pine/other.c Thu Jan 29 01:01:33 1998 @@ -2484,6 +2484,10 @@ return(h_config_cruise_mode_delete); case F_ALLOW_GOTO : return(h_config_allow_goto); + case F_DISABLE_SENDER : + return(h_config_disable_sender); + case F_QMAIL_RETURN_PATH : + return(h_config_qmail_return_path); default : return(NO_HELP); } diff -Nur pine3.96.dist/pine/pine.h pine3.96.local/pine/pine.h --- pine3.96.dist/pine/pine.h Wed Feb 26 14:45:44 1997 +++ pine3.96.local/pine/pine.h Thu Jan 29 01:01:52 1998 @@ -63,7 +63,7 @@ #ifndef _PINE_INCLUDED #define _PINE_INCLUDED -#define PINE_VERSION "3.96" +#define PINE_VERSION "3.96dg4" #define PHONE_HOME_VERSION "396" #define PHONE_HOME_HOST "docserver.cac.washington.edu" #define UPDATE_FOLDER "{pine.cac.washington.edu:144/anonymous}#news." @@ -1153,7 +1153,9 @@ #define F_FROM_DELIM_IN_PRINT 80 #define F_BACKGROUND_POST 81 #define F_ALLOW_GOTO 82 -#define F_LAST_FEATURE 82 /* RESET WITH NEW FEATURES */ +#define F_DISABLE_SENDER 83 +#define F_QMAIL_RETURN_PATH 84 +#define F_LAST_FEATURE 84 /* RESET WITH NEW FEATURES */ #if (F_LAST_FEATURE > (LARGEST_BITMAP - 1)) Whoa! Too many features! diff -Nur pine3.96.dist/pine/pine.hlp pine3.96.local/pine/pine.hlp --- pine3.96.dist/pine/pine.hlp Fri Feb 28 09:32:23 1997 +++ pine3.96.local/pine/pine.hlp Thu Jan 29 01:01:33 1998 @@ -5561,6 +5561,27 @@ two distant directories. +====== h_config_disable_sender ===== + FEATURE: disable-sender + +Normally if the From: header does not match what pine thinks your email +address is, it will generate a Sender: header (or X-Sender: depending on +the use-sender-not-x-sender feature) with the address it thinks you +are at. This feature disables the generation of the Sender: header. + + +====== h_config_qmail_return_path ===== + FEATURE: qmail-return-path + +The qmail mail transfer agent (see http://www.qmail.org/) will interpret a +Return-Path: header as the envelope sender address. This setting allows +the Return-Path to be editted. Additionally, if the Return-Path is not +changed by the user then its value will default to whatever the From: +header contains. This is useful because qmail also allows a user to +create addresses of the form userid-foobar@domain.edu. It is also useful +if the user uses different addresses for different functions. + + ====== h_config_undo ===== Yes, save changes and exit; No, exit without saving any changes made since entering this CONFIGURATION screen; ^C, cancel exit and stay in config screen. @@ -5737,6 +5758,9 @@ ========== h_select_txt_cc ========== Messages with From: headers containing the entered string will be selected. ^C to cancel. ^R enters current msg From: address. ^T enters To: address. +========== h_select_txt_recipients ========== +Messages with To: or Cc: headers containing the entered string will be selected. +^C to cancel. ^R uses From: address. ^T uses To: address. ^Y uses Cc: address. ========== h_select_txt_subj ========== Messages with Subject: headers containing the entered string will be selected. ^C to cancel. ^X enters Subject: line of current message. diff -Nur pine3.96.dist/pine/send.c pine3.96.local/pine/send.c --- pine3.96.dist/pine/send.c Mon Feb 24 13:57:38 1997 +++ pine3.96.local/pine/send.c Thu Jan 29 01:01:33 1998 @@ -50,7 +50,6 @@ #include "../c-client/smtp.h" #include "../c-client/nntp.h" - #ifndef TCPSTREAM #define TCPSTREAM void #endif @@ -1126,7 +1125,12 @@ #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH) {"", "Sender", NO_HELP, 10, 0, NULL, NULL, NULL, NULL, NULL, NULL, - 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE} + 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE}, +#endif +#if defined( QMAIL_RETURN_PATH ) + {"Return-P: ", "Return-Path", h_composer_from, 10, 0, NULL, + build_address, NULL, NULL, addr_book_compose, "To AddrBk", + 0, 1, 0, 1, 0, 1, 0, 0, 0, KS_TOADDRBOOK} #endif }; @@ -1159,6 +1163,7 @@ #define N_NOBODY 14 #define N_POSTERR 15 #define N_SENDER 16 +#define N_RETURNPATH 17 /* this is used in pine_send and pine_simple_send */ /* name::type::canedit::writehdr::localcopy::rcptto */ @@ -1182,6 +1187,9 @@ #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH) {"X-Sender", Address, 0, 1, 1, 0}, #endif +#if defined( QMAIL_RETURN_PATH ) + {"Return-Path", Address, 1, 1, 1, 0}, +#endif {NULL, FreeText} }; @@ -1371,6 +1379,12 @@ pf->addr = &outgoing->sender; break; #endif +#if defined( QMAIL_RETURN_PATH ) + case N_RETURNPATH: + sending_order[NN+13] = pf; + pf->addr = &outgoing->return_path; + break; +#endif case N_NOBODY: /* won't be used here */ sending_order[NN+5] = pf; @@ -1953,7 +1967,7 @@ else index = i; - if(i > 16) + if(i > 17) q_status_message1(SM_ORDER,3,7, "Internal error: i=%d in pine_send", (void *)i); @@ -2125,6 +2139,12 @@ pf->addr = &outgoing->sender; break; #endif +#if defined( QMAIL_RETURN_PATH ) + case N_RETURNPATH: + sending_order[NN+13] = pf; + pf->addr = &outgoing->return_path; + break; +#endif default: q_status_message1(SM_ORDER,3,7, @@ -2186,7 +2206,7 @@ if(index == N_FROM && !*pf->addr) *pf->addr = generate_from(); - }else if(index == N_FROM || index == N_REPLYTO){ + }else if(index == N_FROM || index == N_REPLYTO || index == N_RETURNPATH){ /* side effect of this may set canedit */ set_default_hdrval(pf); }else if(pf->addr && *pf->addr && !(*pf->addr)->mailbox){ @@ -2552,6 +2572,9 @@ mail_free_address(&outgoing->reply_to); #endif /* OLDWAY */ +#ifdef ALLOW_DISABLE_SENDER + if(!F_ON(F_DISABLE_SENDER, ps_global)){ +#endif /* * Don't ever believe the sender that is there. * If From doesn't look quite right, generate our own sender. @@ -2577,6 +2600,24 @@ outgoing->sender->mailbox = cpystr(ps_global->VAR_USER_ID); outgoing->sender->host = cpystr(ps_global->hostname); } +#ifdef ALLOW_DISABLE_SENDER + } +#endif + +#ifdef QMAIL_RETURN_PATH + if(F_ON(F_QMAIL_RETURN_PATH, ps_global)){ + /* + * If the user hasn't edited the Return-Path header then inherit + * it from the From: header + */ + pf = &pfields[N_RETURNPATH]; + if( !pf->he->dirty ) { + if(outgoing->return_path) + mail_free_address(&outgoing->return_path); + outgoing->return_path = rfc822_cpy_adr(outgoing->from); + } + } +#endif /*----- Message is edited, now decide what to do with it ----*/ if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){