/*
* Program: MBOX mail routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 10 March 1992
* Last Edited: 4 January 1996
*
* Copyright 1996 by the University of Washington
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appears in all copies and that both the
* above copyright notice and this permission notice appear in supporting
* documentation, and that the name of the University of Washington not be
* used in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. This software is made
* available "as is", and
* THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
* WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
* NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
* (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
extern int errno; /* just in case */
#include "mail.h"
#include "osdep.h"
#include <sys/stat.h>
#include <sys/time.h>
#include "mbox.h"
#include "bezerk.h"
#include "misc.h"
#include "dummy.h"
/* MBOX mail routines */
/* Driver dispatch used by MAIL */
DRIVER mboxdriver = {
"mbox", /* driver name */
DR_LOCAL|DR_MAIL, /* driver flags */
(DRIVER *) NIL, /* next driver */
mbox_valid, /* mailbox is valid for us */
bezerk_parameters, /* manipulate parameters */
bezerk_scan, /* scan mailboxes */
bezerk_list, /* find mailboxes */
bezerk_lsub, /* find subscribed mailboxes */
NIL, /* subscribe to mailbox */
NIL, /* unsubscribe from mailbox */
dummy_create, /* create mailbox */
dummy_delete, /* delete mailbox */
mbox_rename, /* rename mailbox */
NIL, /* status of mailbox */
mbox_open, /* open mailbox */
bezerk_close, /* close mailbox */
bezerk_fetchfast, /* fetch message "fast" attributes */
bezerk_fetchflags, /* fetch message flags */
bezerk_fetchstructure, /* fetch message structure */
bezerk_fetchheader, /* fetch message header only */
bezerk_fetchtext, /* fetch message body only */
bezerk_fetchbody, /* fetch message body section */
NIL, /* unique identifier */
bezerk_setflag, /* set message flag */
bezerk_clearflag, /* clear message flag */
NIL, /* search for message based on criteria */
mbox_ping, /* ping mailbox to see if still alive */
mbox_check, /* check for new messages */
mbox_expunge, /* expunge deleted messages */
bezerk_copy, /* copy messages to another mailbox */
bezerk_append, /* append string message to mailbox */
bezerk_gc /* garbage collect stream */
};
/* prototype stream */
MAILSTREAM mboxproto = {&mboxdriver};
/* MBOX mail validate mailbox
* Accepts: mailbox name
* Returns: our driver if name is valid, NIL otherwise
*/
DRIVER *mbox_valid (char *name)
{
char tmp[MAILTMPLEN];
char *s = mailboxfile (tmp,name);
if (s && !*s) { /* only consider INBOX */
/* if ~/mbox is in bezerk format */
if (bezerk_isvalid ("mbox",tmp))
/* win if sys is bezerk or empty or non-ex */
return (bezerk_isvalid (sysinbox(),tmp) || !errno || (errno == ENOENT)) ?
&mboxdriver : NIL;
/* if empty ~/mbox, win if sys is bezerk */
else if (!errno && bezerk_isvalid (sysinbox (),tmp)) return &mboxdriver;
}
return NIL; /* can't win (yet, anyway) */
}
/* MBOX mail rename mailbox
* Accepts: MAIL stream
* old mailbox name
* new mailbox name (or NIL for delete)
* Returns: T on success, NIL on failure
*/
long mbox_rename (MAILSTREAM *stream,char *old,char *newname)
{
long ret = T;
char *s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN];
int fd,ld;
/* get the c-client lock */
if ((ld = open (lockname (lock,dummy_file (file,"~/mbox")),O_RDWR|O_CREAT,
(int) mail_parameters (NIL,GET_LOCKPROTECTION,NIL))) < 0) {
sprintf (tmp,"Can't get lock for mailbox %s: %s",old,strerror (errno));
mm_log (tmp,ERROR);
return NIL;
}
/* lock out other c-clients */
if (flock (ld,LOCK_EX|LOCK_NB)) {
close (ld); /* couldn't lock, give up on it then */
sprintf (tmp,"Mailbox %s is in use by another process",old);
mm_log (tmp,ERROR);
return NIL;
}
/* lock out non c-client applications */
if ((fd = bezerk_lock (file,O_RDWR,S_IREAD|S_IWRITE,lockx,LOCK_EX)) < 0) {
sprintf (tmp,"Can't lock mailbox %s: %s",old,strerror (errno));
mm_log (tmp,ERROR);
return NIL;
}
if (newname) { /* want rename? */
if (!((s = dummy_file (tmp,newname)) && *s)) {
sprintf (tmp,"Can't rename mailbox %s to %s: invalid name",old,newname);
mm_log (tmp,ERROR);
ret = NIL; /* set failure */
}
if (rename (file,s)) { /* rename the file */
sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,newname,
strerror (errno));
mm_log (tmp,ERROR);
ret = NIL; /* set failure */
}
}
else if (unlink (file)) {
sprintf (tmp,"Can't delete mailbox %s: %s",old,strerror (errno));
mm_log (tmp,ERROR);
ret = NIL; /* set failure */
}
bezerk_unlock (fd,NIL,lockx); /* unlock and close mailbox */
flock (ld,LOCK_UN); /* release c-client lock lock */
close (ld); /* close c-client lock */
unlink (lock); /* and delete it */
/* recreate file if renamed INBOX */
if (ret) dummy_create (NIL,"mbox");
return ret; /* return success */
}
/* MBOX mail open
* Accepts: stream to open
* Returns: stream on success, NIL on failure
*/
MAILSTREAM *mbox_open (MAILSTREAM *stream)
{
unsigned long i = 1;
unsigned long recent = 0;
char tmp[MAILTMPLEN];
/* return prototype for OP_PROTOTYPE call */
if (!stream) return &mboxproto;
/* change mailbox file name */
sprintf (tmp,"%s/mbox",myhomedir ());
fs_give ((void **) &stream->mailbox);
stream->mailbox = cpystr (tmp);
/* open mailbox, snarf new mail */
if (!(bezerk_open (stream) && mbox_ping (stream))) return NIL;
/* notify upper level of mailbox sizes */
mail_exists (stream,stream->nmsgs);
while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent;
mail_recent (stream,recent); /* including recent messages */
return stream;
}
/* MBOX mail 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!
*/
long mbox_ping (MAILSTREAM *stream)
{
int fd,sfd;
char *s;
unsigned long size;
struct stat sbuf;
char lock[MAILTMPLEN],lockx[MAILTMPLEN];
if (LOCAL && !stream->rdonly && !stream->lock) {
mm_critical (stream); /* go critical */
if ((sfd = bezerk_lock (sysinbox (),O_RDWR,NIL,lockx,LOCK_EX)) >= 0) {
fstat (sfd,&sbuf); /* get size again now that locked */
if (size = sbuf.st_size) {/* get size of new mail if any */
/* mail in good format? */
if (bezerk_isvalid_fd (sfd,lock)) {
lseek (sfd,0,L_SET); /* rewind file */
read (sfd,s = (char *) fs_get (size + 1),size);
s[size] = '\0'; /* tie it off */
if ((fd = bezerk_lock (stream->mailbox,O_WRONLY|O_APPEND,NIL,lock,
LOCK_EX)) >= 0) {
fstat (fd,&sbuf); /* get current file size before write */
if ((write (fd,s,size) >= 0) && !fsync (fd))
ftruncate (sfd,0);/* flush from sysinbx */
else { /* failed */
sprintf (LOCAL->buf,"New mail copy failed: %s",strerror (errno));
mm_log (LOCAL->buf,ERROR);
ftruncate (fd,sbuf.st_size);
}
bezerk_unlock (fd,NIL,lock);
}
fs_give ((void **) &s);/* either way, flush the poop now */
}
else {
sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format",
sysinbox ());
mm_log (LOCAL->buf,ERROR);
}
}
/* all done with update */
bezerk_unlock (sfd,NIL,lockx);
}
mm_nocritical (stream); /* release critical */
}
return bezerk_ping (stream); /* do the bezerk routine now */
}
/* MBOX mail check mailbox
* Accepts: MAIL stream
*/
void mbox_check (MAILSTREAM *stream)
{
/* do local ping, then do bezerk routine */
if (mbox_ping (stream)) bezerk_check (stream);
}
/* MBOX mail expunge mailbox
* Accepts: MAIL stream
*/
void mbox_expunge (MAILSTREAM *stream)
{
bezerk_expunge (stream); /* do expunge */
mbox_ping (stream); /* do local ping */
}
syntax highlighted by Code2HTML, v. 0.9.1