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