[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kmail-devel
Subject:    [PATCH] Don't merge lines when smart quoting mails without user
From:       Martijn Klingens <klingens () kde ! org>
Date:       2004-05-31 21:41:01
Message-ID: 200405312341.01632.klingens () kde ! org
[Download RAW message or body]

(Quite a long subject :)

Attached patch suppresses the merging of lines when smart quoting mails that 
don't have a user agent set. The reason is that those often contain stuff 
that becomes unreadable when using the current quoting algorithm.

For a testcase, just run 'head /var/log/messages | mail your@email.address' 
and hit the reply button. For such mails it's absolutely required that the 
date doesn't end up halfway a line due to merging.

There is a workaround already in KMail, which is disabling smart quoting. That 
workaround however is almost worse than the problem it addresses:

1. You end up with very long lines that get wordwrapped by QTextEdit. This has
   a tendency to get very slow easily because the widget isn't that well
   suited to very long paragraphs.

2. Only the start of a paragraph rather than a line is quoted. This results in
   replies looking line

   > This is the start of a very long paragraph. When the line is wrapped all
   subsequent lines are not prefixed with the '> ' indent string and thus
   look really awkward.
   > The next paragraph then starts with a quoting sign again. No need to
   explain that this is really annoying I guess :)

3. It is a global option, so no mail is smart quoted at all anymore. This is
   the worst when replying to the Outlook crowd, who tend to send very wide
   lines that suffer from #1 and #2 as well.

Ingo mentioned a valid argument AGAINST my patch on IRC that needs some 
thought and discussion, because there's no perfect solution AFAICS: some 
generated mails don't have a User-Agent/X-Mailer set either, but can be smart 
quoted the normal way perfectly well. The best examples for KDE are mailman 
messages and Bugzilla mails.

However, in the case of Bugzilla mails the feature is a double-edged sword, 
because those also often contain console output and backtraces that would 
benefit from my patch.

Ingo just mentioned that a lot of mail on e.g. kde-devel also has no such 
header, so apparently webmailers and such don't set it. That's of course a 
major setback, because it would make it impossible to commit the patch as is. 
The only counter-argument is that my above example in #2 would look with my
patch like

   > This is the start of a very long paragraph. When the line is wrapped all
   > subsequent lines are not prefixed with the '> ' indent string and thus
   > look really awkward.
   > The next paragraph then starts with a quoting sign again. No need to
   > explain that this is really annoying I guess :)

and with the normal algorithm like

   > This is the start of a very long paragraph. When the line is wrapped all
   > subsequent lines are not prefixed with the '> ' indent string and thus
   > look really awkward. The next paragraph then starts with a quoting sign
   > again. No need to explain that this is really annoying I guess :)

I personally think it's an acceptable loss, but I'm not convinced others are 
equally minded. I can already imagine people filing Bugzilla reports if the 
smart quoting breaks occasionally. :(

Suggestions on how to proceed next are welcome, because I've tried to live 
with this situation for over a year now and I'm getting sick of it, so I 
absolutely want a KMail that allows me to reply to syslog mail :)

In the case the patch is rejected and no suitable solution is found then at 
least it's archived here for those brave enough to build from a locally 
patched source...

-- 
Martijn

["kmail-dont_merge_lines.diff" (text/x-diff)]

Index: kmmessage.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/kmmessage.cpp,v
retrieving revision 1.470
diff -u -p -r1.470 kmmessage.cpp
--- kmmessage.cpp	25 May 2004 09:46:21 -0000	1.470
+++ kmmessage.cpp	31 May 2004 21:15:11 -0000
@@ -527,8 +527,9 @@ static QString flowText(QString &text, c
    }
 }
 
-static bool flushPart(QString &msg, QStringList &part,
-                      const QString &indent, int maxLength)
+static bool flushPart( QString &msg, QStringList &part,
+                       const QString &indent, int maxLength,
+                       KMMessage::NewlineMode newlineMode )
 {
    maxLength -= indent.length();
    if (maxLength < 20) maxLength = 20;
@@ -554,13 +555,17 @@ static bool flushPart(QString &msg, QStr
       }
       else
       {
-         if (text.isEmpty())
+         if ( newlineMode == KMMessage::NewlineEndsParagraph || text.isEmpty())
             text = line;
          else
             text += ' '+line.stripWhiteSpace();
 
-         if (((int) text.length() < maxLength) || ((int) line.length() < (maxLength-10)))
-            msg += flowText(text, indent, maxLength);
+         if ( ( newlineMode == KMMessage::NewlineEndsParagraph ) ||
+              ( int( text.length() ) < maxLength ) ||
+              ( int( line.length() ) < ( maxLength - 10 ) ) ) {
+            msg += flowText( text, indent, maxLength );
+            text = QString::null;
+         }
       }
    }
    if (!text.isEmpty())
