root/MimeEncode.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CMimeEncode
  2. CMimeEncode
  3. Initialize
  4. HowManyAttach
  5. HowManyPart
  6. CopyFrom
  7. GetAttach
  8. GetBcc
  9. GetCc
  10. GetFrom
  11. GetInReplyTo
  12. GetSubject
  13. GetDate
  14. GetMail
  15. GetMultipartBody
  16. GetMultipartEncType
  17. GetMultipartFileName
  18. GetMultipartPath
  19. GetMultipartType
  20. GetTo
  21. GetMessageID
  22. GetReplyTo
  23. AddAttach
  24. SetBcc
  25. SetCc
  26. SetFrom
  27. SetInReplyTo
  28. SetDate
  29. AddMultipart
  30. SetMultipart
  31. SetMultipartBody
  32. SetSubject
  33. SetTo
  34. SetXMailer
  35. SetMessageID
  36. SetReplyTo
  37. EncodeHeader
  38. EncodeBase64FromFile
  39. AddAttachedFile
  40. AddPgpKey
  41. AddPgpEncrypted
  42. AddText
  43. RemoveMultipart
  44. AddRFC822
  45. GetCT
  46. GetCD
  47. GetCTE
  48. GetBody
  49. SetMode
  50. GetMode
  51. EncodeBase64

/*
 * Copyright (C) 2002-2003 chik, s.hiranaka
 * For license terms, see the file COPYING in this directory.
 */

// MimeEncode.cpp: CMimeEncode クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Pochy.h"
#include "MimeEncode.h"
#include "base64.h"
#include "CodeConvert.h"
#include "lib.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CMimeEncode::CMimeEncode()
{
        this->Initialize();
}

CMimeEncode::~CMimeEncode()
{

}

void CMimeEncode::Initialize()
{
        m_data.m_attach.RemoveAll();
        m_data.m_multipart.RemoveAll();
        m_data.m_bcc.Empty();
        m_data.m_cc.Empty();
        m_data.m_from.Empty();
        m_data.m_in_reply_to.Empty();
        m_data.m_reply_to.Empty();
        m_data.m_message_id.Empty();
        m_data.m_subject.Empty();
        m_data.m_to.Empty();
        m_data.m_date.Empty();
        m_data.m_xmailer.Empty();
        m_mime_mode = ME_MODE_NONE;
}

int CMimeEncode::HowManyAttach()
{
        return m_data.m_attach.GetSize();
}

int CMimeEncode::HowManyPart()
{
        return m_data.m_multipart.GetSize();
}

void CMimeEncode::CopyFrom(CMimeEncode *me)
{
        Initialize();
        
        m_data.m_bcc = me->m_data.m_bcc;
        m_data.m_cc = me->m_data.m_cc;
        m_data.m_from = me->m_data.m_from;
        m_data.m_in_reply_to = me->m_data.m_in_reply_to;
        m_data.m_message_id = me->m_data.m_message_id;
        m_data.m_reply_to = me->m_data.m_reply_to;
        m_data.m_subject = me->m_data.m_subject;
        m_data.m_to = me->m_data.m_to;
        m_mime_mode = me->m_mime_mode;

        int i=0;
        while(i < me->HowManyAttach()){
                m_data.m_attach.Add(me->m_data.m_attach[i]);
                i++;
        }

        i=0;
        while(i < me->HowManyPart()){
                m_data.m_multipart.Add(me->m_data.m_multipart[i]);
                i++;
        }
}

CString CMimeEncode::GetAttach(int part)
{
        return m_data.m_attach[part];
}

CString CMimeEncode::GetBcc()
{
        return m_data.m_bcc;
}

CString CMimeEncode::GetCc()
{
        return m_data.m_cc;
}

CString CMimeEncode::GetFrom()
{
        return m_data.m_from;
}

CString CMimeEncode::GetInReplyTo()
{
        return m_data.m_in_reply_to;
}

CString CMimeEncode::GetSubject()
{
        return m_data.m_subject;
}

CString CMimeEncode::GetDate()
{
        return m_data.m_date;
}

CString CMimeEncode::GetMail(int for_what)
{
        CString header;
        CString mail;

        // ヘッダの構成
        // RFC 822      To: Pooh Lovers:pooh@100acre.woodwest.uk,piglet@beech.tree.uk; not yet.
        if(for_what != ME_GET_PRE_ENC_PGP){
                header += "To: "+GetTo()+"\r\n";
                header += "From: "+GetFrom()+"\r\n";
                header += "Subject: "+GetSubject()+"\r\n";
                if(!GetCc().IsEmpty())
                        header += "Cc: "+GetCc()+"\r\n";
                if(!GetInReplyTo().IsEmpty())
                        header += "In-reply-to: "+GetInReplyTo()+"\r\n";
                if(!GetReplyTo().IsEmpty())
                        header += "Reply-To: "+GetReplyTo()+"\r\n";
                if((for_what == ME_GET_DRAFT || for_what == ME_GET_OUTBOX) && !GetBcc().IsEmpty())
                        header += "Bcc: "+GetBcc()+"\r\n";
                if(!GetMessageID().IsEmpty())
                        header += "Message-ID: "+GetMessageID()+"\r\n";
                if(!m_data.m_date.IsEmpty())
                        header += "Date: "+GetDate()+"\r\n";
                if(!m_data.m_xmailer.IsEmpty())
                        header += "X-Mailer: "+m_data.m_xmailer+"\r\n";
                header += "MIME-Version: 1.0\r\n";
        }

        // bodyを持たないmultipartを削除(draftに保存される場合は例外)
        int i = 0;
        if(for_what != ME_GET_DRAFT){
                while(i < HowManyPart()){
                        if(m_data.m_multipart[i].m_body.IsEmpty()){
                                m_data.m_multipart.RemoveAt(i);
                                continue;
                        }
                        i++;
                }
        }

        CString body;
        if(0==HowManyPart()){
                header += "Content-Type: Text/Plain; charset=ISO-2022-JP\r\n";
                header += "Content-Transfer-Encoding: 7bit\r\n";
                CCodeConvert cc(header);
                header = cc.ToJis();
                EncodeHeader(header);
                mail = header + "\r\n";
        }else if(1==HowManyPart()){
                if(!GetCT(0).IsEmpty()) header += GetCT(0)+"\r\n";
                if(!GetCTE(0).IsEmpty()) header += GetCTE(0)+"\r\n";
                if(!GetCD(0).IsEmpty()) header += GetCD(0)+"\r\n";
                CCodeConvert cc(header);
                header = cc.ToJis();
                EncodeHeader(header);
                body = GetBody(0);
                CCodeConvert cc2(body);
                body = cc2.ToJis();
                mail = header+"\r\n"+body;
        }else{
                if(m_mime_mode == ME_MODE_NONE){
                        header += "Content-Type: Multipart/Mixed; boundary=----kyoukaisen\r\n";
                        header += "Content-Transfer-Encoding: 7bit\r\n";
                }
                else if(m_mime_mode == ME_MODE_PGP){
                        header += "Content-Type: Multipart/Encrypted; boundary=----kyoukaisen; protocol=application/pgp-encrypted\r\n";
                        header += "Content-Transfer-Encoding: 7bit\r\n";
                }
                else if(m_mime_mode == ME_MODE_RFC822){}
                CCodeConvert cc(header);
                header = cc.ToJis();
                EncodeHeader(header);
                i = 0;
                while(i < HowManyPart()){
                        body += "------kyoukaisen\r\n";
                        if(!GetCT(i).IsEmpty()) body += GetCT(i)+"\r\n";
                        if(!GetCTE(i).IsEmpty()) body += GetCTE(i)+"\r\n";
                        if(!GetCD(i).IsEmpty()) body += GetCD(i)+"\r\n";
                        body += "\r\n";
                        body += GetBody(i);
                        body.TrimRight();
                        body += "\r\n\r\n";
                        i++;
                }
                body += "------kyoukaisen--\r\n";
                CCodeConvert cc2(body);
                body = cc2.ToJis();
                mail = header+"\r\n"+body;
        }
        return mail;
}

CString CMimeEncode::GetMultipartBody(int part)
{
        return m_data.m_multipart[part].m_body;
}

CString CMimeEncode::GetMultipartEncType(int part)
{
        return m_data.m_multipart[part].m_encoding_type;
}

CString CMimeEncode::GetMultipartFileName(int part)
{
        return m_data.m_multipart[part].m_file_name;
}

CString CMimeEncode::GetMultipartPath(int part)
{
        return m_data.m_multipart[part].m_path;
}

CString CMimeEncode::GetMultipartType(int part)
{
        return m_data.m_multipart[part].m_type;
}

CString CMimeEncode::GetTo()
{
        return m_data.m_to;
}

CString CMimeEncode::GetMessageID()
{
        return m_data.m_message_id;
}

CString CMimeEncode::GetReplyTo()
{
        return m_data.m_reply_to;
}

void CMimeEncode::AddAttach(CString attach)
{
        m_data.m_attach.Add(attach);
}

void CMimeEncode::SetBcc(CString bcc)
{
        m_data.m_bcc = bcc;
}

void CMimeEncode::SetCc(CString cc)
{
        m_data.m_cc = cc;
}

void CMimeEncode::SetFrom(CString from)
{
        m_data.m_from = from;
}

void CMimeEncode::SetInReplyTo(CString in_reply_to)
{
        m_data.m_in_reply_to = in_reply_to;
}

