diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c index 00b9683cab38fe904cfb1b60aab93850256e097d..5bde6041fd811c74d779e516c9582cbde43ce3a0 100644 --- a/src/sbbs3/mailsrvr.c +++ b/src/sbbs3/mailsrvr.c @@ -2715,44 +2715,6 @@ static void parse_mail_address(char* p strip_char(name, name, '\\'); } -/* Decode quoted-printable content-transfer-encoded text */ -/* Ignores (strips) unsupported ctrl chars and non-ASCII chars */ -/* Does not enforce 76 char line length limit */ -static char* qp_decode(char* buf) -{ - uchar* p=(uchar*)buf; - uchar* dest=p; - - for(;;p++) { - if(*p==0) { - *dest++='\r'; - *dest++='\n'; - break; - } - if(*p==' ' || (*p>='!' && *p<='~' && *p!='=') || *p=='\t') - *dest++=*p; - else if(*p=='=') { - p++; - if(*p==0) /* soft link break */ - break; - if(IS_HEXDIGIT(*p) && IS_HEXDIGIT(*(p+1))) { - char hex[3]; - hex[0]=*p; - hex[1]=*(p+1); - hex[2]=0; - /* ToDo: what about encoded NULs and the like? */ - *dest++=(uchar)strtoul(hex,NULL,16); - p++; - } else { /* bad encoding */ - *dest++='='; - *dest++=*p; - } - } - } - *dest=0; - return buf; -} - static BOOL checktag(scfg_t *scfg, char *tag, uint usernum) { char fname[MAX_PATH+1]; @@ -2950,12 +2912,6 @@ static void smtp_thread(void* arg) } cmd = SMTP_CMD_NONE; - enum { - ENCODING_NONE - ,ENCODING_BASE64 - ,ENCODING_QUOTED_PRINTABLE - } content_encoding = ENCODING_NONE; - SetThreadName("sbbs/smtp"); thread_up(TRUE /* setuid */); @@ -4059,24 +4015,7 @@ static void smtp_thread(void* arg) p=buf; if(*p=='.') p++; /* Transparency (RFC821 4.5.2) */ if(msgtxt!=NULL) { - switch(content_encoding) { - case ENCODING_BASE64: - { - char decode_buf[sizeof(buf)]; - - if(b64_decode(decode_buf, sizeof(decode_buf), p, strlen(p))<0) - fprintf(msgtxt,"\r\n!Base64 decode error: %s\r\n", p); - else - fputs(decode_buf, msgtxt); - } - break; - case ENCODING_QUOTED_PRINTABLE: - fputs(qp_decode(p), msgtxt); - break; - default: - fprintf(msgtxt, "%s\r\n", p); - break; - } + fputs(p, msgtxt); } lines++; /* release time-slices every x lines */ @@ -4102,20 +4041,6 @@ static void smtp_thread(void* arg) ,sender, sizeof(sender)-1 ,sender_addr, sizeof(sender_addr)-1); } - else if(stricmp(field,"CONTENT-TRANSFER-ENCODING")==0) { - lprintf(LOG_INFO,"%04d %s %s %s = %s", socket, client.protocol, client_id, field, p); - if(stricmp(p,"base64")==0) - content_encoding=ENCODING_BASE64; - else if(stricmp(p,"quoted-printable")==0) - content_encoding=ENCODING_QUOTED_PRINTABLE; - else { /* Other (e.g. 7bit, 8bit, binary) */ - content_encoding=ENCODING_NONE; - if(msgtxt!=NULL) - fprintf(msgtxt, "%s\r\n", buf); - } - hdr_lines++; - continue; - } } } @@ -4410,7 +4335,6 @@ static void smtp_thread(void* arg) break; } rcpt_count=0; - content_encoding=ENCODING_NONE; memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count); @@ -4468,7 +4392,6 @@ static void smtp_thread(void* arg) break; } rcpt_count=0; - content_encoding=ENCODING_NONE; memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count); sockprintf(socket,client.protocol,session,ok_rsp); badcmds=0; diff --git a/src/smblib/smbdefs.h b/src/smblib/smbdefs.h index 89d195f53dfbf80f672839e719a16b7f6c8b6bcc..36e7797d958427ffe467922552b1cdaed7b9ee0e 100644 --- a/src/smblib/smbdefs.h +++ b/src/smblib/smbdefs.h @@ -558,6 +558,7 @@ typedef struct { /* Message */ char* editor; /* Message editor (if known) */ char* mime_version; /* MIME Version (if applicable) */ char* content_type; /* MIME Content-Type (if applicable) */ + char* content_encoding; /* MIME Content-Transfer-Encoding (if applicable) */ char* text_charset; /* MIME text <charset> (if applicable) - malloc'd */ char* text_subtype; /* MIME text/<sub-type> (if applicable) - malloc'd */ uint16_t to_agent, /* Type of agent message is to */ diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c index a670a1262acaa013c1b415d88ddaa55317d2e63b..d0ce6c6334d02a5c72e9123d6e268355a1529753 100644 --- a/src/smblib/smblib.c +++ b/src/smblib/smblib.c @@ -859,6 +859,12 @@ static void set_convenience_ptr(smbmsg_t* msg, uint16_t hfield_type, void* hfiel smb_parse_content_type(p, &(msg->text_subtype), &(msg->text_charset)); break; } + if(strnicmp(p, "Content-Transfer-Encoding:", 26) == 0) { + p += 26; + SKIP_WHITESPACE(p); + msg->content_encoding = p; + break; + } break; } } @@ -897,6 +903,7 @@ static void clear_convenience_ptrs(smbmsg_t* msg) msg->newsgroups=NULL; msg->mime_version=NULL; msg->content_type=NULL; + msg->content_encoding=NULL; msg->text_subtype=NULL; msg->text_charset=NULL; diff --git a/src/smblib/smbtxt.c b/src/smblib/smbtxt.c index 0ffce0d1d5320d54dda792feee3625b5782544da..4d67dcec76c24c4d4793735cf009fa58e9e37ba7 100644 --- a/src/smblib/smbtxt.c +++ b/src/smblib/smbtxt.c @@ -1,7 +1,5 @@ /* Synchronet message base (SMB) message text library routines */ -/* $Id: smbtxt.c,v 1.49 2019/11/19 22:04:55 rswindell Exp $ */ - /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * @@ -15,21 +13,9 @@ * See the GNU Lesser General Public License for more details: lgpl.txt or * * http://www.fsf.org/copyleft/lesser.html * * * - * Anonymous FTP access to the most recent released source is available at * - * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * - * * - * Anonymous CVS access to the development source and modification history * - * is available at cvs.synchro.net:/cvsroot/sbbs, example: * - * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * - * (just hit return, no password is necessary) * - * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * - * * * For Synchronet coding style and modification guidelines, see * * http://www.synchro.net/source.html * * * - * You are encouraged to submit any modifications (preferably in Unix diff * - * format) via e-mail to mods@synchro.net * - * * * Note: If this box doesn't appear square, then you need to fix your tabs. * ****************************************************************************/ @@ -42,7 +28,7 @@ #include "base64.h" #include "lzh.h" -char* SMBCALL smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, ulong mode) +char* smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, ulong mode) { char* buf; char* preamble; @@ -217,7 +203,7 @@ char* SMBCALL smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, ulong mode) return(buf); } -void SMBCALL smb_freemsgtxt(char* buf) +void smb_freemsgtxt(char* buf) { if(buf!=NULL) free(buf); @@ -275,6 +261,22 @@ static size_t strStartsWith_i(const char* buf, const char* match) return 0; } +static enum content_transfer_encoding mime_encoding(const char* str) +{ + const char* p = str; + + if(str == NULL) + return CONTENT_TRANFER_ENCODING_NONE; + SKIP_WHITESPACE(p); + if(strnicmp(p, "base64", 6) == 0) + return CONTENT_TRANFER_ENCODING_BASE64; + if(strnicmp(p, "quoted-printable", 16) == 0) + return CONTENT_TRANFER_ENCODING_QUOTED_PRINTABLE; + if(strnicmp(p, "7bit", 4) == 0 || strnicmp(p, "8bit", 4) == 0 || strnicmp(p, "binary", 6) == 0) + return CONTENT_TRANFER_ENCODING_NONE; + return CONTENT_TRANFER_ENCODING_OTHER; +} + static enum content_transfer_encoding mime_getxferencoding(const char* beg, const char* end) { const char* p = beg; @@ -286,15 +288,7 @@ static enum content_transfer_encoding mime_getxferencoding(const char* beg, cons FIND_CHAR(p, '\n'); continue; } - p += len; - SKIP_WHITESPACE(p); - if(strnicmp(p, "base64", 6) == 0) - return CONTENT_TRANFER_ENCODING_BASE64; - if(strnicmp(p, "quoted-printable", 16) == 0) - return CONTENT_TRANFER_ENCODING_QUOTED_PRINTABLE; - if(strnicmp(p, "7bit", 4) == 0 || strnicmp(p, "8bit", 4) == 0 || strnicmp(p, "binary", 6) == 0) - return CONTENT_TRANFER_ENCODING_NONE; - return CONTENT_TRANFER_ENCODING_OTHER; + return mime_encoding(p + len); } return CONTENT_TRANFER_ENCODING_NONE; @@ -354,7 +348,7 @@ static BOOL mime_getattachment(const char* beg, const char* end, char* attachmen } // Parses a MIME text/* content-type header field -void SMBCALL smb_parse_content_type(const char* content_type, char** subtype, char** charset) +void smb_parse_content_type(const char* content_type, char** subtype, char** charset) { if(subtype != NULL) { FREE_AND_NULL(*subtype); @@ -405,8 +399,8 @@ void SMBCALL smb_parse_content_type(const char* content_type, char** subtype, ch } } -/* Find the specified content-type in a multi-pat MIME-encoded message body, recursively */ -static const char* mime_getcontent(const char* buf, const char* content_type, const char* content_match +/* Find the specified content-type in a multi-part MIME-encoded message body, recursively */ +static const char* mime_getpart(const char* buf, const char* content_type, const char* content_match ,int depth, enum content_transfer_encoding* encoding, char** charset, char* attachment, size_t attachment_len, int index) { const char* txt; @@ -465,12 +459,12 @@ static const char* mime_getcontent(const char* buf, const char* content_type, co const char* cp; if((match_len && strnicmp(content_type, match1, match_len) && strnicmp(content_type, match2, match_len)) || (attachment != NULL && !mime_getattachment(txt, p, attachment, attachment_len))) { - if((cp = mime_getcontent(p, content_type, content_match, depth + 1, encoding, charset, attachment, attachment_len, index)) != NULL) + if((cp = mime_getpart(p, content_type, content_match, depth + 1, encoding, charset, attachment, attachment_len, index)) != NULL) return cp; continue; } if(found++ != index) { - if((cp = mime_getcontent(p, content_type, content_match, depth + 1, encoding, charset, attachment, attachment_len, index)) != NULL) + if((cp = mime_getpart(p, content_type, content_match, depth + 1, encoding, charset, attachment, attachment_len, index)) != NULL) return cp; continue; } @@ -490,29 +484,41 @@ static const char* mime_getcontent(const char* buf, const char* content_type, co /* Get just the (first) plain-text or HTML portion of a MIME-encoded multi-part message body */ /* Returns NULL if there is no MIME-encoded plain-text/html portion of the message */ -char* SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf) +char* smb_getplaintext(smbmsg_t* msg, char* buf) { + size_t len; const char* txt; enum content_transfer_encoding xfer_encoding = CONTENT_TRANFER_ENCODING_NONE; if(msg->mime_version == NULL || msg->content_type == NULL) /* not MIME */ return NULL; - txt = mime_getcontent(buf, msg->content_type, "text/plain", 0, &xfer_encoding, &msg->text_charset - ,/* attachment: */NULL, /* attachment_len: */0, /* index: */0); - if(txt == NULL) { - txt = mime_getcontent(buf, msg->content_type, "text/html", 0, &xfer_encoding, &msg->text_charset + if(strStartsWith_i(msg->content_type, "multipart/") > 0) { + txt = mime_getpart(buf, msg->content_type, "text/plain", 0, &xfer_encoding, &msg->text_charset ,/* attachment: */NULL, /* attachment_len: */0, /* index: */0); - if(txt == NULL) - return NULL; - free(msg->text_subtype); - msg->text_subtype = strdup("html"); + if(txt == NULL) { + txt = mime_getpart(buf, msg->content_type, "text/html", 0, &xfer_encoding, &msg->text_charset + ,/* attachment: */NULL, /* attachment_len: */0, /* index: */0); + if(txt == NULL) + return NULL; + free(msg->text_subtype); + msg->text_subtype = strdup("html"); + } else { + free(msg->text_subtype); + msg->text_subtype = strdup("plain"); + } + + len = strlen(txt); + memmove(buf, txt, len + 1); } else { - free(msg->text_subtype); - msg->text_subtype = strdup("plain"); + /* Single-part MIME */ + if(strStartsWith_i(msg->content_type, "text/") < 1) { + *buf = '\0'; + return buf; + } + xfer_encoding = mime_encoding(msg->content_encoding); + len = strlen(buf); } - - memmove(buf, txt, strlen(txt)+1); - if(*buf == 0) /* No decoding necessary */ + if(len == 0) /* No decoding necessary */ return buf; if(xfer_encoding == CONTENT_TRANFER_ENCODING_QUOTED_PRINTABLE) qp_decode(buf); @@ -520,41 +526,75 @@ char* SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf) char* decoded = strdup(buf); if(decoded == NULL) return NULL; - if(b64_decode(decoded, strlen(decoded), buf, strlen(buf)) > 0) + if(b64_decode(decoded, len, buf, len) > 0) strcpy(buf, decoded); free(decoded); } - return buf; } -/* Get just a base64-encoded attachment (just one) from MIME-encoded message body */ -/* This function is destructive (over-writes 'buf' with decoded attachment)! */ -uint8_t* SMBCALL smb_getattachment(smbmsg_t* msg, char* buf, char* filename, size_t filename_len, uint32_t* filelen, int index) +/* Get an attachment (just one) from single-part or multi-part MIME-encoded message body */ +/* This function can be destructive (over-write 'buf' with decoded attachment)! */ +uint8_t* smb_getattachment(smbmsg_t* msg, char* buf, char* filename, size_t filename_len, uint32_t* filelen, int index) { const char* txt; enum content_transfer_encoding xfer_encoding = CONTENT_TRANFER_ENCODING_NONE; if(msg->mime_version == NULL || msg->content_type == NULL) /* not MIME */ return NULL; - txt = mime_getcontent(buf, msg->content_type, /* match-type: */NULL, 0, &xfer_encoding, /* charset: */NULL - ,/* attachment: */filename, filename_len, index); - if(txt != NULL && xfer_encoding == CONTENT_TRANFER_ENCODING_BASE64) { - memmove(buf, txt, strlen(txt)+1); - int result = b64_decode(buf, strlen(buf), buf, strlen(buf)); + if(strStartsWith_i(msg->content_type, "multipart/") > 0) { + txt = mime_getpart(buf, msg->content_type, /* match-type: */NULL, 0, &xfer_encoding, /* charset: */NULL + ,/* attachment: */filename, filename_len, index); + if(txt != NULL && xfer_encoding == CONTENT_TRANFER_ENCODING_BASE64) { + size_t len = strlen(txt); + memmove(buf, txt, len + 1); + int result = b64_decode(buf, len, buf, len); + if(result < 1) + return NULL; + if(filelen != NULL) + *filelen = result; + return (uint8_t*)buf; + } + return NULL; /* No attachment */ + } + /* Single-part MIME */ + if(index > 0) + return NULL; + if(strStartsWith_i(msg->content_type, "text/") > 0) + return NULL; + if(filename != NULL) { + char* fname = strstr(msg->content_type, "name="); + if(fname == NULL) + return NULL; + fname += 5; + char* term = NULL; + if(*fname == '"') { + fname++; + term = strchr(fname, '"'); + } else + term = strchr(fname, ';'); + if(term != NULL) + *term = '\0'; + strncpy(filename, fname, filename_len); + filename[filename_len - 1] = '\0'; + } + if(mime_encoding(msg->content_encoding) == CONTENT_TRANFER_ENCODING_BASE64) { + size_t len = strlen(buf); + int result = b64_decode(buf, len, buf, len); if(result < 1) return NULL; if(filelen != NULL) *filelen = result; - return (uint8_t*)buf; + } else { + if(filelen != NULL) + *filelen = strlen(buf); } - - return NULL; /* No attachment */ + return buf; } /* Return number of file attachments contained in MIME-encoded message body */ /* 'body' may be NULL if the body text is not already read/available */ -ulong SMBCALL smb_countattachments(smb_t* smb, smbmsg_t* msg, const char* body) +ulong smb_countattachments(smb_t* smb, smbmsg_t* msg, const char* body) { if(msg->mime_version == NULL || msg->content_type == NULL) /* not MIME */ return 0;