~ubuntu-branches/ubuntu/warty/dnprogs/warty

« back to all changes in this revision

Viewing changes to dnlogin/tty.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Caulfield
  • Date: 2004-05-30 10:13:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040530101357-1geqhhh0teccu0cm
Tags: 2.27
* Fix signal handling in sethost so it doesn't die with an embarrassing
  "Alarm clock" message.
* Add dependancy on modutils. Closes: #251508

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
    (c) 2002-2003      P.J. Caulfield          patrick@debian.org
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 ******************************************************************************
 
14
 */
 
15
 
 
16
#include <stdio.h>
 
17
#include <string.h>
 
18
#include <errno.h>
 
19
#include <unistd.h>
 
20
#include <signal.h>
 
21
#include <stdlib.h>
 
22
#include <ctype.h>
 
23
#include <termios.h>
 
24
#include <sys/socket.h>
 
25
#include <sys/ioctl.h>
 
26
#include <sys/types.h>
 
27
#include <sys/time.h>
 
28
#include <sys/fcntl.h>
 
29
#include <netdnet/dn.h>
 
30
#include <netdnet/dnetdb.h>
 
31
#include "dn_endian.h"
 
32
#include "dnlogin.h"
 
33
#include "tty.h"
 
34
 
 
35
/* The global state */
 
36
extern int termfd;
 
37
extern int exit_char;
 
38
extern int finished;
 
39
 
 
40
/* Input state buffers & variables */
 
41
static unsigned char terminators[32];
 
42
static char rahead_buf[128];
 
43
static int  rahead_len=0;
 
44
static char input_buf[1024];
 
45
static int  input_len=0;
 
46
static int  input_pos=0;
 
47
static char prompt_buf[1024];
 
48
static char prompt_len=0;
 
49
static char esc_buf[132];
 
50
static int  esc_len=0;
 
51
static int  max_read_len = sizeof(input_buf);
 
52
static int  echo = 1;
 
53
static int  reading = 0;
 
54
static int  insert_mode = 0;
 
55
static int  echo_terminator = 0;
 
56
 
 
57
/* in dnlogin.c */
 
58
extern int  char_timeout;
 
59
 
 
60
/* Output processors */
 
61
int (*send_input)(unsigned char *buf, int len, int flags);
 
62
int (*send_oob)(char oobchar, int discard);
 
63
 
 
64
static void send_input_buffer(int flags)
 
65
{
 
66
    char buf[1024];
 
67
 
 
68
    memcpy(buf, input_buf, input_len);
 
69
 
 
70
    send_input(buf, input_len, flags);
 
71
    input_len = input_pos = 0;
 
72
    reading = 0;
 
73
    echo = 1;
 
74
}
 
75
 
 
76
/* Raw write to terminal */
 
77
int tty_write(unsigned char *buf, int len)
 
78
{
 
79
    int i;
 
80
 
 
81
    for (i=0; i<len; i++)
 
82
    {
 
83
        if (buf[i] == '\r')
 
84
            write(termfd, "\r\n", 2);
 
85
        else
 
86
            write(termfd, &buf[i], 1);
 
87
    }
 
88
    return len;
 
89
}
 
90
 
 
91
void tty_set_noecho()
 
92
{
 
93
    echo = 0;
 
94
}
 
95
 
 
96
void tty_echo_terminator(int a)
 
97
{
 
98
    if (debug & 4)
 
99
        fprintf(stderr, "TTY: echo terminators = %d\n", a);
 
100
 
 
101
    echo_terminator = a;
 
102
}
 
103
 
 
104
void tty_set_default_terminators()
 
105
{
 
106
    if (debug & 4)
 
107
        fprintf(stderr, "TTY: set default terminators\n");
 
108
 
 
109
    /* All control chars except ^R ^U ^W, BS & HT */
 
110
    /* ie 18, 21, 23, 8, 9 */
 
111
    memset(terminators, 0, sizeof(terminators));
 
112
    terminators[0] = 0x7F;
 
113
    terminators[1] = 0xFE;
 
114
    terminators[2] = 0xAD;
 
115
    terminators[3] = 0xFF;
 
116
}
 
117
 
 
118
void tty_set_terminators(unsigned char *buf, int len)
 
119
{
 
120
    if (debug & 4)
 
121
        fprintf(stderr, "TTY: set terminators... %d bytes\n", len);
 
122
    memset(terminators, 0, sizeof(terminators));
 
123
    memcpy(terminators, buf, len);
 
124
}
 
125
 
 
126
void tty_start_read(char *prompt, int len, int promptlen)
 
