?? maildecoder.cpp
字號:
// =============================================================
// Multi-Purpose Internet Mail Extensions decoder
//
// Purpose: converts a mime encoded e-mail message from
// a string and converts to a tree structure.
//
// This file is part of Eplug
//
// Copyright (c) 2002 - 2003 Pylon Software
// =============================================================
#pragma warning (disable : 4786)
// -------------------------------------------------------------
#include "Base64Decoder.h"
#include "MailDecoder.h"
// -------------------------------------------------------------
static Mime MimeKeywords[] = {
Mime("Return-Path", MIME_RETURNPATH),
Mime("Message-ID", MIME_MESSAGEID),
Mime("From", MIME_FROM),
Mime("To", MIME_TO),
Mime("Cc", MIME_CC),
Mime("Subject", MIME_SUBJECT),
Mime("Date", MIME_DATE),
Mime("MIME-Version", MIME_VERSION),
Mime("Content-Type", MIME_CONTENTTYPE),
Mime("Content-Transfer-Encoding", MIME_CONTENTTRANSFERENCODING),
Mime("Content-Disposition", MIME_CONTENTDISPOSITION),
};
// -------------------------------------------------------------
MailDecoder::MailDecoder() :
m_raw_text(),
m_pos(0),
m_section_pos(0),
m_decoded(NULL),
m_current_section(NULL),
m_current_block(NULL) {
}
bool
MailDecoder::open(std::string mail_content) {
close();
m_raw_text = mail_content;
m_pos = 0;
BlockHeading heading;
DecodeHeadingSection(heading);
DecodeMailSection(heading);
LogMailContents();
return true;
}
void
MailDecoder::close() {
if (m_decoded) {
delete m_decoded;
m_decoded = NULL;
}
}
MailDecoder::~MailDecoder() {
close();
}
// -------------------------------------------------------------
void
MailDecoder::BeginSection() {
MailSection *section = new MailSection;
section->parent = m_current_section;
if (m_current_section)
m_current_section->children.push_back(section);
else
m_decoded = section;
m_current_section = section;
}
void
MailDecoder::EndSection() {
m_current_section = m_current_section->parent;
m_current_block = (m_current_section) ? m_current_section->content.back() : NULL;
}
void
MailDecoder::NewBlock() {
MailBlock *block = new MailBlock;
memset(block, 0, sizeof(MailBlock));
m_current_section->content.push_back(block);
m_current_block = block;
}
void
MailDecoder::SkipWhite() {
while ((m_pos < m_raw_text.length()) && (isspace(m_raw_text[m_pos])))
++m_pos;
}
void
MailDecoder::CopyHeading(BlockHeading &a, BlockHeading &b) {
a.m_boundary = b.m_boundary;
a.m_charset = b.m_charset;
a.m_content_encoding = b.m_content_encoding;
a.m_content_type = b.m_content_type;
a.m_date = b.m_date;
a.m_from = b.m_from;
a.m_message_id = b.m_message_id;
a.m_mime_version = b.m_mime_version;
a.m_return_path = b.m_return_path;
a.m_subject = b.m_subject;
a.m_to = b.m_to;
a.m_cc = b.m_cc;
a.m_content_disposition = b.m_content_disposition;
a.m_filename = b.m_filename;
}
// -------------------------------------------------------------
MimeEnum
MailDecoder::MatchMimeString(std::string s) {
for (int i = 0; i < sizeof(MimeKeywords) / sizeof(std::string); ++i)
if (stricmp(MimeKeywords[i].m_s.c_str(), s.c_str()) == 0)
return MimeKeywords[i].m_mime;
return MIME_UNKNOWN;
}
std::string
MailDecoder::GetFieldName() {
SkipWhite();
std::string tmp;
while ((m_pos < m_raw_text.length()) && (isprint(m_raw_text[m_pos])) && (!isspace(m_raw_text[m_pos])) && (m_raw_text[m_pos] != ':'))
tmp += m_raw_text[m_pos++];
SkipWhite();
return (m_raw_text[m_pos] == ':') ? tmp : "";
}
std::string
MailDecoder::GatherParameters() {
std::string tmp;
while ((m_pos < m_raw_text.length()) && ((m_raw_text[m_pos] != 0x0D) && (m_raw_text[m_pos] != 0x0A)))
tmp += m_raw_text[m_pos++];
while ((m_pos < m_raw_text.length()) && ((m_raw_text[m_pos] == 0x0D) || (m_raw_text[m_pos] == 0x0A)))
++m_pos;
while (isspace(m_raw_text[m_pos])) {
if ((m_raw_text[m_pos] == 0x0D) || (m_raw_text[m_pos] == 0x0A))
break;
SkipWhite();
tmp += ' ';
while ((m_pos < m_raw_text.length()) && ((m_raw_text[m_pos] != 0x0D) && (m_raw_text[m_pos] != 0x0A)))
tmp += m_raw_text[m_pos++];
while ((m_pos < m_raw_text.length()) && ((m_raw_text[m_pos] == 0x0D) || (m_raw_text[m_pos] == 0x0A)))
++m_pos;
}
return tmp;
}
std::string
MailDecoder::DeQuoteString(std::string &s) {
if (((s[0] == '\"') && (s[s.length() - 1] == '\"')) ||
((s[0] == '<') && (s[s.length() - 1] == '>')))
return s.substr(1, s.length() - 2);
return s;
}
std::string
MailDecoder::ReadLine() {
std::string tmp;
while ((m_pos < m_raw_text.length()) && ((m_raw_text[m_pos] != 0x0D) && (m_raw_text[m_pos] != 0x0A)))
tmp += m_raw_text[m_pos++];
while ((m_pos < m_raw_text.length()) && ((m_raw_text[m_pos] == 0x0D) || (m_raw_text[m_pos] == 0x0A)))
++m_pos;
return tmp;
}
void
MailDecoder::DecodeHeadingSection(BlockHeading &heading) {
SkipWhite();
while ((m_pos < m_raw_text.length()) && (!isspace(m_raw_text[m_pos]))) {
int prev_pos = m_pos;
// field name
std::string fieldname = GetFieldName();
if (!fieldname.empty()) {
m_pos++; // assume there is a : there
SkipWhite();
// field params
std::string params = GatherParameters();
// use fieldname with params
switch(MatchMimeString(fieldname)) {
case MIME_RETURNPATH :
DecodeParameters(MIME_RETURNPATH, params, heading, &heading.m_return_path);
break;
case MIME_MESSAGEID :
DecodeParameters(MIME_MESSAGEID, params, heading, &heading.m_message_id);
break;
case MIME_FROM :
DecodeParameters(MIME_FROM, params, heading, &heading.m_from);
break;
case MIME_TO :
DecodeParameters(MIME_TO, params, heading, &heading.m_to);
break;
case MIME_CC :
DecodeParameters(MIME_CC, params, heading, &heading.m_cc);
break;
case MIME_SUBJECT :
DecodeParameters(MIME_SUBJECT, params, heading, &heading.m_subject);
break;
case MIME_DATE :
DecodeParameters(MIME_DATE, params, heading, &heading.m_date);
break;
case MIME_VERSION :
DecodeParameters(MIME_VERSION, params, heading, &heading.m_mime_version);
break;
case MIME_CONTENTTYPE :
DecodeParameters(MIME_CONTENTTYPE, params, heading, &heading.m_content_type);
break;
case MIME_CONTENTTRANSFERENCODING :
DecodeParameters(MIME_CONTENTTRANSFERENCODING, params, heading, &heading.m_content_encoding);
break;
case MIME_CONTENTDISPOSITION :
DecodeParameters(MIME_CONTENTDISPOSITION, params, heading, &heading.m_content_disposition);
break;
}
} else {
m_pos = prev_pos;
break;
}
}
}
void
MailDecoder::DecodeMailSection(BlockHeading &heading) {
// allocate new section
BeginSection();
NewBlock();
// copy heading
CopyHeading(m_current_block->heading, heading);
// handle subheadings and text
if (heading.m_boundary.empty()) {
// copy text
while (m_pos < m_raw_text.length()) {
m_current_block->content += ReadLine();
m_current_block->content += 0x0D;
m_current_block->content += 0x0A;
}
} else {
// copy text and subheadings
while (m_pos < m_raw_text.length()) {
// copy lines until we find the first boundary line
while (m_pos < m_raw_text.length()) {
std::string line = ReadLine();
if ((line[0] == '-') && (line[1] == '-') && (strncmp(line.c_str() + 2, heading.m_boundary.c_str(), heading.m_boundary.length()) == 0))
break;
m_current_block->content += line;
m_current_block->content += 0x0D;
m_current_block->content += 0x0A;
}
while (m_pos < m_raw_text.length()) {
BlockHeading new_heading;
DecodeHeadingSection(new_heading);
// if this is a new section, allocate it and handle it recursively
if (!new_heading.m_boundary.empty()) {
DecodeMailSection(new_heading);
} else {
NewBlock();
CopyHeading(m_current_block->heading, new_heading);
}
// continue copying until we find the last boundary line
while (m_pos < m_raw_text.length()) {
std::string line = ReadLine();
if (strncmp(line.c_str() + 2, heading.m_boundary.c_str(), heading.m_boundary.length()) == 0) {
if ((heading.m_boundary.length() == line.length() - 4) &&
(line[line.length() - 2] == '-') && (line[line.length() - 1] == '-')) {
EndSection();
return;
} else {
break;
}
}
m_current_block->content += line;
m_current_block->content += 0x0D;
m_current_block->content += 0x0A;
}
}
}
}
}
void
MailDecoder::DecodeParameters(MimeEnum mime, std::string ¶ms, BlockHeading &heading, std::string *attribute) {
int i = 0;
std::string *tmp_string = attribute;
// try to decode the following data
switch(mime) {
// multiple <> ids seperated by commas
case MIME_TO :
case MIME_CC :
case MIME_MESSAGEID :
case MIME_RETURNPATH :
while (i < params.length()) {
std::string tmp;
while ((i < params.length()) && (params[i] != ','))
tmp += params[i++];
++i;
while ((i < params.length()) && ((params[i] == ' ') || (params[i] == 0x0A) || (params[i] == 0x0D)))
++i;
if ((*tmp_string).empty())
*tmp_string = DeQuoteString(tmp);
else
*tmp_string += "," + DeQuoteString(tmp);
}
break;
// one descriptor, followed by ; and key/'='/value pairs
case MIME_CONTENTTYPE :
case MIME_CONTENTTRANSFERENCODING :
case MIME_CONTENTDISPOSITION :
while ((i < params.length()) && (params[i] != ';'))
*tmp_string += params[i++];
*tmp_string = DeQuoteString(*tmp_string);
// read next parts
while (i < params.length()) {
// if a ; is there, skip it
if (params[i] == ';')
++i;
// skip white
while ((i < params.length()) && (params[i] == ' '))
++i;
// read l-value
std::string w;
while ((i < params.length()) && (params[i] != '='))
w += params[i++];
// move beyond the = sign
++i;
// if found, skip it
if (strnicmp(w.c_str(), "boundary", 8) == 0)
tmp_string = &heading.m_boundary;
else if (strnicmp(w.c_str(), "charset", 7) == 0)
tmp_string = &heading.m_charset;
else if (strnicmp(w.c_str(), "filename", 8) == 0)
tmp_string = &heading.m_filename;
else
tmp_string = NULL;
// skip white
while ((i < params.length()) && (params[i] == ' '))
++i;
// read the r-value
std::string tmp;
while (i < params.length())
tmp += params[i++];
// assign the tmp string
if (tmp_string)
*tmp_string = DeQuoteString(tmp);
// skip white
while ((i < params.length()) && (params[i] == ' '))
++i;
}
break;
// just copy the text
default :
while (i < params.length())
*tmp_string += params[i++];
break;
}
}
// -------------------------------------------------------------
void
MailDecoder::LogMailContents() {
FILE *f = fopen("log.txt", "a+");
LogMailContents(f, m_decoded);
fclose(f);
}
void
MailDecoder::LogMailContents(FILE *f, MailSection *block) {
for (int j = 0; j < block->content.size(); ++j) {
MailBlock *the_block = block->content[j];
fprintf(f, "[section %d]\n", j);
fprintf(f, "From: %s\n", the_block->heading.m_from.c_str());
fprintf(f, "To: %s\n", the_block->heading.m_to.c_str());
fprintf(f, "Cc: %s\n", the_block->heading.m_cc.c_str());
fprintf(f, "Subject: %s\n", the_block->heading.m_subject.c_str());
fprintf(f, "Content-Type: %s\n", the_block->heading.m_content_type.c_str());
fprintf(f, "Content-Encoding: %s\n", the_block->heading.m_content_encoding.c_str());
fprintf(f, "Content-Disposition: %s\n", the_block->heading.m_content_disposition.c_str());
fprintf(f, "Content-Filename: %s\n", the_block->heading.m_filename.c_str());
fprintf(f, "Content-Size: %d\n", the_block->content.length());
fprintf(f, "Content-Data: \n%s\n\n", the_block->content.c_str());
if (the_block->heading.m_content_encoding == "base64") {
// decode mime data
int size = DecodeFileBase64(NULL, the_block->content.c_str());
unsigned char *s = new unsigned char[size];
DecodeFileBase64(s, the_block->content.c_str());
// save mime data
if (!the_block->heading.m_filename.empty()) {
FILE *f = fopen(the_block->heading.m_filename.c_str(), "wb");
fwrite(s, size, 1, f);
fclose(f);
}
// and get rid of the decoded data
delete [] s;
}
}
for (int i = 0; i < block->children.size(); ++i) {
LogMailContents(f, block->children[i]);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -