Add a rfc2045_mimepos_flags() function superset of rfc2045_mimepos() Adapt dofetchmsgbody, dofetchheadersbuf, dofetchheadersfile, rfc822, rfc822text to only take lines with LF ending into account when computing the length and adding CRs --- imap/fetch.c | 80 ++++++++++++++++++++++++++++++----------------------- rfc2045/rfc2045.c | 61 ++++++++++++++++++++++++++++------------ rfc2045/rfc2045.h | 12 ++++++-- 3 files changed, 99 insertions(+), 54 deletions(-)
diff --git a/imap/fetch.c b/imap/fetch.c index 40dd270..8eaaf8f 100644 --- a/imap/fetch.c +++ b/imap/fetch.c @@ -572,14 +572,14 @@ static void rfc822size(FILE *fp, struct fetchinfo *fi, struct rfc2045 *mimep) { off_t start_pos, end_pos, start_body; -off_t nlines, nbodylines; +off_t nlflines, nlfbodylines; writes("RFC822.SIZE "); - rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body, - &nlines, &nbodylines); + rfc2045_mimepos_flags(mimep, &start_pos, &end_pos, &start_body, + &nlflines, &nlfbodylines, RFC2045_MIMEPOS_LF_LINES); - writen(end_pos - start_pos + nlines); + writen(end_pos - start_pos + nlflines); } static void all(FILE *fp, struct fetchinfo *fi, @@ -676,12 +676,13 @@ static void dofetchmsgbody(FILE *fp, struct fetchinfo *fi, { const char *p=fi->bodysection; off_t start_pos, end_pos, start_body; -off_t nlines, nbodylines; +off_t nlflines, nlfbodylines; unsigned long cnt; char buf[BUFSIZ]; char rbuf[BUFSIZ]; char *rbufptr; int rbufleft; +int last, c; unsigned long bufptr; unsigned long skipping; int ismsgrfc822=1; @@ -776,19 +777,19 @@ off_t cache_phys_chars; return; } - rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body, - &nlines, &nbodylines); + rfc2045_mimepos_flags(mimep, &start_pos, &end_pos, &start_body, + &nlflines, &nlfbodylines, RFC2045_MIMEPOS_LF_LINES); if (p && strcmp(p, "TEXT") == 0) { start_seek_pos=start_body; - cnt=end_pos - start_body + nbodylines; + cnt=end_pos - start_body + nlfbodylines; } else if (p && strcmp(p, "HEADER") == 0) { start_seek_pos=start_pos; - cnt= start_body - start_pos + (nlines - nbodylines); + cnt= start_body - start_pos + (nlflines - nlfbodylines); } else if (p && strcmp(p, "HEADER.FIELDS") == 0) { @@ -824,13 +825,13 @@ off_t cache_phys_chars; { start_seek_pos=start_pos; - cnt= end_pos - start_pos + nlines; + cnt= end_pos - start_pos + nlflines; } else /* Last possibility: entire body */ { start_seek_pos=start_body; - cnt= end_pos - start_body + nbodylines; + cnt= end_pos - start_body + nlfbodylines; } skipping=0; @@ -880,10 +881,9 @@ off_t cache_phys_chars; rbufptr=0; rbufleft=0; + c=0; while (cnt) { - int c; - if (!rbufleft) { rbufleft=fread(rbuf, 1, sizeof(rbuf), fp); @@ -898,10 +898,11 @@ off_t cache_phys_chars; } --rbufleft; + last=c; c=(int)(unsigned char)*rbufptr++; ++cnt_phys_chars; - if (c == '\n') + if (c == '\n' && last != '\r') { ++cnt_virtual_chars; @@ -1002,7 +1003,7 @@ static void dofetchheadersbuf(FILE *fp, struct fetchinfo *fi, int (*headerfunc)(struct fetchinfo *fi, const char *)) { off_t start_pos, end_pos, start_body; -off_t nlines, nbodylines; +off_t nlflines, nlfbodylines; size_t i,j,k,l; char buf[BUFSIZ+2]; int goodheader; @@ -1011,8 +1012,8 @@ unsigned long cnt; char *p; int ii; - rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body, - &nlines, &nbodylines); + rfc2045_mimepos_flags(mimep, &start_pos, &end_pos, &start_body, + &nlflines, &nlfbodylines, RFC2045_MIMEPOS_LF_LINES); if (fseek(fp, start_pos, SEEK_SET) == -1) { writes("{0}\r\n"); @@ -1089,7 +1090,7 @@ int ii; p=buf; while (skipping) { - if (*p == '\n') + if (*p == '\n' && (p == buf || p[-1] != '\r')) { --skipping; if (skipping == 0) @@ -1110,8 +1111,11 @@ int ii; { if (*p == '\n') { - writes("\r"); - if (--cnt == 0) break; + if (p == buf || p[-1] != '\r') + { + writes("\r"); + if (--cnt == 0) break; + } writes("\n"); --cnt; ++p; @@ -1142,9 +1146,9 @@ static void dofetchheadersfile(FILE *fp, struct fetchinfo *fi, int (*headerfunc)(struct fetchinfo *fi, const char *)) { off_t start_pos, end_pos, start_body, left; -off_t nlines, nbodylines; +off_t nlflines, nlfbodylines; size_t i; -int c, pass; +int c, last, pass; char buf1[256]; int goodheader; struct fetchheaderinfo finfo; @@ -1155,8 +1159,8 @@ struct fetchheaderinfo finfo; void (*func)(struct fetchheaderinfo *, const char *, size_t)= pass ? printheader:countheader; - rfc2045_mimepos(mimep, &start_pos, &end_pos, &start_body, - &nlines, &nbodylines); + rfc2045_mimepos_flags(mimep, &start_pos, &end_pos, &start_body, + &nlflines, &nlfbodylines, RFC2045_MIMEPOS_LF_LINES); if (fseek(fp, start_pos, SEEK_SET) == -1) { writes("{0}\r\n"); @@ -1232,6 +1236,7 @@ struct fetchheaderinfo finfo; i=0; while (left) { + last=c; c=getc(fp); if (c == EOF) { @@ -1244,7 +1249,7 @@ struct fetchheaderinfo finfo; (*func)(&finfo, buf1, i); i=0; } - if (c == '\n') + if (c == '\n' && last != '\r') { (*func)(&finfo, buf1, i); buf1[0]='\r'; @@ -1293,7 +1298,7 @@ static void rfc822(FILE *fp, struct fetchinfo *fi, struct rfc2045 *rfcp) { unsigned long n=0; -int c; +int c, last; char buf[BUFSIZ]; unsigned long i; @@ -1305,10 +1310,11 @@ unsigned long i; writes("{0}\r\n"); return; } - while ((c=getc(fp)) != EOF) + c=0; + while (last=c, (c=getc(fp)) != EOF) { ++n; - if (c == '\n') ++n; + if (c == '\n' && last != '\r') ++n; } if (fseek(fp, 0L, SEEK_SET) == -1) @@ -1322,10 +1328,12 @@ unsigned long i; writes("}\r\n"); i=0; + c=0; while (n) { + last=c; c=getc(fp); - if (c == '\n') + if (c == '\n' && last != '\r') { if (i >= sizeof(buf)) { @@ -1435,16 +1443,16 @@ static void rfc822text(FILE *fp, struct fetchinfo *fi, struct rfc2045 *rfcp) { off_t start_pos, end_pos, start_body; -off_t nlines, nbodylines; +off_t nlflines, nlfbodylines; unsigned long i; -int c; +int c, last; char buf[BUFSIZ]; unsigned long l; writes("RFC822.TEXT {"); - rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, - &nlines, &nbodylines); + rfc2045_mimepos_flags(rfcp, &start_pos, &end_pos, &start_body, + &nlflines, &nlfbodylines, RFC2045_MIMEPOS_LF_LINES); if (fseek(fp, start_body, SEEK_SET) == -1) { @@ -1453,14 +1461,16 @@ unsigned long l; return; } - i=end_pos - start_body + nbodylines; + i=end_pos - start_body + nlfbodylines; writen(i); writes("}\r\n"); l=0; + c=0; while (i) { + last=c; c=getc(fp); if (c == EOF) { @@ -1473,7 +1483,7 @@ unsigned long l; writemem(buf, l); l=0; } - if (c == '\n' && i) + if (c == '\n' && i && last != '\r') { --i; buf[l++]='\r'; diff --git a/rfc2045/rfc2045.c b/rfc2045/rfc2045.c index 2245f43..40c5774 100644 --- a/rfc2045/rfc2045.c +++ b/rfc2045/rfc2045.c @@ -238,15 +238,19 @@ static void set_string(char **p, /* Update byte counts for this structure, and all the superstructures */ static void update_counts(struct rfc2045 *p, size_t newcnt, size_t newendcnt, - unsigned nlines) + unsigned nlflines, unsigned ncrlflines) { while (p) { p->endpos = newcnt; p->endbody = newendcnt; - p->nlines += nlines; + p->nlflines += nlflines; + p->ncrlflines += ncrlflines; if (!p->workinheader) - p->nbodylines += nlines; + { + p->nlfbodylines += nlflines; + p->ncrlfbodylines += ncrlflines; + } p=p->parent; } } @@ -326,7 +330,7 @@ void rfc2045_parse_partial(struct rfc2045 *h) (!p->lastpart || !p->lastpart->workclosed)) (*h->rfc2045acptr->section_contents)(h->workbuf, l); - update_counts(p, p->endpos+l, p->endpos+l, 0); + update_counts(p, p->endpos+l, p->endpos+l, 0, 0); p->informdata=1; for (i=0; l<h->workbuflen; l++) h->workbuf[i++]=h->workbuf[l]; @@ -403,7 +407,7 @@ size_t n=cnt-1; /* Strip \n (we always get at least a \n here) */ struct rfc2045 *newp; struct rfc2045ac *rwp=p->rfc2045acptr; unsigned num_levels=0; - +unsigned iscrlf=0; size_t k; int bit8=0; @@ -421,7 +425,10 @@ int bit8=0; } if (n && c[n-1] == '\r') /* Strip trailing \r */ + { --n; + iscrlf=1; + } /* Before the main drill down loop before, look ahead and see if we're ** in a middle of a form-data section. */ @@ -452,7 +459,7 @@ int bit8=0; if (p->lastpart->workclosed) { - update_counts(p, p->endpos+cnt, p->endpos+n, 1); + update_counts(p, p->endpos+cnt, p->endpos+n, !iscrlf, iscrlf); return; } /* Leftover trash -- workclosed is set when the final @@ -488,14 +495,14 @@ int bit8=0; p->lastpart->workclosed=1; update_counts(p, p->endpos+cnt, p->endpos+cnt, - 1); + !iscrlf, iscrlf); return; } /* Create new RFC2045 section */ newp=append_part(p, p->endpos+cnt); - update_counts(p, p->endpos+cnt, p->endpos+n, 1); + update_counts(p, p->endpos+cnt, p->endpos+n, !iscrlf, iscrlf); /* The new RFC2045 section is MIME compliant */ @@ -541,7 +548,7 @@ int bit8=0; (*rwp->section_contents)(c, cnt); update_counts(p, p->endpos+cnt, p->endpos+cnt_update, - 1); + !iscrlf, iscrlf); } return; } @@ -559,13 +566,13 @@ int bit8=0; if ( n == 0 ) /* End of header, body begins. Parse header. */ { do_header(p); /* Clean up any left over header line */ - p->workinheader=0; /* Message body starts right here */ p->startbody=p->endpos+cnt; - update_counts(p, p->startbody, p->startbody, 1); - --p->nbodylines; /* Don't count the blank line */ + update_counts(p, p->startbody, p->startbody, !iscrlf, iscrlf); + + p->workinheader=0; /* Discard content type and boundary if I don't understand ** this MIME flavor. @@ -650,7 +657,7 @@ int bit8=0; /* RFC822 header continues */ - update_counts(p, p->endpos + cnt, p->endpos+n, 1); + update_counts(p, p->endpos + cnt, p->endpos+n, !iscrlf, iscrlf); /* If this header line starts with a space, append one space ** to the saved contents of the previous line, and append this @@ -1281,15 +1288,27 @@ const char *rfc2045_content_md5(const struct rfc2045 *p) return (p->content_md5 ? p->content_md5:""); } -void rfc2045_mimepos(const struct rfc2045 *p, +void rfc2045_mimepos_flags(const struct rfc2045 *p, off_t *start_pos, off_t *end_pos, off_t *start_body, - off_t *nlines, off_t *nbodylines) + off_t *nlines, off_t *nbodylines, int flags) { *start_pos=p->startpos; *end_pos=p->endpos; - *nlines=p->nlines; - *nbodylines=p->nbodylines; + *nlines=0; + *nbodylines=0; + + if (flags & RFC2045_MIMEPOS_LF_LINES) + { + *nlines+=p->nlflines; + *nbodylines+=p->nlfbodylines; + } + if (flags & RFC2045_MIMEPOS_CRLF_LINES) + { + *nlines+=p->ncrlflines; + *nbodylines+=p->ncrlfbodylines; + } + if (p->parent) /* MIME parts do not have the trailing CRLF */ { *end_pos=p->endbody; @@ -1304,6 +1323,14 @@ void rfc2045_mimepos(const struct rfc2045 *p, } } +void rfc2045_mimepos(const struct rfc2045 *p, + off_t *start_pos, off_t *end_pos, off_t *start_body, + off_t *nlines, off_t *nbodylines) +{ + rfc2045_mimepos_flags(p, start_pos, end_pos, start_body, + nlines, nbodylines, RFC2045_MIMEPOS_ALL_LINES); +} + unsigned rfc2045_mimepartcount(const struct rfc2045 *p) { const struct rfc2045 *q; diff --git a/rfc2045/rfc2045.h b/rfc2045/rfc2045.h index ddfab1f..7739757 100644 --- a/rfc2045/rfc2045.h +++ b/rfc2045/rfc2045.h @@ -34,8 +34,10 @@ struct rfc2045 { endpos, /* Where it ends */ startbody, /* Where the body of the msg starts */ endbody; /* endpos - trailing CRLF terminator */ - off_t nlines; /* Number of lines in message */ - off_t nbodylines; /* Number of lines only in the body */ + off_t nlflines; /* Number of lines in message with LF line ending */ + off_t nlfbodylines; /* Number of lines only in the body with LF line ending */ + off_t ncrlflines; /* Number of lines in message with CRLF line ending */ + off_t ncrlfbodylines; /* Number of lines only in the body with CRLF line ending */ char *mime_version; char *content_type; struct rfc2045attr *content_type_attr; /* Content-Type: attributes */ @@ -119,8 +121,14 @@ const char *rfc2045_content_description(const struct rfc2045 *); const char *rfc2045_content_language(const struct rfc2045 *); const char *rfc2045_content_md5(const struct rfc2045 *); +#define RFC2045_MIMEPOS_LF_LINES 1 +#define RFC2045_MIMEPOS_CRLF_LINES 2 +#define RFC2045_MIMEPOS_ALL_LINES 3 + void rfc2045_mimepos(const struct rfc2045 *, off_t *, off_t *, off_t *, off_t *, off_t *); +void rfc2045_mimepos_flags(const struct rfc2045 *, off_t *, off_t *, off_t *, + off_t *, off_t *,int); unsigned rfc2045_mimepartcount(const struct rfc2045 *); void rfc2045_xdump(struct rfc2045 *); -- 1.7.10.4 ------------------------------------------------------------------------------ Slashdot TV. Video for Nerds. Stuff that matters. http://tv.slashdot.org/ _______________________________________________ Courier-imap mailing list Courier-imap@lists.sourceforge.net Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-imap