diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 |
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 |
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /sqwebmail/attachments.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'sqwebmail/attachments.c')
| -rw-r--r-- | sqwebmail/attachments.c | 1142 |
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\" /> ", + 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\"> <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> </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); + } +} |
