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