/***************************************************************************** * Copyright 2005 Alt-N Technologies, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * This code incorporates intellectual property owned by Yahoo! and licensed * pursuant to the Yahoo! DomainKeys Patent License Agreement. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Changes done by ¢feh@fehcom.de obeying the above license * *****************************************************************************/ #include "dkimbase.h" #include #include #include "dkim.h" using std::string; CDKIMBase::CDKIMBase() : m_From(nullptr), m_Sender(nullptr), m_hTag(nullptr), m_hTagSize(0), m_hTagPos(0), m_Line(nullptr), m_LineSize(0), m_LinePos(0), m_InHeaders(true) {} CDKIMBase::~CDKIMBase() // delete { Free(m_Line); Free(m_From); Free(m_Sender); Free(m_hTag); } int CDKIMBase::Init(void) { return DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // Alloc - allocate buffer // //////////////////////////////////////////////////////////////////////////////// int CDKIMBase::Alloc(char *& szBuffer, int nRequiredSize) { szBuffer = new char[nRequiredSize]; return (szBuffer == NULL) ? DKIM_OUT_OF_MEMORY : DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // ReAlloc - extend buffer if necessary, leaving room for future expansion // //////////////////////////////////////////////////////////////////////////////// int CDKIMBase::ReAlloc(char *& szBuffer, int& nBufferSize, int nRequiredSize) { if (nRequiredSize > nBufferSize) { char *newp; int nNewSize = nRequiredSize + BUFFER_ALLOC_INCREMENT; if (Alloc(newp, nNewSize) == DKIM_SUCCESS) { if (szBuffer != NULL && nBufferSize > 0) { memcpy(newp, szBuffer, nBufferSize); delete[] szBuffer; } szBuffer = newp; nBufferSize = nNewSize; } else { return DKIM_OUT_OF_MEMORY; // memory alloc error! } } return DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // Process - split buffers into lines without any CRs or LFs at the end. // //////////////////////////////////////////////////////////////////////////////// void CDKIMBase::Free(char *szBuffer) { delete[] szBuffer; } //////////////////////////////////////////////////////////////////////////////// // // Process - split buffers into lines without any CRs or LFs at the end. // //////////////////////////////////////////////////////////////////////////////// int CDKIMBase::Process(const char *szBuffer, int nBufLength, bool bEOF) { const char *p = szBuffer; const char *e = szBuffer + nBufLength; while (p < e) { if (*p != '\n' || m_LinePos == 0 || m_Line[m_LinePos - 1] != '\r') { // add char to line if (m_LinePos >= m_LineSize) { int nRet = ReAlloc(m_Line, m_LineSize, m_LinePos + 1); if (nRet != DKIM_SUCCESS) return nRet; } m_Line[m_LinePos++] = *p; } else { // back up past the CR m_LinePos--; if (m_InHeaders) { // process header line if (m_LinePos == 0) { m_InHeaders = false; int Result = ProcessHeaders(); if (Result != DKIM_SUCCESS) return Result; } else { // append the header to the headers list if (m_Line[0] != ' ' && m_Line[0] != '\t') { HeaderList.push_back(string(m_Line, m_LinePos)); // fprintf(stderr," dkimbase.cpp:Process:Input: %s \n",m_Line); } else { if (!HeaderList.empty()) { HeaderList.back().append("\r\n", 2).append(m_Line, m_LinePos); } else { // no header to append to... } } } } else { // process body line int Result = ProcessBody(m_Line, m_LinePos, bEOF); if (Result != DKIM_SUCCESS) { m_LinePos = 0; return Result; } } m_LinePos = 0; } p++; } return DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // ProcessFinal - process leftovers if stopping before the body or mid-line // //////////////////////////////////////////////////////////////////////////////// int CDKIMBase::ProcessFinal(void) { if (m_LinePos > 0) Process("\r\n", 2, true); if (m_InHeaders) { m_InHeaders = false; ProcessHeaders(); /* type conversion should be safe as length is zero */ ProcessBody((char *)"", 0, true); } return DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // ProcessHeaders - process the headers (to be implemented by derived class) // //////////////////////////////////////////////////////////////////////////////// int CDKIMBase::ProcessHeaders() { return DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // ProcessBody - process body line (to be implemented by derived class) // //////////////////////////////////////////////////////////////////////////////// int CDKIMBase::ProcessBody(char *szBuffer, int nBufLength, bool bEOF) { return DKIM_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // // RemoveSWSP - remove streaming white space from buffer/string inline // //////////////////////////////////////////////////////////////////////////////// struct isswsp { bool operator()(char ch) { return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); } }; void CDKIMBase::RemoveSWSP(char *szBuffer) { *std::remove_if(szBuffer, szBuffer + strlen(szBuffer), isswsp()) = '\0'; } void CDKIMBase::RemoveSWSP(char *pBuffer, int& nBufLength) { nBufLength = std::remove_if(pBuffer, pBuffer + nBufLength, isswsp()) - pBuffer; } void CDKIMBase::RemoveSWSP(string& sBuffer) { sBuffer.erase(std::remove_if(sBuffer.begin(), sBuffer.end(), isswsp()), sBuffer.end()); } ////////////////////////////////////////////////////////////////////////////////////////// // // CompressSWSP - compress streaming white space into single spaces from buffer/string inline // ////////////////////////////////////////////////////////////////////////////////////////// void CDKIMBase::CompressSWSP(char *pBuffer, int& nBufLength) { char *pSrc = pBuffer; char *pDst = pBuffer; char *pEnd = pBuffer + nBufLength; while (pSrc != pEnd) { if (isswsp()(*pSrc)) { do { ++pSrc; } while (pSrc != pEnd && isswsp()(*pSrc)); if (pSrc == pEnd) break; *pDst++ = ' '; } *pDst++ = *pSrc++; } nBufLength = pDst - pBuffer; } void CDKIMBase::CompressSWSP(string& sBuffer) { string::iterator iSrc = sBuffer.begin(); string::iterator iDst = sBuffer.begin(); string::iterator iEnd = sBuffer.end(); while (iSrc != iEnd) { if (isswsp()(*iSrc)) { do { ++iSrc; } while (iSrc != iEnd && isswsp()(*iSrc)); if (iSrc == iEnd) break; *iDst++ = ' '; } *iDst++ = *iSrc++; } sBuffer.erase(iDst, iEnd); } ////////////////////////////////////////////////////////////////////////////////////////// // // RelaxHeader - relax a header field (lower case the name, remove swsp before and after :) // // modified 4/21/06 STB to remove white space before colon // ////////////////////////////////////////////////////////////////////////////////////////// string CDKIMBase::RelaxHeader(const string& sHeader) { string sTemp = sHeader; CompressSWSP(sTemp); string::size_type cpos = sTemp.find(':'); if (cpos == string::npos) { // no colon?! } else { // lower case the header field name for (unsigned i = 0; i < cpos; i++) { if (sTemp[i] >= 'A' && sTemp[i] <= 'Z') sTemp[i] += 'a' - 'A'; } // remove the space after the : if (cpos + 1 < sTemp.length() && sTemp[cpos + 1] == ' ') sTemp.erase(cpos + 1, 1); // remove the space before the : if (cpos > 0 && sTemp[cpos - 1] == ' ') sTemp.erase(cpos - 1, 1); } return sTemp; }