⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maildecoder.cpp

📁 .net 方面的开发说明资料。
💻 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 &params, 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 + -