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