one entry for korganizer in khelpcenters navigation tree is enough
[kdepim.git] / messagecore / mailinglist.cpp
blob3afcf277ba1b9d1718e1a34d6a738cb3a3fddab4
1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
3 #include "mailinglist.h"
5 #include <kconfig.h>
6 #include <kconfiggroup.h>
7 #include <kurl.h>
8 #include <kdebug.h>
10 #include <QtCore/QSharedData>
11 #include <QtCore/QStringList>
13 #include <boost/shared_ptr.hpp>
15 using namespace MessageCore;
17 typedef QString (*MagicDetectorFunc)( const KMime::Message::Ptr&, QByteArray&, QString& );
19 /* Sender: (owner-([^@]+)|([^@+]-owner)@ */
20 static QString check_sender( const KMime::Message::Ptr &message,
21 QByteArray &headerName,
22 QString &headerValue )
24 QString header = message->sender()->asUnicodeString();
26 if ( header.isEmpty() )
27 return QString();
29 if ( header.left( 6 ) == "owner-" ) {
30 headerName = "Sender";
31 headerValue = header;
32 header = header.mid( 6, header.indexOf( '@' ) - 6 );
33 } else {
34 const int index = header.indexOf( "-owner@ " );
35 if ( index == -1 )
36 return QString();
38 header.truncate( index );
39 headerName = "Sender";
40 headerValue = header;
43 return header;
46 /* X-BeenThere: ([^@]+) */
47 static QString check_x_beenthere( const KMime::Message::Ptr &message,
48 QByteArray &headerName,
49 QString &headerValue )
51 QString header = message->headerByType( "X-BeenThere" ) ? message->headerByType( "X-BeenThere" )->asUnicodeString() : "";
52 if ( header.isNull() || header.indexOf( '@' ) == -1 )
53 return QString();
55 headerName = "X-BeenThere";
56 headerValue = header;
57 header.truncate( header.indexOf( '@' ) );
59 return header;
62 /* Delivered-To:: <([^@]+) */
63 static QString check_delivered_to( const KMime::Message::Ptr &message,
64 QByteArray &headerName,
65 QString &headerValue )
67 QString header = message->headerByType( "Delivered-To" ) ? message->headerByType( "Delivered-To" )->asUnicodeString() : "";
68 if ( header.isNull() || header.left( 13 ) != "mailing list"
69 || header.indexOf( '@' ) == -1 )
70 return QString();
72 headerName = "Delivered-To";
73 headerValue = header;
75 return header.mid( 13, header.indexOf( '@' ) - 13 );
78 /* X-Mailing-List: <?([^@]+) */
79 static QString check_x_mailing_list( const KMime::Message::Ptr &message,
80 QByteArray &headerName,
81 QString &headerValue )
83 QString header = message->headerByType( "X-Mailing-List" ) ? message->headerByType( "X-Mailing-List" )->asUnicodeString() : "";
84 if ( header.isEmpty() )
85 return QString();
87 if ( header.indexOf( '@' ) < 1 )
88 return QString();
90 headerName = "X-Mailing-List";
91 headerValue = header;
92 if ( header[0] == '<' )
93 header = header.mid( 1, header.indexOf( '@' ) - 1 );
94 else
95 header.truncate( header.indexOf( '@' ) );
97 return header;
100 /* List-Id: [^<]* <([^.]+) */
101 static QString check_list_id( const KMime::Message::Ptr &message,
102 QByteArray &headerName,
103 QString &headerValue )
105 QString header = message->headerByType( "List-Id" ) ? message->headerByType( "List-Id" )->asUnicodeString() : "";
106 if ( header.isEmpty() )
107 return QString();
109 const int leftAnglePos = header.indexOf( '<' );
110 if ( leftAnglePos < 0 )
111 return QString();
113 const int firstDotPos = header.indexOf( '.', leftAnglePos );
114 if ( firstDotPos < 0 )
115 return QString();
117 headerName = "List-Id";
118 headerValue = header.mid( leftAnglePos );
119 header = header.mid( leftAnglePos + 1, firstDotPos - leftAnglePos - 1 );
121 return header;
125 /* List-Post: <mailto:[^< ]*>) */
126 static QString check_list_post( const KMime::Message::Ptr &message,
127 QByteArray &headerName,
128 QString &headerValue )
130 QString header = message->headerByType( "List-Post" ) ? message->headerByType( "List-Post" )->asUnicodeString() : "";
131 if ( header.isEmpty() )
132 return QString();
134 int leftAnglePos = header.indexOf( "<mailto:" );
135 if ( leftAnglePos < 0 )
136 return QString();
138 headerName = "List-Post";
139 headerValue = header;
140 header = header.mid( leftAnglePos + 8, header.length() );
141 header.truncate( header.indexOf( '@' ) );
143 return header;
146 /* Mailing-List: list ([^@]+) */
147 static QString check_mailing_list( const KMime::Message::Ptr &message,
148 QByteArray &headerName,
149 QString &headerValue )
151 QString header = message->headerByType( "Mailing-List" ) ? message->headerByType( "Mailing-List" )->asUnicodeString() : "";
152 if ( header.isEmpty() )
153 return QString();
155 if ( header.left( 5 ) != "list " || header.indexOf( '@' ) < 5 )
156 return QString();
158 headerName = "Mailing-List";
159 headerValue = header;
160 header = header.mid( 5, header.indexOf( '@' ) - 5 );
162 return header;
166 /* X-Loop: ([^@]+) */
167 static QString check_x_loop( const KMime::Message::Ptr &message,
168 QByteArray &headerName,
169 QString &headerValue )
171 QString header = message->headerByType( "X-Loop" ) ? message->headerByType( "X-Loop" )->asUnicodeString() : "";
172 if ( header.isEmpty() )
173 return QString();
175 if (header.indexOf( '@' ) < 2 )
176 return QString();
178 headerName = "X-Loop";
179 headerValue = header;
180 header.truncate( header.indexOf( '@' ) );
182 return header;
185 /* X-ML-Name: (.+) */
186 static QString check_x_ml_name( const KMime::Message::Ptr &message,
187 QByteArray &headerName,
188 QString &headerValue )
190 QString header = message->headerByType( "X-ML-Name" ) ? message->headerByType( "X-ML-Name" )->asUnicodeString() : "";
191 if ( header.isEmpty() )
192 return QString();
194 headerName = "X-ML-Name";
195 headerValue = header;
196 header.truncate( header.indexOf( '@' ) );
198 return header;
201 MagicDetectorFunc magic_detector[] =
203 check_list_id,
204 check_list_post,
205 check_sender,
206 check_x_mailing_list,
207 check_mailing_list,
208 check_delivered_to,
209 check_x_beenthere,
210 check_x_loop,
211 check_x_ml_name
214 static const int num_detectors = sizeof( magic_detector ) / sizeof( magic_detector[0] );
216 static QStringList headerToAddress( const QString &header )
218 QStringList addresses;
219 int start = 0;
220 int end = 0;
222 if ( header.isEmpty() )
223 return addresses;
225 while ( (start = header.indexOf( "<", start )) != -1 ) {
226 if ( (end = header.indexOf( ">", ++start ) ) == -1 ) {
227 kWarning() << "Serious mailing list header parsing error!";
228 return addresses;
231 addresses.append( header.mid( start, end - start ) );
234 return addresses;
237 class MessageCore::MailingList::Private : public QSharedData
239 public:
240 Private()
241 : mFeatures( None ),
242 mHandler( KMail )
246 Private( const Private &other )
247 : QSharedData( other )
249 mFeatures = other.mFeatures;
250 mHandler = other.mHandler;
251 mPostUrls = other.mPostUrls;
252 mSubscribeUrls = other.mSubscribeUrls;
253 mUnsubscribeUrls = other.mUnsubscribeUrls;
254 mHelpUrls = other.mHelpUrls;
255 mArchiveUrls = other.mArchiveUrls;
256 mOwnerUrls = other.mOwnerUrls;
257 mArchivedAtUrl = other.mArchivedAtUrl;
258 mId = other.mId;
261 Features mFeatures;
262 Handler mHandler;
263 KUrl::List mPostUrls;
264 KUrl::List mSubscribeUrls;
265 KUrl::List mUnsubscribeUrls;
266 KUrl::List mHelpUrls;
267 KUrl::List mArchiveUrls;
268 KUrl::List mOwnerUrls;
269 KUrl mArchivedAtUrl;
270 QString mId;
273 MailingList MailingList::detect( const KMime::Message::Ptr &message )
275 MailingList mailingList;
277 if ( message->headerByType( "List-Post" ) )
278 mailingList.setPostUrls( headerToAddress( message->headerByType( "List-Post" )->asUnicodeString() ) );
280 if ( message->headerByType( "List-Help" ) )
281 mailingList.setHelpUrls( headerToAddress( message->headerByType( "List-Help" )->asUnicodeString() ) );
283 if ( message->headerByType( "List-Subscribe" ) )
284 mailingList.setSubscribeUrls( headerToAddress( message->headerByType( "List-Subscribe" )->asUnicodeString() ) );
286 if ( message->headerByType( "List-Unsubscribe" ) )
287 mailingList.setUnsubscribeUrls( headerToAddress( message->headerByType( "List-Unsubscribe" )->asUnicodeString() ) );
289 if ( message->headerByType( "List-Archive" ) )
290 mailingList.setArchiveUrls( headerToAddress( message->headerByType( "List-Archive" )->asUnicodeString() ) );
292 if ( message->headerByType( "List-Owner" ) )
293 mailingList.setOwnerUrls( headerToAddress( message->headerByType( "List-Owner" )->asUnicodeString() ) );
295 if ( message->headerByType( "Archived-At" ) )
296 mailingList.setArchivedAtUrl( KUrl( message->headerByType( "Archived-At" )->asUnicodeString() ) );
298 if ( message->headerByType( "List-Id" ) )
299 mailingList.setId( message->headerByType( "List-Id" )->asUnicodeString() );
301 return mailingList;
304 QString MailingList::name( const KMime::Message::Ptr &message,
305 QByteArray &headerName, QString &headerValue )
307 QString mailingList;
308 headerName = QByteArray();
309 headerValue.clear();
311 if ( !message )
312 return QString();
314 for ( int i = 0; i < num_detectors; i++ ) {
315 mailingList = magic_detector[i]( message, headerName, headerValue );
316 if ( !mailingList.isNull() )
317 return mailingList;
320 return QString();
323 MailingList::MailingList()
324 : d( new Private )
328 MailingList::MailingList( const MailingList &other )
329 : d( other.d )
333 MailingList& MailingList::operator=( const MailingList &other )
335 if ( this != &other )
336 d = other.d;
338 return *this;
341 MailingList::~MailingList()
345 MailingList::Features MailingList::features() const
347 return d->mFeatures;
350 void MailingList::setHandler( MailingList::Handler handler )
352 d->mHandler = handler;
355 MailingList::Handler MailingList::handler() const
357 return d->mHandler;
360 void MailingList::setPostUrls( const KUrl::List &urls )
362 d->mFeatures |= Post;
364 if ( urls.empty() ) {
365 d->mFeatures ^= Post;
368 d->mPostUrls = urls;
371 KUrl::List MailingList::postUrls() const
373 return d->mPostUrls;
376 void MailingList::setSubscribeUrls( const KUrl::List &urls )
378 d->mFeatures |= Subscribe;
380 if ( urls.empty() ) {
381 d->mFeatures ^= Subscribe;
384 d->mSubscribeUrls = urls;
387 KUrl::List MailingList::subscribeUrls() const
389 return d->mSubscribeUrls;
392 void MailingList::setUnsubscribeUrls( const KUrl::List &urls )
394 d->mFeatures |= Unsubscribe;
396 if ( urls.empty() ) {
397 d->mFeatures ^= Unsubscribe;
400 d->mUnsubscribeUrls = urls;
403 KUrl::List MailingList::unsubscribeUrls() const
405 return d->mUnsubscribeUrls;
408 void MailingList::setHelpUrls( const KUrl::List &urls )
410 d->mFeatures |= Help;
412 if ( urls.empty() ) {
413 d->mFeatures ^= Help;
416 d->mHelpUrls = urls;
419 KUrl::List MailingList::helpUrls() const
421 return d->mHelpUrls;
424 void MailingList::setArchiveUrls( const KUrl::List &urls )
426 d->mFeatures |= Archive;
428 if ( urls.empty() ) {
429 d->mFeatures ^= Archive;
432 d->mArchiveUrls = urls;
435 KUrl::List MailingList::archiveUrls() const
437 return d->mArchiveUrls;
440 void MailingList::setOwnerUrls( const KUrl::List &urls )
442 d->mFeatures |= Owner;
444 if ( urls.empty() ) {
445 d->mFeatures ^= Owner;
448 d->mOwnerUrls = urls;
451 KUrl::List MailingList::ownerUrls() const
453 return d->mOwnerUrls;
456 void MailingList::setArchivedAtUrl( const KUrl &url )
458 d->mFeatures |= ArchivedAt;
460 if ( !url.isValid() ) {
461 d->mFeatures ^= ArchivedAt;
464 d->mArchivedAtUrl = url;
467 KUrl MailingList::archivedAtUrl() const
469 return d->mArchivedAtUrl;
472 void MailingList::setId( const QString &id )
474 d->mFeatures |= Id;
476 if ( id.isEmpty() ) {
477 d->mFeatures ^= Id;
480 d->mId = id;
483 QString MailingList::id() const
485 return d->mId;
488 void MailingList::writeConfig( KConfigGroup &group ) const
490 group.writeEntry( "MailingListFeatures", static_cast<int>( d->mFeatures ) );
491 group.writeEntry( "MailingListHandler", static_cast<int>( d->mHandler ) );
492 group.writeEntry( "MailingListId", d->mId );
493 group.writeEntry( "MailingListPostingAddress", d->mPostUrls.toStringList() );
494 group.writeEntry( "MailingListSubscribeAddress", d->mSubscribeUrls.toStringList() );
495 group.writeEntry( "MailingListUnsubscribeAddress", d->mUnsubscribeUrls.toStringList() );
496 group.writeEntry( "MailingListArchiveAddress", d->mArchiveUrls.toStringList() );
497 group.writeEntry( "MailingListOwnerAddress", d->mOwnerUrls.toStringList() );
498 group.writeEntry( "MailingListHelpAddress", d->mHelpUrls.toStringList() );
499 /* Note: mArchivedAtUrl deliberately not saved here as it refers to a single
500 * instance of a message rather than an element of a general mailing list.
501 * http://reviewboard.kde.org/r/1768/#review2783
505 void MailingList::readConfig( const KConfigGroup &group )
507 d->mFeatures = static_cast<MailingList::Features>( group.readEntry( "MailingListFeatures", 0 ) );
508 d->mHandler = static_cast<MailingList::Handler>( group.readEntry( "MailingListHandler",
509 static_cast<int>( MailingList::KMail ) ) );
510 d->mId = group.readEntry("MailingListId");
511 d->mPostUrls = group.readEntry( "MailingListPostingAddress", QStringList() );
512 d->mSubscribeUrls = group.readEntry( "MailingListSubscribeAddress", QStringList() );
513 d->mUnsubscribeUrls = group.readEntry( "MailingListUnsubscribeAddress", QStringList() );
514 d->mArchiveUrls = group.readEntry( "MailingListArchiveAddress", QStringList() );
515 d->mOwnerUrls = group.readEntry( "MailingListOwnerddress", QStringList() );
516 d->mHelpUrls = group.readEntry( "MailingListHelpAddress", QStringList() );