📄 mx.c
字号:
/* if deleted, need to trash it */ if ((elt = mail_elt (stream,i))->deleted) { sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); if (unlink (LOCAL->buf)) {/* try to delete the message */ sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i, strerror (errno)); MM_LOG (LOCAL->buf,(long) NIL); break; } /* note uncached */ LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ? elt->private.msg.header.text.size : 0) + (elt->private.msg.text.text.data ? elt->private.msg.text.text.size : 0)); mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS); if(elt->recent)--recent;/* if recent, note one less recent message */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else i++; /* otherwise try next message */ } if (n) { /* output the news if any expunged */ sprintf (LOCAL->buf,"Expunged %lu messages",n); MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); MM_NOCRITICAL (stream); /* release critical */ mx_unlockindex (stream); /* finished with index */ } /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent);}/* MX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options){ STRING st; MESSAGECACHE *elt; struct stat sbuf; int fd; unsigned long i,j; char *t,flags[MAILTMPLEN],date[MAILTMPLEN]; /* copy the messages */ if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL))<0) return NIL; fstat (fd,&sbuf); /* get size of message */ /* is buffer big enough? */ if (sbuf.st_size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1); } /* slurp message */ read (fd,LOCAL->buf,sbuf.st_size); /* tie off file */ LOCAL->buf[sbuf.st_size] = '\0'; close (fd); /* flush message file */ INIT (&st,mail_string,(void *) LOCAL->buf,sbuf.st_size); /* init flag string */ flags[0] = flags[1] = '\0'; if (j = elt->user_flags) do if (t = stream->user_flags[find_rightmost_bit (&j)]) strcat (strcat (flags," "),t); while (j); if (elt->seen) strcat (flags," \\Seen"); if (elt->deleted) strcat (flags," \\Deleted"); if (elt->flagged) strcat (flags," \\Flagged"); if (elt->answered) strcat (flags," \\Answered"); if (elt->draft) strcat (flags," \\Draft"); flags[0] = '('; /* open list */ strcat (flags,")"); /* close list */ mail_date (date,elt); /* generate internal date */ if (!mail_append_full (NIL,mailbox,flags,date,&st)) return NIL; if (options & CP_MOVE) elt->deleted = T; } return T; /* return success */}/* MX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data){ MESSAGECACHE *elt,selt; MAILSTREAM *astream; int fd; char *flags,*date,*s,tmp[MAILTMPLEN]; STRING *message; long f,i,size; unsigned long uf; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&mxproto); /* N.B.: can't use LOCAL->buf for tmp */ /* make sure valid mailbox */ if (!mx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX"); 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 MX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ /* lock the index */ if (mx_lockindex (astream)) do { if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } /* parse flags */ f = mail_parse_flags (astream,flags,&uf); if (date) { /* want to preserve date? */ /* yes, parse date into an elt */ if (!mail_parse_date (&selt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; break; } } mx_file (tmp,mailbox); /* make message name */ sprintf (tmp + strlen (tmp),"/%lu",++astream->uid_last); if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) { sprintf (tmp,"Can't create append message: %s",strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; break; } /* copy message */ s = (char *) fs_get (size = SIZE (message)); for (i = 0; i < size; s[i++] = SNX (message)); /* write the data */ if ((write (fd,s,size) < 0) || fsync (fd)) { unlink (tmp); /* delete mailbox */ sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } fs_give ((void **) &s); /* flush the buffer */ close (fd); /* close the file */ if (ret) { /* set the date for this message */ if (date) mx_setdate (tmp,&selt); /* swell the cache */ mail_exists (astream,++astream->nmsgs); /* copy flags */ (elt = mail_elt (astream,astream->nmsgs))->private.uid=astream->uid_last; if (f&fSEEN) elt->seen = T; if (f&fDELETED) elt->deleted = T; if (f&fFLAGGED) elt->flagged = T; if (f&fANSWERED) elt->answered = T; if (f&fDRAFT) elt->draft = T; elt->user_flags |= uf; /* get next message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); else { MM_LOG ("Message append failed: unable to lock index",ERROR); ret = NIL; } mx_unlockindex (astream); /* unlock index */ MM_NOCRITICAL (stream); /* release critical */ mail_close (astream); return ret;}/* Internal routines *//* MX file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */int mx_select (struct direct *name){ char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T;}/* MX file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */int mx_numsort (const void *d1,const void *d2){ return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name);}/* MX mail build file name * Accepts: destination string * source * Returns: destination */char *mx_file (char *dst,char *name){ char *s; if (!(mailboxfile (dst,name) && *dst)) return mailboxfile (dst,"~/INBOX"); /* tie off unnecessary trailing / */ if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0'; return dst;}/* MX read and lock index * Accepts: MAIL stream * Returns: T if success, NIL if failure */long mx_lockindex (MAILSTREAM *stream){ unsigned long uf,sf,uid; int k = 0; unsigned long msgno = 1; struct stat sbuf; char *s,*t,*idx,tmp[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if ((LOCAL->fd < 0) && /* get index file, no-op if already have it */ (LOCAL->fd = open (strcat (strcpy (tmp,LOCAL->dir),MXINDEXNAME), O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_EX); /* get exclusive lock */ (*bn) (BLOCK_NONE,NIL); fstat (LOCAL->fd,&sbuf); /* get size of index */ /* slurp index */ read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); idx[sbuf.st_size] = '\0'; /* tie off index */ /* parse index */ if (sbuf.st_size) while (s && *s) switch (*s) { case 'V': /* UID validity record */ stream->uid_validity = strtoul (s+1,&s,16); break; case 'L': /* UID last record */ stream->uid_last = strtoul (s+1,&s,16); break; case 'K': /* keyword */ /* find end of keyword */ if (s = strchr (t = ++s,'\n')) { *s++ = '\0'; /* tie off keyword */ /* copy keyword */ if ((k < NUSERFLAGS) && !stream->user_flags[k] && (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t); k++; /* one more keyword */ } break; case 'M': /* message status record */ uid = strtoul (s+1,&s,16);/* get UID for this message */ if (*s == ';') { /* get user flags */ uf = strtoul (s+1,&s,16); if (*s == '.') { /* get system flags */ sf = strtoul (s+1,&s,16); while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid)) msgno++; /* find message number for this UID */ if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) { (elt = mail_elt (stream,msgno))->valid = T; elt->user_flags=uf; /* set user and system flags in elt */ if (sf & fSEEN) elt->seen = T; if (sf & fDELETED) elt->deleted = T; if (sf & fFLAGGED) elt->flagged = T; if (sf & fANSWERED) elt->answered = T; if (sf & fDRAFT) elt->draft = T; } break; } } default: /* bad news */ sprintf (tmp,"Error in index: %.80s",s); MM_LOG (tmp,ERROR); *s = NIL; /* ignore remainder of index */ } else { /* new index */ stream->uid_validity = time (0); user_flags (stream); /* init stream with default user flags */ } fs_give ((void **) &idx); /* flush index */ } return (LOCAL->fd >= 0) ? T : NIL;}/* MX write and unlock index * Accepts: MAIL stream */void mx_unlockindex (MAILSTREAM *stream){ unsigned long i,j; off_t size = 0; char *s,tmp[MAILTMPLEN + 64]; MESSAGECACHE *elt; if (LOCAL->fd >= 0) { lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* write header */ sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]); /* write messages */ for (i = 1; i <= stream->nmsgs; i++) { /* filled buffer? */ if (((s += strlen (s)) - tmp) > MAILTMPLEN) { write (LOCAL->fd,tmp,j = s - tmp); size += j; *(s = tmp) = '\0'; /* dump out and restart buffer */ } elt = mail_elt (stream,i); sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); } /* write tail end of buffer */ if ((s += strlen (s)) != tmp) { write (LOCAL->fd,tmp,j = s - tmp); size += j; } ftruncate (LOCAL->fd,size); flock (LOCAL->fd,LOCK_UN); /* unlock the index */ close (LOCAL->fd); /* finished with file */ LOCAL->fd = -1; /* no index now */ }}/* Set date for message * Accepts: file name * elt containing date */void mx_setdate (char *file,MESSAGECACHE *elt){ time_t tp[2]; tp[0] = time (0); /* atime is now */ tp[1] = mail_longdate (elt); /* modification time */ utime (file,tp); /* set the times */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -