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

List:       kmail-devel
Subject:    [RFC] How to handle URLs in KMail
From:       Ingo =?utf-8?q?Kl=C3=B6cker?= <kloecker () kde ! org>
Date:       2002-09-29 23:23:54
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


Hi,

the way we currently handle URLs in KMail is at best completely broken. 
Most of the time the mailto: URLs which we generate work correctly. But 
this is because we all have latin1-encodable names. The URLs break when 
the email addresses (or other URLs) contain characters which have a 
special meaning in URLs like '#' or '%' 
(http://bugs.kde.org/show_bug.cgi?id=47981). Furthermore they don't 
work at all with non-latin1-encoded names.

To make this work correctly we have to encode the email addresses (and 
also attachment filenames). Unfortunately KURL::encode_string doesn't 
help since this first converts a unicode string to local encoding. 
Obviously this will destroy all characters which don't appear in the 
local encoding. Therefore I introduced two static functions to encode 
and decode from Unicode to URLs (this is more or less a proof of 
concept and no finished patch):

QString KMMessage::encodeUrl( const QString& str )
{
  return KURL::encode_string( QString::fromLatin1( str.utf8() ) );
}

QString KMMessage::decodeUrl( const QString& url )
{
  return QString::fromUtf8( KURL::decode_string( url ).latin1() ); 
}

This works if the local encoding is latin1. But it might not work when 
the local encoding is not latin1 because then all latin1 characters 
which are not contained in the local encoding will be lost during 
encodeUrl.

So we have to come up with a better solution for encoding arbitrary 
Unicode strings as URLs. Does anybody know which RFC deals with this 
and whether we already have a corresponding codec in kdelibs or 
whereever?

The attached patch makes it possible to do almost everything with 
Cyrillic and Chinese (and all other Unicode) email address which 
currently only works for latin1 email addresses. The following things 
work:
- Click on email address to get a new message.
- RMB->Send To...
- RMB->Send Reply To...
- RMB->Forward To...
- RMB->Add to Address Book
- RMB->Copy to Clipboard

For some reason RMB->Open in Address Book doesn't work.

To test this you can e. g. look for the message 立兰 谷 send to this 
mailing list on 26 August 2002, 02:51.

Regards,
Ingo


["encode_decode_urls.diff" (text/x-diff)]

Index: kmcommands.cpp
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmcommands.cpp,v
retrieving revision 1.9
diff -u -3 -p -r1.9 kmcommands.cpp
--- kmcommands.cpp	2002/09/17 16:44:25	1.9
+++ kmcommands.cpp	2002/09/29 22:22:34
@@ -288,7 +288,7 @@ void KMMailtoComposeCommand::execute()
 
   msg->initHeader(id);
   msg->setCharset("utf-8");
-  msg->setTo(mUrl.path());
+  msg->setTo( KMMessage::decodeUrl( mUrl.path() ) );
 
   win = new KMComposeWin(msg, id);
   win->setCharset("", TRUE);
@@ -308,7 +308,7 @@ void KMMailtoReplyCommand::execute()
   KMMessage *msg = retrievedMessage();
   KMComposeWin *win;
   KMMessage *rmsg = msg->createReply(FALSE, FALSE, mSelection );
-  rmsg->setTo(mUrl.path());
+  rmsg->setTo( KMMessage::decodeUrl( mUrl.path() ) );
 
 #ifdef IDENTITY_UOIDs
   win = new KMComposeWin(rmsg, 0);
@@ -333,7 +333,7 @@ void KMMailtoForwardCommand::execute()
   KMMessage *msg = retrievedMessage();
   KMComposeWin *win;
   KMMessage *fmsg = msg->createForward();
-  fmsg->setTo(mUrl.path());
+  fmsg->setTo( KMMessage::decodeUrl( mUrl.path() ) );
 
   win = new KMComposeWin(fmsg);
   win->setCharset(msg->codec()->mimeName(), TRUE);
@@ -349,7 +349,7 @@ KMMailtoAddAddrBookCommand::KMMailtoAddA
 
 void KMMailtoAddAddrBookCommand::execute()
 {
-  KMAddrBookExternal::addEmail(mUrl.path(), mParent );
+  KMAddrBookExternal::addEmail( KMMessage::decodeUrl( mUrl.path() ), mParent );
 }
 
 
@@ -361,7 +361,7 @@ KMMailtoOpenAddrBookCommand::KMMailtoOpe
 
 void KMMailtoOpenAddrBookCommand::execute()
 {
-  KMAddrBookExternal::openEmail(mUrl.path(), mParent );
+  KMAddrBookExternal::openEmail( KMMessage::decodeUrl( mUrl.path() ), mParent );
 }
 
 
@@ -377,9 +377,9 @@ void KMUrlCopyCommand::execute()
   if (mUrl.protocol() == "mailto") {
     // put the url into the mouse selection and the clipboard
     clip->setSelectionMode( true );
-    clip->setText( mUrl.path() );
+    clip->setText( KMMessage::decodeUrl( mUrl.path() ) );
     clip->setSelectionMode( false );
-    clip->setText( mUrl.path() );
+    clip->setText( KMMessage::decodeUrl( mUrl.path() ) );
     if (mMainWin)
       mMainWin->statusMsg( i18n( "Address copied to clipboard." ));
   } else {
@@ -1200,7 +1200,7 @@ void KMUrlClickedCommand::execute()
     msg = new KMMessage;
     msg->initHeader(id);
     msg->setCharset("utf-8");
-    msg->setTo(mUrl.path());
+    msg->setTo( KMMessage::decodeUrl( mUrl.path() ) );
     QString query=mUrl.query();
     while (!query.isEmpty()) {
       QString queryPart;
Index: kmmessage.cpp
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmmessage.cpp,v
retrieving revision 1.324
diff -u -3 -p -r1.324 kmmessage.cpp
--- kmmessage.cpp	2002/09/24 07:47:36	1.324
+++ kmmessage.cpp	2002/09/29 22:22:44
@@ -24,6 +24,7 @@
 #include <kapplication.h>
 #include <kglobalsettings.h>
 #include <khtml_part.h>
+#include <kurl.h>
 #include <qcursor.h>
 
 // we need access to the protected member DwBody::DeleteBodyParts()...
@@ -2649,6 +2650,20 @@ QCString KMMessage::lf2crlf( const QCStr
 
 
 //-----------------------------------------------------------------------------
+QString KMMessage::encodeUrl( const QString& str )
+{
+  return KURL::encode_string( QString::fromLatin1( str.utf8() ) );
+}
+
+
+//-----------------------------------------------------------------------------
+QString KMMessage::decodeUrl( const QString& url )
+{
+  return QString::fromUtf8( KURL::decode_string( url ).latin1() ); 
+}
+
+
+//-----------------------------------------------------------------------------
 QString KMMessage::stripEmailAddr(const QString& aStr)
 {
   QStringList list = splitEmailAddrList(aStr);
@@ -2746,7 +2761,7 @@ QString KMMessage::emailAddrAsAnchor(con
 
     if ((ch == ',' && !insideQuote) || pos + 1 >= email.length())
     {
-      result += addr;
+      result += KMMessage::encodeUrl( tmp2 );
       result += "'>";
       if (stripped) result += KMMessage::stripEmailAddr(tmp2);
       else result += addr;
@@ -2761,6 +2776,8 @@ QString KMMessage::emailAddrAsAnchor(con
     }
   }
   result = result.replace(QRegExp("\n"),"");
+  kdDebug(5006) << "KMMessage::emailAddrAsAnchor('" << aEmail
+                << "') returns:\n-->" << result << "<--" << endl;
   return result;
 }
 
Index: kmmessage.h
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmmessage.h,v
retrieving revision 1.103
diff -u -3 -p -r1.103 kmmessage.h
--- kmmessage.h	2002/09/23 12:52:04	1.103
+++ kmmessage.h	2002/09/29 22:22:45
@@ -445,6 +445,14 @@ public:
    */
   static QCString lf2crlf( const QCString & src );
 
+  /** Converts a unicode string in an encoded URL
+   */
+  static QString encodeUrl( const QString& str );
+
+  /** Converts an encoded URL in a unicode string
+   */
+  static QString decodeUrl( const QString& url );
+
   /** Strip email address from string. Examples:
    * "Stefan Taferner <taferner@kde.org>" returns "Stefan Taferner"
    * "joe@nowhere.com" returns "joe@nowhere.com". Note that this only
Index: kmreaderwin.cpp
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmreaderwin.cpp,v
retrieving revision 1.566
diff -u -3 -p -r1.566 kmreaderwin.cpp
--- kmreaderwin.cpp	2002/09/29 10:58:01	1.566
+++ kmreaderwin.cpp	2002/09/29 22:22:50
@@ -3366,18 +3366,21 @@ QString KMReaderWin::writeMsgHeader(KMMe
 			     strToHtml(aMsg->subject()));
 
     // from line
-    headerStr.append(QString("<tr><th class=\"fancyHeaderDtls\">%1</th><td \
                class=\"fancyHeaderDtls\">%2%3%4</td></tr>")
-                            .arg(i18n("From: "))
-                            .arg(KMMessage::emailAddrAsAnchor(aMsg->from(),FALSE))
-                            .arg(hasVCard ?
-                                 "&nbsp;&nbsp;<a \
                href=\""+vcname+"\">"+i18n("[vCard]")+"</a>"
-                                 : "")
-                            .arg((aMsg->headerField("Organization").isEmpty()) ?
-                                 ""
-                                 : "&nbsp;&nbsp;(" +
-                                   strToHtml(aMsg->headerField("Organization")) +
-                                   ")"));
-
+    // the mailto: URLs can contain %3 etc., therefore usage of multiple
+    // QString::arg is not possible
+    headerStr += QString("<tr><th class=\"fancyHeaderDtls\">%1</th>"
+                         "<td class=\"fancyHeaderDtls\">")
+                         .arg(i18n("From: "))
+                 + KMMessage::emailAddrAsAnchor(aMsg->from(),FALSE)
+                 + ( hasVCard ? "&nbsp;&nbsp;<a href=\""+vcname+"\">"
+                                + i18n("[vCard]") + "</a>"
+                              : "" )
+                 + ( aMsg->headerField("Organization").isEmpty()
+                              ? ""
+                              : "&nbsp;&nbsp;("
+                                + strToHtml(aMsg->headerField("Organization"))
+                                + ")")
+                 + "</td></tr>";
     // to line
     headerStr.append(QString("<tr><th class=\"fancyHeaderDtls\">%1</th><td \
                class=\"fancyHeaderDtls\">%2</td></tr>")
                             .arg(i18n("To: "))
@@ -4538,7 +4541,7 @@ void KMReaderWin::slotUrlOn(const QStrin
     bOk = true;
   }
   if( !bOk )
-    emit statusMsg(aUrl);
+    emit statusMsg( KMMessage::decodeUrl( aUrl ) );
 }
 
 


[Attachment #6 (application/pgp-signature)]
_______________________________________________
KMail Developers mailing list
kmail@mail.kde.org
http://mail.kde.org/mailman/listinfo/kmail

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

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