AnsiString 
   RelaxedCanonicalization::CanonicalizeHeaderValue(AnsiString value)
   {
      /*
      Unfold all header field continuation lines as described in
      [RFC2822]; in particular, lines with terminators embedded in
      continued header field values (that is, CRLF sequences followed by
      WSP) MUST be interpreted without the CRLF.  Implementations MUST
      NOT remove the CRLF at the end of the header field value.
      */

      value.Replace("\r\n ", " ");
      value.Replace("\r\n\t", " ");

      /*
      Convert all sequences of one or more WSP characters to a single SP
      character.  WSP characters here include those before and after a
      line folding boundary.
      */

      value.Replace("\t ", " ");
      value.Replace(" \t", " ");
      
      while (value.Find("  ") >= 0)
         value.Replace("  ", " ");

      /*
      Delete all WSP characters at the end of each unfolded header field value.
      */

      while (value.EndsWith(" ") || value.EndsWith("\t"))
         value = value.Mid(0, value.GetLength() -1);

      /* 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.
      */
      value.Trim();


      return value;
   }
 AnsiString 
 SimpleCanonicalization::CanonicalizeBody(AnsiString value)
 {
    // remove all empty lines.
    while (value.EndsWith("\r\n"))
       value = value.Mid(0, value.GetLength()-2);
    
    value += "\r\n";
    
    return value;
 }
   AnsiString 
   SimpleCanonicalization::CanonicalizeHeader(AnsiString header, const std::pair<AnsiString, AnsiString> &signatureField, const std::vector<AnsiString> &fieldsToInclude, AnsiString &fieldList)
   {
      // first build a formatted list of header lines.
      std::vector<AnsiString> formattedHeaderLines;

      AnsiString result;
      std::vector<AnsiString> headerLines = StringParser::SplitString(header, "\r\n");

      AnsiString foldedLines;
      for (size_t i = headerLines.size(); i > 0; i--)
      {
         AnsiString line = headerLines[i-1];

         if (line.StartsWith(" ") || line.StartsWith("\t"))
         {
            // line is folded. append to next.
            foldedLines = line + "\r\n" + foldedLines;
         }
         else
         {
            // we have a line!
            int colonPos = line.Find(":");
            if (colonPos < 0)
            {
               assert(0); // broken header.
               continue;
            }

            AnsiString entireHeaderField = line + "\r\n" + foldedLines;

            formattedHeaderLines.push_back(entireHeaderField);

            foldedLines = "";
         }
      }

      for(AnsiString fieldToInclude : fieldsToInclude)
      {
         fieldToInclude.Trim();

         // locate the header line.
         auto iter = formattedHeaderLines.begin();
         auto iterEnd = formattedHeaderLines.end();
         
         for (; iter != iterEnd; iter++)
         {
            AnsiString headerLine = (*iter);

            int colonPos = headerLine.Find(":");
            AnsiString headerName = headerLine.Mid(0, colonPos);

            if (headerName.CompareNoCase(fieldToInclude) == 0) 
            {
               result += headerLine;

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

               fieldList += headerName;

               formattedHeaderLines.erase(iter);
               break;
            }
         }

      }

      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 headerName = signatureField.first;

         AnsiString headerLine = headerName + ": " + GetDKIMWithoutSignature_(signatureField.second);

         if (headerLine.EndsWith("\r\n"))
            headerLine = headerLine.Mid(0, headerLine.GetLength()-2);

         result += headerLine;
      }


      return result;
   }