-
Notifications
You must be signed in to change notification settings - Fork 0
/
SeTerm.c
345 lines (271 loc) · 8.86 KB
/
SeTerm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/*
* This file is part of the Seyon, Copyright (c) 1992-1993 by Muhammad M.
* Saggaf. All rights reserved.
*
* See the file COPYING (1-COPYING) or the manual page seyon(1) for a full
* statement of rights and permissions for this program.
*/
/*
* This file contains routines for Seyon's terminal. The main routine is
* terminal(), which reads characters from the terminal and sends them to the
* port. That routine also forks a child process that reads characters from
* the port and writes them to the terminal. Once the parent receives SIGTERM
* (which should be sent by the grand parent), it kills the child and exits.
*/
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <X11/Intrinsic.h>
#include "SeDecl.h"
#include "seyon.h"
extern char TtyReadChar();
extern int MdmReadStr();
extern FILE *tfp, /* terminal pointer */
*cfp; /* capture file pointer */
extern Boolean capture; /* are we capturing or not ? */
extern int tfd, /* terminal descriptor */
mainToTermPipe[];
extern pid_t mainPid;
void send_tbyte(), toggle(), cleanup();
pid_t readProcPid = 0; /* pid of child process */
/*---------------------------------------------------------------------------+
| DoNothingHandler - handler for doing nothing.
+---------------------------------------------------------------------------*/
void DoNothingHandler(sigNum) int sigNum;
{
#ifdef DEBUG
showf(">>> in DoNothingHandler, pid = %d, sig = %d", getpid(), sigNum);
#endif
/* Reinstall the signal handler */
signal(sigNum, DoNothingHandler);
}
/*---------------------------------------------------------------------------+
| TerminalKillHandler - handler for the terminal kill (SIGTERM).
+---------------------------------------------------------------------------*/
void TerminalKillHandler(dummy) int dummy;
{
signal(SIGTERM, SIG_IGN);
/* Kill the child process and wait for it to die, sounds vicious,
doesn't it? The child process is the read process from the port */
if (readProcPid && kill(readProcPid, SIGTERM) == 0)
while (wait((int *)0) < 0)
;
fflush(tfp);
exit(0);
}
/*---------------------------------------------------------------------------+
| TerminalSuspendHandler - handler for the terminal suspension (SIGUSR1).
+---------------------------------------------------------------------------*/
void TerminalSuspendHandler(sigNum) int sigNum;
{
/* Don't deliver or stack (as pending) any more instances of the signal
until we've woken up (below) */
signal(sigNum, SIG_IGN);
if (readProcPid)
kill(readProcPid, sigNum);
pause();
#ifdef DEBUG
showf(">>> Terminal %d woke up - good", getpid());
#endif
/* After waking up */
if (readProcPid)
kill(readProcPid, SIGCONT);
/* Reinstall the signal handler */
signal(sigNum, TerminalSuspendHandler);
}
/*---------------------------------------------------------------------------+
| TerminalRefreshParametersHandler - handler for the terminal to get the
| current session parameters (SIGUSR2).
+---------------------------------------------------------------------------*/
void TerminalRefreshParametersHandler(sigNum) int sigNum;
{
int PutParameters();
void GetParameters();
/* Don't deliver or stack (as pending) any more instances of the signal
until we're finished with the work at hand */
signal(sigNum, SIG_IGN);
GetParameters(NULL, mainToTermPipe);
if (readProcPid &&
(PutParameters(mainToTermPipe) < 0 || kill(readProcPid, sigNum) != 0))
SePError("Could not pipe parameters");
/* Reinstall the signal handler */
signal(sigNum, TerminalRefreshParametersHandler);
}
/*
* Terminal: main routine. Has two processes, one to read from terminal
* and send to the port and the other to do the oppsite.
*/
void Terminal() {
char c;
/* Tell the program where to go when signals are received */
signal(SIGTERM, TerminalKillHandler);
signal(SIGUSR1, TerminalSuspendHandler);
signal(SIGUSR2, TerminalRefreshParametersHandler);
signal(SIGCONT, DoNothingHandler);
signal(SIGCHLD, SIG_DFL);
/* Split into read and write processes */
/* Child, read proc: read from port and write to tty */
if ((readProcPid = SeFork()) == 0)
PortToTty();
/* Parent, write proc: read from tty and write to port */
while (1)
if (TtyReadChar(tfd, &c) >= 0)
send_tbyte(c);
else {
SeError("TTY read error. Terminal process exiting");
if (readProcPid && kill(readProcPid, SIGTERM) == 0)
while (wait((int *)0) < 0)
;
ProcRequest(POPUP_ERROR, "TTY Read Error", "errReadError");
exit(1);
}
/*NOT REACHED*/
}
/*
* Read from the port and write to the tty
*/
void PortToTty() {
static char zmSig[] = "**\030B00";
static char *zmSigPtr = zmSig;
char buf[BUFSIZ], c;
int n, i;
signal(SIGTERM, TerminalKillHandler);
/* Let the main process know we're all set */
kill(mainPid, SIGCONT);
while (1) {
/* Read incoming charaters and exit the process if a read error
is encountered */
if ((n = MdmReadStr(buf)) < 0) {
SeError("Modem read error. Terminal process exiting");
ProcRequest(POPUP_ERROR, "Modem Read Error", "errReadError");
ProcRequest(KILL_TERM, "", "");
exit(1);
}
/* Write incoming characters to the tty */
fwrite(buf, sizeof(char), n, tfp);
fflush(tfp);
for (i = 0; i < n; i++) {
c = buf[i];
/* Write to capture file if capture is enabled */
if (capture)
fputc(c, cfp);
/* Look for Zmodem signature */
if (c != *zmSigPtr)
zmSigPtr = zmSig;
else if (*++zmSigPtr == '\0' && qres.autoZmodem)
ProcRequest(DISPATCH_ACTION, "Zmodem Auto-Download",
qres.autoZmodemAction);
} /* for... */
} /* while(1)... */
/*NOT REACHED*/
}
/*
* send a translated character to the modem
*/
void send_tbyte(c) int c;
{
switch (c) {
/*Translate new line to carriage return if newline translation mode is
in effect*/
case '\n':
switch (newlineTrMode) {
case 2:
c = '\r';
break;
case 3:
sendbyte('\r');
default:
break;
}
break;
/*Translate backspace to delete if del translation mode is in effect*/
case 0x08:
if (qres.backspaceTranslation)
c = 0x7f;
break;
default:
break;
}
/*Send ESC before the character if meta key is pressed with the character
and the meta key translation mode is on*/
if (qres.metaKeyTranslation && (c & 0x80)) {
sendbyte('\033');
sendbyte(c);
}
/*Send the character to the port*/
else
sendbyte(c);
}
/*---------------------------------------------------------------------------+
| Routines to manipulate the terminal process.
+---------------------------------------------------------------------------*/
pid_t termProcPid = 0; /* pid of the terminal process */
/*---------------------------------------------------------------------------+
| StartTerminal - starts the terminal process.
+---------------------------------------------------------------------------*/
void StartTerminal() {
/* Child Process */
if ((termProcPid = SeFork()) == 0) {
Terminal();
exit(1);
}
}
/*---------------------------------------------------------------------------+
| KillTerminal - kills the terminal process.
+---------------------------------------------------------------------------*/
void KillTerminal() {
void (*oldSigHandler)();
if (termProcPid == 0)
return;
/* Make sure it's not suspended so that it can react to SIGTERM */
/* if (SuspContTerminal(TERM_CONTINUE) == 0) return;*/
oldSigHandler = signal(SIGCHLD, SIG_DFL);
/* Kill the child and wait for it to die */
if (termProcPid && kill(termProcPid, SIGTERM) == 0) {
while (wait((int *)0) < 0)
;
termProcPid = 0;
}
signal(SIGCHLD, oldSigHandler);
}
/*---------------------------------------------------------------------------+
| SuspContTerminal - suspends or resumes the terminal process.
+---------------------------------------------------------------------------*/
int SuspContTerminal(state) int state;
{
/* This variable keeps track of whether
the terminal is active or suspended */
static int termSuspended = 0;
if (termProcPid == 0)
return 0;
if (state == TERM_CONTINUE) {
if (termProcPid && kill(termProcPid, SIGCONT) == 0)
termSuspended = 0;
return 1;
}
if (termSuspended)
return 0;
if (termProcPid && kill(termProcPid, SIGUSR1) == 0) {
termSuspended = 1;
return 1;
} else
return 0;
}
int TerminalRefreshParameters() {
int PutParameters();
if (termProcPid &&
(PutParameters(mainToTermPipe) < 0 || kill(termProcPid, SIGUSR2) != 0))
return -1;
else
return 0;
}
/*
* Restart the terminal process (refresh) by killing it and starting a new
* one
*/
void RestartTerminal() {
KillTerminal();
StartTerminal();
}