/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CBaseMailConnect.cpp  -  description
                             -------------------
    begin                : 25 June 2003
    copyright            : (C) 2000-2006 by Alexey S.Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library is distributed in the hope that it will be useful, but 
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#include <stdio.h>
#include <string.h>

#if defined(WIN32)
#pragma warning (disable: 4786)
#endif

#include <sptk3/CBase64.h>
#include <sptk3/CBaseMailConnect.h>
#include <sptk3/CStrings.h>
#include <sptk3/CDateTime.h>
#include <sptk3/string_ext.h>
#include <time.h>

#include <map>

#define LINE_CHARS 72

using namespace std;
using namespace sptk;

class CContentTypes {
   static map<string,string> m_contentTypes;
public:
   CContentTypes() { if (!m_contentTypes.size()) init(); }
   void init();
   static string type(string fileName);
};

map<string,string> CContentTypes::m_contentTypes;
static CContentTypes contentTypes;
static const string boundary1(  "==_MIME_BOUNDARY_=="    );
static const string boundary2("--==_MIME_BOUNDARY_==\n\r");
static const string boundary3("\n\r--==_MIME_BOUNDARY_==--\n\r");

void CContentTypes::init() {
   m_contentTypes["txt"] = "text/plain";
   m_contentTypes["htm"] = "text/html";
   m_contentTypes["html"]= "text/html";
   m_contentTypes["gif"] = "image/gif";
   m_contentTypes["png"] = "image/png";
   m_contentTypes["bmp"] = "image/bmp";
   m_contentTypes["jpg"] = "image/jpeg";
   m_contentTypes["tif"] = "image/tiff";
   m_contentTypes["pdf"] = "application/pdf";
   m_contentTypes["xls"] = "application/vnd.ms-excel";
   m_contentTypes["csv"] = "text/plain";
   m_contentTypes["doc"] = "application/msword";
   m_contentTypes["wav"] = "application/data";
}

string CContentTypes::type(string fileName) {
   const char *extension = strrchr(fileName.c_str(),'.');
   if (!extension)
      return "application/octet-stream";
   extension++;
   if (strlen(extension) > 4)
      return "application/octet-stream";
   const map<string,string>::iterator itor = m_contentTypes.find(extension);
   if (itor != m_contentTypes.end()) return itor->second;
   else
      return "application/octet-stream";
}

void CBaseMailConnect::mimeFile(string fileName,string fileAlias,CBuffer& buffer) {
   CBuffer  bufSource;
   string  strDest;
   char    *header = new char[1024];

   bufSource.loadFromFile(fileName.c_str());

   string ctype = contentTypes.type(trim(fileName));

   sprintf(header,"Content-Type: %s; name=\"%s\"\n\r",ctype.c_str(),fileAlias.c_str());
   strcat(header,"Content-Transfer-Encoding: base64\n\r\n\r");

   buffer.append(header,strlen(header));

   CBase64::encode(strDest,bufSource);
   unsigned cnt = strDest.length();
   const char *data = strDest.c_str();
   char line[90];
   for (unsigned p = 0; p < cnt; p += LINE_CHARS) {
      unsigned length = cnt - p;
      if (length > LINE_CHARS) length = LINE_CHARS;
      memcpy(line,data+p,80);
      line[length] = '\n';
      line[length+1] = '\r';
      line[length+2] = 0;
      buffer.append(line,length+2);
   }
}

