xref: /freebsd/usr.bin/tip/libacu/ventel.c (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
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
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
131 ven_disconnect(void)
132 {
133 	close(FD);
134 }
135 
136 void
137 ven_abort(void)
138 {
139 	write(FD, "\03", 1);
140 	close(FD);
141 }
142 
143 static void
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
168 sigALRM(int signo)
169 {
170 	printf("\07timeout waiting for reply\n");
171 	dialtimeout = 1;
172 	longjmp(timeoutbuf, 1);
173 }
174 
175 static int
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
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