// store the body part to string buffer int CMimeBody::Store(char* pszData, int nMaxSize) const { // store header fields int nSize = CMimeHeader::Store(pszData, nMaxSize); if (nSize <= 0) return nSize; // store content char* pszDataBegin = pszData; // preserve start position pszData += nSize; nMaxSize -= nSize; CMimeCodeBase* pCoder = CMimeEnvironment::CreateCoder(GetTransferEncoding()); ASSERT(pCoder != NULL); pCoder->SetInput((const char*)m_pbText, m_nTextSize, true); int nOutput = pCoder->GetOutput((unsigned char*)pszData, nMaxSize); delete pCoder; if (nOutput < 0) return nOutput; pszData += nOutput; nMaxSize -= nOutput; if (m_listBodies.empty()) return (int)(pszData - pszDataBegin); // store child body parts string strBoundary = GetBoundary(); if (strBoundary.empty()) return -1; // boundary not be set int nBoundSize = (int)strBoundary.size() + 6; for (CBodyList::const_iterator it=m_listBodies.begin(); it!=m_listBodies.end(); it++) { if (nMaxSize < nBoundSize) break; if (m_listBodies.begin() == it && *(pszData-2) == '\r' && *(pszData-1) == '\n') { pszData -= 2; nMaxSize += 2; } ::sprintf(pszData, "\r\n--%s\r\n", strBoundary.c_str()); pszData += nBoundSize; nMaxSize -= nBoundSize; CMimeBody* pBP = *it; ASSERT(pBP != NULL); nOutput = pBP->Store(pszData, nMaxSize); if (nOutput < 0) return nOutput; pszData += nOutput; nMaxSize -= nOutput; } if (nMaxSize >= nBoundSize+2) // add closing boundary delimiter { ::sprintf(pszData, "\r\n--%s--\r\n", strBoundary.c_str()); pszData += nBoundSize + 2; } return (int)(pszData - pszDataBegin); }
// return the length needed to store this body part to string buffer int CMimeBody::GetLength() const { int nLength = CMimeHeader::GetLength(); CMimeCodeBase* pCoder = CMimeEnvironment::CreateCoder(GetTransferEncoding()); ASSERT(pCoder != NULL); pCoder->SetInput((const char*)m_pbText, m_nTextSize, true); nLength += pCoder->GetOutputLength(); delete pCoder; if (m_listBodies.empty()) return nLength; string strBoundary = GetBoundary(); int nBoundSize = (int) strBoundary.size(); list<CMimeBody*>::const_iterator it; for (it=m_listBodies.begin(); it!=m_listBodies.end(); it++) { nLength += nBoundSize + 6; // include 2 leading hyphens and 2 pair of CRLFs CMimeBody* pBP = *it; ASSERT(pBP != NULL); nLength += pBP->GetLength(); } nLength += nBoundSize + 8; // include 2 leading hyphens, 2 trailng hyphens and 2 pair of CRLFs return nLength; }
// write the content (attachment) to a file bool MimeBody::WriteToFile(const String &sFilename) { // First de-code the content. MimeCodeBase* pCoder = MimeEnvironment::CreateCoder(GetTransferEncoding()); ASSERT(pCoder != NULL); pCoder->SetInput(m_pbText, m_pbText.GetLength(), false); AnsiString decoded; pCoder->GetOutput(decoded); FileUtilities::WriteToFile(sFilename, decoded); return true; }
// initialize the content (attachment) by reading from a file bool MimeBody::ReadFromFile(const String &pszFilename) { File oFile; if (!oFile.Open(pszFilename, File::OTReadOnly)) { if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::ReadFromFile - Error opening file RO"); return false; } shared_ptr<ByteBuffer> pUnencodedBuffer = oFile.ReadFile(); if (!pUnencodedBuffer) { if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::ReadFromFile - pUnencodedBuffer empty"); return false; } // Encode the file, to base64 or likewise. MimeCodeBase* pCoder = MimeEnvironment::CreateCoder(GetTransferEncoding()); ASSERT(pCoder != NULL); pCoder->SetInput((const char*) pUnencodedBuffer->GetCharBuffer(), pUnencodedBuffer->GetSize(), true); // Copy the buffer pCoder->GetOutput(m_pbText); AnsiString sCharset = "utf-8"; // Set params to this String sFileName = FileUtilities::GetFileNameFromFullPath(pszFilename); AnsiString sEncodedValue = MIMEUnicodeEncoder::EncodeValue(sCharset, sFileName); SetName(sEncodedValue); // set 'name' parameter: // Create an content-disposition header as well. SetRawFieldValue(CMimeConst::ContentDisposition(), CMimeConst::Inline(), ""); SetParameter(CMimeConst::ContentDisposition(), CMimeConst::Filename(), sEncodedValue); if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::ReadFromFile - Attachment encoded successfully"); return true; }
String MimeBody::GetUnicodeText() { String sWideStr; AnsiString sRawText = GetRawText(); if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::GetUnicodeText sRawText: " + sRawText) else if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::GetUnicodeText sRawText"); if (sRawText.IsEmpty()) { if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::GetUnicodeText sRawText.IsEmpty!"); return sRawText; } std::string strCharset = GetCharset(); if (strCharset.size() == 0) { if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::GetUnicodeText strCharset.size=0!"); return sRawText; } // De-code the value to plain text. AnsiString sRetVal; MimeCodeBase* pCoder = MimeEnvironment::CreateCoder(GetTransferEncoding()); pCoder->SetInput(sRawText, sRawText.GetLength(), false); pCoder->GetOutput(sRetVal); delete pCoder; sWideStr = Charset::ToWideChar(sRetVal, strCharset); if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::GetUnicodeText sWideStr: " + sWideStr) else if (IniFileSettings::Instance()->GetLogLevel() > 99) LOG_DEBUG("MimeBody::GetUnicodeText sWideStr"); return sWideStr; }
// load a body part from string buffer int CMimeBody::Load(const char* pszData, int nDataSize) { // load header fields int nSize = CMimeHeader::Load(pszData, nDataSize); if (nSize <= 0) return nSize; const char* pszDataBegin = pszData; // preserve start position pszData += nSize; nDataSize -= nSize; FreeBuffer(); // determine the length of the content const char* pszEnd = pszData + nDataSize; int nMediaType = GetMediaType(); if (MEDIA_MULTIPART == nMediaType) { // find the begin boundary string strBoundary = GetBoundary(); if (!strBoundary.empty()) { strBoundary = "\r\n--" + strBoundary; pszEnd = ::FindString(pszData-2, strBoundary.c_str(), pszEnd); if (!pszEnd) pszEnd = pszData + nDataSize; else pszEnd += 2; } } // load content nSize = (int)(pszEnd - pszData); if (nSize > 0) { CMimeCodeBase* pCoder = CMimeEnvironment::CreateCoder(GetTransferEncoding()); ASSERT(pCoder != NULL); pCoder->SetInput(pszData, nSize, false); int nOutput = pCoder->GetOutputLength(); if (AllocateBuffer(nOutput+4)) nOutput = pCoder->GetOutput(m_pbText, nOutput); else nOutput = -1; delete pCoder; if (nOutput < 0) return nOutput; ASSERT(nOutput < m_nTextSize); m_pbText[nOutput] = 0; m_nTextSize = nOutput; pszData += nSize; nDataSize -= nSize; } if (nDataSize <= 0) return (int)(pszData - pszDataBegin); // load child body parts string strBoundary = GetBoundary(); ASSERT(strBoundary.size() > 0); strBoundary = "\r\n--" + strBoundary; // look for the first boundary (case sensitive) pszData -= 2; // go back to CRLF nDataSize += 2; pszEnd = pszData + nDataSize; const char* pszBound1 = ::FindString(pszData, strBoundary.c_str(), pszEnd); while (pszBound1 != NULL && pszBound1 < pszEnd) { const char* pszStart = ::FindString(pszBound1+2, "\r\n", pszEnd); if (!pszStart) break; pszStart += 2; if (pszBound1[strBoundary.size()] == '-' && pszBound1[strBoundary.size()+1] == '-') return (int)(pszStart - pszDataBegin); // reach the closing boundary // look for the next boundary const char* pszBound2 = ::FindString(pszStart, strBoundary.c_str(), pszEnd); if (!pszBound2) // overflow, boundary may be truncated pszBound2 = pszEnd; int nEntitySize = (int) (pszBound2 - pszStart); // find the media type of this body part: CMimeHeader header; header.Load(pszStart, nEntitySize); string strMediaType = header.GetMainType(); CMimeBody* pBP = CreatePart(strMediaType.c_str()); int nInputSize = pBP->Load(pszStart, nEntitySize); if (nInputSize < 0) { ErasePart(pBP); return nInputSize; } pszBound1 = pszBound2; } return (int)(pszEnd - pszDataBegin); }