/**
* linklocator.cpp
*
* Copyright (c) 2002 Dave Corrie <kde@davecorrie.com>
*
* This file is part of KMail.
*
* KMail is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "linklocator.h"
LinkLocator::LinkLocator(const QString& text, int pos)
: mText(text), mPos(pos), mMaxUrlLen(4096), mMaxAddressLen(255)
{
// If you change either of the above values for maxUrlLen or
// maxAddressLen, then please also update the documentation for
// setMaxUrlLen()/setMaxAddressLen() in the header file AND the
// default values used for the maxUrlLen/maxAddressLen parameters
// of convertToHtml().
}
void LinkLocator::setMaxUrlLen(int length)
{
mMaxUrlLen = length;
}
int LinkLocator::maxUrlLen() const
{
return mMaxUrlLen;
}
void LinkLocator::setMaxAddressLen(int length)
{
mMaxAddressLen = length;
}
int LinkLocator::maxAddressLen() const
{
return mMaxAddressLen;
}
QString LinkLocator::getUrl()
{
if ( !atUrl() )
return QString::null;
int start = mPos;
QString delimiters = QString::fromLatin1( "\"<>()[]" );
while ( mPos < static_cast<int>( mText.length() ) &&
mText[ mPos ] > ' ' &&
!delimiters.contains( mText[ mPos ] ) )
++mPos;
delimiters = QString::fromLatin1( "#/&" );
while ( mPos > start && mText[ mPos - 1 ].isPunct() &&
!delimiters.contains( mText[ mPos - 1 ] ) )
--mPos;
QString url = mText.mid( start, mPos - start );
if ( isEmptyUrl( url ) || mPos - start > maxUrlLen() ) {
mPos = start;
url = QString::fromLatin1( "" );
} else
--mPos;
return url;
}
bool LinkLocator::atUrl() const
{
QChar ch = mText[mPos];
return
(ch=='h' && mText.mid(mPos, 7) == QString::fromLatin1( "http://")) ||
(ch=='h' && mText.mid(mPos, 8) == QString::fromLatin1( "https://")) ||
(ch=='f' && mText.mid(mPos, 6) == QString::fromLatin1( "ftp://")) ||
(ch=='f' && mText.mid(mPos, 6) == QString::fromLatin1( "ftps://")) ||
(ch=='f' && mText.mid(mPos, 4) == QString::fromLatin1( "ftp." )) ||
(ch=='s' && mText.mid(mPos, 7) == QString::fromLatin1( "sftp://")) ||
(ch=='m' && mText.mid(mPos, 7) == QString::fromLatin1( "mailto:" )) ||
(ch=='w' && mText.mid(mPos, 4) == QString::fromLatin1( "www." ));
}
bool LinkLocator::isEmptyUrl(const QString& url)
{
return url.isEmpty() ||
url == QString::fromLatin1( "http://") ||
url == QString::fromLatin1( "https://") ||
url == QString::fromLatin1( "ftp://") ||
url == QString::fromLatin1( "ftps://") ||
url == QString::fromLatin1( "sftp://") ||
url == QString::fromLatin1( "mailto" ) ||
url == QString::fromLatin1( "www" ) ||
url == QString::fromLatin1( "ftp" );
}
QString LinkLocator::getEmailAddress()
{
QString address;
if(mText[mPos] == '@')
{
// the following characters are allowed in a dot-atom (RFC 2822):
// a-z A-Z 0-9 . ! # $ % & ' * + - / = ? ^ _ ` { | } ~
const QString allowedSpecialChars = QString(QString::fromLatin1( ".!#$%&'*+-/=?^_`{|}~") );
// determine the local part of the email address
int start = mPos - 1;
while (start >= 0 && mText[start].unicode() < 128 &&
(mText[start].isLetterOrNumber() ||
mText[start] == '@' || // allow @ to find invalid email addresses
allowedSpecialChars.find(mText[start]) != -1))
{
--start;
}
++start;
// we assume that an email address starts with a letter or a digit
while (allowedSpecialChars.find(mText[start]) != -1)
++start;
// determine the domain part of the email address
int end = mPos + 1;
while (end < (int)mText.length() && mText[end].unicode() < 128 &&
(mText[end].isLetterOrNumber() ||
mText[end] == '@' || // allow @ to find invalid email addresses
allowedSpecialChars.find(mText[end]) != -1))
{
++end;
}
// we assume that an email address ends with a letter or a digit
while (allowedSpecialChars.find(mText[end - 1]) != -1)
--end;
address = mText.mid(start, end - start);
if(isEmptyAddress(address) || end - start > maxAddressLen() || address.contains('@') != 1)
address = "";
if(!address.isEmpty())
mPos = end - 1;
}
return address;
}
bool LinkLocator::isEmptyAddress(const QString& address)
{
return address.isEmpty() ||
address[0] == '@' ||
address[address.length() - 1] == '@';
}
QString LinkLocator::convertToHtml(const QString& plainText, bool preserveBlanks,
int maxUrlLen, int maxAddressLen)
{
LinkLocator locator(plainText);
locator.setMaxUrlLen(maxUrlLen);
locator.setMaxAddressLen(maxAddressLen);
QString str;
QString result((QChar*)NULL, (int)locator.mText.length() * 2);
QChar ch;
int x;
bool startOfLine = true;
for (locator.mPos = 0, x = 0; locator.mPos < (int)locator.mText.length(); locator.mPos++, x++)
{
ch = locator.mText[locator.mPos];
if (preserveBlanks)
{
if (ch==' ')
{
if (startOfLine) {
result += QString::fromLatin1( " " );
locator.mPos++, x++;
startOfLine = false;
}
while (locator.mText[locator.mPos] == ' ')
{
result += QString::fromLatin1( " " );
locator.mPos++, x++;
if (locator.mText[locator.mPos] == ' ') {
result += QString::fromLatin1( " " );
locator.mPos++, x++;
}
}
locator.mPos--, x--;
continue;
}
else if (ch=='\t')
{
do
{
result += QString::fromLatin1( " " );
x++;
}
while((x&7) != 0);
x--;
startOfLine = false;
continue;
}
}
if (ch=='\n')
{
result += QString::fromLatin1( "<br />" );
startOfLine = true;
x = -1;
continue;
}
startOfLine = false;
if (ch=='&')
result += QString::fromLatin1( "&" );
else if (ch=='"')
result += QString::fromLatin1( """ );
else if (ch=='<')
result += QString::fromLatin1( "<" );
else if (ch=='>')
result += QString::fromLatin1( ">" );
else
{
int start = locator.mPos;
str = locator.getUrl();
if(!str.isEmpty())
{
QString hyperlink;
if(str.left(4) == QString::fromLatin1( "www." ))
hyperlink = QString::fromLatin1( "http://") + str;
else if(str.left(4) == QString::fromLatin1( "ftp." ))
hyperlink = QString::fromLatin1( "ftp://") + str;
else
hyperlink = str;
result += QString::fromLatin1( "<a href=\"" ) + hyperlink +
QString::fromLatin1( "\">" ) + str + QString::fromLatin1( "</a>" );
x += locator.mPos - start;
}
else
{
str = locator.getEmailAddress();
if(!str.isEmpty())
{
// len is the length of the local part
int len = str.find('@');
QString localPart = str.left(len);
// remove the local part from the result (as '&'s have been expanded to
// & we have to take care of the 4 additional characters per '&')
result.truncate(result.length() - len - (localPart.contains('&')*4));
x -= len;
result += QString::fromLatin1( "<a href=\"mailto:" ) + str +
QString::fromLatin1( "\">" ) + str + QString::fromLatin1( "</a>" );
x += str.length() - 1;
}
else
{
result += ch;
}
}
}
}
return result;
}
syntax highlighted by Code2HTML, v. 0.9.1