📄 mmdf.c
字号:
/* MMDF 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 mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op){ int fd; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_FILELOCK,NIL); /* try locking the easy way */ if (dotlock_lock (file,lock,-1)) { /* got dotlock file, easy open */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else dotlock_unlock (lock); /* open failed, free the dotlock */ } /* no dot lock file, open file now */ else if ((fd = open (file,flags,mode)) >= 0) { /* try paranoid way to make a dot lock file */ if (dotlock_lock (file,lock,fd)) { close (fd); /* get fresh fd in case of timing race */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); /* open failed, free the dotlock */ else dotlock_unlock (lock); } else flock (fd,op); /* paranoid way failed, just flock() it */ } (*bn) (BLOCK_NONE,NIL); return fd;}/* MMDF unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock){ if (stream) { /* need to muck with times? */ struct stat sbuf; time_t tp[2]; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (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 */ tp[0] = (tp[1] = (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)) { tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (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,tp)) LOCAL->filetime = tp[1]; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ dotlock_unlock (lock); /* flush the lock file if any */}/* MMDF 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 mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op){ int ti,zn,m; unsigned long i,j,k; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int 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 = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ? O_RDWR : O_RDONLY, (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL), lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (tmp,ERROR); mmdf_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 */ mmdf_unlock (LOCAL->fd,stream,lock); mmdf_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 = mmdf_mbxline (stream,&bs,&i); stream->silent = T; /* quell main program new message events */ do { /* read MMDF header */ if (!(i && ISMMDF (s))){/* see if valid MMDF header */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); /* see if we can back up to a line */ if (i && (j > MMDFHDRLEN)) { SETPOS (&bs,j -= MMDFHDRLEN); /* read previous line */ s = mmdf_mbxline (stream,&bs,&i); /* kill the error if it looks good */ if (i && ISMMDF (s)) tmp[0] = '\0'; } if (tmp[0]) { MM_LOG (tmp,ERROR); mmdf_unlock (LOCAL->fd,stream,lock); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); return NIL; } } /* 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.special.text.size = i; s = mmdf_mbxline (stream,&bs,&i); ti = 0; /* assume not a valid date */ zn = 0,t = NIL; if (i) VALID (s,t,ti,zn); if (ti) { /* generate plausible IMAPish date string */ /* this is also part of header */ elt->private.special.text.size += i; 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); } } else { /* make date from file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; t = NIL; /* suppress line read */ } /* header starts here */ elt->private.msg.header.offset = elt->private.special.text.size; do { /* look for message body */ j = GETPOS (&bs); /* note position before line */ if (t) s = t = mmdf_mbxline (stream,&bs,&i); else t = s; /* this line read was suppressed */ if (ISMMDF (s)) { /* found terminator in header? */ SETPOS (&bs,j); /* oops, back up before line */ /* must insert a newline */ elt->private.spare.data++; break; /* punt */ } /* this line is part of header */ elt->private.msg.header.text.size += i; if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1);#if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last);#endif else { /* normal UID case */ prevuid = elt->private.uid = j;#if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } MM_LOG (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -