📄 unix.c
字号:
unsigned long i,j,k,m; char *s,*t,*te,p1[CHUNK]; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { memcpy (p1,bs->curpos,i); /* remember what we have so far */ /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); memcpy (ret,p1,i); /* copy first chunk */ while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) SNX (bs); /* skip over newline if one seen */ ret[i++] = '\n'; /* make sure newline at end */ ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ return ret;}/* UNIX make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr){ int i; char *s,tmp[MAILTMPLEN]; time_t now = time (0); rfc822_fixed_date (tmp); sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu", pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (s += strlen (s)," %s",stream->user_flags[i]); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg); return strlen (hdr); /* return header length */}/* UNIX make status string * Accepts: MAIL stream * destination string to write * message cache entry * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, long flag){ char *t,stack[64]; char *s = status; unsigned long n; int pad = 50; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ /* need to write X-IMAPbase: header? */ if ((flag < 0) && !stream->uid_nosticky) { *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P'; *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' '; t = stack; n = stream->uid_validity; /* push UID validity digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID validity digits from stack */ while (t > stack) *s++ = *--t; *s++ = ' '; n = stream->uid_last; /* push UID last digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID last digits from stack */ while (t > stack) *s++ = *--t; for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n]) for (*s++ = ' '; *t; *s++ = *t++); *s++ = '\n'; pad += 30; /* increased padding if have IMAPbase */ } *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; *s++ = 'O'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\n'; if (!stream->uid_nosticky) { /* cretins with no life can't use this */ *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; n = elt->private.uid; /* push UID digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\n'; } } *s++ = '\n'; *s = '\0'; /* end of extended message status */ return s - status; /* return size of resulting string */}/* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * Returns: T if success and mailbox unlocked, NIL if failure */#define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock){ MESSAGECACHE *elt; UNIXFILE f; char *s; time_t tp[2]; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) if (!(elt = mail_elt (stream,i))->deleted || !nexp) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.data + unix_xstatus (stream,LOCAL->buf,elt,flag) + elt->private.msg.text.text.size + 1; flag = 1; /* only count X-IMAPbase once */ } /* extend the file as necessary */ if (ret = unix_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ if (nexp && elt->deleted){/* expunge this message? */ /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ (elt->private.dirty || (f.curpos != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.data + unix_xstatus (stream,LOCAL->buf,elt,flag))))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* see if need to squeeze out a CR */ if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') { LOCAL->buf[--elt->private.special.text.size - 1] = '\n'; --size; /* squeezed out a CR from PC */ } /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ unix_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = unix_header (stream,elt->msgno,&j,FT_INTERNAL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 2) || (s[j - 2] == '\n')) j--; if (j != elt->private.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; unix_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ unix_write (&f,LOCAL->buf, j = unix_xstatus (stream,LOCAL->buf,elt,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); /* this can happen if CRs were squeezed */ if (j < elt->private.msg.text.text.size) { /* so fix up counts */ size -= elt->private.msg.text.text.size - j; elt->private.msg.text.text.size = j; } /* can't happen it says here */ else if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1); unix_write (&f,s,j);/* write text */ /* write trailing newline */ unix_write (&f,"\n",1); } else { /* tie off header and status */ unix_write (&f,NIL,NIL); f.curpos = f.protect =/* restart everything at end of message */ f.filepos += elt->private.msg.text.text.size + 1; } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ unix_write (&f,NIL,NIL); f.curpos = f.protect =/* restart everything at end of message */ f.filepos += elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size + 1; } } } unix_write (&f,NIL,NIL); /* tie off final message */ if (size != f.filepos) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); LOCAL->dirty = NIL; /* no longer dirty */ /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ tp[1] = (tp[0] = time (0)) - 1; /* set the times, note change */ if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; close (LOCAL->fd); /* close and reopen file */ if ((LOCAL->fd = open (stream->mailbox,O_RDWR,NIL)) < 0) { sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); unix_abort (stream); } dotlock_unlock (lock); /* flush the lock file */ } return ret; /* return state from algorithm */}/* Extend UNIX mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */long unix_extend (MAILSTREAM *stream,unsigned long size){ unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (mm_diskerror (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); mm_log (LOCAL->buf,ERROR); return NIL; } } } } return LONGT;}/* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flu
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -