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