File indexing completed on 2024-04-21 11:40:39
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"