imapext-2007
diff src/osdep/dos/bezrkdos.c @ 0:ada5e610ab86
imap-2007e
author | yuuji@gentei.org |
---|---|
date | Mon, 14 Sep 2009 15:17:45 +0900 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/osdep/dos/bezrkdos.c Mon Sep 14 15:17:45 2009 +0900 1.3 @@ -0,0 +1,901 @@ 1.4 +/* ======================================================================== 1.5 + * Copyright 1988-2006 University of Washington 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * 1.14 + * ======================================================================== 1.15 + */ 1.16 + 1.17 +/* 1.18 + * Program: Berkeley mail routines 1.19 + * 1.20 + * Author: Mark Crispin 1.21 + * Networks and Distributed Computing 1.22 + * Computing & Communications 1.23 + * University of Washington 1.24 + * Administration Building, AG-44 1.25 + * Seattle, WA 98195 1.26 + * Internet: MRC@CAC.Washington.EDU 1.27 + * 1.28 + * Date: 24 June 1992 1.29 + * Last Edited: 30 August 2006 1.30 + */ 1.31 + 1.32 + 1.33 +/* Dedication: 1.34 + * This file is dedicated with affection to those Merry Marvels of Musical 1.35 + * Madness . . . 1.36 + * -> The Incomparable Leland Stanford Junior University Marching Band <- 1.37 + * who entertain, awaken, and outrage Stanford fans in the fact of repeated 1.38 + * losing seasons and shattered Rose Bowl dreams [Cardinal just don't have 1.39 + * HUSKY FEVER!!!]. 1.40 + * 1.41 + */ 1.42 + 1.43 +#include <ctype.h> 1.44 +#include <errno.h> 1.45 +#include <fcntl.h> 1.46 +#include "mail.h" 1.47 +#include "osdep.h" 1.48 +#include <time.h> 1.49 +#include <sys\stat.h> 1.50 +#include <dos.h> 1.51 +#include "rfc822.h" 1.52 +#include "dummy.h" 1.53 +#include "misc.h" 1.54 +#include "fdstring.h" 1.55 + 1.56 +/* Berkeley I/O stream local data */ 1.57 + 1.58 +typedef struct bezerk_local { 1.59 + int fd; /* file descriptor for I/O */ 1.60 + off_t filesize; /* file size parsed */ 1.61 + char *buf; /* temporary buffer */ 1.62 +} BEZERKLOCAL; 1.63 + 1.64 + 1.65 +/* Convenient access to local data */ 1.66 + 1.67 +#define LOCAL ((BEZERKLOCAL *) stream->local) 1.68 + 1.69 +/* Function prototypes */ 1.70 + 1.71 +DRIVER *bezerk_valid (char *name); 1.72 +long bezerk_isvalid (char *name,char *tmp); 1.73 +int bezerk_valid_line (char *s,char **rx,int *rzn); 1.74 +void *bezerk_parameters (long function,void *value); 1.75 +void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); 1.76 +void bezerk_list (MAILSTREAM *stream,char *ref,char *pat); 1.77 +void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat); 1.78 +long bezerk_create (MAILSTREAM *stream,char *mailbox); 1.79 +long bezerk_delete (MAILSTREAM *stream,char *mailbox); 1.80 +long bezerk_rename (MAILSTREAM *stream,char *old,char *newname); 1.81 +MAILSTREAM *bezerk_open (MAILSTREAM *stream); 1.82 +void bezerk_close (MAILSTREAM *stream,long options); 1.83 +char *bezerk_header (MAILSTREAM *stream,unsigned long msgno, 1.84 + unsigned long *length,long flags); 1.85 +long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs, 1.86 + long flags); 1.87 +long bezerk_ping (MAILSTREAM *stream); 1.88 +void bezerk_check (MAILSTREAM *stream); 1.89 +long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options); 1.90 +long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox, 1.91 + long options); 1.92 +long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); 1.93 +int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, 1.94 + STRING *msg); 1.95 +void bezerk_gc (MAILSTREAM *stream,long gcflags); 1.96 +char *bezerk_file (char *dst,char *name); 1.97 +long bezerk_badname (char *tmp,char *s); 1.98 +long bezerk_parse (MAILSTREAM *stream); 1.99 +unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno, 1.100 + unsigned long *size); 1.101 + 1.102 +/* Berkeley mail routines */ 1.103 + 1.104 + 1.105 +/* Driver dispatch used by MAIL */ 1.106 + 1.107 +DRIVER bezerkdriver = { 1.108 + "bezerk", /* driver name */ 1.109 + /* driver flags */ 1.110 + DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY, 1.111 + (DRIVER *) NIL, /* next driver */ 1.112 + bezerk_valid, /* mailbox is valid for us */ 1.113 + bezerk_parameters, /* manipulate parameters */ 1.114 + bezerk_scan, /* scan mailboxes */ 1.115 + bezerk_list, /* list mailboxes */ 1.116 + bezerk_lsub, /* list subscribed mailboxes */ 1.117 + NIL, /* subscribe to mailbox */ 1.118 + NIL, /* unsubscribe from mailbox */ 1.119 + bezerk_create, /* create mailbox */ 1.120 + bezerk_delete, /* delete mailbox */ 1.121 + bezerk_rename, /* rename mailbox */ 1.122 + mail_status_default, /* status of mailbox */ 1.123 + bezerk_open, /* open mailbox */ 1.124 + bezerk_close, /* close mailbox */ 1.125 + NIL, /* fetch message "fast" attributes */ 1.126 + NIL, /* fetch message flags */ 1.127 + NIL, /* fetch overview */ 1.128 + NIL, /* fetch message envelopes */ 1.129 + bezerk_header, /* fetch message header */ 1.130 + bezerk_text, /* fetch message text */ 1.131 + NIL, /* fetch partial message text */ 1.132 + NIL, /* unique identifier */ 1.133 + NIL, /* message number */ 1.134 + NIL, /* modify flags */ 1.135 + NIL, /* per-message modify flags */ 1.136 + NIL, /* search for message based on criteria */ 1.137 + NIL, /* sort messages */ 1.138 + NIL, /* thread messages */ 1.139 + bezerk_ping, /* ping mailbox to see if still alive */ 1.140 + bezerk_check, /* check for new messages */ 1.141 + bezerk_expunge, /* expunge deleted messages */ 1.142 + bezerk_copy, /* copy messages to another mailbox */ 1.143 + bezerk_append, /* append string message to mailbox */ 1.144 + NIL /* garbage collect stream */ 1.145 +}; 1.146 + 1.147 + /* prototype stream */ 1.148 +MAILSTREAM bezerkproto = {&bezerkdriver}; 1.149 + 1.150 +/* Berkeley mail validate mailbox 1.151 + * Accepts: mailbox name 1.152 + * Returns: our driver if name is valid, NIL otherwise 1.153 + */ 1.154 + 1.155 +DRIVER *bezerk_valid (char *name) 1.156 +{ 1.157 + char tmp[MAILTMPLEN]; 1.158 + return bezerk_isvalid (name,tmp) ? &bezerkdriver : (DRIVER *) NIL; 1.159 +} 1.160 + 1.161 + 1.162 +/* Berkeley mail test for valid mailbox 1.163 + * Accepts: mailbox name 1.164 + * Returns: T if valid, NIL otherwise 1.165 + */ 1.166 + 1.167 +long bezerk_isvalid (char *name,char *tmp) 1.168 +{ 1.169 + int fd; 1.170 + long ret = NIL; 1.171 + struct stat sbuf; 1.172 + errno = EINVAL; /* assume invalid argument */ 1.173 + /* if file, get its status */ 1.174 + if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) { 1.175 + if (!sbuf.st_size)errno = 0;/* empty file */ 1.176 + else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) { 1.177 + memset (tmp,'\0',MAILTMPLEN); 1.178 + errno = -1; /* in case bezerk_valid_line fails */ 1.179 + if (read (fd,tmp,MAILTMPLEN-1) >= 0) 1.180 + ret = bezerk_valid_line (tmp,NIL,NIL); 1.181 + close (fd); /* close the file */ 1.182 + } 1.183 + } 1.184 + /* in case INBOX but not bezerk format */ 1.185 + else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) && 1.186 + ((name[1] == 'N') || (name[1] == 'n')) && 1.187 + ((name[2] == 'B') || (name[2] == 'b')) && 1.188 + ((name[3] == 'O') || (name[3] == 'o')) && 1.189 + ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1; 1.190 + return ret; /* return what we should */ 1.191 +} 1.192 + 1.193 +/* Validate line 1.194 + * Accepts: pointer to candidate string to validate as a From header 1.195 + * return pointer to end of date/time field 1.196 + * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') 1.197 + * return pointer to offset from t of time zone (if non-zero) 1.198 + * Returns: t,ti,zn set if valid From string, else ti is NIL 1.199 + */ 1.200 + 1.201 +int bezerk_valid_line (char *s,char **rx,int *rzn) 1.202 +{ 1.203 + char *x; 1.204 + int zn; 1.205 + int ti = 0; 1.206 + /* line must begin with "From " */ 1.207 + if ((*s != 'F') || (s[1] != 'r') || (s[2] != 'o') || (s[3] != 'm') || 1.208 + (s[4] != ' ')) return NIL; 1.209 + /* find end of line */ 1.210 + for (x = s + 5; *x && *x != '\012'; x++); 1.211 + if (!x) return NIL; /* end of line not found */ 1.212 + if (x[-1] == '\015') x--; /* ignore CR */ 1.213 + if ((x - s < 27)) return NIL; /* line too short */ 1.214 + if (x - s >= 41) { /* possible search for " remote from " */ 1.215 + for (zn = -1; x[zn] != ' '; zn--); 1.216 + if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && 1.217 + (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && 1.218 + (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && 1.219 + (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' ')) 1.220 + x += zn - 12; 1.221 + } 1.222 + if (x[-5] == ' ') { /* ends with year? */ 1.223 + /* no timezone? */ 1.224 + if (x[-8] == ':') zn = 0,ti = -5; 1.225 + /* three letter timezone? */ 1.226 + else if (x[-9] == ' ') ti = zn = -9; 1.227 + /* numeric timezone? */ 1.228 + else if ((x[-11]==' ') && ((x[-10]=='+') || (x[-10]=='-'))) ti = zn = -11; 1.229 + } 1.230 + else if (x[-4] == ' ') { /* no year and three leter timezone? */ 1.231 + if (x[-9] == ' ') zn = -4,ti = -9; 1.232 + } 1.233 + else if (x[-6] == ' ') { /* no year and numeric timezone? */ 1.234 + if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) 1.235 + zn = -6,ti = -11; 1.236 + } 1.237 + /* time must be www mmm dd hh:mm[:ss] */ 1.238 + if (ti && !((x[ti - 3] == ':') && 1.239 + (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && 1.240 + (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && 1.241 + (x[ti - 11] == ' '))) return NIL; 1.242 + if (rx) *rx = x; /* set return values */ 1.243 + if (rzn) *rzn = zn; 1.244 + return ti; 1.245 +} 1.246 + 1.247 +/* Berkeley manipulate driver parameters 1.248 + * Accepts: function code 1.249 + * function-dependent value 1.250 + * Returns: function-dependent return value 1.251 + */ 1.252 + 1.253 +void *bezerk_parameters (long function,void *value) 1.254 +{ 1.255 + return NIL; 1.256 +} 1.257 + 1.258 + 1.259 +/* Berkeley mail scan mailboxes 1.260 + * Accepts: mail stream 1.261 + * reference 1.262 + * pattern to search 1.263 + * string to scan 1.264 + */ 1.265 + 1.266 +void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) 1.267 +{ 1.268 + if (stream) dummy_scan (NIL,ref,pat,contents); 1.269 +} 1.270 + 1.271 + 1.272 +/* Berkeley mail list mailboxes 1.273 + * Accepts: mail stream 1.274 + * reference 1.275 + * pattern to search 1.276 + */ 1.277 + 1.278 +void bezerk_list (MAILSTREAM *stream,char *ref,char *pat) 1.279 +{ 1.280 + if (stream) dummy_list (stream,ref,pat); 1.281 +} 1.282 + 1.283 + 1.284 +/* Berkeley mail list subscribed mailboxes 1.285 + * Accepts: mail stream 1.286 + * reference 1.287 + * pattern to search 1.288 + */ 1.289 + 1.290 +void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat) 1.291 +{ 1.292 + if (stream) dummy_lsub (stream,ref,pat); 1.293 +} 1.294 + 1.295 +/* Berkeley mail create mailbox 1.296 + * Accepts: MAIL stream 1.297 + * mailbox name to create 1.298 + * Returns: T on success, NIL on failure 1.299 + */ 1.300 + 1.301 +long bezerk_create (MAILSTREAM *stream,char *mailbox) 1.302 +{ 1.303 + return dummy_create (stream,mailbox); 1.304 +} 1.305 + 1.306 + 1.307 +/* Berkeley mail delete mailbox 1.308 + * Accepts: MAIL stream 1.309 + * mailbox name to delete 1.310 + * Returns: T on success, NIL on failure 1.311 + */ 1.312 + 1.313 +long bezerk_delete (MAILSTREAM *stream,char *mailbox) 1.314 +{ 1.315 + return dummy_delete (stream,mailbox); 1.316 +} 1.317 + 1.318 + 1.319 +/* Berkeley mail rename mailbox 1.320 + * Accepts: MAIL stream 1.321 + * old mailbox name 1.322 + * new mailbox name (or NIL for delete) 1.323 + * Returns: T on success, NIL on failure 1.324 + */ 1.325 + 1.326 +long bezerk_rename (MAILSTREAM *stream,char *old,char *newname) 1.327 +{ 1.328 + return dummy_rename (stream,old,newname); 1.329 +} 1.330 + 1.331 +/* Berkeley mail open 1.332 + * Accepts: stream to open 1.333 + * Returns: stream on success, NIL on failure 1.334 + */ 1.335 + 1.336 +MAILSTREAM *bezerk_open (MAILSTREAM *stream) 1.337 +{ 1.338 + long i; 1.339 + int fd; 1.340 + char *s; 1.341 + char tmp[MAILTMPLEN]; 1.342 + /* return prototype for OP_PROTOTYPE call */ 1.343 + if (!stream) return &bezerkproto; 1.344 + if (stream->local) fatal ("bezerk recycle stream"); 1.345 + if (!mailboxfile (tmp,stream->mailbox)) 1.346 + return (MAILSTREAM *) bezerk_badname (tmp,stream->mailbox); 1.347 + if (((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0)) { 1.348 + sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); 1.349 + mm_log (tmp,ERROR); 1.350 + return NIL; 1.351 + } 1.352 + stream->rdonly = T; /* this driver is readonly */ 1.353 + stream->local = fs_get (sizeof (BEZERKLOCAL)); 1.354 + /* canonicalize the stream mailbox name */ 1.355 + fs_give ((void **) &stream->mailbox); 1.356 + if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0'; 1.357 + stream->mailbox = cpystr (tmp); 1.358 + LOCAL->fd = fd; /* note the file */ 1.359 + LOCAL->filesize = 0; /* initialize parsed file size */ 1.360 + LOCAL->buf = NIL; /* initially no local buffer */ 1.361 + stream->sequence++; /* bump sequence number */ 1.362 + stream->uid_validity = time (0); 1.363 + /* parse mailbox */ 1.364 + stream->nmsgs = stream->recent = 0; 1.365 + if (!bezerk_ping (stream)) return NIL; 1.366 + if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); 1.367 + stream->perm_seen = stream->perm_deleted = 1.368 + stream->perm_flagged = stream->perm_answered = stream->perm_draft = NIL; 1.369 + stream->perm_user_flags = NIL; 1.370 + return stream; /* return stream to caller */ 1.371 +} 1.372 + 1.373 +/* Berkeley mail close 1.374 + * Accepts: MAIL stream 1.375 + * close options 1.376 + */ 1.377 + 1.378 +void bezerk_close (MAILSTREAM *stream,long options) 1.379 +{ 1.380 + if (stream && LOCAL) { /* only if a file is open */ 1.381 + int silent = stream->silent; 1.382 + stream->silent = T; 1.383 + if (options & CL_EXPUNGE) bezerk_expunge (stream,NIL,NIL); 1.384 + close (LOCAL->fd); /* close the local file */ 1.385 + if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); 1.386 + /* nuke the local data */ 1.387 + fs_give ((void **) &stream->local); 1.388 + stream->dtb = NIL; /* log out the DTB */ 1.389 + } 1.390 +} 1.391 + 1.392 +/* Berkeley mail fetch message header 1.393 + * Accepts: MAIL stream 1.394 + * message # to fetch 1.395 + * pointer to returned header text length 1.396 + * option flags 1.397 + * Returns: message header in RFC822 format 1.398 + */ 1.399 + 1.400 +char *bezerk_header (MAILSTREAM *stream,unsigned long msgno, 1.401 + unsigned long *length,long flags) 1.402 +{ 1.403 + char tmp[MAILTMPLEN]; 1.404 + *length = 0; /* default to empty */ 1.405 + if (flags & FT_UID) return "";/* UID call "impossible" */ 1.406 + /* get to header position */ 1.407 + lseek (LOCAL->fd,bezerk_hdrpos (stream,msgno,length),L_SET); 1.408 + /* is buffer big enough? */ 1.409 + if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); 1.410 + LOCAL->buf = (char *) fs_get ((size_t) *length + 1); 1.411 + LOCAL->buf[*length] = '\0'; /* tie off string */ 1.412 + /* slurp the data */ 1.413 + read (LOCAL->fd,LOCAL->buf,(size_t) *length); 1.414 + return LOCAL->buf; 1.415 +} 1.416 + 1.417 + 1.418 +/* Berkeley mail fetch message text (body only) 1.419 + * Accepts: MAIL stream 1.420 + * message # to fetch 1.421 + * pointer to returned header text length 1.422 + * option flags 1.423 + * Returns: T, always 1.424 + */ 1.425 + 1.426 +long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) 1.427 +{ 1.428 + MESSAGECACHE *elt; 1.429 + FDDATA d; 1.430 + unsigned long hdrsize,hdrpos; 1.431 + /* UID call "impossible" */ 1.432 + if (flags & FT_UID) return NIL; 1.433 + elt = mail_elt (stream,msgno);/* if message not seen */ 1.434 + /* mark message as seen */ 1.435 + if (elt->seen && !(flags & FT_PEEK)) { 1.436 + elt->seen = T; 1.437 + mm_flags (stream,msgno); 1.438 + } 1.439 + /* get location of text data */ 1.440 + hdrpos = bezerk_hdrpos (stream,msgno,&hdrsize); 1.441 + d.fd = LOCAL->fd; /* set initial stringstruct */ 1.442 + d.pos = hdrpos + hdrsize; 1.443 + /* flush old buffer */ 1.444 + if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); 1.445 + d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE); 1.446 + INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize); 1.447 + return T; /* success */ 1.448 +} 1.449 + 1.450 +/* Berkeley mail ping mailbox 1.451 + * Accepts: MAIL stream 1.452 + * Returns: T if stream still alive, NIL if not 1.453 + */ 1.454 + 1.455 +long bezerk_ping (MAILSTREAM *stream) 1.456 +{ 1.457 + /* punt if stream no longer alive */ 1.458 + if (!(stream && LOCAL)) return NIL; 1.459 + /* parse mailbox, punt if parse dies */ 1.460 + return (bezerk_parse (stream)) ? T : NIL; 1.461 +} 1.462 + 1.463 + 1.464 +/* Berkeley mail check mailbox (reparses status too) 1.465 + * Accepts: MAIL stream 1.466 + */ 1.467 + 1.468 +void bezerk_check (MAILSTREAM *stream) 1.469 +{ 1.470 + unsigned long i = 1; 1.471 + if (bezerk_ping (stream)) { /* ping mailbox */ 1.472 + /* get new message status */ 1.473 + while (i <= stream->nmsgs) mail_elt (stream,i++); 1.474 + mm_log ("Check completed",(long) NIL); 1.475 + } 1.476 +} 1.477 + 1.478 +/* Berkeley mail expunge mailbox 1.479 + * Accepts: MAIL stream 1.480 + * sequence to expunge if non-NIL 1.481 + * expunge options 1.482 + * Returns: T, always 1.483 + */ 1.484 + 1.485 +long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options) 1.486 +{ 1.487 + if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",WARN); 1.488 + return LONGT; 1.489 +} 1.490 + 1.491 +/* Berkeley mail copy message(s) 1.492 + * Accepts: MAIL stream 1.493 + * sequence 1.494 + * destination mailbox 1.495 + * copy options 1.496 + * Returns: T if success, NIL if failed 1.497 + */ 1.498 + 1.499 +long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) 1.500 +{ 1.501 + char tmp[MAILTMPLEN]; 1.502 + struct stat sbuf; 1.503 + MESSAGECACHE *elt; 1.504 + unsigned long i,j,k; 1.505 + int fd; 1.506 + mailproxycopy_t pc = 1.507 + (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); 1.508 + if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : 1.509 + mail_sequence (stream,sequence))) return NIL; 1.510 + /* make sure valid mailbox */ 1.511 + if (!bezerk_isvalid (mailbox,tmp) && errno) { 1.512 + if (errno == ENOENT) 1.513 + mm_notify (stream,"[TRYCREATE] Must create mailbox before append", 1.514 + (long) NIL); 1.515 + else if (pc) return (*pc) (stream,sequence,mailbox,options); 1.516 + else if (mailboxfile (tmp,mailbox)) { 1.517 + sprintf (tmp,"Not a Bezerk-format mailbox: %s",mailbox); 1.518 + mm_log (tmp,ERROR); 1.519 + } 1.520 + else bezerk_badname (tmp,mailbox); 1.521 + return NIL; 1.522 + } 1.523 + /* open the destination */ 1.524 + if (!mailboxfile (tmp,mailbox) || 1.525 + (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT, 1.526 + S_IREAD|S_IWRITE)) < 0) { 1.527 + sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno)); 1.528 + mm_log (tmp,ERROR); 1.529 + return NIL; 1.530 + } 1.531 + 1.532 + mm_critical (stream); /* go critical */ 1.533 + fstat (fd,&sbuf); /* get current file size */ 1.534 + /* for each requested message */ 1.535 + for (i = 1; i <= stream->nmsgs; i++) 1.536 + if ((elt = mail_elt (stream,i))->sequence) { 1.537 + lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET); 1.538 + /* number of bytes to copy */ 1.539 + j = elt->private.msg.full.offset + elt->rfc822_size; 1.540 + do { /* read from source position */ 1.541 + k = min (j,(unsigned long) MAILTMPLEN); 1.542 + read (LOCAL->fd,tmp,(unsigned int) k); 1.543 + if (write (fd,tmp,(unsigned int) k) < 0) { 1.544 + sprintf (tmp,"Unable to write message: %s",strerror (errno)); 1.545 + mm_log (tmp,ERROR); 1.546 + chsize (fd,sbuf.st_size); 1.547 + close (fd); /* punt */ 1.548 + mm_nocritical (stream); 1.549 + return NIL; 1.550 + } 1.551 + } while (j -= k); /* until done */ 1.552 + } 1.553 + close (fd); /* close the file */ 1.554 + mm_nocritical (stream); /* release critical */ 1.555 + /* delete all requested messages */ 1.556 + if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) 1.557 + if ((elt = mail_elt (stream,i))->sequence) elt->deleted = T; 1.558 + if (mail_parameters (NIL,GET_COPYUID,NIL)) 1.559 + mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); 1.560 + return T; 1.561 +} 1.562 + 1.563 +/* Berkeley mail append message from stringstruct 1.564 + * Accepts: MAIL stream 1.565 + * destination mailbox 1.566 + * append callback 1.567 + * data for callback 1.568 + * Returns: T if append successful, else NIL 1.569 + */ 1.570 + 1.571 +#define BUFLEN MAILTMPLEN 1.572 + 1.573 +long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) 1.574 +{ 1.575 + struct stat sbuf; 1.576 + int fd; 1.577 + unsigned long i,j; 1.578 + char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; 1.579 + FILE *sf,*df; 1.580 + MESSAGECACHE elt; 1.581 + STRING *message; 1.582 + long ret = LONGT; 1.583 + /* default stream to prototype */ 1.584 + if (!stream) stream = &bezerkproto; 1.585 + /* make sure valid mailbox */ 1.586 + if (!bezerk_isvalid (mailbox,tmp) && errno) { 1.587 + if (errno == ENOENT) { 1.588 + if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) && 1.589 + ((mailbox[1] == 'N') || (mailbox[1] == 'n')) && 1.590 + ((mailbox[2] == 'B') || (mailbox[2] == 'b')) && 1.591 + ((mailbox[3] == 'O') || (mailbox[3] == 'o')) && 1.592 + ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) 1.593 + bezerk_create (NIL,"INBOX"); 1.594 + else { 1.595 + mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); 1.596 + return NIL; 1.597 + } 1.598 + } 1.599 + else if (mailboxfile (tmp,mailbox)) { 1.600 + sprintf (tmp,"Not a Bezerk-format mailbox: %.80ss",mailbox); 1.601 + mm_log (tmp,ERROR); 1.602 + } 1.603 + else bezerk_badname (tmp,mailbox); 1.604 + return NIL; 1.605 + } 1.606 + tzset (); /* initialize timezone stuff */ 1.607 + /* get first message */ 1.608 + if (!(*af) (stream,data,&flags,&date,&message)) return NIL; 1.609 + if (!(sf = tmpfile ())) { /* must have scratch file */ 1.610 + sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); 1.611 + mm_log (tmp,ERROR); 1.612 + } 1.613 + 1.614 + do { /* parse date */ 1.615 + if (!date) rfc822_date (date = tmp); 1.616 + if (!mail_parse_date (&elt,date)) { 1.617 + sprintf (tmp,"Bad date in append: %.80s",date); 1.618 + mm_log (tmp,ERROR); 1.619 + } 1.620 + else { /* user wants to suppress time zones? */ 1.621 + if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { 1.622 + time_t when = mail_longdate (&elt); 1.623 + date = ctime (&when); /* use traditional date */ 1.624 + } 1.625 + /* use POSIX-style date */ 1.626 + else date = mail_cdate (tmp,&elt); 1.627 + if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR); 1.628 + else if (!bezerk_append_msg (stream,sf,flags,date,message)) { 1.629 + sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); 1.630 + mm_log (tmp,ERROR); 1.631 + } 1.632 + /* get next message */ 1.633 + else if ((*af) (stream,data,&flags,&date,&message)) continue; 1.634 + } 1.635 + fclose (sf); /* punt scratch file */ 1.636 + return NIL; /* give up */ 1.637 + } while (message); /* until no more messages */ 1.638 + if (fflush (sf) || fstat (fileno (sf),&sbuf)) { 1.639 + sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); 1.640 + mm_log (tmp,ERROR); 1.641 + fclose (sf); /* punt scratch file */ 1.642 + return NIL; /* give up */ 1.643 + } 1.644 + i = sbuf.st_size; /* size of scratch file */ 1.645 + 1.646 + mm_critical (stream); /* go critical */ 1.647 + /* open the destination */ 1.648 + if (!mailboxfile (tmp,mailbox) || 1.649 + ((fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT, 1.650 + S_IREAD|S_IWRITE)) < 0) || 1.651 + !(df = fdopen (fd,"ab"))) { 1.652 + mm_nocritical (stream); /* done with critical */ 1.653 + sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); 1.654 + mm_log (tmp,ERROR); 1.655 + return NIL; 1.656 + } 1.657 + fstat (fd,&sbuf); /* get current file size */ 1.658 + while (i) /* until written all bytes */ 1.659 + if ((j = fread (buf,1,min ((long) BUFLEN,i),sf)) && 1.660 + (fwrite (buf,1,j,df) == j)) i -= j; 1.661 + fclose (sf); /* done with scratch file */ 1.662 + /* make sure append wins */ 1.663 + if (i || (fflush (df) == EOF)) { 1.664 + chsize (fd,sbuf.st_size); /* revert file */ 1.665 + close (fd); /* make sure fclose() doesn't corrupt us */ 1.666 + sprintf (buf,"Message append failed: %s",strerror (errno)); 1.667 + mm_log (buf,ERROR); 1.668 + ret = NIL; /* return error */ 1.669 + } 1.670 + fclose (df); 1.671 + mm_nocritical (stream); /* release critical */ 1.672 + if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) 1.673 + mm_log ("Can not return meaningful APPENDUID with this mailbox format", 1.674 + WARN); 1.675 + return ret; 1.676 +} 1.677 + 1.678 +/* Write single message to append scratch file 1.679 + * Accepts: MAIL stream 1.680 + * scratch file 1.681 + * flags 1.682 + * message stringstruct 1.683 + * Returns: NIL if write error, else T 1.684 + */ 1.685 + 1.686 +int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, 1.687 + STRING *msg) 1.688 +{ 1.689 + int c; 1.690 + unsigned long i,uf; 1.691 + char tmp[MAILTMPLEN]; 1.692 + long f = mail_parse_flags (stream,flags,&uf); 1.693 + /* build initial header */ 1.694 + if ((fprintf (sf,"From %s@%s %sStatus: ", 1.695 + myusername (),mylocalhost (),date) < 0) || 1.696 + (f&fSEEN && (putc ('R',sf) == EOF)) || 1.697 + (fputs ("\nX-Status: ",sf) == EOF) || 1.698 + (f&fDELETED && (putc ('D',sf) == EOF)) || 1.699 + (f&fFLAGGED && (putc ('F',sf) == EOF)) || 1.700 + (f&fANSWERED && (putc ('A',sf) == EOF)) || 1.701 + (f&fDRAFT && (putc ('T',sf) == EOF)) || 1.702 + (fputs ("\nX-Keywords:",sf) == EOF)) return NIL; 1.703 + while (uf) /* write user flags */ 1.704 + if (fprintf (sf," %s",stream->user_flags[find_rightmost_bit (&uf)]) < 0) 1.705 + return NIL; 1.706 + /* tie off flags */ 1.707 + if (putc ('\n',sf) == EOF) return NIL; 1.708 + while (SIZE (msg)) { /* copy text to scratch file */ 1.709 + /* possible delimiter if line starts with F */ 1.710 + if ((c = 0xff & SNX (msg)) == 'F') { 1.711 + /* copy line to buffer */ 1.712 + for (i = 1,tmp[0] = c; SIZE (msg) && (c != '\n') && (i < MAILTMPLEN);) 1.713 + if (((c = 0xff & SNX (msg)) != '\r') || !(SIZE (msg)) || 1.714 + (CHR (msg) != '\n')) tmp[i++] = c; 1.715 + if ((i > 4) && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && 1.716 + (tmp[4] == ' ')) { /* possible "From " line? */ 1.717 + /* yes, see if need to write a widget */ 1.718 + if (((c != '\n') || bezerk_valid_line (tmp,NIL,NIL)) && 1.719 + (putc ('>',sf) == EOF)) return NIL; 1.720 + } 1.721 + /* write buffered text */ 1.722 + if (fwrite (tmp,1,i,sf) != i) return NIL; 1.723 + if (c == '\n') continue; /* all done if got a complete line */ 1.724 + } 1.725 + /* copy line, toss out CR from CRLF */ 1.726 + do if (((c == '\r') && SIZE (msg) && ((c = 0xff & SNX (msg)) != '\n') && 1.727 + (putc ('\r',sf) == EOF)) || (putc (c,sf) == EOF)) return NIL; 1.728 + while ((c != '\n') && SIZE (msg) && ((c = 0xff & SNX (msg)) ? c : T)); 1.729 + } 1.730 + /* write trailing newline and return */ 1.731 + return (putc ('\n',sf) == EOF) ? NIL : T; 1.732 +} 1.733 + 1.734 + 1.735 +/* Return bad file name error message 1.736 + * Accepts: temporary buffer 1.737 + * file name 1.738 + * Returns: long NIL always 1.739 + */ 1.740 + 1.741 +long bezerk_badname (char *tmp,char *s) 1.742 +{ 1.743 + sprintf (tmp,"Invalid mailbox name: %s",s); 1.744 + mm_log (tmp,ERROR); 1.745 + return (long) NIL; 1.746 +} 1.747 + 1.748 +/* Parse mailbox 1.749 + * Accepts: MAIL stream 1.750 + * Returns: T if parse OK 1.751 + * NIL if failure, stream aborted 1.752 + */ 1.753 + 1.754 +long bezerk_parse (MAILSTREAM *stream) 1.755 +{ 1.756 + struct stat sbuf; 1.757 + MESSAGECACHE *elt; 1.758 + char *s,*t,tmp[MAILTMPLEN + 1],*db,datemsg[100]; 1.759 + long i; 1.760 + int j,ti,zn; 1.761 + long curpos = LOCAL->filesize; 1.762 + long nmsgs = stream->nmsgs; 1.763 + long recent = stream->recent; 1.764 + short silent = stream->silent; 1.765 + fstat (LOCAL->fd,&sbuf); /* get status */ 1.766 + if (sbuf.st_size < curpos) { /* sanity check */ 1.767 + sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); 1.768 + mm_log (tmp,ERROR); 1.769 + bezerk_close (stream,NIL); 1.770 + return NIL; 1.771 + } 1.772 + stream->silent = T; /* don't pass up mm_exists() events yet */ 1.773 + db = datemsg + strlen (strcpy (datemsg,"Unparsable date: ")); 1.774 + /* while there is data to read */ 1.775 + while (i = sbuf.st_size - curpos){ 1.776 + /* get to that position in the file */ 1.777 + lseek (LOCAL->fd,curpos,SEEK_SET); 1.778 + /* read first buffer's worth */ 1.779 + read (LOCAL->fd,tmp,j = (int) min (i,(long) MAILTMPLEN)); 1.780 + tmp[j] = '\0'; /* tie off buffer */ 1.781 + if (!(ti = bezerk_valid_line (tmp,&t,&zn))) { 1.782 + mm_log ("Mailbox format invalidated (consult an expert), aborted",ERROR); 1.783 + bezerk_close (stream,NIL); 1.784 + return NIL; 1.785 + } 1.786 + 1.787 + /* swell the cache */ 1.788 + mail_exists (stream,++nmsgs); 1.789 + /* instantiate an elt for this message */ 1.790 + (elt = mail_elt (stream,nmsgs))->valid = T; 1.791 + elt->private.uid = ++stream->uid_last; 1.792 + /* note file offset of header */ 1.793 + elt->private.special.offset = curpos; 1.794 + /* note offset of message */ 1.795 + elt->private.msg.full.offset = 1.796 + (s = ((*t == '\015') ? (t + 2) : (t + 1))) - tmp; 1.797 + /* generate plausable IMAPish date string */ 1.798 + db[2] = db[6] = db[20] = '-'; db[11] = ' '; db[14] = db[17] = ':'; 1.799 + /* dd */ 1.800 + db[0] = t[ti - 2]; db[1] = t[ti - 1]; 1.801 + /* mmm */ 1.802 + db[3] = t[ti - 6]; db[4] = t[ti - 5]; db[5] = t[ti - 4]; 1.803 + /* hh */ 1.804 + db[12] = t[ti + 1]; db[13] = t[ti + 2]; 1.805 + /* mm */ 1.806 + db[15] = t[ti + 4]; db[16] = t[ti + 5]; 1.807 + if (t[ti += 6] == ':') { /* ss if present */ 1.808 + db[18] = t[++ti]; db[19] = t[++ti]; 1.809 + ti++; /* move to space */ 1.810 + } 1.811 + else db[18] = db[19] = '0'; /* assume 0 seconds */ 1.812 + /* yy -- advance over timezone if necessary */ 1.813 + if (++zn == ++ti) ti += (((t[zn] == '+') || (t[zn] == '-')) ? 6 : 4); 1.814 + db[7] = t[ti]; db[8] = t[ti + 1]; db[9] = t[ti + 2]; db[10] = t[ti + 3]; 1.815 + t = zn ? (t + zn) : "LCL"; /* zzz */ 1.816 + db[21] = *t++; db[22] = *t++; db[23] = *t++; 1.817 + if ((db[21] != '+') && (db[21] != '-')) db[24] = '\0'; 1.818 + else { /* numeric time zone */ 1.819 + db[20] = ' '; db[24] = *t++; db[25] = *t++; db[26] = '\0'; 1.820 + } 1.821 + /* set internal date */ 1.822 + if (!mail_parse_date (elt,db)) mm_log (datemsg,WARN); 1.823 + 1.824 + curpos += s - tmp; /* advance position after header */ 1.825 + t = strchr (s,'\012'); /* start of next line */ 1.826 + /* find start of next message */ 1.827 + while (!(bezerk_valid_line (s,NIL,NIL))) { 1.828 + if (t) { /* have next line? */ 1.829 + t++; /* advance to new line */ 1.830 + curpos += t - s; /* update position and size */ 1.831 + elt->rfc822_size += ((t - s) + ((t[-2] == '\015') ? 0 : 1)); 1.832 + s = t; /* move to next line */ 1.833 + t = strchr (s,'\012'); 1.834 + } 1.835 + else { /* try next buffer */ 1.836 + j = strlen (s); /* length of unread data in buffer */ 1.837 + if ((i = sbuf.st_size - curpos) && (i != j)) { 1.838 + /* get to that position in the file */ 1.839 + lseek (LOCAL->fd,curpos,SEEK_SET); 1.840 + /* read another buffer's worth */ 1.841 + read (LOCAL->fd,s = tmp,j = (int) min (i,(long) MAILTMPLEN)); 1.842 + tmp[j] = '\0'; /* tie off buffer */ 1.843 + if (!(t = strchr (s,'\012'))) fatal ("Line too long in mailbox"); 1.844 + } 1.845 + else { 1.846 + curpos += j; /* last bit of data */ 1.847 + elt->rfc822_size += j; 1.848 + break; 1.849 + } 1.850 + } 1.851 + } 1.852 + } 1.853 + /* update parsed file size */ 1.854 + LOCAL->filesize = sbuf.st_size; 1.855 + stream->silent = silent; /* can pass up events now */ 1.856 + mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ 1.857 + mail_recent (stream,recent); /* and of change in recent messages */ 1.858 + return T; /* return the winnage */ 1.859 +} 1.860 + 1.861 +/* Berkeley locate header for a message 1.862 + * Accepts: MAIL stream 1.863 + * message number 1.864 + * pointer to returned header size 1.865 + * Returns: position of header in file 1.866 + */ 1.867 + 1.868 +unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno, 1.869 + unsigned long *size) 1.870 +{ 1.871 + long siz; 1.872 + size_t i = 0; 1.873 + char c = '\0'; 1.874 + char *s; 1.875 + char tmp[MAILTMPLEN]; 1.876 + MESSAGECACHE *elt = mail_elt (stream,msgno); 1.877 + long pos = elt->private.special.offset + elt->private.msg.full.offset; 1.878 + /* is size known? */ 1.879 + if (!(*size = elt->private.msg.header.text.size)) { 1.880 + /* get to header position */ 1.881 + lseek (LOCAL->fd,pos,SEEK_SET); 1.882 + /* search message for CRLF CRLF */ 1.883 + for (siz = 1; siz <= elt->rfc822_size; siz++) { 1.884 + if (!i && /* buffer empty? */ 1.885 + (read (LOCAL->fd,s = tmp, 1.886 + i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0)) 1.887 + return pos; 1.888 + else i--; 1.889 + /* two newline sequence? */ 1.890 + if ((c == '\012') && (*s == '\012')) { 1.891 + /* yes, note for later */ 1.892 + elt->private.msg.header.text.size = (*size = siz); 1.893 + return pos; /* return to caller */ 1.894 + } 1.895 + else if ((c == '\012') && (*s == '\015')) { 1.896 + /* yes, note for later */ 1.897 + elt->private.msg.header.text.size = (*size = siz + 1); 1.898 + return pos; /* return to caller */ 1.899 + } 1.900 + else c = *s++; /* next character */ 1.901 + } 1.902 + } 1.903 + return pos; /* have position */ 1.904 +}