1 /*
2     This file is part of Konsole, an X terminal.
3 
4     Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
5     Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
6 
7     Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22     02110-1301  USA.
23 */
24 
25 #ifndef SESSION_H
26 #define SESSION_H
27 
28 #include <QStringList>
29 #include <QWidget>
30 
31 #include "Emulation.h"
32 #include "History.h"
33 #include "ProcessInfo.h"
34 
35 class KProcess;
36 
37 namespace Konsole {
38 
39 class Emulation;
40 class Pty;
41 class TerminalDisplay;
42 //class ZModemDialog;
43 
44 /**
45  * Represents a terminal session consisting of a pseudo-teletype and a terminal emulation.
46  * The pseudo-teletype (or PTY) handles I/O between the terminal process and Konsole.
47  * The terminal emulation ( Emulation and subclasses ) processes the output stream from the
48  * PTY and produces a character image which is then shown on views connected to the session.
49  *
50  * Each Session can be connected to one or more views by using the addView() method.
51  * The attached views can then display output from the program running in the terminal
52  * or send input to the program in the terminal in the form of keypresses and mouse
53  * activity.
54  */
55 class Session : public QObject {
56     Q_OBJECT
57 
58 public:
59     Q_PROPERTY(QString name READ nameTitle)
60     Q_PROPERTY(int processId READ processId)
61     Q_PROPERTY(QString keyBindings READ keyBindings WRITE setKeyBindings)
62     Q_PROPERTY(QSize size READ size WRITE setSize)
63 
64     /**
65      * Constructs a new session.
66      *
67      * To start the terminal process, call the run() method,
68      * after specifying the program and arguments
69      * using setProgram() and setArguments()
70      *
71      * If no program or arguments are specified explicitly, the Session
72      * falls back to using the program specified in the SHELL environment
73      * variable.
74      */
75     Session(QObject* parent = 0);
76     virtual ~Session();
77 
78     /**
79      * Returns true if the session is currently running.  This will be true
80      * after run() has been called successfully.
81      */
82     bool isRunning() const;
83 
84     /**
85      * Sets the profile associated with this session.
86      *
87      * @param profileKey A key which can be used to obtain the current
88      * profile settings from the SessionManager
89      */
90     void setProfileKey(const QString & profileKey);
91     /**
92      * Returns the profile key associated with this session.
93      * This can be passed to the SessionManager to obtain the current
94      * profile settings.
95      */
96     QString profileKey() const;
97 
98     /**
99      * Adds a new view for this session.
100      *
101      * The viewing widget will display the output from the terminal and
102      * input from the viewing widget (key presses, mouse activity etc.)
103      * will be sent to the terminal.
104      *
105      * Views can be removed using removeView().  The session is automatically
106      * closed when the last view is removed.
107      */
108     void addView(TerminalDisplay * widget);
109     /**
110      * Removes a view from this session.  When the last view is removed,
111      * the session will be closed automatically.
112      *
113      * @p widget will no longer display output from or send input
114      * to the terminal
115      */
116     void removeView(TerminalDisplay * widget);
117 
118     /**
119      * Returns the views connected to this session
120      */
121     QList<TerminalDisplay *> views() const;
122 
123     /**
124      * Returns the terminal emulation instance being used to encode / decode
125      * characters to / from the process.
126      */
127     Emulation * emulation() const;
128 
129     /**
130      * Returns the environment of this session as a list of strings like
131      * VARIABLE=VALUE
132      */
133     QStringList environment() const;
134     /**
135      * Sets the environment for this session.
136      * @p environment should be a list of strings like
137      * VARIABLE=VALUE
138      */
139     void setEnvironment(const QStringList & environment);
140 
141     /** Returns the unique ID for this session. */
142     int sessionId() const;
143 
144     /**
145      * Return the session title set by the user (ie. the program running
146      * in the terminal), or an empty string if the user has not set a custom title
147      */
148     QString userTitle() const;
149 
150     /**
151      * This enum describes the contexts for which separate
152      * tab title formats may be specified.
153      */
154     enum TabTitleContext {
155         /** Default tab title format */
156         LocalTabTitle,
157         /**
158          * Tab title format used session currently contains
159          * a connection to a remote computer (via SSH)
160          */
161         RemoteTabTitle
162     };
163     /**
164      * Sets the format used by this session for tab titles.
165      *
166      * @param context The context whoose format should be set.
167      * @param format The tab title format.  This may be a mixture
168      * of plain text and dynamic elements denoted by a '%' character
169      * followed by a letter.  (eg. %d for directory).  The dynamic
170      * elements available depend on the @p context
171      */
172     void setTabTitleFormat(TabTitleContext context , const QString & format);
173     /** Returns the format used by this session for tab titles. */
174     QString tabTitleFormat(TabTitleContext context) const;
175 
176 
177     /** Returns the arguments passed to the shell process when run() is called. */
178     QStringList arguments() const;
179     /** Returns the program name of the shell process started when run() is called. */
180     QString program() const;
181 
182     /**
183      * Sets the command line arguments which the session's program will be passed when
184      * run() is called.
185      */
186     void setArguments(const QStringList & arguments);
187     /** Sets the program to be executed when run() is called. */
188     void setProgram(const QString & program);
189 
190     /** Returns the session's current working directory. */
initialWorkingDirectory()191     QString initialWorkingDirectory() {
192         return _initialWorkingDir;
193     }
194 
195     /**
196      * Sets the initial working directory for the session when it is run
197      * This has no effect once the session has been started.
198      */
199     void setInitialWorkingDirectory( const QString & dir );
200 
201     /**
202      * Sets the type of history store used by this session.
203      * Lines of output produced by the terminal are added
204      * to the history store.  The type of history store
205      * used affects the number of lines which can be
206      * remembered before they are lost and the storage
207      * (in memory, on-disk etc.) used.
208      */
209     void setHistoryType(const HistoryType & type);
210     /**
211      * Returns the type of history store used by this session.
212      */
213     const HistoryType & historyType() const;
214     /**
215      * Clears the history store used by this session.
216      */
217     void clearHistory();
218 
219     /**
220      * Enables monitoring for activity in the session.
221      * This will cause notifySessionState() to be emitted
222      * with the NOTIFYACTIVITY state flag when output is
223      * received from the terminal.
224      */
225     void setMonitorActivity(bool);
226     /** Returns true if monitoring for activity is enabled. */
227     bool isMonitorActivity() const;
228 
229     /**
230      * Enables monitoring for silence in the session.
231      * This will cause notifySessionState() to be emitted
232      * with the NOTIFYSILENCE state flag when output is not
233      * received from the terminal for a certain period of
234      * time, specified with setMonitorSilenceSeconds()
235      */
236     void setMonitorSilence(bool);
237     /**
238      * Returns true if monitoring for inactivity (silence)
239      * in the session is enabled.
240      */
241     bool isMonitorSilence()  const;
242     /** See setMonitorSilence() */
243     void setMonitorSilenceSeconds(int seconds);
244 
245     /**
246      * Sets the key bindings used by this session.  The bindings
247      * specify how input key sequences are translated into
248      * the character stream which is sent to the terminal.
249      *
250      * @param id The name of the key bindings to use.  The
251      * names of available key bindings can be determined using the
252      * KeyboardTranslatorManager class.
253      */
254     void setKeyBindings(const QString & id);
255     /** Returns the name of the key bindings used by this session. */
256     QString keyBindings() const;
257 
258     /**
259      * This enum describes the available title roles.
260      */
261     enum TitleRole {
262         /** The name of the session. */
263         NameRole,
264         /** The title of the session which is displayed in tabs etc. */
265         DisplayedTitleRole
266     };
267 
268     /** Sets the session's title for the specified @p role to @p title. */
269     void setTitle(TitleRole role , const QString & title);
270     /** Returns the session's title for the specified @p role. */
271     QString title(TitleRole role) const;
272     /** Convenience method used to read the name property.  Returns title(Session::NameRole). */
nameTitle()273     QString nameTitle() const {
274         return title(Session::NameRole);
275     }
276 
277     /** Sets the name of the icon associated with this session. */
278     void setIconName(const QString & iconName);
279     /** Returns the name of the icon associated with this session. */
280     QString iconName() const;
281 
282     /** Sets the text of the icon associated with this session. */
283     void setIconText(const QString & iconText);
284     /** Returns the text of the icon associated with this session. */
285     QString iconText() const;
286 
287     /** Flag if the title/icon was changed by user/shell. */
288     bool isTitleChanged() const;
289 
290     /** Specifies whether a utmp entry should be created for the pty used by this session. */
291     void setAddToUtmp(bool);
292 
293     /** Sends the specified @p signal to the terminal process. */
294     bool sendSignal(int signal);
295 
296     /**
297      * Specifies whether to close the session automatically when the terminal
298      * process terminates.
299      */
setAutoClose(bool b)300     void setAutoClose(bool b) {
301         _autoClose = b;
302     }
303 
304     /**
305      * Sets whether flow control is enabled for this terminal
306      * session.
307      */
308     void setFlowControlEnabled(bool enabled);
309 
310     /** Returns whether flow control is enabled for this terminal session. */
311     bool flowControlEnabled() const;
312 
313     /**
314      * Sends @p text to the current foreground terminal program.
315      */
316     void sendText(const QString & text) const;
317 
318     /**
319      * Returns the process id of the terminal process.
320      * This is the id used by the system API to refer to the process.
321      */
322     int processId() const;
323 
324     /**
325      * Returns the process id of the terminal's foreground process.
326      * This is initially the same as processId() but can change
327      * as the user starts other programs inside the terminal.
328      */
329     int foregroundProcessId() const;
330 
331     /**
332      * Returns the name of the terminal's foreground process.
333      */
334     QString foregroundProcessName();
335 
336     /** Returns the terminal session's window size in lines and columns. */
337     QSize size();
338     /**
339      * Emits a request to resize the session to accommodate
340      * the specified window size.
341      *
342      * @param size The size in lines and columns to request.
343      */
344     void setSize(const QSize & size);
345 
346     /** Sets the text codec used by this session's terminal emulation. */
347     void setCodec(QTextCodec * codec);
348 
349     /**
350      * Sets whether the session has a dark background or not.  The session
351      * uses this information to set the COLORFGBG variable in the process's
352      * environment, which allows the programs running in the terminal to determine
353      * whether the background is light or dark and use appropriate colors by default.
354      *
355      * This has no effect once the session is running.
356      */
357     void setDarkBackground(bool darkBackground);
358     /**
359      * Returns true if the session has a dark background.
360      * See setDarkBackground()
361      */
362     bool hasDarkBackground() const;
363 
364     /**
365      * Attempts to get the shell program to redraw the current display area.
366      * This can be used after clearing the screen, for example, to get the
367      * shell to redraw the prompt line.
368      */
369     void refresh();
370 
371 //  void startZModem(const QString &rz, const QString &dir, const QStringList &list);
372 //  void cancelZModem();
373 //  bool isZModemBusy() { return _zmodemBusy; }
374 
375     /**
376      * Returns a pty slave file descriptor.
377      * This can be used for display and control
378      * a remote terminal.
379      */
380     int getPtySlaveFd() const;
381 
382 public slots:
383 
384     /**
385      * Starts the terminal session.
386      *
387      * This creates the terminal process and connects the teletype to it.
388      */
389     void run();
390 
391     /**
392      * Starts the terminal session for "as is" PTY
393      * (without the direction a data to internal terminal process).
394      * It can be used for control or display a remote/external terminal.
395      */
396     void runEmptyPTY();
397 
398     /**
399      * Closes the terminal session.  This sends a hangup signal
400      * (SIGHUP) to the terminal process and causes the done(Session*)
401      * signal to be emitted.
402      */
403     void close();
404 
405     /**
406      * Changes the session title or other customizable aspects of the terminal
407      * emulation display. For a list of what may be changed see the
408      * Emulation::titleChanged() signal.
409      */
410     void setUserTitle( int, const QString & caption );
411 
412 signals:
413 
414     /** Emitted when the terminal process starts. */
415     void started();
416 
417     /**
418      * Emitted when the terminal process exits.
419      */
420     void finished();
421 
422     /**
423      * Emitted when output is received from the terminal process.
424      */
425     void receivedData( const QString & text );
426 
427     /** Emitted when the session's title has changed. */
428     void titleChanged();
429 
430     /** Emitted when the session's profile has changed. */
431     void profileChanged(const QString & profile);
432 
433     /**
434      * Emitted when the activity state of this session changes.
435      *
436      * @param state The new state of the session.  This may be one
437      * of NOTIFYNORMAL, NOTIFYSILENCE or NOTIFYACTIVITY
438      */
439     void stateChanged(int state);
440 
441     /** Emitted when a bell event occurs in the session. */
442     void bellRequest( const QString & message );
443 
444     /**
445      * Requests that the color the text for any tabs associated with
446      * this session should be changed;
447      *
448      * TODO: Document what the parameter does
449      */
450     void changeTabTextColorRequest(int);
451 
452     /**
453      * Requests that the background color of views on this session
454      * should be changed.
455      */
456     void changeBackgroundColorRequest(const QColor &);
457 
458     /** TODO: Document me. */
459     void openUrlRequest(const QString & url);
460 
461     /** TODO: Document me. */
462 //  void zmodemDetected();
463 
464     /**
465      * Emitted when the terminal process requests a change
466      * in the size of the terminal window.
467      *
468      * @param size The requested window size in terms of lines and columns.
469      */
470     void resizeRequest(const QSize & size);
471 
472     /**
473      * Emitted when a profile change command is received from the terminal.
474      *
475      * @param text The text of the command.  This is a string of the form
476      * "PropertyName=Value;PropertyName=Value ..."
477      */
478     void profileChangeCommandReceived(const QString & text);
479 
480     /**
481      * Emitted when the flow control state changes.
482      *
483      * @param enabled True if flow control is enabled or false otherwise.
484      */
485     void flowControlEnabledChanged(bool enabled);
486 
487     /**
488      * Broker for Emulation::cursorChanged() signal
489      */
490     void cursorChanged(Emulation::KeyboardCursorShape cursorShape, bool blinkingCursorEnabled);
491 
492     void silence();
493     void activity();
494 
495 private slots:
496     void done(int);
497 
498 //  void fireZModemDetected();
499 
500     void onReceiveBlock( const char * buffer, int len );
501     void monitorTimerDone();
502 
503     void onViewSizeChange(int height, int width);
504     void onEmulationSizeChange(QSize);
505 
506     void activityStateSet(int);
507 
508     //automatically detach views from sessions when view is destroyed
509     void viewDestroyed(QObject * view);
510 
511 //  void zmodemReadStatus();
512 //  void zmodemReadAndSendBlock();
513 //  void zmodemRcvBlock(const char *data, int len);
514 //  void zmodemFinished();
515 
516 private:
517 
518     void updateTerminalSize();
519     bool updateForegroundProcessInfo();
520     WId windowId() const;
521 
522     int            _uniqueIdentifier;
523 
524     Pty     *_shellProcess;
525     Emulation  *  _emulation;
526 
527     QList<TerminalDisplay *> _views;
528 
529     bool           _monitorActivity;
530     bool           _monitorSilence;
531     bool           _notifiedActivity;
532     bool           _masterMode;
533     bool           _autoClose;
534     bool           _wantedClose;
535     QTimer    *    _monitorTimer;
536 
537     int            _silenceSeconds;
538 
539     QString        _nameTitle;
540     QString        _displayTitle;
541     QString        _userTitle;
542 
543     QString        _localTabTitleFormat;
544     QString        _remoteTabTitleFormat;
545 
546     QString        _iconName;
547     QString        _iconText; // as set by: echo -en '\033]1;IconText\007
548     bool           _isTitleChanged; ///< flag if the title/icon was changed by user
549     bool           _addToUtmp;
550     bool           _flowControl;
551     bool           _fullScripting;
552 
553     QString        _program;
554     QStringList    _arguments;
555 
556     QStringList    _environment;
557     int            _sessionId;
558 
559     QString        _initialWorkingDir;
560 
561     // ZModem
562 //  bool           _zmodemBusy;
563 //  KProcess*      _zmodemProc;
564 //  ZModemDialog*  _zmodemProgress;
565 
566     // Color/Font Changes by ESC Sequences
567 
568     QColor         _modifiedBackground; // as set by: echo -en '\033]11;Color\007
569 
570     QString        _profileKey;
571 
572     bool _hasDarkBackground;
573 
574     ProcessInfo *_foregroundProcessInfo;
575     int _foregroundPid;
576     static int lastSessionId;
577     int ptySlaveFd;
578 };
579 
580 /**
581  * Provides a group of sessions which is divided into master and slave sessions.
582  * Activity in master sessions can be propagated to all sessions within the group.
583  * The type of activity which is propagated and method of propagation is controlled
584  * by the masterMode() flags.
585  */
586 class SessionGroup : public QObject {
587     Q_OBJECT
588 
589 public:
590     /** Constructs an empty session group. */
591     SessionGroup();
592     /** Destroys the session group and removes all connections between master and slave sessions. */
593     ~SessionGroup();
594 
595     /** Adds a session to the group. */
596     void addSession( Session * session );
597     /** Removes a session from the group. */
598     void removeSession( Session * session );
599 
600     /** Returns the list of sessions currently in the group. */
601     QList<Session *> sessions() const;
602 
603     /**
604      * Sets whether a particular session is a master within the group.
605      * Changes or activity in the group's master sessions may be propagated
606      * to all the sessions in the group, depending on the current masterMode()
607      *
608      * @param session The session whoose master status should be changed.
609      * @param master True to make this session a master or false otherwise
610      */
611     void setMasterStatus( Session * session , bool master );
612     /** Returns the master status of a session.  See setMasterStatus() */
613     bool masterStatus( Session * session ) const;
614 
615     /**
616      * This enum describes the options for propagating certain activity or
617      * changes in the group's master sessions to all sessions in the group.
618      */
619     enum MasterMode {
620         /**
621          * Any input key presses in the master sessions are sent to all
622          * sessions in the group.
623          */
624         CopyInputToAll = 1
625     };
626 
627     /**
628      * Specifies which activity in the group's master sessions is propagated
629      * to all sessions in the group.
630      *
631      * @param mode A bitwise OR of MasterMode flags.
632      */
633     void setMasterMode( int mode );
634     /**
635      * Returns a bitwise OR of the active MasterMode flags for this group.
636      * See setMasterMode()
637      */
638     int masterMode() const;
639 
640 private:
641     void connectPair(Session * master , Session * other);
642     void disconnectPair(Session * master , Session * other);
643     void connectAll(bool connect);
644     QList<Session *> masters() const;
645 
646     // maps sessions to their master status
647     QHash<Session *,bool> _sessions;
648 
649     int _masterMode;
650 };
651 
652 }
653 
654 #endif
655