xref: /original-bsd/usr.bin/tip/aculib/courier.c (revision 183db9ee)
1 /*
2  * Copyright (c) 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)courier.c	5.3 (Berkeley) 09/13/88";
20 #endif /* not lint */
21 
22 #define write cour_write
23 /*
24  * Routines for calling up on a Courier modem.
25  * Derived from Hayes driver.
26  */
27 #include "tip.h"
28 #include <stdio.h>
29 
30 #define	MAXRETRY	5
31 
32 static	int sigALRM();
33 static	int timeout = 0;
34 static	int connected = 0;
35 static	jmp_buf timeoutbuf, intbuf;
36 static	int (*osigint)();
37 
38 cour_dialer(num, acu)
39 	register char *num;
40 	char *acu;
41 {
42 	register char *cp;
43 #ifdef ACULOG
44 	char line[80];
45 #endif
46 	if (boolean(value(VERBOSE)))
47 		printf("Using \"%s\"\n", acu);
48 
49 	ioctl(FD, TIOCHPCL, 0);
50 	/*
51 	 * Get in synch.
52 	 */
53 	if (!coursync()) {
54 badsynch:
55 		printf("can't synchronize with courier\n");
56 #ifdef ACULOG
57 		logent(value(HOST), num, "courier", "can't synch up");
58 #endif
59 		return (0);
60 	}
61 	write(FD, "AT E0\r", 6);	/* turn off echoing */
62 	sleep(1);
63 #ifdef DEBUG
64 	if (boolean(value(VERBOSE)))
65 		verbose_read();
66 #endif
67 	ioctl(FD, TIOCFLUSH, 0);	/* flush any clutter */
68 	write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
69 	if (!cour_swallow("\r\nOK\r\n"))
70 		goto badsynch;
71 	fflush(stdout);
72 	write(FD, "AT D", 4);
73 	for (cp = num; *cp; cp++)
74 		if (*cp == '=')
75 			*cp = ',';
76 	write(FD, num, strlen(num));
77 	write(FD, "\r", 1);
78 	connected = cour_connect();
79 #ifdef ACULOG
80 	if (timeout) {
81 		sprintf(line, "%d second dial timeout",
82 			number(value(DIALTIMEOUT)));
83 		logent(value(HOST), num, "cour", line);
84 	}
85 #endif
86 	if (timeout)
87 		cour_disconnect();
88 	return (connected);
89 }
90 
91 cour_disconnect()
92 {
93 	 /* first hang up the modem*/
94 	ioctl(FD, TIOCCDTR, 0);
95 	sleep(1);
96 	ioctl(FD, TIOCSDTR, 0);
97 	coursync();				/* reset */
98 	close(FD);
99 }
100 
101 cour_abort()
102 {
103 	write(FD, "\r", 1);	/* send anything to abort the call */
104 	cour_disconnect();
105 }
106 
107 static int
108 sigALRM()
109 {
110 	printf("\07timeout waiting for reply\n");
111 	timeout = 1;
112 	longjmp(timeoutbuf, 1);
113 }
114 
115 static int
116 cour_swallow(match)
117   register char *match;
118   {
119 	char c;
120 	int (*f)();
121 
122 	f = signal(SIGALRM, sigALRM);
123 	timeout = 0;
124 	do {
125 		if (*match =='\0') {
126 			signal(SIGALRM, f);
127 			return (1);
128 		}
129 		if (setjmp(timeoutbuf)) {
130 			signal(SIGALRM, f);
131 			return (0);
132 		}
133 		alarm(number(value(DIALTIMEOUT)));
134 		read(FD, &c, 1);
135 		alarm(0);
136 		c &= 0177;
137 #ifdef DEBUG
138 		if (boolean(value(VERBOSE)))
139 			putchar(c);
140 #endif
141 	} while (c == *match++);
142 #ifdef DEBUG
143 	if (boolean(value(VERBOSE)))
144 		fflush(stdout);
145 #endif
146 	signal(SIGALRM, SIG_DFL);
147 	return (0);
148 }
149 
150 struct baud_msg {
151 	char *msg;
152 	int baud;
153 } baud_msg[] = {
154 	"",		B300,
155 	" 1200",	B1200,
156 	" 2400",	B2400,
157 	0,		0,
158 };
159 
160 static int
161 cour_connect()
162 {
163 	char c;
164 	int nc, nl, n;
165 	struct sgttyb sb;
166 	char dialer_buf[64];
167 	struct baud_msg *bm;
168 	int (*f)();
169 
170 	if (cour_swallow("\r\n") == 0)
171 		return (0);
172 	f = signal(SIGALRM, sigALRM);
173 again:
174 	nc = 0; nl = sizeof(dialer_buf)-1;
175 	bzero(dialer_buf, sizeof(dialer_buf));
176 	timeout = 0;
177 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
178 		if (setjmp(timeoutbuf))
179 			break;
180 		alarm(number(value(DIALTIMEOUT)));
181 		n = read(FD, &c, 1);
182 		alarm(0);
183 		if (n <= 0)
184 			break;
185 		c &= 0x7f;
186 		if (c == '\r') {
187 			if (cour_swallow("\n") == 0)
188 				break;
189 			if (!dialer_buf[0])
190 				goto again;
191 			if (strcmp(dialer_buf, "RINGING") == 0 &&
192 			    boolean(value(VERBOSE))) {
193 #ifdef DEBUG
194 				printf("%s\r\n", dialer_buf);
195 #endif
196 				goto again;
197 			}
198 			if (strncmp(dialer_buf, "CONNECT",
199 				    sizeof("CONNECT")-1) != 0)
200 				break;
201 			for (bm = baud_msg ; bm ; bm++)
202 				if (strcmp(bm->msg,
203 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
204 					if (ioctl(FD, TIOCGETP, &sb) < 0) {
205 						perror("TIOCGETP");
206 						goto error;
207 					}
208 					sb.sg_ispeed = sb.sg_ospeed = bm->baud;
209 					if (ioctl(FD, TIOCSETP, &sb) < 0) {
210 						perror("TIOCSETP");
211 						goto error;
212 					}
213 					signal(SIGALRM, f);
214 #ifdef DEBUG
215 					if (boolean(value(VERBOSE)))
216 						printf("%s\r\n", dialer_buf);
217 #endif
218 					return (1);
219 				}
220 			break;
221 		}
222 		dialer_buf[nc] = c;
223 #ifdef notdef
224 		if (boolean(value(VERBOSE)))
225 			putchar(c);
226 #endif
227 	}
228 error1:
229 	printf("%s\r\n", dialer_buf);
230 error:
231 	signal(SIGALRM, f);
232 	return (0);
233 }
234 
235 /*
236  * This convoluted piece of code attempts to get
237  * the courier in sync.
238  */
239 static int
240 coursync()
241 {
242 	int already = 0;
243 	int len;
244 	char buf[40];
245 
246 	while (already++ < MAXRETRY) {
247 		ioctl(FD, TIOCFLUSH, 0);	/* flush any clutter */
248 		write(FD, "\rAT Z\r", 6);	/* reset modem */
249 		bzero(buf, sizeof(buf));
250 		sleep(1);
251 		ioctl(FD, FIONREAD, &len);
252 		if (len) {
253 			len = read(FD, buf, sizeof(buf));
254 #ifdef DEBUG
255 			buf[len] = '\0';
256 			printf("coursync: (\"%s\")\n\r", buf);
257 #endif
258 			if (index(buf, '0') ||
259 		   	   (index(buf, 'O') && index(buf, 'K')))
260 				return(1);
261 		}
262 		/*
263 		 * If not strapped for DTR control,
264 		 * try to get command mode.
265 		 */
266 		sleep(1);
267 		write(FD, "+++", 3);
268 		sleep(1);
269 		/*
270 		 * Toggle DTR to force anyone off that might have left
271 		 * the modem connected.
272 		 */
273 		ioctl(FD, TIOCCDTR, 0);
274 		sleep(1);
275 		ioctl(FD, TIOCSDTR, 0);
276 	}
277 	write(FD, "\rAT Z\r", 6);
278 	return (0);
279 }
280 
281 #undef write
282 
283 cour_write(fd, cp, n)
284 int fd;
285 char *cp;
286 int n;
287 {
288 	struct sgttyb sb;
289 #ifdef notdef
290 	if (boolean(value(VERBOSE)))
291 		write(1, cp, n);
292 #endif
293 	ioctl(fd, TIOCGETP, &sb);
294 	ioctl(fd, TIOCSETP, &sb);
295 	cour_nap();
296 	for ( ; n-- ; cp++) {
297 		write(fd, cp, 1);
298 		ioctl(fd, TIOCGETP, &sb);
299 		ioctl(fd, TIOCSETP, &sb);
300 		cour_nap();
301 	}
302 }
303 
304 #ifdef DEBUG
305 verbose_read()
306 {
307 	int n = 0;
308 	char buf[BUFSIZ];
309 
310 	if (ioctl(FD, FIONREAD, &n) < 0)
311 		return;
312 	if (n <= 0)
313 		return;
314 	if (read(FD, buf, n) != n)
315 		return;
316 	write(1, buf, n);
317 }
318 #endif
319 
320 /*
321  * Code stolen from /usr/src/lib/libc/gen/sleep.c
322  */
323 #include <sys/time.h>
324 
325 #define mask(s) (1<<((s)-1))
326 #define setvec(vec, a) \
327         vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
328 
329 static napms = 50; /* Give the courier 50 milliseconds between characters */
330 
331 static int ringring;
332 
333 cour_nap()
334 {
335 
336         static int cour_napx();
337 	int omask;
338         struct itimerval itv, oitv;
339         register struct itimerval *itp = &itv;
340         struct sigvec vec, ovec;
341 
342         timerclear(&itp->it_interval);
343         timerclear(&itp->it_value);
344         if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
345                 return;
346         setvec(ovec, SIG_DFL);
347         omask = sigblock(mask(SIGALRM));
348         itp->it_value.tv_sec = napms/1000;
349 	itp->it_value.tv_usec = ((napms%1000)*1000);
350         setvec(vec, cour_napx);
351         ringring = 0;
352         (void) sigvec(SIGALRM, &vec, &ovec);
353         (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
354         while (!ringring)
355                 sigpause(omask &~ mask(SIGALRM));
356         (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
357         (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
358 	(void) sigsetmask(omask);
359 }
360 
361 static
362 cour_napx()
363 {
364         ringring = 1;
365 }
366