127
{
 
128
    if (debug & 4)
 
129
        fprintf(stderr, "TTY: start_read promptlen = %d, maxlen=%d\n",
 
130
                promptlen, len);
 
131
    if (promptlen) write(termfd, prompt, promptlen);
 
132
    if (len < 0) len = sizeof(input_buf);
 
133
 
 
134
    /* Save the actual prompt in one buffer and the prefilled
 
135
       data in the input buffer */
 
136
    memcpy(prompt_buf, prompt, promptlen);
 
137
    prompt_len = promptlen;
 
138
 
 
139
    memcpy(input_buf, prompt+promptlen, len);
 
140
    input_len = 0;
 
141
    input_pos = input_len;
 
142
    max_read_len = len;
 
143
 
 
144
    /* Now add in any typeahead */
 
145
    if (rahead_len)
 
146
    {
 
147
        int copylen = rahead_len;
 
148
 
 
149
        if (debug & 4)
 
150
            fprintf(stderr, "TTY: readahead = %d bytes\n", rahead_len);
 
151
 
 
152
        /* Don't overflow the input buffer */
 
153
        if (input_len + copylen > sizeof(input_buf))
 
154
            copylen = sizeof(input_buf)-input_len;
 
155
 
 
156
        memcpy(input_buf+input_len, rahead_buf, copylen);
 
157
        input_len += copylen;
 
158
        rahead_len = 0;
 
159
    }
 
160
    reading = 1;
 
161
}
 
162
 
 
163
void tty_set_timeout(unsigned short to)
 
164
{
 
165
    char_timeout = to;
 
166
}
 
167
 
 
168
void tty_clear_typeahead()
 
169
{
 
170
    rahead_len = 0;
 
171
}
 
172
 
 
173
void tty_set_maxlen(unsigned short len)
 
174
{
 
175
    max_read_len = len;
 
176
}
 
177
 
 
178
/* Set/Reset the local TTY mode */
 
179
int tty_setup(char *name, int setup)
 
180
{
 
181
    struct termios new_term;
 
182
    static struct termios old_term;
 
183
 
 
184
    if (setup)
 
185
    {
 
186
        termfd = open(name, O_RDWR);
 
187
 
 
188
        tcgetattr(termfd, &old_term);
 
189
        new_term = old_term;
 
190
 
 
191
        new_term.c_iflag &= ~BRKINT;
 
192
        new_term.c_iflag |= IGNBRK;
 
193
        new_term.c_lflag &= ~ISIG;
 
194
        new_term.c_cc[VMIN] = 1;
 
195
        new_term.c_cc[VTIME] = 0;
 
196
        new_term.c_lflag &= ~ICANON;
 
197
        new_term.c_lflag &= ~(ECHO | ECHOCTL | ECHONL);
 
198
        tcsetattr(termfd, TCSANOW, &new_term);
 
199
    }
 
200
    else
 
201
    {
 
202
        tcsetattr(termfd, TCSANOW, &old_term);
 
203
        close(termfd);
 
204
    }
 
205
 
 
206
    return 0;
 
207
}
 
208
 
 
209
static short is_terminator(char c)
 
210
{
 
211
    short termind, msk, aux;
 
212
 
 
213
    termind = c / 8;
 
214
    aux = c - (termind * 8);
 
215
    msk = (1 << aux);
 
216
 
 
217
    if (terminators[termind] && msk)
 
218
    {
 
219
        return 1;
 
220
    }
 
221
    return 0;
 
222
}
 
223
 
 
224
/* Erase to end of line */
 
225
static void erase_eol(void)
 
226
{
 
227
    write(termfd, "\033[0K", 4);
 
228
}
 
229
 
 
230
/* Move to column "hpos", where hpos starts at 0 */
 
231
static void move_cursor_abs(int hpos)
 
232
{
 
233
    char buf[32];
 
234
 
 
235
    sprintf(buf, "\r\033[%dC", hpos);
 
236
    write(termfd, buf, strlen(buf));
 
237
}
 
238
 
 
239
 
 
240
void tty_send_unread()
 
241
{
 
242
    send_input_buffer(0);
 
243
}
 
244
 
 
245
/* Input from keyboard */
 
246
int tty_process_terminal(unsigned char *buf, int len)
 
