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