📄 unixnt.c
字号:
}}/* UNIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */long unix_expunge (MAILSTREAM *stream,char *sequence,long options){ long ret; unsigned long i; char lock[MAILTMPLEN]; char *msg = NIL; /* parse and lock mailbox */ if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ unix_unlock (LOCAL->fd,stream,lock); msg = "No messages deleted, so no update needed"; } else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* unlock the stream */ mm_nocritical (stream); /* done with critical */ if (msg && !stream->silent) mm_log (msg,NIL); } else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN); return ret;}/* UNIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options){ struct stat sbuf; int fd; char *s,file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!(unix_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); unix_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid UNIX-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 UNIX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; mm_critical (stream); /* go critical */ if ((fd = unix_lock (dummy_file (file,mailbox), O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE, lock,LOCK_EX)) < 0) { mm_nocritical (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); /* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') { LOCAL->buf[j - 1] = '\r'; LOCAL->buf[j++] = '\n'; } if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* internal header succeeded */ s = unix_header (stream,i,&j,NIL); /* header size, sans trailing newline */ if (j && (s[j - 4] == '\r')) j -= 2; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = unix_text_work (stream,elt,&j,NIL); if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = (unsigned long) time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } times.modtime = time (0); /* set mtime to now */ /* set atime to now-1 if successful copy */ if (ret) times.actime = times.modtime - 1; else times.actime = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : times.modtime; utime (file,×); /* set the times */ unix_unlock (fd,NIL,lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL * local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) mm_log (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; mm_nocritical (stream); /* release critical */ return ret;}/* UNIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */#define BUFLEN 8*MAILTMPLENlong unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data){ struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN], lock[MAILTMPLEN]; struct utimbuf times; FILE *sf,*df; MESSAGECACHE elt; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; if (!stream) { /* stream specified? */ stream = &unixproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!unix_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } unix_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR); else if (!unix_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); } /* get next message */ else if ((*af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ /* close sniffing stream */ if (tstream != stream) tstream = mail_close (tstream); mm_critical (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = unix_lock (dummy_file (file,mailbox), O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE, lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { mm_nocritical (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); times.modtime = time (0); /* set mtime to now */ /* write all messages */ if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); mm_log (buf,ERROR); ftruncate (fd,sbuf.st_size);/* revert file */ times.actime = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : times.modtime; ret = NIL; /* return error */ } /* set atime to now-1 if successful copy */ else times.actime = times.modtime - 1; utime (file,×); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = (unsigned long) time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); flock (fd,LOCK_UN); /* unlock mailbox (can't use unix_unlock() */ if (lock && *lock) unlink (lock); fclose (df); /* close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL * local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } mm_nocritical (stream); /* release critical */ return ret;}/* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg){ unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata */ if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL; for (s = date; *s; *s++) switch (*s) { default: if (putc (*s,sf) == EOF) return NIL; case '\r': case '\n':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -