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

📄 mailmessage.cpp

📁 funambol windows mobile plugin source code, the source code is taken from the funambol site
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (C) 2003-2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307  USA
 */

#include "base/fscapi.h"
#include "base/util/utils.h"
#include "base/quoted-printable.h"
#include "base/Log.h"
#include "spds/spdsutils.h"
#include "spds/MailMessage.h"

//------------------------------------------------------------------ Defines

// Headers names
#define NL          "\n"
#define FROM        "From: "
#define TO          "To: "
#define CC          "CC: "
#define BCC         "BCC: "
#define DATE        "Date: "
#define RECEIVED    "Received:"
#define SUBJECT     "Subject: "
#define MIMETYPE    "Content-Type: "
#define CT_NAME     "name="
#define CT_CHARSET  "charset="
#define MIMEVERS    "Mime-Version: "
#define MESSAGEID   "Message-ID: "
#define DISPOSITION "Content-Disposition:"
#define CD_FILENAME "filename="
#define ENCODING    "Content-Transfer-Encoding: "

#define MULTIPART   "multipart/"


// Header names' length
static const unsigned char FROM_LEN = strlen(FROM);
static const unsigned char TO_LEN   = strlen(TO);
static const unsigned char CC_LEN   = strlen(CC);
static const unsigned char BCC_LEN  = strlen(BCC);
static const unsigned char DATE_LEN  = strlen(DATE);
static const unsigned char SUBJECT_LEN = strlen(SUBJECT);
static const unsigned char MIMETYPE_LEN = strlen(MIMETYPE);
static const unsigned char MIMEVERS_LEN = strlen(MIMEVERS);
static const unsigned char MESSAGEID_LEN = strlen(MESSAGEID);
static const unsigned char DISPOSITION_LEN = strlen(DISPOSITION);
static const unsigned char ENCODING_LEN = strlen(ENCODING);

//---------------------------------------------------------------- Accessors

const char *MailMessage::getTo() const { return to.c_str(); }
void MailMessage::setTo(const char *to) { this->to = to; }

const char *MailMessage::getFrom() const { return from.c_str(); }
void MailMessage::setFrom(const char *from) { this->from = from; }

const char *MailMessage::getCc() const { return cc.c_str(); }
void MailMessage::setCc(const char *cc) { this->cc = cc; }

const char *MailMessage::getBcc() const { return bcc.c_str(); }
void MailMessage::setBcc(const char *bcc) { this->bcc = bcc; }

//        int addHeader(const char *name, const char *content);
const char *MailMessage::getSubject() const { return subject.c_str(); }
void MailMessage::setSubject(const char *subj) { subject = subj; }

const BasicTime& MailMessage::getDate() const { return date; }
void MailMessage::setDate(const BasicTime& v) { date = v; }

const BasicTime& MailMessage::getReceived() const { return received; }

const char * MailMessage::getContentType() const { return contentType; }
void MailMessage::setContentType(const char *val) { contentType = val; }

const char * MailMessage::getBoundary() const { return boundary; }
void MailMessage::setBoundary(const char *val) { boundary = val; }

const char * MailMessage::getMimeVersion() const { return mimeVersion; }
void MailMessage::setMimeVersion(const char *val) { mimeVersion = val; }

const char * MailMessage::getMessageId() const { return messageId; }
void MailMessage::setMessageId(const char *val) { messageId = val; }

const char* MailMessage::getEntryID() { return entryId.c_str(); }
void MailMessage::setEntryID(const char* id) { entryId = id; }

BodyPart & MailMessage::getBody() { return body; }
void MailMessage::setBody(BodyPart &body) { this->body = body; }

// Alternate representation
//BodyPart * MailMessage::getAlternate() { return alternate; };
//void MailMessage::setAlternate(BodyPart &alt) { alternate = new BodyPart(alt); };

BodyPart * MailMessage::getFirstAttachment() {
    return (BodyPart *)attachments.front();
}

BodyPart * MailMessage::getNextAttachment() {
    return (BodyPart *)attachments.next();
}

int MailMessage::addAttachment(BodyPart &body) {
    return attachments.add(body);
}

int MailMessage::attachmentCount() {
    return attachments.size();
}

//----------------------------------------------------------- Static Functions

static StringBuffer formatBodyPart(const BodyPart &part)
{
    StringBuffer ret;

    LOG.debug("FormatBodyPart START");

    ret = MIMETYPE;
    ret += part.getMimeType(); ret += ";\n";
    if( part.getFilename() ) {
        ret += "        "; ret += CT_NAME; ret += "\""; ret += part.getFilename(); ret += "\"\n";
    }
    if( part.getEncoding() ) {
        ret += ENCODING; ret += part.getEncoding(); ret += NL;
    }
    if( part.getFilename() ) {
        if( part.getDisposition() ) {
            ret += DISPOSITION; ret += part.getDisposition(); ret += ";\n";
        }
        else {
            ret += DISPOSITION; ret += "attachment;\n";
        }

        ret += "      "; ret += CD_FILENAME; ret += "\""; ret += part.getFilename();
        ret += "\"\n";
    }
    // End of part headers
    ret += NL;
    // Content
    if( part.getFilename() ) {
        char *content = loadAndConvert(part.getContent(), part.getEncoding());
        ret += content;
        delete [] content;
    }
    else
        ret += part.getContent();

    LOG.debug("FormatBodyPart END");
    return ret;
}

inline static size_t findNewLine(StringBuffer &str, size_t offset) {
    size_t nl = str.find("\n", offset)+1;
    if(nl == StringBuffer::npos)
        return nl;
    return (str[nl] == '\r') ? nl+1 : nl ;
}

static size_t getHeadersLen(StringBuffer &s, StringBuffer &newline)
{
    // detect the newline used in headers
    size_t pos1 = s.find("\n");
    if(pos1 == StringBuffer::npos){
        LOG.error("MailMessage: no newlines in message?");
        return pos1;
    }
    size_t pos2 = pos1 + 1 ;

    while (s[pos1-1] == '\r'){
        pos1--;
    }
    newline = s.substr(pos1, pos2-pos1);

    StringBuffer emptyline = newline + newline ;

    // Split headers and body
    size_t hdrlen = s.find(emptyline);
    if(hdrlen == StringBuffer::npos) {
        // Empty body, get the message anyway.
        hdrlen = s.length();
    }
    return hdrlen;
}


static StringBuffer getTokenValue(const StringBuffer* line, const char* token, bool toLower = true) {

    StringBuffer ret("");
    if (line->ifind(token) == StringBuffer::npos)
        return ret;

    size_t begin = line->ifind(token) + strlen(token);
    size_t end = begin;
    size_t quote = line->find("\"", begin);
    size_t semicolon = line->find(";", begin);

    if (quote != StringBuffer::npos){
        if (semicolon != StringBuffer::npos) {
            if (quote < semicolon) {
                begin = quote + 1;
                end = line->find("\"", begin) ;
            } else {
                end = line->find(";", begin) ;
            }
        } else {
            begin = quote + 1;
            end = line->find("\"", begin) ;
        }
    } else {
        end = line->find(";", begin) ;
        if (end == StringBuffer::npos) {
            end = line->find(" ", begin);
        }
    }
    ret = line->substr(begin, end-begin);
    if (toLower) {
        ret = ret.lowerCase();
    }
    return ret;
}



/**
 * Get the next bodypart from the message body string.
 *
 * @param rfcBody  (in)  - message content
 * @param boundary (in)  - mime boundary string
 * @param ret      (out) - parsed BodyPart
 * @param next     (i/o) - offset of the new boundary
 * @param isAttach (in)  - says if the current body part is an attachment or not
 */
static bool getBodyPart(StringBuffer &rfcBody, StringBuffer &boundary,
                       BodyPart &ret, size_t &next, bool isAttach)
{
    LOG.debug("getBodyPart START");

    // The part starts on the next line
    size_t begin = findNewLine(rfcBody, next);
    if (begin == StringBuffer::npos)
       return false;
    // find the end of the part
    next = rfcBody.find(boundary, begin);
    if (next == StringBuffer::npos)
       return false;
    // get the part
    StringBuffer part = rfcBody.substr(begin, next-begin);
    // If it is a multipart alternative part, get the text part only.
    if(part.ifind("Content-Type: multipart/alternative") != StringBuffer::npos) {
        size_t b_pos = part.ifind("boundary=");
        if( b_pos != StringBuffer::npos ) {
			size_t begin = part.find("=\"", b_pos) + 2 ;
			size_t end = part.find("\"", begin) ;

			StringBuffer inner_boundary("\n--");
            inner_boundary += part.substr( begin, end-begin );

            begin = part.find(inner_boundary, end);
            begin += inner_boundary.length();
            end = part.find(inner_boundary, begin);
            if (begin != StringBuffer::npos && end != StringBuffer::npos) {
                part = part.substr(begin, end-begin);
                LOG.debug("Bodypart is multipart/alternative: "
                    "getting first alternative only: \n%s\n", part.c_str() );
            }
		}
    }

    StringBuffer newline;

    // Split headers and body
    size_t hdrlen = getHeadersLen(part, newline);

    // Get headers
    StringBuffer headers = part.substr(0, hdrlen);

    // Join header parts using \t or 8 blank
    StringBuffer joinlinetab("\t");
    headers.replaceAll(joinlinetab, " ");
    StringBuffer joinlinespaces(newline);
    joinlinespaces+=" ";  // 8 blanks
    headers.replaceAll(joinlinespaces, " ");

    ArrayList lines;
    const StringBuffer *line;

    // parse the bodypart headers
    headers.split(lines, newline);

    for ( line=(StringBuffer *)lines.front();
		  line;
		  line=(StringBuffer *)lines.next() ) {
        if( *line == "\r" )
            continue;
        // The first empty line marks the end of the header section
        //if( line->empty() ){
        //    break;
        //}
        // Process the headers
        if( line->ifind(MIMETYPE) == 0 ) {  // it must at the beginning
            ret.setMimeType(getTokenValue(line, MIMETYPE));
            if (line->ifind(CT_NAME) != StringBuffer::npos) {
                ret.setName( getTokenValue(line, CT_NAME));
            }
            if (line->ifind(CT_CHARSET) != StringBuffer::npos ) {
                ret.setCharset(getTokenValue(line, CT_CHARSET));
            }
        }

        else if( line->ifind(DISPOSITION) == 0 ) {
            ret.setDisposition( getTokenValue(line, DISPOSITION));
            if (line->ifind(CD_FILENAME) != StringBuffer::npos ) {
                ret.setFilename(getTokenValue(line, CD_FILENAME));
            }
        }

        else if( line->ifind(ENCODING) == 0 ) {
            ret.setEncoding( getTokenValue(line, ENCODING));
        }

    }
    // move to the beginning of the content
    hdrlen += strlen(newline) + strlen(newline); // added 2 new line that separate the bodyparts
    // get bodypart content
    if( isAttach == false) { // || !ret.getFilename() ) {
		// this is not an attachment
        if(ret.getEncoding() && strcmp(ret.getEncoding(), "quoted-printable") == 0 ) {
            char *decoded = qp_decode( part.substr(hdrlen) );
            ret.setContent ( decoded );
            delete [] decoded;
        }
        else if (ret.getEncoding() && strcmp(ret.getEncoding(), "base64") == 0 ) {
            char *decoded = "";
            size_t len = 0;
            if( uudecode( part.substr(hdrlen), &decoded, &len ) ) {
                LOG.error("Error decoding content");
            }
            ret.setContent ( decoded );
            delete [] decoded;
        }
        else {
            bool found = true;
            if (part.substr(hdrlen).length() < 6) {
                StringBuffer s(part.substr(hdrlen));
                for (unsigned int i = 0; i < s.length(); i++) {
                    if (s.c_str()[i] != '\r' && s.c_str()[i] != '\n') {
                        found = true;
                        break;
                    } else {
                        found = false;
                    }
                }
            }
            if (found) {
                ret.setContent ( part.substr(hdrlen) );
            }
        }
    }
    else {
        LOG.debug("Attachment");
        ret.setContent( mkTempFileName( ret.getFilename() ) );
        LOG.debug("%s", ret.getContent());
        StringBuffer p = part.substr(hdrlen);
        if (p.length()) {
            LOG.debug("Saving...");
            if( convertAndSave(ret.getContent(), p.c_str(), ret.getEncoding()) ) {
                LOG.error("Error in convertAndSave");
            }
            else {
                LOG.debug("convertAndSave success");
            }
        }
	}
    LOG.debug("getBodyPart END");

    // return true if there are more parts
	return (next != StringBuffer::npos);
}

static void generateBoundary(StringBuffer& boundary)
{
    char buf[40];
	int i;

    *buf = '=';
    memset(buf+1, '-', 9*sizeof(char));
    for(i=10; i<36; i++) {
        buf[i] = '0' + rand() % 10;
    }
    buf[i]=0;
    boundary = buf;
}

static bool isAscii(const char *str){
    if(!str)
        return true;

    for(size_t i = 0; i < strlen(str); i++) {
        if (str[i] < 32 || str[i] > 126 ){
			return false;
        }
    }
	return true;
}

/*
* It encodes if needed and folds
*/
StringBuffer encodeHeader(StringBuffer line){

    if(isAscii(line))
        return line;

    StringBuffer ret;
    StringBuffer tmp;
    StringBuffer startPattern("=?utf-8?Q?");
    StringBuffer endPattern("?=");
    StringBuffer foldingPattern("\r\n ");
    int foldingLen = 64;

    char* qp = 0;
    qp = qp_encode(line);

    tmp += startPattern;
    tmp += qp;
    delete [] qp;

    // folding action
    unsigned long p = 0;
    while(p + foldingLen < tmp.length()) {
        ret.append(tmp.substr(p, foldingLen));
        ret.append(foldingPattern);
        ret.append(startPattern);
        p += foldingLen;
    }

    if (ret.length() > 0)
        tmp.append(tmp.substr(p, tmp.length() - p));

    ret = tmp;
    ret.append(endPattern);

    return ret;

}


//----------------------------------------------------------- Public Methods

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -