1161754Sru/* $OpenBSD: courier.c,v 1.15 2006/03/17 19:17:13 moritz Exp $ */ 288276Smarkm/* $NetBSD: courier.c,v 1.7 1997/02/11 09:24:16 mrg Exp $ */ 388276Smarkm 47527Sjkh/* 57527Sjkh * Copyright (c) 1986, 1993 67527Sjkh * The Regents of the University of California. All rights reserved. 77527Sjkh * 87527Sjkh * Redistribution and use in source and binary forms, with or without 97527Sjkh * modification, are permitted provided that the following conditions 107527Sjkh * are met: 117527Sjkh * 1. Redistributions of source code must retain the above copyright 127527Sjkh * notice, this list of conditions and the following disclaimer. 137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright 147527Sjkh * notice, this list of conditions and the following disclaimer in the 157527Sjkh * documentation and/or other materials provided with the distribution. 16161754Sru * 3. Neither the name of the University nor the names of its contributors 177527Sjkh * may be used to endorse or promote products derived from this software 187527Sjkh * without specific prior written permission. 197527Sjkh * 207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 237527Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 307527Sjkh * SUCH DAMAGE. 317527Sjkh */ 327527Sjkh 3388276Smarkm#include <sys/cdefs.h> 3488276Smarkm__FBSDID("$FreeBSD$"); 3588276Smarkm 367527Sjkh#ifndef lint 3788276Smarkm#if 0 3888276Smarkmstatic char sccsid[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93"; 39161754Srustatic const char rcsid[] = "$OpenBSD: courier.c,v 1.15 2006/03/17 19:17:13 moritz Exp $"; 4080381Ssheldonh#endif 4188276Smarkm#endif /* not lint */ 427527Sjkh 437527Sjkh/* 447527Sjkh * Routines for calling up on a Courier modem. 457527Sjkh * Derived from Hayes driver. 467527Sjkh */ 477527Sjkh#include "tip.h" 4888276Smarkm#include <sys/ioctl.h> 497527Sjkh#include <stdio.h> 507527Sjkh 517527Sjkh#define MAXRETRY 5 527527Sjkh 53161754Srustatic int dialtimeout = 0; 547527Sjkhstatic int connected = 0; 55161754Srustatic jmp_buf timeoutbuf; 567527Sjkh 57161754Srustatic void sigALRM(int); 58161754Srustatic int cour_swallow(char *); 59161754Srustatic int cour_connect(void); 60161754Srustatic int coursync(void); 61161754Srustatic void cour_write(int, char *, int); 62161754Srustatic void cour_nap(void); 63161754Sru#ifdef DEBUG 64161754Srustatic void cour_verbose_read(void); 65161754Sru#endif 6688276Smarkm 6788276Smarkmint 68161754Srucour_dialer(char *num, char *acu) 697527Sjkh{ 7088276Smarkm char *cp; 7188276Smarkm#ifdef ACULOG 727527Sjkh char line[80]; 737527Sjkh#endif 7488276Smarkm struct termios cntrl; 757527Sjkh 767527Sjkh if (boolean(value(VERBOSE))) 777527Sjkh printf("Using \"%s\"\n", acu); 787527Sjkh 7988276Smarkm tcgetattr(FD, &cntrl); 8088276Smarkm cntrl.c_cflag |= HUPCL; 8188276Smarkm tcsetattr(FD, TCSAFLUSH, &cntrl); 827527Sjkh /* 837527Sjkh * Get in synch. 847527Sjkh */ 857527Sjkh if (!coursync()) { 867527Sjkhbadsynch: 877527Sjkh printf("can't synchronize with courier\n"); 8888276Smarkm#ifdef ACULOG 897527Sjkh logent(value(HOST), num, "courier", "can't synch up"); 907527Sjkh#endif 917527Sjkh return (0); 927527Sjkh } 937527Sjkh cour_write(FD, "AT E0\r", 6); /* turn off echoing */ 947527Sjkh sleep(1); 957527Sjkh#ifdef DEBUG 967527Sjkh if (boolean(value(VERBOSE))) 977527Sjkh cour_verbose_read(); 987527Sjkh#endif 9988276Smarkm tcflush(FD, TCIOFLUSH); 1007527Sjkh cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); 1017527Sjkh if (!cour_swallow("\r\nOK\r\n")) 1027527Sjkh goto badsynch; 1037527Sjkh fflush(stdout); 1047527Sjkh cour_write(FD, "AT D", 4); 1057527Sjkh for (cp = num; *cp; cp++) 1067527Sjkh if (*cp == '=') 1077527Sjkh *cp = ','; 1087527Sjkh cour_write(FD, num, strlen(num)); 1097527Sjkh cour_write(FD, "\r", 1); 1107527Sjkh connected = cour_connect(); 11188276Smarkm#ifdef ACULOG 112161754Sru if (dialtimeout) { 113161754Sru (void)snprintf(line, sizeof line, "%ld second dial timeout", 1147527Sjkh number(value(DIALTIMEOUT))); 1157527Sjkh logent(value(HOST), num, "cour", line); 1167527Sjkh } 1177527Sjkh#endif 118161754Sru if (dialtimeout) 1197527Sjkh cour_disconnect(); 1207527Sjkh return (connected); 1217527Sjkh} 1227527Sjkh 12388276Smarkmvoid 124161754Srucour_disconnect(void) 1257527Sjkh{ 1267527Sjkh /* first hang up the modem*/ 1277527Sjkh ioctl(FD, TIOCCDTR, 0); 1287527Sjkh sleep(1); 1297527Sjkh ioctl(FD, TIOCSDTR, 0); 1307527Sjkh coursync(); /* reset */ 1317527Sjkh close(FD); 1327527Sjkh} 1337527Sjkh 13488276Smarkmvoid 135161754Srucour_abort(void) 1367527Sjkh{ 1377527Sjkh cour_write(FD, "\r", 1); /* send anything to abort the call */ 1387527Sjkh cour_disconnect(); 1397527Sjkh} 1407527Sjkh 141161754Sru/*ARGSUSED*/ 1427527Sjkhstatic void 143161754SrusigALRM(int signo) 1447527Sjkh{ 1457527Sjkh printf("\07timeout waiting for reply\n"); 146161754Sru dialtimeout = 1; 1477527Sjkh longjmp(timeoutbuf, 1); 1487527Sjkh} 1497527Sjkh 1507527Sjkhstatic int 151161754Srucour_swallow(char *match) 15288276Smarkm{ 1537527Sjkh sig_t f; 1547527Sjkh char c; 1557527Sjkh 1567527Sjkh f = signal(SIGALRM, sigALRM); 157161754Sru dialtimeout = 0; 1587527Sjkh do { 1597527Sjkh if (*match =='\0') { 1607527Sjkh signal(SIGALRM, f); 1617527Sjkh return (1); 1627527Sjkh } 1637527Sjkh if (setjmp(timeoutbuf)) { 1647527Sjkh signal(SIGALRM, f); 1657527Sjkh return (0); 1667527Sjkh } 1677527Sjkh alarm(number(value(DIALTIMEOUT))); 1687527Sjkh read(FD, &c, 1); 1697527Sjkh alarm(0); 1707527Sjkh c &= 0177; 1717527Sjkh#ifdef DEBUG 1727527Sjkh if (boolean(value(VERBOSE))) 1737527Sjkh putchar(c); 1747527Sjkh#endif 1757527Sjkh } while (c == *match++); 1767527Sjkh#ifdef DEBUG 1777527Sjkh if (boolean(value(VERBOSE))) 1787527Sjkh fflush(stdout); 1797527Sjkh#endif 1807527Sjkh signal(SIGALRM, SIG_DFL); 1817527Sjkh return (0); 1827527Sjkh} 1837527Sjkh 1847527Sjkhstruct baud_msg { 1857527Sjkh char *msg; 1867527Sjkh int baud; 1877527Sjkh} baud_msg[] = { 188161754Sru { "", B300 }, 189161754Sru { " 1200", B1200 }, 190161754Sru { " 2400", B2400 }, 191161754Sru { " 9600", B9600 }, 192161754Sru { " 9600/ARQ", B9600 }, 193161754Sru { 0, 0 }, 1947527Sjkh}; 1957527Sjkh 1967527Sjkhstatic int 197161754Srucour_connect(void) 1987527Sjkh{ 1997527Sjkh char c; 2007527Sjkh int nc, nl, n; 2017527Sjkh char dialer_buf[64]; 2027527Sjkh struct baud_msg *bm; 2037527Sjkh sig_t f; 2047527Sjkh 2057527Sjkh if (cour_swallow("\r\n") == 0) 2067527Sjkh return (0); 2077527Sjkh f = signal(SIGALRM, sigALRM); 2087527Sjkhagain: 2097527Sjkh nc = 0; nl = sizeof(dialer_buf)-1; 2107527Sjkh bzero(dialer_buf, sizeof(dialer_buf)); 211161754Sru dialtimeout = 0; 2127527Sjkh for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 2137527Sjkh if (setjmp(timeoutbuf)) 2147527Sjkh break; 2157527Sjkh alarm(number(value(DIALTIMEOUT))); 2167527Sjkh n = read(FD, &c, 1); 2177527Sjkh alarm(0); 2187527Sjkh if (n <= 0) 2197527Sjkh break; 2207527Sjkh c &= 0x7f; 2217527Sjkh if (c == '\r') { 2227527Sjkh if (cour_swallow("\n") == 0) 2237527Sjkh break; 2247527Sjkh if (!dialer_buf[0]) 2257527Sjkh goto again; 2267527Sjkh if (strcmp(dialer_buf, "RINGING") == 0 && 2277527Sjkh boolean(value(VERBOSE))) { 2287527Sjkh#ifdef DEBUG 2297527Sjkh printf("%s\r\n", dialer_buf); 2307527Sjkh#endif 2317527Sjkh goto again; 2327527Sjkh } 2337527Sjkh if (strncmp(dialer_buf, "CONNECT", 2347527Sjkh sizeof("CONNECT")-1) != 0) 2357527Sjkh break; 2367527Sjkh for (bm = baud_msg ; bm->msg ; bm++) 2377527Sjkh if (strcmp(bm->msg, 2387527Sjkh dialer_buf+sizeof("CONNECT")-1) == 0) { 23988276Smarkm struct termios cntrl; 24088276Smarkm 24188276Smarkm tcgetattr(FD, &cntrl); 24288276Smarkm cfsetospeed(&cntrl, bm->baud); 24388276Smarkm cfsetispeed(&cntrl, bm->baud); 24488276Smarkm tcsetattr(FD, TCSAFLUSH, &cntrl); 2457527Sjkh signal(SIGALRM, f); 2467527Sjkh#ifdef DEBUG 2477527Sjkh if (boolean(value(VERBOSE))) 2487527Sjkh printf("%s\r\n", dialer_buf); 2497527Sjkh#endif 2507527Sjkh return (1); 2517527Sjkh } 2527527Sjkh break; 2537527Sjkh } 2547527Sjkh dialer_buf[nc] = c; 2557527Sjkh#ifdef notdef 2567527Sjkh if (boolean(value(VERBOSE))) 2577527Sjkh putchar(c); 2587527Sjkh#endif 2597527Sjkh } 2607527Sjkh printf("%s\r\n", dialer_buf); 2617527Sjkh signal(SIGALRM, f); 2627527Sjkh return (0); 2637527Sjkh} 2647527Sjkh 2657527Sjkh/* 2667527Sjkh * This convoluted piece of code attempts to get 2677527Sjkh * the courier in sync. 2687527Sjkh */ 2697527Sjkhstatic int 270161754Srucoursync(void) 2717527Sjkh{ 2727527Sjkh int already = 0; 2737527Sjkh int len; 2747527Sjkh char buf[40]; 2757527Sjkh 2767527Sjkh while (already++ < MAXRETRY) { 27788276Smarkm tcflush(FD, TCIOFLUSH); 2787527Sjkh cour_write(FD, "\rAT Z\r", 6); /* reset modem */ 2797527Sjkh bzero(buf, sizeof(buf)); 2807527Sjkh sleep(1); 2817527Sjkh ioctl(FD, FIONREAD, &len); 2827527Sjkh if (len) { 2837527Sjkh len = read(FD, buf, sizeof(buf)); 2847527Sjkh#ifdef DEBUG 2857527Sjkh buf[len] = '\0'; 2867527Sjkh printf("coursync: (\"%s\")\n\r", buf); 2877527Sjkh#endif 28888276Smarkm if (strchr(buf, '0') || 28988276Smarkm (strchr(buf, 'O') && strchr(buf, 'K'))) 2907527Sjkh return(1); 2917527Sjkh } 2927527Sjkh /* 2937527Sjkh * If not strapped for DTR control, 2947527Sjkh * try to get command mode. 2957527Sjkh */ 2967527Sjkh sleep(1); 2977527Sjkh cour_write(FD, "+++", 3); 2987527Sjkh sleep(1); 2997527Sjkh /* 3007527Sjkh * Toggle DTR to force anyone off that might have left 3017527Sjkh * the modem connected. 3027527Sjkh */ 3037527Sjkh ioctl(FD, TIOCCDTR, 0); 3047527Sjkh sleep(1); 3057527Sjkh ioctl(FD, TIOCSDTR, 0); 3067527Sjkh } 3077527Sjkh cour_write(FD, "\rAT Z\r", 6); 3087527Sjkh return (0); 3097527Sjkh} 3107527Sjkh 31188276Smarkmstatic void 312161754Srucour_write(int fd, char *cp, int n) 3137527Sjkh{ 3147527Sjkh#ifdef notdef 3157527Sjkh if (boolean(value(VERBOSE))) 31688276Smarkm write(1, cp, n); 3177527Sjkh#endif 31888276Smarkm tcdrain(fd); 3197527Sjkh cour_nap(); 3207527Sjkh for ( ; n-- ; cp++) { 3217527Sjkh write(fd, cp, 1); 32288276Smarkm tcdrain(fd); 3237527Sjkh cour_nap(); 3247527Sjkh } 3257527Sjkh} 3267527Sjkh 3277527Sjkh#ifdef DEBUG 328161754Srustatic void 329161754Srucour_verbose_read(void) 3307527Sjkh{ 3317527Sjkh int n = 0; 3327527Sjkh char buf[BUFSIZ]; 3337527Sjkh 3347527Sjkh if (ioctl(FD, FIONREAD, &n) < 0) 3357527Sjkh return; 3367527Sjkh if (n <= 0) 3377527Sjkh return; 3387527Sjkh if (read(FD, buf, n) != n) 3397527Sjkh return; 34088276Smarkm write(1, buf, n); 3417527Sjkh} 3427527Sjkh#endif 3437527Sjkh 34488276Smarkm/* Give the courier 50 milliseconds between characters */ 345161754Srustatic void 346161754Srucour_nap(void) 3477527Sjkh{ 34888276Smarkm struct timespec ts; 34988276Smarkm 35088276Smarkm ts.tv_sec = 0; 35188276Smarkm ts.tv_nsec = 50 * 1000000; 35288276Smarkm 35388276Smarkm nanosleep(&ts, NULL); 3547527Sjkh} 355