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