Bug 94724

Summary: Integrate ktnef into kmail
Product: [Applications] kmail Reporter: xsov
Component: generalAssignee: kdepim bugs <kdepim-bugs>
Status: RESOLVED FIXED    
Severity: wishlist CC: xsov
Priority: NOR    
Version: 1.6.2   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:

Description xsov 2004-12-09 08:05:26 UTC
Version:           1.6.2 (using KDE 3.2.3, compiled sources)
Compiler:          gcc version 3.3.3
OS:                Linux (i686) release 2.4.27

Why not integrate ktnef functionality directly into Kmail? So files from TNEF-archive will be shown just like usual attachments when viewing e-mail with its internal icons (supplied with TNEF-archive)?

It is not handily using external application, such as ktnef.

It may be released as library libtnef, which will be used by kmail and ktnef :)

Or there is some patent/license restrictions?
Comment 1 Konrad Dear 2005-05-02 14:18:40 UTC
I agree,  I think this would be good idea to do.  This is even more relevant when you start sharing Kmail with Outlook against the same email account.  Outlook and Exchange tend to conspire together and add to every message you open a tnef attachment, even those messages without prior attachments.  Perhaps it's their way of updating message flags?

It's particularly annoying seeing every message with a tnef attachment.

I also have thousands of emails, prior to discovering Linux :), with tnefs embedded into them.

To be able to skip the step of saving / opening tnef files would be great.
Comment 2 Jan de Visser 2005-05-02 14:30:46 UTC
I was thinking about/working on this a while ago (sept 2004), but got distracted (work :(. I will see if I can ever pick it up again.
Comment 3 Volker Krause 2007-04-03 23:01:00 UTC
SVN commit 650109 by vkrause:

Merge inline-viewing of TNEF attachments from the KDE PIM enterprise
branch.

FEATURE: 94724

Approved by Ingo and Allen.


 M  +1 -0      Makefile.am  
 M  +4 -2      bodypartformatter.cpp  
 M  +21 -14    kmreaderwin.cpp  
 M  +8 -1      kmreaderwin.h  
 M  +73 -0     objecttreeparser.cpp  
 M  +2 -1      objecttreeparser.h  


--- branches/KDE/3.5/kdepim/kmail/Makefile.am #650108:650109
@@ -14,6 +14,7 @@
 	-I$(top_srcdir)/certmanager/lib \
         -I$(top_srcdir)/certmanager/lib/ui \
         -I$(top_srcdir)/indexlib \
+        -I$(top_srcdir)/ktnef \
         -I$(top_srcdir) \
         $(GPGME_CFLAGS) \
         $(all_includes)
--- branches/KDE/3.5/kdepim/kmail/bodypartformatter.cpp #650108:650109
@@ -114,6 +114,7 @@
   CREATE_BODY_PART_FORMATTER(ApplicationPkcs7Mime)
   CREATE_BODY_PART_FORMATTER(ApplicationChiasmusText)
   //CREATE_BODY_PART_FORMATTER(ApplicationPgp)
+  CREATE_BODY_PART_FORMATTER(ApplicationMsTnef)
 
   CREATE_BODY_PART_FORMATTER(MessageRfc822)
 
@@ -147,6 +148,7 @@
   { "x-pkcs7-mime", &ApplicationPkcs7MimeBodyPartFormatter::create },
   { "vnd.de.bund.bsi.chiasmus-text", &ApplicationChiasmusTextBodyPartFormatter::create },
   { "pgp", &ApplicationPgpBodyPartFormatter::create },
+  { "ms-tnef", &ApplicationMsTnefBodyPartFormatter::create }
 };
 
 static const SubtypeBuiltin textSubtypeBuiltins[] = {
@@ -286,8 +288,8 @@
       break;
     case 'm':
     case 'M':
-      //if ( kasciistricmp( subtype, "ms-tnef" ) == 0 )
-      //  return ApplicationMsTnefBodyPartFormatter::create();
+      if ( kasciistricmp( subtype, "ms-tnef" ) == 0 )
+        return ApplicationMsTnefBodyPartFormatter::create();
       break;
     case 'v':
     case 'V':
--- branches/KDE/3.5/kdepim/kmail/kmreaderwin.cpp #650108:650109
@@ -1679,21 +1679,10 @@
     fileName = aMsgPart->name();
 
   //--- Sven's save attachments to /tmp start ---
-  KTempFile *tempFile = new KTempFile( QString::null,
-                                       "." + QString::number( aPartNum ) );
-  tempFile->setAutoDelete( true );
-  QString fname = tempFile->name();
-  delete tempFile;
+  QString fname = createTempDir( QString::number( aPartNum ) );
+  if ( fname.isEmpty() )
+    return QString();
 
-  if( ::access( QFile::encodeName( fname ), W_OK ) != 0 )
-    // Not there or not writable
-    if( ::mkdir( QFile::encodeName( fname ), 0 ) != 0
-        || ::chmod( QFile::encodeName( fname ), S_IRWXU ) != 0 )
-      return QString::null; //failed create
-
-  assert( !fname.isNull() );
-
-  mTempDirs.append( fname );
   // strip off a leading path
   int slashPos = fileName.findRev( '/' );
   if( -1 != slashPos )
@@ -1719,7 +1708,25 @@
   return fname;
 }
 
+QString KMReaderWin::createTempDir( const QString &param )
+{
+  KTempFile *tempFile = new KTempFile( QString::null, "." + param );
+  tempFile->setAutoDelete( true );
+  QString fname = tempFile->name();
+  delete tempFile;
 
+  if( ::access( QFile::encodeName( fname ), W_OK ) != 0 )
+    // Not there or not writable
+    if( ::mkdir( QFile::encodeName( fname ), 0 ) != 0
+        || ::chmod( QFile::encodeName( fname ), S_IRWXU ) != 0 )
+      return QString::null; //failed create
+
+  assert( !fname.isNull() );
+
+  mTempDirs.append( fname );
+  return fname;
+}
+
 //-----------------------------------------------------------------------------
 void KMReaderWin::showVCard( KMMessagePart * msgPart ) {
   const QString vCard = msgPart->bodyToUnicode( overrideCodec() );
--- branches/KDE/3.5/kdepim/kmail/kmreaderwin.h #650108:650109
@@ -65,7 +65,7 @@
   struct URLArgs;
 }
 
-/** 
+/**
    This class implements a "reader window", that is a window
    used for reading or viewing messages.
 */
@@ -406,6 +406,13 @@
   */
   QString writeMessagePartToTempFile( KMMessagePart* msgPart, int partNumber );
 
+  /**
+    Creates a temporary dir for saving attachments, etc.
+    Will be automatically deleted when another message is viewed.
+    @param param Optional part of the directory name.
+  */
+  QString createTempDir( const QString &param = QString() );
+
   /** show window containing infos about a vCard. */
   void showVCard(KMMessagePart *msgPart);
 
--- branches/KDE/3.5/kdepim/kmail/objecttreeparser.cpp #650108:650109
@@ -72,9 +72,14 @@
 #include <kpgp.h>
 #include <linklocator.h>
 
+#include <ktnef/ktnefparser.h>
+#include <ktnef/ktnefmessage.h>
+#include <ktnef/ktnefattach.h>
+
 // other KDE headers
 #include <kdebug.h>
 #include <klocale.h>
+#include <kmimetype.h>
 #include <kglobal.h>
 #include <khtml_part.h>
 #include <ktempfile.h>
@@ -86,6 +91,7 @@
 
 // other Qt headers
 #include <qtextcodec.h>
+#include <qdir.h>
 #include <qfile.h>
 #include <qapplication.h>
 #include <kstyle.h>
@@ -1703,6 +1709,73 @@
   return true;
 }
 
