Commit | Line | Data |
---|---|---|
1485b502 | 1 | /* |
be11e13c KB |
2 | * Copyright (c) 1986 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
1485b502 DS |
16 | */ |
17 | ||
18 | #ifndef lint | |
be11e13c KB |
19 | static char sccsid[] = "@(#)courier.c 5.3 (Berkeley) %G%"; |
20 | #endif /* not lint */ | |
1485b502 DS |
21 | |
22 | #define write cour_write | |
23 | /* | |
fb6da896 MK |
24 | * Routines for calling up on a Courier modem. |
25 | * Derived from Hayes driver. | |
1485b502 DS |
26 | */ |
27 | #include "tip.h" | |
28 | #include <stdio.h> | |
29 | ||
30 | #define MAXRETRY 5 | |
31 | ||
32 | static int sigALRM(); | |
33 | static int timeout = 0; | |
fb6da896 | 34 | static int connected = 0; |
1485b502 DS |
35 | static jmp_buf timeoutbuf, intbuf; |
36 | static int (*osigint)(); | |
37 | ||
38 | cour_dialer(num, acu) | |
39 | register char *num; | |
40 | char *acu; | |
41 | { | |
42 | register char *cp; | |
1485b502 DS |
43 | #ifdef ACULOG |
44 | char line[80]; | |
45 | #endif | |
46 | if (boolean(value(VERBOSE))) | |
47 | printf("Using \"%s\"\n", acu); | |
48 | ||
49 | ioctl(FD, TIOCHPCL, 0); | |
50 | /* | |
51 | * Get in synch. | |
52 | */ | |
53 | if (!coursync()) { | |
fb6da896 | 54 | badsynch: |
1485b502 DS |
55 | printf("can't synchronize with courier\n"); |
56 | #ifdef ACULOG | |
57 | logent(value(HOST), num, "courier", "can't synch up"); | |
58 | #endif | |
59 | return (0); | |
60 | } | |
fb6da896 MK |
61 | write(FD, "AT E0\r", 6); /* turn off echoing */ |
62 | sleep(1); | |
63 | #ifdef DEBUG | |
64 | if (boolean(value(VERBOSE))) | |
65 | verbose_read(); | |
66 | #endif | |
67 | ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ | |
68 | write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); | |
69 | if (!cour_swallow("\r\nOK\r\n")) | |
70 | goto badsynch; | |
1485b502 DS |
71 | fflush(stdout); |
72 | write(FD, "AT D", 4); | |
73 | for (cp = num; *cp; cp++) | |
74 | if (*cp == '=') | |
75 | *cp = ','; | |
76 | write(FD, num, strlen(num)); | |
77 | write(FD, "\r", 1); | |
78 | connected = cour_connect(); | |
79 | #ifdef ACULOG | |
80 | if (timeout) { | |
81 | sprintf(line, "%d second dial timeout", | |
82 | number(value(DIALTIMEOUT))); | |
83 | logent(value(HOST), num, "cour", line); | |
84 | } | |
85 | #endif | |
86 | if (timeout) | |
87 | cour_disconnect(); | |
88 | return (connected); | |
89 | } | |
90 | ||
91 | cour_disconnect() | |
fb6da896 MK |
92 | { |
93 | /* first hang up the modem*/ | |
94 | ioctl(FD, TIOCCDTR, 0); | |
95 | sleep(1); | |
96 | ioctl(FD, TIOCSDTR, 0); | |
97 | coursync(); /* reset */ | |
1485b502 DS |
98 | close(FD); |
99 | } | |
100 | ||
101 | cour_abort() | |
fb6da896 MK |
102 | { |
103 | write(FD, "\r", 1); /* send anything to abort the call */ | |
104 | cour_disconnect(); | |
1485b502 DS |
105 | } |
106 | ||
107 | static int | |
108 | sigALRM() | |
109 | { | |
110 | printf("\07timeout waiting for reply\n"); | |
111 | timeout = 1; | |
112 | longjmp(timeoutbuf, 1); | |
113 | } | |
114 | ||
115 | static int | |
116 | cour_swallow(match) | |
117 | register char *match; | |
118 | { | |
119 | char c; | |
120 | int (*f)(); | |
121 | ||
122 | f = signal(SIGALRM, sigALRM); | |
123 | timeout = 0; | |
124 | do { | |
125 | if (*match =='\0') { | |
126 | signal(SIGALRM, f); | |
fb6da896 | 127 | return (1); |
1485b502 DS |
128 | } |
129 | if (setjmp(timeoutbuf)) { | |
130 | signal(SIGALRM, f); | |
131 | return (0); | |
132 | } | |
133 | alarm(number(value(DIALTIMEOUT))); | |
134 | read(FD, &c, 1); | |
135 | alarm(0); | |
136 | c &= 0177; | |
fb6da896 | 137 | #ifdef DEBUG |
1485b502 DS |
138 | if (boolean(value(VERBOSE))) |
139 | putchar(c); | |
fb6da896 | 140 | #endif |
1485b502 | 141 | } while (c == *match++); |
fb6da896 | 142 | #ifdef DEBUG |
1485b502 DS |
143 | if (boolean(value(VERBOSE))) |
144 | fflush(stdout); | |
fb6da896 | 145 | #endif |
1485b502 DS |
146 | signal(SIGALRM, SIG_DFL); |
147 | return (0); | |
148 | } | |
149 | ||
150 | struct baud_msg { | |
151 | char *msg; | |
152 | int baud; | |
153 | } baud_msg[] = { | |
154 | "", B300, | |
155 | " 1200", B1200, | |
156 | " 2400", B2400, | |
157 | 0, 0, | |
158 | }; | |
159 | ||
160 | static int | |
161 | cour_connect() | |
162 | { | |
163 | char c; | |
164 | int nc, nl, n; | |
165 | struct sgttyb sb; | |
166 | char dialer_buf[64]; | |
167 | struct baud_msg *bm; | |
168 | int (*f)(); | |
169 | ||
170 | if (cour_swallow("\r\n") == 0) | |
171 | return (0); | |
172 | f = signal(SIGALRM, sigALRM); | |
173 | again: | |
174 | nc = 0; nl = sizeof(dialer_buf)-1; | |
175 | bzero(dialer_buf, sizeof(dialer_buf)); | |
176 | timeout = 0; | |
177 | for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { | |
178 | if (setjmp(timeoutbuf)) | |
179 | break; | |
180 | alarm(number(value(DIALTIMEOUT))); | |
181 | n = read(FD, &c, 1); | |
182 | alarm(0); | |
183 | if (n <= 0) | |
184 | break; | |
185 | c &= 0x7f; | |
186 | if (c == '\r') { | |
187 | if (cour_swallow("\n") == 0) | |
188 | break; | |
189 | if (!dialer_buf[0]) | |
190 | goto again; | |
fb6da896 MK |
191 | if (strcmp(dialer_buf, "RINGING") == 0 && |
192 | boolean(value(VERBOSE))) { | |
193 | #ifdef DEBUG | |
1485b502 | 194 | printf("%s\r\n", dialer_buf); |
fb6da896 | 195 | #endif |
1485b502 DS |
196 | goto again; |
197 | } | |
198 | if (strncmp(dialer_buf, "CONNECT", | |
199 | sizeof("CONNECT")-1) != 0) | |
200 | break; | |
201 | for (bm = baud_msg ; bm ; bm++) | |
202 | if (strcmp(bm->msg, | |
203 | dialer_buf+sizeof("CONNECT")-1) == 0) { | |
204 | if (ioctl(FD, TIOCGETP, &sb) < 0) { | |
205 | perror("TIOCGETP"); | |
206 | goto error; | |
207 | } | |
208 | sb.sg_ispeed = sb.sg_ospeed = bm->baud; | |
209 | if (ioctl(FD, TIOCSETP, &sb) < 0) { | |
210 | perror("TIOCSETP"); | |
211 | goto error; | |
212 | } | |
213 | signal(SIGALRM, f); | |
fb6da896 | 214 | #ifdef DEBUG |
1485b502 DS |
215 | if (boolean(value(VERBOSE))) |
216 | printf("%s\r\n", dialer_buf); | |
fb6da896 | 217 | #endif |
1485b502 DS |
218 | return (1); |
219 | } | |
220 | break; | |
221 | } | |
222 | dialer_buf[nc] = c; | |
223 | #ifdef notdef | |
224 | if (boolean(value(VERBOSE))) | |
225 | putchar(c); | |
226 | #endif | |
227 | } | |
228 | error1: | |
229 | printf("%s\r\n", dialer_buf); | |
230 | error: | |
231 | signal(SIGALRM, f); | |
232 | return (0); | |
233 | } | |
234 | ||
235 | /* | |
236 | * This convoluted piece of code attempts to get | |
fb6da896 | 237 | * the courier in sync. |
1485b502 DS |
238 | */ |
239 | static int | |
240 | coursync() | |
241 | { | |
242 | int already = 0; | |
fb6da896 MK |
243 | int len; |
244 | char buf[40]; | |
1485b502 | 245 | |
1485b502 DS |
246 | while (already++ < MAXRETRY) { |
247 | ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ | |
248 | write(FD, "\rAT Z\r", 6); /* reset modem */ | |
fb6da896 | 249 | bzero(buf, sizeof(buf)); |
1485b502 | 250 | sleep(1); |
fb6da896 MK |
251 | ioctl(FD, FIONREAD, &len); |
252 | if (len) { | |
253 | len = read(FD, buf, sizeof(buf)); | |
254 | #ifdef DEBUG | |
255 | buf[len] = '\0'; | |
256 | printf("coursync: (\"%s\")\n\r", buf); | |
257 | #endif | |
258 | if (index(buf, '0') || | |
259 | (index(buf, 'O') && index(buf, 'K'))) | |
260 | return(1); | |
1485b502 | 261 | } |
fb6da896 MK |
262 | /* |
263 | * If not strapped for DTR control, | |
264 | * try to get command mode. | |
265 | */ | |
266 | sleep(1); | |
1485b502 | 267 | write(FD, "+++", 3); |
fb6da896 MK |
268 | sleep(1); |
269 | /* | |
270 | * Toggle DTR to force anyone off that might have left | |
271 | * the modem connected. | |
272 | */ | |
273 | ioctl(FD, TIOCCDTR, 0); | |
274 | sleep(1); | |
275 | ioctl(FD, TIOCSDTR, 0); | |
1485b502 DS |
276 | } |
277 | write(FD, "\rAT Z\r", 6); | |
fb6da896 | 278 | return (0); |
1485b502 DS |
279 | } |
280 | ||
281 | #undef write | |
282 | ||
283 | cour_write(fd, cp, n) | |
284 | int fd; | |
285 | char *cp; | |
286 | int n; | |
287 | { | |
288 | struct sgttyb sb; | |
fb6da896 | 289 | #ifdef notdef |
1485b502 DS |
290 | if (boolean(value(VERBOSE))) |
291 | write(1, cp, n); | |
fb6da896 | 292 | #endif |
1485b502 DS |
293 | ioctl(fd, TIOCGETP, &sb); |
294 | ioctl(fd, TIOCSETP, &sb); | |
295 | cour_nap(); | |
296 | for ( ; n-- ; cp++) { | |
297 | write(fd, cp, 1); | |
298 | ioctl(fd, TIOCGETP, &sb); | |
299 | ioctl(fd, TIOCSETP, &sb); | |
300 | cour_nap(); | |
301 | } | |
302 | } | |
303 | ||
fb6da896 | 304 | #ifdef DEBUG |
1485b502 DS |
305 | verbose_read() |
306 | { | |
307 | int n = 0; | |
308 | char buf[BUFSIZ]; | |
fb6da896 | 309 | |
1485b502 DS |
310 | if (ioctl(FD, FIONREAD, &n) < 0) |
311 | return; | |
312 | if (n <= 0) | |
313 | return; | |
314 | if (read(FD, buf, n) != n) | |
315 | return; | |
316 | write(1, buf, n); | |
317 | } | |
fb6da896 | 318 | #endif |
1485b502 DS |
319 | |
320 | /* | |
321 | * Code stolen from /usr/src/lib/libc/gen/sleep.c | |
322 | */ | |
323 | #include <sys/time.h> | |
324 | ||
325 | #define mask(s) (1<<((s)-1)) | |
326 | #define setvec(vec, a) \ | |
327 | vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 | |
328 | ||
329 | static napms = 50; /* Give the courier 50 milliseconds between characters */ | |
330 | ||
331 | static int ringring; | |
332 | ||
333 | cour_nap() | |
334 | { | |
335 | ||
336 | static int cour_napx(); | |
337 | int omask; | |
338 | struct itimerval itv, oitv; | |
339 | register struct itimerval *itp = &itv; | |
340 | struct sigvec vec, ovec; | |
341 | ||
342 | timerclear(&itp->it_interval); | |
343 | timerclear(&itp->it_value); | |
344 | if (setitimer(ITIMER_REAL, itp, &oitv) < 0) | |
345 | return; | |
346 | setvec(ovec, SIG_DFL); | |
347 | omask = sigblock(mask(SIGALRM)); | |
348 | itp->it_value.tv_sec = napms/1000; | |
349 | itp->it_value.tv_usec = ((napms%1000)*1000); | |
350 | setvec(vec, cour_napx); | |
351 | ringring = 0; | |
352 | (void) sigvec(SIGALRM, &vec, &ovec); | |
353 | (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); | |
354 | while (!ringring) | |
355 | sigpause(omask &~ mask(SIGALRM)); | |
356 | (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); | |
357 | (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); | |
358 | (void) sigsetmask(omask); | |
359 | } | |
360 | ||
361 | static | |
362 | cour_napx() | |
363 | { | |
364 | ringring = 1; | |
365 | } |