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

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 2000 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. /*
  6. ** $Id: newmsg_newdraft.c,v 1.25 2000/07/01 22:36:34 mrsam Exp $
  7. */
  8. #include "config.h"
  9. #include "cgi/cgi.h"
  10. #include "sqconfig.h"
  11. #include "sqwebmail.h"
  12. #include "auth.h"
  13. #include "pref.h"
  14. #include "maildir.h"
  15. #include "folder.h"
  16. #include "maildir/maildirmisc.h"
  17. #include "rfc822/rfc822.h"
  18. #include "rfc822/rfc2047.h"
  19. #include "rfc2045/rfc2045.h"
  20. #include <stdlib.h>
  21. #include <fcntl.h>
  22. #if HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. extern const char *sqwebmail_mailboxid;
  26. extern const char *sqwebmail_content_charset;
  27. static int start_line;
  28. static int draftfd;
  29. extern const char mimemsg[];
  30. const char *dropre(const char *p, int *flag)
  31. {
  32. *flag=0;
  33. if (strncasecmp(p, "re", 2) == 0 && p[2] == ':')
  34. {
  35. p += 2;
  36. while (*p && strchr(": ", *p))
  37. ++p;
  38. *flag=1;
  39. }
  40. return(p);
  41. }
  42. static void forwardbody(FILE *fp, long nbytes)
  43. {
  44. char buf[512];
  45. int i;
  46. while ((i=nbytes > sizeof(buf) ? sizeof(buf):nbytes) > 0 &&
  47. (i=fread(buf, 1, i, fp)) > 0)
  48. {
  49. nbytes -= i;
  50. maildir_writemsg(draftfd, buf, i);
  51. }
  52. }
  53. static int quotereply(const char *p, size_t l, void *voidptr)
  54. {
  55. size_t i, j;
  56. for (i=j=0; i<l; i++)
  57. {
  58. if (p[i] == 'n')
  59. {
  60. if (start_line)
  61. maildir_writemsgstr(draftfd, "> ");
  62. start_line=0;
  63. maildir_writemsg(draftfd, p+j, i-j);
  64. maildir_writemsgstr(draftfd, "n");
  65. start_line=1;
  66. j=i+1;
  67. }
  68. }
  69. if (j < i)
  70. {
  71. if (start_line)
  72. maildir_writemsgstr(draftfd, "> ");
  73. start_line=0;
  74. maildir_writemsg(draftfd, p+j, i-j);
  75. }
  76. return (0);
  77. }
  78. /* We have to do something with the first text/plain MIME section we have
  79. ** in themessage */
  80. static void decode_textplain(FILE *fp, struct rfc2045 *rfc,
  81. int (*handler)(const char *, size_t, void *))
  82. {
  83. off_t start_pos, end_pos, start_body;
  84. char buf[512];
  85. int cnt;
  86. off_t dummy;
  87. rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
  88. &dummy, &dummy);
  89. if (fseek(fp, start_body, SEEK_SET) == -1) return;
  90.         rfc2045_cdecode_start(rfc, handler, 0);
  91. start_line=1;
  92.         while (start_body < end_pos)
  93.         {
  94.                 cnt=sizeof(buf);
  95.                 if (cnt > end_pos-start_body)
  96.                         cnt=end_pos-start_body;
  97.                 cnt=fread(buf, 1, cnt, fp);
  98.                 if (cnt <= 0)   break;
  99.                 rfc2045_cdecode(rfc, buf, cnt);
  100. start_body += cnt;
  101.         }
  102.         rfc2045_cdecode_end(rfc);
  103. }
  104. void newmsg_handletextplain(FILE *fp, struct rfc2045 *rfc,
  105. int (*handler)(const char *, size_t, void *))
  106. {
  107. const char *content_type, *dummy;
  108.         rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
  109. if (strcmp(content_type, "text/plain") == 0)
  110. decode_textplain(fp, rfc, handler);
  111. else
  112. {
  113. struct rfc2045 *p;
  114. for (p=rfc->firstpart; p; p=p->next)
  115. {
  116. if (p->isdummy) continue;
  117. rfc2045_mimeinfo(p, &content_type, &dummy, &dummy);
  118. if (strcmp(content_type, "text/plain") == 0)
  119. break;
  120. if (strcmp(content_type, "multipart/alternative") == 0)
  121. return(newmsg_handletextplain(fp,p,handler));
  122. }
  123. if (p) decode_textplain(fp, p, handler);
  124. }
  125. }
  126. static void replybody(FILE *fp, struct rfc2045 *rfc)
  127. {
  128. newmsg_handletextplain(fp, rfc, &quotereply);
  129. }
  130. static void newmsg_writesig(int d)
  131. {
  132. FILE *fp=fopen(SIGNATURE, "r");
  133. char buf[256];
  134. int n;
  135. if (!fp) return;
  136. maildir_writemsg(d, "nn", 2);
  137. while ((n=fread(buf, 1, sizeof(buf), fp)) > 0)
  138. maildir_writemsg(d, buf, n);
  139. fclose(fp);
  140. maildir_writemsg(d, "n", 1);
  141. }
  142. static void writereferences(int fd, const char *oldref, const char *oldmsgid)
  143. {
  144. char *buf=malloc((oldref ? strlen(oldref):0)
  145. + (oldmsgid ? strlen(oldmsgid):0)+2);
  146. char *p, *q;
  147. struct rfc822t *tp;
  148. struct rfc822a *ap;
  149. int i;
  150. if (!buf) enomem();
  151. /* Create new references header */
  152. *buf=0;
  153. if (oldref) strcat(buf, oldref);
  154. if (oldref && oldmsgid) strcat(buf, " ");
  155. if (oldmsgid) strcat(buf, oldmsgid);
  156. /* Do wrapping the RIGHT way, by
  157. ** RFC822 parsing the References: header
  158. */
  159. if ((tp=rfc822t_alloc(buf, NULL)) == 0 ||
  160. (ap=rfc822a_alloc(tp)) == 0)
  161. {
  162. enomem();
  163. return;
  164. }
  165. /* Keep only the last 20 message IDs */
  166. i=0;
  167. if (ap->naddrs > 20) i=ap->naddrs-20;
  168. p="";
  169. while (i < ap->naddrs)
  170. {
  171. q=rfc822_gettok(ap->addrs[i].tokens);
  172. if (!q) enomem();
  173. maildir_writemsgstr(fd, p);
  174. maildir_writemsgstr(fd, "<");
  175. maildir_writemsgstr(fd, q);
  176. maildir_writemsgstr(fd, ">n");
  177. p="            ";
  178. free(q);
  179. i++;
  180. }
  181. rfc822a_free(ap);
  182. rfc822t_free(tp);
  183. free(buf);
  184. }
  185. /*
  186. ** This functions creates a new draft message, which may be a reply or a
  187. ** forward of an existing message.
  188. */
  189. static struct rfc2045 *do_mixed_fwd(struct rfc2045 *, off_t *);
  190. char *newmsg_newdraft(const char *folder, const char *pos,
  191. const char *forwardsep, const char *replysalut)
  192. {
  193. char *filename=0;
  194. char *replymode;
  195. size_t pos_n;
  196. FILE *fp;
  197. char *header, *value;
  198. char *oldtocc, *oldfrom, *oldreplyto;
  199. char *subject;
  200. char *oldmsgid;
  201. char *draftfilename;
  202. char *whowrote;
  203. char *oldreferences;
  204. struct rfc2045 *rfc2045p, *rfc2045partp;
  205. const char *mimeidptr;
  206. off_t start_pos, end_pos, start_body, posptr;
  207. off_t dummy;
  208. int x;
  209. if (*cgi(replymode="reply") ||
  210. *cgi(replymode="replyall") ||
  211. *cgi(replymode="forward") ||
  212. *cgi(replymode="forwardatt"))
  213. {
  214. filename=maildir_posfind(folder, (pos_n=atol(pos), &pos_n));
  215. }
  216. if (!filename) return (0);
  217. fp=0;
  218. x=maildir_safeopen(filename, O_RDONLY, 0);
  219. if (x >= 0)
  220. if ((fp=fdopen(x, "r")) == 0)
  221. close(x);
  222. if (fp == 0)
  223. {
  224. free(filename);
  225. return (0);
  226. }
  227. rfc2045p=rfc2045_fromfp(fp);
  228. if (!rfc2045p) enomem();
  229. mimeidptr=cgi("mimeid");
  230. rfc2045partp=0;
  231. if (*mimeidptr)
  232. {
  233. rfc2045partp=rfc2045_find(rfc2045p, mimeidptr);
  234. if (rfc2045partp)
  235. {
  236. const char      *content_type, *dummy;
  237. rfc2045_mimeinfo(rfc2045partp, &content_type,
  238. &dummy, &dummy);
  239. if (!content_type || strcmp(content_type, "message/rfc822"))
  240. rfc2045partp=0;
  241. else
  242. rfc2045partp=rfc2045partp->firstpart;
  243. }
  244. }
  245. if (!rfc2045partp)
  246. rfc2045partp=rfc2045p;
  247. oldtocc=0;
  248. oldfrom=0;
  249. oldreplyto=0;
  250. subject=0;
  251. oldmsgid=0;
  252. oldreferences=0;
  253. rfc2045_mimepos(rfc2045partp, &start_pos, &end_pos, &start_body,
  254. &dummy, &dummy);
  255.         if (fseek(fp, start_pos, SEEK_SET) == -1)
  256.                 enomem();
  257. draftfd=maildir_createmsg(DRAFTS, 0, &draftfilename);
  258. if (draftfd < 0) enomem();
  259. whowrote=0;
  260. maildir_writemsgstr(draftfd, "From: ");
  261. {
  262. const char *f=pref_from;
  263. if (!f || !*f) f=login_fromhdr();
  264. if (!f) f="";
  265. maildir_writemsgstr(draftfd, f);
  266. maildir_writemsgstr(draftfd, "n");
  267. }
  268. if (strcmp(replymode, "forward") == 0 || strcmp(replymode, "forwardatt") == 0)
  269. {
  270. char *boundary=0;
  271. struct rfc2045 *mixed_fwd;
  272. off_t orig_startpos=start_pos;
  273. posptr=start_pos;
  274. while (posptr < end_pos &&
  275. (header=maildir_readheader(fp, &value, 0)) != 0)
  276. {
  277. posptr += strlen(header)+1;
  278. if (strcmp(header, "subject") == 0)
  279. {
  280. if (subject) free(subject);
  281. subject=malloc(strlen(value)+10);
  282. if (!subject) enomem();
  283. strcpy(subject, value);
  284. if (strlen(subject) > 255)
  285. subject[255]='';
  286. }
  287. }
  288. maildir_writemsgstr(draftfd, "Subject: ");
  289. if (subject)
  290. {
  291. int dummy;
  292. maildir_writemsgstr(draftfd, dropre(subject, &dummy));
  293. }
  294. maildir_writemsgstr(draftfd, " (fwd)nMime-Version: 1.0n");
  295. if ((mixed_fwd=strcmp(replymode, "forwardatt") == 0 ? 0:
  296. do_mixed_fwd(rfc2045p, &start_pos)) != 0)
  297. {
  298. /* Borrow boundary from the message */
  299. boundary=strdup(rfc2045_boundary(rfc2045p));
  300. if (!boundary) enomem();
  301. maildir_writemsgstr(draftfd,
  302. "Content-Type: multipart/mixed; boundary="");
  303. maildir_writemsgstr(draftfd, boundary);
  304. maildir_writemsgstr(draftfd,
  305. ""nContent-Transfer-Encoding: 8bitnn");
  306. maildir_writemsgstr(draftfd, mimemsg);
  307. maildir_writemsgstr(draftfd, "--");
  308. maildir_writemsgstr(draftfd, boundary);
  309. maildir_writemsgstr(draftfd, "n");
  310. }
  311. else
  312. if (strcmp(replymode, "forwardatt") == 0)
  313. {
  314. const char *content_type, *content_transfer_encoding, *charset;
  315. boundary=rfc2045_mk_boundary(rfc2045p, fileno(fp));
  316. if (!boundary) enomem();
  317. rfc2045_mimeinfo(rfc2045partp, &content_type,
  318. &content_transfer_encoding, &charset);
  319. maildir_writemsgstr(draftfd,
  320. "Content-Type: multipart/mixed; boundary="");
  321. maildir_writemsgstr(draftfd, boundary);
  322. maildir_writemsgstr(draftfd,
  323. ""nContent-Transfer-Encoding: ");
  324. maildir_writemsgstr(draftfd, content_transfer_encoding);
  325. maildir_writemsgstr(draftfd,
  326. "nn");
  327. maildir_writemsgstr(draftfd, mimemsg);
  328. maildir_writemsgstr(draftfd, "--");
  329. maildir_writemsgstr(draftfd, boundary);
  330. maildir_writemsgstr(draftfd, "n");
  331. }
  332. maildir_writemsgstr(draftfd,
  333. "Content-Type: text/plain; charset="");
  334. maildir_writemsgstr(draftfd, sqwebmail_content_charset);
  335. maildir_writemsgstr(draftfd, ""nn");
  336. newmsg_writesig(draftfd);
  337. maildir_writemsgstr(draftfd, "n");
  338. if (!boundary)
  339. {
  340. if (forwardsep)
  341. {
  342. maildir_writemsgstr(draftfd, forwardsep);
  343. maildir_writemsgstr(draftfd, "n");
  344. }
  345. }
  346. else if (mixed_fwd)
  347. {
  348. off_t txtbody, txtend, dummy;
  349. if (forwardsep)
  350. {
  351. maildir_writemsgstr(draftfd, forwardsep);
  352. maildir_writemsgstr(draftfd, "n");
  353. }
  354. /* Copy original headers. */
  355. if (fseek(fp, orig_startpos, SEEK_SET) == -1)
  356. enomem();
  357. forwardbody(fp, start_body - orig_startpos);
  358. rfc2045_mimepos(mixed_fwd, &dummy, &txtend, &txtbody,
  359. &dummy, &dummy);
  360. if (fseek(fp, txtbody, SEEK_SET) == -1)
  361. enomem();
  362. forwardbody(fp, txtend - txtbody);
  363. maildir_writemsgstr(draftfd, "n--");
  364. maildir_writemsgstr(draftfd, boundary);
  365. maildir_writemsgstr(draftfd, "n");
  366. }
  367. else
  368. {
  369. maildir_writemsgstr(draftfd, "n--");
  370. maildir_writemsgstr(draftfd, boundary);
  371. maildir_writemsgstr(draftfd,
  372. "nContent-Type: message/rfc822nn");
  373. }
  374. if (fseek(fp, start_pos, SEEK_SET) == -1)
  375. enomem();
  376. forwardbody(fp, end_pos - start_pos);
  377. if (boundary)
  378. {
  379. if (!mixed_fwd) /* Already copied */
  380. {
  381. maildir_writemsgstr(draftfd, "n--");
  382. maildir_writemsgstr(draftfd, boundary);
  383. maildir_writemsgstr(draftfd, "--n");
  384. }
  385. free(boundary);
  386. }
  387. }
  388. else
  389. {
  390. maildir_writemsgstr(draftfd, "X-Reply-To-Folder: ");
  391. maildir_writemsgstr(draftfd, folder);
  392. maildir_writemsgstr(draftfd, "nX-Reply-To-Msg: ");
  393. {
  394. char *basename=maildir_basename(filename);
  395. maildir_writemsgstr(draftfd, basename);
  396. free(basename);
  397. }
  398. maildir_writemsgstr(draftfd, "n");
  399. posptr=start_pos;
  400. while (posptr < end_pos &&
  401. (header=maildir_readheader(fp, &value, 0)) != 0)
  402. {
  403. posptr += strlen(header)+1;
  404. if (strcmp(header, "subject") == 0)
  405. {
  406. if (subject) free(subject);
  407. subject=strdup(value);
  408. if (!subject) enomem();
  409. }
  410. else if (strcmp(header, "reply-to") == 0)
  411. {
  412. if (oldreplyto) free(oldreplyto);
  413. oldreplyto=strdup(value);
  414. if (!oldreplyto) enomem();
  415. }
  416. else if (strcmp(header, "from") == 0)
  417. {
  418. if (oldfrom) free(oldfrom);
  419. oldfrom=strdup(value);
  420. if (!oldfrom) enomem();
  421. }
  422. else if (strcmp(header, "message-id") == 0)
  423. {
  424. if (oldmsgid) free(oldmsgid);
  425. oldmsgid=strdup(value);
  426. if (!oldmsgid) enomem();
  427. }
  428. else if (strcmp(header, "references") == 0)
  429. {
  430. if (oldreferences) free(oldreferences);
  431. oldreferences=strdup(value);
  432. if (!oldreferences) enomem();
  433. }
  434. else if (strcmp(replymode, "replyall") == 0 &&
  435. (
  436. strcmp(header, "to") == 0 ||
  437. strcmp(header, "cc") == 0
  438. )
  439. )
  440. {
  441. char *newh=malloc( (oldtocc ?
  442. strlen(oldtocc):0)
  443. + strlen(value)+2);
  444. if (!newh) enomem();
  445. *newh=0;
  446. if (oldtocc)
  447. strcat(strcpy(newh, oldtocc),
  448. ",");
  449. strcat(newh, value);
  450. if (oldtocc) free(oldtocc);
  451. oldtocc=newh;
  452. }
  453. }
  454. /* Write:  "%s writes:" */
  455. if (oldfrom)
  456. {
  457. struct rfc822t *rfcp=rfc822t_alloc(oldfrom, NULL);
  458. struct rfc822a *rfcpa;
  459. char *p, *q;
  460. if (!rfcp) enomem();
  461. rfcpa=rfc822a_alloc(rfcp);
  462. if (!rfcpa) enomem();
  463. p= rfcpa->naddrs > 0 ?
  464. rfc822_getname(rfcpa, 0):0;
  465. rfc822a_free(rfcpa);
  466. rfc822t_free(rfcp);
  467. if (!p) p=strdup(oldfrom);
  468. if (!p) enomem();
  469. q=rfc2047_decode_enhanced(p, sqwebmail_content_charset);
  470. if (!q) enomem();
  471. free(p);
  472. p=q;
  473. whowrote=malloc(strlen(p)+strlen(replysalut)+1);
  474. if (!whowrote) enomem();
  475. sprintf(whowrote, replysalut, p);
  476. free(p);
  477. }
  478. if (oldreplyto)
  479. {
  480. if (oldfrom) free(oldfrom);
  481. oldfrom=oldreplyto;
  482. oldreplyto=0;
  483. }
  484. /* Remove duplicate entries from new Cc header */
  485. if (oldtocc)
  486. {
  487. struct rfc822t *rfccc, *rfcto;
  488. struct rfc822a *arfccc, *arfcto;
  489. int i, j;
  490. const char *returnaddr= login_returnaddr();
  491. char *new_addresses;
  492. rfccc=rfc822t_alloc(oldtocc, NULL);
  493. rfcto= oldfrom ? rfc822t_alloc(oldfrom, NULL):NULL;
  494. arfccc=rfccc ? rfc822a_alloc(rfccc):NULL;
  495. arfcto=rfcto ? rfc822a_alloc(rfcto):NULL;
  496. for (i=0; arfccc && i <arfccc->naddrs; i++)
  497. {
  498. char *addr=rfc822_getaddr(arfccc, i);
  499. if (!addr) continue;
  500. /* Remove address from Cc if it is my address */
  501. if (strcmp(addr, returnaddr) == 0)
  502. {
  503. rfc822_deladdr(arfccc, i); --i;
  504. free(addr);
  505. continue;
  506. }
  507. /* Remove address from Cc if it appears in To: */
  508. for (j=0; arfcto && j < arfcto->naddrs; j++)
  509. {
  510. char *addr2=rfc822_getaddr(arfcto, j);
  511. if (!addr2) continue;
  512. if (strcmp(addr, addr2) == 0)
  513. {
  514. free(addr2);
  515. break;
  516. }
  517. free(addr2);
  518. }
  519. if (arfcto && j < arfcto->naddrs)
  520. {
  521. rfc822_deladdr(arfccc, i); --i;
  522. free(addr);
  523. continue;
  524. }
  525. /* Remove outright duplicates in Cc */
  526. for (j=i+1; j<arfccc->naddrs; j++)
  527. {
  528. char *addr2=rfc822_getaddr(arfccc, j);
  529. if (!addr2) continue;
  530. if (strcmp(addr, addr2) == 0)
  531. {
  532. rfc822_deladdr(arfccc, j);
  533. --j;
  534. }
  535. free(addr2);
  536. }
  537. free(addr);
  538. }
  539. new_addresses=rfc822_getaddrs(arfccc);
  540. free(oldtocc);
  541. oldtocc=new_addresses;
  542. if (arfccc) rfc822a_free(arfccc);
  543. if (arfcto) rfc822a_free(arfcto);
  544. rfc822t_free(rfccc);
  545. if (rfcto) rfc822t_free(rfcto);
  546. }
  547. if (oldfrom)
  548. {
  549. maildir_writemsgstr(draftfd, "To: ");
  550. maildir_writemsgstr(draftfd, oldfrom);
  551. maildir_writemsgstr(draftfd, "n");
  552. free(oldfrom);
  553. }
  554. if (oldtocc)
  555. {
  556. maildir_writemsgstr(draftfd, "Cc: ");
  557. maildir_writemsgstr(draftfd, oldtocc);
  558. maildir_writemsgstr(draftfd, "n");
  559. free(oldtocc);
  560. }
  561. if (oldmsgid || oldreferences)
  562. {
  563. maildir_writemsgstr(draftfd, "References: ");
  564. writereferences(draftfd, oldreferences, oldmsgid);
  565. if (oldreferences) free(oldreferences);
  566. }
  567. if (oldmsgid)
  568. {
  569. maildir_writemsgstr(draftfd, "In-Reply-To: ");
  570. maildir_writemsgstr(draftfd, oldmsgid);
  571. maildir_writemsgstr(draftfd, "n");
  572. free(oldmsgid);
  573. }
  574. maildir_writemsgstr(draftfd, "Subject: Re: ");
  575. if (subject)
  576. {
  577. int dummy;
  578. maildir_writemsgstr(draftfd, dropre(subject, &dummy));
  579. free(subject);
  580. }
  581. maildir_writemsgstr(draftfd, "nn");
  582. if (whowrote)
  583. {
  584. maildir_writemsgstr(draftfd, whowrote);
  585. free(whowrote);
  586. maildir_writemsgstr(draftfd, "nn");
  587. }
  588. if (fseek(fp, start_body, SEEK_SET) == -1)
  589. enomem();
  590. replybody(fp, rfc2045partp);
  591. newmsg_writesig(draftfd);
  592. }
  593. fclose(fp);
  594. if (maildir_closemsg(draftfd, DRAFTS, draftfilename, 1, 0))
  595. {
  596. free(draftfilename);
  597. draftfilename=0;
  598. cgi_put("error", "quota");
  599. }
  600. free(filename);
  601. rfc2045_free(rfc2045p);
  602. return(draftfilename);
  603. }
  604. /*****************************************************************************
  605. **
  606. ** do_mixed_fwd determines if what we should create for forwarding should be
  607. ** a mixture of a portion of the original message, plus attachments.  This
  608. ** should happen when the original message has attachments.  Normally, we
  609. ** either forward the entire message as text/plain, or as a message/rfc822
  610. ** attachment.  When the original message has attachments, it's preferrable
  611. ** to keep the original attachments as attachments of the forward message,
  612. ** while putting the text portion of the original message in the forwarded
  613. ** body.
  614. **
  615. ** So, what we check here is this:
  616. **
  617. ** A) This is a multipart message with at least two parts.
  618. ** B) The first part is text/plain (if it's text/html we'll just quote the
  619. **    whole mess too).  If the first part is multipart/alternative, look
  620. **    inside the multipart/alternative for the text/plain section.
  621. **
  622. ** If this is not the case, we return NULL.  Otherwise we return the
  623. ** rfc2045 pointer to the text/plain section, and the starting position
  624. ** of the first attachment (it's used to reset the starting position of
  625. ** the portion of the original message that's copied into the forwarding
  626. ** message).
  627. */
  628. static struct rfc2045 *do_mixed_fwd(struct rfc2045 *p, off_t *f)
  629. {
  630. const char *content_type, *dummy;
  631. off_t dummyp;
  632. if (!p->firstpart || !p->firstpart->isdummy ||
  633. !p->firstpart->next || !p->firstpart->next->next)
  634. return (0);
  635. rfc2045_mimepos(p->firstpart->next->next, f, &dummyp, &dummyp,
  636. &dummyp, &dummyp);
  637. p=p->firstpart->next;
  638. rfc2045_mimeinfo(p, &content_type, &dummy, &dummy);
  639. if (strcmp(content_type, "text/plain") &&
  640. strcmp(content_type, "text/html") /* GRUMBLE */)
  641. {
  642. if (strcmp(content_type, "multipart/alternative"))
  643. return (0);
  644. for (p=p->firstpart; p; p=p->next)
  645. {
  646. if (p->isdummy) continue;
  647. rfc2045_mimeinfo(p, &content_type, &dummy, &dummy);
  648. if (strcmp(content_type, "text/plain") == 0)
  649. break;
  650. }
  651. if (!p) return (0);
  652. }
  653. return (p);
  654. }