📄 unixnt.c
字号:
break; } if (fputs ("\r\n",sf) == EOF) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (fputs ("\r\n",sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing CRLF and return */ return (fputs ("\r\n",sf) == EOF) ? NIL : T;}/* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set){ int ti,zn,c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)|| (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\r\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\r\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun"); i -= j; /* number of bytes left */ if (!j) continue; /* do nothing if line emptied */ /* complete line? */ if ((c == '\n')) switch (tmp[0]) { case 'F': /* possible "From " (case counts here) */ if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && (tmp[4] == ' ')) { if (!unix_fromwidget) { VALID (tmp,x,ti,zn);/* conditional, only write widget if */ if (!ti) break; /* it looks like a valid header */ } /* write the widget */ if (putc ('>',df) == EOF) return NIL; } break; case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; break; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } if (i) return NIL; /* didn't read entire message */ /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T;}/* Internal routines *//* UNIX mail abort stream * Accepts: MAIL stream */void unix_abort (MAILSTREAM *stream){ if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ }}/* UNIX open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */int unix_lock (char *file,int flags,int mode,char *lock,int op){ int fd,ld,j; int i = LOCKTIMEOUT * 60 - 1; char tmp[MAILTMPLEN]; time_t t; struct stat sb; sprintf (lock,"%s.lock",file);/* build lock filename */ do { /* until OK or out of tries */ t = time (0); /* get the time now */ /* try to get the lock */ if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0) close (ld); /* got it, close the lock file! */ else if (errno != EEXIST) { /* miscellaneous error */ sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno)); if (!(i%15)) mm_log (tmp,WARN); } /* lock exists, still active? */ else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) && ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0)) close (ld); /* got timed-out lock file */ else { /* active lock, try again */ if (!(i%15)) { sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...", file,i); mm_log (tmp,WARN); } sleep (1); /* wait a second before next retry */ } } while (*lock && ld < 0 && i--); /* open file */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else { /* open failed */ j = errno; /* preserve error code */ if (*lock) unlink (lock); /* flush the lock file if any */ errno = j; /* restore error code */ } return fd;}/* UNIX unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */void unix_unlock (int fd,MAILSTREAM *stream,char *lock){ if (stream) { /* need to muck with times? */ struct stat sbuf; struct utimbuf times; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ times.actime = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ times.actime = (times.modtime = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { times.actime = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,×)) LOCAL->filetime = times.modtime; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ /* flush the lock file if any */ if (lock && *lock) unlink (lock);}/* UNIX mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */int unix_parse (MAILSTREAM *stream,char *lock,int op){ int zn; unsigned long i,j,k,m; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int ti = 0,retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); mm_critical (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = unix_lock (stream->mailbox, O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY), NIL,lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); mm_log (tmp,ERROR); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); mm_log (tmp,ERROR); /* this is pretty bad */ unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = unix_mbxline (stream,&bs,&i); t = NIL,zn = 0; if (i) VALID (s,t,ti,zn); /* see if valid From line */ if (!ti) { /* someone pulled the rug from under us */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); mm_log (tmp,ERROR); unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } stream->silent = T; /* quell main program new message events */ do { /* found a message */ /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.msg.header.offset = elt->private.special.text.size = i; /* generate plausible IMAPish date string */ date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6] == ':') {/* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); mm_log (tmp,WARN); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -