00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "./mail.h"
00019
00020 Mail::Mail( long number, const QString& unid, bool isNew, QPointer<Account> account, QObject* parent )
00021 : QObject( parent )
00022 {
00023 this->unid = unid;
00024 this->acc = account;
00025 accountName = acc->getName();
00026 setNumber( number );
00027 setNew( isNew );
00028
00029 init();
00030
00031 }
00032
00033 Mail::Mail( const Mail& mail ): QObject ( NULL ),
00034 unid( mail.unid ), subject( mail.subject ), header( mail.header ), size( mail.size ), number( mail.number ), _new( mail._new ),
00035 from( mail.from ), to( mail.to ), sendDate( mail.sendDate ), contentType( mail.contentType ), markedByFilter( mail.markedByFilter ),
00036 acc( mail.acc ), accountName( mail.accountName )
00037 {
00038 }
00039
00040
00041 Mail::~Mail()
00042 {
00043 }
00044
00045 void Mail::setSize( long size )
00046 {
00047 this->size = size;
00048 }
00049
00050 void Mail::print() const
00051 {
00052 cout << "Subject: " << getSubject().toStdString() << endl;
00053 cout << "UNID: " << getUNID().toStdString() << endl;
00054 cout << "Number: " << getNumber() << endl;
00055 cout << "Size: " << getSize() << " Bytes" << endl;
00056 cout << "New Flag: " << isNew() << endl;
00057 cout << "From: " << from.toStdString() << endl;
00058 cout << "To: " << to.toStdString() << endl;
00059 cout << "Send Date: " << sendDate.toString( KDateTime::LocalDate ).toStdString() << endl;
00060 cout << "Content Type: " << contentType.toStdString() << endl;
00061 }
00062
00063 QString Mail::getSubject() const
00064 {
00065 return subject;
00066 }
00067
00068 QString Mail::getUNID() const
00069 {
00070 return unid;
00071 }
00072
00073 long Mail::getSize() const
00074 {
00075 return size;
00076 }
00077
00078 int Mail::getNumber() const
00079 {
00080 return number;
00081 }
00082
00083 void Mail::setNumber( int number )
00084 {
00085 this->number = number;
00086 }
00087
00088 void Mail::init()
00089 {
00090 size = 0;
00091 markedByFilter = false;
00092 }
00093
00094 void Mail::setNew( bool isnew )
00095 {
00096 _new = isnew;
00097 }
00098
00099 bool Mail::isNew( ) const
00100 {
00101 return _new;
00102 }
00103
00104 void Mail::setHeader(const QStringList & header)
00105 {
00106 this->header = header;
00107
00108
00109 QString subject = scanHeader( "Subject" );
00110 subject = subject.simplified();
00111 setSubject( subject);
00112
00113
00114 QString from = scanHeader( "From" );
00115 from = from.simplified();
00116 setFrom( from );
00117
00118
00119 QString to = scanHeader( "To" );
00120 to = to.simplified();
00121 setTo( to );
00122
00123
00124 QString date = scanHeader( "Date" );
00125 setDate( date );
00126
00127
00128 QString content = scanHeader( "Content-Type" );
00129 content = content.simplified ();
00130
00131
00132 int posSemicolon = content.indexOf( ';' );
00133 if( posSemicolon != -1 )
00134 {
00135 content.remove( posSemicolon, content.length() - posSemicolon );
00136 }
00137
00138
00139 setContent( content );
00140
00141 }
00142
00143 QString Mail::scanHeader(const QString & item) const
00144 {
00145
00146 QString _item( item );
00147 _item.append( ": " );
00148
00149
00150 QStringList header = getHeader();
00151
00152
00153 for ( QStringList::Iterator it = header.begin(); it != header.end(); ++it ) {
00154 QString line( *it );
00155 if( line.startsWith( _item ) )
00156 {
00157
00158 int lengthKeyword = _item.length();
00159 return line.remove( 0, lengthKeyword );
00160 }
00161 }
00162
00163
00164 return "";
00165 }
00166
00167 QString Mail::scanBodyPart( const QStringList& part, const QString& item ) const {
00168
00169
00170 QString _item( item );
00171 _item.append( ": " );
00172
00173
00174 QListIterator<QString> it( part );
00175 while( it.hasNext() ) {
00176
00177 QString line = it.next();
00178 if( line.startsWith( _item ) )
00179 {
00180
00181 int lengthKeyword = _item.length();
00182 return line.remove( 0, lengthKeyword );
00183 }
00184 }
00185
00186
00187 return "";
00188
00189 }
00190
00191
00192 void Mail::setSubject( const QString & subject )
00193 {
00194 this->subject = decodeRfc2047( subject );
00195 }
00196
00197 void Mail::setFrom( const QString & from )
00198 {
00199 this->from = from;
00200 }
00201
00202 void Mail::setTo( const QString & to )
00203 {
00204 this->to = to;
00205 }
00206
00207 void Mail::setDate( const QString& date )
00208 {
00209 KMime::Headers::Date mimeDate;
00210 mimeDate.from7BitString( QByteArray( date.toAscii() ) );
00211 sendDate = mimeDate.dateTime();
00212 }
00213
00214 void Mail::setContent( const QString& contentType )
00215 {
00216 this->contentType = contentType;
00217 }
00218
00219 QStringList Mail::getHeader() const
00220 {
00221 return header;
00222 }
00223
00224 QString Mail::decodeRfc2047( const QString& text ) const
00225 {
00226
00227
00228 KMime::Codec* codec;
00229
00230
00231 QString input;
00232 QRegExp regex( "=\\?.*\\?[bB]\\?.*\\?=" );
00233 if( regex.indexIn( text ) != -1 )
00234 {
00235
00236 codec = KMime::Codec::codecForName( "b" );
00237
00238 }
00239 else
00240 {
00241 regex= QRegExp( "=\\?.*\\?[qQ]\\?.*\\?=" );
00242 if( regex.indexIn( text ) != -1 )
00243 {
00244
00245 codec = KMime::Codec::codecForName( "q" );
00246 }
00247 else
00248 {
00249
00250 return text;
00251 }
00252 }
00253
00254
00255 if( codec == NULL )
00256 {
00257 kdDebug() << "No codec available." << endl;
00258 return text;
00259 }
00260
00261
00262 KMime::Decoder *decoder = codec->makeDecoder();
00263
00264
00265
00266
00267 bool breakIt = false;
00268 QString decodedText;
00269 QString encodedText( text );
00270
00271 while( !breakIt && !encodedText.isEmpty() )
00272 {
00273
00274 regex.setMinimal( true );
00275 int index = regex.indexIn( encodedText );
00276 if( index == -1 )
00277 {
00278
00279 breakIt = true;
00280
00281
00282 decodedText.append( encodedText );
00283 }
00284 else
00285 {
00286
00287
00288
00289 decodedText.append( encodedText.left( index ) );
00290 encodedText = encodedText.remove( 0, index );
00291
00292
00293 QString encodedPart( encodedText.left( regex.matchedLength() ) );
00294 encodedText = encodedText.remove( 0, regex.matchedLength() );
00295
00296
00297 int firstQuestionMark = encodedPart.indexOf( "?" );
00298 int secondQuestionMark = encodedPart.indexOf( "?", firstQuestionMark + 1);
00299 int thirthQuestionMark = encodedPart.indexOf( "?", secondQuestionMark + 1 );
00300 int fourthQuestionMark = encodedPart.indexOf( "?", thirthQuestionMark + 1 );
00301
00302
00303 QString charset = encodedPart.mid( firstQuestionMark + 1, secondQuestionMark - firstQuestionMark - 1 );
00304
00305
00306 encodedPart = encodedPart.mid( thirthQuestionMark + 1, fourthQuestionMark - thirthQuestionMark - 1 );
00307
00308
00309
00310
00311
00312
00313
00314 QByteArray decInput;
00315 decInput.append( encodedPart );
00316 QByteArray::ConstIterator iterIn = decInput.begin();
00317
00318
00319 QByteArray decOutput( 256, '\0');
00320 QByteArray::Iterator iterOut = decOutput.begin();
00321
00322
00323 QString out;
00324
00325
00326 while( !decoder->decode( iterIn, decInput.end(), iterOut, decOutput.end() ) )
00327 {
00328 if( iterOut == decOutput.end() )
00329 {
00330 out.append( decOutput );
00331 iterOut = decOutput.begin();
00332 }
00333 }
00334 while( !decoder->finish( iterOut, decOutput.end() ) )
00335 {
00336 if( iterOut == decOutput.end() )
00337 {
00338 out.append( decOutput );
00339 iterOut = decOutput.begin();
00340 }
00341 }
00342 decOutput.resize( iterOut - decOutput.begin() );
00343 out.append( decOutput );
00344
00345
00346 decodedText.append( out );
00347
00348 }
00349 }
00350
00351
00352 delete decoder;
00353
00354 return decodedText;
00355 }
00356
00357 QPointer<Account> Mail::getAccount() const
00358 {
00359 return acc;
00360 }
00361
00362 QString Mail::getFrom() const
00363 {
00364 return from;
00365 }
00366
00367 QString Mail::getTo() const
00368 {
00369 return to;
00370 }
00371
00372 QString Mail::getSizeSuffix() const
00373 {
00374 QString strSize;
00375
00376 if( size >= 1024 * 1024 )
00377 {
00378
00379 strSize = QString( "%L1M" ).arg( ( (double)size / ( 1024 * 1024 ) ), 0, 'f', 1 );
00380 }
00381 else if( size >= 1024 )
00382 {
00383
00384 strSize = QString( "%L1K" ).arg( ( (double)size / 1024 ), 0, 'f', 1 );
00385 }
00386 else
00387
00388 strSize = QString( "%L1" ).arg( size );
00389
00390 return strSize;
00391 }
00392
00393 KDateTime Mail::getDateTime() const
00394 {
00395 return sendDate;
00396 }
00397
00398 QString Mail::getContent() const
00399 {
00400 return contentType;
00401 }
00402
00403 FilterAction_Type Mail::applyHeaderFilter( HeaderFilter* filter, QString account, QString& mailbox, FilterLog* log )
00404 {
00405 FilterAction_Type action = filter->check( getFrom(), getTo(), getSize(), getSubject(), getHeader(), account, mailbox );
00406
00407
00408 if( action == FActMark ) markedByFilter = true;
00409
00410
00411 if( log == NULL )
00412 kdError() << "Mail::applyHeaderFilter: Pointer to the filter log is NULL. Can't write to log." << endl;;
00413 if( action == FActDelete && log != NULL )
00414 log->addDeletedMail( getDateTime(), getFrom(), account, getSubject() );
00415 if( action == FActMove && log != NULL )
00416 log->addMovedMail( getDateTime(), getFrom(), account, getSubject(), mailbox );
00417
00418
00419 return action;
00420 }
00421
00422 void Mail::save( QDomDocument& doc, QDomElement& parent )
00423 {
00424
00425 QString hdr = QString( ITEM_MESSAGE );
00426 hdr.append( "%1" );
00427 hdr = hdr.arg( getNumber() );
00428
00429
00430 QDomElement elem = doc.createElement( hdr );
00431 elem.setAttribute( QString( ATTRIBUTE_MAIL_NUMBER ), getNumber() );
00432 elem.setAttribute( QString( ATTRIBUTE_MAIL_SIZE ), (qlonglong)getSize() );
00433 elem.setAttribute( QString( ATTRIBUTE_MAIL_UID ), getUNID() );
00434
00435
00436 QDomElement subelem = doc.createElement( ITEM_MAIL_HEADER );
00437 subelem.appendChild( doc.createTextNode( getHeader().join( HEADER_SEPARATOR ) ) );
00438
00439
00440 elem.appendChild( subelem );
00441
00442
00443 parent.appendChild( elem );
00444 }
00445
00446 bool Mail::isMarkedByFilter() const
00447 {
00448 return markedByFilter;
00449 }
00450
00451 QStringList Mail::decodeMailBody( const QStringList& body, bool preferHTML ) const
00452 {
00453 QString charset;
00454 QString encoding;
00455 QStringList decodedBody;
00456
00457
00458
00459
00460 QString boundary = getBoundary();
00461
00462
00463 if( boundary.isEmpty() )
00464 {
00465
00466
00467
00468 int posBlankLine = body.indexOf( "" );
00469
00470
00471
00472 if( posBlankLine != -1 && !body.isEmpty() && body.size() > posBlankLine + 1 ) {
00473 decodedBody = body.mid( posBlankLine + 1 );
00474 }
00475
00476
00477
00478
00479 charset = getCharsetFromHeader();
00480
00481
00482 encoding = getTransferEncodingFromHeader();
00483
00484 }
00485 else
00486 {
00487
00488
00489
00490 bool hasPlaintText = !body.filter( "text/plain", Qt::CaseInsensitive ).isEmpty();
00491 bool hasHTML = !body.filter( "text/html", Qt::CaseInsensitive ).isEmpty();
00492
00493
00494 if( hasPlaintText || hasHTML )
00495 {
00496
00497
00498 int posBlankLine = body.indexOf( "" );
00499
00500
00501
00502 if( posBlankLine != -1 && !body.isEmpty() && body.size() > posBlankLine + 1 ) {
00503 decodedBody = body.mid( posBlankLine + 1 );
00504 }
00505
00506 if( decodedBody.isEmpty() ) return body;
00507
00508
00509 QList<QStringList> bodyParts;
00510 QListIterator<QString> itBody( decodedBody );
00511
00512
00513 boundary = "--" + boundary;
00514
00515
00516 QString line = itBody.next();
00517 if( line != boundary ) return body;
00518
00519 QStringList part;
00520
00521 while( itBody.hasNext() ) {
00522
00523
00524 line = itBody.next();
00525
00526 if( !line.startsWith( boundary ) ) {
00527
00528
00529 part.append( line );
00530
00531 } else {
00532
00533
00534
00535 bodyParts.append( part );
00536 part = QStringList();
00537 }
00538
00539 }
00540
00541
00542 bool takeHTML = ( hasHTML && preferHTML ) || !hasPlaintText;
00543
00544
00545 QString contentTypeString;
00546 if( takeHTML ) {
00547 contentTypeString = QString( "text/html" );
00548 } else {
00549 contentTypeString = QString( "text/plain" );
00550 }
00551
00552 QListIterator<QStringList> itParts( bodyParts );
00553 bool found = false;
00554 while( itParts.hasNext() && !found ) {
00555
00556 QStringList part = itParts.next();
00557 if( !part.filter( contentTypeString, Qt::CaseInsensitive ).isEmpty() ) {
00558
00559
00560 decodedBody = part;
00561 found = true;
00562 }
00563 }
00564
00565
00566 if( !found ) return body;
00567
00568
00569 charset = getCharset( decodedBody );
00570 encoding = getTransferEncoding( decodedBody );
00571
00572
00573 posBlankLine = decodedBody.indexOf( "" );
00574 if( posBlankLine != -1 && !decodedBody.isEmpty() && decodedBody.size() > posBlankLine + 1 ) {
00575 decodedBody = decodedBody.mid( posBlankLine + 1 );
00576 }
00577
00578 if( decodedBody.isEmpty() ) return body;
00579
00580
00581 }
00582 }
00583
00584
00585
00586
00587
00588 QString joinedBody = decodedBody.join( "\n" );
00589
00590
00591 if( !encoding.isEmpty() ) {
00592
00593
00594 KMime::Codec* codec = KMime::Codec::codecForName( encoding.toAscii() );
00595
00596 if( codec != NULL ) {
00597
00598
00599 KMime::Decoder *decoder = codec->makeDecoder();
00600
00601
00602
00603 QByteArray decInput;
00604 decInput.append( joinedBody );
00605 QByteArray::ConstIterator iterIn = decInput.begin();
00606
00607
00608 QByteArray decOutput( 256, '\0');
00609 QByteArray::Iterator iterOut = decOutput.begin();
00610
00611
00612 QString out;
00613
00614
00615 while( !decoder->decode( iterIn, decInput.end(), iterOut, decOutput.end() ) )
00616 {
00617 if( iterOut == decOutput.end() )
00618 {
00619 out.append( decOutput );
00620 iterOut = decOutput.begin();
00621 }
00622 }
00623 while( !decoder->finish( iterOut, decOutput.end() ) )
00624 {
00625 if( iterOut == decOutput.end() )
00626 {
00627 out.append( decOutput );
00628 iterOut = decOutput.begin();
00629 }
00630 }
00631 decOutput.resize( iterOut - decOutput.begin() );
00632 out.append( decOutput );
00633
00634
00635 joinedBody = out;
00636 }
00637
00638
00639 }
00640
00641
00642 if( !charset.isEmpty() ) {
00643
00644
00645 QTextCodec* codec = QTextCodec::codecForName( charset.toAscii() );
00646
00647 if( codec != NULL )
00648 {
00649 joinedBody = codec->toUnicode( joinedBody.toAscii() );
00650 }
00651
00652 }
00653
00654
00655 decodedBody = joinedBody.split( '\n' );
00656
00657
00658 return decodedBody;
00659 }
00660
00661 QString Mail::getBoundary( ) const
00662 {
00663 const QString TAG( "boundary=" );
00664
00665 QString boundary;
00666
00667
00668 if( contentType.contains( "multipart", Qt::CaseInsensitive ) )
00669 {
00670
00671
00672
00673 QStringList boundaries = header.filter( TAG, Qt::CaseInsensitive );
00674 if( boundaries.isEmpty() ) return boundary;
00675 QString boundLine = boundaries.first();
00676
00677
00678 int posBoundary = boundLine.indexOf( TAG, 0, Qt::CaseInsensitive );
00679
00680
00681 if( posBoundary >= 0 )
00682 {
00683
00684 int posFirstQuote = posBoundary + TAG.length();
00685
00686
00687 int posSecondQuote = boundLine.indexOf( '"', posFirstQuote + 1 );
00688
00689
00690 boundary.append( boundLine.mid( posFirstQuote + 1, posSecondQuote - posFirstQuote - 1 ) );
00691 }
00692 }
00693
00694 return boundary;
00695 }
00696
00697 QString Mail::getCharsetFromHeader( ) const
00698 {
00699 return getCharset( header );
00700 }
00701
00702 QString Mail::getCharset( const QStringList& text ) const {
00703
00704 QString charset;
00705 const QString TAG( "charset=" );
00706
00707
00708 QStringList charsets = text.filter( TAG, Qt::CaseInsensitive );
00709 if( charsets.isEmpty() ) return charset;
00710 QString charsetline = charsets.first();
00711
00712
00713 int posCharset = charsetline.indexOf( TAG, 0, Qt::CaseInsensitive );
00714
00715
00716 if( posCharset != -1 )
00717 {
00718
00719 int posFirstQuote = charsetline.indexOf( '"', 0, Qt::CaseInsensitive );
00720 if( posFirstQuote != -1 && posFirstQuote == posCharset + TAG.length() )
00721 {
00722
00723
00724
00725 int posLastQuote = charsetline.indexOf( '"', posFirstQuote + 1, Qt::CaseInsensitive );
00726
00727 if( posLastQuote != - 1 )
00728 {
00729
00730 charset = charsetline.mid( posFirstQuote + 1, posLastQuote - posFirstQuote - 1 );
00731 }
00732 }
00733 else
00734 {
00735
00736 }
00737
00738 }
00739
00740 return charset;
00741
00742
00743 }
00744
00745 QString Mail::getTransferEncodingFromHeader() const {
00746
00747 return scanHeader( "Content-Transfer-Encoding" );
00748 }
00749
00750 QString Mail::getTransferEncoding( const QStringList& text ) const {
00751
00752 const QString TAG( "Content-Transfer-Encoding" );
00753
00754 return scanBodyPart( text, TAG );
00755 }
00756
00757 void Mail::writeToMoveLog( FilterLog * log, QString account, QString mailbox )
00758 {
00759 log->addMovedMail( getDateTime(), getFrom(), account, getSubject(), mailbox );
00760 }
00761
00762 void Mail::setMarkAtNextViewRefresh( )
00763 {
00764 markedByFilter = true;
00765 }
00766
00767 void Mail::writeToDeleteLog( FilterLog * log, QString account )
00768 {
00769 log->addDeletedMail( getDateTime(), getFrom(), account, getSubject() );
00770 }
00771
00772 int Mail::compare( const Mail& other, MailSort_Type property)
00773 {
00774
00775 switch( property ) {
00776
00777
00778 case MailSortState : {
00779
00780 if( isNew() == other.isNew() ) return 0;
00781 else if( isNew() ) return 1;
00782 else return 0;
00783
00784 }
00785
00786
00787 case MailSortNumber : {
00788
00789 if( getNumber() == other.getNumber() ) return 0;
00790 else if( getNumber() > other.getNumber() ) return 1;
00791 else return -1;
00792 }
00793
00794
00795 case MailSortAccount : {
00796
00797 return QString::localeAwareCompare( getAccountName(), other.getAccountName() );
00798 }
00799
00800
00801 case MailSortFrom : {
00802
00803 return QString::localeAwareCompare( getFrom(), other.getFrom() );
00804 }
00805
00806
00807 case MailSortTo : {
00808
00809 return QString::localeAwareCompare( getTo(), other.getTo() );
00810 }
00811
00812
00813 case MailSortSubject : {
00814
00815 return QString::localeAwareCompare( getSubject(), other.getSubject() );
00816 }
00817
00818
00819 case MailSortDate : {
00820
00821 if( getDateTime() == other.getDateTime() ) return 0;
00822 else if( getDateTime() > other.getDateTime() ) return 1;
00823 else return -1;
00824 }
00825
00826
00827 case MailSortSize : {
00828
00829 if( getSize() == other.getSize() ) return 0;
00830 else if( getSize() > other.getSize() ) return 1;
00831 else return -1;
00832 }
00833
00834
00835 case MailSortContent : {
00836
00837 return QString::localeAwareCompare( getContent(), other.getContent() );
00838 }
00839
00840 default : {
00841 return QString::localeAwareCompare( getAccountName(), other.getAccountName() );
00842 }
00843
00844 }
00845 }
00846
00847 QString Mail::getAccountName() const
00848 {
00849 return accountName;
00850 }
00851
00852 Mail& Mail::operator=( const Mail& other )
00853 {
00854 unid = other.unid;
00855
00856 subject = other.subject;
00857
00858 header = other.header;
00859
00860 size = other.size;
00861
00862 number = other.number;
00863
00864 _new = other._new;
00865
00866 from = other.from;
00867
00868 to = other.to;
00869
00870 sendDate = other.sendDate;
00871
00872 contentType = other.contentType;
00873
00874 markedByFilter = other.markedByFilter;
00875
00876 acc = other.acc;
00877
00878 accountName = other.accountName;
00879
00880 return ( *this );
00881
00882 }