1161754Sru/*	$OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $	*/
288276Smarkm/*	$NetBSD: hayes.c,v 1.6 1997/02/11 09:24:17 mrg Exp $	*/
388276Smarkm
47527Sjkh/*
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: releng/10.3/usr.bin/tip/libacu/hayes.c 161781 2006-08-31 19:19:44Z ru $");
3588276Smarkm
367527Sjkh#ifndef lint
3788276Smarkm#if 0
387527Sjkhstatic char sccsid[] = "@(#)hayes.c	8.1 (Berkeley) 6/6/93";
39161754Srustatic const char rcsid[] = "$OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $";
4088276Smarkm#endif
417527Sjkh#endif /* not lint */
427527Sjkh
437527Sjkh/*
447527Sjkh * Routines for calling up on a Hayes Modem
457527Sjkh * (based on the old VenTel driver).
467527Sjkh * The modem is expected to be strapped for "echo".
477527Sjkh * Also, the switches enabling the DTR and CD lines
487527Sjkh * must be set correctly.
497527Sjkh * NOTICE:
507527Sjkh * The easy way to hang up a modem is always simply to
517527Sjkh * clear the DTR signal. However, if the +++ sequence
527527Sjkh * (which switches the modem back to local mode) is sent
537527Sjkh * before modem is hung up, removal of the DTR signal
547527Sjkh * has no effect (except that it prevents the modem from
557527Sjkh * recognizing commands).
5688276Smarkm * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
577527Sjkh */
587527Sjkh/*
597527Sjkh * TODO:
607527Sjkh * It is probably not a good idea to switch the modem
617527Sjkh * state between 'verbose' and terse (status messages).
6288276Smarkm * This should be kicked out and we should use verbose
637527Sjkh * mode only. This would make it consistent with normal
647527Sjkh * interactive use thru the command 'tip dialer'.
657527Sjkh */
667527Sjkh#include "tip.h"
677527Sjkh
6888276Smarkm#include <termios.h>
6988276Smarkm#include <sys/ioctl.h>
7088276Smarkm
717527Sjkh#define	min(a,b)	((a < b) ? a : b)
727527Sjkh
73161754Srustatic	int dialtimeout = 0;
747527Sjkhstatic	jmp_buf timeoutbuf;
75161754Sru
767527Sjkh#define DUMBUFLEN	40
777527Sjkhstatic char dumbuf[DUMBUFLEN];
787527Sjkh
797527Sjkh#define	DIALING		1
807527Sjkh#define IDLE		2
817527Sjkh#define CONNECTED	3
827527Sjkh#define	FAILED		4
837527Sjkhstatic	int state = IDLE;
847527Sjkh
85161754Srustatic void	sigALRM(int);
86161754Srustatic char	gobble(char *);
87161754Srustatic void	error_rep(char);
88161754Srustatic void	goodbye(void);
89161754Srustatic int	hay_sync(void);
90161754Sru
9188276Smarkmint
92161754Sruhay_dialer(char *num, char *acu)
937527Sjkh{
9488276Smarkm	char *cp;
9588276Smarkm	int connected = 0;
967527Sjkh	char dummy;
9788276Smarkm	struct termios cntrl;
9888276Smarkm#ifdef ACULOG
997527Sjkh	char line[80];
1007527Sjkh#endif
1017527Sjkh	if (hay_sync() == 0)		/* make sure we can talk to the modem */
1027527Sjkh		return(0);
1037527Sjkh	if (boolean(value(VERBOSE)))
1047527Sjkh		printf("\ndialing...");
1057527Sjkh	fflush(stdout);
10688276Smarkm	tcgetattr(FD, &cntrl);
10788276Smarkm	cntrl.c_cflag |= HUPCL;
10888276Smarkm	tcsetattr(FD, TCSANOW, &cntrl);
10988276Smarkm	tcflush(FD, TCIOFLUSH);
1107527Sjkh	write(FD, "ATv0\r", 5);	/* tell modem to use short status codes */
1117527Sjkh	gobble("\r");
1127527Sjkh	gobble("\r");
1137527Sjkh	write(FD, "ATTD", 4);	/* send dial command */
11488276Smarkm	for (cp = num; *cp; cp++)
11588276Smarkm		if (*cp == '=')
11688276Smarkm			*cp = ',';
1177527Sjkh	write(FD, num, strlen(num));
1187527Sjkh	state = DIALING;
1197527Sjkh	write(FD, "\r", 1);
1207527Sjkh	connected = 0;
1217527Sjkh	if (gobble("\r")) {
1227527Sjkh		if ((dummy = gobble("01234")) != '1')
1237527Sjkh			error_rep(dummy);
1247527Sjkh		else
1257527Sjkh			connected = 1;
1267527Sjkh	}
1277527Sjkh	if (connected)
1287527Sjkh		state = CONNECTED;
1297527Sjkh	else {
1307527Sjkh		state = FAILED;
1317527Sjkh		return (connected);	/* lets get out of here.. */
1327527Sjkh	}
13388276Smarkm	tcflush(FD, TCIOFLUSH);
13488276Smarkm#ifdef ACULOG
135161754Sru	if (dialtimeout) {
136161754Sru		(void)snprintf(line, sizeof line, "%ld second dial timeout",
1377527Sjkh			number(value(DIALTIMEOUT)));
1387527Sjkh		logent(value(HOST), num, "hayes", line);
1397527Sjkh	}
1407527Sjkh#endif
141161754Sru	if (dialtimeout)
1427527Sjkh		hay_disconnect();	/* insurance */
1437527Sjkh	return (connected);
1447527Sjkh}
1457527Sjkh
14688276Smarkmvoid
147161754Sruhay_disconnect(void)
1487527Sjkh{
1497527Sjkh	/* first hang up the modem*/
1507527Sjkh#ifdef DEBUG
1517527Sjkh	printf("\rdisconnecting modem....\n\r");
1527527Sjkh#endif
1537527Sjkh	ioctl(FD, TIOCCDTR, 0);
1547527Sjkh	sleep(1);
1557527Sjkh	ioctl(FD, TIOCSDTR, 0);
1567527Sjkh	goodbye();
1577527Sjkh}
1587527Sjkh
15988276Smarkmvoid
160161754Sruhay_abort(void)
1617527Sjkh{
1627527Sjkh	write(FD, "\r", 1);	/* send anything to abort the call */
1637527Sjkh	hay_disconnect();
1647527Sjkh}
1657527Sjkh
166161754Sru/*ARGSUSED*/
1677527Sjkhstatic void
168161754SrusigALRM(int signo)
1697527Sjkh{
1707527Sjkh	printf("\07timeout waiting for reply\n\r");
171161754Sru	dialtimeout = 1;
1727527Sjkh	longjmp(timeoutbuf, 1);
1737527Sjkh}
1747527Sjkh
1757527Sjkhstatic char
176161754Srugobble(char *match)
1777527Sjkh{
1787527Sjkh	char c;
1797527Sjkh	sig_t f;
180161781Sru	size_t i;
181161781Sru	int status = 0;
1827527Sjkh
1837527Sjkh	f = signal(SIGALRM, sigALRM);
184161754Sru	dialtimeout = 0;
1857527Sjkh#ifdef DEBUG
1867527Sjkh	printf("\ngobble: waiting for %s\n", match);
1877527Sjkh#endif
1887527Sjkh	do {
1897527Sjkh		if (setjmp(timeoutbuf)) {
1907527Sjkh			signal(SIGALRM, f);
1917527Sjkh			return (0);
1927527Sjkh		}
1937527Sjkh		alarm(number(value(DIALTIMEOUT)));
1947527Sjkh		read(FD, &c, 1);
1957527Sjkh		alarm(0);
1967527Sjkh		c &= 0177;
1977527Sjkh#ifdef DEBUG
1987527Sjkh		printf("%c 0x%x ", c, c);
1997527Sjkh#endif
2007527Sjkh		for (i = 0; i < strlen(match); i++)
2017527Sjkh			if (c == match[i])
2027527Sjkh				status = c;
2037527Sjkh	} while (status == 0);
2047527Sjkh	signal(SIGALRM, SIG_DFL);
2057527Sjkh#ifdef DEBUG
2067527Sjkh	printf("\n");
2077527Sjkh#endif
2087527Sjkh	return (status);
2097527Sjkh}
2107527Sjkh
21188276Smarkmstatic void
212161754Sruerror_rep(char c)
2137527Sjkh{
2147527Sjkh	printf("\n\r");
2157527Sjkh	switch (c) {
2167527Sjkh
2177527Sjkh	case '0':
2187527Sjkh		printf("OK");
2197527Sjkh		break;
2207527Sjkh
2217527Sjkh	case '1':
2227527Sjkh		printf("CONNECT");
2237527Sjkh		break;
224161754Sru
2257527Sjkh	case '2':
2267527Sjkh		printf("RING");
2277527Sjkh		break;
228161754Sru
2297527Sjkh	case '3':
2307527Sjkh		printf("NO CARRIER");
2317527Sjkh		break;
232161754Sru
2337527Sjkh	case '4':
2347527Sjkh		printf("ERROR in input");
2357527Sjkh		break;
236161754Sru
2377527Sjkh	case '5':
2387527Sjkh		printf("CONNECT 1200");
2397527Sjkh		break;
240161754Sru
2417527Sjkh	default:
2427527Sjkh		printf("Unknown Modem error: %c (0x%x)", c, c);
2437527Sjkh	}
2447527Sjkh	printf("\n\r");
2457527Sjkh	return;
2467527Sjkh}
2477527Sjkh
2487527Sjkh/*
2497527Sjkh * set modem back to normal verbose status codes.
2507527Sjkh */
251113163Simpstatic void
252113163Simpgoodbye(void)
2537527Sjkh{
25488276Smarkm	int len;
2557527Sjkh	char c;
2567527Sjkh
25788276Smarkm	tcflush(FD, TCIOFLUSH);
2587527Sjkh	if (hay_sync()) {
2597527Sjkh		sleep(1);
2607527Sjkh#ifndef DEBUG
26188276Smarkm		tcflush(FD, TCIOFLUSH);
2627527Sjkh#endif
2637527Sjkh		write(FD, "ATH0\r", 5);		/* insurance */
2647527Sjkh#ifndef DEBUG
2657527Sjkh		c = gobble("03");
2667527Sjkh		if (c != '0' && c != '3') {
2677527Sjkh			printf("cannot hang up modem\n\r");
2687527Sjkh			printf("please use 'tip dialer' to make sure the line is hung up\n\r");
2697527Sjkh		}
2707527Sjkh#endif
2717527Sjkh		sleep(1);
2727527Sjkh		ioctl(FD, FIONREAD, &len);
2737527Sjkh#ifdef DEBUG
2747527Sjkh		printf("goodbye1: len=%d -- ", len);
2757527Sjkh		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
2767527Sjkh		dumbuf[rlen] = '\0';
2777527Sjkh		printf("read (%d): %s\r\n", rlen, dumbuf);
2787527Sjkh#endif
2797527Sjkh		write(FD, "ATv1\r", 5);
2807527Sjkh		sleep(1);
2817527Sjkh#ifdef DEBUG
2827527Sjkh		ioctl(FD, FIONREAD, &len);
2837527Sjkh		printf("goodbye2: len=%d -- ", len);
2847527Sjkh		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
2857527Sjkh		dumbuf[rlen] = '\0';
2867527Sjkh		printf("read (%d): %s\r\n", rlen, dumbuf);
2877527Sjkh#endif
2887527Sjkh	}
28988276Smarkm	tcflush(FD, TCIOFLUSH);
2907527Sjkh	ioctl(FD, TIOCCDTR, 0);		/* clear DTR (insurance) */
2917527Sjkh	close(FD);
2927527Sjkh}
2937527Sjkh
2947527Sjkh#define MAXRETRY	5
2957527Sjkh
296161754Srustatic int
297161754Sruhay_sync(void)
2987527Sjkh{
2997527Sjkh	int len, retry = 0;
3007527Sjkh
3017527Sjkh	while (retry++ <= MAXRETRY) {
3027527Sjkh		write(FD, "AT\r", 3);
3037527Sjkh		sleep(1);
3047527Sjkh		ioctl(FD, FIONREAD, &len);
3057527Sjkh		if (len) {
3067527Sjkh			len = read(FD, dumbuf, min(len, DUMBUFLEN));
30788276Smarkm			if (strchr(dumbuf, '0') ||
30888276Smarkm		   	(strchr(dumbuf, 'O') && strchr(dumbuf, 'K')))
3097527Sjkh				return(1);
3107527Sjkh#ifdef DEBUG
3117527Sjkh			dumbuf[len] = '\0';
3127527Sjkh			printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
3137527Sjkh#endif
3147527Sjkh		}
3157527Sjkh		ioctl(FD, TIOCCDTR, 0);
3167527Sjkh		ioctl(FD, TIOCSDTR, 0);
3177527Sjkh	}
3187527Sjkh	printf("Cannot synchronize with hayes...\n\r");
3197527Sjkh	return(0);
3207527Sjkh}
321