String 
   MessageUtilities::GetSendersIP(boost::shared_ptr<Message> pMessage)
   {
      const String fileName = PersistentMessage::GetFileName(pMessage);

      AnsiString sHeader = PersistentMessage::LoadHeader(fileName);

      MimeHeader oHeader;
      oHeader.Load(sHeader, sHeader.GetLength(), true);

      // Locate the first Received header
      MimeField *pReceivedHeader = oHeader.GetField("Received");
      if (pReceivedHeader == 0)
         return "127.0.0.1";

      // Now we should try to find the IP in the received header.
      String sReceivedValue = pReceivedHeader->GetValue();

      int iAddressStart = sReceivedValue.Find(_T("[")) +1;
      int iAddressEnd = sReceivedValue.Find(_T("]"), iAddressStart);
      int iAddressLen = iAddressEnd - iAddressStart;

      if (iAddressLen <= 0)
         return "127.0.0.1";

      String sIPAddress = sReceivedValue.Mid(iAddressStart, iAddressLen);

      if (!StringParser::IsValidIPAddress(sIPAddress))
         return "127.0.0.1";

      return sIPAddress;
   }
   void
   MessageAttachmentStripper::_WriteToDisk(shared_ptr<Message> pMessage, MimeBody &oMainMessage, shared_ptr<MimeBody> pBody)
   {
      if (!pBody)
         return;

      AnsiString sHeader;

      vector<MimeField> oFieldList = oMainMessage.Fields();

      vector<MimeField>::iterator iterField = oFieldList.begin();

      while (iterField != oFieldList.end())
      {
         MimeField oField = (*iterField);

         AnsiString sName = oField.GetName();
         if (sName.CompareNoCase("subject") == 0)
         {
            String sTextVirusFound = Configuration::Instance()->GetServerMessages()->GetMessage("VIRUS_FOUND");

            sHeader += sName;
            sHeader += ": " + sTextVirusFound +": ";
            sHeader += oField.GetValue();
            sHeader += "\r\n";
         }
         else
         if (sName.CompareNoCase("content-type") != 0)
         {
            sHeader += sName;
            sHeader += ": ";
            sHeader += oField.GetValue();
            sHeader += "\r\n";
         }

         iterField++;
      }

      String sBody = pBody->GetRawText();

      String sNotification = Configuration::Instance()->GetServerMessages()->GetMessage("VIRUS_ATTACHMENT_REMOVED");

      sBody = sNotification + sBody;

      String sData = sHeader;
      sData += "\r\n";
      sData += sBody + "\r\n";

      pMessage->SetSize(sData.GetLength());

      String fileName = PersistentMessage::GetFileName(pMessage);

      FileUtilities::WriteToFile(fileName, sData, false);
   }
Example #3
0
   // set 'boundary' parameter (for multipart) of Content-Type field
   void MimeHeader::SetBoundary(const char* pszBoundary/*=NULL*/)
   {
      static int s_nPartNumber = 0;
      char buf[80];
      if (!pszBoundary)				// generate a new boundary delimeter
      {
         ::srand(((unsigned)::time(NULL)) ^ (unsigned)this);
         ::sprintf(buf, "__=_Part_Boundary_%03d_%06d.%06d", ++s_nPartNumber, rand(), rand());
         if (s_nPartNumber >= 9)
            s_nPartNumber = 0;
         pszBoundary = buf;
      }

      MimeField *pfd = GetField(CMimeConst::ContentType());
      if (!pfd)
      {
         MimeField fd;
         fd.SetName(CMimeConst::ContentType());
         fd.SetValue("multipart/mixed");
         fd.SetParameter(CMimeConst::Boundary(), pszBoundary);
         m_listFields.push_back(fd);
      }
      else
      {
         if (::_memicmp(pfd->GetValue(), "multipart", 9) != 0)
            pfd->SetValue("multipart/mixed");
         pfd->SetParameter(CMimeConst::Boundary(), pszBoundary);
      }
   }
Example #4
0
 // get the subtype
 string MimeHeader::GetSubType() const
 {
    string strSubType;
    MimeField *pfd = GetField(CMimeConst::ContentType());
    if (pfd != NULL)
    {
       string strType;
       pfd->GetValue(strType);
       string::size_type nSlash = strType.find('/');
       if (nSlash > 0)
          strSubType = strType.substr(nSlash+1);
    }
    else
       strSubType = "plain";
    return strSubType;
 }
Example #5
0
   // load a header from string buffer
   int MimeHeader::Load(const char* pszData, int nDataSize, bool unfold)
   {
      ASSERT(pszData != NULL);

      int nInput = 0;
      while (pszData[nInput] != 0 && pszData[nInput] != '\r')
      {
         MimeField fd;
         int nSize = fd.Load(pszData+nInput, nDataSize-nInput, unfold);
         if (nSize <= 0)
            return nSize;

         nInput += nSize;
         m_listFields.push_back(fd);	// don't use SetField in case of same name fields
      }

      return nInput + 2;				// skip the ending CRLF
   }
