diff --git a/src/smblib/smbdefs.h b/src/smblib/smbdefs.h index 8dd38a18e349f37e213046ae01a98c17e8ef1a50..093f7ac9ab29ed20a4751deaa1c73dbcd024b263 100644 --- a/src/smblib/smbdefs.h +++ b/src/smblib/smbdefs.h @@ -559,7 +559,8 @@ 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* charset; /* MIME plain-text/charset value (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 */ from_agent, /* Type of agent message is from */ replyto_agent; /* Type of agent replies should be sent to */ diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c index eaad8fbd9bb615a1a966ac7f72cb4affc372965b..95bba4a047ebc0304ea27324ba5470d1ad570aad 100644 --- a/src/smblib/smblib.c +++ b/src/smblib/smblib.c @@ -873,6 +873,7 @@ static void set_convenience_ptr(smbmsg_t* msg, uint16_t hfield_type, void* hfiel p += 13; SKIP_WHITESPACE(p); msg->content_type = p; + smb_parse_content_type(p, &msg->text_subtype, &msg->text_charset); break; } break; @@ -1096,7 +1097,8 @@ void SMBCALL smb_freemsgmem(smbmsg_t* msg) msg->dfield=NULL; } msg->hdr.total_dfields=0; - FREE_AND_NULL(msg->charset); + FREE_AND_NULL(msg->text_subtype); + FREE_AND_NULL(msg->text_charset); smb_freemsghdrmem(msg); } diff --git a/src/smblib/smblib.h b/src/smblib/smblib.h index 03a5dae2b17d697f08418264ba9a4f033802dd81..a271343003ca9c926a1aecac1b91853a671d0170 100644 --- a/src/smblib/smblib.h +++ b/src/smblib/smblib.h @@ -103,7 +103,7 @@ #define GETMSGTXT_TAILS (1<<0) /* Incude message tail(s) */ #define GETMSGTXT_NO_BODY (1<<1) /* Exclude message body */ #define GETMSGTXT_NO_HFIELDS (1<<2) /* Exclude text header fields */ -#define GETMSGTXT_PLAIN (1<<3) /* Get plaintext portion only of MIME-encoded body (all, otherwise) */ +#define GETMSGTXT_PLAIN (1<<3) /* Get text-plain or text-html portion only of MIME-encoded body (all, otherwise) */ /* common smb_getmsgtxt() mode values */ #define GETMSGTXT_BODY_ONLY GETMSGTXT_NO_HFIELDS #define GETMSGTXT_TAIL_ONLY (GETMSGTXT_TAILS|GETMSGTXT_NO_BODY|GETMSGTXT_NO_HFIELDS) @@ -273,6 +273,7 @@ SMBEXPORT char* SMBCALL smb_getmsgtxt(smb_t*, smbmsg_t*, ulong mode); SMBEXPORT char* SMBCALL smb_getplaintext(smbmsg_t*, char* body); SMBEXPORT uint8_t* SMBCALL smb_getattachment(smbmsg_t*, char* body, char* filename, size_t filename_len, uint32_t* filelen, int index); SMBEXPORT ulong SMBCALL smb_countattachments(smb_t*, smbmsg_t*, const char* body); +SMBEXPORT void SMBCALL smb_parse_content_type(const char* content_type, char** subtype, char** charset); /* smbfile.c */ SMBEXPORT int SMBCALL smb_feof(FILE* fp); diff --git a/src/smblib/smbtxt.c b/src/smblib/smbtxt.c index 3634dfc35eaba2cb4a96813069d0bed00ef9103b..90db4941383cf1c927db15a7eeec606611110ee0 100644 --- a/src/smblib/smbtxt.c +++ b/src/smblib/smbtxt.c @@ -322,6 +322,46 @@ static BOOL mime_getattachment(char* beg, char* end, char* attachment, size_t at return FALSE; } +// Parses a MIME text/* content-type header field +void SMBCALL smb_parse_content_type(const char* content_type, char** subtype, char** charset) +{ + if(subtype != NULL) { + FREE_AND_NULL(*subtype); + } + if(charset != NULL) { + FREE_AND_NULL(*charset); + } + if(content_type == NULL) + return; + char buf[512]; + SAFECOPY(buf, content_type); + char* p; + if((p = strstr(buf, "text/")) == buf) { + p += 5; + if(subtype != NULL) { + *subtype = strdup(p); + char* tp = *subtype; + FIND_WHITESPACE(tp); + *tp = 0; + tp = *subtype; + FIND_CHAR(tp, ';'); + *tp = 0; + } + if(charset != NULL && (p = strstr(p, "charset=")) != NULL) { + p += 8; + if(*p == '"') + p++; + char* tp = p; + FIND_WHITESPACE(tp); + *tp = 0; + tp = p; + FIND_CHAR(tp, '"'); + *tp = 0; + *charset = strdup(p); + } + } +} + /* Find the specified content-type in a MIME-encoded message body, recursively */ static char* mime_getcontent(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) @@ -367,6 +407,7 @@ static char* mime_getcontent(char* buf, const char* content_type, const char* co p = strstr(txt, "\r\n\r\n"); /* End of header */ if(p==NULL) continue; + *p = 0; // terminate the header char* content_type; for(content_type = txt; content_type < p; content_type++) { SKIP_WHITESPACE(content_type); @@ -392,25 +433,10 @@ static char* mime_getcontent(char* buf, const char* content_type, const char* co } if(encoding != NULL) *encoding = mime_getxferencoding(txt, p); - if(charset != NULL) { - content_type += match_len; - SKIP_WHITESPACE(content_type); - if(strnicmp(content_type, "charset=", 8) == 0) { - content_type += 8; - if(*content_type == '"') - content_type++; - char* tp = content_type; - FIND_WHITESPACE(tp); - *tp = 0; - tp = content_type; - FIND_CHAR(tp, '"'); - *tp = 0; - FREE_AND_NULL(*charset); - *charset = strdup(content_type); - } - } + if(charset != NULL) + smb_parse_content_type(content_type, NULL, charset); - txt = p; + txt = p + 4; // strlen("\r\n\r\n") SKIP_WHITESPACE(txt); if((p = strstr(txt, boundary)) != NULL) *p = 0; @@ -419,19 +445,26 @@ static char* mime_getcontent(char* buf, const char* content_type, const char* co return NULL; } -/* Get just the plain-text portion of a MIME-encoded message body */ -/* Returns NULL if there is no MIME-encoded plain-text portion of the message */ +/* 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* txt; enum content_transfer_encoding xfer_encoding = CONTENT_TRANFER_ENCODING_NONE; + FREE_AND_NULL(msg->text_subtype); 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->charset + 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) - return NULL; + if(txt == NULL) { + txt = mime_getcontent(buf, msg->content_type, "text/html", 0, &xfer_encoding, &msg->text_charset + ,/* attachment: */NULL, /* attachment_len: */0, /* index: */0); + if(txt == NULL) + return NULL; + msg->text_subtype = strdup("html"); + } else + msg->text_subtype = strdup("plain"); memmove(buf, txt, strlen(txt)+1); if(*buf == 0) /* No decoding necessary */