forked from 7jXlqS-hmpBUGsK/iscabbs-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstate.c
221 lines (191 loc) · 3.46 KB
/
state.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
/*
* state.c - A severely hacked version of the BSD4.3/Net2 telnet state machine.
*/
#include "defs.h"
#include "ext.h"
int
telrcv(int *noflush)
{
int c;
for (;;) {
if (!INPUT_LEFT())
{
if (*noflush > 0)
{
fflush(stdout);
*noflush = 0;
}
else if (*noflush < 0)
{
int left;
#ifdef FIONREAD
if (ioctl(0, FIONREAD, &left) < 0 || left < 0)
return(errno = EPIPE, -1);
else if (!left)
return(errno = EWOULDBLOCK, -1);
#else
ioctl (0, TCFLSH, &left);
return (errno = EWOULDBLOCK, -1);
#endif
}
do
{
if (f_alarm)
alarmclock();
if (f_death)
my_exit(5);
if ((XPENDING) && *noflush >= 0)
checkx(1);
errno = 0;
}
while ((c = getchar()) < 0 && errno == EINTR);
if (c < 0)
return(-1);
}
else
c = getchar();
switch (state) {
case TS_CR:
state = TS_DATA;
/* Strip off \n or \0 after a \r */
if (!c || c == '\n')
break;
/* FALL THROUGH */
case TS_DATA:
if (c == IAC) {
state = TS_IAC;
break;
}
if (c == '\r' && !client)
state = TS_CR;
return(c & 0x7f);
case TS_IAC:
gotiac: switch (c) {
/*
* Are You There?
*/
case AYT:
my_printf("\n[Yo!]\n");
fflush(stdout);
break;
/*
* Abort Output
*/
case AO:
my_putchar(IAC);
my_putchar(DM);
break;
case DM:
break;
/*
* This a BBS client option, not a telnet option.
* If in the future it becomes necessary to make
* incompatible changes to the BBS end of things but
* still maintain compatibility with old clients, the
* method by which this can be done will be having the
* client send out a different value for START, the
* future version of the BBS can then check this and
* act differently for a new client and old client.
*/
case START3:
client = 1;
block = 0;
byte = 1;
numposts = 1;
break;
case START:
block = 0;
byte = 1;
break;
case CLIENT:
dead = 0;
break;
case POST_K:
state = TS_KILL;
continue;
/*
* Begin option subnegotiation...
*/
case SB:
state = TS_SB;
SB_CLEAR();
continue;
case WILL:
case WONT:
case DO:
case DONT:
state = TS_VOID;
continue;
case IAC:
return(c & 0x7f);
/* Additions for client controls */
case BLOCK:
block = 0;
break;
default:
break;
}
state = TS_DATA;
break;
case TS_SB:
if (c == IAC)
state = TS_SE;
else
SB_ACCUM(c);
break;
case TS_SE:
if (c != SE) {
if (c != IAC) {
SB_ACCUM(IAC);
SB_ACCUM(c);
subpointer -= 2;
SB_TERM();
if (SB_GET() == TELOPT_NAWS)
rows = subpointer[3];
if (rows < 5 || rows > 100)
rows = 24;
state = TS_IAC;
goto gotiac;
}
SB_ACCUM(c);
state = TS_SB;
} else {
SB_ACCUM(IAC);
SB_ACCUM(SE);
subpointer -= 2;
SB_TERM();
if (SB_GET() == TELOPT_NAWS)
rows = subpointer[3];
if (rows < 5 || rows > 100)
rows = 24;
state = TS_DATA;
}
break;
case TS_VOID:
state = TS_DATA;
break;
case TS_KILL:
if (numposts > 0 && c == (numposts & 0xff))
numposts = -numposts;
state = TS_DATA;
break;
default:
errlog("Illegal telnet state");
my_exit(5);
}
}
}
void
init_states(void)
{
state = TS_DATA;
if (!getenv("ROWS") || !(rows = atoi(getenv("ROWS"))))
rows = 24;
if (client)
{
my_putchar(IAC);
my_putchar(START);
block = 1;
byte = 1;
}
}