📄 tenex.c
字号:
/* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + tenex_size (stream,i); do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = tenex_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ tenex_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ LOCAL->filetime = sbuf.st_mtime; } } return ret;}/* Tenex mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data){ struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,j,uf,size; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&tenexproto); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) && ((mailbox[1] == 'N') || (mailbox[1] == 'n')) && ((mailbox[2] == 'B') || (mailbox[2] == 'b')) && ((mailbox[3] == 'O') || (mailbox[3] == 'o')) && ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) dummy_create (NIL,"mail.txt"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND|O_CREAT, S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",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 append mailbox",ERROR); close (fd); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ do { /* parse flags */ f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ i = GETPOS (message); /* remember current position */ for (j = SIZE (message), size = 0; j; --j) if (SNX (message) != '\015') ++size; SETPOS (message,i); /* restore position */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0) ret = NIL; else { /* write message */ while (size) if ((c = 0xff & SNX (message)) != '\015') { if (putc (c,df) != EOF) --size; else break; } /* get next message */ if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); ret = NIL; } tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ mm_nocritical (stream); /* release critical */ return ret;}/* Internal routines *//* Tenex mail return internal message size in bytes * Accepts: MAIL stream * message # * Returns: internal size of message */unsigned long tenex_size (MAILSTREAM *stream,unsigned long m){ MESSAGECACHE *elt = mail_elt (stream,m); return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset : LOCAL->filesize) - (elt->private.special.offset + elt->private.special.text.size);}/* Tenex mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */char *tenex_file (char *dst,char *name){ char tmp[MAILTMPLEN]; char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ? "~/INBOX" : "mail.txt") : s;}/* Tenex mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */long tenex_parse (MAILSTREAM *stream){ struct stat sbuf; MESSAGECACHE *elt = NIL; char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!(s = strchr (LOCAL->buf,'\012'))) { sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,LOCAL->buf); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 1) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,LOCAL->buf); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->private.msg.full.text.size = strtoul (s,&s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,LOCAL->buf,x,t); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ tenex_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */}/* Tenex get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno){ MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; tenex_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt;}/* Tenex read flags from file * Accepts: MAIL stream * Returns: cache element */void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt){ unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */}/* Tenex update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag){ MESSAGECACHE *elt = mail_elt (stream,msgno); struct stat sbuf; unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* write new flags */ write (LOCAL->fd,LOCAL->buf,12); if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ LOCAL->filetime = sbuf.st_mtime; } }}/* Tenex locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size){ unsigned long siz; long i = 0; char c = '\0'; char *s = NIL; MESSAGECACHE *elt = tenex_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; unsigned long msiz = tenex_size (stream,msgno); /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for LF LF */ for (siz = 0; siz < msiz; siz++) { if (--i <= 0) /* read another buffer as necessary */ read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN)); /* two newline sequence? */ if ((c == '\012') && (*s == '\012')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz + 1); return ret; /* return to caller */ } else c = *s++; /* next character */ } /* header consumes entire message */ elt->private.msg.header.text.size = *size = msiz; } return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -