1161754Sru/*	$OpenBSD: courier.c,v 1.15 2006/03/17 19:17:13 moritz Exp $	*/
288276Smarkm/*	$NetBSD: courier.c,v 1.7 1997/02/11 09:24:16 mrg Exp $	*/
388276Smarkm
47527Sjkh/*
57527Sjkh * Copyright (c) 1986, 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
3788276Smarkm#if 0
3888276Smarkmstatic char sccsid[] = "@(#)courier.c	8.1 (Berkeley) 6/6/93";
39161754Srustatic const char rcsid[] = "$OpenBSD: courier.c,v 1.15 2006/03/17 19:17:13 moritz Exp $";
4080381Ssheldonh#endif
4188276Smarkm#endif /* not lint */
427527Sjkh
437527Sjkh/*
447527Sjkh * Routines for calling up on a Courier modem.
457527Sjkh * Derived from Hayes driver.
467527Sjkh */
477527Sjkh#include "tip.h"
4888276Smarkm#include <sys/ioctl.h>
497527Sjkh#include <stdio.h>
507527Sjkh
517527Sjkh#define	MAXRETRY	5
527527Sjkh
53161754Srustatic	int dialtimeout = 0;
547527Sjkhstatic	int connected = 0;
55161754Srustatic	jmp_buf timeoutbuf;
567527Sjkh
57161754Srustatic void	sigALRM(int);
58161754Srustatic int	cour_swallow(char *);
59161754Srustatic int	cour_connect(void);
60161754Srustatic int	coursync(void);
61161754Srustatic void	cour_write(int, char *, int);
62161754Srustatic void	cour_nap(void);
63161754Sru#ifdef DEBUG
64161754Srustatic void	cour_verbose_read(void);
65161754Sru#endif
6688276Smarkm
6788276Smarkmint
68161754Srucour_dialer(char *num, char *acu)
697527Sjkh{
7088276Smarkm	char *cp;
7188276Smarkm#ifdef ACULOG
727527Sjkh	char line[80];
737527Sjkh#endif
7488276Smarkm	struct termios cntrl;
757527Sjkh
767527Sjkh	if (boolean(value(VERBOSE)))
777527Sjkh		printf("Using \"%s\"\n", acu);
787527Sjkh
7988276Smarkm	tcgetattr(FD, &cntrl);
8088276Smarkm	cntrl.c_cflag |= HUPCL;
8188276Smarkm	tcsetattr(FD, TCSAFLUSH, &cntrl);
827527Sjkh	/*
837527Sjkh	 * Get in synch.
847527Sjkh	 */
857527Sjkh	if (!coursync()) {
867527Sjkhbadsynch:
877527Sjkh		printf("can't synchronize with courier\n");
8888276Smarkm#ifdef ACULOG
897527Sjkh		logent(value(HOST), num, "courier", "can't synch up");
907527Sjkh#endif
917527Sjkh		return (0);
927527Sjkh	}
937527Sjkh	cour_write(FD, "AT E0\r", 6);	/* turn off echoing */
947527Sjkh	sleep(1);
957527Sjkh#ifdef DEBUG
967527Sjkh	if (boolean(value(VERBOSE)))
977527Sjkh		cour_verbose_read();
987527Sjkh#endif
9988276Smarkm	tcflush(FD, TCIOFLUSH);
1007527Sjkh	cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
1017527Sjkh	if (!cour_swallow("\r\nOK\r\n"))
1027527Sjkh		goto badsynch;
1037527Sjkh	fflush(stdout);
1047527Sjkh	cour_write(FD, "AT D", 4);
1057527Sjkh	for (cp = num; *cp; cp++)
1067527Sjkh		if (*cp == '=')
1077527Sjkh			*cp = ',';
1087527Sjkh	cour_write(FD, num, strlen(num));
1097527Sjkh	cour_write(FD, "\r", 1);
1107527Sjkh	connected = cour_connect();
11188276Smarkm#ifdef ACULOG
112161754Sru	if (dialtimeout) {
113161754Sru		(void)snprintf(line, sizeof line, "%ld second dial timeout",
1147527Sjkh			number(value(DIALTIMEOUT)));
1157527Sjkh		logent(value(HOST), num, "cour", line);
1167527Sjkh	}
1177527Sjkh#endif
118161754Sru	if (dialtimeout)
1197527Sjkh		cour_disconnect();
1207527Sjkh	return (connected);
1217527Sjkh}
1227527Sjkh
12388276Smarkmvoid
124161754Srucour_disconnect(void)
1257527Sjkh{
1267527Sjkh	 /* first hang up the modem*/
1277527Sjkh	ioctl(FD, TIOCCDTR, 0);
1287527Sjkh	sleep(1);
1297527Sjkh	ioctl(FD, TIOCSDTR, 0);
1307527Sjkh	coursync();				/* reset */
1317527Sjkh	close(FD);
1327527Sjkh}
1337527Sjkh
13488276Smarkmvoid
135161754Srucour_abort(void)
1367527Sjkh{
1377527Sjkh	cour_write(FD, "\r", 1);	/* send anything to abort the call */
1387527Sjkh	cour_disconnect();
1397527Sjkh}
1407527Sjkh
141161754Sru/*ARGSUSED*/
1427527Sjkhstatic void
143161754SrusigALRM(int signo)
1447527Sjkh{
1457527Sjkh	printf("\07timeout waiting for reply\n");
146161754Sru	dialtimeout = 1;
1477527Sjkh	longjmp(timeoutbuf, 1);
1487527Sjkh}
1497527Sjkh
1507527Sjkhstatic int
151161754Srucour_swallow(char *match)
15288276Smarkm{
1537527Sjkh	sig_t f;
1547527Sjkh	char c;
1557527Sjkh
1567527Sjkh	f = signal(SIGALRM, sigALRM);
157161754Sru	dialtimeout = 0;
1587527Sjkh	do {
1597527Sjkh		if (*match =='\0') {
1607527Sjkh			signal(SIGALRM, f);
1617527Sjkh			return (1);
1627527Sjkh		}
1637527Sjkh		if (setjmp(timeoutbuf)) {
1647527Sjkh			signal(SIGALRM, f);
1657527Sjkh			return (0);
1667527Sjkh		}
1677527Sjkh		alarm(number(value(DIALTIMEOUT)));
1687527Sjkh		read(FD, &c, 1);
1697527Sjkh		alarm(0);
1707527Sjkh		c &= 0177;
1717527Sjkh#ifdef DEBUG
1727527Sjkh		if (boolean(value(VERBOSE)))
1737527Sjkh			putchar(c);
1747527Sjkh#endif
1757527Sjkh	} while (c == *match++);
1767527Sjkh#ifdef DEBUG
1777527Sjkh	if (boolean(value(VERBOSE)))
1787527Sjkh		fflush(stdout);
1797527Sjkh#endif
1807527Sjkh	signal(SIGALRM, SIG_DFL);
1817527Sjkh	return (0);
1827527Sjkh}
1837527Sjkh
1847527Sjkhstruct baud_msg {
1857527Sjkh	char *msg;
1867527Sjkh	int baud;
1877527Sjkh} baud_msg[] = {
188161754Sru	{ "",		B300 },
189161754Sru	{ " 1200",	B1200 },
190161754Sru	{ " 2400",	B2400 },
191161754Sru	{ " 9600",	B9600 },
192161754Sru	{ " 9600/ARQ",	B9600 },
193161754Sru	{ 0,		0 },
1947527Sjkh};
1957527Sjkh
1967527Sjkhstatic int
197161754Srucour_connect(void)
1987527Sjkh{
1997527Sjkh	char c;
2007527Sjkh	int nc, nl, n;
2017527Sjkh	char dialer_buf[64];
2027527Sjkh	struct baud_msg *bm;
2037527Sjkh	sig_t f;
2047527Sjkh
2057527Sjkh	if (cour_swallow("\r\n") == 0)
2067527Sjkh		return (0);
2077527Sjkh	f = signal(SIGALRM, sigALRM);
2087527Sjkhagain:
2097527Sjkh	nc = 0; nl = sizeof(dialer_buf)-1;
2107527Sjkh	bzero(dialer_buf, sizeof(dialer_buf));
211161754Sru	dialtimeout = 0;
2127527Sjkh	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
2137527Sjkh		if (setjmp(timeoutbuf))
2147527Sjkh			break;
2157527Sjkh		alarm(number(value(DIALTIMEOUT)));
2167527Sjkh		n = read(FD, &c, 1);
2177527Sjkh		alarm(0);
2187527Sjkh		if (n <= 0)
2197527Sjkh			break;
2207527Sjkh		c &= 0x7f;
2217527Sjkh		if (c == '\r') {
2227527Sjkh			if (cour_swallow("\n") == 0)
2237527Sjkh				break;
2247527Sjkh			if (!dialer_buf[0])
2257527Sjkh				goto again;
2267527Sjkh			if (strcmp(dialer_buf, "RINGING") == 0 &&
2277527Sjkh			    boolean(value(VERBOSE))) {
2287527Sjkh#ifdef DEBUG
2297527Sjkh				printf("%s\r\n", dialer_buf);
2307527Sjkh#endif
2317527Sjkh				goto again;
2327527Sjkh			}
2337527Sjkh			if (strncmp(dialer_buf, "CONNECT",
2347527Sjkh				    sizeof("CONNECT")-1) != 0)
2357527Sjkh				break;
2367527Sjkh			for (bm = baud_msg ; bm->msg ; bm++)
2377527Sjkh				if (strcmp(bm->msg,
2387527Sjkh				    dialer_buf+sizeof("CONNECT")-1) == 0) {
23988276Smarkm					struct termios	cntrl;
24088276Smarkm
24188276Smarkm					tcgetattr(FD, &cntrl);
24288276Smarkm					cfsetospeed(&cntrl, bm->baud);
24388276Smarkm					cfsetispeed(&cntrl, bm->baud);
24488276Smarkm					tcsetattr(FD, TCSAFLUSH, &cntrl);
2457527Sjkh					signal(SIGALRM, f);
2467527Sjkh#ifdef DEBUG
2477527Sjkh					if (boolean(value(VERBOSE)))
2487527Sjkh						printf("%s\r\n", dialer_buf);
2497527Sjkh#endif
2507527Sjkh					return (1);
2517527Sjkh				}
2527527Sjkh			break;
2537527Sjkh		}
2547527Sjkh		dialer_buf[nc] = c;
2557527Sjkh#ifdef notdef
2567527Sjkh		if (boolean(value(VERBOSE)))
2577527Sjkh			putchar(c);
2587527Sjkh#endif
2597527Sjkh	}
2607527Sjkh	printf("%s\r\n", dialer_buf);
2617527Sjkh	signal(SIGALRM, f);
2627527Sjkh	return (0);
2637527Sjkh}
2647527Sjkh
2657527Sjkh/*
2667527Sjkh * This convoluted piece of code attempts to get
2677527Sjkh * the courier in sync.
2687527Sjkh */
2697527Sjkhstatic int
270161754Srucoursync(void)
2717527Sjkh{
2727527Sjkh	int already = 0;
2737527Sjkh	int len;
2747527Sjkh	char buf[40];
2757527Sjkh
2767527Sjkh	while (already++ < MAXRETRY) {
27788276Smarkm		tcflush(FD, TCIOFLUSH);
2787527Sjkh		cour_write(FD, "\rAT Z\r", 6);	/* reset modem */
2797527Sjkh		bzero(buf, sizeof(buf));
2807527Sjkh		sleep(1);
2817527Sjkh		ioctl(FD, FIONREAD, &len);
2827527Sjkh		if (len) {
2837527Sjkh			len = read(FD, buf, sizeof(buf));
2847527Sjkh#ifdef DEBUG
2857527Sjkh			buf[len] = '\0';
2867527Sjkh			printf("coursync: (\"%s\")\n\r", buf);
2877527Sjkh#endif
28888276Smarkm			if (strchr(buf, '0') ||
28988276Smarkm		   	   (strchr(buf, 'O') && strchr(buf, 'K')))
2907527Sjkh				return(1);
2917527Sjkh		}
2927527Sjkh		/*
2937527Sjkh		 * If not strapped for DTR control,
2947527Sjkh		 * try to get command mode.
2957527Sjkh		 */
2967527Sjkh		sleep(1);
2977527Sjkh		cour_write(FD, "+++", 3);
2987527Sjkh		sleep(1);
2997527Sjkh		/*
3007527Sjkh		 * Toggle DTR to force anyone off that might have left
3017527Sjkh		 * the modem connected.
3027527Sjkh		 */
3037527Sjkh		ioctl(FD, TIOCCDTR, 0);
3047527Sjkh		sleep(1);
3057527Sjkh		ioctl(FD, TIOCSDTR, 0);
3067527Sjkh	}
3077527Sjkh	cour_write(FD, "\rAT Z\r", 6);
3087527Sjkh	return (0);
3097527Sjkh}
3107527Sjkh
31188276Smarkmstatic void
312161754Srucour_write(int fd, char *cp, int n)
3137527Sjkh{
3147527Sjkh#ifdef notdef
3157527Sjkh	if (boolean(value(VERBOSE)))
31688276Smarkm		write(1, cp, n);
3177527Sjkh#endif
31888276Smarkm	tcdrain(fd);
3197527Sjkh	cour_nap();
3207527Sjkh	for ( ; n-- ; cp++) {
3217527Sjkh		write(fd, cp, 1);
32288276Smarkm		tcdrain(fd);
3237527Sjkh		cour_nap();
3247527Sjkh	}
3257527Sjkh}
3267527Sjkh
3277527Sjkh#ifdef DEBUG
328161754Srustatic void
329161754Srucour_verbose_read(void)
3307527Sjkh{
3317527Sjkh	int n = 0;
3327527Sjkh	char buf[BUFSIZ];
3337527Sjkh
3347527Sjkh	if (ioctl(FD, FIONREAD, &n) < 0)
3357527Sjkh		return;
3367527Sjkh	if (n <= 0)
3377527Sjkh		return;
3387527Sjkh	if (read(FD, buf, n) != n)
3397527Sjkh		return;
34088276Smarkm	write(1, buf, n);
3417527Sjkh}
3427527Sjkh#endif
3437527Sjkh
34488276Smarkm/* Give the courier 50 milliseconds between characters */
345161754Srustatic void
346161754Srucour_nap(void)
3477527Sjkh{
34888276Smarkm	struct timespec ts;
34988276Smarkm
35088276Smarkm	ts.tv_sec = 0;
35188276Smarkm	ts.tv_nsec = 50 * 1000000;
35288276Smarkm
35388276Smarkm	nanosleep(&ts, NULL);
3547527Sjkh}
355