///////////////////////////////////////////////////////////////////////////////
//
//  Module: MailMsg.cpp
//
//    Desc: See MailMsg.h
//
// Copyright (c) 2003 Michael Carruth
//
///////////////////////////////////////////////////////////////////////////////

#include "MailMsg.h"
#pragma		warning (disable:4267)

CMailMsg::CMailMsg()
{
   m_sSubject        = _T("NONE");
   m_sMessage        = _T("");
   m_lpCmcLogon      = NULL;
   m_lpCmcSend       = NULL;
   m_lpCmcLogoff     = NULL;
   m_lpMapiLogon     = NULL;
   m_lpMapiSendMail  = NULL;
   m_lpMapiLogoff    = NULL;
   m_bReady          = FALSE;
}

CMailMsg::~CMailMsg()
{
   if (m_bReady)
      Uninitialize();
}

CMailMsg& CMailMsg::SetFrom(CString sAddress, CString sName)
{
   if (m_bReady || Initialize())
   {
      // only one sender allowed
      if (m_from.size())
         m_from.empty();

      m_from[sAddress] = sName;
   }

   return *this;
}

CMailMsg& CMailMsg::SetTo(CString sAddress, CString sName)
{
   if (m_bReady || Initialize())
   {
      // only one recipient allowed
      if (m_to.size())
         m_to.empty();

      m_to[sAddress] = sName;
   }

   return *this;
}

CMailMsg& CMailMsg::SetCc(CString sAddress, CString sName)
{
   if (m_bReady || Initialize())
   {
      m_cc[sAddress] = sName;
   }

   return *this;
}

CMailMsg& CMailMsg::SetBc(CString sAddress, CString sName)
{
   if (m_bReady || Initialize())
   {
      m_bcc[sAddress] = sName;
   }

   return *this;
}

CMailMsg& CMailMsg::AddAttachment(CString sAttachment, CString sTitle)
{
   if (m_bReady || Initialize())
   {
      m_attachments[sAttachment] = sTitle;
   }

   return *this;
}

BOOL CMailMsg::Send()
{
   // try mapi
   if (MAPISend())
      return TRUE;

   // try cmc
   if (CMCSend())
      return TRUE;

   return FALSE;
}