Example #6
0
   void 
      MimeHeader::SetUnicodeFieldValue(const AnsiString &sFieldName, const String & sFieldValue, const AnsiString & sCharset)
   {
      // Retrieve the current charset for this field.
      MimeField* pfd = GetField(sFieldName);

      if (sFieldValue.GetLength() == 0)
      {
         SetRawFieldValue(sFieldName, "", "");
         return;
      }

      AnsiString sCharsetToUse = sCharset;

      // If client hasn't specified character set, assume it's the existing one.
      if (pfd && pfd->GetCharset() && sCharsetToUse.IsEmpty())
         sCharsetToUse = pfd->GetCharset();

      // If there's no existing charset, assume it's the same as for the email.
      if (sCharsetToUse.IsEmpty())
         sCharsetToUse = GetCharset();

      if (sCharsetToUse.IsEmpty())
         sCharsetToUse = "utf-8";

      AnsiString sMBText = Charset::ToMultiByte(sFieldValue, sCharsetToUse);

      // Encode the value
      FieldCodeBase* pCoder = MimeEnvironment::CreateFieldCoder(sFieldName);
      pCoder->SetInput(sMBText, sMBText.GetLength(), true);
      pCoder->SetCharset(sCharsetToUse.c_str());

      AnsiString sEncodedValue;
      pCoder->GetOutput(sEncodedValue);

      delete pCoder;   

      SetRawFieldValue(sFieldName, sEncodedValue, sCharsetToUse);
   }
Example #7
0
 // set the 'charset' parameter (for text) of Content-Type field
 void MimeHeader::SetCharset(const char* pszCharset)
 {
    MimeField *pfd = GetField(CMimeConst::ContentType());
    if (!pfd)
    {
       MimeField fd;
       fd.SetName(CMimeConst::ContentType());
       fd.SetValue("text/plain");
       fd.SetParameter(CMimeConst::Charset(), pszCharset);
       m_listFields.push_back(fd);
    }
    else
       pfd->SetParameter(CMimeConst::Charset(), pszCharset);
 }
Example #8
0
   // set the 'name' parameter (for attachment) of Content-Type field
   void MimeHeader::SetName(const char* pszName)
   {
      MimeField *pfd = GetField(CMimeConst::ContentType());
      if (!pfd)
      {
         // get the appropriate media-type/subtype according to file extension
         ASSERT(pszName != NULL);
         string strType;
         const char* pszType = "application/octet-stream";
         const char* pszFileExt = ::strrchr(pszName, '.');
         if (pszFileExt != NULL)
         {
            pszFileExt++;
            int nIndex = 0;
            while (m_TypeCvtTable[nIndex].nMediaType != MEDIA_UNKNOWN)
            {
               if (!::_stricmp(pszFileExt, m_TypeCvtTable[nIndex].pszFileExt))
               {
                  strType = m_TypeTable[m_TypeCvtTable[nIndex].nMediaType];
                  strType += '/';
                  strType += m_TypeCvtTable[nIndex].pszSubType;
                  pszType = strType.c_str();
                  break;
               }
               nIndex++;
            }
         }

         MimeField fd;
         fd.SetName(CMimeConst::ContentType());
         fd.SetValue(pszType);
         fd.SetParameter(CMimeConst::Name(), pszName);
         m_listFields.push_back(fd);
      }
      else
         pfd->SetParameter(CMimeConst::Name(), pszName);
   }
   AnsiString 
   RelaxedCanonicalization::CanonicalizeHeader(AnsiString header, const std::pair<AnsiString, AnsiString> &signatureField, const std::vector<AnsiString> &fieldsToInclude, AnsiString &fieldList)
   {
      MimeHeader mimeHeader;
      mimeHeader.Load(header, header.GetLength(), true);

      std::vector<MimeField> fields = mimeHeader.Fields();

      String result;
      for(AnsiString headerField : fieldsToInclude)
      {  
         headerField.Trim();

         // locate this field, starting from the end.
         String value;
         for (size_t i = fields.size(); i > 0; i--)
         {
            size_t fieldIndex = i - 1;
            MimeField field = fields[fieldIndex];

            if (headerField.CompareNoCase(field.GetName()) == 0)
            {
               // found
               fields.erase(fields.begin() + fieldIndex);

               value = field.GetValue();
               break;
            }
         }

         if (value.GetLength() > 0)
         {
            /* 
            Convert all header field names (not the header field values) to
            lowercase.  For example, convert "SUBJect: AbC" to "subject: AbC".
            Delete any WSP characters remaining before and after the colon
            separating the header field name from the header field value.  The
            colon separator MUST be retained.
            */

            String relaxedFieldValue;
            String relaxedHeaderName = CanonicalizeHeaderName(headerField);
            relaxedFieldValue = CanonicalizeHeaderValue(value);

            result += relaxedHeaderName + ":" + relaxedFieldValue + "\r\n";

            if (!fieldList.IsEmpty())
               fieldList += ":";

            fieldList += headerField;
         }
      }

      if (!signatureField.first.IsEmpty())
      {
         // Don't pick the value from the actual header, use the header we're verifying instead
         // If there are more than one DKIM-signature fields in the header, this will be important.
         AnsiString  relaxedHeaderName = CanonicalizeHeaderName(signatureField.first);
         AnsiString relaxedFieldValue = CanonicalizeHeaderValue(signatureField.second);

         //and without a trailing CRLF.
         result += relaxedHeaderName + ":" + GetDKIMWithoutSignature_(relaxedFieldValue);
      }

      return result;
   }