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