BOOL CMailMsg::MAPISend()
{
   TStrStrMap::iterator p;
   int                  nIndex = 0;
   int                  nRecipients = 0;
   MapiRecipDesc*       pRecipients = NULL;
   int                  nAttachments = 0;
   MapiFileDesc*        pAttachments = NULL;
   ULONG                status = 0;
   MapiMessage          message;

   if (m_bReady || Initialize())
   {
      nRecipients = m_to.size() + m_cc.size() + m_bcc.size() + m_from.size();
      if (nRecipients)
         pRecipients = new MapiRecipDesc[nRecipients];

      nAttachments = m_attachments.size();
      if (nAttachments)
         pAttachments = new MapiFileDesc[nAttachments];

      if (pRecipients)
      {
         if (m_from.size())
         {
            // set from
            pRecipients[nIndex].ulReserved                 = 0;
            pRecipients[nIndex].ulRecipClass               = MAPI_ORIG;
            pRecipients[nIndex].lpszAddress                = (LPTSTR)(LPCTSTR)m_from.begin()->first;
            pRecipients[nIndex].lpszName                   = (LPTSTR)(LPCTSTR)m_from.begin()->second;
            pRecipients[nIndex].ulEIDSize                  = 0;
            pRecipients[nIndex].lpEntryID                  = NULL;
            nIndex++;
         }

         if (m_to.size())
         {
            // set to
            pRecipients[nIndex].ulReserved                 = 0;
            pRecipients[nIndex].ulRecipClass               = MAPI_TO;
            pRecipients[nIndex].lpszAddress                = (LPTSTR)(LPCTSTR)m_to.begin()->first;
            pRecipients[nIndex].lpszName                   = (LPTSTR)(LPCTSTR)m_to.begin()->second;
            pRecipients[nIndex].ulEIDSize                  = 0;
            pRecipients[nIndex].lpEntryID                  = NULL;
            nIndex++;
         }

         if (m_cc.size())
         {
            // set cc's
            for (p = m_cc.begin(); p != m_cc.end(); p++, nIndex++)
            {
               pRecipients[nIndex].ulReserved         = 0;
               pRecipients[nIndex].ulRecipClass       = MAPI_CC;
               pRecipients[nIndex].lpszAddress        = (LPTSTR)(LPCTSTR)p->first;
               pRecipients[nIndex].lpszName           = (LPTSTR)(LPCTSTR)p->second;
               pRecipients[nIndex].ulEIDSize          = 0;
               pRecipients[nIndex].lpEntryID          = NULL;
            }
         }
   
         if (m_bcc.size())
         {
            // set bcc
            for (p = m_bcc.begin(); p != m_bcc.end(); p++, nIndex++)
            {
               pRecipients[nIndex].ulReserved         = 0;
               pRecipients[nIndex].ulRecipClass       = MAPI_BCC;
               pRecipients[nIndex].lpszAddress        = (LPTSTR)(LPCTSTR)p->first;
               pRecipients[nIndex].lpszName           = (LPTSTR)(LPCTSTR)p->second;
               pRecipients[nIndex].ulEIDSize          = 0;
               pRecipients[nIndex].lpEntryID          = NULL;
            }
         }
      }

      if (pAttachments)
      {
         // add attachments
         for (p = m_attachments.begin(), nIndex = 0;
              p != m_attachments.end(); p++, nIndex++)
         {
            pAttachments[nIndex].ulReserved        = 0;
            pAttachments[nIndex].flFlags           = 0;
            pAttachments[nIndex].nPosition         = 0xFFFFFFFF;
            pAttachments[nIndex].lpszPathName      = (LPTSTR)(LPCTSTR)p->first;
            pAttachments[nIndex].lpszFileName      = (LPTSTR)(LPCTSTR)p->second;
            pAttachments[nIndex].lpFileType        = NULL;
         }
      }

      message.ulReserved                        = 0;
      message.lpszSubject                       = (LPTSTR)(LPCTSTR)m_sSubject;
      message.lpszNoteText                      = (LPTSTR)(LPCTSTR)m_sMessage;
      message.lpszMessageType                   = NULL;
      message.lpszDateReceived                  = NULL;
      message.lpszConversationID                = NULL;
      message.flFlags                           = 0;
      message.lpOriginator                      = m_from.size() ? pRecipients : NULL;
      message.nRecipCount                       = nRecipients - m_from.size(); // don't count originator
      message.lpRecips                          = nRecipients - m_from.size() ? &pRecipients[m_from.size()] : NULL;
      message.nFileCount                        = nAttachments;
      message.lpFiles                           = nAttachments ? pAttachments : NULL;

      status = m_lpMapiSendMail(0, 0, &message, MAPI_DIALOG, 0);

      if (pRecipients)
         delete [] pRecipients;

      if (nAttachments)
         delete [] pAttachments;
   }

   return (SUCCESS_SUCCESS == status);
}

BOOL CMailMsg::CMCSend()
{
   TStrStrMap::iterator p;
   int                  nIndex = 0;
   CMC_recipient*       pRecipients;
   CMC_attachment*      pAttachments;
   CMC_session_id       session;
   CMC_return_code      status = 0;
   CMC_message          message;
   CMC_boolean          bAvailable = FALSE;
   CMC_time             t_now = {0};

   if (m_bReady || Initialize())
   {
      pRecipients = new CMC_recipient[m_to.size() + m_cc.size() + m_bcc.size() + m_from.size()];
      pAttachments = new CMC_attachment[m_attachments.size()];

      // set cc's
      for (p = m_cc.begin(); p != m_cc.end(); p++, nIndex++)
      {
         pRecipients[nIndex].name                = (LPTSTR)(LPCTSTR)p->second;
         pRecipients[nIndex].name_type           = CMC_TYPE_INDIVIDUAL;
         pRecipients[nIndex].address             = (LPTSTR)(LPCTSTR)p->first;
         pRecipients[nIndex].role                = CMC_ROLE_CC;
         pRecipients[nIndex].recip_flags         = 0;
         pRecipients[nIndex].recip_extensions    = NULL;
      }
   
      // set bcc
      for (p = m_bcc.begin(); p != m_bcc.end(); p++, nIndex++)
      {
         pRecipients[nIndex].name                = (LPTSTR)(LPCTSTR)p->second;
         pRecipients[nIndex].name_type           = CMC_TYPE_INDIVIDUAL;
         pRecipients[nIndex].address             = (LPTSTR)(LPCTSTR)p->first;
         pRecipients[nIndex].role                = CMC_ROLE_BCC;
         pRecipients[nIndex].recip_flags         = 0;
         pRecipients[nIndex].recip_extensions    = NULL;
      }
   
      // set to
      pRecipients[nIndex].name                   = (LPTSTR)(LPCTSTR)m_to.begin()->second;
      pRecipients[nIndex].name_type              = CMC_TYPE_INDIVIDUAL;
      pRecipients[nIndex].address                = (LPTSTR)(LPCTSTR)m_to.begin()->first;
      pRecipients[nIndex].role                   = CMC_ROLE_TO;
      pRecipients[nIndex].recip_flags            = 0;
      pRecipients[nIndex].recip_extensions       = NULL;
   
      // set from
      pRecipients[nIndex+1].name                 = (LPTSTR)(LPCTSTR)m_from.begin()->second;
      pRecipients[nIndex+1].name_type            = CMC_TYPE_INDIVIDUAL;
      pRecipients[nIndex+1].address              = (LPTSTR)(LPCTSTR)m_from.begin()->first;
      pRecipients[nIndex+1].role                 = CMC_ROLE_ORIGINATOR;
      pRecipients[nIndex+1].recip_flags          = CMC_RECIP_LAST_ELEMENT;
      pRecipients[nIndex+1].recip_extensions     = NULL;
   
      // add attachments
      for (p = m_attachments.begin(), nIndex = 0;
           p != m_attachments.end(); p++, nIndex++)
      {
         pAttachments[nIndex].attach_title       = (LPTSTR)(LPCTSTR)p->second;
         pAttachments[nIndex].attach_type        = NULL;
         pAttachments[nIndex].attach_filename    = (LPTSTR)(LPCTSTR)p->first;
         pAttachments[nIndex].attach_flags       = 0;
         pAttachments[nIndex].attach_extensions  = NULL;
      }
      pAttachments[nIndex-1].attach_flags        = CMC_ATT_LAST_ELEMENT;

      message.message_reference                 = NULL;
      message.message_type                      = NULL;
      message.subject                           = (LPTSTR)(LPCTSTR)m_sSubject;
      message.time_sent                         = t_now;
      message.text_note                         = (LPTSTR)(LPCTSTR)m_sMessage;
      message.recipients                        = pRecipients;
      message.attachments                       = pAttachments;
      message.message_flags                     = 0;
      message.message_extensions                = NULL;

      status = m_lpCmcQueryConfiguration(
                  0, 
                  CMC_CONFIG_UI_AVAIL, 
                  (void*)&bAvailable, 
                  NULL
                  );

      if (CMC_SUCCESS == status && bAvailable)
      {
         status = m_lpCmcLogon(
                     NULL,
                     NULL,
                     NULL,
                     NULL,
                     0,
                     CMC_VERSION,
                     CMC_LOGON_UI_ALLOWED |
                     CMC_ERROR_UI_ALLOWED,
                     &session,
                     NULL
                     );

         if (CMC_SUCCESS == status)
         {
            status = m_lpCmcSend(session, &message, 0, 0, NULL);

            m_lpCmcLogoff(session, NULL, CMC_LOGON_UI_ALLOWED, NULL);
         }
      }

      delete [] pRecipients;
      delete [] pAttachments;
   }

   return ((CMC_SUCCESS == status) && bAvailable);
}

BOOL CMailMsg::Initialize()
{
   m_hMapi = ::LoadLibrary(_T("mapi32.dll"));
   
   if (!m_hMapi)
      return FALSE;

   m_lpCmcQueryConfiguration = (LPCMCQUERY)::GetProcAddress(m_hMapi, _T("cmc_query_configuration"));
   m_lpCmcLogon = (LPCMCLOGON)::GetProcAddress(m_hMapi, _T("cmc_logon"));
   m_lpCmcSend = (LPCMCSEND)::GetProcAddress(m_hMapi, _T("cmc_send"));
   m_lpCmcLogoff = (LPCMCLOGOFF)::GetProcAddress(m_hMapi, _T("cmc_logoff"));
   m_lpMapiLogon = (LPMAPILOGON)::GetProcAddress(m_hMapi, _T("MAPILogon"));
   m_lpMapiSendMail = (LPMAPISENDMAIL)::GetProcAddress(m_hMapi, _T("MAPISendMail"));
   m_lpMapiLogoff = (LPMAPILOGOFF)::GetProcAddress(m_hMapi, _T("MAPILogoff"));

   m_bReady = (m_lpCmcLogon && m_lpCmcSend && m_lpCmcLogoff) ||
              (m_lpMapiLogon && m_lpMapiSendMail && m_lpMapiLogoff);

   return m_bReady;
}

void CMailMsg::Uninitialize()
{
   ::FreeLibrary(m_hMapi);
}