kmail

templateparser.cpp

00001 /*   -*- mode: C++; c-file-style: "gnu" -*-
00002  *   kmail: KDE mail client
00003  *   This file: Copyright (C) 2006 Dmitry Morozhnikov <dmiceman@mail.ru>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <qstring.h>
00024 #include <qdatetime.h>
00025 #include <klocale.h>
00026 #include <kcalendarsystem.h>
00027 #include <kmime_util.h>
00028 #include <kglobal.h>
00029 #include <kprocess.h>
00030 #include <qregexp.h>
00031 #include <qfile.h>
00032 #include <kmessagebox.h>
00033 #include <kshell.h>
00034 #include <qfileinfo.h>
00035 
00036 #include "kmmessage.h"
00037 #include "kmmsgbase.h"
00038 #include "kmfolder.h"
00039 #include "templatesconfiguration.h"
00040 #include "templatesconfiguration_kfg.h"
00041 #include "customtemplates_kfg.h"
00042 #include "globalsettings_base.h"
00043 #include "kmkernel.h"
00044 #include <libkpimidentities/identity.h>
00045 #include <libkpimidentities/identitymanager.h>
00046 
00047 #include "templateparser.h"
00048 #include <mimelib/bodypart.h>
00049 
00050 TemplateParser::TemplateParser( KMMessage *amsg, const Mode amode,
00051                                 const QString aselection,
00052                                 bool asmartQuote, bool anoQuote,
00053                                 bool aallowDecryption, bool aselectionIsBody ) :
00054   mMode( amode ), mFolder( 0 ), mIdentity( 0 ), mSelection( aselection ),
00055   mSmartQuote( asmartQuote ), mNoQuote( anoQuote ),
00056   mAllowDecryption( aallowDecryption ), mSelectionIsBody( aselectionIsBody ),
00057   mDebug( false ), mQuoteString( "> " ), mAppend( false )
00058 {
00059   mMsg = amsg;
00060 }
00061 
00062 int TemplateParser::parseQuotes( const QString &prefix, const QString &str,
00063                                  QString &quote ) const
00064 {
00065   int pos = prefix.length();
00066   int len;
00067   int str_len = str.length();
00068   QChar qc = '"';
00069   QChar prev = 0;
00070 
00071   pos++;
00072   len = pos;
00073 
00074   while ( pos < str_len ) {
00075     QChar c = str[pos];
00076 
00077     pos++;
00078     len++;
00079 
00080     if ( prev ) {
00081       quote.append( c );
00082       prev = 0;
00083     } else {
00084       if ( c == '\\' ) {
00085         prev = c;
00086       } else if ( c == qc ) {
00087         break;
00088       } else {
00089         quote.append( c );
00090       }
00091     }
00092   }
00093 
00094   return len;
00095 }
00096 
00097 QString TemplateParser::getFName( const QString &str )
00098 {
00099   // simple logic:
00100   // if there is ',' in name, than format is 'Last, First'
00101   // else format is 'First Last'
00102   // last resort -- return 'name' from 'name@domain'
00103   int sep_pos;
00104   QString res;
00105   if ( ( sep_pos = str.find( '@' ) ) > 0 ) {
00106     int i;
00107     for ( i = (sep_pos - 1); i >= 0; --i ) {
00108       QChar c = str[i];
00109       if ( c.isLetterOrNumber() ) {
00110         res.prepend( c );
00111       } else {
00112         break;
00113       }
00114     }
00115   } else if ( ( sep_pos = str.find(',') ) > 0 ) {
00116     unsigned int i;
00117     bool begin = false;
00118     for ( i = sep_pos; i < str.length(); ++i ) {
00119       QChar c = str[i];
00120       if ( c.isLetterOrNumber() ) {
00121         begin = true;
00122         res.append( c );
00123       } else if ( begin ) {
00124         break;
00125       }
00126     }
00127   } else {
00128     unsigned int i;
00129     for ( i = 0; i < str.length(); ++i ) {
00130       QChar c = str[i];
00131       if ( c.isLetterOrNumber() ) {
00132         res.append( c );
00133       } else {
00134         break;
00135       }
00136     }
00137   }
00138   return res;
00139 }
00140 
00141 QString TemplateParser::getLName( const QString &str )
00142 {
00143   // simple logic:
00144   // if there is ',' in name, than format is 'Last, First'
00145   // else format is 'First Last'
00146   int sep_pos;
00147   QString res;
00148   if ( ( sep_pos = str.find(',') ) > 0 ) {
00149     int i;
00150     for ( i = sep_pos; i >= 0; --i ) {
00151       QChar c = str[i];
00152       if ( c.isLetterOrNumber() ) {
00153         res.prepend( c );
00154       } else {
00155         break;
00156       }
00157     }
00158   } else {
00159     if ( ( sep_pos = str.find( ' ' ) ) > 0 ) {
00160       unsigned int i;
00161       bool begin = false;
00162       for ( i = sep_pos; i < str.length(); ++i ) {
00163         QChar c = str[i];
00164         if ( c.isLetterOrNumber() ) {
00165           begin = true;
00166           res.append( c );
00167         } else if ( begin ) {
00168           break;
00169         }
00170       }
00171     }
00172   }
00173   return res;
00174 }
00175 
00176 void TemplateParser::process( KMMessage *aorig_msg, KMFolder *afolder, bool append )
00177 {
00178   mAppend = append;
00179   mOrigMsg = aorig_msg;
00180   mFolder = afolder;
00181   QString tmpl = findTemplate();
00182   return processWithTemplate( tmpl );
00183 }
00184 
00185 void TemplateParser::process( const QString &tmplName, KMMessage *aorig_msg,
00186                               KMFolder *afolder, bool append )
00187 {
00188   mAppend = append;
00189   mOrigMsg = aorig_msg;
00190   mFolder = afolder;
00191   QString tmpl = findCustomTemplate( tmplName );
00192   return processWithTemplate( tmpl );
00193 }
00194 
00195 void TemplateParser::processWithTemplate( const QString &tmpl )
00196 {
00197   QString body;
00198   int tmpl_len = tmpl.length();
00199   bool dnl = false;
00200   for ( int i = 0; i < tmpl_len; ++i ) {
00201     QChar c = tmpl[i];
00202     // kdDebug() << "Next char: " << c << endl;
00203     if ( c == '%' ) {
00204       QString cmd = tmpl.mid( i + 1 );
00205 
00206       if ( cmd.startsWith( "-" ) ) {
00207         // dnl
00208         kdDebug() << "Command: -" << endl;
00209         dnl = true;
00210         i += 1;
00211 
00212       } else if ( cmd.startsWith( "REM=" ) ) {
00213         // comments
00214         kdDebug() << "Command: REM=" << endl;
00215         QString q;
00216         int len = parseQuotes( "REM=", cmd, q );
00217         i += len;
00218 
00219       } else if ( cmd.startsWith( "INSERT=" ) ) {
00220         // insert content of specified file as is
00221         kdDebug() << "Command: INSERT=" << endl;
00222         QString q;
00223         int len = parseQuotes( "INSERT=", cmd, q );
00224         i += len;
00225         QString path = KShell::tildeExpand( q );
00226         QFileInfo finfo( path );
00227         if (finfo.isRelative() ) {
00228           path = KShell::homeDir( "" );
00229           path += '/';
00230           path += q;
00231         }
00232         QFile file( path );
00233         if ( file.open( IO_ReadOnly ) ) {
00234           QByteArray content = file.readAll();
00235           QString str = QString::fromLocal8Bit( content, content.size() );
00236           body.append( str );
00237         } else if ( mDebug ) {
00238           KMessageBox::error( 0,
00239                               i18n( "Cannot insert content from file %1: %2" ).
00240                               arg( path ).arg( file.errorString() ) );
00241         }
00242 
00243       } else if ( cmd.startsWith( "SYSTEM=" ) ) {
00244         // insert content of specified file as is
00245         kdDebug() << "Command: SYSTEM=" << endl;
00246         QString q;
00247         int len = parseQuotes( "SYSTEM=", cmd, q );
00248         i += len;
00249         QString pipe_cmd = q;
00250         QString str = pipe( pipe_cmd, "" );
00251         body.append( str );
00252 
00253       } else if ( cmd.startsWith( "PUT=" ) ) {
00254         // insert content of specified file as is
00255         kdDebug() << "Command: PUT=" << endl;
00256         QString q;
00257         int len = parseQuotes( "PUT=", cmd, q );
00258         i += len;
00259         QString path = KShell::tildeExpand( q );
00260         QFileInfo finfo( path );
00261         if (finfo.isRelative() ) {
00262           path = KShell::homeDir( "" );
00263           path += '/';
00264           path += q;
00265         }
00266         QFile file( path );
00267         if ( file.open( IO_ReadOnly ) ) {
00268           QByteArray content = file.readAll();
00269           body.append( QString::fromLocal8Bit( content, content.size() ) );
00270         } else if ( mDebug ) {
00271           KMessageBox::error( 0,
00272                               i18n( "Cannot insert content from file %1: %2").
00273                               arg( path ).arg(file.errorString() ));
00274         }
00275 
00276       } else if ( cmd.startsWith( "QUOTEPIPE=" ) ) {
00277         // pipe message body throw command and insert it as quotation
00278         kdDebug() << "Command: QUOTEPIPE=" << endl;
00279         QString q;
00280         int len = parseQuotes( "QUOTEPIPE=", cmd, q );
00281         i += len;
00282         QString pipe_cmd = q;
00283         if ( mOrigMsg && !mNoQuote ) {
00284           QString str = pipe( pipe_cmd, mSelection );
00285           QString quote = mOrigMsg->asQuotedString( "", mQuoteString, str,
00286                                                     mSmartQuote, mAllowDecryption );
00287           body.append( quote );
00288         }
00289 
00290       } else if ( cmd.startsWith( "QUOTE" ) ) {
00291         kdDebug() << "Command: QUOTE" << endl;
00292         i += strlen( "QUOTE" );
00293         if ( mOrigMsg && !mNoQuote ) {
00294           QString quote = mOrigMsg->asQuotedString( "", mQuoteString, mSelection,
00295                                                     mSmartQuote, mAllowDecryption );
00296           body.append( quote );
00297         }
00298 
00299       } else if ( cmd.startsWith( "QHEADERS" ) ) {
00300         kdDebug() << "Command: QHEADERS" << endl;
00301         i += strlen( "QHEADERS" );
00302         if ( mOrigMsg && !mNoQuote ) {
00303           QString quote = mOrigMsg->asQuotedString( "", mQuoteString,
00304                                                     mOrigMsg->headerAsSendableString(),
00305                                                     mSmartQuote, false );
00306           body.append( quote );
00307         }
00308 
00309       } else if ( cmd.startsWith( "HEADERS" ) ) {
00310         kdDebug() << "Command: HEADERS" << endl;
00311         i += strlen( "HEADERS" );
00312         if ( mOrigMsg && !mNoQuote ) {
00313           QString str = mOrigMsg->headerAsSendableString();
00314           body.append( str );
00315         }
00316 
00317       } else if ( cmd.startsWith( "TEXTPIPE=" ) ) {
00318         // pipe message body throw command and insert it as is
00319         kdDebug() << "Command: TEXTPIPE=" << endl;
00320         QString q;
00321         int len = parseQuotes( "TEXTPIPE=", cmd, q );
00322         i += len;
00323         QString pipe_cmd = q;
00324         if ( mOrigMsg ) {
00325           QString str = pipe(pipe_cmd, mSelection );
00326           body.append( str );
00327         }
00328 
00329       } else if ( cmd.startsWith( "MSGPIPE=" ) ) {
00330         // pipe full message throw command and insert result as is
00331         kdDebug() << "Command: MSGPIPE=" << endl;
00332         QString q;
00333         int len = parseQuotes( "MSGPIPE=", cmd, q );
00334         i += len;
00335         QString pipe_cmd = q;
00336         if ( mOrigMsg ) {
00337           QString str = pipe(pipe_cmd, mOrigMsg->asString() );
00338           body.append( str );
00339         }
00340 
00341       } else if ( cmd.startsWith( "BODYPIPE=" ) ) {
00342         // pipe message body generated so far throw command and insert result as is
00343         kdDebug() << "Command: BODYPIPE=" << endl;
00344         QString q;
00345         int len = parseQuotes( "BODYPIPE=", cmd, q );
00346         i += len;
00347         QString pipe_cmd = q;
00348         QString str = pipe( pipe_cmd, body );
00349         body.append( str );
00350 
00351       } else if ( cmd.startsWith( "CLEARPIPE=" ) ) {
00352         // pipe message body generated so far throw command and
00353         // insert result as is replacing current body
00354         kdDebug() << "Command: CLEARPIPE=" << endl;
00355         QString q;
00356         int len = parseQuotes( "CLEARPIPE=", cmd, q );
00357         i += len;
00358         QString pipe_cmd = q;
00359         QString str = pipe( pipe_cmd, body );
00360         body = str;
00361         mMsg->setCursorPos( 0 );
00362 
00363       } else if ( cmd.startsWith( "TEXT" ) ) {
00364         kdDebug() << "Command: TEXT" << endl;
00365         i += strlen( "TEXT" );
00366         if ( mOrigMsg ) {
00367           QString quote = mOrigMsg->asPlainText( false, mAllowDecryption );
00368           body.append( quote );
00369         }
00370 
00371       } else if ( cmd.startsWith( "OTEXTSIZE" ) ) {
00372         kdDebug() << "Command: OTEXTSIZE" << endl;
00373         i += strlen( "OTEXTSIZE" );
00374         if ( mOrigMsg ) {
00375           QString str = QString( "%1" ).arg( mOrigMsg->body().length() );
00376           body.append( str );
00377         }
00378 
00379       } else if ( cmd.startsWith( "OTEXT" ) ) {
00380         kdDebug() << "Command: OTEXT" << endl;
00381         i += strlen( "OTEXT" );
00382         if ( mOrigMsg ) {
00383           QString quote = mOrigMsg->asPlainText( false, mAllowDecryption );
00384           body.append( quote );
00385         }
00386 
00387       } else if ( cmd.startsWith( "CCADDR" ) ) {
00388         kdDebug() << "Command: CCADDR" << endl;
00389         i += strlen( "CCADDR" );
00390         QString str = mMsg->cc();
00391         body.append( str );
00392 
00393       } else if ( cmd.startsWith( "CCNAME" ) ) {
00394         kdDebug() << "Command: CCNAME" << endl;
00395         i += strlen( "CCNAME" );
00396         QString str = mMsg->ccStrip();
00397         body.append( str );
00398 
00399       } else if ( cmd.startsWith( "CCFNAME" ) ) {
00400         kdDebug() << "Command: CCFNAME" << endl;
00401         i += strlen( "CCFNAME" );
00402         QString str = mMsg->ccStrip();
00403         body.append( getFName( str ) );
00404 
00405       } else if ( cmd.startsWith( "CCLNAME" ) ) {
00406         kdDebug() << "Command: CCLNAME" << endl;
00407         i += strlen( "CCLNAME" );
00408         QString str = mMsg->ccStrip();
00409         body.append( getLName( str ) );
00410 
00411       } else if ( cmd.startsWith( "TOADDR" ) ) {
00412         kdDebug() << "Command: TOADDR" << endl;
00413         i += strlen( "TOADDR" );
00414         QString str = mMsg->to();
00415         body.append( str );
00416 
00417       } else if ( cmd.startsWith( "TONAME" ) ) {
00418         kdDebug() << "Command: TONAME" << endl;
00419         i += strlen( "TONAME" );
00420         QString str = mMsg->toStrip();
00421         body.append( str );
00422 
00423       } else if ( cmd.startsWith( "TOFNAME" ) ) {
00424         kdDebug() << "Command: TOFNAME" << endl;
00425         i += strlen( "TOFNAME" );
00426         QString str = mMsg->toStrip();
00427         body.append( getFName( str ) );
00428 
00429       } else if ( cmd.startsWith( "TOLNAME" ) ) {
00430         kdDebug() << "Command: TOLNAME" << endl;
00431         i += strlen( "TOLNAME" );
00432         QString str = mMsg->toStrip();
00433         body.append( getLName( str ) );
00434 
00435       } else if ( cmd.startsWith( "TOLIST" ) ) {
00436         kdDebug() << "Command: TOLIST" << endl;
00437         i += strlen( "TOLIST" );
00438         QString str = mMsg->to();
00439         body.append( str );
00440 
00441       } else if ( cmd.startsWith( "FROMADDR" ) ) {
00442         kdDebug() << "Command: FROMADDR" << endl;
00443         i += strlen( "FROMADDR" );
00444         QString str = mMsg->from();
00445         body.append( str );
00446 
00447       } else if ( cmd.startsWith( "FROMNAME" ) ) {
00448         kdDebug() << "Command: FROMNAME" << endl;
00449         i += strlen( "FROMNAME" );
00450         QString str = mMsg->fromStrip();
00451         body.append( str );
00452 
00453       } else if ( cmd.startsWith( "FROMFNAME" ) ) {
00454         kdDebug() << "Command: FROMFNAME" << endl;
00455         i += strlen( "FROMFNAME" );
00456         QString str = mMsg->fromStrip();
00457         body.append( getFName( str ) );
00458 
00459       } else if ( cmd.startsWith( "FROMLNAME" ) ) {
00460         kdDebug() << "Command: FROMLNAME" << endl;
00461         i += strlen( "FROMLNAME" );
00462         QString str = mMsg->fromStrip();
00463         body.append( getLName( str ) );
00464 
00465       } else if ( cmd.startsWith( "FULLSUBJECT" ) ) {
00466         kdDebug() << "Command: FULLSUBJECT" << endl;
00467         i += strlen( "FULLSUBJECT" );
00468         QString str = mMsg->subject();
00469         body.append( str );
00470 
00471       } else if ( cmd.startsWith( "FULLSUBJ" ) ) {
00472         kdDebug() << "Command: FULLSUBJ" << endl;
00473         i += strlen( "FULLSUBJ" );
00474         QString str = mMsg->subject();
00475         body.append( str );
00476 
00477       } else if ( cmd.startsWith( "MSGID" ) ) {
00478         kdDebug() << "Command: MSGID" << endl;
00479         i += strlen( "MSGID" );
00480         QString str = mMsg->id();
00481         body.append( str );
00482 
00483       } else if ( cmd.startsWith( "OHEADER=" ) ) {
00484         // insert specified content of header from original message
00485         kdDebug() << "Command: OHEADER=" << endl;
00486         QString q;
00487         int len = parseQuotes( "OHEADER=", cmd, q );
00488         i += len;
00489         if ( mOrigMsg ) {
00490           QString hdr = q;
00491           QString str = mOrigMsg->headerFields(hdr.local8Bit() ).join( ", " );
00492           body.append( str );
00493         }
00494 
00495       } else if ( cmd.startsWith( "HEADER=" ) ) {
00496         // insert specified content of header from current message
00497         kdDebug() << "Command: HEADER=" << endl;
00498         QString q;
00499         int len = parseQuotes( "HEADER=", cmd, q );
00500         i += len;
00501         QString hdr = q;
00502         QString str = mMsg->headerFields(hdr.local8Bit() ).join( ", " );
00503         body.append( str );
00504 
00505       } else if ( cmd.startsWith( "HEADER( " ) ) {
00506         // insert specified content of header from current message
00507         kdDebug() << "Command: HEADER( " << endl;
00508         QRegExp re = QRegExp( "^HEADER\\((.+)\\)" );
00509         re.setMinimal( true );
00510         int res = re.search( cmd );
00511         if ( res != 0 ) {
00512           // something wrong
00513           i += strlen( "HEADER( " );
00514         } else {
00515           i += re.matchedLength();
00516           QString hdr = re.cap( 1 );
00517           QString str = mMsg->headerFields( hdr.local8Bit() ).join( ", " );
00518           body.append( str );
00519         }
00520 
00521       } else if ( cmd.startsWith( "OCCADDR" ) ) {
00522         kdDebug() << "Command: OCCADDR" << endl;
00523         i += strlen( "OCCADDR" );
00524         if ( mOrigMsg ) {
00525           QString str = mOrigMsg->cc();
00526           body.append( str );
00527         }
00528 
00529       } else if ( cmd.startsWith( "OCCNAME" ) ) {
00530         kdDebug() << "Command: OCCNAME" << endl;
00531         i += strlen( "OCCNAME" );
00532         if ( mOrigMsg ) {
00533           QString str = mOrigMsg->ccStrip();
00534           body.append( str );
00535         }
00536 
00537       } else if ( cmd.startsWith( "OCCFNAME" ) ) {
00538         kdDebug() << "Command: OCCFNAME" << endl;
00539         i += strlen( "OCCFNAME" );
00540         if ( mOrigMsg ) {
00541           QString str = mOrigMsg->ccStrip();
00542           body.append( getFName( str ) );
00543         }
00544 
00545       } else if ( cmd.startsWith( "OCCLNAME" ) ) {
00546         kdDebug() << "Command: OCCLNAME" << endl;
00547         i += strlen( "OCCLNAME" );
00548         if ( mOrigMsg ) {
00549           QString str = mOrigMsg->ccStrip();
00550           body.append( getLName( str ) );
00551         }
00552 
00553       } else if ( cmd.startsWith( "OTOADDR" ) ) {
00554         kdDebug() << "Command: OTOADDR" << endl;
00555         i += strlen( "OTOADDR" );
00556         if ( mOrigMsg ) {
00557           QString str = mOrigMsg->to();
00558           body.append( str );
00559         }
00560 
00561       } else if ( cmd.startsWith( "OTONAME" ) ) {
00562         kdDebug() << "Command: OTONAME" << endl;
00563         i += strlen( "OTONAME" );
00564         if ( mOrigMsg ) {
00565           QString str = mOrigMsg->toStrip();
00566           body.append( str );
00567         }
00568 
00569       } else if ( cmd.startsWith( "OTOFNAME" ) ) {
00570         kdDebug() << "Command: OTOFNAME" << endl;
00571         i += strlen( "OTOFNAME" );
00572         if ( mOrigMsg ) {
00573           QString str = mOrigMsg->toStrip();
00574           body.append( getFName( str ) );
00575         }
00576 
00577       } else if ( cmd.startsWith( "OTOLNAME" ) ) {
00578         kdDebug() << "Command: OTOLNAME" << endl;
00579         i += strlen( "OTOLNAME" );
00580         if ( mOrigMsg ) {
00581           QString str = mOrigMsg->toStrip();
00582           body.append( getLName( str ) );
00583         }
00584 
00585       } else if ( cmd.startsWith( "OTOLIST" ) ) {
00586         kdDebug() << "Command: OTOLIST" << endl;
00587         i += strlen( "OTOLIST" );
00588         if ( mOrigMsg ) {
00589           QString str = mOrigMsg->to();
00590           body.append( str );
00591         }
00592 
00593       } else if ( cmd.startsWith( "OTO" ) ) {
00594         kdDebug() << "Command: OTO" << endl;
00595         i += strlen( "OTO" );
00596         if ( mOrigMsg ) {
00597           QString str = mOrigMsg->to();
00598           body.append( str );
00599         }
00600 
00601       } else if ( cmd.startsWith( "OFROMADDR" ) ) {
00602         kdDebug() << "Command: OFROMADDR" << endl;
00603         i += strlen( "OFROMADDR" );
00604         if ( mOrigMsg ) {
00605           QString str = mOrigMsg->from();
00606           body.append( str );
00607         }
00608 
00609       } else if ( cmd.startsWith( "OFROMNAME" ) ) {
00610         kdDebug() << "Command: OFROMNAME" << endl;
00611         i += strlen( "OFROMNAME" );
00612         if ( mOrigMsg ) {
00613           QString str = mOrigMsg->fromStrip();
00614           body.append( str );
00615         }
00616 
00617       } else if ( cmd.startsWith( "OFROMFNAME" ) ) {
00618         kdDebug() << "Command: OFROMFNAME" << endl;
00619         i += strlen( "OFROMFNAME" );
00620         if ( mOrigMsg ) {
00621           QString str = mOrigMsg->fromStrip();
00622           body.append( getFName( str ) );
00623         }
00624 
00625       } else if ( cmd.startsWith( "OFROMLNAME" ) ) {
00626         kdDebug() << "Command: OFROMLNAME" << endl;
00627         i += strlen( "OFROMLNAME" );
00628         if ( mOrigMsg ) {
00629           QString str = mOrigMsg->fromStrip();
00630           body.append( getLName( str ) );
00631         }
00632 
00633       } else if ( cmd.startsWith( "OFULLSUBJECT" ) ) {
00634         kdDebug() << "Command: OFULLSUBJECT" << endl;
00635         i += strlen( "OFULLSUBJECT" );
00636         if ( mOrigMsg ) {
00637           QString str = mOrigMsg->subject();
00638           body.append( str );
00639         }
00640 
00641       } else if ( cmd.startsWith( "OFULLSUBJ" ) ) {
00642         kdDebug() << "Command: OFULLSUBJ" << endl;
00643         i += strlen( "OFULLSUBJ" );
00644         if ( mOrigMsg ) {
00645           QString str = mOrigMsg->subject();
00646           body.append( str );
00647         }
00648 
00649       } else if ( cmd.startsWith( "OMSGID" ) ) {
00650         kdDebug() << "Command: OMSGID" << endl;
00651         i += strlen( "OMSGID" );
00652         if ( mOrigMsg ) {
00653           QString str = mOrigMsg->id();
00654           body.append( str );
00655         }
00656 
00657       } else if ( cmd.startsWith( "DATEEN" ) ) {
00658         kdDebug() << "Command: DATEEN" << endl;
00659         i += strlen( "DATEEN" );
00660         QDateTime date = QDateTime::currentDateTime();
00661         KLocale locale( "C" );
00662         QString str = locale.formatDate( date.date(), false );
00663         body.append( str );
00664 
00665       } else if ( cmd.startsWith( "DATESHORT" ) ) {
00666         kdDebug() << "Command: DATESHORT" << endl;
00667         i += strlen( "DATESHORT" );
00668         QDateTime date = QDateTime::currentDateTime();
00669         QString str = KGlobal::locale()->formatDate( date.date(), true );
00670         body.append( str );
00671 
00672       } else if ( cmd.startsWith( "DATE" ) ) {
00673         kdDebug() << "Command: DATE" << endl;
00674         i += strlen( "DATE" );
00675         QDateTime date = QDateTime::currentDateTime();
00676         QString str = KGlobal::locale()->formatDate( date.date(), false );
00677         body.append( str );
00678 
00679       } else if ( cmd.startsWith( "DOW" ) ) {
00680         kdDebug() << "Command: DOW" << endl;
00681         i += strlen( "DOW" );
00682         QDateTime date = QDateTime::currentDateTime();
00683         QString str = KGlobal::locale()->calendar()->weekDayName( date.date(), false );
00684         body.append( str );
00685 
00686       } else if ( cmd.startsWith( "TIMELONGEN" ) ) {
00687         kdDebug() << "Command: TIMELONGEN" << endl;
00688         i += strlen( "TIMELONGEN" );
00689         QDateTime date = QDateTime::currentDateTime();
00690         KLocale locale( "C");
00691         QString str = locale.formatTime( date.time(), true );
00692         body.append( str );
00693 
00694       } else if ( cmd.startsWith( "TIMELONG" ) ) {
00695         kdDebug() << "Command: TIMELONG" << endl;
00696         i += strlen( "TIMELONG" );
00697         QDateTime date = QDateTime::currentDateTime();
00698         QString str = KGlobal::locale()->formatTime( date.time(), true );
00699         body.append( str );
00700 
00701       } else if ( cmd.startsWith( "TIME" ) ) {
00702         kdDebug() << "Command: TIME" << endl;
00703         i += strlen( "TIME" );
00704         QDateTime date = QDateTime::currentDateTime();
00705         QString str = KGlobal::locale()->formatTime( date.time(), false );
00706         body.append( str );
00707 
00708       } else if ( cmd.startsWith( "ODATEEN" ) ) {
00709         kdDebug() << "Command: ODATEEN" << endl;
00710         i += strlen( "ODATEEN" );
00711         if ( mOrigMsg ) {
00712           QDateTime date;
00713           date.setTime_t( mOrigMsg->date() );
00714           KLocale locale( "C");
00715           QString str = locale.formatDate( date.date(), false );
00716           body.append( str );
00717         }
00718 
00719       } else if ( cmd.startsWith( "ODATESHORT") ) {
00720         kdDebug() << "Command: ODATESHORT" << endl;
00721         i += strlen( "ODATESHORT");
00722         if ( mOrigMsg ) {
00723           QDateTime date;
00724           date.setTime_t( mOrigMsg->date() );
00725           QString str = KGlobal::locale()->formatDate( date.date(), true );
00726           body.append( str );
00727         }
00728 
00729       } else if ( cmd.startsWith( "ODATE") ) {
00730         kdDebug() << "Command: ODATE" << endl;
00731         i += strlen( "ODATE");
00732         if ( mOrigMsg ) {
00733           QDateTime date;
00734           date.setTime_t( mOrigMsg->date() );
00735           QString str = KGlobal::locale()->formatDate( date.date(), false );
00736           body.append( str );
00737         }
00738 
00739       } else if ( cmd.startsWith( "ODOW") ) {
00740         kdDebug() << "Command: ODOW" << endl;
00741         i += strlen( "ODOW");
00742         if ( mOrigMsg ) {
00743           QDateTime date;
00744           date.setTime_t( mOrigMsg->date() );
00745           QString str = KGlobal::locale()->calendar()->weekDayName( date.date(), false );
00746           body.append( str );
00747         }
00748 
00749       } else if ( cmd.startsWith( "OTIMELONGEN") ) {
00750         kdDebug() << "Command: OTIMELONGEN" << endl;
00751         i += strlen( "OTIMELONGEN");
00752         if ( mOrigMsg ) {
00753           QDateTime date;
00754           date.setTime_t( mOrigMsg->date() );
00755           KLocale locale( "C");
00756           QString str = locale.formatTime( date.time(), true );
00757           body.append( str );
00758         }
00759 
00760       } else if ( cmd.startsWith( "OTIMELONG") ) {
00761         kdDebug() << "Command: OTIMELONG" << endl;
00762         i += strlen( "OTIMELONG");
00763         if ( mOrigMsg ) {
00764           QDateTime date;
00765           date.setTime_t( mOrigMsg->date() );
00766           QString str = KGlobal::locale()->formatTime( date.time(), true );
00767           body.append( str );
00768         }
00769 
00770       } else if ( cmd.startsWith( "OTIME") ) {
00771         kdDebug() << "Command: OTIME" << endl;
00772         i += strlen( "OTIME");
00773         if ( mOrigMsg ) {
00774           QDateTime date;
00775           date.setTime_t( mOrigMsg->date() );
00776           QString str = KGlobal::locale()->formatTime( date.time(), false );
00777           body.append( str );
00778         }
00779 
00780       } else if ( cmd.startsWith( "BLANK" ) ) {
00781         // do nothing
00782         kdDebug() << "Command: BLANK" << endl;
00783         i += strlen( "BLANK" );
00784 
00785       } else if ( cmd.startsWith( "NOP" ) ) {
00786         // do nothing
00787         kdDebug() << "Command: NOP" << endl;
00788         i += strlen( "NOP" );
00789 
00790       } else if ( cmd.startsWith( "CLEAR" ) ) {
00791         // clear body buffer; not too useful yet
00792         kdDebug() << "Command: CLEAR" << endl;
00793         i += strlen( "CLEAR" );
00794         body = "";
00795         mMsg->setCursorPos( 0 );
00796 
00797       } else if ( cmd.startsWith( "DEBUGOFF" ) ) {
00798         // turn off debug
00799         kdDebug() << "Command: DEBUGOFF" << endl;
00800         i += strlen( "DEBUGOFF" );
00801         mDebug = false;
00802 
00803       } else if ( cmd.startsWith( "DEBUG" ) ) {
00804         // turn on debug
00805         kdDebug() << "Command: DEBUG" << endl;
00806         i += strlen( "DEBUG" );
00807         mDebug = true;
00808 
00809       } else if ( cmd.startsWith( "CURSOR" ) ) {
00810         // turn on debug
00811         kdDebug() << "Command: CURSOR" << endl;
00812         i += strlen( "CURSOR" );
00813         mMsg->setCursorPos( body.length() );
00814 
00815       } else {
00816         // wrong command, do nothing
00817         body.append( c );
00818       }
00819 
00820     } else if ( dnl && ( c == '\n' || c == '\r') ) {
00821       // skip
00822       if ( ( c == '\n' && tmpl[i + 1] == '\r' ) ||
00823            ( c == '\r' && tmpl[i + 1] == '\n' ) ) {
00824         // skip one more
00825         i += 1;
00826       }
00827       dnl = false;
00828     } else {
00829       body.append( c );
00830     }
00831   }
00832 
00833   // kdDebug(5006) << "Message body: " << body << endl;
00834 
00835   if ( mAppend ) {
00836     QCString msg_body = mMsg->body();
00837     msg_body.append( body.utf8() );
00838     mMsg->setBody( msg_body );
00839   } else {
00840     DwEntity *entityToChange = 0;
00841     if ( mMsg->typeStr().lower() == "multipart" ) {
00842       entityToChange = mMsg->findDwBodyPart( "text", "plain" );
00843       if ( !entityToChange )
00844         kdWarning() << "No text/plain part found in this multipart message, "
00845                        "template parser can not set the text!" << endl;
00846     }
00847 
00848     mMsg->setBodyFromUnicode( body, entityToChange );
00849   }
00850 }
00851 
00852 QString TemplateParser::findCustomTemplate( const QString &tmplName )
00853 {
00854   CTemplates t( tmplName );
00855   QString content = t.content();
00856   if ( !content.isEmpty() ) {
00857     return content;
00858   } else {
00859     return findTemplate();
00860   }
00861 }
00862 
00863 QString TemplateParser::findTemplate()
00864 {
00865   // import 'Phrases' if it not done yet
00866   if ( !GlobalSettings::self()->phrasesConverted() ) {
00867     TemplatesConfiguration::importFromPhrases();
00868   }
00869 
00870   // kdDebug() << "Trying to find template for mode " << mode << endl;
00871 
00872   QString tmpl;
00873 
00874   if ( !mFolder ) { // find folder message belongs to
00875     mFolder = mMsg->parent();
00876     if ( !mFolder ) {
00877       if ( mOrigMsg ) {
00878         mFolder = mOrigMsg->parent();
00879       }
00880       if ( !mFolder ) {
00881         kdDebug(5006) << "Oops! No folder for message" << endl;
00882       }
00883     }
00884   }
00885   kdDebug(5006) << "Folder found: " << mFolder << endl;
00886 
00887   if ( mFolder )  // only if a folder was found
00888   {
00889     QString fid = mFolder->idString();
00890     Templates fconf( fid );
00891     if ( fconf.useCustomTemplates() ) {   // does folder use custom templates?
00892       switch( mMode ) {
00893       case NewMessage:
00894         tmpl = fconf.templateNewMessage();
00895         break;
00896       case Reply:
00897         tmpl = fconf.templateReply();
00898         break;
00899       case ReplyAll:
00900         tmpl = fconf.templateReplyAll();
00901         break;
00902       case Forward:
00903         tmpl = fconf.templateForward();
00904         break;
00905       default:
00906         kdDebug(5006) << "Unknown message mode: " << mMode << endl;
00907         return "";
00908       }
00909       mQuoteString = fconf.quoteString();
00910       if ( !tmpl.isEmpty() ) {
00911         return tmpl;  // use folder-specific template
00912       }
00913     }
00914   }
00915 
00916   if ( !mIdentity ) { // find identity message belongs to
00917     mIdentity = mMsg->identityUoid();
00918     if ( !mIdentity && mOrigMsg ) {
00919       mIdentity = mOrigMsg->identityUoid();
00920     }
00921     mIdentity = kmkernel->identityManager()->identityForUoidOrDefault( mIdentity ).uoid();
00922     if ( !mIdentity ) {
00923       kdDebug(5006) << "Oops! No identity for message" << endl;
00924     }
00925   }
00926   kdDebug(5006) << "Identity found: " << mIdentity << endl;
00927 
00928   QString iid;
00929   if ( mIdentity ) {
00930     iid = QString("IDENTITY_%1").arg( mIdentity );  // templates ID for that identity
00931   }
00932   else {
00933     iid = "IDENTITY_NO_IDENTITY"; // templates ID for no identity
00934   }
00935 
00936   Templates iconf( iid );
00937   if ( iconf.useCustomTemplates() ) { // does identity use custom templates?
00938     switch( mMode ) {
00939     case NewMessage:
00940       tmpl = iconf.templateNewMessage();
00941       break;
00942     case Reply:
00943       tmpl = iconf.templateReply();
00944       break;
00945     case ReplyAll:
00946       tmpl = iconf.templateReplyAll();
00947       break;
00948     case Forward:
00949       tmpl = iconf.templateForward();
00950       break;
00951     default:
00952       kdDebug(5006) << "Unknown message mode: " << mMode << endl;
00953       return "";
00954     }
00955     mQuoteString = iconf.quoteString();
00956     if ( !tmpl.isEmpty() ) {
00957       return tmpl;  // use identity-specific template
00958     }
00959   }
00960 
00961   switch( mMode ) { // use the global template
00962   case NewMessage:
00963     tmpl = GlobalSettings::self()->templateNewMessage();
00964     break;
00965   case Reply:
00966     tmpl = GlobalSettings::self()->templateReply();
00967     break;
00968   case ReplyAll:
00969     tmpl = GlobalSettings::self()->templateReplyAll();
00970     break;
00971   case Forward:
00972     tmpl = GlobalSettings::self()->templateForward();
00973     break;
00974   default:
00975     kdDebug(5006) << "Unknown message mode: " << mMode << endl;
00976     return "";
00977   }
00978 
00979   mQuoteString = GlobalSettings::self()->quoteString();
00980   return tmpl;
00981 }
00982 
00983 QString TemplateParser::pipe( const QString &cmd, const QString &buf )
00984 {
00985   mPipeOut = "";
00986   mPipeErr = "";
00987   mPipeRc = 0;
00988 
00989   KProcess proc;
00990   QCString data = buf.local8Bit();
00991 
00992   // kdDebug() << "Command data: " << data << endl;
00993 
00994   proc << KShell::splitArgs( cmd, KShell::TildeExpand );
00995   proc.setUseShell( true );
00996   connect( &proc, SIGNAL( receivedStdout( KProcess *, char *, int ) ),
00997            this, SLOT( onReceivedStdout( KProcess *, char *, int ) ) );
00998   connect( &proc, SIGNAL( receivedStderr( KProcess *, char *, int ) ),
00999            this, SLOT( onReceivedStderr( KProcess *, char *, int ) ) );
01000   connect( &proc, SIGNAL( wroteStdin( KProcess * ) ),
01001            this, SLOT( onWroteStdin( KProcess * ) ) );
01002 
01003   if ( proc.start( KProcess::NotifyOnExit, KProcess::All ) ) {
01004 
01005     bool pipe_filled = proc.writeStdin( data, data.length() );
01006     if ( pipe_filled ) {
01007       proc.closeStdin();
01008 
01009       bool exited = proc.wait( PipeTimeout );
01010       if ( exited ) {
01011 
01012         if ( proc.normalExit() ) {
01013 
01014           mPipeRc = proc.exitStatus();
01015           if ( mPipeRc != 0 && mDebug ) {
01016             if ( mPipeErr.isEmpty() ) {
01017               KMessageBox::error( 0,
01018                                   i18n( "Pipe command exit with status %1: %2").
01019                                   arg( mPipeRc ).arg( cmd ) );
01020             } else {
01021               KMessageBox::detailedError( 0,
01022                                           i18n( "Pipe command exit with status %1: %2" ).
01023                                           arg( mPipeRc ).arg( cmd ), mPipeErr );
01024             }
01025           }
01026 
01027         } else {
01028 
01029           mPipeRc = -( proc.exitSignal() );
01030           if ( mPipeRc != 0 && mDebug ) {
01031             if ( mPipeErr.isEmpty() ) {
01032               KMessageBox::error( 0,
01033                                   i18n( "Pipe command killed by signal %1: %2" ).
01034                                   arg( -(mPipeRc) ).arg( cmd ) );
01035             } else {
01036               KMessageBox::detailedError( 0,
01037                                           i18n( "Pipe command killed by signal %1: %2" ).
01038                                           arg( -(mPipeRc) ).arg( cmd ), mPipeErr );
01039             }
01040           }
01041         }
01042 
01043       } else {
01044         // process does not exited after TemplateParser::PipeTimeout seconds, kill it
01045         proc.kill();
01046         proc.detach();
01047         if ( mDebug ) {
01048           KMessageBox::error( 0,
01049                               i18n( "Pipe command did not finish within %1 seconds: %2" ).
01050                               arg( PipeTimeout ).arg( cmd ) );
01051         }
01052       }
01053 
01054     } else {
01055       // can`t write to stdin of process
01056       proc.kill();
01057       proc.detach();
01058       if ( mDebug ) {
01059         if ( mPipeErr.isEmpty() ) {
01060           KMessageBox::error( 0,
01061                               i18n( "Cannot write to process stdin: %1" ).arg( cmd ) );
01062         } else {
01063           KMessageBox::detailedError( 0,
01064                                       i18n( "Cannot write to process stdin: %1" ).
01065                                       arg( cmd ), mPipeErr );
01066         }
01067       }
01068     }
01069 
01070   } else if ( mDebug ) {
01071     KMessageBox::error( 0,
01072                         i18n( "Cannot start pipe command from template: %1" ).
01073                         arg( cmd ) );
01074   }
01075 
01076   return mPipeOut;
01077 }
01078 
01079 void TemplateParser::onProcessExited( KProcess *proc )
01080 {
01081   Q_UNUSED( proc );
01082   // do nothing for now
01083 }
01084 
01085 void TemplateParser::onReceivedStdout( KProcess *proc, char *buffer, int buflen )
01086 {
01087   Q_UNUSED( proc );
01088   mPipeOut += QString::fromLocal8Bit( buffer, buflen );
01089 }
01090 
01091 void TemplateParser::onReceivedStderr( KProcess *proc, char *buffer, int buflen )
01092 {
01093   Q_UNUSED( proc );
01094   mPipeErr += QString::fromLocal8Bit( buffer, buflen );
01095 }
01096 
01097 void TemplateParser::onWroteStdin( KProcess *proc )
01098 {
01099   proc->closeStdin();
01100 }
01101 
01102 #include "templateparser.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys