You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

444 lines
12 KiB

// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
#include "mailinglist-magic.h"
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kurl.h>
#include <kdebug.h>
#include <QStringList>
#include <QByteArray>
#include <boost/shared_ptr.hpp>
using namespace KMail;
typedef QString (*MagicDetectorFunc) (const KMime::Message::Ptr &, QByteArray &, QString &);
/* Sender: (owner-([^@]+)|([^@+]-owner)@ */
static QString check_sender( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->sender()->asUnicodeString();
if ( header.isEmpty() )
return QString();
if ( header.left( 6 ) == "owner-" )
{
header_name = "Sender";
header_value = header;
header = header.mid( 6, header.indexOf( '@' ) - 6 );
} else {
int index = header.indexOf( "-owner@ " );
if ( index == -1 )
return QString();
header.truncate( index );
header_name = "Sender";
header_value = header;
}
return header;
}
/* X-BeenThere: ([^@]+) */
static QString check_x_beenthere( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "X-BeenThere" ) ?message->headerByType( "X-BeenThere" )->asUnicodeString() : "";
if ( header.isNull() || header.indexOf( '@' ) == -1 )
return QString();
header_name = "X-BeenThere";
header_value = header;
header.truncate( header.indexOf( '@' ) );
return header;
}
/* Delivered-To:: <([^@]+) */
static QString check_delivered_to( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "Delivered-To" ) ?message->headerByType( "Delivered-To" )->asUnicodeString() : "";
if ( header.isNull() || header.left(13 ) != "mailing list"
|| header.indexOf( '@' ) == -1 )
return QString();
header_name = "Delivered-To";
header_value = header;
return header.mid( 13, header.indexOf( '@' ) - 13 );
}
/* X-Mailing-List: <?([^@]+) */
static QString check_x_mailing_list( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "X-Mailing-List" ) ?message->headerByType( "X-Mailing-List" )->asUnicodeString() : "";
if ( header.isEmpty() )
return QString();
if ( header.indexOf( '@' ) < 1 )
return QString();
header_name = "X-Mailing-List";
header_value = header;
if ( header[0] == '<' )
header = header.mid(1, header.indexOf( '@' ) - 1);
else
header.truncate( header.indexOf( '@' ) );
return header;
}
/* List-Id: [^<]* <([^.]+) */
static QString check_list_id( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
int lAnglePos, firstDotPos;
QString header = message->headerByType( "List-Id" ) ?message->headerByType( "List-Id" )->asUnicodeString() : "";
if ( header.isEmpty() )
return QString();
lAnglePos = header.indexOf( '<' );
if ( lAnglePos < 0 )
return QString();
firstDotPos = header.indexOf( '.', lAnglePos );
if ( firstDotPos < 0 )
return QString();
header_name = "List-Id";
header_value = header.mid( lAnglePos );
header = header.mid( lAnglePos + 1, firstDotPos - lAnglePos - 1 );
return header;
}
/* List-Post: <mailto:[^< ]*>) */
static QString check_list_post( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "List-Post" ) ?message->headerByType( "List-Post" )->asUnicodeString() : "";
if ( header.isEmpty() )
return QString();
int lAnglePos = header.indexOf( "<mailto:" );
if ( lAnglePos < 0 )
return QString();
header_name = "List-Post";
header_value = header;
header = header.mid( lAnglePos + 8, header.length());
header.truncate( header.indexOf('@') );
return header;
}
/* Mailing-List: list ([^@]+) */
static QString check_mailing_list( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "Mailing-List" ) ?message->headerByType( "Mailing-List" )->asUnicodeString() : "";
if ( header.isEmpty() )
return QString();
if (header.left( 5 ) != "list " || header.indexOf( '@' ) < 5 )
return QString();
header_name = "Mailing-List";
header_value = header;
header = header.mid(5, header.indexOf( '@' ) - 5);
return header;
}
/* X-Loop: ([^@]+) */
static QString check_x_loop( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "X-Loop" ) ?message->headerByType( "X-Loop" )->asUnicodeString() : "";
if ( header.isEmpty() )
return QString();
if (header.indexOf( '@' ) < 2 )
return QString();
header_name = "X-Loop";
header_value = header;
header.truncate(header.indexOf( '@' ));
return header;
}
/* X-ML-Name: (.+) */
static QString check_x_ml_name( const KMime::Message::Ptr &message,
QByteArray &header_name,
QString &header_value )
{
QString header = message->headerByType( "X-ML-Name" ) ?message->headerByType( "X-ML-Name" )->asUnicodeString() : "";
if ( header.isEmpty() )
return QString();
header_name = "X-ML-Name";
header_value = header;
header.truncate(header.indexOf( '@' ));
return header;
}
MagicDetectorFunc magic_detector[] =
{
check_list_id,
check_list_post,
check_sender,
check_x_mailing_list,
check_mailing_list,
check_delivered_to,
check_x_beenthere,
check_x_loop,
check_x_ml_name
};
static const int num_detectors = sizeof (magic_detector) / sizeof (magic_detector[0]);
static QStringList
headerToAddress( const QString& header )
{
QStringList addr;
int start = 0;
int end = 0;
if ( header.isEmpty() )
return addr;
while ( (start = header.indexOf( "<", start )) != -1 ) {
if ( (end = header.indexOf( ">", ++start ) ) == -1 ) {
kDebug()<<"Serious mailing list header parsing error !";
return addr;
}
//kDebug()<<"Mailing list ="<<header.mid( start, end - start );
addr.append( header.mid( start, end - start ) );
}
return addr;
}
MailingList
MailingList::detect( const KMime::Message::Ptr &message )
{
MailingList mlist;
mlist.setPostURLS( headerToAddress(
message->headerByType( "List-Post" ) ? message->headerByType( "List-Post" )->asUnicodeString() : "" ) );
mlist.setHelpURLS( headerToAddress(
message->headerByType( "List-Help" ) ? message->headerByType( "List-Help" )->asUnicodeString() : "" ) );
mlist.setSubscribeURLS( headerToAddress(
message->headerByType( "List-Subscribe" ) ? message->headerByType( "List-Subscribe" )->asUnicodeString() : ""));
mlist.setUnsubscribeURLS( headerToAddress(
message->headerByType( "List-Unsubscribe" ) ? message->headerByType( "List-Unsubscribe" )->asUnicodeString() : ""));
mlist.setArchiveURLS( headerToAddress(
message->headerByType( "List-Arhive" ) ? message->headerByType( "List-Archive" )->asUnicodeString() : "" ) );
mlist.setOwnerURLS( headerToAddress(
message->headerByType( "List-Owner" ) ? message->headerByType( "List-Owner" )->asUnicodeString() : "" ) );
mlist.setArchivedAt( message->headerByType( "Archived-At" ) ? message->headerByType( "Archived-At" )->asUnicodeString() : "" );
mlist.setId( message->headerByType( "List-Id" ) ? message->headerByType( "List-Id" )->asUnicodeString() : "" );
return mlist;
}
QString
MailingList::name( const KMime::Message::Ptr &message, QByteArray &header_name,
QString &header_value )
{
QString mlist;
header_name = QByteArray();
header_value.clear();
if ( !message )
return QString();
for (int i = 0; i < num_detectors; i++) {
mlist = magic_detector[i] (message, header_name, header_value);
if ( !mlist.isNull() )
return mlist;
}
return QString();
}
MailingList::MailingList()
: mFeatures( None ), mHandler( KMail )
{
}
int MailingList::features() const
{
return mFeatures;
}
void MailingList::setHandler( MailingList::Handler han )
{
mHandler = han;
}
MailingList::Handler MailingList::handler() const
{
return mHandler;
}
void MailingList::setPostURLS ( const KUrl::List& lst )
{
mFeatures |= Post;
if ( lst.empty() ) {
mFeatures ^= Post;
}
mPostURLS = lst;
}
KUrl::List MailingList::postURLS() const
{
return mPostURLS;
}
void MailingList::setSubscribeURLS( const KUrl::List& lst )
{
mFeatures |= Subscribe;
if ( lst.empty() ) {
mFeatures ^= Subscribe;
}
mSubscribeURLS = lst;
}
KUrl::List MailingList::subscribeURLS() const
{
return mSubscribeURLS;
}
void MailingList::setUnsubscribeURLS( const KUrl::List& lst )
{
mFeatures |= Unsubscribe;
if ( lst.empty() ) {
mFeatures ^= Unsubscribe;
}
mUnsubscribeURLS = lst;
}
KUrl::List MailingList::unsubscribeURLS() const
{
return mUnsubscribeURLS;
}
void MailingList::setHelpURLS( const KUrl::List& lst )
{
mFeatures |= Help;
if ( lst.empty() ) {
mFeatures ^= Help;
}
mHelpURLS = lst;
}
KUrl::List MailingList::helpURLS() const
{
return mHelpURLS;
}
void MailingList::setArchiveURLS( const KUrl::List& lst )
{
mFeatures |= Archive;
if ( lst.empty() ) {
mFeatures ^= Archive;
}
mArchiveURLS = lst;
}
KUrl::List MailingList::archiveURLS() const
{
return mArchiveURLS;
}
void MailingList::setOwnerURLS( const KUrl::List& lst )
{
mFeatures |= Owner;
if ( lst.empty() ) {
mFeatures ^= Owner;
}
mOwnerURLS = lst;
}
KUrl::List MailingList::ownerURLS() const
{
return mOwnerURLS;
}
void MailingList::setArchivedAt( const QString& str )
{
mFeatures |= ArchivedAt;
if ( str.isEmpty() ) {
mFeatures ^= ArchivedAt;
}
mArchivedAt = str;
}
QString MailingList::archivedAt() const
{
return mArchivedAt;
}
void MailingList::setId( const QString& str )
{
mFeatures |= Id;
if ( str.isEmpty() ) {
mFeatures ^= Id;
}
mId = str;
}
QString MailingList::id() const
{
return mId;
}
void MailingList::writeConfig( KConfigGroup & config ) const
{
config.writeEntry( "MailingListFeatures", mFeatures );
config.writeEntry( "MailingListHandler", (int)mHandler );
config.writeEntry( "MailingListId", mId );
config.writeEntry( "MailingListPostingAddress", mPostURLS.toStringList() );
config.writeEntry( "MailingListSubscribeAddress", mSubscribeURLS.toStringList() );
config.writeEntry( "MailingListUnsubscribeAddress", mUnsubscribeURLS.toStringList() );
config.writeEntry( "MailingListArchiveAddress", mArchiveURLS.toStringList() );
config.writeEntry( "MailingListOwnerAddress", mOwnerURLS.toStringList() );
config.writeEntry( "MailingListHelpAddress", mHelpURLS.toStringList() );
/* Note: mArchivedAt deliberately not saved here as it refers to a single
* instance of a message rather than an element of a general mailing list.
* http://reviewboard.kde.org/r/1768/#review2783
*/
}
void MailingList::readConfig( KConfigGroup & config )
{
mFeatures = config.readEntry( "MailingListFeatures", 0 );
mHandler = static_cast<MailingList::Handler>(
config.readEntry( "MailingListHandler", (int)MailingList::KMail ) );
mId = config.readEntry("MailingListId");
mPostURLS = config.readEntry( "MailingListPostingAddress", QStringList() );
mSubscribeURLS = config.readEntry( "MailingListSubscribeAddress", QStringList() );
mUnsubscribeURLS = config.readEntry( "MailingListUnsubscribeAddress", QStringList() );
mArchiveURLS = config.readEntry( "MailingListArchiveAddress", QStringList() );
mOwnerURLS = config.readEntry( "MailingListOwnerddress", QStringList() );
mHelpURLS = config.readEntry( "MailingListHelpAddress", QStringList() );
}