void CBaseMailConnect::mimeMessage(CBuffer& buffer) {
   string headers;

   if (m_from.length())
      headers += "From: " + m_from + "\n\r";
   else  headers += "From: postmaster\n\r";

   replaceAll(m_to,";",", ");
   headers += "To: " + m_to + "\n\r";

   if (m_cc.length()) {
      replaceAll(m_cc,";",", ");
      headers += "CC: " + m_cc + "\n\r";
   }

   headers += "Subject: " + m_subject + "\n\r";

   CDateTime   date = CDateTime::Now();
   short dy,dm,dd,th,tm,ts,tms;
   date.decodeDate(&dy,&dm,&dd);
   date.decodeTime(&th,&tm,&ts,&tms);

   char  dateBuffer[128];
   char  *sign = "-";
   int   offset = CDateTime::timeZoneOffset;
   if (offset >= 0) 
      sign = "";
   else
      offset = -offset;

   sprintf(dateBuffer,
      "Date: %s, %i %s %04i %02i:%02i:%02i %s%04i (%s)\n\r",
      date.dayOfWeekName().substr(0,3).c_str(),
      dd,
      CDateTime::monthNames[dm-1].substr(0,3).c_str(),
      dy,
      th,tm,ts,
      sign,
      offset * 100,
      CDateTime::timeZoneName.c_str() 
   );


   headers += dateBuffer;

   string mimeHeaders("MIME-Version: 1.0\n\r");

   if (m_body.type() == MMT_PLAIN_TEXT_MESSAGE) {

      mimeHeaders += "Content-Type: multipart/mixed;\n\r boundary=\"" + boundary1 + "\"\n\r";
      mimeHeaders += "\n\rThis message is in MIME format.";
      mimeHeaders += " Since your mail reader does not understand this format, some or all of this message may not be legible.\n\r\n\r";

      mimeHeaders += boundary2;
      mimeHeaders += "Content-Type: text/plain; charset=\"us-ascii\"\n\r";
      mimeHeaders += "Content-Transfer-Encoding: 7bit\n\r";
      mimeHeaders += "\n\r" + m_body.text() + "\n\r\n\r";

   } else {
/*
      mimeHeaders += "Content-Type: multipart/alternative;\n\r boundary=\"" + boundary1 + "\"\n\r";
      mimeHeaders += "\n\rThis message is in MIME format.";
      mimeHeaders += " Since your mail reader does not understand this format, some or all of this message may not be legible.\n\r\n\r";

      mimeHeaders += boundary2;
      mimeHeaders += "Content-Type: text/plain; charset=\"us-ascii\"\n\r";
      mimeHeaders += "Content-Transfer-Encoding: 7bit\n\r";
      mimeHeaders += "\n\r" + m_body.text() + "\n\r\n\r";

      mimeHeaders += boundary2;
      mimeHeaders += "Content-Type: text/html; charset=\"us-ascii\"\n\r";
      mimeHeaders += "Content-Transfer-Encoding: 7bit\n\r";
      mimeHeaders += "\n\r" + m_body.html() + "\n\r\n\r";
*/
      mimeHeaders += "Content-Type: multipart/mixed;\n\r boundary=\"" + boundary1 + "\"\n\r";
      mimeHeaders += "\n\rThis message is in MIME format.";
      mimeHeaders += " Since your mail reader does not understand this format, some or all of this message may not be legible.\n\r\n\r";

      mimeHeaders += boundary2;
      mimeHeaders += "Content-Type: text/html; charset=\"us-ascii\"\n\r";
      mimeHeaders += "Content-Transfer-Encoding: 7bit\n\r";
      mimeHeaders += "\n\r" + m_body.html() + "\n\r\n\r";
   }

   buffer.reset(2048);
   buffer.append(headers.c_str(),headers.length());
   buffer.append(mimeHeaders.c_str(),mimeHeaders.length());

   CStrings sl(m_attachments,";");
   for (unsigned i = 0; i < sl.size(); i++) {
      string attachment = sl[i];
      string attachmentAlias = attachment;
      char *separator = "\\";
      if (attachment.find("/") != string::npos)
         separator = "/";
      CStrings attachmentParts(attachment,separator);
      int attachmentPartsCount = attachmentParts.size();
      if (attachmentPartsCount > 1)
         attachmentAlias = attachmentParts[attachmentPartsCount-1].c_str();
      if (attachment.length()) {
         buffer.append(boundary2.c_str(),boundary2.length());
         mimeFile(attachment,attachmentAlias,buffer);
      }
   }
   buffer.append(boundary3.c_str(),boundary3.length());
}
