📄 mh.c
字号:
/* * Program: MH mail routines * * Author(s): Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 23 February 1992 * Last Edited: 4 November 2004 * * The IMAP toolkit provided in this Distribution is * Copyright 1988-2004 University of Washington. * The full text of our legal notices is contained in the file called * CPYRIGHT, included with this Distribution. */#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 "mh.h"#include "misc.h"#include "dummy.h"/* MH I/O stream local data */ typedef struct mh_local { char *dir; /* spool directory name */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long cachedtexts; /* total size of all cached texts */ time_t scantime; /* last time directory scanned */} MHLOCAL;/* Convenient access to local data */#define LOCAL ((MHLOCAL *) stream->local)/* Function prototypes */DRIVER *mh_valid (char *name);int mh_isvalid (char *name,char *tmp,long synonly);void *mh_parameters (long function,void *value);void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);void mh_list (MAILSTREAM *stream,char *ref,char *pat);void mh_lsub (MAILSTREAM *stream,char *ref,char *pat);void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level);long mh_subscribe (MAILSTREAM *stream,char *mailbox);long mh_unsubscribe (MAILSTREAM *stream,char *mailbox);long mh_create (MAILSTREAM *stream,char *mailbox);long mh_delete (MAILSTREAM *stream,char *mailbox);long mh_rename (MAILSTREAM *stream,char *old,char *newname);MAILSTREAM *mh_open (MAILSTREAM *stream);void mh_close (MAILSTREAM *stream,long options);void mh_fast (MAILSTREAM *stream,char *sequence,long flags);char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags);long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);long mh_ping (MAILSTREAM *stream);void mh_check (MAILSTREAM *stream);void mh_expunge (MAILSTREAM *stream);long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options);long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);int mh_select (struct direct *name);int mh_numsort (const void *d1,const void *d2);char *mh_file (char *dst,char *name);long mh_canonicalize (char *pattern,char *ref,char *pat);void mh_setdate (char *file,MESSAGECACHE *elt);/* MH mail routines *//* Driver dispatch used by MAIL */DRIVER mhdriver = { "mh", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ mh_valid, /* mailbox is valid for us */ mh_parameters, /* manipulate parameters */ mh_scan, /* scan mailboxes */ mh_list, /* find mailboxes */ mh_lsub, /* find subscribed mailboxes */ mh_subscribe, /* subscribe to mailbox */ mh_unsubscribe, /* unsubscribe from mailbox */ mh_create, /* create mailbox */ mh_delete, /* delete mailbox */ mh_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mh_open, /* open mailbox */ mh_close, /* close mailbox */ mh_fast, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mh_header, /* fetch message header */ mh_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mh_ping, /* ping mailbox to see if still alive */ mh_check, /* check for new messages */ mh_expunge, /* expunge deleted messages */ mh_copy, /* copy messages to another mailbox */ mh_append, /* append string message to mailbox */ NIL /* garbage collect stream */}; /* prototype stream */MAILSTREAM mhproto = {&mhdriver};/* MH mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */DRIVER *mh_valid (char *name){ char tmp[MAILTMPLEN]; return mh_isvalid (name,tmp,T) ? &mhdriver : NIL;}/* MH mail test for valid mailbox * Accepts: mailbox name * temporary buffer to use * syntax only test flag * Returns: T if valid, NIL otherwise */static char *mh_profile = NIL; /* holds MH profile */static char *mh_path = NIL; /* holds MH path name */static long mh_once = 0; /* already through this code */int mh_isvalid (char *name,char *tmp,long synonly){ struct stat sbuf; /* name must be #MHINBOX or #mh/... */ if ((name[0] != '#') || ((name[1] != 'm') && name[1] != 'M') || ((name[2] != 'h') && name[2] != 'H') || ((name[3] != '/') && compare_cstring (name+3,"INBOX"))) { errno = EINVAL; /* bogus name */ return NIL; } if (!mh_path) { /* have MH path yet? */ char *s,*t,*v; int fd; if (mh_once++) return NIL; /* only do this code once */ if (!mh_profile) { /* have MH profile? */ sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE); mh_profile = cpystr (tmp); } if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { strcat (tmp," not found, mh format names disabled"); mm_log (tmp,WARN); return NIL; } fstat (fd,&sbuf); /* yes, get size and read file */ read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size); close (fd); /* don't need the file any more */ t[sbuf.st_size] = '\0'; /* tie it off */ /* parse profile file */ for (s = strtok (t,"\r\n"); s && *s; s = strtok (NIL,"\r\n")) { /* found space in line? */ if (v = strpbrk (s," \t")) { *v++ = '\0'; /* tie off, is keyword "Path:"? */ if (!strcmp (lcase (s),"path:")) { /* skip whitespace */ while ((*v == ' ') || (*v == '\t')) ++v; if (*v == '/') s = v; /* absolute path? */ else sprintf (s = tmp,"%s/%s",myhomedir (),v); mh_path = cpystr (s); /* copy name */ break; /* don't need to look at rest of file */ } } } fs_give ((void **) &t); /* flush profile text */ if (!mh_path) { /* default path if not in the profile */ sprintf (tmp,"%s/%s",myhomedir (),MHPATH); mh_path = cpystr (tmp); } } if (synonly) return T; /* all done if syntax only check */ errno = NIL; /* zap error */ /* validate name as directory */ return ((stat (mh_file (tmp,name),&sbuf) == 0) && (sbuf.st_mode & S_IFMT) == S_IFDIR);}/* MH manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *mh_parameters (long function,void *value){ void *ret = NIL; switch ((int) function) { case SET_MHPROFILE: if (mh_profile) fs_give ((void **) &mh_profile); mh_profile = cpystr ((char *) value); case GET_MHPROFILE: ret = (void *) mh_profile; break; case SET_MHPATH: if (mh_path) fs_give ((void **) &mh_path); mh_path = cpystr ((char *) value); case GET_MHPATH: ret = (void *) mh_path; break; } return ret;}/* MH scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents){ char tmp[MAILTMPLEN]; if (mh_canonicalize (tmp,ref,pat)) mm_log ("Scan not valid for mh mailboxes",ERROR);}/* MH list mailboxes * Accepts: mail stream * reference * pattern to search */void mh_list (MAILSTREAM *stream,char *ref,char *pat){ char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i = 0; if (!pat || !*pat) { /* empty pattern? */ if (mh_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'/')) *++s = '\0'; else test[0] = '\0'; mm_list (stream,'/',test,LATT_NOSELECT); } } /* get canonical form of name */ else if (mh_canonicalize (test,ref,pat)) { if (test[3] == '/') { /* looking down levels? */ /* yes, found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test+4,i = s - (test+4)); file[i] = '\0'; /* tie off */ } else strcpy (file,test+4);/* use just that name then */ /* find directory name */ if (s = strrchr (file,'/')) { *s = '\0'; /* found, tie off at that point */ s = file; } /* do the work */ mh_list_work (stream,s,test,0); } /* always an INBOX */ if (!compare_cstring (test,"#MHINBOX")) mm_list (stream,NIL,"#MHINBOX",LATT_NOINFERIORS); }}/* MH list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */void mh_lsub (MAILSTREAM *stream,char *ref,char *pat){ void *sdb = NIL; char *s,test[MAILTMPLEN]; /* get canonical form of name */ if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) { do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */ }}/* MH list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * search level */void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level){ DIR *dp; struct direct *d; struct stat sbuf; char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN]; /* build MH name to search */ if (dir) sprintf (name,"#mh/%s/",dir); else strcpy (name,"#mh/"); /* make directory name, punt if bogus */ if (!mh_file (curdir,name)) return; cp = curdir + strlen (curdir);/* end of directory name */ np = name + strlen (name); /* end of MH name */ if (dp = opendir (curdir)) { /* open directory */ while (d = readdir (dp)) /* scan, ignore . and numeric names */ if ((d->d_name[0] != '.') && !mh_select (d)) { strcpy (cp,d->d_name); /* make directory name */ if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { strcpy (np,d->d_name);/* make mh name of directory name */ /* yes, an MH name if full match */ if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL); /* check if should recurse */ if (dmatch (name,pat,'/') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) mh_list_work (stream,name+4,pat,level+1); } } closedir (dp); /* all done, flush directory */ }}/* MH mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */long mh_subscribe (MAILSTREAM *stream,char *mailbox){ return sm_subscribe (mailbox);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -