📄 mbx.c
字号:
* Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *mbx_open (MAILSTREAM *stream){ int fd,ld; short silent; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mbxproto); if (stream->local) fatal ("mbx recycle stream"); if (stream->rdonly || (fd = open (mbx_file (tmp,stream->mailbox),O_RDWR,NIL)) < 0) { if ((fd = open (mbx_file (tmp,stream->mailbox),O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (MAXMESSAGESIZE + 1); LOCAL->buflen = MAXMESSAGESIZE; /* note if an INBOX or not */ stream->inbox = !strcmp(ucase (strcpy (LOCAL->buf,stream->mailbox)),"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get parse/append permission */ if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = HDRSIZE; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->fullcheck = LOCAL->flagcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; silent = stream->silent; /* defer events */ stream->silent = T; if (mbx_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); mail_recent (stream,stream->recent); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */}/* MBX mail close * Accepts: MAIL stream * close options */void mbx_close (MAILSTREAM *stream,long options){ if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* do an expunge if requested */ if (options & CL_EXPUNGE) mbx_expunge (stream); else { /* otherwise do a checkpoint to purge */ LOCAL->fullcheck = T; /* possible expunged messages */ mbx_ping (stream); } stream->silent = silent; /* restore previous status */ mbx_abort (stream); }}/* MBX mail abort stream * Accepts: MAIL stream */void mbx_abort (MAILSTREAM *stream){ if (stream && LOCAL) { /* only if a file is open */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text 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 */ }}/* MBX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */void mbx_flags (MAILSTREAM *stream,char *sequence,long flags){ unsigned long i; if (mbx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) mbx_elt (stream,i,NIL);}/* MBX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags){ unsigned long i; char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get header position, possibly header */ i = mbx_hdrpos (stream,msgno,length,&s); if (s) return s; /* mbx_hdrpos() returned header */ lseek (LOCAL->fd,i,L_SET); /* get to header position */ /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length); return LOCAL->buf;}/* MBX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = mbx_elt (stream,msgno,NIL); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mbx_update_status (stream,msgno,mus_SYNC); mm_flags (stream,msgno); } /* find header position */ i = mbx_hdrpos (stream,msgno,&j,NIL); /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); /* is buffer big enough? */ if ((i = elt->rfc822_size - j) > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } read (LOCAL->fd,LOCAL->buf,i);/* slurp the data */ LOCAL->buf[i] = '\0'; /* tie off string */ /* set up stringstruct */ INIT (bs,mail_string,LOCAL->buf,i); return T; /* success */}/* MBX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags){ struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ LOCAL->filetime = sbuf.st_mtime; } if ((LOCAL->ffuserflag < NUSERFLAGS)&&stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream); /* update header */}/* MBX mail per-message modify flags * Accepts: MAIL stream * message cache element */void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt){ struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->flagcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ mbx_update_status (stream,elt->msgno,NIL);}/* MBX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */long mbx_ping (MAILSTREAM *stream){ unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ int snarf = stream->inbox && !stream->rdonly; fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (!LOCAL->fullcheck) { /* don't bother if already full checking */ if (LOCAL->expunged && mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->fullcheck = T; /* upgrade to expunged message checking */ else if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; /* upgrade to flag checking */ } /* sweep mailbox for changed message status */ if (LOCAL->fullcheck || LOCAL->flagcheck) { while (i <= stream->nmsgs) if (mbx_elt (stream,i,LOCAL->fullcheck)) ++i; LOCAL->flagcheck = NIL; /* got all the updates */ } if ((snarf || (i = (sbuf.st_size - LOCAL->filesize) || !stream->nmsgs)) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { /* parse new messages in mailbox */ if (i) r = mbx_parse (stream); if (LOCAL && snarf) { /* snarf new messages if still OK */ mbx_snarf (stream); r = mbx_parse (stream); /* parse snarfed messages */ } unlockfd (ld,lock); /* release shared parse/append permission */ } else if ((sbuf.st_ctime > sbuf.st_atime)||(sbuf.st_ctime > sbuf.st_mtime)){ time_t tp[2]; /* whack the times if necessary */ LOCAL->filetime = tp[0] = tp[1] = time (0); utime (stream->mailbox,tp); } if (r && LOCAL->fullcheck) {/* full check requested? */ /* no more full check or pending expunge */ LOCAL->fullcheck = LOCAL->expunged = NIL; if (!stream->rdonly) { /* rewrite if not readonly */ if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check"); if (i) { sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i); mm_log (LOCAL->buf,(long) NIL); } } } } return r; /* return result of the parse */}/* MBX mail check mailbox (reparses status too) * Accepts: MAIL stream */void mbx_check (MAILSTREAM *stream){ /* mark that a check is desired */ if (LOCAL) LOCAL->fullcheck = T; if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL);}/* MBX mail expunge mailbox * Accepts: MAIL stream */void mbx_expunge (MAILSTREAM *stream){ struct stat sbuf; unsigned long nexp,reclaimed; if (!mbx_ping (stream)); /* do nothing if stream dead */ else if (stream->rdonly) /* won't do on readonly files! */ mm_log ("Expunge ignored on readonly mailbox",WARN); else { /* see if will need a flagcheck after this */ if (LOCAL->filetime && !LOCAL->flagcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; } /* if expunged any messages */ if (nexp = mbx_rewrite (stream,&reclaimed,T)) { sprintf (LOCAL->buf,"Expunged %lu messages",nexp); mm_log (LOCAL->buf,(long) NIL); } else if (reclaimed) { /* or if any prior expunged space reclaimed */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); }}/* MBX mail snarf messages from system inbox * Accepts: MAIL stream, already locked */void mbx_snarf (MAILSTREAM *stream){ unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; /* give up if can't get exclusive permission */ if ((time (0) < (LOCAL->lastsnarf + 30)) || !strcmp (sysinbox (),stream->mailbox)) return; mm_critical (stream); /* go critical */ /* see if anything there */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size) { fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ /* sizes match and can get sysibx mailbox? */ if ((sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK); if (j = hdrlen + txtlen) { /* calculate header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;00000000%04x-00000000\015\012",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -