newmsg_newdraft.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:17k
- /*
- ** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
- ** distribution information.
- */
- /*
- ** $Id: newmsg_newdraft.c,v 1.25 2000/07/01 22:36:34 mrsam Exp $
- */
- #include "config.h"
- #include "cgi/cgi.h"
- #include "sqconfig.h"
- #include "sqwebmail.h"
- #include "auth.h"
- #include "pref.h"
- #include "maildir.h"
- #include "folder.h"
- #include "maildir/maildirmisc.h"
- #include "rfc822/rfc822.h"
- #include "rfc822/rfc2047.h"
- #include "rfc2045/rfc2045.h"
- #include <stdlib.h>
- #include <fcntl.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- extern const char *sqwebmail_mailboxid;
- extern const char *sqwebmail_content_charset;
- static int start_line;
- static int draftfd;
- extern const char mimemsg[];
- const char *dropre(const char *p, int *flag)
- {
- *flag=0;
- if (strncasecmp(p, "re", 2) == 0 && p[2] == ':')
- {
- p += 2;
- while (*p && strchr(": ", *p))
- ++p;
- *flag=1;
- }
- return(p);
- }
- static void forwardbody(FILE *fp, long nbytes)
- {
- char buf[512];
- int i;
- while ((i=nbytes > sizeof(buf) ? sizeof(buf):nbytes) > 0 &&
- (i=fread(buf, 1, i, fp)) > 0)
- {
- nbytes -= i;
- maildir_writemsg(draftfd, buf, i);
- }
- }
- static int quotereply(const char *p, size_t l, void *voidptr)
- {
- size_t i, j;
- for (i=j=0; i<l; i++)
- {
- if (p[i] == 'n')
- {
- if (start_line)
- maildir_writemsgstr(draftfd, "> ");
- start_line=0;
- maildir_writemsg(draftfd, p+j, i-j);
- maildir_writemsgstr(draftfd, "n");
- start_line=1;
- j=i+1;
- }
- }
- if (j < i)
- {
- if (start_line)
- maildir_writemsgstr(draftfd, "> ");
- start_line=0;
- maildir_writemsg(draftfd, p+j, i-j);
- }
- return (0);
- }
- /* We have to do something with the first text/plain MIME section we have
- ** in themessage */
- static void decode_textplain(FILE *fp, struct rfc2045 *rfc,
- int (*handler)(const char *, size_t, void *))
- {
- off_t start_pos, end_pos, start_body;
- char buf[512];
- int cnt;
- off_t dummy;
- rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
- &dummy, &dummy);
- if (fseek(fp, start_body, SEEK_SET) == -1) return;
- rfc2045_cdecode_start(rfc, handler, 0);
- start_line=1;
- while (start_body < end_pos)
- {
- cnt=sizeof(buf);
- if (cnt > end_pos-start_body)
- cnt=end_pos-start_body;
- cnt=fread(buf, 1, cnt, fp);
- if (cnt <= 0) break;
- rfc2045_cdecode(rfc, buf, cnt);
- start_body += cnt;
- }
- rfc2045_cdecode_end(rfc);
- }
- void newmsg_handletextplain(FILE *fp, struct rfc2045 *rfc,
- int (*handler)(const char *, size_t, void *))
- {
- const char *content_type, *dummy;
- rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
- if (strcmp(content_type, "text/plain") == 0)
- decode_textplain(fp, rfc, handler);
- else
- {
- struct rfc2045 *p;
- for (p=rfc->firstpart; p; p=p->next)
- {
- if (p->isdummy) continue;
- rfc2045_mimeinfo(p, &content_type, &dummy, &dummy);
- if (strcmp(content_type, "text/plain") == 0)
- break;
- if (strcmp(content_type, "multipart/alternative") == 0)
- return(newmsg_handletextplain(fp,p,handler));
- }
- if (p) decode_textplain(fp, p, handler);
- }
- }
- static void replybody(FILE *fp, struct rfc2045 *rfc)
- {
- newmsg_handletextplain(fp, rfc, "ereply);
- }
- static void newmsg_writesig(int d)
- {
- FILE *fp=fopen(SIGNATURE, "r");
- char buf[256];
- int n;
- if (!fp) return;
- maildir_writemsg(d, "nn", 2);
- while ((n=fread(buf, 1, sizeof(buf), fp)) > 0)
- maildir_writemsg(d, buf, n);
- fclose(fp);
- maildir_writemsg(d, "n", 1);
- }
- static void writereferences(int fd, const char *oldref, const char *oldmsgid)
- {
- char *buf=malloc((oldref ? strlen(oldref):0)
- + (oldmsgid ? strlen(oldmsgid):0)+2);
- char *p, *q;
- struct rfc822t *tp;
- struct rfc822a *ap;
- int i;
- if (!buf) enomem();
- /* Create new references header */
- *buf=0;
- if (oldref) strcat(buf, oldref);
- if (oldref && oldmsgid) strcat(buf, " ");
- if (oldmsgid) strcat(buf, oldmsgid);
- /* Do wrapping the RIGHT way, by
- ** RFC822 parsing the References: header
- */
- if ((tp=rfc822t_alloc(buf, NULL)) == 0 ||
- (ap=rfc822a_alloc(tp)) == 0)
- {
- enomem();
- return;
- }
- /* Keep only the last 20 message IDs */
- i=0;
- if (ap->naddrs > 20) i=ap->naddrs-20;
- p="";
- while (i < ap->naddrs)
- {
- q=rfc822_gettok(ap->addrs[i].tokens);
- if (!q) enomem();
- maildir_writemsgstr(fd, p);
- maildir_writemsgstr(fd, "<");
- maildir_writemsgstr(fd, q);
- maildir_writemsgstr(fd, ">n");
- p=" ";
- free(q);
- i++;
- }
- rfc822a_free(ap);
- rfc822t_free(tp);
- free(buf);
- }
- /*
- ** This functions creates a new draft message, which may be a reply or a
- ** forward of an existing message.
- */
- static struct rfc2045 *do_mixed_fwd(struct rfc2045 *, off_t *);
- char *newmsg_newdraft(const char *folder, const char *pos,
- const char *forwardsep, const char *replysalut)
- {
- char *filename=0;
- char *replymode;
- size_t pos_n;
- FILE *fp;
- char *header, *value;
- char *oldtocc, *oldfrom, *oldreplyto;
- char *subject;
- char *oldmsgid;
- char *draftfilename;
- char *whowrote;
- char *oldreferences;
- struct rfc2045 *rfc2045p, *rfc2045partp;
- const char *mimeidptr;
- off_t start_pos, end_pos, start_body, posptr;
- off_t dummy;
- int x;
- if (*cgi(replymode="reply") ||
- *cgi(replymode="replyall") ||
- *cgi(replymode="forward") ||
- *cgi(replymode="forwardatt"))
- {
- filename=maildir_posfind(folder, (pos_n=atol(pos), &pos_n));
- }
- if (!filename) return (0);
- fp=0;
- x=maildir_safeopen(filename, O_RDONLY, 0);
- if (x >= 0)
- if ((fp=fdopen(x, "r")) == 0)
- close(x);
- if (fp == 0)
- {
- free(filename);
- return (0);
- }
- rfc2045p=rfc2045_fromfp(fp);
- if (!rfc2045p) enomem();
- mimeidptr=cgi("mimeid");
- rfc2045partp=0;
- if (*mimeidptr)
- {
- rfc2045partp=rfc2045_find(rfc2045p, mimeidptr);
- if (rfc2045partp)
- {
- const char *content_type, *dummy;
- rfc2045_mimeinfo(rfc2045partp, &content_type,
- &dummy, &dummy);
- if (!content_type || strcmp(content_type, "message/rfc822"))
- rfc2045partp=0;
- else
- rfc2045partp=rfc2045partp->firstpart;
- }
- }
- if (!rfc2045partp)
- rfc2045partp=rfc2045p;
- oldtocc=0;
- oldfrom=0;
- oldreplyto=0;
- subject=0;
- oldmsgid=0;
- oldreferences=0;
- rfc2045_mimepos(rfc2045partp, &start_pos, &end_pos, &start_body,
- &dummy, &dummy);
- if (fseek(fp, start_pos, SEEK_SET) == -1)
- enomem();
- draftfd=maildir_createmsg(DRAFTS, 0, &draftfilename);
- if (draftfd < 0) enomem();
- whowrote=0;
- maildir_writemsgstr(draftfd, "From: ");
- {
- const char *f=pref_from;
- if (!f || !*f) f=login_fromhdr();
- if (!f) f="";
- maildir_writemsgstr(draftfd, f);
- maildir_writemsgstr(draftfd, "n");
- }
- if (strcmp(replymode, "forward") == 0 || strcmp(replymode, "forwardatt") == 0)
- {
- char *boundary=0;
- struct rfc2045 *mixed_fwd;
- off_t orig_startpos=start_pos;
- posptr=start_pos;
- while (posptr < end_pos &&
- (header=maildir_readheader(fp, &value, 0)) != 0)
- {
- posptr += strlen(header)+1;
- if (strcmp(header, "subject") == 0)
- {
- if (subject) free(subject);
- subject=malloc(strlen(value)+10);
- if (!subject) enomem();
- strcpy(subject, value);
- if (strlen(subject) > 255)
- subject[255]=' ';
- }
- }
- maildir_writemsgstr(draftfd, "Subject: ");
- if (subject)
- {
- int dummy;
- maildir_writemsgstr(draftfd, dropre(subject, &dummy));
- }
- maildir_writemsgstr(draftfd, " (fwd)nMime-Version: 1.0n");
- if ((mixed_fwd=strcmp(replymode, "forwardatt") == 0 ? 0:
- do_mixed_fwd(rfc2045p, &start_pos)) != 0)
- {
- /* Borrow boundary from the message */
- boundary=strdup(rfc2045_boundary(rfc2045p));
- if (!boundary) enomem();
- maildir_writemsgstr(draftfd,
- "Content-Type: multipart/mixed; boundary="");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd,
- ""nContent-Transfer-Encoding: 8bitnn");
- maildir_writemsgstr(draftfd, mimemsg);
- maildir_writemsgstr(draftfd, "--");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd, "n");
- }
- else
- if (strcmp(replymode, "forwardatt") == 0)
- {
- const char *content_type, *content_transfer_encoding, *charset;
- boundary=rfc2045_mk_boundary(rfc2045p, fileno(fp));
- if (!boundary) enomem();
- rfc2045_mimeinfo(rfc2045partp, &content_type,
- &content_transfer_encoding, &charset);
- maildir_writemsgstr(draftfd,
- "Content-Type: multipart/mixed; boundary="");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd,
- ""nContent-Transfer-Encoding: ");
- maildir_writemsgstr(draftfd, content_transfer_encoding);
- maildir_writemsgstr(draftfd,
- "nn");
- maildir_writemsgstr(draftfd, mimemsg);
- maildir_writemsgstr(draftfd, "--");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd, "n");
- }
- maildir_writemsgstr(draftfd,
- "Content-Type: text/plain; charset="");
- maildir_writemsgstr(draftfd, sqwebmail_content_charset);
- maildir_writemsgstr(draftfd, ""nn");
- newmsg_writesig(draftfd);
- maildir_writemsgstr(draftfd, "n");
- if (!boundary)
- {
- if (forwardsep)
- {
- maildir_writemsgstr(draftfd, forwardsep);
- maildir_writemsgstr(draftfd, "n");
- }
- }
- else if (mixed_fwd)
- {
- off_t txtbody, txtend, dummy;
- if (forwardsep)
- {
- maildir_writemsgstr(draftfd, forwardsep);
- maildir_writemsgstr(draftfd, "n");
- }
- /* Copy original headers. */
- if (fseek(fp, orig_startpos, SEEK_SET) == -1)
- enomem();
- forwardbody(fp, start_body - orig_startpos);
- rfc2045_mimepos(mixed_fwd, &dummy, &txtend, &txtbody,
- &dummy, &dummy);
- if (fseek(fp, txtbody, SEEK_SET) == -1)
- enomem();
- forwardbody(fp, txtend - txtbody);
- maildir_writemsgstr(draftfd, "n--");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd, "n");
- }
- else
- {
- maildir_writemsgstr(draftfd, "n--");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd,
- "nContent-Type: message/rfc822nn");
- }
- if (fseek(fp, start_pos, SEEK_SET) == -1)
- enomem();
- forwardbody(fp, end_pos - start_pos);
- if (boundary)
- {
- if (!mixed_fwd) /* Already copied */
- {
- maildir_writemsgstr(draftfd, "n--");
- maildir_writemsgstr(draftfd, boundary);
- maildir_writemsgstr(draftfd, "--n");
- }
- free(boundary);
- }
- }
- else
- {
- maildir_writemsgstr(draftfd, "X-Reply-To-Folder: ");
- maildir_writemsgstr(draftfd, folder);
- maildir_writemsgstr(draftfd, "nX-Reply-To-Msg: ");
- {
- char *basename=maildir_basename(filename);
- maildir_writemsgstr(draftfd, basename);
- free(basename);
- }
- maildir_writemsgstr(draftfd, "n");
- posptr=start_pos;
- while (posptr < end_pos &&
- (header=maildir_readheader(fp, &value, 0)) != 0)
- {
- posptr += strlen(header)+1;
- if (strcmp(header, "subject") == 0)
- {
- if (subject) free(subject);
- subject=strdup(value);
- if (!subject) enomem();
- }
- else if (strcmp(header, "reply-to") == 0)
- {
- if (oldreplyto) free(oldreplyto);
- oldreplyto=strdup(value);
- if (!oldreplyto) enomem();
- }
- else if (strcmp(header, "from") == 0)
- {
- if (oldfrom) free(oldfrom);
- oldfrom=strdup(value);
- if (!oldfrom) enomem();
- }
- else if (strcmp(header, "message-id") == 0)
- {
- if (oldmsgid) free(oldmsgid);
- oldmsgid=strdup(value);
- if (!oldmsgid) enomem();
- }
- else if (strcmp(header, "references") == 0)
- {
- if (oldreferences) free(oldreferences);
- oldreferences=strdup(value);
- if (!oldreferences) enomem();
- }
- else if (strcmp(replymode, "replyall") == 0 &&
- (
- strcmp(header, "to") == 0 ||
- strcmp(header, "cc") == 0
- )
- )
- {
- char *newh=malloc( (oldtocc ?
- strlen(oldtocc):0)
- + strlen(value)+2);
- if (!newh) enomem();
- *newh=0;
- if (oldtocc)
- strcat(strcpy(newh, oldtocc),
- ",");
- strcat(newh, value);
- if (oldtocc) free(oldtocc);
- oldtocc=newh;
- }
- }
- /* Write: "%s writes:" */
- if (oldfrom)
- {
- struct rfc822t *rfcp=rfc822t_alloc(oldfrom, NULL);
- struct rfc822a *rfcpa;
- char *p, *q;
- if (!rfcp) enomem();
- rfcpa=rfc822a_alloc(rfcp);
- if (!rfcpa) enomem();
- p= rfcpa->naddrs > 0 ?
- rfc822_getname(rfcpa, 0):0;
- rfc822a_free(rfcpa);
- rfc822t_free(rfcp);
- if (!p) p=strdup(oldfrom);
- if (!p) enomem();
- q=rfc2047_decode_enhanced(p, sqwebmail_content_charset);
- if (!q) enomem();
- free(p);
- p=q;
- whowrote=malloc(strlen(p)+strlen(replysalut)+1);
- if (!whowrote) enomem();
- sprintf(whowrote, replysalut, p);
- free(p);
- }
- if (oldreplyto)
- {
- if (oldfrom) free(oldfrom);
- oldfrom=oldreplyto;
- oldreplyto=0;
- }
- /* Remove duplicate entries from new Cc header */
- if (oldtocc)
- {
- struct rfc822t *rfccc, *rfcto;
- struct rfc822a *arfccc, *arfcto;
- int i, j;
- const char *returnaddr= login_returnaddr();
- char *new_addresses;
- rfccc=rfc822t_alloc(oldtocc, NULL);
- rfcto= oldfrom ? rfc822t_alloc(oldfrom, NULL):NULL;
- arfccc=rfccc ? rfc822a_alloc(rfccc):NULL;
- arfcto=rfcto ? rfc822a_alloc(rfcto):NULL;
- for (i=0; arfccc && i <arfccc->naddrs; i++)
- {
- char *addr=rfc822_getaddr(arfccc, i);
- if (!addr) continue;
- /* Remove address from Cc if it is my address */
- if (strcmp(addr, returnaddr) == 0)
- {
- rfc822_deladdr(arfccc, i); --i;
- free(addr);
- continue;
- }
- /* Remove address from Cc if it appears in To: */
- for (j=0; arfcto && j < arfcto->naddrs; j++)
- {
- char *addr2=rfc822_getaddr(arfcto, j);
- if (!addr2) continue;
- if (strcmp(addr, addr2) == 0)
- {
- free(addr2);
- break;
- }
- free(addr2);
- }
- if (arfcto && j < arfcto->naddrs)
- {
- rfc822_deladdr(arfccc, i); --i;
- free(addr);
- continue;
- }
- /* Remove outright duplicates in Cc */
- for (j=i+1; j<arfccc->naddrs; j++)
- {
- char *addr2=rfc822_getaddr(arfccc, j);
- if (!addr2) continue;
- if (strcmp(addr, addr2) == 0)
- {
- rfc822_deladdr(arfccc, j);
- --j;
- }
- free(addr2);
- }
- free(addr);
- }
- new_addresses=rfc822_getaddrs(arfccc);
- free(oldtocc);
- oldtocc=new_addresses;
- if (arfccc) rfc822a_free(arfccc);
- if (arfcto) rfc822a_free(arfcto);
- rfc822t_free(rfccc);
- if (rfcto) rfc822t_free(rfcto);
- }
- if (oldfrom)
- {
- maildir_writemsgstr(draftfd, "To: ");
- maildir_writemsgstr(draftfd, oldfrom);
- maildir_writemsgstr(draftfd, "n");
- free(oldfrom);
- }
- if (oldtocc)
- {
- maildir_writemsgstr(draftfd, "Cc: ");
- maildir_writemsgstr(draftfd, oldtocc);
- maildir_writemsgstr(draftfd, "n");
- free(oldtocc);
- }
- if (oldmsgid || oldreferences)
- {
- maildir_writemsgstr(draftfd, "References: ");
- writereferences(draftfd, oldreferences, oldmsgid);
- if (oldreferences) free(oldreferences);
- }
- if (oldmsgid)
- {
- maildir_writemsgstr(draftfd, "In-Reply-To: ");
- maildir_writemsgstr(draftfd, oldmsgid);
- maildir_writemsgstr(draftfd, "n");
- free(oldmsgid);
- }
- maildir_writemsgstr(draftfd, "Subject: Re: ");
- if (subject)
- {
- int dummy;
- maildir_writemsgstr(draftfd, dropre(subject, &dummy));
- free(subject);
- }
- maildir_writemsgstr(draftfd, "nn");
- if (whowrote)
- {
- maildir_writemsgstr(draftfd, whowrote);
- free(whowrote);
- maildir_writemsgstr(draftfd, "nn");
- }
- if (fseek(fp, start_body, SEEK_SET) == -1)
- enomem();
- replybody(fp, rfc2045partp);
- newmsg_writesig(draftfd);
- }
- fclose(fp);
- if (maildir_closemsg(draftfd, DRAFTS, draftfilename, 1, 0))
- {
- free(draftfilename);
- draftfilename=0;
- cgi_put("error", "quota");
- }
- free(filename);
- rfc2045_free(rfc2045p);
- return(draftfilename);
- }
- /*****************************************************************************
- **
- ** do_mixed_fwd determines if what we should create for forwarding should be
- ** a mixture of a portion of the original message, plus attachments. This
- ** should happen when the original message has attachments. Normally, we
- ** either forward the entire message as text/plain, or as a message/rfc822
- ** attachment. When the original message has attachments, it's preferrable
- ** to keep the original attachments as attachments of the forward message,
- ** while putting the text portion of the original message in the forwarded
- ** body.
- **
- ** So, what we check here is this:
- **
- ** A) This is a multipart message with at least two parts.
- ** B) The first part is text/plain (if it's text/html we'll just quote the
- ** whole mess too). If the first part is multipart/alternative, look
- ** inside the multipart/alternative for the text/plain section.
- **
- ** If this is not the case, we return NULL. Otherwise we return the
- ** rfc2045 pointer to the text/plain section, and the starting position
- ** of the first attachment (it's used to reset the starting position of
- ** the portion of the original message that's copied into the forwarding
- ** message).
- */
- static struct rfc2045 *do_mixed_fwd(struct rfc2045 *p, off_t *f)
- {
- const char *content_type, *dummy;
- off_t dummyp;
- if (!p->firstpart || !p->firstpart->isdummy ||
- !p->firstpart->next || !p->firstpart->next->next)
- return (0);
- rfc2045_mimepos(p->firstpart->next->next, f, &dummyp, &dummyp,
- &dummyp, &dummyp);
- p=p->firstpart->next;
- rfc2045_mimeinfo(p, &content_type, &dummy, &dummy);
- if (strcmp(content_type, "text/plain") &&
- strcmp(content_type, "text/html") /* GRUMBLE */)
- {
- if (strcmp(content_type, "multipart/alternative"))
- return (0);
- for (p=p->firstpart; p; p=p->next)
- {
- if (p->isdummy) continue;
- rfc2045_mimeinfo(p, &content_type, &dummy, &dummy);
- if (strcmp(content_type, "text/plain") == 0)
- break;
- }
- if (!p) return (0);
- }
- return (p);
- }