/* ** 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 #include #include #include #include #include #if HAVE_UNISTD_H #include #endif #include #include #if HAVE_SYS_WAIT_H #include #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 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(""); 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("", showsize(end_pos - start_body)); } if (cnt == 0) printf("\n", noattach_lab); printf("
 ", 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("  %s
%s
\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("
", pref_noarchive ? "":" checked=\"checked\"", getarg("PRESERVELAB")); if (auth_getoptionenvint("wbnodsn") == 0) printf("
", getarg("DSN")); if (libmail_gpg_has_gpg(GPGDIR) == 0) { char *all_addr; printf("
\n"); all_addr=newmsg_alladdrs(fp); printf("" "" "\n"); if (ishttps()) printf("\n", getarg("PASSPHRASE")); printf("
 %s

\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= 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); } }