kmail

mailinglist-magic.cpp
1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2 #ifdef HAVE_CONFIG_H
3 #include <config.h>
4 #endif
5 
6 #include "mailinglist-magic.h"
7 
8 #include "kmmessage.h"
9 
10 #include <tdeconfig.h>
11 #include <kurl.h>
12 #include <kdebug.h>
13 
14 #include <tqstringlist.h>
15 
16 using namespace KMail;
17 
18 typedef TQString (*MagicDetectorFunc) (const KMMessage *, TQCString &, TQString &);
19 
20 /* Sender: (owner-([^@]+)|([^@+]-owner)@ */
21 static TQString check_sender(const KMMessage *message,
22  TQCString &header_name,
23  TQString &header_value )
24 {
25  TQString header = message->headerField( "Sender" );
26 
27  if ( header.isEmpty() )
28  return TQString();
29 
30  if ( header.left( 6 ) == "owner-" )
31  {
32  header_name = "Sender";
33  header_value = header;
34  header = header.mid( 6, header.find( '@' ) - 6 );
35 
36  } else {
37  int index = header.find( "-owner@ " );
38  if ( index == -1 )
39  return TQString();
40 
41  header.truncate( index );
42  header_name = "Sender";
43  header_value = header;
44  }
45 
46  return header;
47 }
48 
49 /* X-BeenThere: ([^@]+) */
50 static TQString check_x_beenthere(const KMMessage *message,
51  TQCString &header_name,
52  TQString &header_value )
53 {
54  TQString header = message->headerField( "X-BeenThere" );
55  if ( header.isNull() || header.find( '@' ) == -1 )
56  return TQString();
57 
58  header_name = "X-BeenThere";
59  header_value = header;
60  header.truncate( header.find( '@' ) );
61  return header;
62 }
63 
64 /* Delivered-To:: <([^@]+) */
65 static TQString check_delivered_to(const KMMessage *message,
66  TQCString &header_name,
67  TQString &header_value )
68 {
69  TQString header = message->headerField( "Delivered-To" );
70  if ( header.isNull() || header.left(13 ) != "mailing list"
71  || header.find( '@' ) == -1 )
72  return TQString();
73 
74  header_name = "Delivered-To";
75  header_value = header;
76 
77  return header.mid( 13, header.find( '@' ) - 13 );
78 }
79 
80 /* X-Mailing-List: <?([^@]+) */
81 static TQString check_x_mailing_list(const KMMessage *message,
82  TQCString &header_name,
83  TQString &header_value )
84 {
85  TQString header = message->headerField( "X-Mailing-List");
86  if ( header.isEmpty() )
87  return TQString();
88 
89  if ( header.find( '@' ) < 1 )
90  return TQString();
91 
92  header_name = "X-Mailing-List";
93  header_value = header;
94  if ( header[0] == '<' )
95  header = header.mid(1, header.find( '@' ) - 1);
96  else
97  header.truncate( header.find( '@' ) );
98  return header;
99 }
100 
101 /* List-Id: [^<]* <([^.]+) */
102 static TQString check_list_id(const KMMessage *message,
103  TQCString &header_name,
104  TQString &header_value )
105 {
106  int lAnglePos, firstDotPos;
107  TQString header = message->headerField( "List-Id" );
108  if ( header.isEmpty() )
109  return TQString();
110 
111  lAnglePos = header.find( '<' );
112  if ( lAnglePos < 0 )
113  return TQString();
114 
115  firstDotPos = header.find( '.', lAnglePos );
116  if ( firstDotPos < 0 )
117  return TQString();
118 
119  header_name = "List-Id";
120  header_value = header.mid( lAnglePos );
121  header = header.mid( lAnglePos + 1, firstDotPos - lAnglePos - 1 );
122  return header;
123 }
124 
125 
126 /* List-Post: <mailto:[^< ]*>) */
127 static TQString check_list_post(const KMMessage *message,
128  TQCString &header_name,
129  TQString &header_value )
130 {
131  TQString header = message->headerField( "List-Post" );
132  if ( header.isEmpty() )
133  return TQString();
134 
135  int lAnglePos = header.find( "<mailto:" );
136  if ( lAnglePos < 0 )
137  return TQString();
138 
139  header_name = "List-Post";
140  header_value = header;
141  header = header.mid( lAnglePos + 8, header.length());
142  header.truncate( header.find('@') );
143  return header;
144 }
145 
146 /* Mailing-List: list ([^@]+) */
147 static TQString check_mailing_list(const KMMessage *message,
148  TQCString &header_name,
149  TQString &header_value )
150 {
151  TQString header = message->headerField( "Mailing-List");
152  if ( header.isEmpty() )
153  return TQString();
154 
155  if (header.left( 5 ) != "list " || header.find( '@' ) < 5 )
156  return TQString();
157 
158  header_name = "Mailing-List";
159  header_value = header;
160  header = header.mid(5, header.find( '@' ) - 5);
161  return header;
162 }
163 
164 
165 /* X-Loop: ([^@]+) */
166 static TQString check_x_loop(const KMMessage *message,
167  TQCString &header_name,
168  TQString &header_value ){
169  TQString header = message->headerField( "X-Loop");
170  if ( header.isEmpty() )
171  return TQString();
172 
173  if (header.find( '@' ) < 2 )
174  return TQString();
175 
176  header_name = "X-Loop";
177  header_value = header;
178  header.truncate(header.find( '@' ));
179  return header;
180 }
181 
182 /* X-ML-Name: (.+) */
183 static TQString check_x_ml_name(const KMMessage *message,
184  TQCString &header_name,
185  TQString &header_value ){
186  TQString header = message->headerField( "X-ML-Name");
187  if ( header.isEmpty() )
188  return TQString();
189 
190  header_name = "X-ML-Name";
191  header_value = header;
192  header.truncate(header.find( '@' ));
193  return header;
194 }
195 
196 MagicDetectorFunc magic_detector[] =
197 {
198  check_list_id,
199  check_list_post,
200  check_sender,
201  check_x_mailing_list,
202  check_mailing_list,
203  check_delivered_to,
204  check_x_beenthere,
205  check_x_loop,
206  check_x_ml_name
207 };
208 
209 static const int num_detectors = sizeof (magic_detector) / sizeof (magic_detector[0]);
210 
211 static TQStringList
212 headerToAddress( const TQString& header )
213 {
214  TQStringList addr;
215  int start = 0;
216  int end = 0;
217 
218  if ( header.isEmpty() )
219  return addr;
220 
221  while ( (start = header.find( "<", start )) != -1 ) {
222  if ( (end = header.find( ">", ++start ) ) == -1 ) {
223  kdDebug(5006)<<k_funcinfo<<"Serious mailing list header parsing error !"<<endl;
224  return addr;
225  }
226  kdDebug(5006)<<"Mailing list = "<<header.mid( start, end - start )<<endl;
227  addr.append( header.mid( start, end - start ) );
228  }
229  return addr;
230 }
231 
233 MailingList::detect( const KMMessage *message )
234 {
235  MailingList mlist;
236 
237  mlist.setPostURLS( headerToAddress(
238  message->headerField( "List-Post" ) ) );
239  mlist.setHelpURLS( headerToAddress(
240  message->headerField( "List-Help" ) ) );
241  mlist.setSubscribeURLS( headerToAddress(
242  message->headerField( "List-Subscribe" ) ) );
243  mlist.setUnsubscribeURLS( headerToAddress(
244  message->headerField( "List-Unsubscribe" ) ) );
245  mlist.setArchiveURLS( headerToAddress(
246  message->headerField( "List-Archive" ) ) );
247  mlist.setId( message->headerField( "List-Id" ) );
248 
249  return mlist;
250 }
251 
252 TQString
253 MailingList::name( const KMMessage *message, TQCString &header_name,
254  TQString &header_value )
255 {
256  TQString mlist;
257  header_name = TQCString();
258  header_value = TQString();
259 
260  if ( !message )
261  return TQString();
262 
263  for (int i = 0; i < num_detectors; i++) {
264  mlist = magic_detector[i] (message, header_name, header_value);
265  if ( !mlist.isNull() )
266  return mlist;
267  }
268 
269  return TQString();
270 }
271 
272 MailingList::MailingList()
273  : mFeatures( None ), mHandler( KMail )
274 {
275 }
276 
277 int
278 MailingList::features() const
279 {
280  return mFeatures;
281 }
282 
283 void
284 MailingList::setHandler( MailingList::Handler han )
285 {
286  mHandler = han;
287 }
288 MailingList::Handler
289 MailingList::handler() const
290 {
291  return mHandler;
292 }
293 
294 void
295 MailingList::setPostURLS ( const KURL::List& lst )
296 {
297  mFeatures |= Post;
298  if ( lst.empty() ) {
299  mFeatures ^= Post;
300  }
301  mPostURLS = lst;
302 }
303 KURL::List
304 MailingList::postURLS() const
305 {
306  return mPostURLS;
307 }
308 
309 void
310 MailingList::setSubscribeURLS( const KURL::List& lst )
311 {
312  mFeatures |= Subscribe;
313  if ( lst.empty() ) {
314  mFeatures ^= Subscribe;
315  }
316 
317  mSubscribeURLS = lst;
318 }
319 KURL::List
320 MailingList::subscribeURLS() const
321 {
322  return mSubscribeURLS;
323 }
324 
325 void
326 MailingList::setUnsubscribeURLS( const KURL::List& lst )
327 {
328  mFeatures |= Unsubscribe;
329  if ( lst.empty() ) {
330  mFeatures ^= Unsubscribe;
331  }
332 
333  mUnsubscribeURLS = lst;
334 }
335 KURL::List MailingList::unsubscribeURLS() const
336 {
337  return mUnsubscribeURLS;
338 }
339 
340 void
341 MailingList::setHelpURLS( const KURL::List& lst )
342 {
343  mFeatures |= Help;
344  if ( lst.empty() ) {
345  mFeatures ^= Help;
346  }
347 
348  mHelpURLS = lst;
349 }
350 KURL::List
351 MailingList::helpURLS() const
352 {
353  return mHelpURLS;
354 }
355 
356 void
357 MailingList::setArchiveURLS( const KURL::List& lst )
358 {
359  mFeatures |= Archive;
360  if ( lst.empty() ) {
361  mFeatures ^= Archive;
362  }
363 
364  mArchiveURLS = lst;
365 }
366 KURL::List
367 MailingList::archiveURLS() const
368 {
369  return mArchiveURLS;
370 }
371 
372 void
373 MailingList::setId( const TQString& str )
374 {
375  mFeatures |= Id;
376  if ( str.isEmpty() ) {
377  mFeatures ^= Id;
378  }
379 
380  mId = str;
381 }
382 TQString
383 MailingList::id() const
384 {
385  return mId;
386 }
387 
388 void
389 MailingList::writeConfig( TDEConfig* config ) const
390 {
391  config->writeEntry( "MailingListFeatures", mFeatures );
392  config->writeEntry( "MailingListHandler", mHandler );
393  config->writeEntry( "MailingListId", mId );
394  config->writeEntry( "MailingListPostingAddress", mPostURLS.toStringList() );
395  config->writeEntry( "MailingListSubscribeAddress", mSubscribeURLS.toStringList() );
396  config->writeEntry( "MailingListUnsubscribeAddress", mUnsubscribeURLS.toStringList() );
397  config->writeEntry( "MailingListArchiveAddress", mArchiveURLS.toStringList() );
398  config->writeEntry( "MailingListHelpAddress", mHelpURLS.toStringList() );
399 }
400 
401 void
402 MailingList::readConfig( TDEConfig* config )
403 {
404  mFeatures = config->readNumEntry( "MailingListFeatures", 0 );
405  mHandler = static_cast<MailingList::Handler>(
406  config->readNumEntry( "MailingListHandler", MailingList::KMail ) );
407 
408  mId = config->readEntry("MailingListId");
409  mPostURLS = config->readListEntry( "MailingListPostingAddress" );
410  mSubscribeURLS = config->readListEntry( "MailingListSubscribeAddress" );
411  mUnsubscribeURLS = config->readListEntry( "MailingListUnsubscribeAddress" );
412  mArchiveURLS = config->readListEntry( "MailingListArchiveAddress" );
413  mHelpURLS = config->readListEntry( "MailingListHelpAddress" );
414 }