showrecordelem.cpp

00001 /***************************************************************************
00002                           showrecord.cpp  -  description
00003                              -------------------
00004     begin                : Thu Dec 28 2000
00005     copyright            : (C) 2000-2001 by Eggert Ehmke
00006     email                : eggert.ehmke@berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 
00019 
00020 
00021 #include "showrecordelem.h"
00022 
00023 int const ShowRecordElem::continueShowHeaders( 0 );
00024 int const ShowRecordElem::cancelShowHeaders( 1 );
00025 
00026 ShowRecordElem::ShowRecordElem ()
00027 {
00028   //set default values
00029   m_from = "???";
00030   m_subject = "???";
00031   m_size = 0;
00032   m_pItem = NULL;
00033   m_new = false;
00034   m_pFilter = NULL;
00035 }
00036 
00037 ShowRecordElem::ShowRecordElem( int number, TQString& uid, bool isNew )
00038 {
00039   //set default values
00040   m_from = "???";
00041   m_subject = "???";
00042   m_size = 0;
00043   m_pItem = NULL;
00044   m_pFilter = NULL;
00045 
00046   //set given values
00047   m_nNumber = number;
00048   m_uid = uid;
00049   m_new = isNew;
00050 }
00051 
00052 
00053 TQCString ShowRecordElem::scanHeader( const TQString& item ) const
00054 {
00055   TQCString headerline( "" );      //found header line
00056 
00057   //get e.g. the "From:" line, starting with cr,lf,"From:" and ending
00058   //with a carriage return
00059 
00060   //build the search string
00061   TQString searchstring( TQString( "\r\n%1:" ).arg( item ) );
00062 
00063   //searching...
00064   int pos1 = m_header.find( searchstring, 0, FALSE );
00065   int pos2 = m_header.find( '\r', pos1 + 2 );
00066 
00067   //cut out the interesting content, if we have found a matching line
00068   //if we have found nothing, the returned string will be ""
00069   if( pos1 >= 0 )
00070   {
00071     headerline = m_header.mid( pos1 + searchstring.length(), pos2 - pos1 - searchstring.length() );
00072   }
00073 
00074   return headerline;
00075 }
00076 
00077 void ShowRecordElem::setHeader( const TQString& header )
00078 {
00079   //store given header
00080   m_header = header.ascii();
00081 
00082   //extract sender and store it
00083   TQCString from = scanHeader( "From" );
00084   from = from.simplifyWhiteSpace();
00085   setFrom( from );
00086 
00087   //extract addressee and store it
00088   TQCString to = scanHeader( "To" );
00089   to = to.simplifyWhiteSpace();
00090   setTo (to);
00091 
00092   //extract subject and store it
00093   TQCString subject = scanHeader( "Subject" );
00094   subject = subject.simplifyWhiteSpace();
00095   setSubject( subject );
00096 
00097   //extract date and store it
00098   TQCString date = scanHeader( "Date" );
00099   setDate( date );
00100 
00101   //extract content type
00102   TQCString content = scanHeader( "Content-Type" );
00103   content = content.simplifyWhiteSpace ();
00104 
00105   //remove the stuff after the content type; see RFC 2045
00106   int posSemicolon = content.find( ';' );
00107   if( posSemicolon != -1 )
00108   {
00109     content.remove( posSemicolon, content.length() - posSemicolon );
00110   }
00111 
00112   //store content type
00113   setContent (content);
00114 }
00115 
00116 void ShowRecordElem::setDate( const TQCString& date )
00117 {
00118   DwDateTime dwDate;      //this class represents an RFC-822 date-time;
00119                           //see mimelib/datetime.h
00120 
00121   //convert and store the date-time
00122   dwDate.FromString( date );
00123   dwDate.Parse();
00124   m_unixDate.setTime_t( dwDate.AsUnixTime() );
00125 }
00126 
00127 TQString ShowRecordElem::from() const
00128 {
00129   return Codecs::decodeRFC2047( m_from );
00130 }
00131 
00132 TQString ShowRecordElem::to() const
00133 {
00134   return Codecs::decodeRFC2047( m_to );
00135 }
00136 
00137 TQString ShowRecordElem::subject() const
00138 {
00139   return Codecs::decodeRFC2047( m_subject );
00140 }
00141 
00142 TQString ShowRecordElem::date() const
00143 {
00144   return TDEGlobal::locale()->formatDateTime( m_unixDate, true, true );
00145 }
00146 
00147 TQString ShowRecordElem::strUnixTime() const
00148 {
00149   return m_unixDate.toString( TQt::ISODate );
00150 }
00151 
00152 TQString ShowRecordElem::strSize() const
00153 {
00154   return TQString( "%1" ).arg( m_size, 8 );
00155 }
00156 
00157 TQString ShowRecordElem::state() const
00158 {
00159   if( m_new )
00160     return i18n( "new" );
00161   else
00162     return i18n( "old" );
00163 }
00164 
00165 void ShowRecordElem::saveOptions( TQDomDocument& doc, TQDomElement& parent )
00166 {
00167   //build item tag of this mail( with mail number)
00168   TQString hdr = TQString( ITEM_MESSAGE );
00169   hdr.append( "%1" );
00170   hdr = hdr.arg( m_nNumber );
00171 
00172   //create a new element and store the mail meta data in it
00173   TQDomElement elem = doc.createElement( hdr );
00174   elem.setAttribute( ATTRIBUTE_MAIL_NUMBER, m_nNumber );
00175   elem.setAttribute( ATTRIBUTE_MAIL_SIZE, m_size );
00176   elem.setAttribute( ATTRIBUTE_MAIL_UID, m_uid );
00177 
00178   //create a sub element for the mail header in store the header in it
00179   TQDomElement subelem = doc.createElement( ITEM_MAIL_HEADER );
00180   subelem.appendChild( doc.createTextNode( m_header ) );
00181 
00182   //add header element to the mail element
00183   elem.appendChild( subelem );
00184 
00185   //add mail element to the account (parent) element
00186   parent.appendChild( elem );
00187 }
00188 
00189 void ShowRecordElem::readOptions( TQDomElement& elem )
00190 {
00191   //get number, size and uid
00192   setNumber( elem.attribute( ATTRIBUTE_MAIL_NUMBER ).toInt() );
00193   setSize( elem.attribute( ATTRIBUTE_MAIL_SIZE ).toInt() );
00194   setUIDL( elem.attribute( ATTRIBUTE_MAIL_UID ) );
00195 
00196   //search for the header item and read it
00197   TQDomElement subelem = elem.namedItem( ITEM_MAIL_HEADER ).toElement();
00198   setHeader( subelem.text() );
00199 
00200   //the mail is not new
00201   setNew( false );
00202 }
00203 
00204 void ShowRecordElem::applyFilters ()
00205 {
00206   //search for a matching filter
00207   FilterElem* filter = Filter::matches( this );
00208 
00209   if( filter != NULL )
00210   {
00211     //if we have found a matching filter, highlight the corresponding
00212     //list view entry
00213     m_pItem->setSelected (true);
00214 
00215     //store a pointer to the filter
00216     setFilter( filter );
00217   }
00218 }
00219 
00220 void ShowRecordElem::setFrom( const TQCString & from )
00221 {
00222   m_from = from;
00223 }
00224 
00225 void ShowRecordElem::setTo( const TQCString & to )
00226 {
00227   m_to = to;
00228 }
00229 
00230 void ShowRecordElem::setSubject( const TQCString & subject )
00231 {
00232   m_subject = subject;
00233 }
00234 
00235 void ShowRecordElem::setContent( const TQCString& content )
00236 {
00237   m_content = content;
00238 }
00239 
00240 TQString ShowRecordElem::header( ) const
00241 {
00242   return TQString( m_header );
00243 }
00244 
00245 void ShowRecordElem::setUIDL( const TQString & uid )
00246 {
00247   m_uid = uid;
00248 }
00249 
00250 TQString ShowRecordElem::uidl( ) const
00251 {
00252   return m_uid;
00253 }
00254 
00255 void ShowRecordElem::setSize( int size )
00256 {
00257   m_size = size;
00258 }
00259 
00260 int ShowRecordElem::size( ) const
00261 {
00262   return m_size;
00263 }
00264 
00265 void ShowRecordElem::setNew( bool isnew )
00266 {
00267   m_new = isnew;
00268 }
00269 
00270 bool ShowRecordElem::isNew( ) const
00271 {
00272   return m_new;
00273 }
00274 
00275 void ShowRecordElem::setNumber( int n )
00276 {
00277   m_nNumber = n;
00278 }
00279 
00280 int ShowRecordElem::number( ) const
00281 {
00282   return m_nNumber;
00283 }
00284 
00285 TQString ShowRecordElem::content( ) const
00286 {
00287   return m_content;
00288 }
00289 
00290 void ShowRecordElem::setViewItem( ShowListViewItem* item )
00291 {
00292   m_pItem = item;
00293 }
00294 
00295 ShowListViewItem * ShowRecordElem::viewItem( ) const
00296 {
00297   return m_pItem;
00298 }
00299 
00300 void ShowRecordElem::setFilter( FilterElem* filter )
00301 {
00302   m_pFilter = filter;
00303 }
00304 
00305 bool ShowRecordElem::isSelected( ) const
00306 {
00307   if( m_pItem != NULL )
00308     return m_pItem->isSelected();
00309   else
00310     return false;
00311 }
00312 
00313 TQString ShowRecordElem::strSizePrefix( ) const
00314 {
00315   TQString size;
00316 
00317   if( m_size >= 1024 * 1024 )
00318   {
00319     //prefix is mega
00320     size = TQString( "%L1M" ).arg( ( (double)m_size / ( 1024 * 1024 ) ), 0, 'f', 1 );
00321   }
00322   else if( m_size >= 1024 )
00323   {
00324     //prefix is kilo
00325     size = TQString( "%L1K" ).arg( ( (double)m_size / 1024 ), 0, 'f', 1 );
00326   }
00327   else
00328     //no prefix
00329     size = TQString( "%L1" ).arg( m_size );
00330 
00331   return size;
00332 }
00333 
00334 TQString ShowRecordElem::decodeMailBody( TQByteArray body, bool preferHTML ) const
00335 {
00336   TQString charset;    //charset of the content
00337   TQString encoding;   //content transfer encoding
00338 
00339   //cast given body to a TQCString
00340   //class TQCString needs a null terminated char array to create
00341   //an object. Therefore we append an null byte to the given mail body
00342   body.resize( body.size() + 1 );
00343   body[ body.size() - 1 ] = '\0';
00344   TQCString strBody( (char *)body.data() );
00345 
00346   //normalize line ends; remove all \r characters
00347   for( uint i = 0; i < strBody.size(); i++ )
00348     if( strBody[ i ] == '\r' )
00349       strBody.remove( i, 1 );
00350 
00351   //get boundary that is separating the parts of a multipart message
00352   //if the header doesn't contain a boundary attribute, this messsage
00353   //has just one part
00354   TQString boundary = getBoundary();
00355 
00356   //process body subject to it is a multipart messsage or not
00357   if( boundary == "" )
00358   {
00359     //the message has just one body part
00360 
00361     //get the position of the first blank line
00362     int posBlankLine = strBody.find( "\n\n" );
00363 
00364     //truncate body; the found blank line is separating the
00365     //header from the message
00366     strBody = strBody.mid( posBlankLine + 2 );
00367     while( strBody[ 0 ] == '\n')
00368       strBody.remove( 0, 1 );
00369 
00370     //get charset of the message; it is behind the
00371     //content type attribute in the header
00372     charset = getCharset();
00373 
00374     //get transfer encoding type from the header
00375     encoding = getTransferEncoding();
00376   }
00377   else
00378   {
00379     //the message has multiple parts
00380 
00381     //get positions of a plain text and html flag (value of the content type attribute)
00382     int posPlainFlag = strBody.find( "text/plain", 0, false );
00383     int posHTMLFlag = strBody.find( "text/html", 0, false );
00384 
00385     //just decode the body, if a plain text or a HTML part is available
00386     if( posPlainFlag != -1 || posHTMLFlag != -1 )
00387     {
00388       //do we want to take the HTML part?
00389       bool hasHTML = posHTMLFlag != -1;
00390       bool takeHTML = ( hasHTML && preferHTML ) || posPlainFlag == -1;
00391 
00392       //now we want to extract the designated part
00393       //While the (truncated) mail text (or the header at the first pass)
00394       //contains a boundary attribute we will extract the designated part
00395       //between the boundaries
00396       int posInside;    //a position inside the designated part
00397       while( boundary != "" )
00398       {
00399         //get a position inside the designated part
00400         if( takeHTML )
00401           posInside = strBody.find( "text/html", 0, false );
00402         else
00403           posInside = strBody.find( "text/plain", 0, false );
00404 
00405         //get length of the boundary
00406         int lengthBoundary = boundary.length();
00407 
00408         //calculate the begin and end of the part to extract
00409         int beginPart = strBody.findRev( boundary.ascii(), posInside ) + lengthBoundary + 1;
00410         int lengthPart = strBody.findRev( '\n', strBody.find( boundary.ascii(), posInside ) ) - beginPart;
00411 
00412         strBody = strBody.mid( beginPart, lengthPart );
00413 
00414         //looking for a further boundary attribute
00415         //get the position of the first occurance of "boundary="
00416         int posBoundary = strBody.find( "boundary=", 0, false );
00417 
00418         if( posBoundary >= 0 )
00419         {
00420           //calculate positon of the first quote
00421           int posFirstQuote = posBoundary + 9;
00422 
00423           //get the position of closing quote
00424           int posSecondQuote = strBody.find( '"', posFirstQuote + 1 );
00425 
00426           //get boundary string
00427           boundary.append( strBody.mid( posFirstQuote + 1, posSecondQuote - posFirstQuote - 1 ) );
00428         }
00429         else
00430           boundary = "";
00431       }
00432 
00433       //now we get charset and transfer encoding if available in the extracted
00434       //part
00435 
00436       //get the position of the first occurance of "charset="
00437       int posCharset = strBody.find( "charset=", 0, false );
00438 
00439       //continue, if a charset attribute was found
00440       if( posCharset >= 0 )
00441       {
00442         //calculate positon of the value
00443         int posBeginValue = posCharset + 8;
00444 
00445         //get end of the value
00446         int posEndValue = strBody.find( '\n', posBeginValue ) - 1;
00447 
00448         //get charset
00449         charset.append( strBody.mid( posBeginValue, posEndValue - posBeginValue + 1 ) );
00450 
00451         //remove quotes
00452         charset.remove( '"' );
00453         //remove all content after the first semicolon (inclusive)
00454         int posSemicolon = charset.find( ';' );
00455         charset = charset.left( posSemicolon );
00456       }
00457 
00458       //get the position of the first occurance of "charset="
00459       int posEncoding = strBody.find( "Content-Transfer-Encoding:", 0, false );
00460 
00461       //continue, if a charset attribute was found
00462       if( posEncoding >= 0 )
00463       {
00464         //calculate positon of the value
00465         int posBeginValue = posEncoding + 26;
00466 
00467         //get end of the value
00468         int posEndValue = strBody.find( '\n', posBeginValue ) - 1;
00469 
00470         //get charset
00471         encoding.append( strBody.mid( posBeginValue, posEndValue - posBeginValue + 1 ) );
00472 
00473         //remove quotes and spaces
00474         encoding = encoding.stripWhiteSpace();
00475         encoding.remove( '"' );
00476       }
00477 
00478       //cut off the part header; the found blank line is separating the
00479       //part header from the message
00480       if( posCharset != -1 || posEncoding != -1 )
00481       {
00482         int posBlankLine = strBody.find( "\n\n" );
00483         strBody = strBody.mid( posBlankLine + 2 );
00484         while( strBody[ 0 ] == '\n')
00485           strBody.remove( 0, 1 );
00486       }
00487     }
00488   }
00489 
00490   //Good things come to those who wait. We have extract the message.
00491   //Now we have to decode the message, if it is encoded
00492   if( encoding == "quoted-printable" )
00493   {
00494     strBody = KCodecs::quotedPrintableDecode( strBody );
00495   }
00496 
00497   return TQString( strBody );
00498 }
00499 
00500 TQString ShowRecordElem::getBoundary( ) const
00501 {
00502   TQString boundary;
00503 
00504   //check, whether it is a multipart message
00505   if( m_content.contains( "multipart", false ) )
00506   {
00507     //it is a multipart message
00508 
00509     //get the position of the first occurance of "boundary="
00510     int posBoundary = m_header.find( "boundary=", 0, false );
00511 
00512     //continue, if a boundary attribute was found
00513     if( posBoundary >= 0 )
00514     {
00515       //calculate positon of the first quote
00516       int posFirstQuote = posBoundary + 9;
00517 
00518       //get the position of closing quote
00519       int posSecondQuote = m_header.find( '"', posFirstQuote + 1 );
00520 
00521       //get boundary string
00522       boundary.append( m_header.mid( posFirstQuote + 1, posSecondQuote - posFirstQuote - 1 ) );
00523     }
00524   }
00525 
00526   return boundary;
00527 }
00528 
00529 TQString ShowRecordElem::getCharset( ) const
00530 {
00531   TQString charset;
00532 
00533   //get the position of the first occurance of "charset="
00534   int posCharset = m_header.find( "charset=", 0, false );
00535 
00536   //continue, if a charset attribute was found
00537   if( posCharset >= 0 )
00538   {
00539     //calculate positon of the value
00540     int posBeginValue = posCharset + 8;
00541 
00542     //get end of the value
00543     int posEndValue = m_header.find( '\r', posBeginValue ) - 1;
00544 
00545     //get charset
00546     charset.append( m_header.mid( posBeginValue, posEndValue - posBeginValue + 1 ) );
00547 
00548     //remove quotes
00549     charset.remove( '"' );
00550     //remove all content after the first semicolon (inclusive)
00551     int posSemicolon = charset.find( ';' );
00552     charset = charset.left( posSemicolon );
00553   }
00554 
00555   return TQString( charset );
00556 }
00557 
00558 TQString ShowRecordElem::getTransferEncoding( ) const
00559 {
00560   TQString encoding;
00561 
00562   //get the position of the first occurance of "charset="
00563   int posEncoding = m_header.find( "Content-Transfer-Encoding:", 0, false );
00564 
00565   //continue, if a charset attribute was found
00566   if( posEncoding >= 0 )
00567   {
00568     //calculate positon of the value
00569     int posBeginValue = posEncoding + 26;
00570 
00571     //get end of the value
00572     int posEndValue = m_header.find( '\r', posBeginValue ) - 1;
00573 
00574     //get charset
00575     encoding.append( m_header.mid( posBeginValue, posEndValue - posBeginValue + 1 ) );
00576 
00577     //remove quotes and spaces
00578     encoding = encoding.stripWhiteSpace();
00579     encoding.remove( '"' );
00580   }
00581 
00582   return TQString( encoding );
00583 
00584 }
00585 
00586 int ShowRecordElem::showHeader( TQString& account )
00587 {
00588   //show header
00589   TQString tsubject = subject();
00590   TQString tmailheader = header();
00591 
00592   //create and open the window
00593   ShowHeaderDialog dlg( kapp->mainWidget(), account, tsubject, tmailheader );
00594   int ret = dlg.exec();
00595 
00596   //returns the matching value
00597   return ret == TQDialog::Accepted ? ShowRecordElem::continueShowHeaders : ShowRecordElem::cancelShowHeaders;
00598 }
00599 
00600 

Generated on Thu Jul 5 19:36:07 2007 for kshowmail by  doxygen 1.5.0