void CMimeEncode::SetDate(CString date)
{
        m_data.m_date = date;
}

void CMimeEncode::AddMultipart(MULTIPART_STRUCT2 &multipart)
{
        m_data.m_multipart.Add(multipart);
}

void CMimeEncode::SetMultipart(int part, MULTIPART_STRUCT2 &multipart)
{
        m_data.m_multipart.SetAt(part, multipart);
}


void CMimeEncode::SetMultipartBody(int part, CString body)
{
        m_data.m_multipart[part].m_body = body;
}

void CMimeEncode::SetSubject(CString subject)
{
        m_data.m_subject = subject;
}

void CMimeEncode::SetTo(CString to)
{
        m_data.m_to = to;
}

void CMimeEncode::SetXMailer(CString xmailer)
{
        m_data.m_xmailer = xmailer;
}

void CMimeEncode::SetMessageID(CString message_id)
{
        m_data.m_message_id = message_id;
}

void CMimeEncode::SetReplyTo(CString reply_to)
{
        m_data.m_reply_to = reply_to;
}

void CMimeEncode::EncodeHeader(CString& org)
{
        int i = 0;
        int j = 0;
        int istart;
        CString dst;
        CString tmp;
        CString tmp2;
        CString tmp3;
        unsigned char *out;
        const int size = 30;
        BOOL folding_space = FALSE;

        CStringArray array_org;
        CStringArray array_dst;
        CStringArray array_tmp;
        CString buf;
        CString buf2;

        if(org.IsEmpty())
                return;

        array_org.RemoveAll();
        array_dst.RemoveAll();
        array_tmp.RemoveAll();
        g_cstr2cstra(org, array_org, "\r\n");

        i = 0;
        while(i < array_org.GetSize()){
                buf = array_org.GetAt(i);
                buf.TrimRight();
                array_tmp.RemoveAll();
                j = 0;
                while(j < buf.GetLength()){
                        // search non-ascii char
                        if(buf[j]==0x1b && buf[j+1]==0x24 && buf[j+2]==0x42){
                                istart=j;
                                j+=3;
                                for(;j<buf.GetLength()-2 && (buf[j]!=0x1b || buf[j+1]!=0x28 || buf[j+2]!=0x42);j++);
                                j+=3;
                                // pick out non-ascii char
                                tmp=buf.Mid(istart, j-istart);
                                // need to confirm whether or not length of line is less than 57.
                                if(!buf2.IsEmpty()){
                                        buf2.TrimRight();
                                        buf2+="\r\n";
                                        while(buf2.GetLength() > 76){
                                                array_tmp.Add(buf2.Left(76)+"\r\n");
                                                buf2 = buf2.Mid(76);
                                        }
                                        array_tmp.Add(buf2);
                                        buf2.Empty();
                                }
                                while(tmp.GetLength() > 40){
                                        tmp3 = tmp.Left(40);
                                        tmp = tmp.Mid(40);
                                        out = (unsigned char *)tmp2.GetBuffer(tmp3.GetLength()*3);
                                        to64frombits(out, (unsigned char *)tmp3.GetBuffer(0), tmp3.GetLength());
                                        tmp2.ReleaseBuffer();
                                        tmp2 = "=?ISO-2022-JP?B?"+tmp2+"?=\r\n";
                                        array_tmp.Add(tmp2);
                                        tmp2.Empty();
                                        tmp3.Empty();
                                }
                                out = (unsigned char *)tmp2.GetBuffer(tmp.GetLength()*3);
                                to64frombits(out, (unsigned char *)tmp.GetBuffer(0), tmp.GetLength());
                                tmp2.ReleaseBuffer();
                                tmp2 = "=?ISO-2022-JP?B?"+tmp2+"?=";
                                tmp2.TrimRight();
                                tmp2+="\r\n";
                                array_tmp.Add(tmp2);
                                tmp2.Empty();
                        }else{
                                buf2+=buf[j];
                                j++;
                        }
                }

                // need to confirm length of line
                if(!buf2.IsEmpty() && (buf2 != "\r\n")){
                        buf2.TrimRight(); buf2+="\r\n";
                        array_tmp.Add(buf2); buf2.Empty();
                }

                j = 1;
                while(j < array_tmp.GetSize()){
                        array_tmp.SetAt(j, " "+array_tmp.GetAt(j));
                        j++;
                }

                j = 0;
                while(j < array_tmp.GetSize()){
                        array_dst.Add(array_tmp.GetAt(j));
                        j++;
                }
                i++;
        }
        g_cstra2cstr(array_dst, org, g_cstra_getsize(array_dst));
}

BOOL CMimeEncode::EncodeBase64FromFile(CString path, CString &buf)
{
        FILE *file;
        unsigned char in[READBUFSIZE*3];
        unsigned char out[READBUFSIZE*4+(2*READBUFSIZE/76)+1];
        CString msg;

        DWORD size = g_getfs(path);

        file = fopen(path, "rb");
        if(file == NULL){
                msg.Format("cannot open %s", path);
                AfxMessageBox(msg);
                return FALSE;
        }

        CString c;
        CString tmp;
        char *ptmp = tmp.GetBuffer(g_getfs(path)/5*7);

        int len = 0;
        while(1){
                if(size > READBUFSIZE*3){
                        fread(in, sizeof(unsigned char), READBUFSIZE*3, file);
                        to64frombits(out, in, READBUFSIZE*3);
                        c = out;
                        c += "\r\n";
                        strcpy(ptmp, c);
                        ptmp += c.GetLength();
                        len += c.GetLength();
                        size -= READBUFSIZE*3;
                }else{
                        fread(in, sizeof(unsigned char), size, file);
                        to64frombits(out, in, size);
                        c = out;
                        c += "\r\n";
                        strcpy(ptmp, c);
                        ptmp += c.GetLength();
                        len += c.GetLength();
                        break;
                }
        }
        tmp.ReleaseBuffer(len);
        buf = tmp;
        fclose(file);
        return TRUE;
}

BOOL CMimeEncode::AddAttachedFile(CString path)
{
/*      Content-Type: application/octet-stream; name=hogehoge
        Content-Transfer-Encoding: base64
        Content-Disposition: attachment; filename=hogehoge*/

        MULTIPART_STRUCT2 data;
        data.m_encoding_type = "base64";
        data.m_file_name = path.Mid(path.ReverseFind('\\')+1);
        data.m_type = "application/octet-stream";
        data.m_path = path;

        data.m_content_type.Format("Content-Type: application/octet-stream; name=%s", 
                path.Mid(path.ReverseFind('\\')+1));

        data.m_content_transfer_encoding = "Content-Transfer-Encoding: base64";

        data.m_content_disposition.Format("Content-Disposition: attachment; filename=%s",
                path.Mid(path.ReverseFind('\\')+1));

        if(!this->EncodeBase64FromFile(path, data.m_body))
                return FALSE;

        m_data.m_multipart.Add(data);
        return TRUE;
}

void CMimeEncode::AddPgpKey(CString key)
{
        MULTIPART_STRUCT2 data;
        data.m_content_type = "Content-Type: application/pgp-keys";
        data.m_body = key;

        m_data.m_multipart.Add(data);
}

void CMimeEncode::AddPgpEncrypted(CString enc)
{
        SetMode(ME_MODE_PGP);

        m_data.m_multipart.RemoveAll();
        
        MULTIPART_STRUCT2 data;
        data.m_content_type = "Content-Type: application/pgp-encrypted";
        data.m_content_transfer_encoding = "Content-Transfer-Encoding: 7bit";
        data.m_body = "Version: 1\r\n";

        m_data.m_multipart.Add(data);

        data.m_content_type = "Content-Type: application/octet-stream";
        data.m_content_transfer_encoding = "Content-Transfer-Encoding: 7bit";
        data.m_body = enc;

        m_data.m_multipart.Add(data);
}

void CMimeEncode::AddText(CString body)
{
/*      Content-Type: text/plain; charset=iso-2022-jp
        Content-Transfer-Encoding: 7bit*/
        
        MULTIPART_STRUCT2 data;
        data.m_encoding_type = "7bit";
        data.m_type = "text/plain";
        data.m_content_type = "Content-Type: Text/Plain; charset=ISO-2022-JP";
        data.m_content_transfer_encoding = "Content-Transfer-Encoding: 7bit";
        data.m_body = body;

        m_data.m_multipart.Add(data);
}

void CMimeEncode::RemoveMultipart(int part)
{
        m_data.m_multipart.RemoveAt(part);
}

void CMimeEncode::AddRFC822(CString mail)
{
        
}

CString CMimeEncode::GetCT(int part)
{
        return m_data.m_multipart[part].m_content_type;
}

CString CMimeEncode::GetCD(int part)
{
        return m_data.m_multipart[part].m_content_disposition;
}

CString CMimeEncode::GetCTE(int part)
{
        return m_data.m_multipart[part].m_content_transfer_encoding;
}

CString CMimeEncode::GetBody(int part)
{
        return m_data.m_multipart[part].m_body;
}

void CMimeEncode::SetMode(int mime_mode)
{
        m_mime_mode = mime_mode;
}

int CMimeEncode::GetMode()
{
        return m_mime_mode;
}

BOOL CMimeEncode::EncodeBase64(CString &out, CString in)
{
        return TRUE;
}

/* [<][>][^][v][top][bottom][index][help] */