00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <unistd.h>
00012 #include <cstdlib>
00013 #include <qstringlist.h>
00014 #include <qregexp.h>
00015 #include <qdir.h>
00016 #include <qtimer.h>
00017
00018 #include <mythtv/util.h>
00019 #include <mythtv/mythcontext.h>
00020 #include <mythtv/compat.h>
00021
00022 #include "mtd.h"
00023 #include "logging.h"
00024
00025 enum RIP_QUALITIES { QUALITY_ISO = -1, QUALITY_PERFECT, QUALITY_TRANSCODE };
00026
00027 DiscCheckingThread::DiscCheckingThread(MTD *owner,
00028 DVDProbe *probe,
00029 QMutex *drive_access_mutex,
00030 QMutex *mutex_for_titles)
00031 {
00032
00033
00034
00035
00036
00037
00038
00039 cancel_me = false;
00040 have_disc = false;
00041 dvd_probe = probe;
00042 dvd_drive_access = drive_access_mutex;
00043 titles_mutex = mutex_for_titles;
00044 parent = owner;
00045 }
00046
00047 bool DiscCheckingThread::keepGoing()
00048 {
00049
00050
00051
00052
00053
00054
00055 return (parent->threadsShouldContinue() && ! cancel_me);
00056 }
00057
00058 void DiscCheckingThread::run()
00059 {
00060
00061
00062
00063
00064
00065 while(keepGoing())
00066 {
00067 while(!dvd_drive_access->tryLock())
00068 {
00069 sleep(3);
00070 }
00071 while(!titles_mutex->tryLock())
00072 {
00073 sleep(3);
00074 }
00075 if(dvd_probe->probe())
00076 {
00077
00078
00079
00080
00081 have_disc = true;
00082 }
00083 else
00084 {
00085 have_disc = false;
00086 }
00087 titles_mutex->unlock();
00088 dvd_drive_access->unlock();
00089 sleep(1);
00090 }
00091 return;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 MTD::MTD(int port, bool log_stdout)
00103 :QObject()
00104 {
00105 keep_running = true;
00106 have_disc = false;
00107
00108 int nice_priority = gContext->GetNumSetting("MTDNiceLevel", 20);
00109 nice(nice_priority);
00110 nice_level = nice_priority;
00111
00112
00113
00114
00115
00116 server_socket = new MTDServerSocket(port);
00117 connect(server_socket, SIGNAL(newConnect(QSocket *)),
00118 this, SLOT(newConnection(QSocket *)));
00119 connect(server_socket, SIGNAL(endConnect(QSocket *)),
00120 this, SLOT(endConnection(QSocket *)));
00121
00122
00123
00124
00125
00126 mtd_log = new MTDLogger(log_stdout);
00127 mtd_log->addStartup();
00128 connect(this, SIGNAL(writeToLog(const QString &)), mtd_log, SLOT(addEntry(const QString &)));
00129
00130
00131
00132
00133
00134 emit writeToLog(QString("mtd is listening on port %1").arg(port));
00135
00136
00137
00138
00139
00140 job_threads.setAutoDelete( TRUE );
00141
00142
00143
00144
00145
00146 dvd_drive_access = new QMutex();
00147
00148
00149
00150
00151
00152 titles_mutex = new QMutex();
00153
00154
00155
00156
00157
00158
00159
00160 concurrent_transcodings_mutex = new QMutex();
00161 concurrent_transcodings = 0;
00162 max_concurrent_transcodings = gContext->GetNumSetting("MTDConcurrentTranscodings", 1);
00163
00164
00165
00166
00167
00168
00169 thread_cleaning_timer = new QTimer();
00170 connect(thread_cleaning_timer, SIGNAL(timeout()), this, SLOT(cleanThreads()));
00171 thread_cleaning_timer->start(2000);
00172
00173
00174
00175
00176
00177
00178
00179 dvd_device = gContext->GetSetting("DVDDeviceLocation");
00180 dvd_probe = new DVDProbe(dvd_device);
00181 disc_checking_thread = new DiscCheckingThread(this, dvd_probe, dvd_drive_access, titles_mutex);
00182 disc_checking_thread->start();
00183 disc_checking_timer = new QTimer();
00184 disc_checking_timer->start(1000);
00185 connect(disc_checking_timer, SIGNAL(timeout()), this, SLOT(checkDisc()));
00186
00187 }
00188
00189 void MTD::checkDisc()
00190 {
00191
00192 if (!dvd_probe)
00193 return;
00194
00195 bool had_disc = have_disc;
00196 QString old_name = dvd_probe->getName();
00197 if(disc_checking_thread->haveDisc())
00198 {
00199 have_disc = true;
00200 if(had_disc)
00201 {
00202 if(!old_name == dvd_probe->getName())
00203 {
00204
00205
00206
00207 emit writeToLog(QString("DVD changed to: %1").arg(dvd_probe->getName()));
00208 }
00209 }
00210 else
00211 {
00212
00213
00214
00215 emit writeToLog(QString("DVD inserted: %1").arg(dvd_probe->getName()));
00216 QPtrList<DVDTitle> *list_of_titles = dvd_probe->getTitles();
00217
00218
00219
00220
00221
00222
00223 if(list_of_titles)
00224 {
00225 for(uint i = 0; i < list_of_titles->count(); i++)
00226 {
00227 emit writeToLog(QString(" : Title %1 is of type %2 (dvdinput table)")
00228 .arg(i+1)
00229 .arg(list_of_titles->at(i)->getInputID()));
00230 }
00231 }
00232 }
00233 }
00234 else
00235 {
00236 have_disc = false;
00237 if(had_disc)
00238 {
00239
00240
00241
00242 emit writeToLog("DVD removed");
00243 }
00244 }
00245 }
00246
00247 void MTD::cleanThreads()
00248 {
00249
00250
00251
00252
00253
00254
00255 JobThread *iterator;
00256 for(iterator = job_threads.first(); iterator; iterator = job_threads.next() )
00257 {
00258 if(iterator->finished())
00259 {
00260 QString problem = iterator->getProblem();
00261 QString job_command = iterator->getJobString();
00262 if(problem.length() > 0)
00263 {
00264 emit writeToLog(QString("job failed: %1").arg(job_command));
00265
00266 }
00267 else
00268 {
00269 emit writeToLog(QString("job finished successfully: %1").arg(job_command));
00270 }
00271
00272
00273
00274
00275
00276
00277 if(iterator->transcodeSlotUsed())
00278 {
00279 concurrent_transcodings_mutex->lock();
00280 concurrent_transcodings--;
00281 if(concurrent_transcodings < 0)
00282 {
00283 cerr << "mtd.o: Your number of transcode jobs ended up negative. That should be impossible." << endl;
00284 concurrent_transcodings = 0;
00285 }
00286 concurrent_transcodings_mutex->unlock();
00287 }
00288
00289
00290 job_threads.remove(iterator);
00291 }
00292 }
00293
00294 }
00295
00296 void MTD::newConnection(QSocket *socket)
00297 {
00298 connect(socket, SIGNAL(readyRead()),
00299 this, SLOT(readSocket()));
00300
00301 mtd_log->socketOpened();
00302 }
00303
00304 void MTD::endConnection(QSocket *socket)
00305 {
00306 socket->close();
00307 mtd_log->socketClosed();
00308 }
00309
00310 void MTD::readSocket()
00311 {
00312
00313 QSocket *socket = (QSocket *)sender();
00314 if(socket->canReadLine())
00315 {
00316 QString incoming_data = socket->readLine();
00317 incoming_data = incoming_data.replace( QRegExp("\n"), "" );
00318 incoming_data = incoming_data.replace( QRegExp("\r"), "" );
00319 incoming_data.simplifyWhiteSpace();
00320 QStringList tokens = QStringList::split(" ", incoming_data);
00321 parseTokens(tokens, socket);
00322 }
00323 }
00324
00325
00326 void MTD::parseTokens(const QStringList &tokens, QSocket *socket)
00327 {
00328
00329
00330
00331
00332 if(tokens[0] == "halt" ||
00333 tokens[0] == "quit" ||
00334 tokens[0] == "shutdown")
00335 {
00336 shutDown();
00337 }
00338 else if(tokens[0] == "hello")
00339 {
00340 sayHi(socket);
00341 }
00342 else if(tokens[0] == "status")
00343 {
00344 sendStatusReport(socket);
00345 }
00346 else if(tokens[0] == "media")
00347 {
00348 sendMediaReport(socket);
00349 }
00350 else if(tokens[0] == "job")
00351 {
00352 startJob(tokens);
00353 }
00354 else if(tokens[0] == "abort")
00355 {
00356 startAbort(tokens);
00357 }
00358 else if (tokens[0] == "use")
00359 {
00360 useDrive(tokens);
00361 }
00362 else if (tokens[0] == "no")
00363 {
00364 noDrive(tokens);
00365 }
00366 else
00367 {
00368 QString did_not_parse = tokens.join(" ");
00369 emit writeToLog(QString("failed to parse this: %1").arg(did_not_parse));
00370 }
00371 }
00372
00373
00374 void MTD::shutDown()
00375 {
00376
00377
00378
00379
00380
00381
00382 keep_running = false;
00383
00384
00385
00386
00387
00388 disc_checking_thread->wait();
00389
00390
00391
00392
00393
00394 JobThread *iterator;
00395 for(iterator = job_threads.first(); iterator; iterator = job_threads.next() )
00396 {
00397 iterator->wait();
00398 }
00399
00400 for(uint i = 0; i < job_threads.count(); i++)
00401 {
00402 job_threads.remove(i);
00403 }
00404
00405
00406
00407
00408
00409
00410 mtd_log->addShutdown();
00411 delete mtd_log;
00412
00413 delete server_socket;
00414 exit(0);
00415 }
00416
00417 void MTD::sendMessage(QSocket *where, const QString &what)
00418 {
00419 QString message = what;
00420 message.append("\n");
00421
00422 where->writeBlock(message.utf8(), message.utf8().length());
00423 }
00424
00425 void MTD::sayHi(QSocket *socket)
00426 {
00427 sendMessage(socket, "greetings");
00428 }
00429
00430 void MTD::sendStatusReport(QSocket *socket)
00431 {
00432
00433
00434
00435
00436
00437
00438
00439
00440 sendMessage(socket, QString("status dvd summary %1").arg(job_threads.count()));
00441
00442 for(uint i = 0; i < job_threads.count() ; i++)
00443 {
00444 QString a_status_message = QString("status dvd job %1 overall %2 %3")
00445 .arg(i)
00446 .arg(job_threads.at(i)->getProgress())
00447 .arg(job_threads.at(i)->getJobName());
00448 sendMessage(socket, a_status_message);
00449 a_status_message = QString("status dvd job %1 subjob %2 %3")
00450 .arg(i)
00451 .arg(job_threads.at(i)->getSubProgress())
00452 .arg(job_threads.at(i)->getSubName());
00453 sendMessage(socket, a_status_message);
00454 }
00455
00456 sendMessage(socket, "status dvd complete");
00457 }
00458
00459 void MTD::sendMediaReport(QSocket *socket)
00460 {
00461
00462
00463
00464
00465 if(have_disc)
00466 {
00467
00468
00469
00470
00471 while(!titles_mutex->tryLock())
00472 {
00473 sleep(1);
00474 }
00475 QPtrList<DVDTitle> *dvd_titles = dvd_probe->getTitles();
00476 sendMessage(socket, QString("media dvd summary %1 %2").arg(dvd_titles->count()).arg(dvd_probe->getName()));
00477
00478
00479
00480
00481
00482
00483
00484
00485 for(uint i = 0; i < dvd_titles->count(); ++i)
00486 {
00487 sendMessage(socket, QString("media dvd title %1 %2 %3 %4 %5 %6 %7")
00488 .arg(dvd_titles->at(i)->getTrack())
00489 .arg(dvd_titles->at(i)->getChapters())
00490 .arg(dvd_titles->at(i)->getAngles())
00491 .arg(dvd_titles->at(i)->getHours())
00492 .arg(dvd_titles->at(i)->getMinutes())
00493 .arg(dvd_titles->at(i)->getSeconds())
00494 .arg(dvd_titles->at(i)->getInputID())
00495 );
00496
00497
00498
00499 QPtrList<DVDAudio> *audio_tracks = dvd_titles->at(i)->getAudioTracks();
00500 for(uint j = 0; j < audio_tracks->count(); j++)
00501 {
00502
00503
00504
00505
00506 sendMessage(socket, QString("media dvd title-audio %1 %2 %3 %4")
00507 .arg(dvd_titles->at(i)->getTrack())
00508 .arg(j+1)
00509 .arg(audio_tracks->at(j)->getChannels())
00510 .arg(audio_tracks->at(j)->getAudioString())
00511 );
00512 }
00513
00514
00515
00516
00517 QPtrList<DVDSubTitle> *subtitles = dvd_titles->at(i)->getSubTitles();
00518 for(uint j = 0; j < subtitles->count(); j++)
00519 {
00520 sendMessage(socket, QString("media dvd title-subtitle %1 %2 %3 %4")
00521 .arg(dvd_titles->at(i)->getTrack())
00522 .arg(subtitles->at(j)->getID())
00523 .arg(subtitles->at(j)->getLanguage())
00524 .arg(subtitles->at(j)->getName())
00525 );
00526 }
00527
00528
00529
00530 }
00531 titles_mutex->unlock();
00532 }
00533 else
00534 {
00535 sendMessage(socket, "media dvd summary 0 No Disc");
00536 }
00537 sendMessage(socket, "media dvd complete");
00538 }
00539
00540
00541 void MTD::startAbort(const QStringList &tokens)
00542 {
00543 QString flat = tokens.join(" ");
00544
00545
00546
00547
00548
00549 if(tokens.count() < 4)
00550 {
00551 emit writeToLog(QString("bad abort request: %1").arg(flat));
00552 return;
00553 }
00554
00555 if(tokens[1] != "dvd" ||
00556 tokens[2] != "job")
00557 {
00558 emit writeToLog(QString("I don't know how to handle this abort request: %1").arg(flat));
00559 return;
00560 }
00561
00562 bool ok;
00563 int job_to_kill = tokens[3].toInt(&ok);
00564 if(!ok || job_to_kill < 0)
00565 {
00566 emit writeToLog(QString("Could not make out a job number in this abort request: %1").arg(flat));
00567 return;
00568 }
00569
00570 if(job_to_kill >= (int) job_threads.count())
00571 {
00572 emit writeToLog(QString("Was asked to kill a job that does not exist: %1").arg(flat));
00573 return;
00574 }
00575
00576
00577
00578
00579
00580 job_threads.at(job_to_kill)->setSubProgress(0.0, 0);
00581 job_threads.at(job_to_kill)->setSubName("Cancelling ...", 0);
00582 job_threads.at(job_to_kill)->cancelMe(true);
00583 }
00584
00585 void MTD::startJob(const QStringList &tokens)
00586 {
00587
00588
00589
00590
00591 if(tokens.count() < 2)
00592 {
00593 QString flat = tokens.join(" ");
00594 emit writeToLog(QString("bad job request: %1").arg(flat));
00595 return;
00596 }
00597
00598 if(tokens[1] == "dvd")
00599 {
00600 startDVD(tokens);
00601 }
00602 else
00603 {
00604 emit writeToLog(QString("I don't know how to process jobs of type %1").arg(tokens[1]));
00605 }
00606
00607 }
00608
00609 void MTD::startDVD(const QStringList &tokens)
00610 {
00611 QString flat = tokens.join(" ");
00612 bool ok;
00613
00614 if(tokens.count() < 8)
00615 {
00616 emit writeToLog(QString("bad dvd job request: %1").arg(flat));
00617 return;
00618 }
00619
00620
00621
00622
00623
00624
00625
00626 int dvd_title = tokens[2].toInt(&ok);
00627 if(dvd_title < 1 || dvd_title > 99 || !ok)
00628 {
00629 emit writeToLog(QString("bad title number in job request: %1").arg(flat));
00630 return;
00631 }
00632
00633 int audio_track = tokens[3].toInt(&ok);
00634 if(audio_track < 0 || audio_track > 10 || !ok)
00635 {
00636 emit writeToLog(QString("bad audio track in job request: %1").arg(flat));
00637 return;
00638 }
00639
00640 int quality = tokens[4].toInt(&ok);
00641 if(quality < QUALITY_ISO || !ok)
00642 {
00643 emit writeToLog(QString("bad quality value in job request: %1").arg(flat));
00644 return;
00645 }
00646
00647 bool ac3_flag = false;
00648 int flag_value = tokens[5].toUInt(&ok);
00649 if(!ok)
00650 {
00651 emit writeToLog(QString("bad ac3 flag in job request: %1").arg(flat));
00652 return;
00653 }
00654 if(flag_value)
00655 {
00656 ac3_flag = true;
00657 }
00658
00659 int subtitle_track = tokens[6].toInt(&ok);
00660 if(!ok)
00661 {
00662 emit writeToLog(QString("bad subtitle reference in job request: %1").arg(flat));
00663 return;
00664 }
00665
00666
00667
00668
00669
00670
00671 QString dir_and_file = "";
00672
00673 for(uint i=7; i < tokens.count(); i++)
00674 {
00675 dir_and_file += tokens[i];
00676 if(i != tokens.count() - 1)
00677 {
00678 dir_and_file += " ";
00679 }
00680 }
00681
00682 QDir dest_dir(dir_and_file.section("/", 0, -2));
00683 if(!dest_dir.exists())
00684 {
00685 emit writeToLog(QString("bad destination directory in job request: %1").arg(flat));
00686 return;
00687 }
00688
00689 QString file_name = dir_and_file.section("/", -1, -1);
00690
00691 if(dvd_device.length() < 1)
00692 {
00693 emit writeToLog("crapity crap crap - all set to launch a dvd job and you don't have a dvd device defined");
00694 return;
00695 }
00696
00697
00698
00699
00700
00701 if(quality == QUALITY_ISO)
00702 {
00703 QFile final_file(dest_dir.filePath(file_name));
00704
00705 if(!checkFinalFile(&final_file, ".iso"))
00706 {
00707 emit writeToLog("Final file name is not useable. File exists? Other Pending job?");
00708 return;
00709 }
00710
00711 emit writeToLog(QString("launching job: %1").arg(flat));
00712
00713
00714
00715
00716
00717 JobThread *new_job = new DVDISOCopyThread(this,
00718 dvd_drive_access,
00719 dvd_device,
00720 dvd_title,
00721 final_file.name(),
00722 file_name,
00723 flat,
00724 nice_level);
00725 job_threads.append(new_job);
00726 new_job->start();
00727 }
00728 else if(quality == QUALITY_PERFECT)
00729 {
00730 QFile final_file(dest_dir.filePath(file_name));
00731
00732 if(!checkFinalFile(&final_file, ".mpg"))
00733 {
00734 emit writeToLog("Final file name is not useable. File exists? Other Pending job?");
00735 return;
00736 }
00737
00738 emit writeToLog(QString("launching job: %1").arg(flat));
00739
00740
00741
00742
00743
00744 JobThread *new_job = new DVDPerfectThread(this,
00745 dvd_drive_access,
00746 dvd_device,
00747 dvd_title,
00748 final_file.name(),
00749 file_name,
00750 flat,
00751 nice_level);
00752 job_threads.append(new_job);
00753 new_job->start();
00754 }
00755 else if (quality >= QUALITY_TRANSCODE)
00756 {
00757 QFile final_file(dest_dir.filePath(file_name));
00758
00759 if(!checkFinalFile(&final_file, ".avi"))
00760 {
00761 emit writeToLog("Final file name is not useable. File exists? Other Pending job?");
00762 return;
00763 }
00764
00765 while(!titles_mutex->tryLock())
00766 {
00767 sleep(1);
00768 }
00769
00770 DVDTitle *which_title = dvd_probe->getTitle(dvd_title);
00771 titles_mutex->unlock();
00772
00773 if(!which_title)
00774 {
00775 cerr << "mtd.o: title number not valid? " << endl;
00776 return;
00777 }
00778
00779 uint numb_seconds = which_title->getPlayLength();
00780
00781 emit writeToLog(QString("launching job: %1").arg(flat));
00782
00783
00784
00785
00786
00787 JobThread *new_job = new DVDTranscodeThread(this,
00788 dvd_drive_access,
00789 dvd_device,
00790 dvd_title,
00791 final_file.name(),
00792 file_name,
00793 flat,
00794 nice_level,
00795 quality,
00796 ac3_flag,
00797 audio_track,
00798 numb_seconds,
00799 subtitle_track);
00800 job_threads.append(new_job);
00801 new_job->start();
00802
00803 }
00804 else
00805 {
00806 cerr << "mtd.o: Hmmmmm. Got sent a job with a negative quality parameter. That's just plain weird." << endl;
00807 }
00808 }
00809
00813 void MTD::useDrive(const QStringList &tokens)
00814 {
00815 if (tokens.count() != 3)
00816 {
00817 emit writeToLog("Bad usedrive request: " + tokens.join(" "));
00818 return;
00819 }
00820
00821 if (tokens[1] == "dvd")
00822 useDVD(tokens);
00823 else
00824 emit writeToLog("I don't know how to use drives of type: " + tokens[1]);
00825 }
00826
00830 void MTD::useDVD(const QStringList &tokens)
00831 {
00832 if (dvd_device == tokens[2])
00833 return;
00834
00835 DVDProbe *newDrive = new DVDProbe(tokens[2]);
00836 if (!newDrive->probe())
00837 {
00838 emit writeToLog("Drive not available: " + tokens[2]);
00839 return;
00840 }
00841
00842 forgetDVD();
00843
00844 dvd_device = tokens[2];
00845 dvd_probe = newDrive;
00846
00847 disc_checking_thread = new DiscCheckingThread(this, dvd_probe,
00848 dvd_drive_access,
00849 titles_mutex);
00850 disc_checking_thread->start();
00851
00852 have_disc = true;
00853 }
00854
00858 void MTD::noDrive(const QStringList &tokens)
00859 {
00860 if (tokens.count() < 2 || tokens.count() > 3)
00861 {
00862 emit writeToLog("Bad no drive request: " + tokens.join(" "));
00863 return;
00864 }
00865
00866 QString device;
00867
00868 if (tokens[1] == "dvd")
00869 device = noDVD(tokens);
00870 else
00871 {
00872 emit writeToLog("I don't know how to forget drives of type: "
00873 + tokens[1]);
00874 return;
00875 }
00876
00877 for (JobThread *itr = job_threads.first(); itr; itr = job_threads.next())
00878 if (itr->usesDevice(device))
00879 {
00880 itr->setSubProgress(0.0, 0);
00881 itr->setSubName("Cancelling ...", 0);
00882 itr->cancelMe(true);
00883
00884 emit writeToLog("Waiting for job : " + itr->getJobName());
00885 itr->wait();
00886
00887 job_threads.remove(itr);
00888 }
00889 }
00890
00894 QString MTD::noDVD(const QStringList &tokens)
00895 {
00896 QString device;
00897
00898 if (tokens.count() == 2)
00899 device = dvd_device;
00900 else
00901 device = tokens[2];
00902
00903
00904
00905
00906 if (device == dvd_device)
00907 forgetDVD();
00908
00909 return device;
00910 }
00911
00915 void MTD::forgetDVD()
00916 {
00917 if (disc_checking_thread)
00918 {
00919 disc_checking_thread->cancelMe(true);
00920 disc_checking_thread->wait(50000);
00921 delete disc_checking_thread;
00922 disc_checking_thread = NULL;
00923 }
00924
00925 while (!dvd_drive_access->tryLock())
00926 sleep(3);
00927
00928 if (dvd_probe)
00929 {
00930 delete dvd_probe;
00931 dvd_probe = NULL;
00932 }
00933
00934 dvd_device = "";
00935 have_disc = false;
00936
00937 dvd_drive_access->unlock();
00938 }
00939
00940 bool MTD::checkFinalFile(QFile *final_file, const QString &extension)
00941 {
00942
00943
00944
00945
00946 QString final_with_extension_string = final_file->name() + extension;
00947 QFile tester(final_with_extension_string);
00948
00949 if(tester.exists())
00950 {
00951 return false;
00952 }
00953
00954
00955
00956
00957 JobThread *iterator;
00958 for(iterator = job_threads.first(); iterator; iterator = job_threads.next() )
00959 {
00960 if(iterator->getFinalFileName() == final_file->name())
00961 {
00962 return false;
00963 }
00964 }
00965
00966 return true;
00967 }
00968
00969 bool MTD::isItOkToStartTranscoding()
00970 {
00971 concurrent_transcodings_mutex->lock();
00972 if(concurrent_transcodings < max_concurrent_transcodings)
00973 {
00974 concurrent_transcodings++;
00975 concurrent_transcodings_mutex->unlock();
00976 return true;
00977 }
00978 concurrent_transcodings_mutex->unlock();
00979 return false;
00980 }
00981
00982 void MTD::customEvent(QCustomEvent *ce)
00983 {
00984 if(ce->type() == 65432)
00985 {
00986 LoggingEvent *le = (LoggingEvent*)ce;
00987 emit writeToLog(le->getString());
00988 }
00989 else if(ce->type() == 65431)
00990 {
00991 ErrorEvent *ee = (ErrorEvent*)ce;
00992 QString error_string = "Error: " + ee->getString();
00993 emit writeToLog(error_string);
00994 }
00995 else
00996 {
00997 cerr << "mtd.o: receiving events I don't understand" << endl;
00998 }
00999 }
01000