libkdenetwork Library API Documentation

linklocator.cpp

00001 
00023 #include "linklocator.h"
00024 
00025 
00026 LinkLocator::LinkLocator(const QString& text, int pos)
00027   : mText(text), mPos(pos), mMaxUrlLen(4096), mMaxAddressLen(255)
00028 {
00029   // If you change either of the above values for maxUrlLen or
00030   // maxAddressLen, then please also update the documentation for
00031   // setMaxUrlLen()/setMaxAddressLen() in the header file AND the
00032   // default values used for the maxUrlLen/maxAddressLen parameters
00033   // of convertToHtml().
00034 }
00035 
00036 void LinkLocator::setMaxUrlLen(int length)
00037 {
00038   mMaxUrlLen = length;
00039 }
00040 
00041 int LinkLocator::maxUrlLen() const
00042 {
00043   return mMaxUrlLen;
00044 }
00045 
00046 void LinkLocator::setMaxAddressLen(int length)
00047 {
00048   mMaxAddressLen = length;
00049 }
00050 
00051 int LinkLocator::maxAddressLen() const
00052 {
00053   return mMaxAddressLen;
00054 }
00055 
00056 QString LinkLocator::getUrl()
00057 {
00058   QString url;
00059   if(atUrl())
00060   {
00061     // handle cases like this: <link>http://foobar.org/</link>
00062     int start = mPos;
00063     while(mPos < (int)mText.length() && mText[mPos] > ' ' && mText[mPos] != '"' &&
00064       QString("<>()[]").find(mText[mPos]) == -1)
00065     {
00066       ++mPos;
00067     }
00068     /* some URLs really end with:  # / &     */
00069     const QString allowedSpecialChars = QString("#/&");
00070     while(mPos > start && mText[mPos-1].isPunct() &&
00071             allowedSpecialChars.find(mText[mPos-1]) == -1 )
00072     {
00073       --mPos;
00074     }
00075 
00076     url = mText.mid(start, mPos - start);
00077     if(isEmptyUrl(url) || mPos - start > maxUrlLen())
00078     {
00079       mPos = start;
00080       url = "";
00081     }
00082     else
00083     {
00084       --mPos;
00085     }
00086   }
00087   return url;
00088 }
00089 
00090 // keep this in sync with KMMainWin::slotUrlClicked()
00091 bool LinkLocator::atUrl() const
00092 {
00093   // the following characters are allowed in a dot-atom (RFC 2822):
00094   // a-z A-Z 0-9 . ! # $ % & ' * + - / = ? ^ _ ` { | } ~
00095   const QString allowedSpecialChars = QString(".!#$%&'*+-/=?^_`{|}~");
00096 
00097   // the character directly before the URL must not be a letter, a number or
00098   // any other character allowed in a dot-atom (RFC 2822).
00099   if( ( mPos > 0 ) && ( mText[mPos-1].isLetterOrNumber() ||
00100                         ( allowedSpecialChars.find( mText[mPos-1] ) != -1 ) ) )
00101     return false;
00102 
00103   QChar ch = mText[mPos];
00104   return (ch=='h' && ( mText.mid(mPos, 7) == "http://" ||
00105                        mText.mid(mPos, 8) == "https://") ) ||
00106          (ch=='v' && mText.mid(mPos, 6) == "vnc://") ||
00107          (ch=='f' && ( mText.mid(mPos, 6) == "ftp://" ||
00108                        mText.mid(mPos, 7) == "ftps://") ) ||
00109          (ch=='s' && ( mText.mid(mPos, 7) == "sftp://" ||
00110                        mText.mid(mPos, 6) == "smb://") ) ||
00111          (ch=='m' && mText.mid(mPos, 7) == "mailto:") ||
00112          (ch=='w' && mText.mid(mPos, 4) == "www.") ||
00113          (ch=='f' && mText.mid(mPos, 4) == "ftp.");
00114          // note: no "file:" for security reasons
00115 }
00116 
00117 bool LinkLocator::isEmptyUrl(const QString& url)
00118 {
00119   return url.isEmpty() ||
00120          url == "http://" ||
00121          url == "https://" ||
00122          url == "ftp://" ||
00123          url == "ftps://" ||
00124          url == "sftp://" ||
00125          url == "smb://" ||
00126          url == "vnc://" ||
00127          url == "mailto" ||
00128          url == "www" ||
00129          url == "ftp";
00130 }
00131 
00132 QString LinkLocator::getEmailAddress()
00133 {
00134   QString address;
00135 
00136   if(mText[mPos] == '@')
00137   {
00138     // the following characters are allowed in a dot-atom (RFC 2822):
00139     // a-z A-Z 0-9 . ! # $ % & ' * + - / = ? ^ _ ` { | } ~
00140     const QString allowedSpecialChars = QString(".!#$%&'*+-/=?^_`{|}~");
00141 
00142     // determine the local part of the email address
00143     int start = mPos - 1;
00144     while (start >= 0 && mText[start].unicode() < 128 &&
00145       (mText[start].isLetterOrNumber() ||
00146         mText[start] == '@' || // allow @ to find invalid email addresses
00147         allowedSpecialChars.find(mText[start]) != -1))
00148     {
00149       --start;
00150     }
00151     ++start;
00152     // we assume that an email address starts with a letter or a digit
00153     while (allowedSpecialChars.find(mText[start]) != -1)
00154       ++start;
00155 
00156     // determine the domain part of the email address
00157     int end = mPos + 1;
00158     while (end < (int)mText.length() &&
00159       (mText[end].isLetterOrNumber() ||
00160         mText[end] == '@' || // allow @ to find invalid email addresses
00161         allowedSpecialChars.find(mText[end]) != -1))
00162     {
00163       ++end;
00164     }
00165     // we assume that an email address ends with a letter or a digit
00166     while (allowedSpecialChars.find(mText[end - 1]) != -1)
00167       --end;
00168 
00169     address = mText.mid(start, end - start);
00170     if(isEmptyAddress(address) || end - start > maxAddressLen() || address.contains('@') != 1)
00171       address = "";
00172 
00173     if(!address.isEmpty())
00174       mPos = end - 1;
00175   }
00176   return address;
00177 }
00178 
00179 bool LinkLocator::isEmptyAddress(const QString& address)
00180 {
00181   return address.isEmpty() ||
00182          address[0] == '@' ||
00183          address[address.length() - 1] == '@';
00184 }
00185 
00186 QString LinkLocator::convertToHtml(const QString& plainText, bool preserveBlanks,
00187   int maxUrlLen, int maxAddressLen)
00188 {
00189   LinkLocator locator(plainText);
00190   locator.setMaxUrlLen(maxUrlLen);
00191   locator.setMaxAddressLen(maxAddressLen);
00192 
00193   QString str;
00194   QString result((QChar*)0, (int)locator.mText.length() * 2);
00195   QChar ch;
00196   int x;
00197   bool startOfLine = true;
00198 
00199   for (locator.mPos = 0, x = 0; locator.mPos < (int)locator.mText.length(); locator.mPos++, x++)
00200   {
00201     ch = locator.mText[locator.mPos];
00202     if (preserveBlanks)
00203     {
00204       if (ch==' ')
00205       {
00206         if (startOfLine) {
00207           result += "&nbsp;";
00208           locator.mPos++, x++;
00209           startOfLine = false;
00210         }
00211         while (locator.mText[locator.mPos] == ' ')
00212         {
00213           result += " ";
00214           locator.mPos++, x++;
00215           if (locator.mText[locator.mPos] == ' ') {
00216             result += "&nbsp;";
00217             locator.mPos++, x++;
00218           }
00219         }
00220         locator.mPos--, x--;
00221         continue;
00222       }
00223       else if (ch=='\t')
00224       {
00225         do
00226         {
00227           result += "&nbsp;";
00228           x++;
00229         }
00230         while((x&7) != 0);
00231         x--;
00232         startOfLine = false;
00233         continue;
00234       }
00235     }
00236     if (ch=='\n')
00237     {
00238       result += "<br />";
00239       startOfLine = true;
00240       x = -1;
00241       continue;
00242     }
00243 
00244     startOfLine = false;
00245     if (ch=='&')
00246       result += "&amp;";
00247     else if (ch=='"')
00248       result += "&quot;";
00249     else if (ch=='<')
00250       result += "&lt;";
00251     else if (ch=='>')
00252       result += "&gt;";
00253     else
00254     {
00255       int start = locator.mPos;
00256       str = locator.getUrl();
00257       if(!str.isEmpty())
00258       {
00259         QString hyperlink;
00260         if(str.left(4) == "www.")
00261           hyperlink = "http://" + str;
00262         else if(str.left(4) == "ftp.")
00263           hyperlink = "ftp://" + str;
00264         else
00265           hyperlink = str;
00266 
00267     str = str.replace('&', "&amp;");
00268         result += "<a href=\"" + hyperlink + "\">" + str + "</a>";
00269         x += locator.mPos - start;
00270       }
00271       else
00272       {
00273         str = locator.getEmailAddress();
00274         if(!str.isEmpty())
00275         {
00276           // len is the length of the local part
00277           int len = str.find('@');
00278           QString localPart = str.left(len);
00279 
00280           // remove the local part from the result (as '&'s have been expanded to
00281           // &amp; we have to take care of the 4 additional characters per '&')
00282           result.truncate(result.length() - len - (localPart.contains('&')*4));
00283           x -= len;
00284 
00285           result += "<a href=\"mailto:" + str + "\">" + str + "</a>";
00286           x += str.length() - 1;
00287         }
00288         else
00289         {
00290           result += ch;
00291         }
00292       }
00293     }
00294   }
00295 
00296   return result;
00297 }
00298 
00299 
KDE Logo
This file is part of the documentation for libkdenetwork Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Aug 23 18:18:12 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003