1#include <ctype.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <sys/mman.h>
5#include <fcntl.h>
6#include <string.h>
7#include <termios.h>
8#include <unistd.h>
9
10struct {
11    char key;
12    char *chars;
13} map[] = {
14    { '1', "_ -1?!,.:;\"'<=>()_" },
15    { '2', "Cabc2ABC" },
16    { '3', "Fdef3DEF" },
17    { '4', "Ighi4GHI" },
18    { '5', "Ljkl5JKL" },
19    { '6', "Omno6MNO" },
20    { '7', "Spqrs7PQRS" },
21    { '8', "Vtuv8TUV" },
22    { '9', "Zwxyz9WXYZ" },
23    { '0', "*+&0@/#*" },
24};
25
26char next_char(char key, char current)
27{
28    int i;
29    char *next;
30    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
31        if(key == map[i].key) {
32            next = strchr(map[i].chars, current);
33            if(next && next[1])
34                return next[1];
35            return map[i].chars[1];
36        }
37    }
38    return key;
39}
40
41char prev_char(char key, char current)
42{
43    int i;
44    char *next;
45    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
46        if(key == map[i].key) {
47            next = strchr(map[i].chars+1, current);
48            if(next && next[-1])
49                return next[-1];
50            return map[i].chars[1];
51        }
52    }
53    return key;
54}
55
56int readtty_main(int argc, char *argv[])
57{
58    int c;
59    //int flags;
60    char buf[1];
61    int res;
62    struct termios ttyarg;
63    struct termios savedttyarg;
64    int nonblock = 0;
65    int timeout = 0;
66    int flush = 0;
67    int phone = 0;
68    char *accept = NULL;
69    char *rejectstring = NULL;
70    char last_char_in = 0;
71    char current_char = 0;
72    char *exit_string = NULL;
73    int exit_match = 0;
74
75    do {
76        c = getopt(argc, argv, "nt:fa:r:pe:");
77        if (c == EOF)
78            break;
79        switch (c) {
80        case 't':
81            timeout = atoi(optarg);
82            break;
83        case 'n':
84            nonblock = 1;
85            break;
86        case 'f':
87            flush = 1;
88            break;
89        case 'a':
90            accept = optarg;
91            break;
92        case 'r':
93            rejectstring = optarg;
94            break;
95        case 'p':
96            phone = 1;
97            break;
98        case 'e':
99            exit_string = optarg;
100            break;
101        case '?':
102            fprintf(stderr, "%s: invalid option -%c\n",
103                argv[0], optopt);
104            exit(1);
105        }
106    } while (1);
107
108    if(flush)
109        tcflush(STDIN_FILENO, TCIFLUSH);
110    ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ;       /* set changed tty arguments */
111    ttyarg = savedttyarg;
112    ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1;                /* minimum of 0 chars */
113    ttyarg.c_cc[VTIME] = timeout;              /* wait max 15/10 sec */
114    ttyarg.c_iflag = BRKINT | ICRNL;
115    ttyarg.c_lflag &= ~(ECHO | ICANON);
116    ioctl(STDIN_FILENO, TCSETS , &ttyarg);
117
118    while (1) {
119        res = read(STDIN_FILENO, buf, 1);
120        if(res <= 0) {
121            if(phone) {
122                if(current_char) {
123                    write(STDERR_FILENO, &current_char, 1);
124                    write(STDOUT_FILENO, &current_char, 1);
125                    if(exit_string && current_char == exit_string[exit_match]) {
126                        exit_match++;
127                        if(exit_string[exit_match] == '\0')
128                            break;
129                    }
130                    else
131                        exit_match = 0;
132                    current_char = 0;
133                }
134                continue;
135            }
136            break;
137        }
138        if(accept && strchr(accept, buf[0]) == NULL) {
139            if(rejectstring) {
140                write(STDOUT_FILENO, rejectstring, strlen(rejectstring));
141                break;
142            }
143            if(flush)
144                tcflush(STDIN_FILENO, TCIFLUSH);
145            continue;
146        }
147        if(phone) {
148            //if(!isprint(buf[0])) {
149            //  fprintf(stderr, "got unprintable character 0x%x\n", buf[0]);
150            //}
151            if(buf[0] == '\0') {
152                if(current_char) {
153                    current_char = prev_char(last_char_in, current_char);
154                    write(STDERR_FILENO, &current_char, 1);
155                    write(STDERR_FILENO, "\b", 1);
156                }
157                continue;
158            }
159            if(current_char && buf[0] != last_char_in) {
160                write(STDERR_FILENO, &current_char, 1);
161                write(STDOUT_FILENO, &current_char, 1);
162                if(exit_string && current_char == exit_string[exit_match]) {
163                    exit_match++;
164                    if(exit_string[exit_match] == '\0')
165                        break;
166                }
167                else
168                    exit_match = 0;
169                current_char = 0;
170            }
171            last_char_in = buf[0];
172            current_char = next_char(last_char_in, current_char);
173            write(STDERR_FILENO, &current_char, 1);
174            write(STDERR_FILENO, "\b", 1);
175            continue;
176        }
177        write(STDOUT_FILENO, buf, 1);
178        break;
179    }
180    ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ;       /* set changed tty arguments */
181
182    return 0;
183}
184