1 /* $OpenBSD: ventel.c,v 1.12 2006/03/17 19:17:13 moritz Exp $ */
2 /* $NetBSD: ventel.c,v 1.6 1997/02/11 09:24:21 mrg Exp $ */
3
4 /*-
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Copyright (c) 1983, 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 /*
36 * Routines for calling up on a Ventel Modem
37 * The Ventel is expected to be strapped for local echo (just like uucp)
38 */
39 #include "tip.h"
40 #include <termios.h>
41 #include <sys/ioctl.h>
42
43 #define MAXRETRY 5
44
45 static int dialtimeout = 0;
46 static jmp_buf timeoutbuf;
47
48 static void echo(char *);
49 static void sigALRM(int);
50 static int gobble(char, char *);
51 static int vensync(int);
52
53 /*
54 * some sleep calls have been replaced by this macro
55 * because some ventel modems require two <cr>s in less than
56 * a second in order to 'wake up'... yes, it is dirty...
57 */
58 #define delay(num,denom) busyloop(CPUSPEED*num/denom)
59 #define CPUSPEED 1000000 /* VAX 780 is 1MIPS */
60 #define DELAY(n) do { long N = (n); while (--N > 0); } while (0)
61 #define busyloop(n) do { DELAY(n); } while (0)
62
63 int
ven_dialer(char * num,char * acu)64 ven_dialer(char *num, char *acu)
65 {
66 char *cp;
67 int connected = 0;
68 char *msg, line[80];
69 struct termios cntrl;
70
71 /*
72 * Get in synch with a couple of carriage returns
73 */
74 if (!vensync(FD)) {
75 printf("can't synchronize with ventel\n");
76 #ifdef ACULOG
77 logent(value(HOST), num, "ventel", "can't synch up");
78 #endif
79 return (0);
80 }
81 if (boolean(value(VERBOSE)))
82 printf("\ndialing...");
83 fflush(stdout);
84 tcgetattr(FD, &cntrl);
85 cntrl.c_cflag |= HUPCL;
86 tcsetattr(FD, TCSANOW, &cntrl);
87 echo("#k$\r$\n$D$I$A$L$:$ ");
88 for (cp = num; *cp; cp++) {
89 delay(1, 10);
90 write(FD, cp, 1);
91 }
92 delay(1, 10);
93 write(FD, "\r", 1);
94 gobble('\n', line);
95 if (gobble('\n', line))
96 connected = gobble('!', line);
97 tcflush(FD, TCIOFLUSH);
98 #ifdef ACULOG
99 if (dialtimeout) {
100 (void)snprintf(line, sizeof line, "%ld second dial timeout",
101 number(value(DIALTIMEOUT)));
102 logent(value(HOST), num, "ventel", line);
103 }
104 #endif
105 if (dialtimeout)
106 ven_disconnect(); /* insurance */
107 if (connected || dialtimeout || !boolean(value(VERBOSE)))
108 return (connected);
109 /* call failed, parse response for user */
110 cp = strchr(line, '\r');
111 if (cp)
112 *cp = '\0';
113 for (cp = line; (cp = strchr(cp, ' ')) != NULL; cp++)
114 if (cp[1] == ' ')
115 break;
116 if (cp) {
117 while (*cp == ' ')
118 cp++;
119 msg = cp;
120 while (*cp) {
121 if (isupper(*cp))
122 *cp = tolower(*cp);
123 cp++;
124 }
125 printf("%s...", msg);
126 }
127 return (connected);
128 }
129
130 void
ven_disconnect(void)131 ven_disconnect(void)
132 {
133 close(FD);
134 }
135
136 void
ven_abort(void)137 ven_abort(void)
138 {
139 write(FD, "\03", 1);
140 close(FD);
141 }
142
143 static void
echo(char * s)144 echo(char *s)
145 {
146 char c;
147
148 while ((c = *s++) != '\0')
149 switch (c) {
150 case '$':
151 read(FD, &c, 1);
152 s++;
153 break;
154
155 case '#':
156 c = *s++;
157 write(FD, &c, 1);
158 break;
159
160 default:
161 write(FD, &c, 1);
162 read(FD, &c, 1);
163 }
164 }
165
166 /*ARGSUSED*/
167 static void
sigALRM(int signo)168 sigALRM(int signo)
169 {
170 printf("\07timeout waiting for reply\n");
171 dialtimeout = 1;
172 longjmp(timeoutbuf, 1);
173 }
174
175 static int
gobble(char match,char response[])176 gobble(char match, char response[])
177 {
178 char *cp = response;
179 sig_t f;
180 char c;
181
182 f = signal(SIGALRM, sigALRM);
183 dialtimeout = 0;
184 do {
185 if (setjmp(timeoutbuf)) {
186 signal(SIGALRM, f);
187 *cp = '\0';
188 return (0);
189 }
190 alarm(number(value(DIALTIMEOUT)));
191 read(FD, cp, 1);
192 alarm(0);
193 c = (*cp++ &= 0177);
194 #ifdef notdef
195 if (boolean(value(VERBOSE)))
196 putchar(c);
197 #endif
198 } while (c != '\n' && c != match);
199 signal(SIGALRM, SIG_DFL);
200 *cp = '\0';
201 return (c == match);
202 }
203
204 #define min(a,b) ((a)>(b)?(b):(a))
205 /*
206 * This convoluted piece of code attempts to get
207 * the ventel in sync. If you don't have FIONREAD
208 * there are gory ways to simulate this.
209 */
210 static int
vensync(int fd)211 vensync(int fd)
212 {
213 int already = 0, nread;
214 char buf[60];
215
216 /*
217 * Toggle DTR to force anyone off that might have left
218 * the modem connected, and insure a consistent state
219 * to start from.
220 *
221 * If you don't have the ioctl calls to diddle directly
222 * with DTR, you can always try setting the baud rate to 0.
223 */
224 ioctl(FD, TIOCCDTR, 0);
225 sleep(1);
226 ioctl(FD, TIOCSDTR, 0);
227 while (already < MAXRETRY) {
228 /*
229 * After reseting the modem, send it two \r's to
230 * autobaud on. Make sure to delay between them
231 * so the modem can frame the incoming characters.
232 */
233 write(fd, "\r", 1);
234 delay(1,10);
235 write(fd, "\r", 1);
236 sleep(2);
237 if (ioctl(fd, FIONREAD, (caddr_t)&nread) < 0) {
238 perror("tip: ioctl");
239 continue;
240 }
241 while (nread > 0) {
242 read(fd, buf, min(nread, 60));
243 if ((buf[nread - 1] & 0177) == '$')
244 return (1);
245 nread -= min(nread, 60);
246 }
247 sleep(1);
248 already++;
249 }
250 return (0);
251 }
252