⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmdf.c

📁 广泛使用的邮件服务器!同时
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -