courier.c revision 1.10 1 /* $NetBSD: courier.c,v 1.10 1998/07/12 09:14:20 mrg 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 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93";
40 #endif
41 __RCSID("$NetBSD: courier.c,v 1.10 1998/07/12 09:14:20 mrg Exp $");
42 #endif /* not lint */
43
44 /*
45 * Routines for calling up on a Courier modem.
46 * Derived from Hayes driver.
47 */
48 #include "tip.h"
49
50 #define MAXRETRY 5
51
52 static int timeout = 0;
53 static int connected = 0;
54 static jmp_buf timeoutbuf;
55
56 static int cour_connect __P((void));
57 static void cour_nap __P((void));
58 static void cour_napx __P((int));
59 static int cour_swallow __P((char *));
60 static int coursync __P((void));
61 #ifdef DEBUG
62 static void cour_verbose_read __P((void));
63 #endif
64 static void cour_write __P((int, char *, int));
65 static void sigALRM __P((int));
66
67 int
68 cour_dialer(num, acu)
69 char *num;
70 char *acu;
71 {
72 char *cp;
73 #ifdef ACULOG
74 char line[80];
75 #endif
76 struct termios cntrl;
77
78 if (boolean(value(VERBOSE)))
79 printf("Using \"%s\"\n", acu);
80
81 tcgetattr(FD, &cntrl);
82 cntrl.c_cflag |= HUPCL;
83 tcsetattr(FD, TCSAFLUSH, &cntrl);
84 /*
85 * Get in synch.
86 */
87 if (!coursync()) {
88 badsynch:
89 printf("can't synchronize with courier\n");
90 #ifdef ACULOG
91 logent(value(HOST), num, "courier", "can't synch up");
92 #endif
93 return (0);
94 }
95 cour_write(FD, "AT E0\r", 6); /* turn off echoing */
96 sleep(1);
97 #ifdef DEBUG
98 if (boolean(value(VERBOSE)))
99 cour_verbose_read();
100 #endif
101 tcflush(FD, TCIOFLUSH);
102 cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
103 if (!cour_swallow("\r\nOK\r\n"))
104 goto badsynch;
105 fflush(stdout);
106 cour_write(FD, "AT D", 4);
107 for (cp = num; *cp; cp++)
108 if (*cp == '=')
109 *cp = ',';
110 cour_write(FD, num, strlen(num));
111 cour_write(FD, "\r", 1);
112 connected = cour_connect();
113 #ifdef ACULOG
114 if (timeout) {
115 (void)snprintf(line, sizeof line, "%d second dial timeout",
116 (int)number(value(DIALTIMEOUT)));
117 logent(value(HOST), num, "cour", line);
118 }
119 #endif
120 if (timeout)
121 cour_disconnect();
122 return (connected);
123 }
124
125 void
126 cour_disconnect()
127 {
128
129 /* first hang up the modem*/
130 ioctl(FD, TIOCCDTR, 0);
131 sleep(1);
132 ioctl(FD, TIOCSDTR, 0);
133 coursync(); /* reset */
134 close(FD);
135 }
136
137 void
138 cour_abort()
139 {
140
141 cour_write(FD, "\r", 1); /* send anything to abort the call */
142 cour_disconnect();
143 }
144
145 static void
146 sigALRM(dummy)
147 int dummy;
148 {
149
150 printf("\07timeout waiting for reply\n");
151 timeout = 1;
152 longjmp(timeoutbuf, 1);
153 }
154
155 static int
156 cour_swallow(match)
157 char *match;
158 {
159 sig_t f;
160 char c;
161
162 #if __GNUC__ /* XXX pacify gcc */
163 (void)&match;
164 #endif
165
166 f = signal(SIGALRM, sigALRM);
167 timeout = 0;
168 do {
169 if (*match =='\0') {
170 signal(SIGALRM, f);
171 return (1);
172 }
173 if (setjmp(timeoutbuf)) {
174 signal(SIGALRM, f);
175 return (0);
176 }
177 alarm(number(value(DIALTIMEOUT)));
178 read(FD, &c, 1);
179 alarm(0);
180 c &= 0177;
181 #ifdef DEBUG
182 if (boolean(value(VERBOSE)))
183 putchar(c);
184 #endif
185 } while (c == *match++);
186 #ifdef DEBUG
187 if (boolean(value(VERBOSE)))
188 fflush(stdout);
189 #endif
190 signal(SIGALRM, SIG_DFL);
191 return (0);
192 }
193
194 struct baud_msg {
195 char *msg;
196 int baud;
197 } baud_msg[] = {
198 { "", B300 },
199 { " 1200", B1200 },
200 { " 2400", B2400 },
201 { " 9600", B9600 },
202 { " 9600/ARQ", B9600 },
203 { 0, 0 }
204 };
205
206 static int
207 cour_connect()
208 {
209 char c;
210 int nc, nl, n;
211 char dialer_buf[64];
212 struct baud_msg *bm;
213 sig_t f;
214
215 #if __GNUC__ /* XXX pacify gcc */
216 (void)&nc;
217 (void)&nl;
218 #endif
219
220 if (cour_swallow("\r\n") == 0)
221 return (0);
222 f = signal(SIGALRM, sigALRM);
223 again:
224 memset(dialer_buf, 0, sizeof(dialer_buf));
225 timeout = 0;
226 for (nc = 0, nl = sizeof(dialer_buf) - 1 ; nl > 0 ; nc++, nl--) {
227 if (setjmp(timeoutbuf))
228 break;
229 alarm(number(value(DIALTIMEOUT)));
230 n = read(FD, &c, 1);
231 alarm(0);
232 if (n <= 0)
233 break;
234 c &= 0x7f;
235 if (c == '\r') {
236 if (cour_swallow("\n") == 0)
237 break;
238 if (!dialer_buf[0])
239 goto again;
240 if (strcmp(dialer_buf, "RINGING") == 0 &&
241 boolean(value(VERBOSE))) {
242 #ifdef DEBUG
243 printf("%s\r\n", dialer_buf);
244 #endif
245 goto again;
246 }
247 if (strncmp(dialer_buf, "CONNECT",
248 sizeof("CONNECT")-1) != 0)
249 break;
250 for (bm = baud_msg ; bm->msg ; bm++)
251 if (strcmp(bm->msg,
252 dialer_buf+sizeof("CONNECT")-1) == 0) {
253 struct termios cntrl;
254
255 tcgetattr(FD, &cntrl);
256 cfsetospeed(&cntrl, bm->baud);
257 cfsetispeed(&cntrl, bm->baud);
258 tcsetattr(FD, TCSAFLUSH, &cntrl);
259 signal(SIGALRM, f);
260 #ifdef DEBUG
261 if (boolean(value(VERBOSE)))
262 printf("%s\r\n", dialer_buf);
263 #endif
264 return (1);
265 }
266 break;
267 }
268 dialer_buf[nc] = c;
269 #ifdef notdef
270 if (boolean(value(VERBOSE)))
271 putchar(c);
272 #endif
273 }
274 printf("%s\r\n", dialer_buf);
275 signal(SIGALRM, f);
276 return (0);
277 }
278
279 /*
280 * This convoluted piece of code attempts to get
281 * the courier in sync.
282 */
283 static int
284 coursync()
285 {
286 int already = 0;
287 int len;
288 char buf[40];
289
290 while (already++ < MAXRETRY) {
291 tcflush(FD, TCIOFLUSH);
292 cour_write(FD, "\rAT Z\r", 6); /* reset modem */
293 memset(buf, 0, sizeof(buf));
294 sleep(1);
295 ioctl(FD, FIONREAD, &len);
296 if (len) {
297 len = read(FD, buf, sizeof(buf));
298 #ifdef DEBUG
299 buf[len] = '\0';
300 printf("coursync: (\"%s\")\n\r", buf);
301 #endif
302 if (strchr(buf, '0') ||
303 (strchr(buf, 'O') && strchr(buf, 'K')))
304 return(1);
305 }
306 /*
307 * If not strapped for DTR control,
308 * try to get command mode.
309 */
310 sleep(1);
311 cour_write(FD, "+++", 3);
312 sleep(1);
313 /*
314 * Toggle DTR to force anyone off that might have left
315 * the modem connected.
316 */
317 ioctl(FD, TIOCCDTR, 0);
318 sleep(1);
319 ioctl(FD, TIOCSDTR, 0);
320 }
321 cour_write(FD, "\rAT Z\r", 6);
322 return (0);
323 }
324
325 static void
326 cour_write(fd, cp, n)
327 int fd;
328 char *cp;
329 int n;
330 {
331
332 #ifdef notdef
333 if (boolean(value(VERBOSE)))
334 write(1, cp, n);
335 #endif
336 tcdrain(fd);
337 cour_nap();
338 for ( ; n-- ; cp++) {
339 write(fd, cp, 1);
340 tcdrain(fd);
341 cour_nap();
342 }
343 }
344
345 #ifdef DEBUG
346 static void
347 cour_verbose_read()
348 {
349 int n = 0;
350 char buf[BUFSIZ];
351
352 if (ioctl(FD, FIONREAD, &n) < 0)
353 return;
354 if (n <= 0)
355 return;
356 if (read(FD, buf, n) != n)
357 return;
358 write(1, buf, n);
359 }
360 #endif
361
362 /*
363 * Code stolen from /usr/src/lib/libc/gen/sleep.c
364 */
365 #define mask(s) (1<<((s)-1))
366 #define setvec(vec, a) \
367 vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
368
369 static int napms = 50; /* Give the courier 50 milliseconds between characters */
370
371 static int ringring;
372
373 void
374 cour_nap()
375 {
376
377 int omask;
378 struct itimerval itv, oitv;
379 struct itimerval *itp = &itv;
380 struct sigvec vec, ovec;
381
382 timerclear(&itp->it_interval);
383 timerclear(&itp->it_value);
384 if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
385 return;
386 setvec(ovec, SIG_DFL);
387 omask = sigblock(mask(SIGALRM));
388 itp->it_value.tv_sec = napms/1000;
389 itp->it_value.tv_usec = ((napms%1000)*1000);
390 setvec(vec, cour_napx);
391 ringring = 0;
392 (void) sigvec(SIGALRM, &vec, &ovec);
393 (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
394 while (!ringring)
395 sigpause(omask &~ mask(SIGALRM));
396 (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
397 (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
398 (void) sigsetmask(omask);
399 }
400
401 static void
402 cour_napx(dummy)
403 int dummy;
404 {
405
406 ringring = 1;
407 }
408