newmsg_create.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:19k
- /*
- ** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
- ** distribution information.
- */
- /*
- ** $Id: newmsg_create.c,v 1.29 2000/06/18 01:26:21 mrsam Exp $
- */
- #include "config.h"
- #include "cgi/cgi.h"
- #include "sqconfig.h"
- #include "sqwebmail.h"
- #include "auth.h"
- #include "maildir.h"
- #include "folder.h"
- #include "filter.h"
- #include "pref.h"
- #include "addressbook.h"
- #include "maildir/maildirmisc.h"
- #include "rfc822/rfc822.h"
- #include "rfc2045/rfc2045.h"
- #include "rfc822/rfc2047.h"
- #include "http11/http11.h"
- #include "htmllibdir.h"
- #include <stdlib.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <ctype.h>
- #include <fcntl.h>
- extern const char *rfc822_mkdt(time_t);
- extern const char *sqwebmail_content_charset;
- extern const char *sqwebmail_content_language;
- int newdraftfd;
- extern const char *sqwebmail_mailboxid;
- const char mimemsg[]="This is a MIME-formatted message. If you see this text it means that yournmail software cannot handle MIME-formatted messages.nn";
- char *newmsg_createdraft_do(const char *, const char *, int);
- /* Save message in a draft file */
- char *newmsg_createdraft(const char *curdraft)
- {
- if (curdraft && *curdraft)
- {
- char *base=maildir_basename(curdraft);
- char *filename=maildir_find(DRAFTS, base);
- if (filename)
- {
- char *p=newmsg_createdraft_do(filename, cgi("message"), 0);
- free(filename);
- free(base);
- return (p);
- }
- free(base);
- }
- return (newmsg_createdraft_do(0, cgi("message"), 0));
- }
- static void create_draftheader_do(const char *hdrname, const char *p,
- int isrfc822addr);
- static void create_draftheader(const char *hdrname, const char *p,
- const char *q, int isrfc822addr)
- {
- if (q && *q) /* Add from address book */
- {
- char *nick=cgi_multiple("nick", ",");
- char *s;
- if (nick)
- {
- s=malloc(strlen(p)+strlen(nick)+2);
- if (s)
- {
- strcpy(s, p);
- if (*s && *nick) strcat(s, ",");
- strcat(s, nick);
- create_draftheader_do(hdrname, s, isrfc822addr);
- free(s);
- free(nick);
- return;
- }
- free(nick);
- }
- }
- create_draftheader_do(hdrname, p, isrfc822addr);
- }
- static void create_draftheader_do(const char *hdrname, const char *p,
- int isrfc822addr)
- {
- char *s;
- if (!*p) return;
- if (!isrfc822addr)
- {
- s=rfc2047_encode_str(p, sqwebmail_content_charset);
- }
- else
- {
- struct rfc822t *t;
- struct rfc822a *a;
- /*
- ** For proper RFC 2047 encoding, we must RFC822-parse
- ** this header.
- */
- s=0;
- if ((t=rfc822t_alloc(p, 0)) != 0)
- {
- if ((a=rfc822a_alloc(t)) != 0)
- {
- s=rfc2047_encode_header(a,
- sqwebmail_content_charset);
- rfc822a_free(a);
- }
- rfc822t_free(t);
- }
- }
- if (!s)
- {
- close(newdraftfd);
- enomem();
- }
- maildir_writemsgstr(newdraftfd, hdrname);
- maildir_writemsgstr(newdraftfd, s);
- maildir_writemsgstr(newdraftfd, "n");
- free(s);
- }
- void newmsg_create_multipart(int newdraftfd, const char *charset,
- const char *multipart_boundary)
- {
- maildir_writemsgstr(newdraftfd,
- "Mime-version: 1.0n"
- "Content-Type: multipart/mixed; boundary="");
- maildir_writemsgstr(newdraftfd, multipart_boundary);
- maildir_writemsgstr(newdraftfd, ""; charset="");
- maildir_writemsgstr(newdraftfd, charset);
- maildir_writemsgstr(newdraftfd,
- ""nn");
- maildir_writemsgstr(newdraftfd, mimemsg);
- }
- static char *newmsg_multipart_boundary(FILE *, const char *);
- static void newmsg_copy_attachments(FILE *, const char *);
- void newmsg_copy_nonmime_headers(FILE *fp)
- {
- char *header, *value;
- char *q;
- while ((header=maildir_readheader(fp, &value, 1)) != NULL)
- {
- if (strcmp(header, "mime-version") == 0 ||
- strncmp(header, "content-", 8) == 0) continue;
- /* Fluff - capitalize header names */
- for (q=header; *q; q++)
- {
- for (*q=toupper(*q); *q; q++)
- if (*q == '-') break;
- }
- maildir_writemsgstr(newdraftfd, header);
- maildir_writemsgstr(newdraftfd, ": ");
- maildir_writemsgstr(newdraftfd, value);
- maildir_writemsgstr(newdraftfd, "n");
- }
- }
- static void do_save(const char *, size_t);
- char *newmsg_createdraft_do(const char *curdraft, const char *newmsg,
- int keepheader)
- {
- char *draftfilename;
- FILE *fp=0;
- char *multipart_boundary;
- const char *content_type;
- const char *content_transfer_encoding;
- const char *charset;
- unsigned long prev_size=0;
- off_t transferencodingpos;
- if (curdraft) /* Reuse a draft filename */
- newdraftfd=maildir_recreatemsg(DRAFTS, curdraft, &draftfilename);
- else
- newdraftfd=maildir_createmsg(DRAFTS, 0, &draftfilename);
- if (newdraftfd < 0) enomem();
- fp=NULL;
- if (curdraft)
- {
- int x=maildir_safeopen(curdraft, O_RDONLY, 0);
- if (x >= 0)
- if ((fp=fdopen(x, "r")) == 0)
- close(x);
- }
- if (fp)
- {
- char *header, *value;
- struct stat stat_buf;
- if (fstat(fileno(fp), &stat_buf))
- {
- fclose(fp);
- enomem();
- }
- prev_size=stat_buf.st_size;
- while ((header=maildir_readheader(fp, &value, 1)) != NULL)
- {
- if (!keepheader)
- {
- if (strcmp(header, "in-reply-to") &&
- strcmp(header, "references") &&
- strncmp(header, "x-", 2)) continue;
- /* Do not discard these headers */
- }
- else /* Called from spell */
- {
- if (strcasecmp(header, "mime-version") == 0 ||
- strncasecmp(header, "content-", 8) == 0)
- continue;
- }
- maildir_writemsgstr(newdraftfd, header);
- maildir_writemsgstr(newdraftfd, ": ");
- maildir_writemsgstr(newdraftfd, value);
- maildir_writemsgstr(newdraftfd, "n");
- }
- }
- if (!keepheader) /* Coming back from msg edit, set headers */
- {
- time_t t;
- const char *p=cgi("headerfrom");
- if (!*p) p=pref_from;
- if (!p || !*p || access(NOCHANGINGFROM, 0) == 0)
- p=login_fromhdr();
- create_draftheader("From: ", p, 0, 1);
- if (!pref_from || strcmp(p, pref_from))
- pref_setfrom(p);
- /* sam ????
- create_draftheader("In-Reply-To: ", cgi("headerin-reply-to"));
- */
- create_draftheader("To: ", cgi("headerto"),
- cgi("addressbook_to"), 1);
- create_draftheader("Cc: ", cgi("headercc"),
- cgi("addressbook_cc"), 1);
- create_draftheader("Bcc: ", cgi("headerbcc"),
- cgi("addressbook_bcc"), 1);
- create_draftheader("Reply-To: ", cgi("headerreply-to"), 0, 1);
- create_draftheader("Subject: ", cgi("headersubject"), 0, 0);
- maildir_writemsgstr(newdraftfd, "Date: ");
- time (&t);
- maildir_writemsgstr(newdraftfd, rfc822_mkdt(t));
- maildir_writemsgstr(newdraftfd, "n");
- }
- /* If the message has attachments, calculate multipart boundary */
- multipart_boundary=fp ? newmsg_multipart_boundary(fp, newmsg) : NULL;
- if (multipart_boundary)
- {
- struct rfc2045 *rfcp=rfc2045_fromfp(fp), *q;
- /* Copy over existing charset */
- if (!rfcp)
- {
- close(newdraftfd);
- fclose(fp);
- enomem();
- }
- rfc2045_mimeinfo(rfcp, &content_type,
- &content_transfer_encoding, &charset);
- newmsg_create_multipart(newdraftfd,
- sqwebmail_content_charset, multipart_boundary);
- maildir_writemsgstr(newdraftfd, "--");
- maildir_writemsgstr(newdraftfd, multipart_boundary);
- for (q=rfcp->firstpart; q; q=q->next)
- {
- if (q->isdummy) continue;
- rfc2045_mimeinfo(q, &content_type,
- &content_transfer_encoding, &charset);
- if (strcmp(content_type, "text/plain") == 0) break;
- }
- maildir_writemsgstr(newdraftfd, "nContent-Type: text/plain");
- if (q)
- {
- maildir_writemsgstr(newdraftfd, "; charset="");
- maildir_writemsgstr(newdraftfd,
- sqwebmail_content_charset);
- maildir_writemsgstr(newdraftfd, """);
- }
- rfc2045_free(rfcp);
- maildir_writemsgstr(newdraftfd, "n");
- }
- else
- {
- struct rfc2045 *rfcp;
- if (fp)
- {
- rfcp=rfc2045_fromfp(fp);
- if (!rfcp)
- {
- close(newdraftfd);
- fclose(fp);
- enomem();
- }
- rfc2045_mimeinfo(rfcp, &content_type,
- &content_transfer_encoding, &charset);
- }
- else
- {
- rfcp=0;
- charset=sqwebmail_content_charset;
- }
- maildir_writemsgstr(newdraftfd, "Mime-Version: 1.0nContent-Type: text/plain; charset="");
- maildir_writemsgstr(newdraftfd, charset);
- maildir_writemsgstr(newdraftfd, ""n");
- if (rfcp)
- rfc2045_free(rfcp);
- }
- maildir_writemsgstr(newdraftfd, "Content-Transfer-Encoding: ");
- transferencodingpos=writebufpos;
- maildir_writemsgstr(newdraftfd, "7bitnn");
- maildir_writemsgstr(newdraftfd, "n");
- {
- char *buf=strdup(newmsg);
- size_t i,j;
- for (i=j=0; buf[i]; i++)
- if (buf[i] != 'r') buf[j++]=buf[i];
- filter_start(FILTER_FOR_SAVING, &do_save);
- filter(buf, j);
- if (j && buf[j-1] != 'n')
- filter("n", 1);
- filter_end();
- free(buf);
- }
- if ( multipart_boundary)
- {
- newmsg_copy_attachments(fp, multipart_boundary);
- maildir_writemsgstr(newdraftfd, "n--");
- maildir_writemsgstr(newdraftfd, multipart_boundary);
- maildir_writemsgstr(newdraftfd, "--n");
- free(multipart_boundary);
- }
- if (fp) fclose(fp);
- if ( maildir_writemsg_flush(newdraftfd) == 0 && writebuf8bit)
- {
- if (lseek(newdraftfd, transferencodingpos, SEEK_SET) < 0 ||
- write(newdraftfd, "8", 1) != 1)
- {
- close(newdraftfd);
- enomem();
- }
- }
- if ( maildir_closemsg(newdraftfd, DRAFTS, draftfilename, -1, prev_size))
- cgi_put("error", "quota");
- return(draftfilename);
- }
- static void do_save(const char *p, size_t l)
- {
- maildir_writemsg(newdraftfd, p, l);
- }
- /* Create message in the sent folder */
- static void sentmsg_copy(FILE *, struct rfc2045 *);
- static void sentmsg_reformat(FILE *, struct rfc2045 *);
- extern void header_uc(char *h);
- struct lookup_buffers {
- struct lookup_buffers *next;
- char *buf;
- char *buf2;
- } ;
- static int lookup_addressbook_do(const char *header, const char *value,
- struct lookup_buffers **lookup_buffer_list)
- {
- struct rfc822t *t;
- struct rfc822a *a;
- int i;
- char *newbuf;
- struct lookup_buffers *ptr;
- int expanded=0;
- t=rfc822t_alloc(value, 0);
- if (!t) enomem();
- a=rfc822a_alloc(t);
- if (!a)
- {
- rfc822t_free(t);
- enomem();
- }
- for (i=0; i<a->naddrs; i++)
- {
- char *p;
- const char *q;
- struct lookup_buffers *r;
- if (a->addrs[i].tokens == 0)
- continue;
- if (a->addrs[i].name)
- continue; /* Can't be a nickname */
- p=rfc822_getaddr(a, i);
- if (!p)
- {
- rfc822a_free(a);
- rfc822t_free(t);
- free(p);
- return (-1);
- }
- for (ptr= *lookup_buffer_list; ptr; ptr=ptr->next)
- if (strcmp(ptr->buf2, p) == 0)
- break;
- if (ptr) /* Address book loop */
- {
- int j;
- for (j=i+1; j<a->naddrs; j++)
- a->addrs[j-1]=a->addrs[j];
- --a->naddrs;
- --i;
- free(p);
- continue;
- }
- if ((q=ab_find(p)) == 0)
- {
- free(p);
- continue;
- }
- r=malloc(sizeof(struct lookup_buffers));
- if (r) r->buf=r->buf2=0;
- if (!r || !(r->buf=strdup(q)) || !(r->buf2=strdup(p)))
- {
- free(p);
- if (r && r->buf) free(r->buf);
- if (r) free(r);
- rfc822a_free(a);
- rfc822t_free(t);
- return (-1);
- }
- free(p);
- r->next= *lookup_buffer_list;
- *lookup_buffer_list=r;
- a->addrs[i].tokens->next=0;
- a->addrs[i].tokens->token=0;
- a->addrs[i].tokens->ptr=r->buf;
- a->addrs[i].tokens->len=strlen(r->buf);
- expanded=1;
- }
- newbuf=rfc822_getaddrs_wrap(a, 70);
- rfc822a_free(a);
- rfc822t_free(t);
- if (!newbuf) return (-1);
- if (expanded) /* Look through the address book again */
- {
- int rc=lookup_addressbook_do(header, newbuf, lookup_buffer_list);
- free(newbuf);
- return (rc);
- }
- create_draftheader_do(header, newbuf, 1);
- free(newbuf);
- return (0);
- }
- static void lookup_addressbook(const char *header, const char *value)
- {
- struct lookup_buffers *lookup_buffer_list=0;
- int rc;
- char *s=strdup(value);
- if (!s) enomem();
- rc=lookup_addressbook_do(header, s, &lookup_buffer_list);
- free(s);
- while (lookup_buffer_list)
- {
- struct lookup_buffers *p=lookup_buffer_list;
- lookup_buffer_list=p->next;
- free(p->buf);
- free(p->buf2);
- free(p);
- }
- if (rc) enomem();
- }
- char *newmsg_createsentmsg(const char *draftname)
- {
- char *filename=maildir_find(DRAFTS, draftname);
- FILE *fp;
- char *sentname;
- char *header, *value;
- struct rfc2045 *rfcp;
- int x;
- #if 0
- off_t transferencodingpos;
- #endif
- 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);
- enomem();
- }
- newdraftfd=maildir_createmsg(SENT, 0, &sentname);
- if (newdraftfd < 0)
- {
- free(filename);
- fclose(fp);
- enomem();
- }
- /* First, copy all headers except X- headers */
- while ((header=maildir_readheader(fp, &value, 1)) != 0)
- {
- if (strncmp(header, "x-", 2) == 0) continue;
- header_uc(header);
- if (strcasecmp(header, "To") == 0)
- {
- lookup_addressbook("To: ", value);
- continue;
- }
- if (strcasecmp(header, "Cc") == 0)
- {
- lookup_addressbook("Cc: ", value);
- continue;
- }
- if (strcasecmp(header, "Bcc") == 0)
- {
- lookup_addressbook("Bcc: ", value);
- continue;
- }
- maildir_writemsgstr(newdraftfd, header);
- maildir_writemsgstr(newdraftfd, ": ");
- maildir_writemsgstr(newdraftfd, value);
- maildir_writemsgstr(newdraftfd, "n");
- }
- if (access(USEXSENDER, 0) == 0)
- {
- maildir_writemsgstr(newdraftfd, "X-Sender: ");
- maildir_writemsgstr(newdraftfd, login_returnaddr());
- maildir_writemsgstr(newdraftfd, "n");
- }
- #if 0
- maildir_writemsgstr(newdraftfd, "Content-Transfer-Encoding: ");
- transferencodingpos=writebufpos;
- maildir_writemsgstr(newdraftfd, "7bitn");
- #endif
- maildir_writemsgstr(newdraftfd, "n");
- rfcp=rfc2045_fromfp(fp);
- if (!rfcp)
- {
- fclose(fp);
- close(newdraftfd);
- enomem();
- }
- if (!rfcp->firstpart)
- sentmsg_reformat(fp, rfcp);
- else
- {
- int found_textplain=0;
- struct rfc2045 *p;
- for (p=rfcp->firstpart; p; p=p->next)
- {
- const char *content_type;
- const char *content_transfer_encoding;
- const char *charset;
- rfc2045_mimeinfo(p, &content_type,
- &content_transfer_encoding, &charset);
- if (strcmp(content_type, "text/plain") == 0 &&
- !p->isdummy && !found_textplain)
- {
- maildir_writemsgstr(newdraftfd,
- "Content-Type: text/plain; charset=");
- maildir_writemsgstr(newdraftfd, charset);
- maildir_writemsgstr(newdraftfd,
- "nContent-Transfer-Encoding: ");
- maildir_writemsgstr(newdraftfd,
- content_transfer_encoding);
- maildir_writemsgstr(newdraftfd, "nn");
- sentmsg_reformat(fp, p);
- found_textplain=1;
- }
- else sentmsg_copy(fp, p);
- maildir_writemsgstr(newdraftfd, "n--");
- maildir_writemsgstr(newdraftfd, rfc2045_boundary(rfcp));
- if (!p->next)
- maildir_writemsgstr(newdraftfd, "--");
- maildir_writemsgstr(newdraftfd, "n");
- }
- }
- if ( maildir_writemsg_flush(newdraftfd))
- {
- free(sentname);
- return (0);
- }
- #if 0
- if (writebuf8bit)
- {
- if (lseek(newdraftfd, transferencodingpos, SEEK_SET) < 0 ||
- write(newdraftfd, "8", 1) != 1)
- {
- free(sentname);
- return (0);
- }
- }
- #endif
- if ( maildir_closemsg(newdraftfd, SENT, sentname, 1, 0))
- {
- free(sentname);
- return (0);
- }
- return (sentname);
- }
- /* Note - sentmsg_copy is also reused in newmsg_copy_attachments */
- static void sentmsg_copy(FILE *f, struct rfc2045 *p)
- {
- off_t start_pos, end_pos, start_body;
- char buf[512];
- int n;
- off_t dummy;
- rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy);
- if (fseek(f, start_pos, SEEK_SET) == -1)
- {
- fclose(f);
- close(newdraftfd);
- enomem();
- }
- while (start_pos < end_pos)
- {
- int cnt=sizeof(buf);
- if (cnt > end_pos - start_pos)
- cnt=end_pos - start_pos;
- if ((n=fread(buf, 1, cnt, f)) <= 0)
- {
- fclose(f);
- close(newdraftfd);
- enomem();
- }
- maildir_writemsg(newdraftfd, buf, n);
- start_pos += n;
- }
- }
- static void write_to_draft(const char *p, size_t l)
- {
- maildir_writemsg(newdraftfd, p, l);
- }
- static void sentmsg_reformat(FILE *f, struct rfc2045 *p)
- {
- off_t start_pos, end_pos, start_body;
- char buf[BUFSIZ];
- int n;
- off_t dummy;
- FILE *fp;
- rfc2045_mimepos(p, &start_pos, &end_pos, &start_body,
- &dummy, &dummy);
- if (fseek(f, start_body, SEEK_SET) == -1)
- {
- fclose(f);
- close(newdraftfd);
- enomem();
- }
- filter_start(FILTER_FOR_SENDING, &write_to_draft);
- while (start_body < end_pos)
- {
- int cnt=sizeof(buf);
- if (cnt > end_pos - start_body)
- cnt=end_pos - start_body;
- if ((n=fread(buf, 1, cnt, f)) <= 0)
- {
- fclose(f);
- close(newdraftfd);
- enomem();
- }
- filter(buf, n);
- start_body += n;
- }
- fp=http11_open_langfile(HTMLLIBDIR, sqwebmail_content_language,
- "footer");
- if (fp != 0)
- {
- while ((n=fread(buf, 1, sizeof(buf), fp)) > 0)
- filter(buf, n);
- fclose(fp);
- }
- filter_end();
- }
- /* ---------------------------------------------------------------------- */
- /* Create a potential multipart boundary separator tag */
- char *multipart_boundary_create()
- {
- char pidbuf[MAXLONGSIZE];
- char timebuf[MAXLONGSIZE];
- time_t t;
- char cntbuf[MAXLONGSIZE];
- unsigned long cnt=0;
- char *p;
- sprintf(pidbuf, "%lu", (unsigned long)getpid());
- time(&t);
- sprintf(timebuf, "%lu", (unsigned long)t);
- sprintf(cntbuf, "%lu", cnt++);
- p=malloc(strlen(pidbuf)+strlen(timebuf) +strlen(cntbuf)+10);
- sprintf(p, "=_%s_%s_%s", cntbuf, pidbuf, timebuf);
- return (p);
- }
- /* Search for the boundary tag in a string buffer - this is the new message
- ** we're creating. We should really look for the tag at the beginning of the
- ** line, however, the text is not yet linewrapped, besides, why make your
- ** life hard?
- */
- int multipart_boundary_checks(const char *boundary, const char *msg)
- {
- size_t boundarylen=strlen(boundary);
- while (*msg)
- {
- if (msg[0] == '-' && msg[1] == '-' && msg[2] != '-' &&
- strncasecmp(msg+2, boundary, boundarylen) == 0)
- return (-1);
- ++msg;
- }
- return (0);
- }
- /* Again, just look for it at the beginning of the line -- why make your
- ** life hard? */
- int multipart_boundary_checkf(const char *boundary, FILE *f)
- {
- size_t boundarylen=strlen(boundary);
- const char *line;
- if (fseek(f, 0L, SEEK_SET) == -1)
- {
- fclose(f);
- close(newdraftfd);
- enomem();
- }
- while ((line=maildir_readline(f)) != 0)
- if (line[0] == '-' && line[1] == '-' &&
- strncasecmp(line+2, boundary, boundarylen) == 0)
- return (-1);
- return (0);
- }
- /* ---------------------------------------------------------------------- */
- /* Copy existing attachments into the new draft message */
- /* multipart_boundary - determine if current draft has attachments */
- static struct rfc2045 *copyrfc2045;
- static char *newmsg_multipart_boundary(FILE *f, const char *msg)
- {
- char *p=0;
- copyrfc2045=rfc2045_fromfp(f);
- if (!copyrfc2045)
- {
- fclose(f);
- close(newdraftfd);
- enomem();
- }
- if ( copyrfc2045->firstpart == 0)
- {
- rfc2045_free(copyrfc2045);
- return (0);
- }
- do
- {
- if (p) free(p);
- p=multipart_boundary_create();
- } while (multipart_boundary_checks(p, msg)
- || multipart_boundary_checkf(p, f));
- return (p);
- }
- static void newmsg_copy_attachments(FILE *f, const char *boundary)
- {
- struct rfc2045 *p;
- int foundtextplain=0;
- const char *content_type;
- const char *content_transfer_encoding;
- const char *charset;
- for (p=copyrfc2045->firstpart; p; p=p->next)
- {
- if (p->isdummy) continue;
- rfc2045_mimeinfo(p, &content_type,
- &content_transfer_encoding, &charset);
- if (!foundtextplain && strcmp(content_type,
- "text/plain") == 0)
- { /* Previous version of this message */
- foundtextplain=1;
- continue;
- }
- maildir_writemsgstr(newdraftfd, "n--");
- maildir_writemsgstr(newdraftfd, boundary);
- maildir_writemsgstr(newdraftfd, "n");
- sentmsg_copy(f, p); /* Reuse some code */
- }
- rfc2045_free(copyrfc2045);
- }