247
{
 
248
    int i;
 
249
 
 
250
    for (i=0; i<len; i++)
 
251
    {
 
252
        if (buf[i] == exit_char)
 
253
        {
 
254
            finished = 1;
 
255
            return 0;
 
256
        }
 
257
 
 
258
        /* Swap LF for CR */
 
259
        //PJC: is this right??
 
260
        if (buf[i] == '\n')
 
261
            buf[i] = '\r';
 
262
 
 
263
        /* Is it ESCAPE ? */
 
264
        if (buf[i] == ESC && esc_len == 0)
 
265
        {
 
266
            esc_buf[esc_len++] = buf[i];
 
267
            continue;
 
268
        }
 
269
 
 
270
        /* Terminators */
 
271
        if (!esc_len && is_terminator(buf[i]))
 
272
        {
 
273
            if (echo_terminator)
 
274
            {
 
275
                write(termfd, &buf[i], 1);
 
276
            }
 
277
            input_buf[input_len++] = buf[i];
 
278
            send_input_buffer(1);
 
279
            reading = 0;
 
280
            return 0;
 
281
        }
 
282
 
 
283
        /* Check for OOB - these discard input */
 
284
        if (buf[i] == CTRL_C || buf[i] == CTRL_Y)
 
285
        {
 
286
            send_oob(buf[i], 1);
 
287
            continue;
 
288
        }
 
289
 
 
290
        /* Check for OOB  - these don't */
 
291
        if (buf[i] == CTRL_Z || buf[i] == CTRL_T)
 
292
        {
 
293
            send_oob(buf[i], 0);
 
294
            continue;
 
295
        }
 
296
 
 
297
        /* Still processing escape sequence */
 
298
        if (esc_len)
 
299
        {
 
300
            esc_buf[esc_len++] = buf[i];
 
301
            if (isalpha(buf[i]))
 
302
            {
 
303
                int esc_done = 0;
 
304
 
 
305
                /* Process escape sequences */
 
306
                if (strncmp(esc_buf, "\033[C", 3) == 0) /* Cursor RIGHT */
 
307
                {
 
308
                    if (input_pos < input_len)
 
309
                    {
 
310
                        input_pos++;
 
311
                        if (echo) write(termfd, esc_buf, esc_len);
 
312
                    }
 
313
                    esc_done = 1;
 
314
                }
 
315
                if (strncmp(esc_buf, "\033[D", 3) == 0) /* Cursor LEFT */
 
316
                {
 
317
                    if (input_pos > 0)
 
318
                    {
 
319
                        input_pos--;
 
320
                        if (echo) write(termfd, esc_buf, esc_len);
 
321
                    }
 
322
                    esc_done = 1;
 
323
                }
 
324
                /* If we didn't process it above, then just send it to
 
325
                   the host */
 
326
                if (!esc_done)
 
327
                {
 
328
                    send_input(esc_buf, esc_len, 2);
 
329
                }
 
330
                esc_len = 0;
 
331
            }
 
332
            continue;
 
333
        }
 
334
 
 
335
        /* Process non-terminator control chars */
 
336
        if (buf[i] < ' ' || buf[i] == DEL)
 
337
        {
 
338
            switch (buf[i])
 
339
            {
 
340
            case CTRL_B: // Up a line
 
341
                break;
 
342
            case CTRL_X: // delete input line
 
343
            case CTRL_U: // delete input line
 
344
                move_cursor_abs(prompt_len);
 
345
                if (echo) erase_eol();
 
346
                input_pos = input_len = 0;
 
347
                break;
 
348
            case CTRL_H: // back to start of line
 
349
                if (echo) move_cursor_abs(prompt_len);
 
350
                input_pos = 0;
 
351
                break;
 
352
            case CTRL_A: /* switch overstrike/insert mode */
 
353
                insert_mode = 1-insert_mode;
 
354
                break;
 
355
            case CTRL_M:
 
356
                input_buf[input_len++] = buf[i];
 
357
                send_input_buffer(1);
 
358
                input_len = input_pos = 0;
 
359
                reading = 0;
 
360
                break;
 
361
            case DEL:
 
362
                if (input_pos > 0)
 
363
                {
 
364
                    input_pos--;
 
365
                    input_len = input_pos;
 
366
                     if (echo) write(termfd, "\033[D \033[D", 7);
 
367
                }
 
368
                break;
 
369
            }
 
370
            continue;
 
371
        }
 
372
 
 
373
        /* Read not active, store in the read ahead buffer */
 
374
        if (!reading)
 
375
        {
 
376
            if (rahead_len < sizeof(rahead_buf))
 
377
                rahead_buf[rahead_len++] = buf[i];
 
378
            continue;
 
379
        }
 
380
 
 
381
        /* echo if req'd */
 
382
        if (echo)
 
383
            write(termfd, &buf[i], 1);
 
384
 
 
385
        /* Check for buffer overflow */
 
386
        input_buf[input_pos++] = buf[i];
 
387
        if (input_len < input_pos)
 
388
            input_len = input_pos;
 
389
 
 
390
        if (input_len >= max_read_len)
 
391
        {
 
392
            send_input_buffer(4);
 
393
        }
 
394
    }
 
395
    return 0;
 
396
}