|
a/src/bincimapmime/mime-parsefull.cc |
|
b/src/bincimapmime/mime-parsefull.cc |
|
... |
|
... |
25 |
*/
|
25 |
*/
|
26 |
#ifdef HAVE_CONFIG_H
|
26 |
#ifdef HAVE_CONFIG_H
|
27 |
#include <config.h>
|
27 |
#include <config.h>
|
28 |
#endif
|
28 |
#endif
|
29 |
|
29 |
|
30 |
#include "mime.h"
|
30 |
#include <string.h>
|
31 |
#include "mime-utils.h"
|
31 |
#include <ctype.h>
|
32 |
#include "mime-inputsource.h"
|
32 |
#include <stdio.h>
|
33 |
#include "convert.h"
|
33 |
#include <errno.h>
|
|
|
34 |
|
34 |
#include <string>
|
35 |
#include <string>
|
35 |
#include <vector>
|
36 |
#include <vector>
|
36 |
#include <map>
|
37 |
#include <map>
|
37 |
#include <exception>
|
38 |
#include <exception>
|
38 |
#include <iostream>
|
39 |
#include <iostream>
|
39 |
|
40 |
|
40 |
#include <string.h>
|
|
|
41 |
#include <ctype.h>
|
|
|
42 |
#include <stdio.h>
|
|
|
43 |
#include <errno.h>
|
|
|
44 |
|
|
|
45 |
Binc::MimeInputSource *mimeSource = 0;
|
|
|
46 |
|
|
|
47 |
#ifndef NO_NAMESPACES
|
41 |
#ifndef NO_NAMESPACES
|
48 |
using namespace ::std;
|
42 |
using namespace ::std;
|
49 |
#endif /* NO_NAMESPACES */
|
43 |
#endif /* NO_NAMESPACES */
|
50 |
|
44 |
|
51 |
#undef MPF
|
45 |
#include "mime.h"
|
|
|
46 |
#include "mime-utils.h"
|
|
|
47 |
#include "mime-inputsource.h"
|
|
|
48 |
#include "convert.h"
|
|
|
49 |
|
|
|
50 |
// #define MPF
|
52 |
#ifdef MPF
|
51 |
#ifdef MPF
|
53 |
#define MPFDEB(X) fprintf X
|
52 |
#define MPFDEB(X) fprintf X
|
54 |
#else
|
53 |
#else
|
55 |
#define MPFDEB(X)
|
54 |
#define MPFDEB(X)
|
56 |
#endif
|
55 |
#endif
|
57 |
|
56 |
|
58 |
//------------------------------------------------------------------------
|
57 |
//------------------------------------------------------------------------
|
59 |
void Binc::MimeDocument::parseFull(int fd) const
|
58 |
void Binc::MimeDocument::parseFull(int fd)
|
60 |
{
|
59 |
{
|
61 |
if (allIsParsed)
|
60 |
if (allIsParsed)
|
62 |
return;
|
61 |
return;
|
63 |
|
62 |
|
64 |
allIsParsed = true;
|
63 |
allIsParsed = true;
|
65 |
|
64 |
|
66 |
if (!mimeSource || mimeSource->getFileDescriptor() != fd) {
|
|
|
67 |
delete mimeSource;
|
65 |
delete doc_mimeSource;
|
68 |
mimeSource = new MimeInputSource(fd);
|
66 |
doc_mimeSource = new MimeInputSource(fd);
|
69 |
} else {
|
|
|
70 |
mimeSource->reset();
|
|
|
71 |
}
|
|
|
72 |
|
67 |
|
73 |
headerstartoffsetcrlf = 0;
|
68 |
headerstartoffsetcrlf = 0;
|
74 |
headerlength = 0;
|
69 |
headerlength = 0;
|
75 |
bodystartoffsetcrlf = 0;
|
70 |
bodystartoffsetcrlf = 0;
|
76 |
bodylength = 0;
|
71 |
bodylength = 0;
|
|
... |
|
... |
78 |
messagerfc822 = false;
|
73 |
messagerfc822 = false;
|
79 |
multipart = false;
|
74 |
multipart = false;
|
80 |
|
75 |
|
81 |
int bsize = 0;
|
76 |
int bsize = 0;
|
82 |
string bound;
|
77 |
string bound;
|
83 |
doParseFull(bound, bsize);
|
78 |
doParseFull(doc_mimeSource, bound, bsize);
|
84 |
|
79 |
|
85 |
// eat any trailing junk to get the correct size
|
80 |
// eat any trailing junk to get the correct size
|
86 |
char c;
|
81 |
char c;
|
87 |
while (mimeSource->getChar(&c));
|
82 |
while (doc_mimeSource->getChar(&c));
|
88 |
|
83 |
|
89 |
size = mimeSource->getOffset();
|
84 |
size = doc_mimeSource->getOffset();
|
90 |
}
|
85 |
}
|
91 |
|
86 |
|
92 |
void Binc::MimeDocument::parseFull(istream& s) const
|
87 |
void Binc::MimeDocument::parseFull(istream& s)
|
93 |
{
|
88 |
{
|
94 |
if (allIsParsed)
|
89 |
if (allIsParsed)
|
95 |
return;
|
90 |
return;
|
96 |
|
91 |
|
97 |
allIsParsed = true;
|
92 |
allIsParsed = true;
|
98 |
|
93 |
|
99 |
delete mimeSource;
|
94 |
delete doc_mimeSource;
|
100 |
mimeSource = new MimeInputSourceStream(s);
|
95 |
doc_mimeSource = new MimeInputSourceStream(s);
|
101 |
|
96 |
|
102 |
headerstartoffsetcrlf = 0;
|
97 |
headerstartoffsetcrlf = 0;
|
103 |
headerlength = 0;
|
98 |
headerlength = 0;
|
104 |
bodystartoffsetcrlf = 0;
|
99 |
bodystartoffsetcrlf = 0;
|
105 |
bodylength = 0;
|
100 |
bodylength = 0;
|
|
... |
|
... |
107 |
messagerfc822 = false;
|
102 |
messagerfc822 = false;
|
108 |
multipart = false;
|
103 |
multipart = false;
|
109 |
|
104 |
|
110 |
int bsize = 0;
|
105 |
int bsize = 0;
|
111 |
string bound;
|
106 |
string bound;
|
112 |
doParseFull(bound, bsize);
|
107 |
doParseFull(doc_mimeSource, bound, bsize);
|
113 |
|
108 |
|
114 |
// eat any trailing junk to get the correct size
|
109 |
// eat any trailing junk to get the correct size
|
115 |
char c;
|
110 |
char c;
|
116 |
while (mimeSource->getChar(&c));
|
111 |
while (doc_mimeSource->getChar(&c));
|
117 |
|
112 |
|
118 |
size = mimeSource->getOffset();
|
113 |
size = doc_mimeSource->getOffset();
|
119 |
}
|
114 |
}
|
120 |
|
115 |
|
121 |
//------------------------------------------------------------------------
|
116 |
//------------------------------------------------------------------------
|
122 |
static bool parseOneHeaderLine(Binc::Header *header, unsigned int *nlines)
|
117 |
bool Binc::MimePart::parseOneHeaderLine(Binc::Header *header,
|
|
|
118 |
unsigned int *nlines)
|
123 |
{
|
119 |
{
|
124 |
using namespace ::Binc;
|
120 |
using namespace ::Binc;
|
125 |
char c;
|
121 |
char c;
|
126 |
bool eof = false;
|
122 |
bool eof = false;
|
127 |
char cqueue[4];
|
123 |
char cqueue[4];
|
|
... |
|
... |
200 |
|
196 |
|
201 |
return !(eof || endOfHeaders);
|
197 |
return !(eof || endOfHeaders);
|
202 |
}
|
198 |
}
|
203 |
|
199 |
|
204 |
//------------------------------------------------------------------------
|
200 |
//------------------------------------------------------------------------
|
205 |
static void parseHeader(Binc::Header *header, unsigned int *nlines)
|
201 |
void Binc::MimePart::parseHeader(Binc::Header *header, unsigned int *nlines)
|
206 |
{
|
202 |
{
|
207 |
while (parseOneHeaderLine(header, nlines))
|
203 |
while (parseOneHeaderLine(header, nlines))
|
208 |
{ }
|
204 |
{ }
|
209 |
}
|
205 |
}
|
210 |
|
206 |
|
211 |
//------------------------------------------------------------------------
|
207 |
//------------------------------------------------------------------------
|
212 |
static void analyzeHeader(Binc::Header *header, bool *multipart,
|
208 |
void Binc::MimePart::analyzeHeader(Binc::Header *header, bool *multipart,
|
213 |
bool *messagerfc822, string *subtype,
|
209 |
bool *messagerfc822, string *subtype,
|
214 |
string *boundary)
|
210 |
string *boundary)
|
215 |
{
|
211 |
{
|
216 |
using namespace ::Binc;
|
212 |
using namespace ::Binc;
|
217 |
|
213 |
|
218 |
// Do simple parsing of headers to determine the
|
214 |
// Do simple parsing of headers to determine the
|
219 |
// type of message (multipart,messagerfc822 etc)
|
215 |
// type of message (multipart,messagerfc822 etc)
|
|
... |
|
... |
265 |
}
|
261 |
}
|
266 |
}
|
262 |
}
|
267 |
}
|
263 |
}
|
268 |
}
|
264 |
}
|
269 |
|
265 |
|
270 |
static void parseMessageRFC822(vector<Binc::MimePart> *members,
|
266 |
void Binc::MimePart::parseMessageRFC822(vector<Binc::MimePart> *members,
|
271 |
bool *foundendofpart,
|
267 |
bool *foundendofpart,
|
272 |
unsigned int *bodylength,
|
268 |
unsigned int *bodylength,
|
273 |
unsigned int *nbodylines,
|
269 |
unsigned int *nbodylines,
|
274 |
const string &toboundary)
|
270 |
const string &toboundary)
|
275 |
{
|
271 |
{
|
276 |
using namespace ::Binc;
|
272 |
using namespace ::Binc;
|
277 |
|
273 |
|
278 |
// message rfc822 means a completely enclosed mime document. we
|
274 |
// message rfc822 means a completely enclosed mime document. we
|
279 |
// call the parser recursively, and pass on the boundary string
|
275 |
// call the parser recursively, and pass on the boundary string
|
|
... |
|
... |
284 |
unsigned int bodystartoffsetcrlf = mimeSource->getOffset();
|
280 |
unsigned int bodystartoffsetcrlf = mimeSource->getOffset();
|
285 |
|
281 |
|
286 |
// parsefull returns the number of bytes that need to be removed
|
282 |
// parsefull returns the number of bytes that need to be removed
|
287 |
// from the body because of the terminating boundary string.
|
283 |
// from the body because of the terminating boundary string.
|
288 |
int bsize = 0;
|
284 |
int bsize = 0;
|
289 |
if (m.doParseFull(toboundary, bsize))
|
285 |
if (m.doParseFull(mimeSource, toboundary, bsize))
|
290 |
*foundendofpart = true;
|
286 |
*foundendofpart = true;
|
291 |
|
287 |
|
292 |
// make sure bodylength doesn't overflow
|
288 |
// make sure bodylength doesn't overflow
|
293 |
*bodylength = mimeSource->getOffset();
|
289 |
*bodylength = mimeSource->getOffset();
|
294 |
if (*bodylength >= bodystartoffsetcrlf) {
|
290 |
if (*bodylength >= bodystartoffsetcrlf) {
|
|
... |
|
... |
305 |
*nbodylines += m.getNofLines();
|
301 |
*nbodylines += m.getNofLines();
|
306 |
|
302 |
|
307 |
members->push_back(m);
|
303 |
members->push_back(m);
|
308 |
}
|
304 |
}
|
309 |
|
305 |
|
310 |
static bool skipUntilBoundary(const string &delimiter,
|
306 |
bool Binc::MimePart::skipUntilBoundary(const string &delimiter,
|
311 |
unsigned int *nlines, bool *eof)
|
307 |
unsigned int *nlines, bool *eof)
|
312 |
{
|
308 |
{
|
313 |
int endpos = delimiter.length();
|
309 |
int endpos = delimiter.length();
|
314 |
char *delimiterqueue = 0;
|
310 |
char *delimiterqueue = 0;
|
315 |
int delimiterpos = 0;
|
311 |
int delimiterpos = 0;
|
316 |
const char *delimiterStr = delimiter.c_str();
|
312 |
const char *delimiterStr = delimiter.c_str();
|
|
... |
|
... |
358 |
|
354 |
|
359 |
// JFD: Things we do after finding a boundary (something like CRLF--somestring)
|
355 |
// JFD: Things we do after finding a boundary (something like CRLF--somestring)
|
360 |
// Need to see if this is a final one (with an additional -- at the end),
|
356 |
// Need to see if this is a final one (with an additional -- at the end),
|
361 |
// and need to check if it is immediately followed by another boundary
|
357 |
// and need to check if it is immediately followed by another boundary
|
362 |
// (in this case, we give up our final CRLF in its favour)
|
358 |
// (in this case, we give up our final CRLF in its favour)
|
363 |
static inline void postBoundaryProcessing(bool *eof,
|
359 |
inline void Binc::MimePart::postBoundaryProcessing(bool *eof,
|
364 |
unsigned int *nlines,
|
360 |
unsigned int *nlines,
|
365 |
int *boundarysize,
|
361 |
int *boundarysize,
|
366 |
bool *foundendofpart)
|
362 |
bool *foundendofpart)
|
367 |
{
|
363 |
{
|
368 |
// Read two more characters. This may be CRLF, it may be "--" and
|
364 |
// Read two more characters. This may be CRLF, it may be "--" and
|
369 |
// it may be any other two characters.
|
365 |
// it may be any other two characters.
|
370 |
char a = '\0';
|
366 |
char a = '\0';
|
371 |
if (!mimeSource->getChar(&a))
|
367 |
if (!mimeSource->getChar(&a))
|
|
... |
|
... |
428 |
mimeSource->ungetChar();
|
424 |
mimeSource->ungetChar();
|
429 |
mimeSource->ungetChar();
|
425 |
mimeSource->ungetChar();
|
430 |
}
|
426 |
}
|
431 |
}
|
427 |
}
|
432 |
|
428 |
|
433 |
static void parseMultipart(const string &boundary,
|
429 |
void Binc::MimePart::parseMultipart(const string &boundary,
|
434 |
const string &toboundary,
|
430 |
const string &toboundary,
|
435 |
bool *eof,
|
431 |
bool *eof,
|
436 |
unsigned int *nlines,
|
432 |
unsigned int *nlines,
|
437 |
int *boundarysize,
|
433 |
int *boundarysize,
|
438 |
bool *foundendofpart,
|
434 |
bool *foundendofpart,
|
439 |
unsigned int *bodylength,
|
435 |
unsigned int *bodylength,
|
440 |
vector<Binc::MimePart> *members)
|
436 |
vector<Binc::MimePart> *members)
|
441 |
{
|
437 |
{
|
442 |
MPFDEB((stderr, "BINC: ParseMultipart: boundary [%s], toboundary[%s]\n",
|
438 |
MPFDEB((stderr, "BINC: ParseMultipart: boundary [%s], toboundary[%s]\n",
|
443 |
boundary.c_str(),
|
439 |
boundary.c_str(),
|
444 |
toboundary.c_str()));
|
440 |
toboundary.c_str()));
|
445 |
using namespace ::Binc;
|
441 |
using namespace ::Binc;
|
|
... |
|
... |
466 |
MimePart m;
|
462 |
MimePart m;
|
467 |
|
463 |
|
468 |
// If parseFull returns != 0, then it encountered the multipart's
|
464 |
// If parseFull returns != 0, then it encountered the multipart's
|
469 |
// final boundary.
|
465 |
// final boundary.
|
470 |
int bsize = 0;
|
466 |
int bsize = 0;
|
471 |
if (m.doParseFull(boundary, bsize)) {
|
467 |
if (m.doParseFull(mimeSource, boundary, bsize)) {
|
472 |
quit = true;
|
468 |
quit = true;
|
473 |
*boundarysize = bsize;
|
469 |
*boundarysize = bsize;
|
474 |
}
|
470 |
}
|
475 |
|
471 |
|
476 |
members->push_back(m);
|
472 |
members->push_back(m);
|
|
... |
|
... |
506 |
*bodylength = 0;
|
502 |
*bodylength = 0;
|
507 |
}
|
503 |
}
|
508 |
MPFDEB((stderr, "BINC: ParseMultipart return\n"));
|
504 |
MPFDEB((stderr, "BINC: ParseMultipart return\n"));
|
509 |
}
|
505 |
}
|
510 |
|
506 |
|
511 |
static void parseSinglePart(const string &toboundary,
|
507 |
void Binc::MimePart::parseSinglePart(const string &toboundary,
|
512 |
int *boundarysize,
|
508 |
int *boundarysize,
|
513 |
unsigned int *nbodylines,
|
509 |
unsigned int *nbodylines,
|
514 |
unsigned int *nlines,
|
510 |
unsigned int *nlines,
|
515 |
bool *eof, bool *foundendofpart,
|
511 |
bool *eof, bool *foundendofpart,
|
516 |
unsigned int *bodylength)
|
512 |
unsigned int *bodylength)
|
|
... |
|
... |
589 |
MPFDEB((stderr, "BINC: parseSimple ret: bodylength %d, boundarysize %d\n",
|
585 |
MPFDEB((stderr, "BINC: parseSimple ret: bodylength %d, boundarysize %d\n",
|
590 |
*bodylength, *boundarysize));
|
586 |
*bodylength, *boundarysize));
|
591 |
}
|
587 |
}
|
592 |
|
588 |
|
593 |
//------------------------------------------------------------------------
|
589 |
//------------------------------------------------------------------------
|
594 |
int Binc::MimePart::doParseFull(const string &toboundary,
|
590 |
int Binc::MimePart::doParseFull(MimeInputSource *ms, const string &toboundary,
|
595 |
int &boundarysize) const
|
591 |
int &boundarysize)
|
596 |
{
|
592 |
{
|
597 |
MPFDEB((stderr, "BINC: doParsefull, toboundary[%s]\n", toboundary.c_str()));
|
593 |
MPFDEB((stderr, "BINC: doParsefull, toboundary[%s]\n", toboundary.c_str()));
|
|
|
594 |
mimeSource = ms;
|
598 |
headerstartoffsetcrlf = mimeSource->getOffset();
|
595 |
headerstartoffsetcrlf = mimeSource->getOffset();
|
599 |
|
596 |
|
600 |
// Parse the header of this mime part.
|
597 |
// Parse the header of this mime part.
|
601 |
parseHeader(&h, &nlines);
|
598 |
parseHeader(&h, &nlines);
|
602 |
|
599 |
|
603 |
// Headerlength includes the seperating CRLF. Body starts after the
|
600 |
// Headerlength includes the seperating CRLF. Body starts after the
|
604 |
// CRLF.
|
601 |
// CRLF.
|
605 |
headerlength = mimeSource->getOffset() - headerstartoffsetcrlf;
|
602 |
headerlength = mimeSource->getOffset() - headerstartoffsetcrlf;
|
606 |
bodystartoffsetcrlf = mimeSource->getOffset();
|
603 |
bodystartoffsetcrlf = mimeSource->getOffset();
|
|
|
604 |
MPFDEB((stderr, "BINC: doParsefull, bodystartoffsetcrlf %d\n", bodystartoffsetcrlf));
|
607 |
bodylength = 0;
|
605 |
bodylength = 0;
|
608 |
|
606 |
|
609 |
// Determine the type of mime part by looking at fields in the
|
607 |
// Determine the type of mime part by looking at fields in the
|
610 |
// header.
|
608 |
// header.
|
611 |
analyzeHeader(&h, &multipart, &messagerfc822, &subtype, &boundary);
|
609 |
analyzeHeader(&h, &multipart, &messagerfc822, &subtype, &boundary);
|