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