📄 tenex.c
字号:
}}/* Tenex mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to get flags */void tenex_flags (MAILSTREAM *stream,char *sequence,long flags){ unsigned long i; if (stream && LOCAL && ((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) tenex_elt (stream,i);}/* TENEX 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 *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags){ char *s; unsigned long i; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET); if (flags & FT_INTERNAL) { if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length = i); } else { s = (char *) fs_get (i + 1);/* get readin buffer */ s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i); fs_give ((void **) &s); /* free readin buffer */ } return LOCAL->buf;}/* TENEX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ char *s; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = tenex_elt (stream,msgno); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ tenex_update_status (stream,msgno,T); mm_flags (stream,msgno); } /* find header position */ i = tenex_hdrpos (stream,msgno,&j); lseek (LOCAL->fd,i + j,L_SET); /* go to text position */ if (flags & FT_INTERNAL) { /* if internal representation wanted */ if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* slurp the data */ read (LOCAL->fd,LOCAL->buf,i); } else { /* get readin buffer */ s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1); s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ i = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i); fs_give ((void **) &s); /* free readin buffer */ } /* set up stringstruct */ INIT (bs,mail_string,LOCAL->buf,i); return T; /* success */}/* Tenex mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */void tenex_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; }}/* Tenex mail per-message modify flags * Accepts: MAIL stream * message cache element */void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt){ struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ tenex_update_status (stream,elt->msgno,NIL);}/* Tenex mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */long tenex_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 */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ mm_notify (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) tenex_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } if (LOCAL) { /* stream must still be alive */ /* snarf if this is a read-write inbox */ if (stream->inbox && !stream->rdonly) { tenex_snarf (stream); fstat (LOCAL->fd,&sbuf);/* see if file changed now */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; 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); } } } return r; /* return result of the parse */}/* Tenex mail check mailbox (reparses status too) * Accepts: MAIL stream */void tenex_check (MAILSTREAM *stream){ /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL);}/* Tenex mail snarf messages from system inbox * Accepts: MAIL stream */void tenex_snarf (MAILSTREAM *stream){ unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; int ld; /* give up if can't get exclusive permission */ if ((time (0) < (LOCAL->lastsnarf + 30)) || (!strcmp (sysinbox (),stream->mailbox)) || ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)) 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,FT_INTERNAL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|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;0000000000%02o\n",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); mail_flag (sysibx,tmp,"\\Deleted",ST_SET); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); } mm_nocritical (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ LOCAL->lastsnarf = time (0); /* note time of last snarf */}/* Tenex mail expunge mailbox * Accepts: MAIL stream */void tenex_expunge (MAILSTREAM *stream){ struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* do nothing if stream dead */ if (!tenex_ping (stream)) return; if (stream->rdonly) { /* won't do on readonly files! */ mm_log ("Expunge ignored on readonly mailbox",WARN); return; } if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get exclusive parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) { mm_log ("Unable to lock expunge mailbox",ERROR); return; } /* get exclusive access */ if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* recover previous lock */ (*bn) (BLOCK_NONE,NIL); mm_log("Can't expunge because mailbox is in use by another process",ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return; } mm_critical (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ while (i <= stream->nmsgs) { /* for each message */ elt = tenex_elt (stream,i); /* get cache element */ /* number of bytes to smash or preserve */ k = elt->private.special.text.size + tenex_size (stream,i); if (elt->deleted) { /* if deleted */ if (elt->recent) --recent;/* if recent, note one less recent message */ delta += k; /* number of bytes to delete */ mail_expunged (stream,i); /* notify upper levels */ n++; /* count up one more expunged message */ } else if (i++ && delta) { /* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ lseek (LOCAL->fd,pos,L_SET); while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf,"Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); mm_log (LOCAL->buf,WARN); LOCAL->filesize = pos; /* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ LOCAL->filetime = sbuf.st_mtime; mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* allow sharers again */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,lock); /* release exclusive parse/append permission */}/* Tenex mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options){ struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd=open(tenex_file(file,mailbox),O_RDWR|O_CREAT,S_IREAD|S_IWRITE))<0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ /* get exclusive parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { mm_log ("Unable to lock copy mailbox",ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -