1 /*        $NetBSD: ventel.c,v 1.17 2020/07/22 01:24:40 msaitoh Exp $  */
2 
3 /*
4  * Copyright (c) 1983, 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. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)ventel.c    8.1 (Berkeley) 6/6/93";
36 #endif
37 __RCSID("$NetBSD: ventel.c,v 1.17 2020/07/22 01:24:40 msaitoh Exp $");
38 #endif /* not lint */
39 
40 /*
41  * Routines for calling up on a Ventel Modem
42  * The Ventel is expected to be strapped for local echo (just like uucp)
43  */
44 #include "tip.h"
45 
46 #define   MAXRETRY  5
47 
48 static    int timeout = 0;
49 static    jmp_buf timeoutbuf;
50 
51 static    void      echo(const char *);
52 static    int       gobble(char, char *);
53 static    void      sigALRM(int);
54 static    int       vensync(int);
55 
56 /*
57  * some sleep calls have been replaced by usleep(DELAYUS)
58  * because some ventel modems require two <cr>s in less than
59  * a second in order to 'wake up'
60  */
61 #define   DELAYUS             100000              /* delay in microseconds */
62 
63 int
64 /*ARGSUSED*/
ven_dialer(char * num,char * acu __unused)65 ven_dialer(char *num, char *acu __unused)
66 {
67           char *cp;
68           int connected = 0;
69           char *msg, line[80];
70           struct termios      cntrl;
71 
72           /*
73            * Get in synch with a couple of carriage returns
74            */
75           if (!vensync(FD)) {
76                     (void)printf("can't synchronize with ventel\n");
77                     return (0);
78           }
79           if (boolean(value(VERBOSE)))
80                     (void)printf("\ndialing...");
81           (void)fflush(stdout);
82           (void)tcgetattr(FD, &cntrl);
83           cntrl.c_cflag |= HUPCL;
84           (void)tcsetattr(FD, TCSANOW, &cntrl);
85           echo("#k$\r$\n$D$I$A$L$:$ ");
86           for (cp = num; *cp; cp++) {
87                     (void)usleep(DELAYUS);
88                     (void)write(FD, cp, 1);
89           }
90           (void)usleep(DELAYUS);
91           (void)write(FD, "\r", 1);
92           (void)gobble('\n', line);
93           if (gobble('\n', line))
94                     connected = gobble('!', line);
95           (void)tcflush(FD, TCIOFLUSH);
96           if (timeout)
97                     ven_disconnect();   /* insurance */
98           if (connected || timeout || !boolean(value(VERBOSE)))
99                     return (connected);
100           /* call failed, parse response for user */
101           cp = strchr(line, '\r');
102           if (cp)
103                     *cp = '\0';
104           for (cp = line; (cp = strchr(cp, ' ')) != NULL; cp++)
105                     if (cp[1] == ' ')
106                               break;
107           if (cp) {
108                     while (*cp == ' ')
109                               cp++;
110                     msg = cp;
111                     while (*cp) {
112                               if (isupper((unsigned char)*cp))
113                                         *cp = tolower((unsigned char)*cp);
114                               cp++;
115                     }
116                     (void)printf("%s...", msg);
117           }
118           return (connected);
119 }
120 
121 void
ven_disconnect(void)122 ven_disconnect(void)
123 {
124 
125           (void)close(FD);
126 }
127 
128 void
ven_abort(void)129 ven_abort(void)
130 {
131 
132           (void)write(FD, "\03", 1);
133           (void)close(FD);
134 }
135 
136 static void
echo(const char * s)137 echo(const char *s)
138 {
139           char c;
140 
141           while ((c = *s++) != 0) switch (c) {
142 
143           case '$':
144                     (void)read(FD, &c, 1);
145                     s++;
146                     break;
147 
148           case '#':
149                     c = *s++;
150                     (void)write(FD, &c, 1);
151                     break;
152 
153           default:
154                     (void)write(FD, &c, 1);
155                     (void)read(FD, &c, 1);
156           }
157 }
158 
159 static void
160 /*ARGSUSED*/
sigALRM(int dummy __unused)161 sigALRM(int dummy __unused)
162 {
163 
164           (void)printf("\07timeout waiting for reply\n");
165           timeout = 1;
166           longjmp(timeoutbuf, 1);
167 }
168 
169 static int
gobble(char match,char response[])170 gobble(char match, char response[])
171 {
172           char * volatile cp;
173           sig_t f;
174           char c;
175 
176           cp = response;
177           f = signal(SIGALRM, sigALRM);
178           timeout = 0;
179           do {
180                     if (setjmp(timeoutbuf)) {
181                               (void)signal(SIGALRM, f);
182                               *cp = '\0';
183                               return (0);
184                     }
185                     (void)alarm((unsigned)number(value(DIALTIMEOUT)));
186                     (void)read(FD, cp, 1);
187                     (void)alarm(0);
188                     c = (*cp++ &= 0177);
189 #ifdef notdef
190                     if (boolean(value(VERBOSE)))
191                               (void)putchar(c);
192 #endif
193           } while (c != '\n' && c != match);
194           (void)signal(SIGALRM, SIG_DFL);
195           *cp = '\0';
196           return (c == match);
197 }
198 
199 #define min(a,b)    ((a)>(b)?(b):(a))
200 /*
201  * This convoluted piece of code attempts to get
202  * the ventel in sync.  If you don't have FIONREAD
203  * there are gory ways to simulate this.
204  */
205 static int
vensync(int fd)206 vensync(int fd)
207 {
208           int already = 0, nread;
209           char buf[60];
210 
211           /*
212            * Toggle DTR to force anyone off that might have left
213            * the modem connected, and insure a consistent state
214            * to start from.
215            *
216            * If you don't have the ioctl calls to diddle directly
217            * with DTR, you can always try setting the baud rate to 0.
218            */
219           (void)ioctl(FD, TIOCCDTR, 0);
220           (void)sleep(1);
221           (void)ioctl(FD, TIOCSDTR, 0);
222           while (already < MAXRETRY) {
223                     /*
224                      * After resetting the modem, send it two \r's to
225                      * autobaud on. Make sure to delay between them
226                      * so the modem can frame the incoming characters.
227                      */
228                     (void)write(fd, "\r", 1);
229                     (void)usleep(DELAYUS);
230                     (void)write(fd, "\r", 1);
231                     (void)sleep(2);
232                     if (ioctl(fd, FIONREAD, &nread) < 0) {
233                               perror("tip: ioctl");
234                               continue;
235                     }
236                     while (nread > 0) {
237                               (void)read(fd, buf, min(nread, sizeof buf));
238                               if ((buf[min(nread, sizeof buf) - 1] & 0177) == '$')
239                                         return (1);
240                               nread -= min(nread, 60);
241                     }
242                     (void)sleep(1);
243                     already++;
244           }
245           return (0);
246 }
247