xref: /csrg-svn/usr.bin/tip/aculib/courier.c (revision 30517)
127000Sdonn /*
227000Sdonn  * Copyright (c) 1986 Regents of the University of California.
327000Sdonn  * All rights reserved.  The Berkeley software License Agreement
427000Sdonn  * specifies the terms and conditions for redistribution.
527000Sdonn  */
627000Sdonn 
727000Sdonn #ifndef lint
8*30517Skarels static char sccsid[] = "@(#)courier.c	5.2 (Berkeley) 02/17/87";
927000Sdonn #endif
1027000Sdonn 
1127000Sdonn #define write cour_write
1227000Sdonn /*
13*30517Skarels  * Routines for calling up on a Courier modem.
14*30517Skarels  * Derived from Hayes driver.
1527000Sdonn  */
1627000Sdonn #include "tip.h"
1727000Sdonn #include <stdio.h>
1827000Sdonn 
1927000Sdonn #define	MAXRETRY	5
2027000Sdonn 
2127000Sdonn static	int sigALRM();
2227000Sdonn static	int timeout = 0;
23*30517Skarels static	int connected = 0;
2427000Sdonn static	jmp_buf timeoutbuf, intbuf;
2527000Sdonn static	int (*osigint)();
2627000Sdonn 
2727000Sdonn cour_dialer(num, acu)
2827000Sdonn 	register char *num;
2927000Sdonn 	char *acu;
3027000Sdonn {
3127000Sdonn 	register char *cp;
3227000Sdonn #ifdef ACULOG
3327000Sdonn 	char line[80];
3427000Sdonn #endif
3527000Sdonn 	if (boolean(value(VERBOSE)))
3627000Sdonn 		printf("Using \"%s\"\n", acu);
3727000Sdonn 
3827000Sdonn 	ioctl(FD, TIOCHPCL, 0);
3927000Sdonn 	/*
4027000Sdonn 	 * Get in synch.
4127000Sdonn 	 */
4227000Sdonn 	if (!coursync()) {
43*30517Skarels badsynch:
4427000Sdonn 		printf("can't synchronize with courier\n");
4527000Sdonn #ifdef ACULOG
4627000Sdonn 		logent(value(HOST), num, "courier", "can't synch up");
4727000Sdonn #endif
4827000Sdonn 		return (0);
4927000Sdonn 	}
50*30517Skarels 	write(FD, "AT E0\r", 6);	/* turn off echoing */
51*30517Skarels 	sleep(1);
52*30517Skarels #ifdef DEBUG
53*30517Skarels 	if (boolean(value(VERBOSE)))
54*30517Skarels 		verbose_read();
55*30517Skarels #endif
56*30517Skarels 	ioctl(FD, TIOCFLUSH, 0);	/* flush any clutter */
57*30517Skarels 	write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
58*30517Skarels 	if (!cour_swallow("\r\nOK\r\n"))
59*30517Skarels 		goto badsynch;
6027000Sdonn 	fflush(stdout);
6127000Sdonn 	write(FD, "AT D", 4);
6227000Sdonn 	for (cp = num; *cp; cp++)
6327000Sdonn 		if (*cp == '=')
6427000Sdonn 			*cp = ',';
6527000Sdonn 	write(FD, num, strlen(num));
6627000Sdonn 	write(FD, "\r", 1);
6727000Sdonn 	connected = cour_connect();
6827000Sdonn #ifdef ACULOG
6927000Sdonn 	if (timeout) {
7027000Sdonn 		sprintf(line, "%d second dial timeout",
7127000Sdonn 			number(value(DIALTIMEOUT)));
7227000Sdonn 		logent(value(HOST), num, "cour", line);
7327000Sdonn 	}
7427000Sdonn #endif
7527000Sdonn 	if (timeout)
7627000Sdonn 		cour_disconnect();
7727000Sdonn 	return (connected);
7827000Sdonn }
7927000Sdonn 
8027000Sdonn cour_disconnect()
81*30517Skarels {
82*30517Skarels 	 /* first hang up the modem*/
83*30517Skarels 	ioctl(FD, TIOCCDTR, 0);
84*30517Skarels 	sleep(1);
85*30517Skarels 	ioctl(FD, TIOCSDTR, 0);
86*30517Skarels 	coursync();				/* reset */
8727000Sdonn 	close(FD);
8827000Sdonn }
8927000Sdonn 
9027000Sdonn cour_abort()
91*30517Skarels {
92*30517Skarels 	write(FD, "\r", 1);	/* send anything to abort the call */
93*30517Skarels 	cour_disconnect();
9427000Sdonn }
9527000Sdonn 
9627000Sdonn static int
9727000Sdonn sigALRM()
9827000Sdonn {
9927000Sdonn 	printf("\07timeout waiting for reply\n");
10027000Sdonn 	timeout = 1;
10127000Sdonn 	longjmp(timeoutbuf, 1);
10227000Sdonn }
10327000Sdonn 
10427000Sdonn static int
10527000Sdonn cour_swallow(match)
10627000Sdonn   register char *match;
10727000Sdonn   {
10827000Sdonn 	char c;
10927000Sdonn 	int (*f)();
11027000Sdonn 
11127000Sdonn 	f = signal(SIGALRM, sigALRM);
11227000Sdonn 	timeout = 0;
11327000Sdonn 	do {
11427000Sdonn 		if (*match =='\0') {
11527000Sdonn 			signal(SIGALRM, f);
116*30517Skarels 			return (1);
11727000Sdonn 		}
11827000Sdonn 		if (setjmp(timeoutbuf)) {
11927000Sdonn 			signal(SIGALRM, f);
12027000Sdonn 			return (0);
12127000Sdonn 		}
12227000Sdonn 		alarm(number(value(DIALTIMEOUT)));
12327000Sdonn 		read(FD, &c, 1);
12427000Sdonn 		alarm(0);
12527000Sdonn 		c &= 0177;
126*30517Skarels #ifdef DEBUG
12727000Sdonn 		if (boolean(value(VERBOSE)))
12827000Sdonn 			putchar(c);
129*30517Skarels #endif
13027000Sdonn 	} while (c == *match++);
131*30517Skarels #ifdef DEBUG
13227000Sdonn 	if (boolean(value(VERBOSE)))
13327000Sdonn 		fflush(stdout);
134*30517Skarels #endif
13527000Sdonn 	signal(SIGALRM, SIG_DFL);
13627000Sdonn 	return (0);
13727000Sdonn }
13827000Sdonn 
13927000Sdonn struct baud_msg {
14027000Sdonn 	char *msg;
14127000Sdonn 	int baud;
14227000Sdonn } baud_msg[] = {
14327000Sdonn 	"",		B300,
14427000Sdonn 	" 1200",	B1200,
14527000Sdonn 	" 2400",	B2400,
14627000Sdonn 	0,		0,
14727000Sdonn };
14827000Sdonn 
14927000Sdonn static int
15027000Sdonn cour_connect()
15127000Sdonn {
15227000Sdonn 	char c;
15327000Sdonn 	int nc, nl, n;
15427000Sdonn 	struct sgttyb sb;
15527000Sdonn 	char dialer_buf[64];
15627000Sdonn 	struct baud_msg *bm;
15727000Sdonn 	int (*f)();
15827000Sdonn 
15927000Sdonn 	if (cour_swallow("\r\n") == 0)
16027000Sdonn 		return (0);
16127000Sdonn 	f = signal(SIGALRM, sigALRM);
16227000Sdonn again:
16327000Sdonn 	nc = 0; nl = sizeof(dialer_buf)-1;
16427000Sdonn 	bzero(dialer_buf, sizeof(dialer_buf));
16527000Sdonn 	timeout = 0;
16627000Sdonn 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
16727000Sdonn 		if (setjmp(timeoutbuf))
16827000Sdonn 			break;
16927000Sdonn 		alarm(number(value(DIALTIMEOUT)));
17027000Sdonn 		n = read(FD, &c, 1);
17127000Sdonn 		alarm(0);
17227000Sdonn 		if (n <= 0)
17327000Sdonn 			break;
17427000Sdonn 		c &= 0x7f;
17527000Sdonn 		if (c == '\r') {
17627000Sdonn 			if (cour_swallow("\n") == 0)
17727000Sdonn 				break;
17827000Sdonn 			if (!dialer_buf[0])
17927000Sdonn 				goto again;
180*30517Skarels 			if (strcmp(dialer_buf, "RINGING") == 0 &&
181*30517Skarels 			    boolean(value(VERBOSE))) {
182*30517Skarels #ifdef DEBUG
18327000Sdonn 				printf("%s\r\n", dialer_buf);
184*30517Skarels #endif
18527000Sdonn 				goto again;
18627000Sdonn 			}
18727000Sdonn 			if (strncmp(dialer_buf, "CONNECT",
18827000Sdonn 				    sizeof("CONNECT")-1) != 0)
18927000Sdonn 				break;
19027000Sdonn 			for (bm = baud_msg ; bm ; bm++)
19127000Sdonn 				if (strcmp(bm->msg,
19227000Sdonn 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
19327000Sdonn 					if (ioctl(FD, TIOCGETP, &sb) < 0) {
19427000Sdonn 						perror("TIOCGETP");
19527000Sdonn 						goto error;
19627000Sdonn 					}
19727000Sdonn 					sb.sg_ispeed = sb.sg_ospeed = bm->baud;
19827000Sdonn 					if (ioctl(FD, TIOCSETP, &sb) < 0) {
19927000Sdonn 						perror("TIOCSETP");
20027000Sdonn 						goto error;
20127000Sdonn 					}
20227000Sdonn 					signal(SIGALRM, f);
203*30517Skarels #ifdef DEBUG
20427000Sdonn 					if (boolean(value(VERBOSE)))
20527000Sdonn 						printf("%s\r\n", dialer_buf);
206*30517Skarels #endif
20727000Sdonn 					return (1);
20827000Sdonn 				}
20927000Sdonn 			break;
21027000Sdonn 		}
21127000Sdonn 		dialer_buf[nc] = c;
21227000Sdonn #ifdef notdef
21327000Sdonn 		if (boolean(value(VERBOSE)))
21427000Sdonn 			putchar(c);
21527000Sdonn #endif
21627000Sdonn 	}
21727000Sdonn error1:
21827000Sdonn 	printf("%s\r\n", dialer_buf);
21927000Sdonn error:
22027000Sdonn 	signal(SIGALRM, f);
22127000Sdonn 	return (0);
22227000Sdonn }
22327000Sdonn 
22427000Sdonn /*
22527000Sdonn  * This convoluted piece of code attempts to get
226*30517Skarels  * the courier in sync.
22727000Sdonn  */
22827000Sdonn static int
22927000Sdonn coursync()
23027000Sdonn {
23127000Sdonn 	int already = 0;
232*30517Skarels 	int len;
233*30517Skarels 	char buf[40];
23427000Sdonn 
23527000Sdonn 	while (already++ < MAXRETRY) {
23627000Sdonn 		ioctl(FD, TIOCFLUSH, 0);	/* flush any clutter */
23727000Sdonn 		write(FD, "\rAT Z\r", 6);	/* reset modem */
238*30517Skarels 		bzero(buf, sizeof(buf));
23927000Sdonn 		sleep(1);
240*30517Skarels 		ioctl(FD, FIONREAD, &len);
241*30517Skarels 		if (len) {
242*30517Skarels 			len = read(FD, buf, sizeof(buf));
243*30517Skarels #ifdef DEBUG
244*30517Skarels 			buf[len] = '\0';
245*30517Skarels 			printf("coursync: (\"%s\")\n\r", buf);
246*30517Skarels #endif
247*30517Skarels 			if (index(buf, '0') ||
248*30517Skarels 		   	   (index(buf, 'O') && index(buf, 'K')))
249*30517Skarels 				return(1);
25027000Sdonn 		}
251*30517Skarels 		/*
252*30517Skarels 		 * If not strapped for DTR control,
253*30517Skarels 		 * try to get command mode.
254*30517Skarels 		 */
255*30517Skarels 		sleep(1);
25627000Sdonn 		write(FD, "+++", 3);
257*30517Skarels 		sleep(1);
258*30517Skarels 		/*
259*30517Skarels 		 * Toggle DTR to force anyone off that might have left
260*30517Skarels 		 * the modem connected.
261*30517Skarels 		 */
262*30517Skarels 		ioctl(FD, TIOCCDTR, 0);
263*30517Skarels 		sleep(1);
264*30517Skarels 		ioctl(FD, TIOCSDTR, 0);
26527000Sdonn 	}
26627000Sdonn 	write(FD, "\rAT Z\r", 6);
267*30517Skarels 	return (0);
26827000Sdonn }
26927000Sdonn 
27027000Sdonn #undef write
27127000Sdonn 
27227000Sdonn cour_write(fd, cp, n)
27327000Sdonn int fd;
27427000Sdonn char *cp;
27527000Sdonn int n;
27627000Sdonn {
27727000Sdonn 	struct sgttyb sb;
278*30517Skarels #ifdef notdef
27927000Sdonn 	if (boolean(value(VERBOSE)))
28027000Sdonn 		write(1, cp, n);
281*30517Skarels #endif
28227000Sdonn 	ioctl(fd, TIOCGETP, &sb);
28327000Sdonn 	ioctl(fd, TIOCSETP, &sb);
28427000Sdonn 	cour_nap();
28527000Sdonn 	for ( ; n-- ; cp++) {
28627000Sdonn 		write(fd, cp, 1);
28727000Sdonn 		ioctl(fd, TIOCGETP, &sb);
28827000Sdonn 		ioctl(fd, TIOCSETP, &sb);
28927000Sdonn 		cour_nap();
29027000Sdonn 	}
29127000Sdonn }
29227000Sdonn 
293*30517Skarels #ifdef DEBUG
29427000Sdonn verbose_read()
29527000Sdonn {
29627000Sdonn 	int n = 0;
29727000Sdonn 	char buf[BUFSIZ];
298*30517Skarels 
29927000Sdonn 	if (ioctl(FD, FIONREAD, &n) < 0)
30027000Sdonn 		return;
30127000Sdonn 	if (n <= 0)
30227000Sdonn 		return;
30327000Sdonn 	if (read(FD, buf, n) != n)
30427000Sdonn 		return;
30527000Sdonn 	write(1, buf, n);
30627000Sdonn }
307*30517Skarels #endif
30827000Sdonn 
30927000Sdonn /*
31027000Sdonn  * Code stolen from /usr/src/lib/libc/gen/sleep.c
31127000Sdonn  */
31227000Sdonn #include <sys/time.h>
31327000Sdonn 
31427000Sdonn #define mask(s) (1<<((s)-1))
31527000Sdonn #define setvec(vec, a) \
31627000Sdonn         vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
31727000Sdonn 
31827000Sdonn static napms = 50; /* Give the courier 50 milliseconds between characters */
31927000Sdonn 
32027000Sdonn static int ringring;
32127000Sdonn 
32227000Sdonn cour_nap()
32327000Sdonn {
32427000Sdonn 
32527000Sdonn         static int cour_napx();
32627000Sdonn 	int omask;
32727000Sdonn         struct itimerval itv, oitv;
32827000Sdonn         register struct itimerval *itp = &itv;
32927000Sdonn         struct sigvec vec, ovec;
33027000Sdonn 
33127000Sdonn         timerclear(&itp->it_interval);
33227000Sdonn         timerclear(&itp->it_value);
33327000Sdonn         if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
33427000Sdonn                 return;
33527000Sdonn         setvec(ovec, SIG_DFL);
33627000Sdonn         omask = sigblock(mask(SIGALRM));
33727000Sdonn         itp->it_value.tv_sec = napms/1000;
33827000Sdonn 	itp->it_value.tv_usec = ((napms%1000)*1000);
33927000Sdonn         setvec(vec, cour_napx);
34027000Sdonn         ringring = 0;
34127000Sdonn         (void) sigvec(SIGALRM, &vec, &ovec);
34227000Sdonn         (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
34327000Sdonn         while (!ringring)
34427000Sdonn                 sigpause(omask &~ mask(SIGALRM));
34527000Sdonn         (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
34627000Sdonn         (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
34727000Sdonn 	(void) sigsetmask(omask);
34827000Sdonn }
34927000Sdonn 
35027000Sdonn static
35127000Sdonn cour_napx()
35227000Sdonn {
35327000Sdonn         ringring = 1;
35427000Sdonn }
355