--Boundary-00=_tZ6uA0cgcfqtKwq Content-Type: text/plain; charset="us-ascii"; boundary="" Content-Transfer-Encoding: 7bit Content-Disposition: inline (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 --Boundary-00=_tZ6uA0cgcfqtKwq Content-Type: text/x-diff; charset="us-ascii"; name="kmail-dont_merge_lines.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kmail-dont_merge_lines.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:
-	%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
     
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. */ --Boundary-00=_tZ6uA0cgcfqtKwq Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ KMail developers mailing list KMail-devel@kde.org https://mail.kde.org/mailman/listinfo/kmail-devel --Boundary-00=_tZ6uA0cgcfqtKwq--