📄 mix.c
字号:
/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== *//* * Program: MIX mail routines * * Author(s): Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 March 2006 * Last Edited: 7 May 2008 */#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 "misc.h"#include "dummy.h"#include "fdstring.h"/* MIX definitions */#define MEGABYTE (1024*1024)#define MIXDATAROLL MEGABYTE /* size at which we roll to a new file *//* MIX files */#define MIXNAME ".mix" /* prefix for all MIX file names */#define MIXMETA "meta" /* suffix for metadata */#define MIXINDEX "index" /* suffix for index */#define MIXSTATUS "status" /* suffix for status */#define MIXSORTCACHE "sortcache"/* suffix for sortcache */#define METAMAX (MEGABYTE-1) /* maximum metadata file size (sanity check) *//* MIX file formats */ /* sequence format (all but msg files) */#define SEQFMT "S%08lx\015\012" /* metadata file format */#define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012" /* index file record format */#define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012" /* status file record format */#define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012" /* message file header format */#define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012"#define MSGTOK ":msg:"#define MSGTSZ (sizeof(MSGTOK)-1) /* sortcache file record format */#define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012"/* MIX I/O stream local data */ typedef struct mix_local { unsigned long curmsg; /* current message file number */ unsigned long newmsg; /* current new message file number */ time_t lastsnarf; /* last snarf time */ int msgfd; /* file description of current msg file */ int mfd; /* file descriptor of open metadata */ unsigned long metaseq; /* metadata sequence */ char *index; /* mailbox index name */ unsigned long indexseq; /* index sequence */ char *status; /* mailbox status name */ unsigned long statusseq; /* status sequence */ char *sortcache; /* mailbox sortcache name */ unsigned long sortcacheseq; /* sortcache sequence */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned int expok : 1; /* non-zero if expunge reports OK */ unsigned int internal : 1; /* internally opened, do not validate */} MIXLOCAL;#define MIXBURP struct mix_burpMIXBURP { unsigned long fileno; /* message file number */ char *name; /* message file name */ SEARCHSET *tail; /* tail of ranges */ SEARCHSET set; /* set of retained ranges */ MIXBURP *next; /* next file to burp */};/* Convenient access to local data */#define LOCAL ((MIXLOCAL *) stream->local)/* Function prototypes */DRIVER *mix_valid (char *name);long mix_isvalid (char *name,char *meta);void *mix_parameters (long function,void *value);long mix_dirfmttest (char *name);void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);long mix_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz);void mix_list (MAILSTREAM *stream,char *ref,char *pat);void mix_lsub (MAILSTREAM *stream,char *ref,char *pat);long mix_subscribe (MAILSTREAM *stream,char *mailbox);long mix_unsubscribe (MAILSTREAM *stream,char *mailbox);long mix_create (MAILSTREAM *stream,char *mailbox);long mix_delete (MAILSTREAM *stream,char *mailbox);long mix_rename (MAILSTREAM *stream,char *old,char *newname);int mix_rselect (struct direct *name);MAILSTREAM *mix_open (MAILSTREAM *stream);void mix_close (MAILSTREAM *stream,long options);void mix_abort (MAILSTREAM *stream);char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags);long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags);THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags);long mix_ping (MAILSTREAM *stream);void mix_check (MAILSTREAM *stream);long mix_expunge (MAILSTREAM *stream,char *sequence,long options);int mix_select (struct direct *name);int mix_msgfsort (const void *d1,const void *d2);long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size);long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed);long mix_burp_check (SEARCHSET *set,size_t size,char *file);long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options);long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt, STRING *msg,SEARCHSET *set,unsigned long seq);FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags);char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq);long mix_meta_update (MAILSTREAM *stream);long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag);long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag);FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size, unsigned long newsize);FILE *mix_sortcache_open (MAILSTREAM *stream);long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache);char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type);unsigned long mix_read_sequence (FILE *f);char *mix_dir (char *dst,char *name);char *mix_file (char *dst,char *dir,char *name);char *mix_file_data (char *dst,char *dir,unsigned long data);unsigned long mix_modseq (unsigned long oldseq);/* MIX mail routines *//* Driver dispatch used by MAIL */DRIVER mixdriver = { "mix", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ, (DRIVER *) NIL, /* next driver */ mix_valid, /* mailbox is valid for us */ mix_parameters, /* manipulate parameters */ mix_scan, /* scan mailboxes */ mix_list, /* find mailboxes */ mix_lsub, /* find subscribed mailboxes */ mix_subscribe, /* subscribe to mailbox */ mix_unsubscribe, /* unsubscribe from mailbox */ mix_create, /* create mailbox */ mix_delete, /* delete mailbox */ mix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mix_open, /* open mailbox */ mix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mix_header, /* fetch message header only */ mix_text, /* fetch message body only */ NIL, /* fetch partial message test */ NIL, /* unique identifier */ NIL, /* message number */ mix_flag, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ mix_sort, /* sort messages */ mix_thread, /* thread messages */ mix_ping, /* ping mailbox to see if still alive */ mix_check, /* check for new messages */ mix_expunge, /* expunge deleted messages */ mix_copy, /* copy messages to another mailbox */ mix_append, /* append string message to mailbox */ NIL /* garbage collect stream */}; /* prototype stream */MAILSTREAM mixproto = {&mixdriver};/* MIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */DRIVER *mix_valid (char *name){ char tmp[MAILTMPLEN]; return mix_isvalid (name,tmp) ? &mixdriver : NIL;}/* MIX mail test for valid mailbox * Accepts: mailbox name * buffer to return meta name * Returns: T if valid, NIL otherwise, metadata name written in both cases */long mix_isvalid (char *name,char *meta){ char dir[MAILTMPLEN]; struct stat sbuf; /* validate name as directory */ if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) && *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) && !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* name is directory; is it mix? */ if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return LONGT; else errno = NIL; /* directory but not mix */ } return NIL;}/* MIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *mix_parameters (long function,void *value){ void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mailboxfile ((char *) value,"~/INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mix_dirfmttest; break; case GET_SCANCONTENTS: ret = (void *) mix_scan_contents; break; case SET_ONETIMEEXPUNGEATPING: if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret;}/* MIX test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */long mix_dirfmttest (char *name){ /* belongs to MIX if starts with .mix */ return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT;}/* MIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents){ if (stream) dummy_scan (NIL,ref,pat,contents);}/* MIX scan mailbox for contents * Accepts: mailbox name * desired contents * contents size * file size (ignored) * Returns: NIL if contents not found, T if found */long mix_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz){ long i,nfiles; void *a; char *s; long ret = NIL; size_t namelen = strlen (name); struct stat sbuf; struct direct **names = NIL; if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0) for (i = 0; i < nfiles; ++i) { if (!ret) { sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2), "%s/%s",name,names[i]->d_name); if (!stat (s,&sbuf) && (csiz <= sbuf.st_size)) ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size); fs_give ((void **) &s); } fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); return ret;}/* MIX list mailboxes * Accepts: mail stream * reference * pattern to search */void mix_list (MAILSTREAM *stream,char *ref,char *pat){ if (stream) dummy_list (NIL,ref,pat);}/* MIX list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */void mix_lsub (MAILSTREAM *stream,char *ref,char *pat){ if (stream) dummy_lsub (NIL,ref,pat);}/* MIX mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */long mix_subscribe (MAILSTREAM *stream,char *mailbox){ return sm_subscribe (mailbox);}/* MIX mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -