rfc2045.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:25k
源码类别:

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. /*
  6. ** $Id: rfc2045.c,v 1.20 2000/04/10 22:42:02 mrsam Exp $
  7. */
  8. #if    HAVE_CONFIG_H
  9. #include       "config.h"
  10. #endif
  11. #include       <stdlib.h>
  12. #include       <stdio.h>
  13. #include       <string.h>
  14. #if    HAVE_STRINGS_H
  15. #include       <strings.h>
  16. #endif
  17. #include <ctype.h>
  18. #include "rfc2045.h"
  19. #include "rfc822/rfc822.h"
  20. #include "rfc2045charset.h"
  21. static char *rfc2045_defcharset=0;
  22. extern void rfc2045_enomem();
  23. #define MAXLEVELS 20
  24. #define MAXPARTS 300
  25. /*
  26. New RFC2045 structure.
  27. */
  28. struct rfc2045 *rfc2045_alloc()
  29. {
  30. struct rfc2045 *p=(struct rfc2045 *)malloc(sizeof(struct rfc2045));
  31. if (!p) rfc2045_enomem();
  32. /* Initialize everything to nulls, except for one thing */
  33. memset(p, '', sizeof(*p));
  34. p->pindex=1; /* Start with part #1 */
  35. p->workinheader=1;
  36. /* Most of the time, we're about to read a header */
  37. return (p);
  38. }
  39. const char *rfc2045_getattr(const struct rfc2045attr *p, const char *name)
  40. {
  41. while (p)
  42. {
  43. if (p->name && strcmp(p->name, name) == 0)
  44. return (p->value);
  45. p=p->next;
  46. }
  47. return (0);
  48. }
  49. void rfc2045_setattr(struct rfc2045attr **p, const char *name, const char *val)
  50. {
  51. char *v;
  52. while (*p)
  53. {
  54. if (strcmp( (*p)->name, name) == 0) break;
  55. p=&(*p)->next;
  56. }
  57. if (val == 0)
  58. {
  59. struct rfc2045attr *q= *p;
  60. if (q)
  61. {
  62. *p=q->next;
  63. if (q->name) free(q->name);
  64. if (q->value) free(q->value);
  65. free(q);
  66. }
  67. return;
  68. }
  69. v=strdup(val);
  70. if (!v) rfc2045_enomem();
  71. if (!*p)
  72. {
  73. if (((*p)=(struct rfc2045attr *)malloc(sizeof(**p))) == 0)
  74. {
  75. free(v);
  76. rfc2045_enomem();
  77. }
  78. memset( (*p), 0, sizeof(**p));
  79. if ( ((*p)->name=strdup(name)) == 0)
  80. {
  81. free( *p );
  82. *p=0;
  83. free(v);
  84. rfc2045_enomem();
  85. }
  86. }
  87. if ( (*p)->value ) free ( (*p)->value );
  88. (*p)->value=v;
  89. }
  90. /* static const char cb_name[]="boundary"; */
  91. /* #define ContentBoundary(p) (rfc2045_getattr( (p)->content_type_attr, cb_name)) */
  92. #define ContentBoundary(p) ( (p)->boundary )
  93. /*
  94. Unallocate the RFC2045 structure.  Recursively unallocate
  95. all sub-structures.  Unallocate all associated buffers.
  96. */
  97. static void rfc2045_freeattr(struct rfc2045attr *p)
  98. {
  99. while (p)
  100. {
  101. struct rfc2045attr *q=p->next;
  102. if (p->name) free(p->name);
  103. if (p->value) free(p->value);
  104. free(p);
  105. p=q;
  106. }
  107. }
  108. void rfc2045_free(struct rfc2045 *p)
  109. {
  110. struct rfc2045 *q, *r;
  111. for (q=p->firstpart; q; )
  112. {
  113. r=q->next;
  114. rfc2045_free(q);
  115. q=r;
  116. }
  117. rfc2045_freeattr(p->content_type_attr);
  118. rfc2045_freeattr(p->content_disposition_attr);
  119. if (p->content_md5) free(p->content_md5);
  120. if (p->content_base) free(p->content_base);
  121. if (p->content_location) free(p->content_location);
  122. if (p->content_language) free(p->content_language);
  123. if (p->content_id) free(p->content_id);
  124. if (p->content_description) free(p->content_description);
  125. if (p->content_transfer_encoding) free(p->content_transfer_encoding);
  126. if (p->boundary) free(p->boundary);
  127. if (p->content_type) free(p->content_type);
  128. if (p->mime_version) free(p->mime_version);
  129. if (p->workbuf) free(p->workbuf);
  130. if (p->content_disposition) free(p->content_disposition);
  131. if (p->rw_transfer_encoding) free(p->rw_transfer_encoding);
  132. free(p);
  133. }
  134. /*
  135. Generic dynamic buffer append.
  136. */
  137. void rfc2045_add_buf(
  138. char **bufptr, /* Buffer */
  139. size_t *bufsize, /* Buffer's maximum size */
  140. size_t *buflen, /* Buffer's current size */
  141. const char *p, size_t len) /* Append this data */
  142. {
  143. if (len + *buflen > *bufsize)
  144. {
  145. size_t newsize=len+*buflen+256;
  146. char *p= *bufptr ? (char *)realloc(*bufptr, newsize):
  147. (char *)malloc(newsize);
  148. if (!p) rfc2045_enomem();
  149. *bufptr=p;
  150. *bufsize=newsize;
  151. }
  152. memcpy(*bufptr + *buflen, p, len);
  153. *buflen += len;
  154. }
  155. /* Append to the work buffer */
  156. void rfc2045_add_workbuf(struct rfc2045 *h, const char *p, size_t len)
  157. {
  158. rfc2045_add_buf( &h->workbuf, &h->workbufsize, &h->workbuflen, p, len);
  159. }
  160. /* Append one character to the work buffer */
  161. void rfc2045_add_workbufch(struct rfc2045 *h, int c)
  162. {
  163. char cc= (char)c;
  164. rfc2045_add_workbuf(h, &cc, 1);
  165. }
  166. /*
  167. Generic function to duplicate contents of a string.
  168. The destination string may already be previously allocated,
  169. so unallocate it.
  170. */
  171. static void set_string(char **p,
  172. const char *q)
  173. {
  174. if (*p) free(*p);
  175. *p=0;
  176. if (!q) return;
  177. if ((*p=(char *)malloc(strlen(q)+1)) == 0)
  178. rfc2045_enomem();
  179. strcpy(*p, q);
  180. }
  181. /* Update byte counts for this structure, and all the superstructures */
  182. static void update_counts(struct rfc2045 *p, size_t newcnt, size_t newendcnt,
  183. unsigned nlines)
  184. {
  185. while (p)
  186. {
  187. p->endpos = newcnt;
  188. p->endbody = newendcnt;
  189. p->nlines += nlines;
  190. if (!p->workinheader)
  191. p->nbodylines += nlines;
  192. p=p->parent;
  193. }
  194. }
  195. /*
  196. Main entry point for RFC2045 parsing.  External data is fed
  197. by repetitively calling rfc2045_parse().
  198. rfc2045_parse() breaks up input into lines, and calls doline()
  199. to process each line.
  200. */
  201. static void doline(struct rfc2045 *);
  202. void rfc2045_parse(struct rfc2045 *h, const char *buf, size_t s)
  203. {
  204. size_t l;
  205. while (s)
  206. {
  207. for (l=0; l<s; l++)
  208. if (buf[l] == 'n') break;
  209. if (l < s && buf[l] == 'n')
  210. {
  211. ++l;
  212. rfc2045_add_workbuf(h, buf, l);
  213. doline(h);
  214. h->workbuflen=0;
  215. }
  216. else
  217. rfc2045_add_workbuf(h, buf, l);
  218. buf += l;
  219. s -= l;
  220. }
  221. /*
  222. ** Our buffer's getting pretty big.  Let's see if we can
  223. ** partially handle it.
  224. */
  225. if (h->workbuflen > 512)
  226. {
  227. struct rfc2045 *p;
  228. int l, i;
  229. for (p=h; p->lastpart && !p->lastpart->workclosed;
  230. p=p->lastpart)
  231. ;
  232. /* If p->workinheader, we've got a mother of all headers
  233. ** here.  Well, that's just too bad, we'll end up garbling
  234. ** it.
  235. */
  236. l=h->workbuflen;
  237. /* We do need to make sure that the final rn gets
  238. ** stripped off, so don't gobble up everything if
  239. ** the last character we see is a r
  240. */
  241. if (h->workbuf[l-1] == 'r')
  242. --l;
  243. /* If we'll be rewriting, make sure rwprep knows about
  244. ** stuff that was skipped just now. */
  245. if (h->rfc2045acptr && !p->workinheader &&
  246. (!p->lastpart || !p->lastpart->workclosed))
  247. (*h->rfc2045acptr->section_contents)(h->workbuf, l);
  248. update_counts(p, p->endpos+l, p->endpos+l, 0);
  249. p->informdata=1;
  250. for (i=0; l<h->workbuflen; l++)
  251. h->workbuf[i++]=h->workbuf[l];
  252. h->workbuflen=i;
  253. }
  254. }
  255. /*
  256. Append a new RFC2045 subpart.  Adds new RFC2045 structure to the
  257. end of the list of existing RFC2045 substructures.
  258. */
  259. static struct rfc2045 *append_part_noinherit(struct rfc2045 *p, size_t startpos){
  260. struct rfc2045 *newp;
  261. newp=rfc2045_alloc();
  262. if (p->lastpart)
  263. {
  264. p->lastpart->next=newp;
  265. newp->pindex=p->lastpart->pindex+1;
  266. }
  267. else
  268. {
  269. p->firstpart=newp;
  270. newp->pindex=0;
  271. }
  272. p->lastpart=newp;
  273. newp->parent=p;
  274. /* Initialize source pointers */
  275. newp->startpos=newp->endpos=newp->startbody=newp->endbody=startpos;
  276. while (p->parent)
  277. p=p->parent;
  278. ++p->numparts;
  279. return (newp);
  280. }
  281. static struct rfc2045 *append_part(struct rfc2045 *p, size_t startpos)
  282. {
  283. struct rfc2045 *newp=append_part_noinherit(p, startpos);
  284. /* Substructures inherit content transfer encoding and character set */
  285. set_string(&newp->content_transfer_encoding,
  286. p->content_transfer_encoding);
  287. rfc2045_setattr(&newp->content_type_attr, "charset",
  288. rfc2045_getattr(p->content_type_attr, "charset"));
  289. return (newp);
  290. }
  291. /*
  292. doline() processes next line in the RFC2045 message.
  293. Drills down the list of all the multipart messages currently open,
  294. and checks if the line is a boundary line for the given multipart.
  295. In theory the boundary line, if there is one, should be the boundary
  296. line only for the inner multipart only, but, this takes into account
  297. broken MIME messages.
  298. */
  299. static void do_header(struct rfc2045 *);
  300. static void doline(struct rfc2045 *p)
  301. {
  302. size_t cnt=p->workbuflen;
  303. char *c=p->workbuf;
  304. size_t n=cnt-1; /* Strip n (we always get at least a n here) */
  305. struct rfc2045 *newp;
  306. struct rfc2045ac *rwp=p->rfc2045acptr;
  307. unsigned num_levels=0;
  308. size_t k;
  309. int bit8=0;
  310. if (p->numparts > MAXPARTS)
  311. {
  312. p->rfcviolation |= RFC2045_ERR2COMPLEX;
  313. return;
  314. }
  315. for (k=0; k<cnt; k++)
  316. if (c[k] & 0x80) bit8=1;
  317. if (n && c[n-1] == 'r') /* Strip trailing r */
  318. --n;
  319. /* Before the main drill down loop before, look ahead and see if we're
  320. ** in a middle of a form-data section.  */
  321. for (newp=p; newp->lastpart &&
  322. !newp->lastpart->workclosed; newp=newp->lastpart,
  323. ++num_levels)
  324. {
  325. if (ContentBoundary(newp) == 0 || newp->workinheader)
  326. continue;
  327. if (newp->lastpart->informdata)
  328. {
  329. p=newp->lastpart;
  330. p->informdata=0;
  331. break;
  332. }
  333. }
  334. /* Drill down until we match a boundary, or until we've reached
  335. the last RFC2045 section that has been opened.
  336. */
  337. while (p->lastpart)
  338. {
  339. size_t l;
  340. const char *cb;
  341. if (p->lastpart->workclosed)
  342. {
  343. update_counts(p, p->endpos+cnt, p->endpos+cnt, 1);
  344. return;
  345. }
  346. /* Leftover trash -- workclosed is set when the final
  347. ** terminating boundary has been seen */
  348. /* content_boundary may be set before the entire header
  349. ** has been seen, so continue drilling down in that case
  350. */
  351. cb=ContentBoundary(p);
  352. if (cb == 0 || p->workinheader)
  353. {
  354. p=p->lastpart;
  355. ++num_levels;
  356. continue;
  357. }
  358. l=strlen(cb);
  359. if (c[0] == '-' && c[1] == '-' && n >= 2+l &&
  360. strncasecmp(cb, c+2, l) == 0)
  361. {
  362. if (rwp && (!p->lastpart || !p->lastpart->isdummy))
  363. (*rwp->end_section)();
  364. /* Ok, we've found a boundary */
  365. if (n >= 4+l && strncmp(c+2+l, "--", 2) == 0)
  366. {
  367. /* Last boundary */
  368. p->lastpart->workclosed=1;
  369. update_counts(p, p->endpos+cnt, p->endpos+cnt,
  370. 1);
  371. return;
  372. }
  373. /* Create new RFC2045 section */
  374. newp=append_part(p, p->endpos+cnt);
  375. update_counts(p, p->endpos+cnt, p->endpos+n, 1);
  376. /* The new RFC2045 section is MIME compliant */
  377. if ((newp->mime_version=strdup(p->mime_version)) == 0)
  378. rfc2045_enomem();
  379. return;
  380. }
  381. p=p->lastpart;
  382. ++num_levels;
  383. }
  384. /* Ok, we've found the RFC2045 section that we're working with.
  385. ** No what?
  386. */
  387. if (! p->workinheader)
  388. {
  389. /* Processing body, just update the counts. */
  390. size_t cnt_update=cnt;
  391. if (bit8 && !p->content_8bit &&
  392. (p->rfcviolation & RFC2045_ERR8BITCONTENT) == 0)
  393. {
  394. struct rfc2045 *q;
  395. for (q=p; q; q=q->parent)
  396. q->rfcviolation |= RFC2045_ERR8BITCONTENT;
  397. }
  398. /*
  399. ** In multiparts, the final newline in a part belongs to the
  400. ** boundary, otherwise, include it in the text.
  401. */
  402. if (p->parent && p->parent->content_type &&
  403. strncasecmp(p->parent->content_type,
  404. "multipart/", 10) == 0)
  405. cnt_update=n;
  406. if (!p->lastpart || !p->lastpart->workclosed)
  407. {
  408. if (rwp && !p->isdummy)
  409. (*rwp->section_contents)(c, cnt);
  410. update_counts(p, p->endpos+cnt, p->endpos+cnt_update,
  411. 1);
  412. }
  413. return;
  414. }
  415. if (bit8 && (p->rfcviolation & RFC2045_ERR8BITHEADER) == 0)
  416. {
  417. struct rfc2045 *q;
  418. for (q=p; q; q=q->parent)
  419. q->rfcviolation |= RFC2045_ERR8BITHEADER;
  420. }
  421. /* In the header */
  422. if ( n == 0 ) /* End of header, body begins.  Parse header. */
  423. {
  424. do_header(p); /* Clean up any left over header line */
  425. p->workinheader=0;
  426. /* Message body starts right here */
  427. p->startbody=p->endpos+cnt;
  428. update_counts(p, p->startbody, p->startbody, 1);
  429. --p->nbodylines; /* Don't count the blank line */
  430. /* Discard content type and boundary if I don't understand
  431. ** this MIME flavor.
  432. */
  433. if (!RFC2045_ISMIME1(p->mime_version))
  434. {
  435. set_string(&p->content_type, 0);
  436. rfc2045_freeattr(p->content_type_attr);
  437. p->content_type_attr=0;
  438. set_string(&p->content_disposition, 0);
  439. rfc2045_freeattr(p->content_disposition_attr);
  440. p->content_disposition_attr=0;
  441. if (p->boundary)
  442. {
  443. free(p->boundary);
  444. p->boundary=0;
  445. }
  446. }
  447. /* Normally, if we don't have a content_type, default it
  448. ** to text/plain.  However, if the multipart type is
  449. ** multipart/digest, it is message/rfc822.
  450. */
  451. if (RFC2045_ISMIME1(p->mime_version) && !p->content_type)
  452. {
  453. char *q="text/plain";
  454. if (p->parent && p->parent->content_type &&
  455. strcmp(p->parent->content_type,
  456. "multipart/digest") == 0)
  457. q="message/rfc822";
  458. set_string(&p->content_type, q);
  459. }
  460. /* If this is not a multipart section, we don't want to
  461. ** hear about any boundaries
  462. */
  463. if (!p->content_type ||
  464. strncmp(p->content_type, "multipart/", 10))
  465. rfc2045_setattr(&p->content_type_attr, "boundary", 0);
  466. /* If this section's a message, we will expect to see
  467. ** more RFC2045 stuff, so create a nested RFC2045 structure,
  468. ** and indicate that we expect to see headers.
  469. */
  470. if (p->content_type &&
  471. strcmp(p->content_type, "message/rfc822") == 0)
  472. {
  473. newp=append_part_noinherit(p, p->startbody);
  474. newp->workinheader=1;
  475. return;
  476. }
  477. /*
  478. ** If this is a multipart message (boundary defined),
  479. ** create a RFC2045 structure for the pseudo-section
  480. ** that precedes the first boundary line.
  481. */
  482. if (ContentBoundary(p))
  483. {
  484. newp=append_part(p, p->startbody);
  485. newp->workinheader=0;
  486. newp->isdummy=1;
  487. /* It's easier just to create it. */
  488. return;
  489. }
  490. if (rwp)
  491. (*rwp->start_section)(p);
  492. return;
  493. }
  494. /* RFC822 header continues */
  495. update_counts(p, p->endpos + cnt, p->endpos+n, 1);
  496. /* If this header line starts with a space, append one space
  497. ** to the saved contents of the previous line, and append this
  498. ** line to it.
  499. */
  500. if (isspace((int)(unsigned char)*c))
  501. {
  502. rfc2045_add_buf(&p->header, &p->headersize, &p->headerlen, " ", 1);
  503. }
  504. else
  505. {
  506. /* Otherwise the previous header line is complete, so process it */
  507. do_header(p);
  508. p->headerlen=0;
  509. }
  510. /* Save this line in the header buffer, because the next line
  511. ** could be a continuation.
  512. */
  513. rfc2045_add_buf( &p->header, &p->headersize, &p->headerlen, c, n);
  514. }
  515. /***********************************************************************/
  516. /*
  517. ** paste_tokens() - recombine an array of RFC822 tokens back as a string.
  518. ** (Comments) are ignored.
  519. */
  520. static char *paste_tokens(struct rfc822t *h, int start, int cnt)
  521. {
  522. int l;
  523. int i;
  524. char *p;
  525. /* Calculate string size */
  526. l=1;
  527. for (i=0; i<cnt; i++)
  528. {
  529. if (h->tokens[start+i].token == '(')
  530. continue;
  531. if (rfc822_is_atom(h->tokens[start+i].token))
  532. l += h->tokens[start+i].len;
  533. else
  534. l++;
  535. }
  536. /* Do it */
  537. p=( char *)malloc(l);
  538. if (!p)
  539. {
  540. /* The RFC822 structure we've allocated was temporary.
  541. ** Error condition - free it, so we don't leak memory.
  542. */
  543. rfc822t_free(h);
  544. rfc2045_enomem();
  545. }
  546. l=0;
  547. for (i=0; i<cnt; i++)
  548. {
  549. if (h->tokens[start+i].token == '(')
  550. continue;
  551. if (rfc822_is_atom(h->tokens[start+i].token))
  552. {
  553. int l2=h->tokens[start+i].len;
  554. memcpy(p+l, h->tokens[start+i].ptr, l2);
  555. l += l2;
  556. }
  557. else p[l++]=h->tokens[start+i].token;
  558. }
  559. p[l]=0;
  560. return (p);
  561. }
  562. /* Various permutations of the above, including forcing the string to
  563. ** lowercase
  564. */
  565. static char *lower_paste_tokens(struct rfc822t *h, int start, int cnt)
  566. {
  567. char *p=paste_tokens(h, start, cnt);
  568. char *q;
  569. for (q=p; *q; q++)
  570. *q=tolower(*q);
  571. return (p);
  572. }
  573. static char *paste_token(struct rfc822t *h, int i)
  574. {
  575. if (i >= h->ntokens) return (0);
  576. return (paste_tokens(h, i, 1));
  577. }
  578. static char *lower_paste_token(struct rfc822t *h, int i)
  579. {
  580. char *p=paste_token(h, i);
  581. char *q;
  582. for (q=p; *q; q++)
  583. *q=tolower(*q);
  584. return (p);
  585. }
  586. /*
  587. do_header() - process completed RFC822 header.
  588. */
  589. static void mime_version(struct rfc2045 *, struct rfc822t *);
  590. static void content_type(struct rfc2045 *, struct rfc822t *);
  591. static void content_transfer_encoding(struct rfc2045 *, struct rfc822t *);
  592. static void content_disposition(struct rfc2045 *, struct rfc822t *);
  593. static void content_id(struct rfc2045 *, struct rfc822t *);
  594. static void content_description(struct rfc2045 *, const char *);
  595. static void content_language(struct rfc2045 *, const char *);
  596. static void content_md5(struct rfc2045 *, const char *);
  597. static void content_base(struct rfc2045 *, struct rfc822t *);
  598. static void content_location(struct rfc2045 *, struct rfc822t *);
  599. static void do_header(struct rfc2045 *p)
  600. {
  601. struct rfc822t *header;
  602. char *t;
  603. if (p->headerlen == 0) return;
  604. rfc2045_add_buf( &p->header, &p->headersize, &p->headerlen, "", 1);
  605. /* 0 terminate */
  606. /* Parse the header line according to RFC822 */
  607. header=rfc822t_alloc(p->header, NULL);
  608. if (!header) return; /* Broken header */
  609. if (header->ntokens < 2 ||
  610. header->tokens[0].token ||
  611. header->tokens[1].token != ':')
  612. {
  613. rfc822t_free(header);
  614. return; /* Broken header */
  615. }
  616. t=lower_paste_token(header, 0);
  617. if (strcmp(t, "mime-version") == 0)
  618. {
  619. free(t);
  620. mime_version(p, header);
  621. }
  622. else if (strcmp(t, "content-type") == 0)
  623. {
  624. free(t);
  625. content_type(p, header);
  626. } else if (strcmp(t, "content-transfer-encoding") == 0)
  627. {
  628. free(t);
  629. content_transfer_encoding(p, header);
  630. } else if (strcmp(t, "content-disposition") == 0)
  631. {
  632. free(t);
  633. content_disposition(p, header);
  634. } else if (strcmp(t, "content-id") == 0)
  635. {
  636. free(t);
  637. content_id(p, header);
  638. } else if (strcmp(t, "content-description") == 0)
  639. {
  640. free(t);
  641. t=strchr(p->header, ':');
  642. if (t) ++t;
  643. while (t && isspace((int)(unsigned char)*t))
  644. ++t;
  645. content_description(p, t);
  646. } else if (strcmp(t, "content-language") == 0)
  647. {
  648. free(t);
  649. t=strchr(p->header, ':');
  650. if (t) ++t;
  651. while (t && isspace((int)(unsigned char)*t))
  652. ++t;
  653. content_language(p, t);
  654. } else if (strcmp(t, "content-base") == 0)
  655. {
  656. free(t);
  657. content_base(p, header);
  658. } else if (strcmp(t, "content-location") == 0)
  659. {
  660. free(t);
  661. content_location(p, header);
  662. } else if (strcmp(t, "content-md5") == 0)
  663. {
  664. free(t);
  665. t=strchr(p->header, ':');
  666. if (t) ++t;
  667. while (t && isspace((int)(unsigned char)*t))
  668. ++t;
  669. content_md5(p, t);
  670. }
  671. else free(t);
  672. rfc822t_free(header);
  673. }
  674. /* Mime-Version: and Content-Transfer-Encoding: headers are easy */
  675. static void mime_version(struct rfc2045 *p, struct rfc822t *header)
  676. {
  677. char *vers=paste_tokens(header, 2, header->ntokens-2);
  678. if (p->mime_version) free(p->mime_version);
  679. p->mime_version=vers;
  680. }
  681. static void content_transfer_encoding(struct rfc2045 *r,
  682. struct rfc822t *header)
  683. {
  684. char *p;
  685. p=lower_paste_tokens(header, 2, header->ntokens-2);
  686. if (r->content_transfer_encoding)
  687. free(r->content_transfer_encoding);
  688. r->content_transfer_encoding=p;
  689. if (strcmp(p, "8bit") == 0)
  690. r->content_8bit=1;
  691. }
  692. /* Dig into the content_type header */
  693. static void parse_content_header(struct rfc2045 *r, struct rfc822t *header,
  694. void (*init_token)(struct rfc2045 *, char *),
  695. void (*init_parameter)(struct rfc2045 *, const char *,
  696. struct rfc822t *, int, int))
  697. {
  698. int start;
  699. int i, j;
  700. char *p;
  701. /* Look for the 1st ; */
  702. for (start=2; start < header->ntokens; start++)
  703. if (header->tokens[start].token == ';')
  704. break;
  705. /* Everything up to the 1st ; is the content type */
  706. p=lower_paste_tokens(header, 2, start-2);
  707. (*init_token)(r, p);
  708. if (start < header->ntokens) start++;
  709. /* Handle the remainder of the Content-Type: header */
  710. while (start < header->ntokens)
  711. {
  712. /* Look for next ; */
  713. for (i=start; i<header->ntokens; i++)
  714. if (header->tokens[i].token == ';')
  715. break;
  716. j=start;
  717. if (j < i)
  718. {
  719. ++j;
  720. /* We only understand <atom>= */
  721. while (j < i && header->tokens[j].token == '(')
  722. ++j;
  723. if (j < i && header->tokens[j].token == '=')
  724. {
  725. ++j;
  726. p=lower_paste_token(header, start);
  727. (*init_parameter)(r, p, header, j, i-j);
  728. free(p);
  729. }
  730. }
  731. if ( i<header->ntokens ) ++i; /* Skip over ; */
  732. start=i;
  733. }
  734. }
  735. /* Dig into the content_type header */
  736. static void save_content_type(struct rfc2045 *, char *);
  737. static void save_content_type_parameter( struct rfc2045 *, const char *,
  738. struct rfc822t *, int, int);
  739. static void content_type(struct rfc2045 *r, struct rfc822t *header)
  740. {
  741. parse_content_header(r, header, &save_content_type,
  742. &save_content_type_parameter);
  743. }
  744. static void save_content_type(struct rfc2045 *r, char *content_type)
  745. {
  746. if (r->content_type) free(r->content_type);
  747. r->content_type=content_type;
  748. }
  749. static void save_content_type_parameter(
  750. struct rfc2045 *r, const char *name,
  751. struct rfc822t *header, int start, int len)
  752. {
  753. char *p;
  754. p=strcmp(name, "charset") == 0 ?
  755. lower_paste_tokens(header, start, len):
  756. paste_tokens(header, start, len);
  757. rfc2045_setattr(&r->content_type_attr, name, p);
  758. free(p);
  759. if (strcmp(name, "boundary") == 0)
  760. {
  761. if (r->boundary)
  762. free(r->boundary);
  763. p=lower_paste_tokens(header, start, len);
  764. r->boundary=p;
  765. }
  766. }
  767. /* Dig into content-disposition */
  768. static void save_content_disposition(struct rfc2045 *, char *);
  769. static void save_content_disposition_parameter( struct rfc2045 *, const char *,
  770. struct rfc822t *, int, int);
  771. static void content_disposition(struct rfc2045 *r, struct rfc822t *header)
  772. {
  773. parse_content_header(r, header, &save_content_disposition,
  774. &save_content_disposition_parameter);
  775. }
  776. static void save_content_disposition(struct rfc2045 *r,
  777. char *content_disposition)
  778. {
  779. if (r->content_disposition) free(r->content_disposition);
  780. r->content_disposition=content_disposition;
  781. }
  782. static void save_content_disposition_parameter(
  783. struct rfc2045 *r, const char *name,
  784. struct rfc822t *header, int start, int len)
  785. {
  786. char *p;
  787. p=paste_tokens(header, start, len);
  788. rfc2045_setattr(&r->content_disposition_attr, name, p);
  789. free(p);
  790. }
  791. char *rfc2045_related_start(const struct rfc2045 *p)
  792. {
  793. const char *cb=rfc2045_getattr( p->content_type_attr, "start");
  794. struct rfc822t *t;
  795. struct rfc822a *a;
  796. int i;
  797. if (!cb || !*cb) return (0);
  798. t=rfc822t_alloc(cb, 0);
  799. if (!t) rfc2045_enomem();
  800. a=rfc822a_alloc(t);
  801. if (!a)
  802. {
  803. rfc822t_free(t);
  804. rfc2045_enomem();
  805. }
  806. for (i=0; i<a->naddrs; i++)
  807. if (a->addrs[i].tokens)
  808. {
  809. char *s=rfc822_getaddr(a, i);
  810. rfc822a_free(a);
  811. rfc822t_free(t);
  812. if (!s)
  813. rfc2045_enomem();
  814. return (s);
  815. }
  816. rfc822a_free(a);
  817. rfc822t_free(t);
  818. return (0);
  819. }
  820. static void content_id(struct rfc2045 *p, struct rfc822t *t)
  821. {
  822. struct rfc822a *a=rfc822a_alloc(t);
  823. int i;
  824. if (!a) rfc2045_enomem();
  825. for (i=0; i<a->naddrs; i++)
  826. if (a->addrs[i].tokens)
  827. {
  828. char *s=rfc822_getaddr(a, i);
  829. if (!s)
  830. {
  831. rfc822a_free(a);
  832. rfc2045_enomem();
  833. }
  834. if (p->content_id)
  835. free(p->content_id);
  836. p->content_id=s;
  837. break;
  838. }
  839. rfc822a_free(a);
  840. }
  841. static void content_description(struct rfc2045 *p, const char *s)
  842. {
  843. if (s && *s)
  844. set_string(&p->content_description, s);
  845. }
  846. static void content_language(struct rfc2045 *p, const char *s)
  847. {
  848. if (s && *s)
  849. set_string(&p->content_language, s);
  850. }
  851. static void content_md5(struct rfc2045 *p, const char *s)
  852. {
  853. if (s && *s)
  854. set_string(&p->content_md5, s);
  855. }
  856. static void content_base(struct rfc2045 *p, struct rfc822t *t)
  857. {
  858. char *s;
  859. int i;
  860. for (i=0; i<t->ntokens; i++)
  861. if (t->tokens[i].token == '"')
  862. t->tokens[i].token=0;
  863. s=paste_tokens(t, 2, t->ntokens-2);
  864. set_string(&p->content_base, s);
  865. }
  866. static void content_location(struct rfc2045 *p, struct rfc822t *t)
  867. {
  868. char *s;
  869. int i;
  870. for (i=0; i<t->ntokens; i++)
  871. if (t->tokens[i].token == '"')
  872. t->tokens[i].token=0;
  873. s=paste_tokens(t, 2, t->ntokens-2);
  874. set_string(&p->content_location, s);
  875. }
  876. /* -------------------- */
  877. #define GETINFO(s, def) ( (s) && (*s) ? (s):def)
  878. void rfc2045_mimeinfo(const struct rfc2045 *p,
  879. const char **content_type_s,
  880. const char **content_transfer_encoding_s,
  881. const char **charset_s)
  882. {
  883. const char *c;
  884. *content_type_s=GETINFO(p->content_type, "text/plain");
  885. *content_transfer_encoding_s=GETINFO(p->content_transfer_encoding,
  886. "8bit");
  887. c=rfc2045_getattr(p->content_type_attr, "charset");
  888. if (!c) c=rfc2045_getdefaultcharset();
  889. *charset_s=c;
  890. }
  891. const char *rfc2045_getdefaultcharset()
  892. {
  893. const char *p=rfc2045_defcharset;
  894. if (!p) p=RFC2045CHARSET;
  895. return (p);
  896. }
  897. void rfc2045_setdefaultcharset(const char *charset)
  898. {
  899. char *p=strdup(charset);
  900. if (!p) rfc2045_enomem();
  901. if (rfc2045_defcharset) free(rfc2045_defcharset);
  902. rfc2045_defcharset=p;
  903. }
  904. const char *rfc2045_boundary(const struct rfc2045 *p)
  905. {
  906. const char *cb=rfc2045_getattr( p->content_type_attr, "boundary");
  907. if (!cb) cb="";
  908. return (cb);
  909. }
  910. void rfc2045_dispositioninfo(const struct rfc2045 *p,
  911. const char **disposition_s,
  912. const char **disposition_name_s,
  913. const char **disposition_filename_s)
  914. {
  915. *disposition_s=p->content_disposition;
  916. *disposition_name_s=rfc2045_getattr(p->content_disposition_attr,
  917. "name");
  918. *disposition_filename_s=rfc2045_getattr(p->content_disposition_attr,
  919. "filename");
  920. }
  921. const char *rfc2045_contentname(const struct rfc2045 *p)
  922. {
  923. const char *q=rfc2045_getattr(p->content_type_attr, "name");
  924. if (!q) q="";
  925. return (q);
  926. }
  927. const char *rfc2045_content_id(const struct rfc2045 *p)
  928. {
  929. return (p->content_id ? p->content_id:"");
  930. }
  931. const char *rfc2045_content_description(const struct rfc2045 *p)
  932. {
  933. return (p->content_description ? p->content_description:"");
  934. }
  935. const char *rfc2045_content_language(const struct rfc2045 *p)
  936. {
  937. return (p->content_language ? p->content_language:"");
  938. }
  939. const char *rfc2045_content_md5(const struct rfc2045 *p)
  940. {
  941. return (p->content_md5 ? p->content_md5:"");
  942. }
  943. void rfc2045_mimepos(const struct rfc2045 *p,
  944. off_t *start_pos, off_t *end_pos, off_t *start_body,
  945. off_t *nlines, off_t *nbodylines)
  946. {
  947. *start_pos=p->startpos;
  948. *end_pos=p->endpos;
  949. *nlines=p->nlines;
  950. *nbodylines=p->nbodylines;
  951. if (p->parent) /* MIME parts do not have the trailing CRLF */
  952. {
  953. *end_pos=p->endbody;
  954. if (*nlines) --*nlines;
  955. if (*nbodylines) --*nbodylines;
  956. }
  957. *start_body=p->startbody;
  958. }
  959. unsigned rfc2045_mimepartcount(const struct rfc2045 *p)
  960. {
  961. const struct rfc2045 *q;
  962. unsigned n=0;
  963. for (q=p->firstpart; q; q=q->next) ++n;
  964. return (n);
  965. }