00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "Session.h"
00025
00026
00027 #include <assert.h>
00028 #include <stdlib.h>
00029 #include <signal.h>
00030
00031
00032 #include <QtGui/QApplication>
00033 #include <QtCore/QByteRef>
00034 #include <QtCore/QDir>
00035 #include <QtCore/QFile>
00036 #include <QtCore/QRegExp>
00037 #include <QtCore/QStringList>
00038 #include <QtDBus/QtDBus>
00039 #include <QtCore/QDate>
00040
00041
00042 #include <KDebug>
00043 #include <KLocale>
00044 #include <KMessageBox>
00045 #include <KNotification>
00046 #include <KProcess>
00047 #include <KRun>
00048 #include <kshell.h>
00049 #include <KStandardDirs>
00050
00051
00052 #include <config-konsole.h>
00053 #include <sessionadaptor.h>
00054
00055 #include "Pty.h"
00056 #include "TerminalDisplay.h"
00057 #include "ShellCommand.h"
00058 #include "Vt102Emulation.h"
00059 #include "ZModemDialog.h"
00060
00061 using namespace Konsole;
00062
00063 int Session::lastSessionId = 0;
00064
00065 Session::Session(QObject* parent) :
00066 QObject(parent)
00067 , _shellProcess(0)
00068 , _emulation(0)
00069 , _monitorActivity(false)
00070 , _monitorSilence(false)
00071 , _notifiedActivity(false)
00072 , _autoClose(true)
00073 , _wantedClose(false)
00074 , _silenceSeconds(10)
00075 , _addToUtmp(true)
00076 , _flowControl(true)
00077 , _fullScripting(false)
00078 , _sessionId(0)
00079 , _zmodemBusy(false)
00080 , _zmodemProc(0)
00081 , _zmodemProgress(0)
00082 , _hasDarkBackground(false)
00083 {
00084
00085 new SessionAdaptor(this);
00086 _sessionId = ++lastSessionId;
00087 QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
00088
00089
00090 _emulation = new Vt102Emulation();
00091
00092 connect( _emulation, SIGNAL( titleChanged( int, const QString & ) ),
00093 this, SLOT( setUserTitle( int, const QString & ) ) );
00094 connect( _emulation, SIGNAL( stateSet(int) ),
00095 this, SLOT( activityStateSet(int) ) );
00096 connect( _emulation, SIGNAL( zmodemDetected() ), this ,
00097 SLOT( fireZModemDetected() ) );
00098 connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ),
00099 this, SIGNAL( changeTabTextColorRequest( int ) ) );
00100 connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString&)),
00101 this, SIGNAL( profileChangeCommandReceived(const QString&)) );
00102 connect( _emulation, SIGNAL(flowControlKeyPressed(bool)) , this,
00103 SLOT(updateFlowControlState(bool)) );
00104
00105
00106 openTeletype(-1);
00107
00108
00109 _monitorTimer = new QTimer(this);
00110 _monitorTimer->setSingleShot(true);
00111 connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
00112 }
00113
00114 void Session::openTeletype(int fd)
00115 {
00116 if (_shellProcess && isRunning())
00117 {
00118 kWarning() << "Attempted to open teletype in a running session.";
00119 return;
00120 }
00121
00122 delete _shellProcess;
00123
00124 if (fd < 0)
00125 _shellProcess = new Pty();
00126 else
00127 _shellProcess = new Pty(fd);
00128
00129 _shellProcess->setUtf8Mode(_emulation->utf8());
00130
00131
00132 connect( _shellProcess,SIGNAL(receivedData(const char*,int)),this,
00133 SLOT(onReceiveBlock(const char*,int)) );
00134 connect( _emulation,SIGNAL(sendData(const char*,int)),_shellProcess,
00135 SLOT(sendData(const char*,int)) );
00136 connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) );
00137 connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) );
00138 connect( _shellProcess,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(done(int)) );
00139 connect( _emulation,SIGNAL(imageSizeChanged(int,int)),this,SLOT(updateWindowSize(int,int)) );
00140 }
00141
00142 WId Session::windowId() const
00143 {
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 if ( _views.count() == 0 )
00157 return 0;
00158 else
00159 {
00160 QWidget* window = _views.first();
00161
00162 Q_ASSERT( window );
00163
00164 while ( window->parentWidget() != 0 )
00165 window = window->parentWidget();
00166
00167 return window->winId();
00168 }
00169 }
00170
00171 void Session::setDarkBackground(bool darkBackground)
00172 {
00173 _hasDarkBackground = darkBackground;
00174 }
00175 bool Session::hasDarkBackground() const
00176 {
00177 return _hasDarkBackground;
00178 }
00179 bool Session::isRunning() const
00180 {
00181 return _shellProcess->state() == QProcess::Running;
00182 }
00183
00184 void Session::setCodec(QTextCodec* codec)
00185 {
00186 emulation()->setCodec(codec);
00187 }
00188
00189 void Session::setProgram(const QString& program)
00190 {
00191 _program = ShellCommand::expand(program);
00192 }
00193 void Session::setInitialWorkingDirectory(const QString& dir)
00194 {
00195 _initialWorkingDir = ShellCommand::expand(dir);
00196 }
00197 void Session::setArguments(const QStringList& arguments)
00198 {
00199 _arguments = ShellCommand::expand(arguments);
00200 }
00201
00202 QList<TerminalDisplay*> Session::views() const
00203 {
00204 return _views;
00205 }
00206
00207 void Session::addView(TerminalDisplay* widget)
00208 {
00209 Q_ASSERT( !_views.contains(widget) );
00210
00211 _views.append(widget);
00212
00213 if ( _emulation != 0 )
00214 {
00215
00216 connect( widget , SIGNAL(keyPressedSignal(QKeyEvent*)) , _emulation ,
00217 SLOT(sendKeyEvent(QKeyEvent*)) );
00218 connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation ,
00219 SLOT(sendMouseEvent(int,int,int,int)) );
00220 connect( widget , SIGNAL(sendStringToEmu(const char*)) , _emulation ,
00221 SLOT(sendString(const char*)) );
00222
00223
00224
00225 connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
00226 SLOT(setUsesMouse(bool)) );
00227
00228 widget->setUsesMouse( _emulation->programUsesMouse() );
00229
00230 widget->setScreenWindow(_emulation->createWindow());
00231 }
00232
00233
00234 QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this,
00235 SLOT(onViewSizeChange(int,int)));
00236
00237 QObject::connect( widget ,SIGNAL(destroyed(QObject*)) , this ,
00238 SLOT(viewDestroyed(QObject*)) );
00239 }
00240
00241 void Session::viewDestroyed(QObject* view)
00242 {
00243 TerminalDisplay* display = (TerminalDisplay*)view;
00244
00245 Q_ASSERT( _views.contains(display) );
00246
00247 removeView(display);
00248 }
00249
00250 void Session::removeView(TerminalDisplay* widget)
00251 {
00252 _views.removeAll(widget);
00253
00254 disconnect(widget,0,this,0);
00255
00256 if ( _emulation != 0 )
00257 {
00258
00259
00260
00261
00262
00263
00264 disconnect( widget, 0, _emulation, 0);
00265
00266
00267 disconnect( _emulation , 0 , widget , 0);
00268 }
00269
00270
00271 if ( _views.count() == 0 )
00272 {
00273 close();
00274 }
00275 }
00276
00277 QString Session::checkProgram(const QString& program) const
00278 {
00279
00280
00281 QString exec = QFile::encodeName(program);
00282
00283 if (exec.isEmpty())
00284 return QString();
00285
00286
00287
00288 if ( exec.isEmpty() )
00289 exec = getenv("SHELL");
00290 if ( exec.isEmpty() )
00291 exec = "/bin/sh";
00292
00293 exec = KRun::binaryName(exec, false);
00294 exec = KShell::tildeExpand(exec);
00295 QString pexec = KGlobal::dirs()->findExe(exec);
00296 if ( pexec.isEmpty() )
00297 {
00298 kError() << i18n("Could not find binary: ") << exec;
00299 return QString();
00300 }
00301
00302 return exec;
00303 }
00304
00305 void Session::terminalWarning(const QString& message)
00306 {
00307 static const QByteArray warningText = i18n("Warning: ").toLocal8Bit();
00308 QByteArray messageText = message.toLocal8Bit();
00309
00310 static const char* redPenOn = "\033[1m\033[31m";
00311 static const char* redPenOff = "\033[0m";
00312
00313 _emulation->receiveData(redPenOn,strlen(redPenOn));
00314 _emulation->receiveData("\n\r\n\r",4);
00315 _emulation->receiveData(warningText.constData(),strlen(warningText.constData()));
00316 _emulation->receiveData(messageText.constData(),strlen(messageText.constData()));
00317 _emulation->receiveData("\n\r\n\r",4);
00318 _emulation->receiveData(redPenOff,strlen(redPenOff));
00319 }
00320 void Session::run()
00321 {
00322
00323 if (_program.isEmpty())
00324 kDebug() << "Session::run() - program to run not set.";
00325 if (_arguments.isEmpty())
00326 kDebug() << "Session::run() - no command line arguments specified.";
00327
00328 const int CHOICE_COUNT = 3;
00329 QString programs[CHOICE_COUNT] = {_program,getenv("SHELL"),"/bin/sh"};
00330 QString exec;
00331 int choice = 0;
00332 while (choice < CHOICE_COUNT)
00333 {
00334 exec = checkProgram(programs[choice]);
00335 if (exec.isEmpty())
00336 choice++;
00337 else
00338 break;
00339 }
00340
00341
00342 if (choice != 0 && choice < CHOICE_COUNT && !_program.isEmpty())
00343 {
00344 terminalWarning(i18n("Could not find '%1', starting '%2' instead. Please check your profile settings.",_program,exec));
00345 }
00346
00347 else if (choice == CHOICE_COUNT)
00348 {
00349 terminalWarning(i18n("Could not find an interactive shell to start."));
00350 return;
00351 }
00352
00353
00354 QStringList arguments = _arguments.join(QChar(' ')).isEmpty() ?
00355 QStringList() << exec : _arguments;
00356
00357 QString dbusService = QDBusConnection::sessionBus().baseService();
00358 QString cwd_save = QDir::currentPath();
00359 if (!_initialWorkingDir.isEmpty())
00360 _shellProcess->setWorkingDirectory(_initialWorkingDir);
00361 else
00362 _shellProcess->setWorkingDirectory(QDir::homePath());
00363
00364 _shellProcess->setFlowControlEnabled(_flowControl);
00365 _shellProcess->setErase(_emulation->getErase());
00366
00367
00368
00369
00370
00371 QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15";
00372
00373 int result = _shellProcess->start(exec,
00374 arguments,
00375 _environment << backgroundColorHint,
00376 windowId(),
00377 _addToUtmp,
00378 dbusService,
00379 (QLatin1String("/Sessions/") +
00380 QString::number(_sessionId)));
00381
00382 if (result < 0)
00383 {
00384 terminalWarning(i18n("Could not start program '%1' with arguments '%2'.", exec, arguments.join(" ")));
00385 return;
00386 }
00387
00388 _shellProcess->setWriteable(false);
00389
00390 emit started();
00391 }
00392
00393 void Session::setUserTitle( int what, const QString &caption )
00394 {
00395
00396 bool modified = false;
00397
00398 if ((what == IconNameAndWindowTitle) || (what == WindowTitle))
00399 {
00400 if ( _userTitle != caption ) {
00401 _userTitle = caption;
00402 modified = true;
00403 }
00404 }
00405
00406 if ((what == IconNameAndWindowTitle) || (what == IconName))
00407 {
00408 if ( _iconText != caption ) {
00409 _iconText = caption;
00410 modified = true;
00411 }
00412 }
00413
00414 if (what == TextColor || what == BackgroundColor)
00415 {
00416 QString colorString = caption.section(';',0,0);
00417 QColor color = QColor(colorString);
00418 if (color.isValid())
00419 {
00420 if (what == TextColor)
00421 emit changeForegroundColorRequest(color);
00422 else
00423 emit changeBackgroundColorRequest(color);
00424 }
00425 }
00426
00427 if (what == SessionName)
00428 {
00429 if ( _nameTitle != caption ) {
00430 setTitle(Session::NameRole,caption);
00431 return;
00432 }
00433 }
00434
00435 if (what == 31)
00436 {
00437 QString cwd=caption;
00438 cwd=cwd.replace( QRegExp("^~"), QDir::homePath() );
00439 emit openUrlRequest(cwd);
00440 }
00441
00442
00443 if (what == 32)
00444 {
00445 if ( _iconName != caption ) {
00446 _iconName = caption;
00447
00448 modified = true;
00449 }
00450 }
00451
00452 if (what == ProfileChange)
00453 {
00454 emit profileChangeCommandReceived(caption);
00455 return;
00456 }
00457
00458 if ( modified )
00459 emit titleChanged();
00460 }
00461
00462 QString Session::userTitle() const
00463 {
00464 return _userTitle;
00465 }
00466 void Session::setTabTitleFormat(TabTitleContext context , const QString& format)
00467 {
00468 if ( context == LocalTabTitle )
00469 _localTabTitleFormat = format;
00470 else if ( context == RemoteTabTitle )
00471 _remoteTabTitleFormat = format;
00472 }
00473 QString Session::tabTitleFormat(TabTitleContext context) const
00474 {
00475 if ( context == LocalTabTitle )
00476 return _localTabTitleFormat;
00477 else if ( context == RemoteTabTitle )
00478 return _remoteTabTitleFormat;
00479
00480 return QString();
00481 }
00482
00483 void Session::monitorTimerDone()
00484 {
00485
00486
00487
00488
00489
00490
00491
00492
00493 if (_monitorSilence) {
00494 KNotification::event("Silence", i18n("Silence in session '%1'", _nameTitle), QPixmap(),
00495 QApplication::activeWindow(),
00496 KNotification::CloseWhenWidgetActivated);
00497 emit stateChanged(NOTIFYSILENCE);
00498 }
00499 else
00500 {
00501 emit stateChanged(NOTIFYNORMAL);
00502 }
00503
00504 _notifiedActivity=false;
00505 }
00506 void Session::updateFlowControlState(bool suspended)
00507 {
00508 if (suspended)
00509 {
00510 if (flowControlEnabled())
00511 {
00512 foreach(TerminalDisplay* display,_views)
00513 {
00514 if (display->flowControlWarningEnabled())
00515 display->outputSuspended(true);
00516 }
00517 }
00518 }
00519 else
00520 {
00521 foreach(TerminalDisplay* display,_views)
00522 display->outputSuspended(false);
00523 }
00524 }
00525 void Session::activityStateSet(int state)
00526 {
00527 if (state==NOTIFYBELL)
00528 {
00529 emit bellRequest( i18n("Bell in session '%1'",_nameTitle) );
00530 }
00531 else if (state==NOTIFYACTIVITY)
00532 {
00533 if (_monitorSilence) {
00534 _monitorTimer->start(_silenceSeconds*1000);
00535 }
00536
00537 if ( _monitorActivity ) {
00538
00539 if (!_notifiedActivity) {
00540 KNotification::event("Activity", i18n("Activity in session '%1'", _nameTitle), QPixmap(),
00541 QApplication::activeWindow(),
00542 KNotification::CloseWhenWidgetActivated);
00543 _notifiedActivity=true;
00544 }
00545 }
00546 }
00547
00548 if ( state==NOTIFYACTIVITY && !_monitorActivity )
00549 state = NOTIFYNORMAL;
00550 if ( state==NOTIFYSILENCE && !_monitorSilence )
00551 state = NOTIFYNORMAL;
00552
00553 emit stateChanged(state);
00554 }
00555
00556 void Session::onViewSizeChange(int , int )
00557 {
00558 updateTerminalSize();
00559 }
00560
00561 void Session::updateTerminalSize()
00562 {
00563 QListIterator<TerminalDisplay*> viewIter(_views);
00564
00565 int minLines = -1;
00566 int minColumns = -1;
00567
00568
00569
00570
00571 const int VIEW_LINES_THRESHOLD = 2;
00572 const int VIEW_COLUMNS_THRESHOLD = 2;
00573
00574
00575 while ( viewIter.hasNext() )
00576 {
00577 TerminalDisplay* view = viewIter.next();
00578 if ( view->isHidden() == false &&
00579 view->lines() >= VIEW_LINES_THRESHOLD &&
00580 view->columns() >= VIEW_COLUMNS_THRESHOLD )
00581 {
00582 minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() );
00583 minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() );
00584 }
00585 }
00586
00587
00588 if ( minLines > 0 && minColumns > 0 )
00589 {
00590 _emulation->setImageSize( minLines , minColumns );
00591 }
00592 }
00593 void Session::updateWindowSize(int lines, int columns)
00594 {
00595 Q_ASSERT(lines > 0 && columns > 0);
00596 _shellProcess->setWindowSize(lines,columns);
00597 }
00598 void Session::refresh()
00599 {
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 const QSize existingSize = _shellProcess->windowSize();
00615 _shellProcess->setWindowSize(existingSize.height(),existingSize.width()+1);
00616 _shellProcess->setWindowSize(existingSize.height(),existingSize.width());
00617 }
00618
00619 bool Session::kill(int signal)
00620 {
00621 int result = ::kill(_shellProcess->pid(),signal);
00622
00623 if ( result == 0 )
00624 {
00625 _shellProcess->waitForFinished();
00626 return true;
00627 }
00628 else
00629 return false;
00630 }
00631
00632 void Session::close()
00633 {
00634 _autoClose = true;
00635 _wantedClose = true;
00636
00637 if (!isRunning() || !kill(SIGHUP))
00638 {
00639
00640 QTimer::singleShot(1, this, SIGNAL(finished()));
00641 }
00642 }
00643
00644 void Session::sendText(const QString &text) const
00645 {
00646 _emulation->sendText(text);
00647 }
00648
00649 Session::~Session()
00650 {
00651 delete _emulation;
00652 delete _shellProcess;
00653 delete _zmodemProc;
00654 }
00655
00656 void Session::done(int exitStatus)
00657 {
00658 if (!_autoClose)
00659 {
00660 _userTitle = i18n("Finished");
00661 emit titleChanged();
00662 return;
00663 }
00664
00665 QString message;
00666 if (!_wantedClose || exitStatus != 0)
00667 {
00668 if (_shellProcess->exitStatus() == QProcess::NormalExit)
00669 message = i18n("Program '%1' exited with status %2.", _shellProcess->program().first(), exitStatus);
00670 else
00671 message = i18n("Program '%1' crashed.", _shellProcess->program().first());
00672
00673
00674 KNotification::event("Finished", message , QPixmap(),
00675 QApplication::activeWindow(),
00676 KNotification::CloseWhenWidgetActivated);
00677 }
00678
00679 if ( !_wantedClose && _shellProcess->exitStatus() != QProcess::NormalExit )
00680 terminalWarning(message);
00681 else
00682 emit finished();
00683 }
00684
00685 Emulation* Session::emulation() const
00686 {
00687 return _emulation;
00688 }
00689
00690 QString Session::keyBindings() const
00691 {
00692 return _emulation->keyBindings();
00693 }
00694
00695 QStringList Session::environment() const
00696 {
00697 return _environment;
00698 }
00699
00700 void Session::setEnvironment(const QStringList& environment)
00701 {
00702 _environment = environment;
00703 }
00704
00705 int Session::sessionId() const
00706 {
00707 return _sessionId;
00708 }
00709
00710 void Session::setKeyBindings(const QString &id)
00711 {
00712 _emulation->setKeyBindings(id);
00713 }
00714
00715 void Session::setTitle(TitleRole role , const QString& newTitle)
00716 {
00717 if ( title(role) != newTitle )
00718 {
00719 if ( role == NameRole )
00720 _nameTitle = newTitle;
00721 else if ( role == DisplayedTitleRole )
00722 _displayTitle = newTitle;
00723
00724 emit titleChanged();
00725 }
00726 }
00727
00728 QString Session::title(TitleRole role) const
00729 {
00730 if ( role == NameRole )
00731 return _nameTitle;
00732 else if ( role == DisplayedTitleRole )
00733 return _displayTitle;
00734 else
00735 return QString();
00736 }
00737
00738 void Session::setIconName(const QString& iconName)
00739 {
00740 if ( iconName != _iconName )
00741 {
00742 _iconName = iconName;
00743 emit titleChanged();
00744 }
00745 }
00746
00747 void Session::setIconText(const QString& iconText)
00748 {
00749 _iconText = iconText;
00750 }
00751
00752 QString Session::iconName() const
00753 {
00754 return _iconName;
00755 }
00756
00757 QString Session::iconText() const
00758 {
00759 return _iconText;
00760 }
00761
00762 void Session::setHistoryType(const HistoryType &hType)
00763 {
00764 _emulation->setHistory(hType);
00765 }
00766
00767 const HistoryType& Session::historyType() const
00768 {
00769 return _emulation->history();
00770 }
00771
00772 void Session::clearHistory()
00773 {
00774 _emulation->clearHistory();
00775 }
00776
00777 QStringList Session::arguments() const
00778 {
00779 return _arguments;
00780 }
00781
00782 QString Session::program() const
00783 {
00784 return _program;
00785 }
00786
00787
00788 bool Session::isMonitorActivity() const { return _monitorActivity; }
00789
00790 bool Session::isMonitorSilence() const { return _monitorSilence; }
00791
00792 void Session::setMonitorActivity(bool _monitor)
00793 {
00794 _monitorActivity=_monitor;
00795 _notifiedActivity=false;
00796
00797 activityStateSet(NOTIFYNORMAL);
00798 }
00799
00800 void Session::setMonitorSilence(bool _monitor)
00801 {
00802 if (_monitorSilence==_monitor)
00803 return;
00804
00805 _monitorSilence=_monitor;
00806 if (_monitorSilence)
00807 {
00808 _monitorTimer->start(_silenceSeconds*1000);
00809 }
00810 else
00811 _monitorTimer->stop();
00812
00813 activityStateSet(NOTIFYNORMAL);
00814 }
00815
00816 void Session::setMonitorSilenceSeconds(int seconds)
00817 {
00818 _silenceSeconds=seconds;
00819 if (_monitorSilence) {
00820 _monitorTimer->start(_silenceSeconds*1000);
00821 }
00822 }
00823
00824 void Session::setAddToUtmp(bool set)
00825 {
00826 _addToUtmp = set;
00827 }
00828
00829 void Session::setFlowControlEnabled(bool enabled)
00830 {
00831 _flowControl = enabled;
00832
00833 if (_shellProcess)
00834 _shellProcess->setFlowControlEnabled(_flowControl);
00835
00836 emit flowControlEnabledChanged(enabled);
00837 }
00838 bool Session::flowControlEnabled() const
00839 {
00840 if (_shellProcess)
00841 return _shellProcess->flowControlEnabled();
00842 else
00843 return _flowControl;
00844 }
00845 void Session::fireZModemDetected()
00846 {
00847 if (!_zmodemBusy)
00848 {
00849 QTimer::singleShot(10, this, SIGNAL(zmodemDetected()));
00850 _zmodemBusy = true;
00851 }
00852 }
00853
00854 void Session::cancelZModem()
00855 {
00856 _shellProcess->sendData("\030\030\030\030", 4);
00857 _zmodemBusy = false;
00858 }
00859
00860 void Session::startZModem(const QString &zmodem, const QString &dir, const QStringList &list)
00861 {
00862 _zmodemBusy = true;
00863 _zmodemProc = new KProcess();
00864 _zmodemProc->setOutputChannelMode( KProcess::SeparateChannels );
00865
00866 *_zmodemProc << zmodem << "-v" << list;
00867
00868 if (!dir.isEmpty())
00869 _zmodemProc->setWorkingDirectory(dir);
00870
00871 _zmodemProc->start();
00872
00873 connect(_zmodemProc,SIGNAL (readyReadStandardOutput()),
00874 this, SLOT(zmodemReadAndSendBlock()));
00875 connect(_zmodemProc,SIGNAL (readyReadStandardError()),
00876 this, SLOT(zmodemReadStatus()));
00877 connect(_zmodemProc,SIGNAL (finished(int,QProcess::ExitStatus)),
00878 this, SLOT(zmodemFinished()));
00879
00880 disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
00881 connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(zmodemRcvBlock(const char*,int)) );
00882
00883 _zmodemProgress = new ZModemDialog(QApplication::activeWindow(), false,
00884 i18n("ZModem Progress"));
00885
00886 connect(_zmodemProgress, SIGNAL(user1Clicked()),
00887 this, SLOT(zmodemDone()));
00888
00889 _zmodemProgress->show();
00890 }
00891
00892 void Session::zmodemReadAndSendBlock()
00893 {
00894 _zmodemProc->setReadChannel( QProcess::StandardOutput );
00895 QByteArray data = _zmodemProc->readAll();
00896
00897 if ( data.count() == 0 )
00898 return;
00899
00900 _shellProcess->sendData(data.constData(),data.count());
00901 }
00902
00903 void Session::zmodemReadStatus()
00904 {
00905 _zmodemProc->setReadChannel( QProcess::StandardError );
00906 QByteArray msg = _zmodemProc->readAll();
00907 while(!msg.isEmpty())
00908 {
00909 int i = msg.indexOf('\015');
00910 int j = msg.indexOf('\012');
00911 QByteArray txt;
00912 if ((i != -1) && ((j == -1) || (i < j)))
00913 {
00914 msg = msg.mid(i+1);
00915 }
00916 else if (j != -1)
00917 {
00918 txt = msg.left(j);
00919 msg = msg.mid(j+1);
00920 }
00921 else
00922 {
00923 txt = msg;
00924 msg.truncate(0);
00925 }
00926 if (!txt.isEmpty())
00927 _zmodemProgress->addProgressText(QString::fromLocal8Bit(txt));
00928 }
00929 }
00930
00931 void Session::zmodemRcvBlock(const char *data, int len)
00932 {
00933 QByteArray ba( data, len );
00934
00935 _zmodemProc->write( ba );
00936 }
00937
00938 void Session::zmodemFinished()
00939 {
00940 if (_zmodemProc)
00941 {
00942 delete _zmodemProc;
00943 _zmodemProc = 0;
00944 _zmodemBusy = false;
00945
00946 disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this ,SLOT(zmodemRcvBlock(const char*,int)) );
00947 connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
00948
00949 _shellProcess->sendData("\030\030\030\030", 4);
00950 _shellProcess->sendData("\001\013\n", 3);
00951 _zmodemProgress->transferDone();
00952 }
00953 }
00954
00955 void Session::onReceiveBlock( const char* buf, int len )
00956 {
00957 _emulation->receiveData( buf, len );
00958 emit receivedData( QString::fromLatin1( buf, len ) );
00959 }
00960
00961 QSize Session::size()
00962 {
00963 return _emulation->imageSize();
00964 }
00965
00966 void Session::setSize(const QSize& size)
00967 {
00968 if ((size.width() <= 1) || (size.height() <= 1))
00969 return;
00970
00971 emit resizeRequest(size);
00972 }
00973 int Session::foregroundProcessId() const
00974 {
00975 return _shellProcess->foregroundProcessGroup();
00976 }
00977 int Session::processId() const
00978 {
00979 return _shellProcess->pid();
00980 }
00981
00982 SessionGroup::SessionGroup(QObject* parent)
00983 : QObject(parent), _masterMode(0)
00984 {
00985 }
00986 SessionGroup::~SessionGroup()
00987 {
00988
00989 connectAll(false);
00990 }
00991 int SessionGroup::masterMode() const { return _masterMode; }
00992 QList<Session*> SessionGroup::sessions() const { return _sessions.keys(); }
00993 bool SessionGroup::masterStatus(Session* session) const { return _sessions[session]; }
00994
00995 void SessionGroup::addSession(Session* session)
00996 {
00997 connect(session,SIGNAL(finished()),this,SLOT(sessionFinished()));
00998
00999 _sessions.insert(session,false);
01000
01001 QListIterator<Session*> masterIter(masters());
01002
01003 while ( masterIter.hasNext() )
01004 connectPair(masterIter.next(),session);
01005 }
01006 void SessionGroup::removeSession(Session* session)
01007 {
01008 disconnect(session,SIGNAL(finished()),this,SLOT(sessionFinished()));
01009
01010 setMasterStatus(session,false);
01011
01012 QListIterator<Session*> masterIter(masters());
01013
01014 while ( masterIter.hasNext() )
01015 disconnectPair(masterIter.next(),session);
01016
01017 _sessions.remove(session);
01018 }
01019 void SessionGroup::sessionFinished()
01020 {
01021 Session* session = qobject_cast<Session*>(sender());
01022 Q_ASSERT(session);
01023 removeSession(session);
01024 }
01025 void SessionGroup::setMasterMode(int mode)
01026 {
01027 _masterMode = mode;
01028
01029 connectAll(false);
01030 connectAll(true);
01031 }
01032 QList<Session*> SessionGroup::masters() const
01033 {
01034 return _sessions.keys(true);
01035 }
01036 void SessionGroup::connectAll(bool connect)
01037 {
01038 QListIterator<Session*> masterIter(masters());
01039
01040 while ( masterIter.hasNext() )
01041 {
01042 Session* master = masterIter.next();
01043
01044 QListIterator<Session*> otherIter(_sessions.keys());
01045 while ( otherIter.hasNext() )
01046 {
01047 Session* other = otherIter.next();
01048
01049 if ( other != master )
01050 {
01051 if ( connect )
01052 connectPair(master,other);
01053 else
01054 disconnectPair(master,other);
01055 }
01056 }
01057 }
01058 }
01059 void SessionGroup::setMasterStatus(Session* session , bool master)
01060 {
01061 bool wasMaster = _sessions[session];
01062 _sessions[session] = master;
01063
01064 if ( ( !wasMaster && !master )
01065 || ( wasMaster && master ) )
01066 return;
01067
01068 QListIterator<Session*> iter(_sessions.keys());
01069 while ( iter.hasNext() )
01070 {
01071 Session* other = iter.next();
01072
01073 if ( other != session )
01074 {
01075 if ( master )
01076 connectPair(session,other);
01077 else
01078 disconnectPair(session,other);
01079 }
01080 }
01081 }
01082 void SessionGroup::connectPair(Session* master , Session* other)
01083 {
01084 if ( _masterMode & CopyInputToAll )
01085 {
01086 connect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
01087 SLOT(sendString(const char*,int)) );
01088 }
01089 }
01090 void SessionGroup::disconnectPair(Session* master , Session* other)
01091 {
01092 if ( _masterMode & CopyInputToAll )
01093 {
01094 disconnect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
01095 SLOT(sendString(const char*,int)) );
01096 }
01097 }
01098
01099 #include "Session.moc"