1161754Sru/*	$OpenBSD: ventel.c,v 1.12 2006/03/17 19:17:13 moritz Exp $	*/
288276Smarkm/*	$NetBSD: ventel.c,v 1.6 1997/02/11 09:24:21 mrg Exp $	*/
388276Smarkm
4331722Seadler/*
57527Sjkh * Copyright (c) 1983, 1993
67527Sjkh *	The Regents of the University of California.  All rights reserved.
77527Sjkh *
87527Sjkh * Redistribution and use in source and binary forms, with or without
97527Sjkh * modification, are permitted provided that the following conditions
107527Sjkh * are met:
117527Sjkh * 1. Redistributions of source code must retain the above copyright
127527Sjkh *    notice, this list of conditions and the following disclaimer.
137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright
147527Sjkh *    notice, this list of conditions and the following disclaimer in the
157527Sjkh *    documentation and/or other materials provided with the distribution.
16161754Sru * 3. Neither the name of the University nor the names of its contributors
177527Sjkh *    may be used to endorse or promote products derived from this software
187527Sjkh *    without specific prior written permission.
197527Sjkh *
207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237527Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307527Sjkh * SUCH DAMAGE.
317527Sjkh */
327527Sjkh
3388276Smarkm#include <sys/cdefs.h>
3488276Smarkm__FBSDID("$FreeBSD$");
3588276Smarkm
367527Sjkh#ifndef lint
3728365Scharnier#if 0
387527Sjkhstatic char sccsid[] = "@(#)ventel.c	8.1 (Berkeley) 6/6/93";
39161754Srustatic const char rcsid[] = "$OpenBSD: ventel.c,v 1.12 2006/03/17 19:17:13 moritz Exp $";
4028365Scharnier#endif
417527Sjkh#endif /* not lint */
427527Sjkh
437527Sjkh/*
447527Sjkh * Routines for calling up on a Ventel Modem
457527Sjkh * The Ventel is expected to be strapped for local echo (just like uucp)
467527Sjkh */
477527Sjkh#include "tip.h"
4888276Smarkm#include <termios.h>
4988276Smarkm#include <sys/ioctl.h>
507527Sjkh
517527Sjkh#define	MAXRETRY	5
527527Sjkh
53161754Srustatic	int dialtimeout = 0;
547527Sjkhstatic	jmp_buf timeoutbuf;
557527Sjkh
56161754Srustatic void	echo(char *);
57161754Srustatic void	sigALRM(int);
58161754Srustatic int	gobble(char, char *);
59161754Srustatic int	vensync(int);
6088276Smarkm
617527Sjkh/*
627527Sjkh * some sleep calls have been replaced by this macro
637527Sjkh * because some ventel modems require two <cr>s in less than
647527Sjkh * a second in order to 'wake up'... yes, it is dirty...
657527Sjkh */
667527Sjkh#define delay(num,denom) busyloop(CPUSPEED*num/denom)
677527Sjkh#define CPUSPEED 1000000	/* VAX 780 is 1MIPS */
6888276Smarkm#define DELAY(n) do { long N = (n); while (--N > 0); } while (0)
6988276Smarkm#define busyloop(n) do { DELAY(n); } while (0)
707527Sjkh
7188276Smarkmint
72161754Sruven_dialer(char *num, char *acu)
737527Sjkh{
7488276Smarkm	char *cp;
7588276Smarkm	int connected = 0;
7688276Smarkm	char *msg, line[80];
7788276Smarkm	struct termios	cntrl;
787527Sjkh
797527Sjkh	/*
807527Sjkh	 * Get in synch with a couple of carriage returns
817527Sjkh	 */
827527Sjkh	if (!vensync(FD)) {
837527Sjkh		printf("can't synchronize with ventel\n");
8488276Smarkm#ifdef ACULOG
857527Sjkh		logent(value(HOST), num, "ventel", "can't synch up");
867527Sjkh#endif
877527Sjkh		return (0);
887527Sjkh	}
897527Sjkh	if (boolean(value(VERBOSE)))
907527Sjkh		printf("\ndialing...");
917527Sjkh	fflush(stdout);
9288276Smarkm	tcgetattr(FD, &cntrl);
9388276Smarkm	cntrl.c_cflag |= HUPCL;
9488276Smarkm	tcsetattr(FD, TCSANOW, &cntrl);
957527Sjkh	echo("#k$\r$\n$D$I$A$L$:$ ");
967527Sjkh	for (cp = num; *cp; cp++) {
977527Sjkh		delay(1, 10);
987527Sjkh		write(FD, cp, 1);
997527Sjkh	}
1007527Sjkh	delay(1, 10);
1017527Sjkh	write(FD, "\r", 1);
1027527Sjkh	gobble('\n', line);
1037527Sjkh	if (gobble('\n', line))
1047527Sjkh		connected = gobble('!', line);
10588276Smarkm	tcflush(FD, TCIOFLUSH);
10688276Smarkm#ifdef ACULOG
107161754Sru	if (dialtimeout) {
108161754Sru		(void)snprintf(line, sizeof line, "%ld second dial timeout",
1097527Sjkh			number(value(DIALTIMEOUT)));
1107527Sjkh		logent(value(HOST), num, "ventel", line);
1117527Sjkh	}
1127527Sjkh#endif
113161754Sru	if (dialtimeout)
1147527Sjkh		ven_disconnect();	/* insurance */
115161754Sru	if (connected || dialtimeout || !boolean(value(VERBOSE)))
1167527Sjkh		return (connected);
1177527Sjkh	/* call failed, parse response for user */
11888276Smarkm	cp = strchr(line, '\r');
1197527Sjkh	if (cp)
1207527Sjkh		*cp = '\0';
121161754Sru	for (cp = line; (cp = strchr(cp, ' ')) != NULL; cp++)
1227527Sjkh		if (cp[1] == ' ')
1237527Sjkh			break;
1247527Sjkh	if (cp) {
1257527Sjkh		while (*cp == ' ')
1267527Sjkh			cp++;
1277527Sjkh		msg = cp;
1287527Sjkh		while (*cp) {
1297527Sjkh			if (isupper(*cp))
1307527Sjkh				*cp = tolower(*cp);
1317527Sjkh			cp++;
1327527Sjkh		}
1337527Sjkh		printf("%s...", msg);
1347527Sjkh	}
1357527Sjkh	return (connected);
1367527Sjkh}
1377527Sjkh
13888276Smarkmvoid
139161754Sruven_disconnect(void)
1407527Sjkh{
1417527Sjkh	close(FD);
1427527Sjkh}
1437527Sjkh
14488276Smarkmvoid
145161754Sruven_abort(void)
1467527Sjkh{
1477527Sjkh	write(FD, "\03", 1);
1487527Sjkh	close(FD);
1497527Sjkh}
1507527Sjkh
1517527Sjkhstatic void
152161754Sruecho(char *s)
1537527Sjkh{
1547527Sjkh	char c;
1557527Sjkh
156161754Sru	while ((c = *s++) != '\0')
157161754Sru		switch (c) {
158161754Sru		case '$':
159161754Sru			read(FD, &c, 1);
160161754Sru			s++;
161161754Sru			break;
1627527Sjkh
163161754Sru		case '#':
164161754Sru			c = *s++;
165161754Sru			write(FD, &c, 1);
166161754Sru			break;
1677527Sjkh
168161754Sru		default:
169161754Sru			write(FD, &c, 1);
170161754Sru			read(FD, &c, 1);
171161754Sru		}
1727527Sjkh}
1737527Sjkh
174161754Sru/*ARGSUSED*/
1757527Sjkhstatic void
176161754SrusigALRM(int signo)
1777527Sjkh{
1787527Sjkh	printf("\07timeout waiting for reply\n");
179161754Sru	dialtimeout = 1;
1807527Sjkh	longjmp(timeoutbuf, 1);
1817527Sjkh}
1827527Sjkh
1837527Sjkhstatic int
184161754Srugobble(char match, char response[])
1857527Sjkh{
18688276Smarkm	char *cp = response;
1877527Sjkh	sig_t f;
1887527Sjkh	char c;
1897527Sjkh
1907527Sjkh	f = signal(SIGALRM, sigALRM);
191161754Sru	dialtimeout = 0;
1927527Sjkh	do {
1937527Sjkh		if (setjmp(timeoutbuf)) {
1947527Sjkh			signal(SIGALRM, f);
1957527Sjkh			*cp = '\0';
1967527Sjkh			return (0);
1977527Sjkh		}
1987527Sjkh		alarm(number(value(DIALTIMEOUT)));
1997527Sjkh		read(FD, cp, 1);
2007527Sjkh		alarm(0);
2017527Sjkh		c = (*cp++ &= 0177);
2027527Sjkh#ifdef notdef
2037527Sjkh		if (boolean(value(VERBOSE)))
2047527Sjkh			putchar(c);
2057527Sjkh#endif
2067527Sjkh	} while (c != '\n' && c != match);
2077527Sjkh	signal(SIGALRM, SIG_DFL);
2087527Sjkh	*cp = '\0';
2097527Sjkh	return (c == match);
2107527Sjkh}
2117527Sjkh
2127527Sjkh#define min(a,b)	((a)>(b)?(b):(a))
2137527Sjkh/*
2147527Sjkh * This convoluted piece of code attempts to get
2157527Sjkh * the ventel in sync.  If you don't have FIONREAD
2167527Sjkh * there are gory ways to simulate this.
2177527Sjkh */
2187527Sjkhstatic int
219161754Sruvensync(int fd)
2207527Sjkh{
2217527Sjkh	int already = 0, nread;
2227527Sjkh	char buf[60];
2237527Sjkh
2247527Sjkh	/*
2257527Sjkh	 * Toggle DTR to force anyone off that might have left
2267527Sjkh	 * the modem connected, and insure a consistent state
2277527Sjkh	 * to start from.
2287527Sjkh	 *
2297527Sjkh	 * If you don't have the ioctl calls to diddle directly
2307527Sjkh	 * with DTR, you can always try setting the baud rate to 0.
2317527Sjkh	 */
2327527Sjkh	ioctl(FD, TIOCCDTR, 0);
2337527Sjkh	sleep(1);
2347527Sjkh	ioctl(FD, TIOCSDTR, 0);
2357527Sjkh	while (already < MAXRETRY) {
2367527Sjkh		/*
2377527Sjkh		 * After reseting the modem, send it two \r's to
2387527Sjkh		 * autobaud on. Make sure to delay between them
2397527Sjkh		 * so the modem can frame the incoming characters.
2407527Sjkh		 */
2417527Sjkh		write(fd, "\r", 1);
2427527Sjkh		delay(1,10);
2437527Sjkh		write(fd, "\r", 1);
2447527Sjkh		sleep(2);
2457527Sjkh		if (ioctl(fd, FIONREAD, (caddr_t)&nread) < 0) {
24688276Smarkm			perror("tip: ioctl");
2477527Sjkh			continue;
2487527Sjkh		}
2497527Sjkh		while (nread > 0) {
2507527Sjkh			read(fd, buf, min(nread, 60));
2517527Sjkh			if ((buf[nread - 1] & 0177) == '$')
2527527Sjkh				return (1);
2537527Sjkh			nread -= min(nread, 60);
2547527Sjkh		}
2557527Sjkh		sleep(1);
2567527Sjkh		already++;
2577527Sjkh	}
2587527Sjkh	return (0);
2597527Sjkh}
260