summaryrefslogtreecommitdiffstats
path: root/sqwebmail/attachments.c
diff options
context:
space:
mode:
Diffstat (limited to 'sqwebmail/attachments.c')
-rw-r--r--sqwebmail/attachments.c1142
1 files changed, 1142 insertions, 0 deletions
diff --git a/sqwebmail/attachments.c b/sqwebmail/attachments.c
new file mode 100644
index 0000000..629b438
--- /dev/null
+++ b/sqwebmail/attachments.c
@@ -0,0 +1,1142 @@
+/*
+** Copyright 1998 - 2011 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+
+/*
+*/
+#include "config.h"
+#include "sqwebmail.h"
+#include "cgi/cgi.h"
+#include "sqconfig.h"
+#include "maildir.h"
+#include "folder.h"
+#include "pref.h"
+#include "rfc822/rfc822.h"
+#include "rfc822/rfc2047.h"
+#include "rfc2045/rfc2045.h"
+#include "token.h"
+#include "newmsg.h"
+#include "gpg.h"
+#include "gpglib/gpglib.h"
+#include "courierauth.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#include "maildir/maildirmisc.h"
+
+#include "htmllibdir.h"
+#include "unicode/unicode.h"
+
+extern char *newmsg_alladdrs(FILE *);
+extern void newmsg_copy_content_headers(FILE *fp);
+
+extern char *alloc_filename(const char *, const char *, const char *);
+extern const char *showsize(unsigned long);
+extern void output_attrencoded(const char *);
+extern int newdraftfd;
+extern void newmsg_hiddenheader(const char *, const char *);
+extern void output_scriptptrget();
+extern void output_urlencoded(const char *);
+extern void sendmsg_done();
+
+extern char *multipart_boundary_create();
+extern int multipart_boundary_checkf(const char *, FILE *);
+extern int ishttps();
+
+extern void newmsg_create_multipart(int, const char *, const char *);
+extern void newmsg_copy_nonmime_headers(FILE *);
+
+extern const char *sqwebmail_content_charset;
+extern const char *sqwebmail_content_language;
+
+static void attachment_showname(const char *);
+
+#define HASTEXTPLAIN(q) (rfc2045_searchcontenttype((q), "text/plain") != NULL)
+/* Also in newmsg_create.c */
+
+
+static off_t max_attach()
+{
+ off_t n=0;
+ const char *p=getenv("SQWEBMAIL_MAXMSGSIZE");
+
+ if (p)
+ n=atol(p);
+
+ if (n < MAXMSGSIZE)
+ n=MAXMSGSIZE;
+ return n;
+}
+
+
+void attachments_head(const char *folder, const char *pos, const char *draft)
+{
+char *filename;
+FILE *fp;
+struct rfc2045 *rfcp;
+int cnt=0;
+struct rfc2045 *q;
+int foundtextplain=0;
+const char *noattach_lab=getarg("NOATTACH");
+const char *quotaerr=getarg("QUOTAERR");
+const char *limiterr=getarg("LIMITERR");
+off_t dummy;
+int fd2;
+
+ CHECKFILENAME(draft);
+ filename=maildir_find(INBOX "." DRAFTS, draft);
+ if (!filename) return;
+
+ fd2=maildir_safeopen(filename, O_RDONLY, 0);
+
+ fp=0;
+ if (fd2 >= 0)
+ {
+ fp=fdopen(fd2, "r");
+ if (fp == NULL)
+ close(fd2);
+ }
+
+ if (fp == NULL)
+ {
+ free(filename);
+ return;
+ }
+
+ rfcp=rfc2045_fromfp(fp);
+ fclose(fp);
+ free(filename);
+
+ if (strcmp(cgi("error"), "quota") == 0)
+ {
+ printf("%s", quotaerr);
+ }
+
+ if (strcmp(cgi("error"), "limits") == 0)
+ {
+ printf(limiterr, (unsigned long)(max_attach() / (1024 * 1024)));
+ }
+
+ if (strcmp(cgi("error"), "makemime") == 0)
+ {
+ printf(getarg("MAKEMIMEERR"), MAKEMIME);
+ }
+ newmsg_hiddenheader("pos", pos);
+ newmsg_hiddenheader("draft", draft);
+ tokennew();
+ printf("<table width=\"100%%\" border=\"0\">");
+
+ if (rfcp)
+ {
+ const char *content_type;
+ const char *content_transfer_encoding;
+ const char *charset;
+
+ rfc2045_mimeinfo(rfcp, &content_type,
+ &content_transfer_encoding, &charset);
+
+ if (content_type &&
+ strcmp(content_type, "multipart/alternative") == 0)
+ rfcp=NULL;
+
+ /* No attachments here */
+ }
+
+ for (q=rfcp ? rfcp->firstpart:0; q; q=q->next)
+ {
+ const char *content_type;
+ const char *content_transfer_encoding;
+ const char *charset;
+ const char *name;
+ const char *cn;
+ char *content_name;
+
+ off_t start_pos, end_pos, start_body;
+
+ if (q->isdummy) continue;
+
+ rfc2045_mimeinfo(q, &content_type,
+ &content_transfer_encoding, &charset);
+ if (!foundtextplain && HASTEXTPLAIN(q))
+ {
+ foundtextplain=1;
+ continue;
+ }
+ rfc2045_mimepos(q, &start_pos, &end_pos, &start_body,
+ &dummy, &dummy);
+
+ ++cnt;
+ printf("<tr><td align=\"left\"><input type=\"checkbox\" name=\"del%d\" id=\"del%d\" />&nbsp;",
+ cnt, cnt);
+
+ if (rfc2231_udecodeType(q, "name", sqwebmail_content_charset,
+ &content_name) < 0 ||
+ rfc2231_udecodeDisposition(q, "filename",
+ sqwebmail_content_charset,
+ &content_name) < 0)
+ content_name=NULL;
+
+ if (!content_name &&
+ ((cn=rfc2045_getattr(q->content_type_attr, "name")) ||
+ (cn=rfc2045_getattr(q->content_disposition_attr,
+ "filename"))))
+ {
+ content_name =
+ rfc822_display_hdrvalue_tobuf("subject",
+ cn,
+ sqwebmail_content_charset,
+ NULL,
+ NULL);
+ }
+
+ if ((!content_name || !*content_name) &&
+ strcmp(content_type, "application/pgp-keys") == 0)
+ name=getarg("KEYDESCR");
+ else
+ {
+ name=content_name;
+ }
+
+ attachment_showname(name);
+ if (content_name)
+ free(content_name);
+ printf("</td><td align=\"left\">&nbsp;&nbsp;<label for=\"del%d\">", cnt);
+ output_attrencoded( content_type );
+ printf("</label></td><td align=\"right\">%s<br /></td></tr>",
+ showsize(end_pos - start_body));
+ }
+
+ if (cnt == 0)
+ printf("<tr><td align=\"center\">%s<br /></td></tr>\n",
+ noattach_lab);
+ printf("</table>\n");
+}
+
+void attachments_opts(const char *draft)
+{
+ char *filename;
+ FILE *fp;
+
+ CHECKFILENAME(draft);
+
+ filename=maildir_find(INBOX "." DRAFTS, draft);
+ if (!filename)
+ return;
+ fp=fopen(filename, "r");
+ free(filename);
+ if (!fp)
+ return;
+
+ printf("<label><input type=\"checkbox\" name=\"fcc\"%s />%s</label><br />",
+ pref_noarchive ? "":" checked=\"checked\"",
+ getarg("PRESERVELAB"));
+ if (auth_getoptionenvint("wbnodsn") == 0)
+ printf("<label><input type=\"checkbox\" name=\"dsn\" />%s</label><br />",
+ getarg("DSN"));
+
+ if (libmail_gpg_has_gpg(GPGDIR) == 0)
+ {
+ char *all_addr;
+
+ printf("<label><input type=\"checkbox\" "
+ "name=\"sign\" />%s</label><select name=\"signkey\">",
+ getarg("SIGNLAB"));
+ gpgselectkey();
+ printf("</select><br />\n");
+
+ all_addr=newmsg_alladdrs(fp);
+
+ printf("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"
+ "<tr valign=\"middle\"><td><input type=\"checkbox\""
+ " name=\"encrypt\" id=\"encrypt\" /></td><td><label for=\"encrypt\">%s</label></td>"
+ "<td><select size=\"4\" multiple=\"multiple\" name=\"encryptkey\">",
+ getarg("ENCRYPTLAB"));
+ gpgencryptkeys(all_addr);
+ printf("</select></td></tr>\n");
+
+ if (ishttps())
+ printf("<tr valign=\"middle\"><td>&nbsp;</td><td>%s</td><td><input type=\"password\" name=\"passphrase\" /></td></tr>\n",
+ getarg("PASSPHRASE"));
+
+ printf("</table><br />\n");
+ if (all_addr)
+ free(all_addr);
+ }
+ fclose(fp);
+}
+
+static void attachment_showname(const char *name)
+{
+ if (!name || !*name) name="[attachment]"; /* Eh??? */
+ output_attrencoded(name);
+}
+
+static void attachment_open(const char *draft,
+ FILE **fp,
+ int *fd2,
+ struct rfc2045 **rfcp)
+{
+char *oldname=maildir_find(INBOX "." DRAFTS, draft);
+
+ if (!oldname) enomem();
+
+ *fd2=maildir_safeopen(oldname, O_RDONLY, 0);
+
+ *fp=0;
+ if (*fd2 >= 0)
+ {
+ *fp=fdopen(*fd2, "r");
+ if (*fp == NULL)
+ close(*fd2);
+ }
+
+ if (*fp == NULL) enomem();
+ *rfcp=rfc2045_fromfp( *fp );
+ if (!*rfcp) enomem();
+}
+
+static int messagecopy(FILE *fp, off_t start, off_t end)
+{
+char buf[512];
+int n;
+
+ if (fseek(fp, start, SEEK_SET) == -1) return (-1);
+ while (start < end)
+ {
+ n=sizeof(buf);
+ if (n > end - start)
+ n=end - start;
+ n=fread(buf, 1, n, fp);
+ if (n <= 0) enomem();
+ maildir_writemsg(newdraftfd, buf, n);
+ start += n;
+ }
+ return (0);
+}
+
+/* Return non-zero if user selected all attachments for deletion */
+
+static int deleting_all_attachments(struct rfc2045 *p)
+{
+struct rfc2045 *q;
+const char *content_type;
+const char *content_transfer_encoding;
+const char *charset;
+int foundtextplain, cnt;
+char buf[MAXLONGSIZE+4];
+
+ foundtextplain=0;
+ cnt=0;
+ for (q=p->firstpart; q; q=q->next)
+ {
+ rfc2045_mimeinfo(q, &content_type,
+ &content_transfer_encoding, &charset);
+ if (q->isdummy) continue;
+
+ if (!foundtextplain && HASTEXTPLAIN(q))
+ {
+ foundtextplain=1;
+ continue;
+ }
+
+ sprintf(buf, "del%d", ++cnt);
+ if (*cgi(buf) == '\0') return (0);
+ }
+ return (1);
+}
+
+static int del_final_attachment(FILE *fp, struct rfc2045 *rfcp)
+{
+struct rfc2045 *q;
+const char *content_type;
+const char *content_transfer_encoding;
+const char *charset;
+off_t start_pos, end_pos, start_body;
+off_t dummy;
+
+ for (q=rfcp->firstpart; q; q=q->next)
+ {
+ if (q->isdummy) continue;
+ rfc2045_mimeinfo(q, &content_type,
+ &content_transfer_encoding, &charset);
+ if (HASTEXTPLAIN(q))
+ break;
+ }
+ if (!q) return (-1);
+
+ if (fseek(fp, 0L, SEEK_SET) == -1) return (-1);
+ newmsg_copy_nonmime_headers(fp);
+ maildir_writemsgstr(newdraftfd, "mime-version: 1.0\n");
+
+ rfc2045_mimepos(q, &start_pos, &end_pos, &start_body, &dummy, &dummy);
+ return (messagecopy(fp, start_pos, end_pos));
+}
+
+static int del_some_attachments(FILE *fp, struct rfc2045 *rfcp)
+{
+struct rfc2045 *q;
+const char *content_type;
+const char *content_transfer_encoding;
+const char *charset;
+int foundtextplain;
+int cnt;
+const char *boundary=rfc2045_boundary(rfcp);
+off_t start_pos, end_pos, start_body;
+off_t dummy;
+
+ rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, &dummy,
+ &dummy);
+ if (messagecopy(fp, 0, start_body)) return (-1);
+
+ foundtextplain=0;
+ cnt=0;
+ for (q=rfcp->firstpart; q; q=q->next)
+ {
+ rfc2045_mimeinfo(q, &content_type,
+ &content_transfer_encoding, &charset);
+ if (q->isdummy)
+ ;
+ else if (!foundtextplain && HASTEXTPLAIN(q))
+ foundtextplain=1;
+ else
+ {
+ char buf[MAXLONGSIZE+4];
+
+ sprintf(buf, "del%d", ++cnt);
+ if (*cgi(buf)) continue; /* This one's gone */
+ }
+
+ if (!q->isdummy)
+ {
+ maildir_writemsgstr(newdraftfd, "\n--");
+ maildir_writemsgstr(newdraftfd, boundary);
+ maildir_writemsgstr(newdraftfd, "\n");
+ }
+ rfc2045_mimepos(q, &start_pos, &end_pos, &start_body, &dummy,
+ &dummy);
+ if (messagecopy(fp, start_pos, end_pos))
+ return (-1);
+ }
+ maildir_writemsgstr(newdraftfd, "\n--");
+ maildir_writemsgstr(newdraftfd, boundary);
+ maildir_writemsgstr(newdraftfd, "--\n");
+ return (0);
+}
+
+void attach_delete(const char *draft)
+{
+FILE *fp;
+int fd2;
+struct rfc2045 *rfcp;
+char *draftfilename;
+int isok=1;
+struct stat stat_buf;
+
+ attachment_open(draft, &fp, &fd2, &rfcp);
+ if (!rfcp->firstpart)
+ {
+ rfc2045_free(rfcp);
+ fclose(fp);
+ return; /* No attachments to delete */
+ }
+
+ if (fstat(fileno(fp), &stat_buf))
+ {
+ fclose(fp);
+ enomem();
+ }
+
+ newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, draft, &draftfilename);
+ if (newdraftfd < 0)
+ {
+ fclose(fp);
+ enomem();
+ }
+
+ if (deleting_all_attachments(rfcp))
+ {
+ /* Deleting all attachments */
+
+ if (del_final_attachment(fp, rfcp)) isok=0;
+ }
+ else
+ {
+ if (del_some_attachments(fp, rfcp)) isok=0;
+ }
+ fclose(fp);
+ rfc2045_free(rfcp);
+
+ if ( maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, isok,
+ stat_buf.st_size))
+ {
+ free(draftfilename);
+ enomem();
+ }
+ free(draftfilename);
+ maildir_remcache(INBOX "." DRAFTS); /* Cache file invalid now */
+}
+
+/* ---------------------------------------------------------------------- */
+/* Upload an attachment */
+
+static int isbinary;
+static int attachfd;
+static const char *cgi_attachname, *cgi_attachfilename;
+
+static int upload_start(const char *name, const char *filename, void *dummy)
+{
+const char *p;
+
+ p=strrchr(filename, '/');
+ if (p) filename=p+1;
+
+ p=strrchr(filename, '\\');
+ if (p) filename=p+1;
+
+ cgi_attachname=name;
+ cgi_attachfilename=filename;
+ isbinary=0;
+ return (0);
+}
+
+static int upload_file(const char *ptr, size_t cnt, void *voidptr)
+{
+size_t i;
+
+ for (i=0; i<cnt; i++)
+ if ( (ptr[i] < ' ' || ptr[i] >= 127) && ptr[i] != '\n' &&
+ ptr[i] != '\r')
+ isbinary=1;
+ maildir_writemsg(attachfd, ptr, cnt);
+ return (0);
+}
+
+static void upload_end(void *dummy)
+{
+}
+
+#if 0
+static void writebase64encode(const char *p, size_t n)
+{
+ maildir_writemsg(newdraftfd, p, n);
+}
+#endif
+
+static const char *search_mime_type(const char *mimetype, const char *filename)
+{
+FILE *fp;
+char *p, *q;
+
+ if (!filename || !(filename=strrchr(filename, '.'))) return (0);
+ ++filename;
+
+ if ((fp=fopen(mimetype, "r")) == NULL) return(0);
+ while ((p=maildir_readline(fp)) != NULL)
+ {
+ if ((q=strchr(p, '#')) != NULL) *q='\0';
+ if ((p=strtok(p, " \t")) == NULL) continue;
+ while ((q=strtok(NULL, " \t")) != NULL)
+ if (strcasecmp(q, filename) == 0)
+ {
+ fclose(fp);
+ return (p);
+ }
+ }
+ fclose(fp);
+ return (NULL);
+}
+
+const char *calc_mime_type(const char *filename)
+{
+static const char mimetypes[]=MIMETYPES;
+const char *p;
+char *q;
+const char *r;
+char *s;
+
+ p=mimetypes;
+ if (!p) enomem();
+ while (*p)
+ {
+ if (*p == ':')
+ {
+ ++p;
+ continue;
+ }
+ q=strdup(p);
+ if (!q) enomem();
+ if ((s=strchr(q, ':')) != NULL) *s='\0';
+ if ((r=search_mime_type(q, filename)) != 0)
+ {
+ free(q);
+ return (r);
+ }
+ free(q);
+ while (*p && *p != ':')
+ p++;
+ }
+ return ("auto");
+}
+
+static int getkey(const char *keyname, int issecret)
+{
+ int rc;
+
+ if (!*keyname)
+ return (1);
+ upload_start("", "", NULL);
+
+ rc=gpgexportkey(keyname, issecret, &upload_file, NULL);
+ upload_end(NULL);
+ return (rc);
+}
+
+#if 0
+static void write_disposition_param(const char *label, const char *value)
+{
+char *p, *q;
+const char *r;
+
+ while (value && ((r=strchr(value, ':')) || (r=strchr(value, '/'))
+ || (r=strchr(value, '\\'))))
+ value=r+1;
+
+ if (!value || !*value) return;
+ maildir_writemsgstr(newdraftfd, "; ");
+ maildir_writemsgstr(newdraftfd, label);
+ maildir_writemsgstr(newdraftfd, "=\"");
+ p=strdup(value);
+ if (!p) enomem();
+ while ((q=strchr(p, '\\')) || (q=strchr(p, '"')))
+ *q='_';
+ maildir_writemsgstr(newdraftfd, p);
+ maildir_writemsgstr(newdraftfd, "\"");
+ free(p);
+}
+#endif
+
+static int cnt_filename(const char *param,
+ const char *value,
+ void *void_arg)
+{
+ *(int *)void_arg += strlen(param)+strlen(value)+5;
+ return 0;
+}
+
+static int save_filename(const char *param,
+ const char *value,
+ void *void_arg)
+{
+ strcat(strcat(strcat(strcat((char *)void_arg, ";\n "), param),
+ "="), value);
+ return 0;
+}
+
+int attach_upload(const char *draft,
+ const char *attpubkey,
+ const char *attprivkey)
+{
+ char *attachfilename;
+ char *draftfilename;
+ FILE *draftfp;
+ char *boundary;
+ FILE *tempfp;
+ struct rfc2045 *rfcp, *q;
+ const char *content_type;
+ const char *content_transfer_encoding;
+ const char *charset;
+ off_t start_pos, end_pos, start_body;
+ int n;
+ char buf[BUFSIZ];
+ int pipefd[2];
+ struct stat stat_buf, attach_stat_buf;
+ off_t dummy;
+ int fd2;
+ char *filenamemime;
+ char *argvec[20];
+ char *filenamebuf;
+ pid_t pid1, pid2;
+ int waitstat;
+
+ /* Open the file containing the draft message */
+
+ draftfilename=maildir_find(INBOX "." DRAFTS, draft);
+ if (!draftfilename) return (0);
+
+ fd2=maildir_safeopen(draftfilename, O_RDONLY, 0);
+
+ draftfp=0;
+ if (fd2 >= 0)
+ {
+ draftfp=fdopen(fd2, "r");
+ if (draftfp == NULL)
+ close(fd2);
+ }
+
+ if (draftfp == 0)
+ enomem();
+
+ free(draftfilename);
+ if (fstat(fileno(draftfp), &stat_buf))
+ {
+ fclose(draftfp);
+ enomem();
+ }
+
+ /* Create a temporary file in tmp where we'll temporarily store the
+ ** attachment
+ */
+
+ attachfd=maildir_createmsg(INBOX "." DRAFTS, "temp", &attachfilename);
+ if (attachfd < 0)
+ {
+ fclose(draftfp);
+ enomem();
+ }
+
+ if ((
+ attpubkey ? getkey(attpubkey, 0):
+ attprivkey ? getkey(attprivkey, 1):
+ cgi_getfiles( &upload_start, &upload_file, &upload_end, 1, NULL))
+ || maildir_writemsg_flush(attachfd))
+ {
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ free(attachfilename);
+ fclose(draftfp);
+ close(attachfd);
+ return (0);
+ }
+
+ if (fstat(attachfd, &attach_stat_buf) ||
+ attach_stat_buf.st_size + stat_buf.st_size > max_attach())
+ {
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
+ free(attachfilename);
+ fclose(draftfp);
+ close(attachfd);
+ return (-2);
+ }
+
+
+ /* Calculate new MIME content boundary */
+
+ boundary=0;
+ tempfp=0;
+
+ n=dup(attachfd);
+
+ if (n < 0)
+ {
+ fclose(draftfp);
+ enomem();
+ }
+ tempfp=fdopen(n, "r");
+ if (tempfp == 0)
+ {
+ fclose(draftfp);
+ enomem();
+ }
+
+ do
+ {
+ if (boundary) free(boundary);
+ boundary=multipart_boundary_create();
+ } while ( multipart_boundary_checkf(boundary, draftfp) ||
+ multipart_boundary_checkf(boundary, tempfp));
+
+ if (tempfp) fclose(tempfp);
+
+ /* Parse existing draft for its MIME structure */
+
+ rfcp=rfc2045_fromfp(draftfp);
+
+ rfc2045_mimeinfo(rfcp, &content_type,
+ &content_transfer_encoding, &charset);
+
+ /* Create a new version of the draft message */
+
+ newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, draft, &draftfilename);
+ if (newdraftfd < 0)
+ {
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ fclose(draftfp);
+ close(attachfd);
+ enomem();
+ }
+
+ if (fseek(draftfp, 0L, SEEK_SET) < 0)
+ {
+ maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ fclose(draftfp);
+ close(attachfd);
+ enomem();
+ }
+
+ newmsg_copy_nonmime_headers(draftfp);
+
+ /* Create a multipart message, 1st attachment is the existing
+ ** contents.
+ */
+
+ newmsg_create_multipart(newdraftfd, charset, boundary);
+ maildir_writemsgstr(newdraftfd, "--");
+ maildir_writemsgstr(newdraftfd, boundary);
+ maildir_writemsgstr(newdraftfd, "\n");
+
+ if (rfcp == NULL || strcmp(content_type, "multipart/mixed"))
+ {
+ int rc;
+
+ /*
+ ** The current draft does not have attachments. Take its
+ ** sole contents, and write it as a text/plain attachment.
+ */
+
+ if (fseek(draftfp, 0L, SEEK_SET) < 0)
+ rc = -1;
+ else
+ {
+ newmsg_copy_content_headers(draftfp);
+ maildir_writemsgstr(newdraftfd, "\n");
+ rfc2045_mimepos(rfcp, &start_pos, &end_pos,
+ &start_body,
+ &dummy, &dummy);
+ rc=messagecopy(draftfp, start_body, end_pos);
+ }
+
+ if (rc)
+ {
+ maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename,
+ 0, 0);
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename,
+ 0, 0);
+ fclose(draftfp);
+ close(newdraftfd);
+ close(attachfd);
+ enomem();
+ }
+
+ maildir_writemsgstr(newdraftfd, "\n--");
+ maildir_writemsgstr(newdraftfd, boundary);
+ maildir_writemsgstr(newdraftfd, "\n");
+ }
+ else
+ {
+ /* If the current draft already has MIME attachments,
+ ** just copy them over to the new draft message.
+ */
+
+ for (q=rfcp->firstpart; q; q=q->next)
+ {
+ if (q->isdummy) continue;
+ rfc2045_mimepos(q, &start_pos, &end_pos, &start_body,
+ &dummy, &dummy);
+ if (messagecopy(draftfp, start_pos, end_pos))
+ {
+ maildir_closemsg(newdraftfd, INBOX "." DRAFTS,
+ draftfilename, 0, 0);
+ maildir_closemsg(attachfd, INBOX "." DRAFTS,
+ attachfilename, 0, 0);
+ fclose(draftfp);
+ close(newdraftfd);
+ close(attachfd);
+ enomem();
+ }
+ maildir_writemsgstr(newdraftfd, "\n--");
+ maildir_writemsgstr(newdraftfd, boundary);
+ maildir_writemsgstr(newdraftfd, "\n");
+ }
+ }
+
+ {
+ const char *cp=strrchr(cgi_attachfilename, '/');
+ int len;
+ static const char fnStr[]="filename";
+
+ if (cp)
+ ++cp;
+ else
+ cp=cgi_attachfilename;
+
+ len=1;
+ rfc2231_attrCreate(fnStr, cp,
+ sqwebmail_content_charset,
+ sqwebmail_content_language,
+ &cnt_filename, &len);
+
+ filenamemime=malloc(len);
+
+ if (filenamemime)
+ {
+ *filenamemime=0;
+ rfc2231_attrCreate(fnStr, cp,
+ sqwebmail_content_charset,
+ sqwebmail_content_language,
+ save_filename, filenamemime);
+ }
+ }
+
+ argvec[0]="makemime";
+ argvec[1]="-c";
+
+ if (attpubkey || attprivkey)
+ {
+ argvec[2]="application/pgp-keys";
+ argvec[3]="-N";
+ argvec[4]="pgpkeys.txt";
+ argvec[5]="-a";
+ argvec[6]="Content-Disposition: attachment; filename=\"pgpkeys.txt\"";
+ n=7;
+ filenamebuf=0;
+ }
+ else
+ {
+ const char *pp;
+
+ argvec[2]=(char *)calc_mime_type(cgi_attachfilename);
+ argvec[3]="-N";
+ argvec[4]=cgi_attachfilename ?
+ (char *)cgi_attachfilename:"filename.dat";
+ n=5;
+
+ pp=*cgi("attach_inline") ?
+ "Content-Disposition: inline":
+ "Content-Disposition: attachment";
+
+ filenamebuf=malloc(strlen(pp)+strlen(filenamemime ?
+ filenamemime:"") + 15);
+
+ if (filenamebuf)
+ {
+ strcpy(filenamebuf, pp);
+ strcat(filenamebuf, filenamemime ? filenamemime:"");
+
+ argvec[n++]="-a";
+ argvec[n++]=filenamebuf;
+ }
+ }
+
+ argvec[n++]="-C";
+ argvec[n++]=(char *)sqwebmail_content_charset;
+
+ signal(SIGCHLD, SIG_DFL);
+
+ argvec[n++]="-";
+ argvec[n++]=0;
+
+ if (pipe(pipefd) < 0)
+ {
+ if (filenamemime)
+ free(filenamemime);
+ if (filenamebuf)
+ free(filenamebuf);
+ maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ fclose(draftfp);
+ close(newdraftfd);
+ close(attachfd);
+ enomem();
+ }
+
+ if (lseek(attachfd, 0L, SEEK_SET) < 0 || (pid1=fork()) < 0)
+ {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ if (filenamemime)
+ free(filenamemime);
+ if (filenamebuf)
+ free(filenamebuf);
+ maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ fclose(draftfp);
+ close(newdraftfd);
+ close(attachfd);
+ enomem();
+ return (0);
+ }
+
+ if (pid1 == 0)
+ {
+ dup2(attachfd, 0);
+ dup2(pipefd[1], 1);
+ close(attachfd);
+ close(newdraftfd);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ execv(MAKEMIME, argvec);
+ fprintf(stderr,
+ "CRIT: exec %s: %s\n", MAKEMIME, strerror(errno));
+ exit(1);
+ }
+
+ if (filenamemime)
+ free(filenamemime);
+ if (filenamebuf)
+ free(filenamebuf);
+
+ close (pipefd[1]);
+
+
+ while ((n=read(pipefd[0], buf, sizeof(buf))) > 0)
+ {
+ maildir_writemsg(newdraftfd, buf, n);
+ }
+ close(pipefd[0]);
+
+ for (;;)
+ {
+ pid2=wait(&waitstat);
+
+ if (pid2 == pid1)
+ {
+ waitstat= WIFEXITED(waitstat) ? WEXITSTATUS(waitstat)
+ : 1;
+ break;
+ }
+
+ if (pid2 == -1)
+ {
+ waitstat=1;
+ break;
+ }
+ }
+
+ if (waitstat > 0 || n < 0)
+ {
+ maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ fclose(draftfp);
+ close(newdraftfd);
+ maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
+ close(attachfd);
+ return (-3);
+ }
+
+ maildir_writemsgstr(newdraftfd, "\n--");
+ maildir_writemsgstr(newdraftfd, boundary);
+ maildir_writemsgstr(newdraftfd, "--\n");
+
+ /* Finish new draft message, let it replace the current one */
+
+ if (maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 1,
+ stat_buf.st_size))
+ {
+ maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
+ free(draftfilename);
+ maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
+ free(attachfilename);
+ rfc2045_free(rfcp);
+ fclose(draftfp);
+ close(attachfd);
+ return (-1);
+ }
+ free(draftfilename);
+
+ fclose(draftfp);
+
+ /* Remove and delete temp attachment file */
+
+ maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
+ free(attachfilename);
+ rfc2045_free(rfcp);
+ return (0);
+}
+
+void doattach(const char *folder, const char *draft)
+{
+int quotaflag=0;
+
+ CHECKFILENAME(draft);
+ if (*cgi("dodelete"))
+ {
+ if (!tokencheck())
+ {
+ attach_delete(draft);
+ tokensave();
+ }
+ }
+ else if (*cgi("upload"))
+ {
+ if (!tokencheck())
+ {
+ quotaflag=attach_upload(draft, NULL, NULL);
+ tokensave();
+ }
+ }
+ else if (*cgi("uppubkey") && libmail_gpg_has_gpg(GPGDIR) == 0)
+ {
+ if (!tokencheck())
+ {
+ quotaflag=attach_upload(draft, cgi("pubkey"), NULL);
+ tokensave();
+ }
+ }
+ else if (*cgi("upprivkey") && *cgi("really") &&
+ libmail_gpg_has_gpg(GPGDIR) == 0)
+ {
+ if (!tokencheck())
+ {
+ quotaflag=attach_upload(draft, NULL, cgi("privkey"));
+ tokensave();
+ }
+ }
+ else if (*cgi("previewmsg"))
+ {
+ cgi_put("draft", draft);
+ newmsg_do(folder);
+ return;
+ }
+ else if (*cgi("sendmsg"))
+ {
+ cgi_put("draftmessage", draft);
+ newmsg_do(folder);
+ return;
+ }
+ else if (*cgi("savedraft"))
+ {
+ sendmsg_done();
+ return;
+ }
+
+ if (quotaflag == -2)
+ {
+ http_redirect_argss(
+ "&form=attachments&pos=%s&draft=%s&error=limits",
+ cgi("pos"), draft);
+ }
+ else if (quotaflag == -3)
+ {
+ http_redirect_argss(
+ "&form=attachments&pos=%s&draft=%s&error=makemime",
+ cgi("pos"), draft);
+ }
+ else
+ {
+ http_redirect_argss(
+ (quotaflag ? "&form=attachments&pos=%s&draft=%s&error=quota":
+ "&form=attachments&pos=%s&draft=%s"), cgi("pos"),
+ draft);
+ }
+}