+bool ObjectTreeParser::processApplicationMsTnefSubtype( partNode *node, ProcessResult &result )
+{
+  Q_UNUSED( result );
+  if ( !mReader )
+    return false;
+
+  const QString fileName = mReader->writeMessagePartToTempFile( &node->msgPart(), node->nodeId() );
+  KTNEFParser parser;
+  if ( !parser.openFile( fileName ) || !parser.message()) {
+    kdDebug() << k_funcinfo << "Could not parse " << fileName << endl;
+    return false;
+  }
+
+  QPtrList<KTNEFAttach> tnefatts = parser.message()->attachmentList();
+  if ( tnefatts.isEmpty() ) {
+    kdDebug() << k_funcinfo << "No attachments found in " << fileName << endl;
+    return false;
+  }
+
+  if ( !showOnlyOneMimePart() ) {
+    QString label = node->msgPart().fileName().stripWhiteSpace();
+    if ( label.isEmpty() )
+      label = node->msgPart().name().stripWhiteSpace();
+    label = KMMessage::quoteHtmlChars( label, true );
+    const QString comment = KMMessage::quoteHtmlChars( node->msgPart().contentDescription(), true );
+    const QString dir = QApplication::reverseLayout() ? "rtl" : "ltr" ;
+
+    QString htmlStr = "<table cellspacing=\"1\" class=\"textAtm\">"
+                "<tr class=\"textAtmH\"><td dir=\"" + dir + "\">";
+    if ( !fileName.isEmpty() )
+      htmlStr += "<a href=\"" + QString("file:")
+        + KURL::encode_string( fileName ) + "\">"
+        + label + "</a>";
+    else
+      htmlStr += label;
+    if ( !comment.isEmpty() )
+      htmlStr += "<br>" + comment;
+    htmlStr += "</td></tr><tr class=\"textAtmB\"><td>";
+    htmlWriter()->queue( htmlStr );
+  }
+
+  for ( uint i = 0; i < tnefatts.count(); ++i ) {
+    KTNEFAttach *att = tnefatts.at( i );
+    QString label = att->displayName();
+    if( label.isEmpty() )
+      label = att->name();
+    label = KMMessage::quoteHtmlChars( label, true );
+
+    QString dir = mReader->createTempDir( "ktnef-" + QString::number( i ) );
+    parser.extractFileTo( att->name(), dir );
+    mReader->mTempFiles.append( dir + QDir::separator() + att->name() );
+    QString href = "file:" + KURL::encode_string( dir + QDir::separator() + att->name() );
+
+    KMimeType::Ptr mimeType = KMimeType::mimeType( att->mimeTag() );
+    QString iconName = KGlobal::instance()->iconLoader()->iconPath( mimeType->icon( QString(), false ), KIcon::Desktop );
+
+    htmlWriter()->queue( "<div><a href=\"" + href + "\"><img src=\"" +
+                          iconName + "\" border=\"0\" style=\"max-width: 100%\">" + label +
+                          "</a></div><br>" );
+  }
+
+  if ( !showOnlyOneMimePart() )
+    htmlWriter()->queue( "</td></tr></table>" );
+
+  return true;
+}
+
   void ObjectTreeParser::writeBodyString( const QCString & bodyString,
                                           const QString & fromAddress,
                                           const QTextCodec * codec,
--- branches/KDE/3.5/kdepim/kmail/objecttreeparser.h #650108:650109
@@ -2,7 +2,7 @@
     objecttreeparser.h
 
     This file is part of KMail, the KDE mail client.
-    Copyright (c) 2002-2003 Klar