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

Reply via email to