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