📄 mbx.c
字号:
/* * Program: MBX 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: 3 October 1995 * Last Edited: 18 October 2000 * * Copyright 2000 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 <pwd.h>#include <sys/stat.h>#include <sys/time.h>#include "mbx.h"#include "misc.h"#include "dummy.h"/* MBX mail routines *//* Driver dispatch used by MAIL */DRIVER mbxdriver = { "mbx", /* driver name */ DR_LOCAL|DR_MAIL|DR_CRLF, /* driver flags */ (DRIVER *) NIL, /* next driver */ mbx_valid, /* mailbox is valid for us */ mbx_parameters, /* manipulate parameters */ mbx_scan, /* scan mailboxes */ mbx_list, /* list mailboxes */ mbx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbx_create, /* create mailbox */ mbx_delete, /* delete mailbox */ mbx_rename, /* rename mailbox */ mbx_status, /* status of mailbox */ mbx_open, /* open mailbox */ mbx_close, /* close mailbox */ mbx_flags, /* fetch message "fast" attributes */ mbx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mbx_header, /* fetch message header */ mbx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mbx_flag, /* modify flags */ mbx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbx_ping, /* ping mailbox to see if still alive */ mbx_check, /* check for new messages */ mbx_expunge, /* expunge deleted messages */ mbx_copy, /* copy messages to another mailbox */ mbx_append, /* append string message to mailbox */ NIL /* garbage collect stream */}; /* prototype stream */MAILSTREAM mbxproto = {&mbxdriver};/* MBX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */DRIVER *mbx_valid (char *name){ char tmp[MAILTMPLEN]; return mbx_isvalid (name,tmp) ? &mbxdriver : NIL;}/* MBX mail test for valid mailbox * Accepts: mailbox name * scratch buffer * Returns: T if valid, NIL otherwise */int mbx_isvalid (char *name,char *tmp){ int fd; int ret = NIL; char *s,hdr[HDRSIZE]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) && ((fd = open (tmp,O_RDONLY,NIL)) >= 0)) { errno = -1; /* bogus format */ /* I love cretinous C compilers -- don't you? */ if (read (fd,hdr,HDRSIZE) == HDRSIZE) if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8])) if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (hdr[15]) && isxdigit (hdr[16])) if (isxdigit (hdr[17]) && isxdigit (hdr[18]) && isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) && isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) ret = T; close (fd); /* close the file */ tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (tmp,tp); /* set the times */ } /* in case INBOX but not mbx format */ else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) && ((name[1] == 'N') || (name[1] == 'n')) && ((name[2] == 'B') || (name[2] == 'b')) && ((name[3] == 'O') || (name[3] == 'o')) && ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1; return ret; /* return what we should */}/* MBX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *mbx_parameters (long function,void *value){ void *ret = NIL; switch ((int) function) { case SET_ONETIMEEXPUNGEATPING: if (value && (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expunged)) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->fullcheck = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->fullcheck; break; } return ret;}/* MBX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents){ if (stream) dummy_scan (NIL,ref,pat,contents);}/* MBX mail list mailboxes * Accepts: mail stream * reference * pattern to search */void mbx_list (MAILSTREAM *stream,char *ref,char *pat){ if (stream) dummy_list (NIL,ref,pat);}/* MBX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat){ if (stream) dummy_lsub (NIL,ref,pat);}/* MBX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */long mbx_create (MAILSTREAM *stream,char *mailbox){ char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE]; long ret = NIL; int i,fd; if (!(s = mbx_file (mbx,mailbox))) { sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s)) { /* done if made directory */ if ((s = strrchr (s,'/')) && !s[1]) return T; if ((fd = open (mbx,O_WRONLY, (int) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',HDRSIZE); sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012", (unsigned long) time (0)); for (i = 0; i < NUSERFLAGS; ++i) sprintf (s += strlen (s),"%s\015\012",(t = default_user_flag (i)) ? t : ""); if (write (fd,tmp,HDRSIZE) != HDRSIZE) { sprintf (tmp,"Can't initialize mailbox node %.80s: %s", mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else ret = T; /* success */ } close (fd); /* close file, set proper protections */ } return ret ? set_mbx_protections (mailbox,mbx) : NIL;}/* MBX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */long mbx_delete (MAILSTREAM *stream,char *mailbox){ return mbx_rename (stream,mailbox,NIL);}/* MBX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */long mbx_rename (MAILSTREAM *stream,char *old,char *newname){ long ret = T; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int ld; int fd = open (mbx_file (file,old),O_RDWR,NIL); struct stat sbuf; if (fd < 0) { /* open mailbox */ sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ if (!((s = mbx_file (tmp,newname)) && *s)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: invalid name", old,newname); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } if (s = strrchr (s,'/')) { /* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create (stream,tmp)) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ /* recreate file if renamed INBOX */ if (ret && !strcmp (ucase (strcpy (tmp,old)),"INBOX")) mbx_create (NIL,"INBOX"); return ret; /* return success */}/* MBX Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */long mbx_status (MAILSTREAM *stream,char *mbx,long flags){ MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } /* pass status to main program */ mm_status (stream,mbx,&status); if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */}/* MBX mail open
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -