courier.c revision 92922
1/*	$OpenBSD: courier.c,v 1.9 2001/10/24 18:38:58 millert Exp $	*/
2/*	$NetBSD: courier.c,v 1.7 1997/02/11 09:24:16 mrg Exp $	*/
3
4/*
5 * Copyright (c) 1986, 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. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/usr.bin/tip/libacu/courier.c 92922 2002-03-22 01:42:45Z imp $");
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)courier.c	8.1 (Berkeley) 6/6/93";
43static char rcsid[] = "$OpenBSD: courier.c,v 1.9 2001/10/24 18:38:58 millert Exp $";
44#endif
45#endif /* not lint */
46
47/*
48 * Routines for calling up on a Courier modem.
49 * Derived from Hayes driver.
50 */
51#include "tip.h"
52#include <sys/ioctl.h>
53#include <stdio.h>
54
55#define	MAXRETRY	5
56
57static	void sigALRM();
58static	int timeout = 0;
59static	int connected = 0;
60static	jmp_buf timeoutbuf, intbuf;
61static	int coursync(), cour_connect(), cour_swallow();
62void	cour_nap();
63
64void cour_disconnect(void);
65
66int
67cour_dialer(num, acu)
68	char *num;
69	char *acu;
70{
71	char *cp;
72#ifdef ACULOG
73	char line[80];
74#endif
75	struct termios cntrl;
76
77	if (boolean(value(VERBOSE)))
78		printf("Using \"%s\"\n", acu);
79
80	tcgetattr(FD, &cntrl);
81	cntrl.c_cflag |= HUPCL;
82	tcsetattr(FD, TCSAFLUSH, &cntrl);
83	/*
84	 * Get in synch.
85	 */
86	if (!coursync()) {
87badsynch:
88		printf("can't synchronize with courier\n");
89#ifdef ACULOG
90		logent(value(HOST), num, "courier", "can't synch up");
91#endif
92		return (0);
93	}
94	cour_write(FD, "AT E0\r", 6);	/* turn off echoing */
95	sleep(1);
96#ifdef DEBUG
97	if (boolean(value(VERBOSE)))
98		cour_verbose_read();
99#endif
100	tcflush(FD, TCIOFLUSH);
101	cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
102	if (!cour_swallow("\r\nOK\r\n"))
103		goto badsynch;
104	fflush(stdout);
105	cour_write(FD, "AT D", 4);
106	for (cp = num; *cp; cp++)
107		if (*cp == '=')
108			*cp = ',';
109	cour_write(FD, num, strlen(num));
110	cour_write(FD, "\r", 1);
111	connected = cour_connect();
112#ifdef ACULOG
113	if (timeout) {
114		(void)sprintf(line, "%ld second dial timeout",
115			number(value(DIALTIMEOUT)));
116		logent(value(HOST), num, "cour", line);
117	}
118#endif
119	if (timeout)
120		cour_disconnect();
121	return (connected);
122}
123
124void
125cour_disconnect()
126{
127	 /* first hang up the modem*/
128	ioctl(FD, TIOCCDTR, 0);
129	sleep(1);
130	ioctl(FD, TIOCSDTR, 0);
131	coursync();				/* reset */
132	close(FD);
133}
134
135void
136cour_abort()
137{
138	cour_write(FD, "\r", 1);	/* send anything to abort the call */
139	cour_disconnect();
140}
141
142static void
143sigALRM()
144{
145	printf("\07timeout waiting for reply\n");
146	timeout = 1;
147	longjmp(timeoutbuf, 1);
148}
149
150static int
151cour_swallow(match)
152	char *match;
153{
154	sig_t f;
155	char c;
156
157	f = signal(SIGALRM, sigALRM);
158	timeout = 0;
159	do {
160		if (*match =='\0') {
161			signal(SIGALRM, f);
162			return (1);
163		}
164		if (setjmp(timeoutbuf)) {
165			signal(SIGALRM, f);
166			return (0);
167		}
168		alarm(number(value(DIALTIMEOUT)));
169		read(FD, &c, 1);
170		alarm(0);
171		c &= 0177;
172#ifdef DEBUG
173		if (boolean(value(VERBOSE)))
174			putchar(c);
175#endif
176	} while (c == *match++);
177#ifdef DEBUG
178	if (boolean(value(VERBOSE)))
179		fflush(stdout);
180#endif
181	signal(SIGALRM, SIG_DFL);
182	return (0);
183}
184
185struct baud_msg {
186	char *msg;
187	int baud;
188} baud_msg[] = {
189	"",		B300,
190	" 1200",	B1200,
191	" 2400",	B2400,
192	" 9600",	B9600,
193	" 9600/ARQ",	B9600,
194	0,		0,
195};
196
197static int
198cour_connect()
199{
200	char c;
201	int nc, nl, n;
202	char dialer_buf[64];
203	struct baud_msg *bm;
204	sig_t f;
205
206	if (cour_swallow("\r\n") == 0)
207		return (0);
208	f = signal(SIGALRM, sigALRM);
209again:
210	nc = 0; nl = sizeof(dialer_buf)-1;
211	bzero(dialer_buf, sizeof(dialer_buf));
212	timeout = 0;
213	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
214		if (setjmp(timeoutbuf))
215			break;
216		alarm(number(value(DIALTIMEOUT)));
217		n = read(FD, &c, 1);
218		alarm(0);
219		if (n <= 0)
220			break;
221		c &= 0x7f;
222		if (c == '\r') {
223			if (cour_swallow("\n") == 0)
224				break;
225			if (!dialer_buf[0])
226				goto again;
227			if (strcmp(dialer_buf, "RINGING") == 0 &&
228			    boolean(value(VERBOSE))) {
229#ifdef DEBUG
230				printf("%s\r\n", dialer_buf);
231#endif
232				goto again;
233			}
234			if (strncmp(dialer_buf, "CONNECT",
235				    sizeof("CONNECT")-1) != 0)
236				break;
237			for (bm = baud_msg ; bm->msg ; bm++)
238				if (strcmp(bm->msg,
239				    dialer_buf+sizeof("CONNECT")-1) == 0) {
240					struct termios	cntrl;
241
242					tcgetattr(FD, &cntrl);
243					cfsetospeed(&cntrl, bm->baud);
244					cfsetispeed(&cntrl, bm->baud);
245					tcsetattr(FD, TCSAFLUSH, &cntrl);
246					signal(SIGALRM, f);
247#ifdef DEBUG
248					if (boolean(value(VERBOSE)))
249						printf("%s\r\n", dialer_buf);
250#endif
251					return (1);
252				}
253			break;
254		}
255		dialer_buf[nc] = c;
256#ifdef notdef
257		if (boolean(value(VERBOSE)))
258			putchar(c);
259#endif
260	}
261	printf("%s\r\n", dialer_buf);
262	signal(SIGALRM, f);
263	return (0);
264}
265
266/*
267 * This convoluted piece of code attempts to get
268 * the courier in sync.
269 */
270static int
271coursync()
272{
273	int already = 0;
274	int len;
275	char buf[40];
276
277	while (already++ < MAXRETRY) {
278		tcflush(FD, TCIOFLUSH);
279		cour_write(FD, "\rAT Z\r", 6);	/* reset modem */
280		bzero(buf, sizeof(buf));
281		sleep(1);
282		ioctl(FD, FIONREAD, &len);
283		if (len) {
284			len = read(FD, buf, sizeof(buf));
285#ifdef DEBUG
286			buf[len] = '\0';
287			printf("coursync: (\"%s\")\n\r", buf);
288#endif
289			if (strchr(buf, '0') ||
290		   	   (strchr(buf, 'O') && strchr(buf, 'K')))
291				return(1);
292		}
293		/*
294		 * If not strapped for DTR control,
295		 * try to get command mode.
296		 */
297		sleep(1);
298		cour_write(FD, "+++", 3);
299		sleep(1);
300		/*
301		 * Toggle DTR to force anyone off that might have left
302		 * the modem connected.
303		 */
304		ioctl(FD, TIOCCDTR, 0);
305		sleep(1);
306		ioctl(FD, TIOCSDTR, 0);
307	}
308	cour_write(FD, "\rAT Z\r", 6);
309	return (0);
310}
311
312static void
313cour_write(fd, cp, n)
314int fd;
315char *cp;
316int n;
317{
318#ifdef notdef
319	if (boolean(value(VERBOSE)))
320		write(1, cp, n);
321#endif
322	tcdrain(fd);
323	cour_nap();
324	for ( ; n-- ; cp++) {
325		write(fd, cp, 1);
326		tcdrain(fd);
327		cour_nap();
328	}
329}
330
331#ifdef DEBUG
332cour_verbose_read()
333{
334	int n = 0;
335	char buf[BUFSIZ];
336
337	if (ioctl(FD, FIONREAD, &n) < 0)
338		return;
339	if (n <= 0)
340		return;
341	if (read(FD, buf, n) != n)
342		return;
343	write(1, buf, n);
344}
345#endif
346
347/* Give the courier 50 milliseconds between characters */
348void
349cour_nap()
350{
351	struct timespec ts;
352
353	ts.tv_sec = 0;
354	ts.tv_nsec = 50 * 1000000;
355
356	nanosleep(&ts, NULL);
357}
358