Back to index

courier  0.68.2
fetch.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2010 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 
00010 #include      <stdio.h>
00011 #include      <stdlib.h>
00012 #include      <string.h>
00013 #include      <ctype.h>
00014 #include      <errno.h>
00015 #if    HAVE_UNISTD_H
00016 #include      <unistd.h>
00017 #endif
00018 #include      <sys/types.h>
00019 #include      <sys/stat.h>
00020 
00021 #include      "imaptoken.h"
00022 #include      "imapwrite.h"
00023 #include      "imapscanclient.h"
00024 #include      "fetchinfo.h"
00025 #include      "rfc822/rfc822.h"
00026 #include      "rfc2045/rfc2045.h"
00027 #include      "maildir/config.h"
00028 #include      "maildir/maildirgetquota.h"
00029 #include      "maildir/maildirquota.h"
00030 #include      "maildir/maildiraclt.h"
00031 
00032 #if SMAP
00033 extern int smapflag;
00034 #endif
00035 
00036 static const char unavailable[]=
00037        "\
00038 From: System Administrator <root@localhost>\n\
00039 Subject: message unavailable\n\n\
00040 This message is no longer available on the server.\n";
00041 
00042 unsigned long header_count=0, body_count=0;      /* Total transferred */
00043 
00044 extern int current_mailbox_ro;
00045 extern char *current_mailbox_acl;
00046 extern struct imapscaninfo current_maildir_info;
00047 extern char *current_mailbox;
00048 extern char *rfc2045id(struct rfc2045 *);
00049 
00050 extern void snapshot_needed();
00051 
00052 extern void msgenvelope(void (*)(const char *, size_t),
00053                 FILE *, struct rfc2045 *);
00054 extern void msgbodystructure( void (*)(const char *, size_t), int,
00055         FILE *, struct rfc2045 *);
00056 
00057 extern int is_trash(const char *);
00058 extern void get_message_flags(struct imapscanmessageinfo *,
00059        char *, struct imapflags *);
00060 extern void append_flags(char *, struct imapflags *);
00061 
00062 static int fetchitem(FILE **, int *, struct fetchinfo *,
00063        struct imapscaninfo *,  unsigned long,
00064        struct rfc2045 **);
00065 
00066 static void bodystructure(FILE *, struct fetchinfo *,
00067        struct imapscaninfo *,  unsigned long,
00068        struct rfc2045 *);
00069 
00070 static void body(FILE *, struct fetchinfo *,
00071        struct imapscaninfo *,  unsigned long,
00072        struct rfc2045 *);
00073 
00074 static void fetchmsgbody(FILE *, struct fetchinfo *,
00075        struct imapscaninfo *,  unsigned long,
00076        struct rfc2045 *);
00077 
00078 static void dofetchmsgbody(FILE *, struct fetchinfo *,
00079        struct imapscaninfo *,  unsigned long,
00080        struct rfc2045 *);
00081 
00082 static void envelope(FILE *, struct fetchinfo *,
00083        struct imapscaninfo *,  unsigned long,
00084        struct rfc2045 *);
00085 
00086 void doflags(FILE *, struct fetchinfo *,
00087             struct imapscaninfo *, unsigned long, struct rfc2045 *);
00088 
00089 static void internaldate(FILE *, struct fetchinfo *,
00090        struct imapscaninfo *, unsigned long, struct rfc2045 *);
00091 
00092 static void uid(FILE *, struct fetchinfo *,
00093        struct imapscaninfo *, unsigned long, struct rfc2045 *);
00094 
00095 static void all(FILE *, struct fetchinfo *,
00096        struct imapscaninfo *, unsigned long, struct rfc2045 *);
00097 
00098 static void fast(FILE *, struct fetchinfo *,
00099        struct imapscaninfo *, unsigned long, struct rfc2045 *);
00100 
00101 static void full(FILE *, struct fetchinfo *,
00102        struct imapscaninfo *, unsigned long, struct rfc2045 *);
00103 
00104 static void rfc822size(FILE *, struct fetchinfo *,
00105        struct imapscaninfo *, unsigned long, struct rfc2045 *);
00106 
00107 #if 0
00108 static void do_envelope(FILE *, struct fetchinfo *,
00109        struct imapscanmessageinfo *, struct rfc2045 *);
00110 #endif
00111 
00112 static void dofetchheadersbuf(FILE *, struct fetchinfo *,
00113        struct imapscaninfo *, unsigned long,
00114        struct rfc2045 *,
00115        int (*)(struct fetchinfo *fi, const char *));
00116 static void dofetchheadersfile(FILE *, struct fetchinfo *,
00117        struct imapscaninfo *, unsigned long,
00118        struct rfc2045 *,
00119        int (*)(struct fetchinfo *fi, const char *));
00120 
00121 static void print_bodysection_partial(struct fetchinfo *,
00122               void (*)(const char *));
00123 static void print_bodysection_output(const char *);
00124 
00125 static int dofetchheaderfields(struct fetchinfo *, const char *);
00126 static int dofetchheadernotfields(struct fetchinfo *, const char *);
00127 static int dofetchheadermime(struct fetchinfo *, const char *);
00128 
00129 static void rfc822(FILE *, struct fetchinfo *,
00130        struct imapscaninfo *, unsigned long,
00131        struct rfc2045 *);
00132 
00133 static void rfc822header(FILE *, struct fetchinfo *,
00134        struct imapscaninfo *, unsigned long,
00135        struct rfc2045 *);
00136 
00137 static void rfc822text(FILE *, struct fetchinfo *,
00138        struct imapscaninfo *, unsigned long,
00139        struct rfc2045 *);
00140 
00141 struct rfc2045 *fetch_alloc_rfc2045(unsigned long, FILE *);
00142 FILE *open_cached_fp(unsigned long);
00143 
00144 void fetchflags(unsigned long);
00145 
00146 static void fetcherrorprt(const char *p)
00147 {
00148        fprintf(stderr, "%s", p);
00149 }
00150 
00151 static void fetcherror(const char *errmsg,
00152               struct fetchinfo *fi,
00153               struct imapscaninfo *info, unsigned long j)
00154 {
00155 struct imapscanmessageinfo *mi=info->msgs+j;
00156 
00157        fprintf(stderr, "IMAP FETCH ERROR: %s, uid=%u, filename=%s: %s",
00158               errmsg, (unsigned)getuid(), mi->filename, fi->name);
00159        if (fi->bodysection)
00160               print_bodysection_partial(fi, &fetcherrorprt);
00161        fprintf(stderr, "\n");
00162 }
00163 
00164 char *get_reflagged_filename(const char *fn, struct imapflags *newflags)
00165 {
00166        char *p=malloc(strlen(fn)+20);
00167        char *q;
00168 
00169        if (!p)       write_error_exit(0);
00170        strcpy(p, fn);
00171        if ((q=strrchr(p, MDIRSEP[0])) != 0)      *q=0;
00172        strcat(p, MDIRSEP "2,");
00173        append_flags(p, newflags);
00174        return p;
00175 }
00176 
00177 int reflag_filename(struct imapscanmessageinfo *mi, struct imapflags *flags,
00178        int fd)
00179 {
00180 char    *p, *q, *r;
00181 int    rc=0;
00182 struct imapflags old_flags;
00183 struct stat   stat_buf;
00184 
00185        get_message_flags(mi, 0, &old_flags);
00186 
00187        p=get_reflagged_filename(mi->filename, flags);
00188 
00189        q=malloc(strlen(current_mailbox)+strlen(mi->filename)+sizeof("/cur/"));
00190        r=malloc(strlen(current_mailbox)+strlen(p)+sizeof("/cur/"));
00191        if (!q || !r) write_error_exit(0);
00192        strcat(strcat(strcpy(q, current_mailbox), "/cur/"), mi->filename);
00193        strcat(strcat(strcpy(r, current_mailbox), "/cur/"), p);
00194        if (strcmp(q, r))
00195        {
00196               if (maildirquota_countfolder(current_mailbox)
00197                      && old_flags.deleted != flags->deleted
00198                      && fstat(fd, &stat_buf) == 0)
00199               {
00200                      struct maildirsize quotainfo;
00201                      int64_t       nbytes;
00202                      unsigned long unbytes;
00203                      int    nmsgs=1;
00204 
00205                      if (maildir_parsequota(mi->filename, &unbytes) == 0)
00206                             nbytes=unbytes;
00207                      else
00208                             nbytes=stat_buf.st_size;
00209                      if ( flags->deleted )
00210                      {
00211                             nbytes= -nbytes;
00212                             nmsgs= -nmsgs;
00213                      }
00214 
00215                      if ( maildir_quota_delundel_start(current_mailbox,
00216                                                    &quotainfo,
00217                                                    nbytes, nmsgs))
00218                             rc= -1;
00219                      else
00220                             maildir_quota_delundel_end(&quotainfo,
00221                                                     nbytes, nmsgs);
00222               }
00223 
00224               if (rc == 0)
00225                      rename(q, r);
00226 
00227 #if SMAP
00228               snapshot_needed();
00229 #endif
00230        }
00231        free(q);
00232        free(r);
00233        free(mi->filename);
00234        mi->filename=p;
00235 
00236 #if 0
00237        if (is_sharedsubdir(current_mailbox))
00238               maildir_shared_updateflags(current_mailbox, p);
00239 #endif
00240 
00241        return (rc);
00242 }
00243 
00244 int do_fetch(unsigned long n, int byuid, void *p)
00245 {
00246        struct fetchinfo *fi=(struct fetchinfo *)p;
00247        FILE   *fp;
00248        struct rfc2045 *rfc2045p;
00249        int    seen;
00250        int    open_err;
00251 
00252        fp=NULL;
00253        open_err=0;
00254 
00255        writes("* ");
00256        writen(n);
00257        writes(" FETCH (");
00258 
00259        if (byuid)
00260        {
00261        struct fetchinfo *fip;
00262 
00263               for (fip=fi; fip; fip=fip->next)
00264                      if (strcmp(fip->name, "UID") == 0)
00265                             break;
00266 
00267               if (fip == 0)
00268               {
00269                      writes("UID ");
00270                      writen(current_maildir_info.msgs[n-1].uid);
00271                      writes(" ");
00272               }
00273        }
00274        seen=0;
00275        rfc2045p=0;
00276        while (fi)
00277        {
00278               if (fetchitem(&fp, &open_err, fi, &current_maildir_info, n-1,
00279                      &rfc2045p))   seen=1;
00280               if ((fi=fi->next) != 0)     writes(" ");
00281        }
00282        writes(")\r\n");
00283 
00284        if (open_err)
00285        {
00286               writes("* NO Cannot open message ");
00287               writen(n);
00288               writes("\r\n");
00289               return (0);
00290        }
00291 
00292 
00293 #if SMAP
00294        if (!smapflag)
00295 #endif
00296               if (current_mailbox_acl &&
00297                   strchr(current_mailbox_acl, ACL_SEEN[0]) == NULL)
00298                      seen=0; /* No permissions */
00299 
00300        if (seen && !current_mailbox_ro)
00301        {
00302        struct imapflags     flags;
00303 
00304               get_message_flags(current_maildir_info.msgs+(n-1),
00305                             0, &flags);
00306               if (!flags.seen)
00307               {
00308                      flags.seen=1;
00309                      reflag_filename(&current_maildir_info.msgs[n-1],&flags,
00310                             fileno(fp));
00311                      current_maildir_info.msgs[n-1].changedflags=1;
00312               }
00313        }
00314 
00315        if (current_maildir_info.msgs[n-1].changedflags)
00316               fetchflags(n-1);
00317        return (0);
00318 }
00319 
00320 static int fetchitem(FILE **fp, int *open_err, struct fetchinfo *fi,
00321        struct imapscaninfo *i, unsigned long msgnum,
00322        struct rfc2045 **mimep)
00323 {
00324        void (*fetchfunc)(FILE *, struct fetchinfo *,
00325                        struct imapscaninfo *, unsigned long,
00326                        struct rfc2045 *);
00327        int    parsemime=0;
00328        int    rc=0;
00329        int    do_open=1;
00330 
00331        if (strcmp(fi->name, "ALL") == 0)
00332        {
00333               parsemime=1;
00334               fetchfunc= &all;
00335        }
00336        else if (strcmp(fi->name, "BODYSTRUCTURE") == 0)
00337        {
00338               parsemime=1;
00339               fetchfunc= &bodystructure;
00340        }
00341        else if (strcmp(fi->name, "BODY") == 0)
00342        {
00343               parsemime=1;
00344               fetchfunc= &body;
00345               if (fi->bodysection)
00346               {
00347                      fetchfunc= &fetchmsgbody;
00348                      rc=1;
00349               }
00350        }
00351        else if (strcmp(fi->name, "BODY.PEEK") == 0)
00352        {
00353               parsemime=1;
00354               fetchfunc= &body;
00355               if (fi->bodysection)
00356                      fetchfunc= &fetchmsgbody;
00357        }
00358        else if (strcmp(fi->name, "ENVELOPE") == 0)
00359        {
00360               parsemime=1;
00361               fetchfunc= &envelope;
00362        }
00363        else if (strcmp(fi->name, "FAST") == 0)
00364        {
00365               parsemime=1;
00366               fetchfunc= &fast;
00367        }
00368        else if (strcmp(fi->name, "FULL") == 0)
00369        {
00370               parsemime=1;
00371               fetchfunc= &full;
00372        }
00373        else if (strcmp(fi->name, "FLAGS") == 0)
00374        {
00375               fetchfunc= &doflags;
00376               do_open=0;
00377        }
00378        else if (strcmp(fi->name, "INTERNALDATE") == 0)
00379        {
00380               fetchfunc= &internaldate;
00381        }
00382        else if (strcmp(fi->name, "RFC822") == 0)
00383        {
00384               fetchfunc= &rfc822;
00385               rc=1;
00386        }
00387        else if (strcmp(fi->name, "RFC822.HEADER") == 0)
00388        {
00389               fetchfunc= &rfc822header;
00390        }
00391        else if (strcmp(fi->name, "RFC822.SIZE") == 0)
00392        {
00393               parsemime=1;
00394               fetchfunc= &rfc822size;
00395        }
00396        else if (strcmp(fi->name, "RFC822.TEXT") == 0)
00397        {
00398               parsemime=1;
00399               fetchfunc= &rfc822text;
00400        }
00401        else if (strcmp(fi->name, "UID") == 0)
00402        {
00403               fetchfunc= &uid;
00404               do_open=0;
00405        }
00406        else   return (0);
00407 
00408        if (do_open && *fp == NULL)
00409        {
00410               *fp=open_cached_fp(msgnum);
00411               if (!*fp)
00412               {
00413                      *open_err=1;
00414                      return rc;
00415               }
00416        }
00417 
00418        if (parsemime && !*mimep)
00419        {
00420               *mimep=fetch_alloc_rfc2045(msgnum, *fp);
00421        }
00422 
00423        (*fetchfunc)(*fp, fi, i, msgnum, *mimep);
00424        return (rc);
00425 }
00426 
00427 static void bodystructure(FILE *fp, struct fetchinfo *fi,
00428        struct imapscaninfo *i, unsigned long msgnum,
00429        struct rfc2045 *mimep)
00430 {
00431        writes("BODYSTRUCTURE ");
00432        msgbodystructure(writemem, 1, fp, mimep);
00433 }
00434 
00435 static void body(FILE *fp, struct fetchinfo *fi,
00436        struct imapscaninfo *i, unsigned long msgnum,
00437        struct rfc2045 *mimep)
00438 {
00439        writes("BODY ");
00440        msgbodystructure(writemem, 0, fp, mimep);
00441 }
00442 
00443 static void envelope(FILE *fp, struct fetchinfo *fi,
00444        struct imapscaninfo *i, unsigned long msgnum,
00445        struct rfc2045 *mimep)
00446 {
00447        writes("ENVELOPE ");
00448        msgenvelope( &writemem, fp, mimep);
00449 }
00450 
00451 void fetchflags(unsigned long n)
00452 {
00453 #if SMAP
00454        if (smapflag)
00455        {
00456               writes("* FETCH ");
00457               writen(n+1);
00458        }
00459        else
00460 #endif
00461        {
00462               writes("* ");
00463               writen(n+1);
00464               writes(" FETCH (");
00465        }
00466 
00467        doflags(0, 0, &current_maildir_info, n, 0);
00468 
00469 #if SMAP
00470        if (smapflag)
00471        {
00472               writes("\n");
00473        }
00474        else
00475 #endif
00476               writes(")\r\n");
00477 }
00478 
00479 void fetchflags_byuid(unsigned long n)
00480 {
00481        writes("* ");
00482        writen(n+1);
00483        writes(" FETCH (");
00484        uid(0, 0, &current_maildir_info, n, 0);
00485        writes(" ");
00486        doflags(0, 0, &current_maildir_info, n, 0);
00487        writes(")\r\n");
00488 }
00489 
00490 void doflags(FILE *fp, struct fetchinfo *fi,
00491             struct imapscaninfo *i, unsigned long msgnum,
00492             struct rfc2045 *mimep)
00493 {
00494        struct libmail_kwMessageEntry *kme;
00495 
00496        char   buf[256];
00497 
00498 #if SMAP
00499        if (smapflag)
00500        {
00501               writes(" FLAGS=");
00502               get_message_flags(i->msgs+msgnum, buf, 0);
00503               writes(buf);
00504        }
00505        else
00506 #endif
00507        {
00508               struct libmail_kwMessage *km;
00509 
00510               writes("FLAGS ");
00511 
00512               get_message_flags(i->msgs+msgnum, buf, 0);
00513 
00514               writes("(");
00515               writes(buf);
00516 
00517               if (buf[0])
00518                      strcpy(buf, " ");
00519 
00520               if ((km=i->msgs[msgnum].keywordMsg) != NULL)
00521                      for (kme=km->firstEntry; kme; kme=kme->next)
00522                      {
00523                             writes(buf);
00524                             strcpy(buf, " ");
00525                             writes(keywordName(kme->libmail_keywordEntryPtr));
00526                      }
00527               writes(")");
00528        }
00529 
00530        i->msgs[msgnum].changedflags=0;
00531 }
00532 
00533 static void internaldate(FILE *fp, struct fetchinfo *fi,
00534        struct imapscaninfo *i, unsigned long msgnum,
00535        struct rfc2045 *mimep)
00536 {
00537 struct stat   stat_buf;
00538 char   buf[256];
00539 char   *p, *q;
00540 
00541        writes("INTERNALDATE ");
00542        if (fstat(fileno(fp), &stat_buf) == 0)
00543        {
00544               rfc822_mkdate_buf(stat_buf.st_mtime, buf);
00545 
00546               /* Convert RFC822 date to imap date */
00547 
00548               p=strchr(buf, ',');
00549               if (p) ++p;
00550               else   p=buf;
00551               while (*p == ' ')    ++p;
00552               if ((q=strchr(p, ' ')) != 0)       *q++='-';
00553               if ((q=strchr(p, ' ')) != 0)       *q++='-';
00554               writes("\"");
00555               writes(p);
00556               writes("\"");
00557        }
00558        else
00559               writes("NIL");
00560 }
00561 
00562 static void uid(FILE *fp, struct fetchinfo *fi,
00563        struct imapscaninfo *i, unsigned long msgnum,
00564        struct rfc2045 *mimep)
00565 {
00566        writes("UID ");
00567        writen(i->msgs[msgnum].uid);
00568 }
00569 
00570 static void rfc822size(FILE *fp, struct fetchinfo *fi,
00571        struct imapscaninfo *i, unsigned long msgnum,
00572        struct rfc2045 *mimep)
00573 {
00574 off_t start_pos, end_pos, start_body;
00575 off_t nlines, nbodylines;
00576 
00577        writes("RFC822.SIZE ");
00578 
00579        rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body,
00580               &nlines, &nbodylines);
00581 
00582        writen(end_pos - start_pos + nlines);
00583 }
00584 
00585 static void all(FILE *fp, struct fetchinfo *fi,
00586        struct imapscaninfo *i, unsigned long msgnum,
00587        struct rfc2045 *mimep)
00588 {
00589        doflags(fp, fi, i, msgnum, mimep);
00590        writes(" ");
00591        internaldate(fp, fi, i, msgnum, mimep);
00592        writes(" ");
00593        rfc822size(fp, fi, i, msgnum, mimep);
00594        writes(" ");
00595        envelope(fp, fi, i, msgnum, mimep);
00596 }
00597 
00598 static void fast(FILE *fp, struct fetchinfo *fi,
00599        struct imapscaninfo *i, unsigned long msgnum,
00600        struct rfc2045 *mimep)
00601 {
00602        doflags(fp, fi, i, msgnum, mimep);
00603        writes(" ");
00604        internaldate(fp, fi, i, msgnum, mimep);
00605        writes(" ");
00606        rfc822size(fp, fi, i, msgnum, mimep);
00607 }
00608 
00609 static void full(FILE *fp, struct fetchinfo *fi,
00610        struct imapscaninfo *i, unsigned long msgnum,
00611        struct rfc2045 *mimep)
00612 {
00613        doflags(fp, fi, i, msgnum, mimep);
00614        writes(" ");
00615        internaldate(fp, fi, i, msgnum, mimep);
00616        writes(" ");
00617        rfc822size(fp, fi, i, msgnum, mimep);
00618        writes(" ");
00619        envelope(fp, fi, i, msgnum, mimep);
00620        writes(" ");
00621        body(fp, fi, i, msgnum, mimep);
00622 }
00623 
00624 static void fetchmsgbody(FILE *fp, struct fetchinfo *fi,
00625        struct imapscaninfo *i, unsigned long msgnum,
00626        struct rfc2045 *mimep)
00627 {
00628        writes("BODY");
00629        print_bodysection_partial(fi, &print_bodysection_output);
00630        writes(" ");
00631        dofetchmsgbody(fp, fi, i, msgnum, mimep);
00632 }
00633 
00634 static void print_bodysection_output(const char *p)
00635 {
00636        writes(p);
00637 }
00638 
00639 static void print_bodysection_partial(struct fetchinfo *fi,
00640        void (*func)(const char *))
00641 {
00642        (*func)("[");
00643        if (fi->bodysection)
00644        {
00645        struct fetchinfo *subl;
00646 
00647               (*func)(fi->bodysection);
00648               if (fi->bodysublist)
00649               {
00650               char   *p=" (";
00651 
00652                      for (subl=fi->bodysublist; subl; subl=subl->next)
00653                      {
00654                             (*func)(p);
00655                             p=" ";
00656                             (*func)("\"");
00657                             (*func)(subl->name);
00658                             (*func)("\"");
00659                      }
00660                      (*func)(")");
00661               }
00662        }
00663        (*func)("]");
00664        if (fi->ispartial)
00665        {
00666        char   buf[80];
00667 
00668               sprintf(buf, "<%lu>", (unsigned long)fi->partialstart);
00669               (*func)(buf);
00670        }
00671 }
00672 
00673 static void dofetchmsgbody(FILE *fp, struct fetchinfo *fi,
00674        struct imapscaninfo *i, unsigned long msgnum,
00675        struct rfc2045 *mimep)
00676 {
00677 const char *p=fi->bodysection;
00678 off_t start_pos, end_pos, start_body;
00679 off_t nlines, nbodylines;
00680 unsigned long cnt;
00681 char   buf[BUFSIZ];
00682 char   rbuf[BUFSIZ];
00683 char   *rbufptr;
00684 int    rbufleft;
00685 unsigned long bufptr;
00686 unsigned long skipping;
00687 int    ismsgrfc822=1;
00688 
00689 off_t start_seek_pos;
00690  struct rfc2045 *headermimep;
00691 
00692 /*
00693 ** To optimize consecutive FETCHes, we cache our virtual and physical
00694 ** position.  What we do is that on the first fetch we count off the
00695 ** characters we read, and keep track of both the physical and the CRLF-based
00696 ** offset into the message.  Then, on subsequent FETCHes, we attempt to
00697 ** use that information.
00698 */
00699 
00700 off_t cnt_virtual_chars;
00701 off_t cnt_phys_chars;
00702 
00703 off_t cache_virtual_chars;
00704 off_t cache_phys_chars;
00705 
00706        headermimep=mimep;
00707  
00708        while (p && isdigit((int)(unsigned char)*p))
00709        {
00710        unsigned long n=0;
00711 
00712               headermimep=mimep;
00713 
00714               do
00715               {
00716                      n=n*10 + (*p++ - '0');
00717               } while (isdigit((int)(unsigned char)*p));
00718 
00719               if (mimep)
00720               {
00721                      if (ismsgrfc822)
00722                      {
00723                             const char *ct, *dummy;
00724 
00725                             if (mimep->firstpart == 0)
00726                             {
00727                                    /* Not a multipart, n must be 1 */
00728                                    if (n != 1)
00729                                           mimep=0;
00730                                    if (*p == '.')
00731                                           ++p;
00732                                    continue;
00733                             }
00734                             ismsgrfc822=0;
00735 
00736                             rfc2045_mimeinfo(mimep, &ct,
00737                                            &dummy,
00738                                            &dummy);
00739 
00740                             if (ct && strcasecmp(ct, "message/rfc822"
00741                                                ) == 0)
00742                                    ismsgrfc822=1;
00743                             /* The content is another message/rfc822 */
00744                      }
00745 
00746                      mimep=mimep->firstpart;
00747                      while (mimep)
00748                      {
00749                             if (!mimep->isdummy && --n == 0)
00750                                    break;
00751                             mimep=mimep->next;
00752                      }
00753                      headermimep=mimep;
00754 
00755                      if (mimep && mimep->firstpart &&
00756                             !mimep->firstpart->isdummy)
00757                             /* This is a message/rfc822 part */
00758                      {
00759                             if (!*p)
00760                                    break;
00761 
00762                             mimep=mimep->firstpart;
00763                             ismsgrfc822=1;
00764                      }
00765               }
00766               if (*p == '.')
00767                      ++p;
00768        }
00769 
00770        if (p && strcmp(p, "MIME") == 0)
00771               mimep=headermimep;
00772 
00773        if (mimep == 0)
00774        {
00775               writes("{0}\r\n");
00776               return;
00777        }
00778 
00779        rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body,
00780               &nlines, &nbodylines);
00781 
00782 
00783        if (p && strcmp(p, "TEXT") == 0)
00784        {
00785               start_seek_pos=start_body;
00786               cnt=end_pos - start_body + nbodylines;
00787        }
00788        else if (p && strcmp(p, "HEADER") == 0)
00789        {
00790               start_seek_pos=start_pos;
00791               cnt= start_body - start_pos + (nlines - nbodylines);
00792        }
00793        else if (p && strcmp(p, "HEADER.FIELDS") == 0)
00794        {
00795               if (start_body - start_pos <= BUFSIZ)
00796                      dofetchheadersbuf(fp, fi, i, msgnum, mimep,
00797                             &dofetchheaderfields);
00798               else
00799                      dofetchheadersfile(fp, fi, i, msgnum, mimep,
00800                             &dofetchheaderfields);
00801               return;
00802        }
00803        else if (p && strcmp(p, "HEADER.FIELDS.NOT") == 0)
00804        {
00805               if (start_body - start_pos <= BUFSIZ)
00806                      dofetchheadersbuf(fp, fi, i, msgnum, mimep,
00807                             &dofetchheadernotfields);
00808               else
00809                      dofetchheadersfile(fp, fi, i, msgnum, mimep,
00810                             &dofetchheadernotfields);
00811               return;
00812        }
00813        else if (p && strcmp(p, "MIME") == 0)
00814        {
00815               if (start_body - start_pos <= BUFSIZ)
00816                      dofetchheadersbuf(fp, fi, i, msgnum, mimep,
00817                             &dofetchheadermime);
00818               else
00819                      dofetchheadersfile(fp, fi, i, msgnum, mimep,
00820                             &dofetchheadermime);
00821               return;
00822        }
00823        else if (*fi->bodysection == 0)
00824        {
00825               start_seek_pos=start_pos;
00826 
00827               cnt= end_pos - start_pos + nlines;
00828        }
00829        else   /* Last possibility: entire body */
00830        {
00831               start_seek_pos=start_body;
00832 
00833               cnt= end_pos - start_body + nbodylines;
00834        }
00835 
00836        skipping=0;
00837        if (fi->ispartial)
00838        {
00839               skipping=fi->partialstart;
00840               if (skipping > cnt)  skipping=cnt;
00841               cnt -= skipping;
00842               if (fi->ispartial > 1 && cnt > fi->partialend)
00843                      cnt=fi->partialend;
00844        }
00845 
00846        if (get_cached_offsets(start_seek_pos, &cnt_virtual_chars,
00847                             &cnt_phys_chars) == 0 &&
00848            cnt_virtual_chars <= skipping) /* Yeah - cache it, baby! */
00849        {
00850               if (fseek(fp, start_seek_pos+cnt_phys_chars, SEEK_SET) == -1)
00851               {
00852                      writes("{0}\r\n");
00853                      fetcherror("fseek", fi, i, msgnum);
00854                      return;
00855               }
00856               skipping -= cnt_virtual_chars;
00857        }
00858        else
00859        {
00860               if (fseek(fp, start_seek_pos, SEEK_SET) == -1)
00861               {
00862                      writes("{0}\r\n");
00863                      fetcherror("fseek", fi, i, msgnum);
00864                      return;
00865               }
00866 
00867               cnt_virtual_chars=0;
00868               cnt_phys_chars=0;
00869        }
00870 
00871        cache_virtual_chars=cnt_virtual_chars;
00872        cache_phys_chars=cnt_phys_chars;
00873 
00874        writes("{");
00875        writen(cnt);
00876        writes("}\r\n");
00877        bufptr=0;
00878        writeflush();
00879 
00880        rbufptr=0;
00881        rbufleft=0;
00882 
00883        while (cnt)
00884        {
00885        int    c;
00886 
00887               if (!rbufleft)
00888               {
00889                      rbufleft=fread(rbuf, 1, sizeof(rbuf), fp);
00890                      if (rbufleft < 0)    rbufleft=0;
00891                      rbufptr=rbuf;
00892               }
00893 
00894               if (!rbufleft)
00895               {
00896                      fetcherror("unexpected EOF", fi, i, msgnum);
00897                      _exit(1);
00898               }
00899 
00900               --rbufleft;
00901               c=(int)(unsigned char)*rbufptr++;
00902               ++cnt_phys_chars;
00903 
00904               if (c == '\n')
00905               {
00906                      ++cnt_virtual_chars;
00907 
00908                      if (skipping)
00909                             --skipping;
00910                      else
00911                      {
00912                             if (bufptr >= sizeof(buf))
00913                             {
00914                                    writemem(buf, sizeof(buf));
00915                                    bufptr=0;
00916                                    /*writeflush();*/
00917                             }
00918                             buf[bufptr++]='\r';
00919                             --cnt;
00920 
00921                             if (cnt == 0)
00922                                    break;
00923                      }
00924               }
00925 
00926               ++cnt_virtual_chars;
00927               if (skipping)
00928                      --skipping;
00929               else
00930               {
00931                      ++body_count;
00932 
00933                      if (bufptr >= sizeof(buf))
00934                      {
00935                             writemem(buf, sizeof(buf));
00936                             bufptr=0;
00937                             /*writeflush();*/
00938                      }
00939                      buf[bufptr++]=c;
00940                      --cnt;
00941               }
00942               cache_virtual_chars=cnt_virtual_chars;
00943               cache_phys_chars=cnt_phys_chars;
00944        }
00945        writemem(buf, bufptr);
00946        writeflush();
00947        save_cached_offsets(start_seek_pos, cache_virtual_chars,
00948                          cache_phys_chars);
00949 }
00950 
00951 static int dofetchheaderfields(struct fetchinfo *fi, const char *name)
00952 {
00953        for (fi=fi->bodysublist; fi; fi=fi->next)
00954        {
00955        int    i, a, b;
00956 
00957               if (fi->name == 0)   continue;
00958               for (i=0; fi->name[i] && name[i]; i++)
00959               {
00960                      a=(unsigned char)name[i];
00961                      a=toupper(a);
00962                      b=fi->name[i];
00963                      b=toupper(b);
00964                      if (a != b)   break;
00965               }
00966               if (fi->name[i] == 0 && name[i] == 0)     return (1);
00967        }
00968 
00969        return (0);
00970 }
00971 
00972 static int dofetchheadernotfields(struct fetchinfo *fi, const char *name)
00973 {
00974        return (!dofetchheaderfields(fi, name));
00975 }
00976 
00977 static int dofetchheadermime(struct fetchinfo *fi, const char *name)
00978 {
00979 int    i, a;
00980 static const char mv[]="MIME-VERSION";
00981 
00982        for (i=0; i<sizeof(mv)-1; i++)
00983        {
00984               a= (unsigned char)name[i];
00985               a=toupper(a);
00986               if (a != mv[i])      break;
00987        }
00988        if (mv[i] == 0 && name[i] == 0)    return (1);
00989 
00990        for (i=0; i<8; i++)
00991        {
00992               a= (unsigned char)name[i];
00993               a=toupper(a);
00994               if (a != "CONTENT-"[i])     return (0);
00995        }
00996        return (1);
00997 }
00998 
00999 static void dofetchheadersbuf(FILE *fp, struct fetchinfo *fi,
01000        struct imapscaninfo *info, unsigned long msgnum,
01001        struct rfc2045 *mimep,
01002        int (*headerfunc)(struct fetchinfo *fi, const char *))
01003 {
01004 off_t start_pos, end_pos, start_body;
01005 off_t nlines, nbodylines;
01006 size_t i,j,k,l;
01007 char   buf[BUFSIZ+2];
01008 int    goodheader;
01009 unsigned long skipping;
01010 unsigned long cnt;
01011 char   *p;
01012 int    ii;
01013 
01014        rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body,
01015               &nlines, &nbodylines);
01016        if (fseek(fp, start_pos, SEEK_SET) == -1)
01017        {
01018               writes("{0}\r\n");
01019               fetcherror("fseek", fi, info, msgnum);
01020               return;
01021        }
01022 
01023        ii=fread(buf, 1, start_body - start_pos, fp);
01024        if (ii < 0 || (i=ii) != start_body - start_pos)
01025        {
01026               fetcherror("unexpected EOF", fi, info, msgnum);
01027               exit(1);
01028        }
01029        goodheader= (*headerfunc)(fi, "");
01030 
01031        l=0;
01032        for (j=0; j<i; )
01033        {
01034               if (buf[j] != '\n' && buf[j] != '\r' &&
01035                      !isspace((int)(unsigned char)buf[j]))
01036               {
01037                      goodheader= (*headerfunc)(fi, "");
01038 
01039                      for (k=j; k<i; k++)
01040                      {
01041                             if (buf[k] == '\n' || buf[k] == ':')
01042                                    break;
01043                      }
01044 
01045                      if (k < i && buf[k] == ':')
01046                      {
01047                             buf[k]=0;
01048                             goodheader=(*headerfunc)(fi, buf+j);
01049                             buf[k]=':';
01050                      }
01051               }
01052               else if (buf[j] == '\n')
01053                      goodheader=0;
01054 
01055               for (k=j; k<i; k++)
01056                      if (buf[k] == '\n')
01057                      {
01058                             ++k;
01059                             break;
01060                      }
01061 
01062               if (goodheader)
01063               {
01064                      while (j<k)
01065                             buf[l++]=buf[j++];
01066               }
01067               j=k;
01068        }
01069 
01070        buf[l++]='\n';       /* Always append a blank line */
01071 
01072        cnt=l;
01073        for (i=0; i<l; i++)
01074               if (buf[i] == '\n')  ++cnt;
01075 
01076        skipping=0;
01077        if (fi->ispartial)
01078        {
01079               skipping=fi->partialstart;
01080               if (skipping > cnt)  skipping=cnt;
01081               cnt -= skipping;
01082               if (fi->ispartial > 1 && cnt > fi->partialend)
01083                      cnt=fi->partialend;
01084        }
01085 
01086        writes("{");
01087        writen(cnt);
01088        writes("}\r\n");
01089        p=buf;
01090        while (skipping)
01091        {
01092               if (*p == '\n')
01093               {
01094                      --skipping;
01095                      if (skipping == 0)
01096                      {
01097                             if (cnt)
01098                             {
01099                                    writes("\n");
01100                                    --cnt;
01101                             }
01102                             break;
01103                      }
01104               }
01105               --skipping;
01106               ++p;
01107        }
01108 
01109        while (cnt)
01110        {
01111               if (*p == '\n')
01112               {
01113                      writes("\r");
01114                      if (--cnt == 0)      break;
01115                      writes("\n");
01116                      --cnt;
01117                      ++p;
01118                      continue;
01119               }
01120               for (i=0; i<cnt; i++)
01121                      if (p[i] == '\n')
01122                             break;
01123               writemem(p, i);
01124               p += i;
01125               cnt -= i;
01126               header_count += i;
01127        }
01128 }
01129 
01130 struct fetchheaderinfo {
01131        unsigned long skipping;
01132        unsigned long cnt;
01133        } ;
01134 
01135 static void countheader(struct fetchheaderinfo *, const char *, size_t);
01136 
01137 static void printheader(struct fetchheaderinfo *, const char *, size_t);
01138 
01139 static void dofetchheadersfile(FILE *fp, struct fetchinfo *fi,
01140        struct imapscaninfo *info, unsigned long msgnum,
01141        struct rfc2045 *mimep,
01142        int (*headerfunc)(struct fetchinfo *fi, const char *))
01143 {
01144 off_t start_pos, end_pos, start_body, left;
01145 off_t nlines, nbodylines;
01146 size_t i;
01147 int    c, pass;
01148 char   buf1[256];
01149 int    goodheader;
01150 struct fetchheaderinfo finfo;
01151 
01152        finfo.cnt=0;
01153        for (pass=0; pass<2; pass++)
01154        {
01155        void (*func)(struct fetchheaderinfo *, const char *, size_t)=
01156                      pass ? printheader:countheader;
01157 
01158               rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body,
01159                      &nlines, &nbodylines);
01160               if (fseek(fp, start_pos, SEEK_SET) == -1)
01161               {
01162                      writes("{0}\r\n");
01163                      fetcherror("fseek", fi, info, msgnum);
01164                      return;
01165               }
01166               if (pass)
01167               {
01168                      finfo.skipping=0;
01169                      if (fi->ispartial)
01170                      {
01171                             finfo.skipping=fi->partialstart;
01172                             if (finfo.skipping > finfo.cnt)
01173                                    finfo.skipping=finfo.cnt;
01174                             finfo.cnt -= finfo.skipping;
01175                             if (fi->ispartial > 1 &&
01176                                    finfo.cnt > fi->partialend)
01177                                    finfo.cnt=fi->partialend;
01178                      }
01179 
01180                      writes("{");
01181                      writen(finfo.cnt+2); /* BUG */
01182                      writes("}\r\n");
01183               }
01184               left=start_body - start_pos;
01185 
01186               goodheader= (*headerfunc)(fi, "");
01187               while (left)
01188               {
01189                      for (i=0; i<sizeof(buf1)-1 && i<left; i++)
01190                      {
01191                             c=getc(fp);
01192                             if (c == EOF)
01193                             {
01194                                    fetcherror("unexpected EOF", fi, info, msgnum);
01195                                    _exit(1);
01196                             }
01197 
01198                             if (c == '\n' || c == ':')
01199                             {
01200                                    ungetc(c, fp);
01201                                    break;
01202                             }
01203                             buf1[i]=c;
01204                      }
01205                      buf1[i]=0;
01206                      left -= i;
01207 
01208                      if (buf1[0] != '\n' && buf1[0] != '\r' &&
01209                             !isspace((int)(unsigned char)buf1[0]))
01210                             goodheader= (*headerfunc)(fi, buf1);
01211                      else if (buf1[0] == '\n')
01212                             goodheader=0;
01213 
01214                      if (!goodheader)
01215                      {
01216                             while (left)
01217                             {
01218                                    c=getc(fp);
01219                                    --left;
01220                                    if (c == EOF)
01221                                    {
01222                                           fetcherror("unexpected EOF", fi, info, msgnum);
01223                                           _exit(1);
01224                                    }
01225                                    if (c == '\n')       break;
01226                             }
01227                             continue;
01228                      }
01229 
01230                      (*func)(&finfo, buf1, i);
01231 
01232                      i=0;
01233                      while (left)
01234                      {
01235                             c=getc(fp);
01236                             if (c == EOF)
01237                             {
01238                                    fetcherror("unexpected EOF", fi, info, msgnum);
01239                                    _exit(1);
01240                             }
01241                             --left;
01242                             if (i >= sizeof(buf1))
01243                             {
01244                                    (*func)(&finfo, buf1, i);
01245                                    i=0;
01246                             }
01247                             if (c == '\n')
01248                             {
01249                                    (*func)(&finfo, buf1, i);
01250                                    buf1[0]='\r';
01251                                    i=1;
01252                             }
01253                             buf1[i++]=c;
01254                             if (c == '\n')       break;
01255                      }
01256                      (*func)(&finfo, buf1, i);
01257                      if (pass && finfo.cnt == 0) break;
01258               }
01259        }
01260        writes("\r\n");      /* BUG */
01261 }
01262 
01263 static void countheader(struct fetchheaderinfo *fi, const char *p, size_t s)
01264 {
01265        fi->cnt += s;
01266 }
01267 
01268 static void printheader(struct fetchheaderinfo *fi, const char *p, size_t s)
01269 {
01270        size_t i;
01271 
01272        if (fi->skipping)
01273        {
01274               if (fi->skipping > s)
01275               {
01276                      fi->skipping -= s;
01277                      return;
01278               }
01279               p += fi->skipping;
01280               s -= fi->skipping;
01281               fi->skipping=0;
01282        }
01283        if (s > fi->cnt)     s=fi->cnt;
01284        for (i=0; i <= s; i++)
01285               if (p[i] != '\r')
01286                      ++header_count;
01287        writemem(p, s);
01288        fi->cnt -= s;
01289 }
01290 
01291 static void rfc822(FILE *fp, struct fetchinfo *fi,
01292        struct imapscaninfo *info, unsigned long msgnum,
01293        struct rfc2045 *rfcp)
01294 {
01295 unsigned long n=0;
01296 int    c;
01297 char   buf[BUFSIZ];
01298 unsigned long i;
01299 
01300        writes("RFC822 ");
01301 
01302        if (fseek(fp, 0L, SEEK_SET) == -1)
01303        {
01304               fetcherror("fseek", fi, info, msgnum);
01305               writes("{0}\r\n");
01306               return;
01307        }
01308        while ((c=getc(fp)) != EOF)
01309        {
01310               ++n;
01311               if (c == '\n')       ++n;
01312        }
01313 
01314        if (fseek(fp, 0L, SEEK_SET) == -1)
01315        {
01316               fetcherror("fseek", fi, info, msgnum);
01317               writes("{0}\r\n");
01318               return;
01319        }
01320        writes("{");
01321        writen(n);
01322        writes("}\r\n");
01323 
01324        i=0;
01325        while (n)
01326        {
01327               c=getc(fp);
01328               if (c == '\n')
01329               {
01330                      if (i >= sizeof(buf))
01331                      {
01332                             writemem(buf, i);
01333                             i=0;
01334                      }
01335                      buf[i++]='\r';
01336                      if (--n == 0) break;
01337               }
01338 
01339               if (i >= sizeof(buf))
01340               {
01341                      writemem(buf, i);
01342                      i=0;
01343               }
01344               buf[i++]=c;
01345               --n;
01346               ++body_count;
01347        }
01348        writemem(buf, i);
01349 }
01350 
01351 static void rfc822header(FILE *fp, struct fetchinfo *fi,
01352        struct imapscaninfo *info, unsigned long msgnum,
01353        struct rfc2045 *rfcp)
01354 {
01355 unsigned long n=0;
01356 int    c;
01357 char   buf[BUFSIZ];
01358 unsigned long i;
01359 int    eol;
01360 
01361        writes("RFC822.HEADER ");
01362 
01363        if (fseek(fp, 0L, SEEK_SET) == -1)
01364        {
01365               fetcherror("fseek", fi, info, msgnum);
01366               writes("{0}\r\n");
01367               return;
01368        }
01369 
01370        eol=0;
01371        while ((c=getc(fp)) != EOF)
01372        {
01373               ++n;
01374               if (c != '\n')
01375               {
01376                      eol=0;
01377                      continue;
01378               }
01379               ++n;
01380               if (eol)      break;
01381               eol=1;
01382        }
01383 
01384        if (fseek(fp, 0L, SEEK_SET) == -1)
01385        {
01386               fetcherror("fseek", fi, info, msgnum);
01387               writes("{0}\r\n");
01388               return;
01389        }
01390        writes("{");
01391        writen(n);
01392        writes("}\r\n");
01393 
01394        i=0;
01395        while (n)
01396        {
01397               c=getc(fp);
01398               if (c == '\n')
01399               {
01400                      if (i >= sizeof(buf))
01401                      {
01402                             writemem(buf, i);
01403                             i=0;
01404                      }
01405                      buf[i++]='\r';
01406                      if (--n == 0) break;
01407               }
01408 
01409               if (i >= sizeof(buf))
01410               {
01411                      writemem(buf, i);
01412                      i=0;
01413               }
01414               buf[i++]=c;
01415               --n;
01416               ++header_count;
01417        }
01418        writemem(buf, i);
01419 }
01420 
01421 static void rfc822text(FILE *fp, struct fetchinfo *fi,
01422        struct imapscaninfo *info, unsigned long msgnum,
01423        struct rfc2045 *rfcp)
01424 {
01425 off_t start_pos, end_pos, start_body;
01426 off_t nlines, nbodylines;
01427 unsigned long i;
01428 int    c;
01429 char   buf[BUFSIZ];
01430 unsigned long l;
01431 
01432        writes("RFC822.TEXT {");
01433 
01434        rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body,
01435               &nlines, &nbodylines);
01436 
01437        if (fseek(fp, start_body, SEEK_SET) == -1)
01438        {
01439               fetcherror("fseek", fi, info, msgnum);
01440               writes("0}\r\n");
01441               return;
01442        }
01443 
01444        i=end_pos - start_body + nbodylines;
01445 
01446        writen(i);
01447        writes("}\r\n");
01448 
01449        l=0;
01450        while (i)
01451        {
01452               c=getc(fp);
01453               if (c == EOF)
01454               {
01455                      fetcherror("unexpected EOF", fi, info, msgnum);
01456                      _exit(1);
01457               }
01458               --i;
01459               if (l >= sizeof(BUFSIZ))
01460               {
01461                      writemem(buf, l);
01462                      l=0;
01463               }
01464               if (c == '\n' && i)
01465               {
01466                      --i;
01467                      buf[l++]='\r';
01468                      if (l >= sizeof(BUFSIZ))
01469                      {
01470                             writemem(buf, l);
01471                             l=0;
01472                      }
01473               }
01474               buf[l++]=c;
01475               ++body_count;
01476        }
01477        writemem(buf, l);
01478 }
01479 
01480 /*
01481 ** Poorly written IMAP clients (read: Netscape Messenger) like to issue
01482 ** consecutive partial fetches for downloading large messages.
01483 **
01484 ** To save the time of reparsing the MIME structure, we cache it.
01485 */
01486 
01487 static struct rfc2045 *cached_rfc2045p;
01488 static char *cached_filename;
01489 
01490 void fetch_free_cached()
01491 {
01492        if (cached_rfc2045p)
01493        {
01494               rfc2045_free(cached_rfc2045p);
01495               cached_rfc2045p=0;
01496               free(cached_filename);
01497               cached_filename=0;
01498        }
01499 }
01500 
01501 struct rfc2045 *fetch_alloc_rfc2045(unsigned long msgnum, FILE *fp)
01502 {
01503        if (cached_rfc2045p &&
01504            strcmp(cached_filename,
01505                  current_maildir_info.msgs[msgnum].filename) == 0)
01506               return (cached_rfc2045p);
01507 
01508        fetch_free_cached();
01509 
01510        if ((cached_filename=strdup(current_maildir_info.
01511                                 msgs[msgnum].filename))
01512            == 0) write_error_exit(0);
01513 
01514        if (fseek(fp, 0L, SEEK_SET) == -1)
01515        {
01516               write_error_exit(0);
01517               return (0);
01518        }
01519        cached_rfc2045p=rfc2045_fromfp(fp);
01520        if (!cached_rfc2045p)
01521        {
01522               free(cached_filename);
01523               cached_filename=0;
01524               write_error_exit(0);
01525        }
01526        return (cached_rfc2045p);
01527 }
01528 
01529 static FILE *cached_fp=0;
01530 static char *cached_fp_filename=0;
01531 static off_t cached_base_offset;
01532 static off_t cached_virtual_offset;
01533 static off_t cached_phys_offset;
01534 
01535 FILE *open_cached_fp(unsigned long msgnum)
01536 {
01537        int    fd;
01538 
01539        if (cached_fp && strcmp(cached_fp_filename,
01540                             current_maildir_info.msgs[msgnum].filename)
01541            == 0)
01542               return (cached_fp);
01543 
01544        if (cached_fp)
01545        {
01546               fclose(cached_fp);
01547               free(cached_fp_filename);
01548               cached_fp_filename=0;
01549               cached_fp=0;
01550        }
01551 
01552        fd=imapscan_openfile(current_mailbox, &current_maildir_info, msgnum);
01553        if (fd < 0 || (cached_fp=fdopen(fd, "r")) == 0)
01554        {
01555               if (fd >= 0)  close(fd);
01556 
01557               if ((cached_fp=tmpfile()) != 0)
01558               {
01559                      fprintf(cached_fp, unavailable);
01560                      if (fseek(cached_fp, 0L, SEEK_SET) < 0 ||
01561                          ferror(cached_fp))
01562                      {
01563                             fclose(cached_fp);
01564                             cached_fp=0;
01565                      }
01566               }
01567 
01568               if (cached_fp == 0)
01569               {
01570                      fprintf(stderr, "ERR: %s: %s\n",
01571                             getenv("AUTHENTICATED"),
01572 #if    HAVE_STRERROR
01573                             strerror(errno)
01574 #else
01575                             "error"
01576 #endif
01577 
01578                             );
01579                      fflush(stderr);
01580                      _exit(1);
01581               }
01582        }
01583 
01584        if ((cached_fp_filename=strdup(current_maildir_info.
01585                                    msgs[msgnum].filename))
01586            == 0)
01587        {
01588               fclose(cached_fp);
01589               cached_fp=0;
01590               write_error_exit(0);
01591        }
01592        cached_base_offset=0;
01593        cached_virtual_offset=0;
01594        cached_phys_offset=0;
01595        return (cached_fp);
01596 }
01597 
01598 void fetch_free_cache()
01599 {
01600        if (cached_fp)
01601        {
01602               fclose(cached_fp);
01603               cached_fp=0;
01604               free(cached_fp_filename);
01605               cached_fp_filename=0;
01606        }
01607 }
01608 
01609 void save_cached_offsets(off_t base, off_t virt, off_t phys)
01610 {
01611        cached_base_offset=base;
01612        cached_virtual_offset=virt;
01613        cached_phys_offset=phys;
01614 }
01615 
01616 int get_cached_offsets(off_t base, off_t *virt, off_t *phys)
01617 {
01618        if (!cached_fp)
01619               return (-1);
01620        if (base != cached_base_offset)
01621               return (-1);
01622 
01623        *virt=cached_virtual_offset;
01624        *phys=cached_phys_offset;
01625        return (0);
01626 }