File indexing completed on 2024-03-24 15:43:29

0001 /***************************************************************************
0002                           ctranscript.cpp  -  session transcript
0003     This file is a part of KMuddy distribution.
0004                              -------------------
0005     begin                : Thu oct 31 2002
0006     copyright            : (C) 2002 by Tomas Mecir
0007     email                : kmuddy@kmuddy.com
0008  ***************************************************************************/
0009 
0010 /***************************************************************************
0011  *                                                                         *
0012  *   This program is free software; you can redistribute it and/or modify  *
0013  *   it under the terms of the GNU General Public License as published by  *
0014  *   the Free Software Foundation; either version 2 of the License, or     *
0015  *   (at your option) any later version.                                   *
0016  *                                                                         *
0017  ***************************************************************************/
0018 
0019 #include "ctranscript.h"
0020 
0021 #include "cactionmanager.h"
0022 #include "cansiparser.h"
0023 #include "cconsole.h"   // needed for buffer dump
0024 #include "coutput.h"
0025 #include "cprofilemanager.h"
0026 #include "cprofilesettings.h"
0027 #include "ctelnet.h"
0028 #include "ctextchunk.h"
0029 #include "dialogs/dlgtranscript.h"
0030 #include "dialogs/dlgdumpbuffer.h"
0031 
0032 #include <QDir>
0033 #include <QFile>
0034 #include <QPushButton>
0035 #include <QTimer>
0036 #include <KLocalizedString>
0037 #include <kmessagebox.h>
0038 #include <kconfig.h>
0039 #include <kconfiggroup.h>
0040 
0041 cTranscript::cTranscript (int sess) : cActionBase ("transcript", sess)
0042 {
0043   running = false;
0044   advrunning = false;
0045   rotatedaily = false;
0046   overwrite = true;
0047   includedump = false;
0048   includetimestamp = false;
0049   type = advtype = 1;
0050   nextLineGagged = false;
0051   
0052   addEventHandler ("disconnected", 20, PT_NOTHING);
0053   addEventHandler ("got-line-after-triggers", 50, PT_TEXTCHUNK);
0054   addEventHandler ("will-gag", 50, PT_NOTHING);
0055   addEventHandler ("displayed-line", 50, PT_TEXTCHUNK);
0056   addEventHandler ("displayed-prompt", 50, PT_TEXTCHUNK);
0057 }
0058 
0059 cTranscript::~cTranscript ()
0060 { 
0061   stopTranscript ();
0062   stopAdvTranscript ();
0063 
0064   removeEventHandler ("disconnected");
0065   removeEventHandler ("will-gag");
0066   removeEventHandler ("got-line-after-triggers");
0067   removeEventHandler ("displayed-line");
0068   removeEventHandler ("displayed-prompt");
0069 }
0070 
0071 void cTranscript::eventNothingHandler (QString event, int)
0072 {
0073   if (event == "disconnected") {
0074     stopTranscript ();
0075     stopAdvTranscript ();
0076   }
0077   else if (event == "will-gag") {
0078     nextLineGagged = true;
0079   }
0080 }
0081 
0082 void cTranscript::eventChunkHandler (QString event, int, cTextChunk *chunk)
0083 {
0084   if (event == "displayed-line") {
0085     addLineToTranscript (chunk);
0086     addLineToAdvTranscript (chunk);
0087   }
0088   else if (event == "displayed-prompt") {
0089     addLineToTranscript (chunk);
0090     addLineToAdvTranscript (chunk);
0091   }
0092   else if (event == "got-line-after-triggers") {
0093     // got-line-after-triggers is called for every line, gagged or not
0094     // if the line will be gagged, will-gag was invoked immediately before this
0095     if (nextLineGagged) {
0096       // gagged lines will also be added to the transcript
0097       // we don't use this event for everything, so that later on, we can configure, whether
0098       // we want to include gagged lines or not
0099       addLineToTranscript (chunk);
0100       addLineToAdvTranscript (chunk);
0101       nextLineGagged = false;
0102     }
0103   }
0104 }
0105 
0106 void cTranscript::addLineToTranscript (cTextChunk *chunk)
0107 {
0108   if (!running)
0109     return;
0110   
0111   cANSIParser *ap = dynamic_cast<cANSIParser *>(object ("ansiparser"));
0112   QString s;
0113   switch (type) {
0114     case TRANSCRIPT_PLAIN: s = chunk->toText () + "\n"; break;
0115     case TRANSCRIPT_ANSI: s = chunk->toAnsi (ap) + "\n"; break;
0116     case TRANSCRIPT_HTML: s = chunk->toHTML (); break;
0117   };
0118   file.write (s.toLocal8Bit ());
0119   file.flush();
0120 }
0121 
0122 void cTranscript::addLineToAdvTranscript (cTextChunk *chunk)
0123 {
0124   if (!advrunning)
0125     return;
0126   
0127   QString timestamp;
0128   if (includetimestamp)
0129   {
0130     QTime time = QTime::currentTime ();
0131     timestamp = QString("[%1:%2:%3.%4] ").arg(time.hour(), 2, QChar('0')).arg(time.minute(), 2, QChar('0')).arg(time.second(), 2, QChar('0')).arg(time.msec() / 10, 2, QChar('0'));
0132     advfile.write (timestamp.toLatin1());
0133   }
0134  
0135   cANSIParser *ap = dynamic_cast<cANSIParser *>(object ("ansiparser"));
0136   QString s;
0137   switch (advtype) {
0138     case TRANSCRIPT_PLAIN: s = chunk->toText () + "\n"; break;
0139     case TRANSCRIPT_ANSI: s = chunk->toAnsi (ap) + "\n"; break;
0140     case TRANSCRIPT_HTML: s = chunk->toHTML (); break;
0141   };
0142   advfile.write (s.toLocal8Bit ());
0143   
0144   advfile.flush();
0145 }
0146 
0147 void cTranscript::stopTranscript ()
0148 {
0149   if (!running)
0150     return;
0151     
0152   file.write ("\n\n");
0153   
0154   if (type == TRANSCRIPT_ANSI)  //ANSI transcript
0155   {
0156     //set output color to default (usually gray on black)
0157     char defcolor[5];
0158     defcolor[0] = 27;
0159     defcolor[1] = '[';
0160     defcolor[2] = '0';
0161     defcolor[3] = 'm';
0162     defcolor[4] = 0;
0163     file.write (defcolor);
0164   }
0165   if (type == TRANSCRIPT_HTML)  //HTML transcript
0166   {
0167     //closing HTML tags
0168     file.write ("</pre></body></html>\n");
0169   }
0170   
0171   running = false;
0172   file.close();
0173   invokeEvent ("message", sess(), i18n ("Session transcript has been stopped."));
0174 }
0175 
0176 void cTranscript::stopAdvTranscript ()
0177 {
0178   if (!advrunning)
0179     return;
0180     
0181   advfile.write ("\n\n");
0182   
0183   if (type == TRANSCRIPT_ANSI)  //ANSI transcript
0184   {
0185     //set output color to default (usually gray on black)
0186     char defcolor[5];
0187     defcolor[0] = 27;
0188     defcolor[1] = '[';
0189     defcolor[2] = '0';
0190     defcolor[3] = 'm';
0191     defcolor[4] = 0;
0192     advfile.write (defcolor);
0193   }
0194   if (type == TRANSCRIPT_HTML)  //HTML transcript
0195   {
0196     //closing HTML tags
0197     advfile.write ("</pre></body></html>\n");
0198   }
0199     
0200   advrunning = false;
0201   advfile.close();
0202   if (transtimer->isActive ())
0203   {
0204     transtimer->stop ();
0205     delete transtimer;
0206   }
0207   invokeEvent ("message", sess(), i18n ("Advanced session transcript has been stopped."));
0208 }
0209 
0210 void cTranscript::configure ()
0211 {
0212   //so first we have to create the dialog...
0213   tdlg = new dlgTranscript (cActionManager::self()->mainWidget());
0214 
0215   //then we connect() all its signals - this handles everything that the dialog offers...
0216   connect (tdlg, &dlgTranscript::accepted, this, &cTranscript::applyTranscript);
0217   connect (tdlg->button (QDialogButtonBox::Apply), &QPushButton::clicked, this, &cTranscript::applyTranscript);
0218 
0219   //next we fill in its data
0220   tdlg->setEnabled (running);
0221 
0222   cProfileSettings *sett = settings ();
0223   fname = sett ? sett->getString ("transcript-directory") : QDir::homePath();
0224   
0225   fname += "/kmuddy_transcript.txt";
0226 
0227   tdlg->setTranscriptType (type);
0228   tdlg->setFName (fname);
0229   tdlg->setAFName (fileformat);
0230   tdlg->setOverwrite (overwrite);
0231   tdlg->setIncludeDump (includedump);
0232   tdlg->setAdvTranscript(advrunning);
0233   tdlg->setRotateDaily (rotatedaily);
0234   tdlg->setIncludeTimestamp(includetimestamp);  
0235   tdlg->setAdvTranscriptType (advtype);
0236   
0237   //dialog is ready - show it!
0238   tdlg->exec ();
0239 
0240   //finally, destroy that dialog!
0241   delete tdlg;
0242 }
0243 
0244 void cTranscript::startTranscript ()
0245 {
0246   //we'll have multiple <html></html> sections in a transcript file if we continue an existing
0247   //one, but every browser that I've tested can handle it correctly :D
0248   if (running)
0249     stopTranscript ();
0250   cTelnet *telnet = dynamic_cast<cTelnet *>(object ("telnet"));
0251   if (!(telnet->isConnected()))  //no transcript if we aren't connected
0252     return;
0253   
0254   file.setFileName (fname);
0255   if (!file.open (QIODevice::WriteOnly | QIODevice::Text | ( overwrite ? QIODevice::Truncate : QIODevice::Append )))
0256   {
0257     KMessageBox::detailedError (cActionManager::self()->mainWidget(),
0258         i18n ("Transcript file could not be opened."), file.errorString());
0259     invokeEvent ("message", sess(), i18n ("Session transcript could not be started."));
0260     return;
0261   }
0262 
0263   running = true;
0264   cOutput *output = dynamic_cast<cOutput *>(object ("output"));
0265   file.write ("\n\n");
0266   if (type == TRANSCRIPT_HTML)
0267   {
0268     cProfileSettings *sett = settings();
0269     //TODO: what if we're adding to an existing HTML transcript?
0270     file.write ("<html><head>\n");
0271     file.write ("<meta name=\"Generator\" content=\"KMuddy\">\n");
0272     file.write (("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + sett->getString ("encoding") + "\">").toLatin1());
0273     file.write ("<style> p { margin: 0px; padding: 2px; } </style>");
0274     file.write ("</head><body bgcolor=");
0275     file.write (output->defaultBkColor().name().toLatin1());
0276     file.write (">\n");
0277   }
0278   QString s = i18n ("Session transcript has just started.");
0279   file.write (s.toLatin1());
0280   if (type == TRANSCRIPT_HTML) file.write ("<br/><pre>");  //pre-formatted text starting...
0281   file.write ("\n\n");
0282 
0283   //add buffer dump if requested
0284   if (includedump)
0285     output->console()->dumpBuffer (false, file, type);
0286 
0287   invokeEvent ("message", sess(), i18n ("Session transcript has been started."));
0288 }
0289 
0290 void cTranscript::startAdvTranscript ()
0291 {
0292   QString af;
0293   
0294   if (advrunning)
0295     stopAdvTranscript ();
0296   cTelnet *telnet = dynamic_cast<cTelnet *>(object ("telnet"));
0297   if (!(telnet->isConnected()))  //no transcript if we aren't connected
0298     return;
0299   
0300   if(advfname.isEmpty())
0301     return; // no transcript if advanced filename failed
0302   
0303   transtimer = new QTimer();
0304   connect (transtimer, &QTimer::timeout, this, &cTranscript::timeout);
0305 
0306   cProfileSettings *sett = settings ();
0307   af = sett ? sett->getString ("transcript-directory") : QDir::homePath();
0308   af += advfname;
0309 
0310   file.setFileName (af);
0311   if (!advfile.open (QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
0312   {
0313     KMessageBox::detailedError (cActionManager::self()->mainWidget(),
0314         i18n ("Advanced transcript file could not be opened."), advfile.errorString());
0315     invokeEvent ("message", sess(), i18n ("Advanced session transcript could not be started."));
0316     return;
0317   }
0318 
0319   advrunning = true;
0320   cOutput *output = dynamic_cast<cOutput *>(object ("output"));
0321   advfile.write ("\n\n");
0322   if (advtype == TRANSCRIPT_HTML)
0323   {
0324     //TODO: what if we're adding to an existing HTML transcript?
0325     advfile.write ("<html>\n");
0326     advfile.write ("<meta name=\"Generator\" content=\"KMuddy\">\n");
0327     advfile.write ("<body bgcolor=");
0328     advfile.write (output->defaultBkColor().name().toLatin1());
0329     advfile.write (">\n");
0330   }
0331   QString s = i18n ("Advanced session transcript has just started.");
0332   advfile.write (s.toLatin1());
0333   if (advtype == TRANSCRIPT_HTML) advfile.write ("<br/><pre>");  //pre-formatted text starting...
0334   advfile.write ("\n\n");
0335 
0336   invokeEvent ("message", sess(), i18n ("Advanced session transcript has been started."));
0337   
0338   if (rotatedaily)
0339   {
0340     invokeEvent ("message", sess(), i18n ("Session transcript will be rotated at midnight."));
0341     transtimer->start (60000);
0342   }
0343 }
0344 
0345 void cTranscript::load()
0346 {
0347   QString path = cProfileManager::self()->profilePath (sess());
0348   
0349   KConfig *config = new KConfig (path + "transcript");
0350   
0351   KConfigGroup g = config->group ("Advanced transcript");
0352   setEnableRotate (g.readEntry ("Daily rotation", false));
0353   setPrependTimestamp (g.readEntry("Prepend timestamp", false));
0354   setAFName (g.readEntry("Advanced logname", QString()));
0355   advtype = g.readEntry ("Transcript type", 1);
0356   delete config;
0357 }
0358 
0359 void cTranscript::save()
0360 {
0361   QString path = cProfileManager::self()->profilePath (sess());
0362   KConfig *config = new KConfig ( path + "transcript");
0363   
0364   KConfigGroup g = config->group ("Advanced transcript");
0365   g.writeEntry ("Daily rotation", rotatedaily);
0366   g.writeEntry ("Prepend timestamp", includetimestamp);
0367   g.writeEntry ("Advanced logname", fileformat);
0368   g.writeEntry ("Transcript type", advtype);
0369   delete config;
0370 }
0371 
0372 void cTranscript::applyTranscript ()
0373 //handler of OK/Apply in transcript dialog
0374 {
0375   stopTranscript ();
0376   stopAdvTranscript();
0377   overwrite = tdlg->isOverwrite ();
0378   includedump = tdlg->includeDump ();
0379   fname = tdlg->getFName ();  
0380   type = tdlg->transcriptType();
0381   
0382   fileformat = tdlg->getAFName(); 
0383   setAFName (fileformat);
0384   
0385   if (tdlg->isEnabled ())
0386     startTranscript ();  
0387   
0388   rotatedaily = tdlg->rotateDaily();
0389   includetimestamp = tdlg->includeTimestamp();
0390   advtype = tdlg->advTranscriptType();
0391   
0392   if(tdlg->advTranscript())
0393     startAdvTranscript();
0394   
0395   save();
0396 }
0397 
0398 void cTranscript::dumpBuffer ()
0399 {
0400   //so first we have to create the dialog...
0401   bdlg = new dlgDumpBuffer (cActionManager::self()->mainWidget());
0402 
0403   QString fName;
0404   cProfileSettings *sett = settings ();
0405   fName = sett ? sett->getString ("transcript-directory") : QDir::homePath();
0406   fName += "/buffer_dump.html";
0407   bdlg->setFileName (fName);
0408   bdlg->setType (TRANSCRIPT_HTML);
0409   //then we connect() all its signals - this handles everything that the dialog offers...
0410   connect (bdlg, &dlgDumpBuffer::accepted, this, &cTranscript::doDumpBuffer);
0411 
0412   //dialog is ready - show it!
0413   bdlg->exec ();
0414 
0415   //finally, destroy that dialog!
0416   delete bdlg;
0417 }
0418 
0419 void cTranscript::doDumpBuffer ()
0420 {
0421   QString fName = bdlg->fileName();
0422   int type = bdlg->type();
0423   QFile f (fName);
0424   if (!f.open (QIODevice::WriteOnly | QIODevice::Text)) {
0425     KMessageBox::detailedError (cActionManager::self()->mainWidget(),
0426         i18n ("Dump file could not be opened."), f.errorString());
0427     return;
0428   }
0429   cOutput *output = dynamic_cast<cOutput *>(object ("output"));
0430   if (type == TRANSCRIPT_HTML)
0431   {
0432     f.write ("<html>\n");
0433     f.write ("<meta name=\"Generator\" content=\"KMuddy\">\n");
0434     f.write ("<body bgcolor=");
0435     f.write (output->defaultBkColor().name().toLatin1());
0436     f.write ("><pre>\n");
0437   }
0438   output->console()->dumpBuffer (bdlg->curPos(), f, type);
0439   if (type == TRANSCRIPT_HTML)
0440     f.write ("\n</pre></body></html>\n");
0441   f.close ();
0442 }
0443 
0444 void cTranscript::timeout()
0445 {
0446   QTime time = QTime::currentTime();
0447   
0448   if((time.hour() == 0) && (time.minute() == 0))
0449   {
0450     stopAdvTranscript();
0451     startAdvTranscript();
0452   }
0453 }
0454 
0455 void cTranscript::setAFName(const QString &what)
0456 {
0457   QString sessname;
0458 
0459   QDate date = QDate::currentDate();
0460   QTime time = QTime::currentTime();
0461   
0462   fileformat = what;
0463 
0464   QString day   = QString("%1").arg(date.day(), 2, QChar('0'));
0465   QString month = QString("%1").arg(date.month(),  2, QChar('0'));
0466   QString year  = QString("%1").arg(date.year(),   2, QChar('0'));
0467   QString hour  = QString("%1").arg(time.hour(),   2, QChar('0'));
0468   QString min   = QString("%1").arg(time.minute(), 2, QChar('0'));
0469 
0470   if (settings()) {
0471     cProfileManager *pm = cProfileManager::self();
0472     sessname = pm->visibleProfileName (pm->profileName (sess()));
0473   }
0474   
0475   if (!what.isEmpty())
0476   {
0477     advfname = what;
0478     advfname.replace("$W", sessname);
0479     advfname.replace("$D", day);
0480     advfname.replace("$M", month);
0481     advfname.replace("$Y", year);
0482     advfname.replace("$h", hour);
0483     advfname.replace("$m", min);
0484     
0485   }
0486   else
0487   {
0488     if(!sessname.isEmpty())
0489       advfname = sessname + "-" + day + "-" + month + "-" + year + ".log";
0490     else
0491       advfname = "unnamed-" + day + "-" + month + "-" + year + ".log";
0492   }
0493 }
0494 
0495 QString cTranscript::getAFName()
0496 {
0497   return advfname;
0498 }
0499 
0500 #include "moc_ctranscript.cpp"