@@ -581,7 +586,8 @@ static QString stripSignature( const QSt
     return msg.left( msg.findRev( "\n-- \n" ) );
 }
 
-static QString smartQuote( const QString & msg, int maxLength )
+static QString smartQuote( const QString &msg, int maxLength,
+                           KMMessage::NewlineMode newlineMode )
 {
   QStringList part;
   QString oldIndent;
@@ -628,7 +634,7 @@ static QString smartQuote( const QString
               part.remove(it2);
            }
         }
-        if (flushPart( result, part, oldIndent, maxLength))
+        if ( flushPart( result, part, oldIndent, maxLength, newlineMode ) )
         {
            if (oldIndent.length() > indent.length())
               result += indent + '\n';
@@ -643,7 +649,7 @@ static QString smartQuote( const QString
      }
      part.append(line);
   }
-  flushPart( result, part, oldIndent, maxLength);
+  flushPart( result, part, oldIndent, maxLength, newlineMode );
   return result;
 }
 
@@ -755,10 +761,12 @@ QString KMMessage::asPlainText( bool aSt
 }
 
 QString KMMessage::asQuotedString( const QString& aHeaderStr,
-				   const QString& aIndentStr,
-				   const QString& selection /* = QString::null */,
-				   bool aStripSignature /* = true */,
-				   bool allowDecryption /* = true */) const
+                                   const QString& aIndentStr,
+                                   const QString& selection /* = QString::null */,
+                                   bool aStripSignature /* = true */,
+                                   bool allowDecryption /* = true */,
+                                   NewlineMode aNewlineMode /* = NewlineIsLineBreak */
+                                 ) const
 {
   QString content = selection.isEmpty() ?
     asPlainText( aStripSignature, allowDecryption ) : selection ;
@@ -777,7 +785,7 @@ QString KMMessage::asQuotedString( const
 
   const QString headerStr = formatString( aHeaderStr );
   if ( sSmartQuote && sWordWrap )
-    return headerStr + smartQuote( content, sWrapCol );
+    return headerStr + smartQuote( content, sWrapCol, aNewlineMode );
   else
     return headerStr + content;
 }
@@ -1038,9 +1046,18 @@ KMMessage* KMMessage::createReply( KMail
     if( selectionIsBody ){
       QCString cStr = selection.latin1();
       msg->setBody( cStr );
-    }else{
-      msg->setBody(asQuotedString(replyStr + "\n", sIndentPrefixStr, selection,
-				  sSmartQuote, allowDecryption).utf8());
+    } else {
+      // If there's no mailer specified we assume the mail was send by an
+      // automated process. In this case it's often undesirable to merge
+      // multiple lines, so we set the NewlineMode accordingly.
+      NewlineMode newlineMode;
+      if ( !headerField( "User-Agent" ).isEmpty() || !headerField( "X-Mailer" ).isEmpty() )
+        newlineMode = NewlineIsLineBreak;
+      else
+        newlineMode = NewlineEndsParagraph;
+
+      msg->setBody( asQuotedString( replyStr + "\n", sIndentPrefixStr, selection,
+                    sSmartQuote, allowDecryption, newlineMode ).utf8() );
     }
   }
 
@@ -1103,7 +1120,13 @@ KMMessage* KMMessage::createRedirect()
   /// ###        as the original message
   /// ### FIXME: ??Add some Resent-* headers?? (c.f. RFC2822 3.6.6)
 
-  QString st = asQuotedString("", "", QString::null, false, false);
+  NewlineMode newlineMode;
+  if ( !headerField( "User-Agent" ).isEmpty() || !headerField( "X-Mailer" ).isEmpty() )
+    newlineMode = NewlineIsLineBreak;
+  else
+    newlineMode = NewlineEndsParagraph;
+
+  QString st = asQuotedString( "", "", QString::null, false, false, newlineMode );
   QCString encoding = autoDetectCharset(charset(), sPrefCharsets, st);
   if (encoding.isEmpty()) encoding = "utf-8";
   QCString str = codecForName(encoding)->fromUnicode(st);
@@ -1228,10 +1251,16 @@ QCString KMMessage::createForwardBody()
   QString s;
   QCString str;
 
+  NewlineMode newlineMode;
+  if ( !headerField( "User-Agent" ).isEmpty() || !headerField( "X-Mailer" ).isEmpty() )
+    newlineMode = NewlineIsLineBreak;
+  else
+    newlineMode = NewlineEndsParagraph;
+
   if (sHeaderStrategy == HeaderStrategy::all()) {
     s = "\n\n----------  " + sForwardStr + "  ----------\n\n";
     s += headerAsString();
-    str = asQuotedString(s, "", QString::null, false, false).utf8();
+    str = asQuotedString( s, "", QString::null, false, false, newlineMode ).utf8();
     str += "\n-------------------------------------------------------\n";
   } else {
     s = "\n\n----------  " + sForwardStr + "  ----------\n\n";
@@ -1244,7 +1273,7 @@ QCString KMMessage::createForwardBody()
     s += "To: " + to() + "\n";
     if (!cc().isEmpty()) s += "Cc: " + cc() + "\n";
     s += "\n";
-    str = asQuotedString(s, "", QString::null, false, false).utf8();
+    str = asQuotedString( s, "", QString::null, false, false, newlineMode ).utf8();
     str += "\n-------------------------------------------------------\n";
   }
 
Index: kmmessage.h
===================================================================
RCS file: /home/kde/kdepim/kmail/kmmessage.h,v
retrieving revision 1.167
diff -u -p -r1.167 kmmessage.h
--- kmmessage.h	23 May 2004 22:02:25 -0000	1.167
+++ kmmessage.h	31 May 2004 21:15:11 -0000
@@ -860,6 +860,18 @@ public:
 
   void updateAttachmentState(DwBodyPart * part = 0);
 
+  /** Determine how to treat newlines when quoting mail in
+    @ref asQuotedString.
+
+    NewlineIsLineBreak   - Single newlines are treated as line breaks
+                           inserted by the sending MUA and are stripped
+                           off before quoting. A paragraph is ended by
+                           a double newline in this mode. This is the
+                           default setting and is what KMail 3.2 and
+                           before did when smart quoting.
+    NewlineEndsParagraph - A newline is considered a paragraph ending. */
+  enum NewlineMode { NewlineIsLineBreak = 0, NewlineEndsParagraph };
+
 private:
   /** Returns message body with quoting header and indented by the
     given indentation string. This is suitable for including the message
@@ -867,20 +879,26 @@ private:
     a template where the following fields are replaced with the
     corresponding values:
     <pre>
-	%D: date of this message
-	%S: subject of this message
-	%F: sender (from) of this message
-	%%: a single percent sign
+        %D: date of this message
+        %S: subject of this message
+        %F: sender (from) of this message
+        %%: a single percent sign
     </pre>
     No attachments are handled if includeAttach is false.
     The signature is stripped if aStripSignature is true and
     smart quoting is turned on. Signed or encrypted texts
-    get converted to plain text when allowDecryption is true. */
-  QString asQuotedString( const QString & headerStr,
-			  const QString & indentStr,
-			  const QString & selection=QString::null,
-			  bool aStripSignature=true,
-			  bool allowDecryption=true) const;
+    get converted to plain text when allowDecryption is true.
+
+    If aNewlineMode is set to NewlineEndsParagraph the quoting
+    algorithm will never join lines on newline. This is useful
+    when the original mail is automatically generated (like
+    'cat /var/log/messages | mail joe@company.com'). */
+  QString asQuotedString( const QString &headerStr,
+                          const QString &indentStr,
+                          const QString &selection = QString::null,
+                          bool aStripSignature = true,
+                          bool allowDecryption = true,
+                          NewlineMode aNewlineMode = NewlineIsLineBreak ) const;
 
   /** Return the textual content of the message as plain text,
       converting HTML to plain text if necessary. */


_______________________________________________
KMail developers mailing list
KMail-devel@kde.org
https://mail.kde.org/mailman/listinfo/kmail-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic