Update of /cvsroot/mahogany/M/src/mail
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23263/src/mail
Modified Files:
MessageCC.cpp MimePartCC.cpp
Added Files:
MimePartCCBase.cpp MimePartVirtual.cpp
Log Message:
a lot of changes to make it possible to fully support PGP-MIME messages
(although not quite yet):
1. added MimePartVirtual class which can be created from raw text
2. use it instead of (not existing any longer) MimePartRaw in UUDecode.cpp
3. added MessageView::AddVirtualMimePart() which allows to attach a virtual
MIME part to the viewer, this replaces ugly hack used by UUDecode.cpp
4. added MimePartCCBase: common base for MimePartCC and MimePartVirtual
5. MimePartCC implementation is now in MimePartCC.cpp, not MessageCC.cpp
6. added CclientParseMessage() function, fixed CR LF confusion in MessageCC
ctor from text
***** Error reading new file: [Errno 2] No such file or directory: 'MimePartCCBase.cpp'
***** Error reading new file: [Errno 2] No such file or directory:
'MimePartVirtual.cpp'
Index: MessageCC.cpp
===================================================================
RCS file: /cvsroot/mahogany/M/src/mail/MessageCC.cpp,v
retrieving revision 1.150
retrieving revision 1.151
diff -b -u -2 -r1.150 -r1.151
--- MessageCC.cpp 15 May 2004 10:45:41 -0000 1.150
+++ MessageCC.cpp 13 Jul 2004 21:58:41 -0000 1.151
@@ -93,9 +93,6 @@
m_Body = NULL;
m_Envelope = NULL;
- m_partContentPtr = NULL;
m_msgText = NULL;
- m_ownsPartContent = false;
-
m_folder = NULL;
m_Profile = NULL;
@@ -146,35 +143,8 @@
m_msgText =
strutil_strdup(wxConvertWX2MB(strutil_enforceCRLF(wxConvertMB2WX(text))));
- // find end of header "\012\012" (FIXME: not "\015\012"???)
- char
- *header = NULL,
- *bodycptr = NULL;
- unsigned long
- headerLen = 0;
-
- for ( unsigned long pos = 0; m_msgText[pos]; pos++ )
- {
- if((m_msgText[pos] == '\012' && m_msgText[pos+1] == '\012') // empty line
- // is end of header
- || m_msgText[pos+1] == '\0')
- {
- header = new char [pos+2];
- strncpy(header, m_msgText, pos+1);
- header[pos+1] = '\0';
- headerLen = pos+1;
- bodycptr = m_msgText + pos + 2;
- break;
- }
- pos++;
+ if ( !CclientParseMessage(m_msgText, &m_Envelope, &m_Body) )
+ {
+ wxLogError(_("Failed to create a mail message."));
}
-
- if(! header)
- return; // failed
-
- STRING str;
- INIT(&str, mail_string, (void *) bodycptr, strlen(bodycptr));
- rfc822_parse_msg (&m_Envelope, &m_Body, header, headerLen,
- &str, "" /*defaulthostname */, 0);
- delete [] header;
}
@@ -183,10 +153,16 @@
delete m_mimePartTop;
- if ( m_ownsPartContent )
- fs_give(&m_partContentPtr);
-
+ if ( m_folder )
+ {
+ m_folder->DecRef();
+ }
+ else
+ {
delete [] m_msgText;
- SafeDecRef(m_folder);
+ mail_free_envelope(&m_env);
+ mail_free_body(&m_body);
+ }
+
SafeDecRef(m_Profile);
}
@@ -602,61 +578,9 @@
}
- m_numParts = 0;
- m_mimePartTop = new MimePartCC(this);
-
- DecodeMIME(m_mimePartTop, m_Body);
+ m_mimePartTop = new MimePartCC(this, m_Body);
return true;
}
-void MessageCC::DecodeMIME(MimePartCC *mimepart, BODY *body)
-{
- CHECK_RET( mimepart && body, _T("NULL pointer(s) in DecodeMIME") );
-
- mimepart->m_body = body;
-
- if ( body->type != TYPEMULTIPART )
- {
- m_numParts++;
-
- // is it an encapsulated message?
- if ( body->type == TYPEMESSAGE && strcmp(body->subtype, "RFC822") == 0 )
- {
- body = body->nested.msg->body;
- if ( body )
- {
- mimepart->m_nested = new MimePartCC(mimepart);
-
- DecodeMIME(mimepart->m_nested, body);
- }
- else
- {
- // this is not fatal but not expected neither - I don't know if it
- // can ever happen, in fact
- wxLogDebug(_T("Embedded message/rfc822 without body structure?"));
- }
- }
- }
- else // multi part
- {
- // note that we don't increment m_numParts here as we only count parts
- // containing something and GetMimePart(n) ignores multitype parts
-
- MimePartCC **prev = &mimepart->m_nested;
- PART *part;
-
- // NB: message parts are counted from 1
- size_t n;
- for ( n = 1, part = body->nested.part; part; part = part->next, n++ )
- {
- *prev = new MimePartCC(mimepart, n);
-
- DecodeMIME(*prev, &part->body);
-
- prev = &((*prev)->m_next);
- }
- }
-}
-
const MimePart *MessageCC::GetTopMimePart() const
{
@@ -671,5 +595,5 @@
CheckMIME();
- return m_numParts;
+ return m_mimePartTop->GetPartsCount();
}
@@ -717,10 +641,11 @@
CheckMIME();
- CHECK( n >= 0 && (size_t)n < m_numParts, NULL, _T("invalid part number") );
+ CHECK( n >= 0 && n < CountParts(), NULL, _T("invalid part number") );
MimePart *mimepart = m_mimePartTop;
- // skip the MULTIPART pseudo parts - this is consistent with DecodeMIME()
- // which doesn't count them in m_numParts neither
+ // skip the MULTIPART pseudo parts -- this is consistent with how
+ // MimePartCCBase numbers the MIME parts as it doesn't count them in
+ // neither
while ( n || mimepart->GetType().GetPrimary() == MimeType::MULTIPART )
{
@@ -809,199 +734,4 @@
}
-const void *
-MessageCC::GetPartData(const MimePart& mimepart, unsigned long *lenptr)
-{
- CHECK( lenptr, NULL, _T("MessageCC::GetPartData(): NULL len ptr") );
-
- // first get the raw text
- // ----------------------
-
- const char *cptr = GetRawPartData(mimepart, lenptr);
- if ( !cptr || !*lenptr )
- return NULL;
-
- // now decode it
- // -------------
-
- // free old text
- if (m_ownsPartContent )
- {
- m_ownsPartContent = false;
-
- fs_give(&m_partContentPtr);
- }
-
- // total size of this message part
- unsigned long size = mimepart.GetSize();
-
- // just for convenience...
- unsigned char *text = (unsigned char *)cptr;
-
- switch ( mimepart.GetTransferEncoding() )
- {
- case ENCQUOTEDPRINTABLE: // human-readable 8-as-7 bit data
- m_partContentPtr = rfc822_qprint(text, size, lenptr);
-
- // some broken mailers sent messages with QP specified as the content
- // transfer encoding in the headers but don't encode the message
- // properly - in this case show it as plain text which is better than
- // not showing it at all
- if ( m_partContentPtr )
- {
- m_ownsPartContent = true;
-
- break;
- }
- //else: treat it as plain text
-
- // it was overwritten by rfc822_qprint() above
- *lenptr = size;
-
- // fall through
-
- case ENC7BIT: // 7 bit SMTP semantic data
- case ENC8BIT: // 8 bit SMTP semantic data
- case ENCBINARY: // 8 bit binary data
- case ENCOTHER: // unknown
- default:
- // nothing to do
- m_partContentPtr = text;
- break;
-
-
- case ENCBASE64: // base-64 encoded data
- // the size of possible extra non Base64 encoded text following a
- // Base64 encoded part
- const unsigned char *startSlack = NULL;
- size_t sizeSlack = 0;
-
- // there is a frequent problem with mail list software appending the
- // mailing list footer (i.e. a standard signature containing the
- // instructions about how to [un]subscribe) to the top level part of a
- // Base64-encoded message thus making it invalid - worse c-client code
- // doesn't complain about it but simply returns some garbage in this
- // case
- //
- // we try to detect this case and correct for it: note that neither
- // '-' nor '_' which typically start the signature are valid
- // characters in base64 so the logic below should work for all common
- // cases
-
- // only check the top level part
- if ( !mimepart.GetParent() )
- {
- const unsigned char *p;
- for ( p = text; *p; p++ )
- {
- // we do *not* want to use the locale-specific settings here,
- // hence don't use isalpha()
- const unsigned char ch = *p;
- if ( (ch >= 'A' && ch <= 'Z') ||
- (ch >= 'a' && ch <= 'z') ||
- (ch >= '0' && ch <= '9') ||
- (ch == '+' || ch == '/' || ch == '\r' || ch == '\n') )
- {
- // valid Base64 char
- continue;
- }
-
- if ( ch == '=' )
- {
- p++;
-
- // valid, but can only occur at the end of data as padding,
- // so still break below -- but not before:
-
- // a) skipping a possible second '=' (can't be more than 2 of
- // them)
- if ( *p == '=' )
- p++;
-
- // b) skipping the terminating "\r\n"
- if ( p[0] == '\r' && p[1] == '\n' )
- p += 2;
- }
-
- // what (if anything) follows can't appear in a valid Base64
- // message
- break;
- }
-
- size_t sizeValid = p - text;
- if ( sizeValid != size )
- {
- ASSERT_MSG( sizeValid < size,
- _T("logic error in base64 validity check") );
-
- // take all the rest verbatim below
- startSlack = p;
- sizeSlack = size - sizeValid;
-
- // and decode just the (at least potentially) valid part
- size = sizeValid;
- }
- }
-
- m_partContentPtr = rfc822_base64(text, size, lenptr);
- if ( !m_partContentPtr )
- {
- wxLogDebug(_T("rfc822_base64() failed"));
-
- // use original text: this is better than nothing and can be
- // exactly what we need in case of messages generated with base64
- // encoding in the headers but then sent as 8 it binary (old (circa
- // 2003) versions of Thunderbird did this!)
- m_partContentPtr = text;
- *lenptr = size;
- }
- else // ok
- {
- // append the non Base64-encoded chunk, if any, to the end of decoded
- // data
- if ( sizeSlack )
- {
- fs_resize(&m_partContentPtr, *lenptr + sizeSlack);
- memcpy((char *)m_partContentPtr + *lenptr, startSlack, sizeSlack);
-
- *lenptr += sizeSlack;
- }
-
- m_ownsPartContent = true;
- }
- }
-
- return m_partContentPtr;
-}
-
-const void *MimePartCC::GetRawContent(unsigned long *len) const
-{
- return GetMessage()->GetRawPartData(*this, len);
-}
-
-const void *MimePartCC::GetContent(unsigned long *len) const
-{
- return GetMessage()->GetPartData(*this, len);
-}
-
-String MimePartCC::GetHeaders() const
-{
- return GetMessage()->GetPartHeaders(*this);
-}
-
-String MimePartCC::GetTextContent() const
-{
- unsigned long len;
- const char *p = reinterpret_cast<const char *>(GetContent(&len));
- if ( !p )
- return wxGetEmptyString();
-
-#if wxUSE_UNICODE
- #warning "We need the original encoding here, TODO"
- return wxConvertMB2WX(p);
-#else // ANSI
- return wxString(p, len);
-#endif // Unicode/ANSI
-}
-
// ----------------------------------------------------------------------------
// get the body and/or envelope information from cclient
@@ -1137,4 +867,9 @@
}
+MailFolder *MessageCC::GetFolder() const
+{
+ return m_folder;
+}
+
// ----------------------------------------------------------------------------
// MessageCC::WriteToString
@@ -1181,2 +916,52 @@
}
+// ============================================================================
+// functions from Mcclient.h
+// ============================================================================
+
+bool
+CclientParseMessage(const char *msgText,
+ ENVELOPE **ppEnv,
+ BODY **ppBody,
+ size_t *pHdrLen)
+{
+ const char *bodycptr = NULL;
+ unsigned long headerLen = 0;
+
+ // find end of header "\r\n\r\n"
+ bool eol = true;
+ for ( unsigned long pos = 0; msgText[pos]; pos++ )
+ {
+ // empty line or end of text?
+ if ( msgText[pos] == '\r' && msgText[++pos] == '\n' )
+ {
+ if ( eol )
+ {
+ headerLen = pos - 1;
+ bodycptr = msgText + pos + 1; // skip eol
+ break;
+ }
+
+ eol = true;
+ }
+ else
+ {
+ eol = false;
+ }
+ }
+
+ if ( !headerLen )
+ return false;
+
+ STRING str;
+ INIT(&str, mail_string, const_cast<char *>(bodycptr), strlen(bodycptr));
+ rfc822_parse_msg(ppEnv, ppBody,
+ const_cast<char *>(msgText), headerLen,
+ &str, "", 0);
+
+ if ( pHdrLen )
+ *pHdrLen = headerLen;
+
+ return true;
+}
+
Index: MimePartCC.cpp
===================================================================
RCS file: /cvsroot/mahogany/M/src/mail/MimePartCC.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -b -u -2 -r1.11 -r1.12
--- MimePartCC.cpp 12 Oct 2003 17:24:19 -0000 1.11
+++ MimePartCC.cpp 13 Jul 2004 21:58:41 -0000 1.12
@@ -30,67 +30,8 @@
#endif // USE_PCH
-#include <wx/fontmap.h>
-
#include "MimePartCC.h"
+#include "MessageCC.h"
#include "MailFolder.h" // for DecodeHeader
-#undef MESSAGE
-
-// ============================================================================
-// MimeType implementation
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// initializing
-// ----------------------------------------------------------------------------
-
-MimeType::MimeType(Primary primary, const String& subtype)
-{
- m_primary = primary;
- m_subtype = subtype.Upper();
-}
-
-MimeType& MimeType::Assign(const String& mimetype)
-{
- String type = mimetype.BeforeFirst('/').Upper();
-
- m_primary = INVALID;
- for ( size_t n = 0; body_types[n]; n++ )
- {
- if ( type == wxConvertMB2WX(body_types[n]) )
- {
- m_primary = (MimeType::Primary)n;
-
- break;
- }
- }
-
- m_subtype = mimetype.AfterFirst('/').Upper();
-
- return *this;
-}
-
-// ----------------------------------------------------------------------------
-// accessors
-// ----------------------------------------------------------------------------
-
-String MimeType::GetType() const
-{
- ASSERT_MSG( IsOk(), _T("using uninitialized MimeType") );
-
- // body_types is defined in c-client/rfc822.c
- return wxConvertMB2WX(body_types[m_primary]);
-}
-
-// ----------------------------------------------------------------------------
-// tests
-// ----------------------------------------------------------------------------
-
-bool MimeType::Matches(const MimeType& wildcard) const
-{
- return m_primary == wildcard.m_primary &&
- (wildcard.m_subtype == '*' || m_subtype == wildcard.m_subtype);
-}
-
// ============================================================================
// MimePartCC implementation
@@ -98,223 +39,66 @@
// ----------------------------------------------------------------------------
-// ctors/dtors
+// ctors
// ----------------------------------------------------------------------------
-void MimePartCC::Init()
+MimePartCC::MimePartCC(MessageCC *message, BODY *body)
+ : MimePartCCBase(body)
{
- m_body = NULL;
-
- m_parent =
- m_nested =
- m_next = NULL;
-
- m_message = NULL;
+ m_message = message;
- m_parameterList =
- m_dispositionParameterList = NULL;
+ CreateSubParts();
}
-MimePartCC::MimePartCC(MessageCC *message)
+MimePartCC::MimePartCC(BODY *body, MimePartCC *parent, size_t nPart)
+ : MimePartCCBase(body, parent, nPart)
{
- Init();
-
- m_message = message;
+ // only the top level message has m_message set, so delegate to parent if we
+ // have one
+ m_message = parent->GetMessage();
- // if this message is not multipart, we must have "1", otherwise it is
- // unused anyhow (the trouble is that we don't know if we're multipart or
- // not yet as m_body is not set)
- m_spec = _T('1');
+ CreateSubParts();
}
-MimePartCC::MimePartCC(MimePartCC *parent, size_t nPart)
+void MimePartCC::CreateSubParts()
{
- Init();
-
- m_parent = parent;
-
- /*
- Nasty hack: c-client (and so probably IMAP as well) doesn't seem to
- number the multipart parts whose parent part is the message, so when
- assigning the part spec to their children we should skip the parent and
- use the grandparent spec as the base.
-
- I'd like to really understand the rule to be used here one of these
- days...
- */
- if ( m_parent && m_parent->GetParent() )
+ if ( m_body->type != TYPEMULTIPART )
{
- String specParent;
+ m_numParts++;
- MimeType::Primary mt = m_parent->GetType().GetPrimary();
- if ( mt == MimeType::MULTIPART )
+ // is it an encapsulated message?
+ if ( m_body->type == TYPEMESSAGE &&
+ strcmp(m_body->subtype, "RFC822") == 0 )
{
- MimePartCC *grandparent = m_parent->m_parent;
-
- // it shouldn't be the top level part (note that it is non NULL
- // because of the test in the enclosing if)
- if ( grandparent->m_parent )
- {
- mt = grandparent->GetType().GetPrimary();
-
- if ( mt == MimeType::MESSAGE )
+ BODY *bodyNested = m_body->nested.msg->body;
+ if ( bodyNested )
{
- // our parent part doesn't have its own part number, use the
- // grand parent spec as the base
- specParent = grandparent->m_spec;
- }
+ m_nested = new MimePartCC(bodyNested, this, 1);
}
- }
-
- if ( specParent.empty() )
+ else
{
- specParent = m_parent->m_spec;
- }
-
- m_spec << specParent << '.';
+ // this is not fatal but not expected neither - I don't know if it
+ // can ever happen, in fact
+ wxLogDebug(_T("Embedded message/rfc822 without body structure?"));
}
-
- m_spec << wxString::Format(_T("%lu"), (unsigned long)nPart);
-}
-
-MimePartCC::~MimePartCC()
-{
- delete m_next;
- delete m_nested;
-
- delete m_parameterList;
- delete m_dispositionParameterList;
-}
-
-// ----------------------------------------------------------------------------
-// MIME tree access
-// ----------------------------------------------------------------------------
-
-MimePart *MimePartCC::GetParent() const
-{
- return m_parent;
-}
-
-MimePart *MimePartCC::GetNext() const
-{
- return m_next;
-}
-
-MimePart *MimePartCC::GetNested() const
-{
- return m_nested;
-}
-
-// ----------------------------------------------------------------------------
-// headers access
-// ----------------------------------------------------------------------------
-
-MimeType MimePartCC::GetType() const
-{
- // cast is ok as we use the same values in MimeType as c-client
- return MimeType((MimeType::Primary)m_body->type, wxConvertMB2WX(m_body->subtype));
-}
-
-String MimePartCC::GetDescription() const
-{
- // FIXME: we lose the encoding info here - but we don't have any way to
- // return it from here currently
- return MailFolder::DecodeHeader(wxConvertMB2WX(m_body->description));
-}
-
-String MimePartCC::GetFilename() const
-{
- // try hard to find an acceptable name for this part
- String filename = GetDispositionParam(_T("filename"));
-
- if ( filename.empty() )
- filename = GetParam(_T("filename"));
-
- if ( filename.empty() )
- filename = GetParam(_T("name"));
-
- return filename;
-}
-
-String MimePartCC::GetDisposition() const
-{
- return wxConvertMB2WX(m_body->disposition.type);
-}
-
-String MimePartCC::GetPartSpec() const
-{
- return m_spec;
-}
-
-// ----------------------------------------------------------------------------
-// parameters access
-// ----------------------------------------------------------------------------
-
-/* static */
-String MimePartCC::FindParam(const MimeParameterList& list, const String& name)
-{
- String value;
-
- MimeParameterList::iterator i;
- for ( i = list.begin(); i != list.end(); i++ )
- {
- // parameter names are not case-sensitive, i.e. "charset" == "CHARSET"
- if ( name.CmpNoCase(i->name) == 0 )
- {
- // found
- value = i->value;
- break;
}
}
-
- // FIXME: we lose the encoding info here - but we don't have any way to
- // return it from here currently
- return MailFolder::DecodeHeader(value);
-}
-
-String MimePartCC::GetParam(const String& name) const
-{
- return FindParam(GetParameters(), name);
-}
-
-String MimePartCC::GetDispositionParam(const String& name) const
-{
- return FindParam(GetDispositionParameters(), name);
-}
-
-// ----------------------------------------------------------------------------
-// parameter lists handling
-// ----------------------------------------------------------------------------
-
-/* static */
-void MimePartCC::InitParamList(MimeParameterList *list, PARAMETER *par)
-{
- while ( par )
+ else // multi part
{
- list->push_back(new MimeParameter(wxConvertMB2WX(par->attribute),
wxConvertMB2WX(par->value)));
+ // note that we don't increment m_numParts here as we only count parts
+ // containing something and MessageCC::GetMimePart(n) ignores multitype
+ // parts
- par = par->next;
- }
-}
+ MimePartCCBase **prev = &m_nested;
-const MimeParameterList& MimePartCC::GetParameters() const
-{
- if ( !m_parameterList )
+ // NB: message parts are counted from 1
+ size_t n = 1;
+ for ( PART *part = m_body->nested.part; part; part = part->next, n++ )
{
- ((MimePartCC *)this)->m_parameterList = new MimeParameterList;
- InitParamList(m_parameterList, m_body->parameter);
- }
-
- return *m_parameterList;
-}
+ *prev = new MimePartCC(&part->body, this, n);
-const MimeParameterList& MimePartCC::GetDispositionParameters() const
-{
- if ( !m_dispositionParameterList )
- {
- ((MimePartCC *)this)->m_dispositionParameterList = new MimeParameterList;
- InitParamList(m_dispositionParameterList, m_body->disposition.parameter);
+ // static_cast<> needed to access protected member
+ prev = &(static_cast<MimePartCC *>(*prev)->m_next);
+ }
}
-
- return *m_dispositionParameterList;
}
@@ -323,41 +107,12 @@
// ----------------------------------------------------------------------------
-MessageCC *MimePartCC::GetMessage() const
+const void *MimePartCC::GetRawContent(unsigned long *len) const
{
- // only the top level message has m_message set, so delegate to parent if we
- // have one
- return m_parent ? m_parent->GetMessage() : m_message;
+ return GetMessage()->GetRawPartData(*this, len);
}
-// MimePartCC::GetContent(), GetRawContent() and GetHeaders() are implemented
-// in MessageCC.cpp to reduce compilation dependencies (Message doesn't have
-// the necessary methods so we'd need to include MessageCC.h here...)
-
-MimeXferEncoding MimePartCC::GetTransferEncoding() const
+String MimePartCC::GetHeaders() const
{
- // cast is ok as we use the same values for MimeXferEncoding as c-client
- return (MimeXferEncoding)m_body->encoding;
-}
-
-size_t MimePartCC::GetSize() const
-{
- return m_body->size.bytes;
-}
-
-// ----------------------------------------------------------------------------
-// text part additional info
-// ----------------------------------------------------------------------------
-
-size_t MimePartCC::GetNumberOfLines() const
-{
- return m_body->size.lines;
-}
-
-wxFontEncoding MimePartCC::GetTextEncoding() const
-{
- String charset = GetParam(_T("charset"));
-
- return charset.empty() ? wxFONTENCODING_SYSTEM
- : wxFontMapper::Get()->CharsetToEncoding(charset);
+ return GetMessage()->GetPartHeaders(*this);
}
-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 -
digital self defense, top technical experts, no vendor pitches,
unmatched networking opportunities. Visit www.blackhat.com
_______________________________________________
Mahogany-cvsupdates mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/mahogany-cvsupdates