kmail

templateparser.cpp

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