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 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93"; 39 static const char rcsid[] = "$OpenBSD: courier.c,v 1.15 2006/03/17 19:17:13 moritz Exp $"; 40 #endif 41 #endif /* not lint */ 42 43 /* 44 * Routines for calling up on a Courier modem. 45 * Derived from Hayes driver. 46 */ 47 #include "tip.h" 48 #include <sys/ioctl.h> 49 #include <stdio.h> 50 51 #define MAXRETRY 5 52 53 static int dialtimeout = 0; 54 static int connected = 0; 55 static jmp_buf timeoutbuf; 56 57 static void sigALRM(int); 58 static int cour_swallow(char *); 59 static int cour_connect(void); 60 static int coursync(void); 61 static void cour_write(int, char *, int); 62 static void cour_nap(void); 63 #ifdef DEBUG 64 static void cour_verbose_read(void); 65 #endif 66 67 int 68 cour_dialer(char *num, char *acu) 69 { 70 char *cp; 71 #ifdef ACULOG 72 char line[80]; 73 #endif 74 struct termios cntrl; 75 76 if (boolean(value(VERBOSE))) 77 printf("Using \"%s\"\n", acu); 78 79 tcgetattr(FD, &cntrl); 80 cntrl.c_cflag |= HUPCL; 81 tcsetattr(FD, TCSAFLUSH, &cntrl); 82 /* 83 * Get in synch. 84 */ 85 if (!coursync()) { 86 badsynch: 87 printf("can't synchronize with courier\n"); 88 #ifdef ACULOG 89 logent(value(HOST), num, "courier", "can't synch up"); 90 #endif 91 return (0); 92 } 93 cour_write(FD, "AT E0\r", 6); /* turn off echoing */ 94 sleep(1); 95 #ifdef DEBUG 96 if (boolean(value(VERBOSE))) 97 cour_verbose_read(); 98 #endif 99 tcflush(FD, TCIOFLUSH); 100 cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); 101 if (!cour_swallow("\r\nOK\r\n")) 102 goto badsynch; 103 fflush(stdout); 104 cour_write(FD, "AT D", 4); 105 for (cp = num; *cp; cp++) 106 if (*cp == '=') 107 *cp = ','; 108 cour_write(FD, num, strlen(num)); 109 cour_write(FD, "\r", 1); 110 connected = cour_connect(); 111 #ifdef ACULOG 112 if (dialtimeout) { 113 (void)snprintf(line, sizeof line, "%ld second dial timeout", 114 number(value(DIALTIMEOUT))); 115 logent(value(HOST), num, "cour", line); 116 } 117 #endif 118 if (dialtimeout) 119 cour_disconnect(); 120 return (connected); 121 } 122 123 void 124 cour_disconnect(void) 125 { 126 /* first hang up the modem*/ 127 ioctl(FD, TIOCCDTR, 0); 128 sleep(1); 129 ioctl(FD, TIOCSDTR, 0); 130 coursync(); /* reset */ 131 close(FD); 132 } 133 134 void 135 cour_abort(void) 136 { 137 cour_write(FD, "\r", 1); /* send anything to abort the call */ 138 cour_disconnect(); 139 } 140 141 /*ARGSUSED*/ 142 static void 143 sigALRM(int signo) 144 { 145 printf("\07timeout waiting for reply\n"); 146 dialtimeout = 1; 147 longjmp(timeoutbuf, 1); 148 } 149 150 static int 151 cour_swallow(char *match) 152 { 153 sig_t f; 154 char c; 155 156 f = signal(SIGALRM, sigALRM); 157 dialtimeout = 0; 158 do { 159 if (*match =='\0') { 160 signal(SIGALRM, f); 161 return (1); 162 } 163 if (setjmp(timeoutbuf)) { 164 signal(SIGALRM, f); 165 return (0); 166 } 167 alarm(number(value(DIALTIMEOUT))); 168 read(FD, &c, 1); 169 alarm(0); 170 c &= 0177; 171 #ifdef DEBUG 172 if (boolean(value(VERBOSE))) 173 putchar(c); 174 #endif 175 } while (c == *match++); 176 #ifdef DEBUG 177 if (boolean(value(VERBOSE))) 178 fflush(stdout); 179 #endif 180 signal(SIGALRM, SIG_DFL); 181 return (0); 182 } 183 184 struct baud_msg { 185 char *msg; 186 int baud; 187 } baud_msg[] = { 188 { "", B300 }, 189 { " 1200", B1200 }, 190 { " 2400", B2400 }, 191 { " 9600", B9600 }, 192 { " 9600/ARQ", B9600 }, 193 { 0, 0 }, 194 }; 195 196 static int 197 cour_connect(void) 198 { 199 char c; 200 int nc, nl, n; 201 char dialer_buf[64]; 202 struct baud_msg *bm; 203 sig_t f; 204 205 if (cour_swallow("\r\n") == 0) 206 return (0); 207 f = signal(SIGALRM, sigALRM); 208 again: 209 nc = 0; nl = sizeof(dialer_buf)-1; 210 bzero(dialer_buf, sizeof(dialer_buf)); 211 dialtimeout = 0; 212 for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 213 if (setjmp(timeoutbuf)) 214 break; 215 alarm(number(value(DIALTIMEOUT))); 216 n = read(FD, &c, 1); 217 alarm(0); 218 if (n <= 0) 219 break; 220 c &= 0x7f; 221 if (c == '\r') { 222 if (cour_swallow("\n") == 0) 223 break; 224 if (!dialer_buf[0]) 225 goto again; 226 if (strcmp(dialer_buf, "RINGING") == 0 && 227 boolean(value(VERBOSE))) { 228 #ifdef DEBUG 229 printf("%s\r\n", dialer_buf); 230 #endif 231 goto again; 232 } 233 if (strncmp(dialer_buf, "CONNECT", 234 sizeof("CONNECT")-1) != 0) 235 break; 236 for (bm = baud_msg ; bm->msg ; bm++) 237 if (strcmp(bm->msg, 238 dialer_buf+sizeof("CONNECT")-1) == 0) { 239 struct termios cntrl; 240 241 tcgetattr(FD, &cntrl); 242 cfsetospeed(&cntrl, bm->baud); 243 cfsetispeed(&cntrl, bm->baud); 244 tcsetattr(FD, TCSAFLUSH, &cntrl); 245 signal(SIGALRM, f); 246 #ifdef DEBUG 247 if (boolean(value(VERBOSE))) 248 printf("%s\r\n", dialer_buf); 249 #endif 250 return (1); 251 } 252 break; 253 } 254 dialer_buf[nc] = c; 255 #ifdef notdef 256 if (boolean(value(VERBOSE))) 257 putchar(c); 258 #endif 259 } 260 printf("%s\r\n", dialer_buf); 261 signal(SIGALRM, f); 262 return (0); 263 } 264 265 /* 266 * This convoluted piece of code attempts to get 267 * the courier in sync. 268 */ 269 static int 270 coursync(void) 271 { 272 int already = 0; 273 int len; 274 char buf[40]; 275 276 while (already++ < MAXRETRY) { 277 tcflush(FD, TCIOFLUSH); 278 cour_write(FD, "\rAT Z\r", 6); /* reset modem */ 279 bzero(buf, sizeof(buf)); 280 sleep(1); 281 ioctl(FD, FIONREAD, &len); 282 if (len) { 283 len = read(FD, buf, sizeof(buf)); 284 #ifdef DEBUG 285 buf[len] = '\0'; 286 printf("coursync: (\"%s\")\n\r", buf); 287 #endif 288 if (strchr(buf, '0') || 289 (strchr(buf, 'O') && strchr(buf, 'K'))) 290 return(1); 291 } 292 /* 293 * If not strapped for DTR control, 294 * try to get command mode. 295 */ 296 sleep(1); 297 cour_write(FD, "+++", 3); 298 sleep(1); 299 /* 300 * Toggle DTR to force anyone off that might have left 301 * the modem connected. 302 */ 303 ioctl(FD, TIOCCDTR, 0); 304 sleep(1); 305 ioctl(FD, TIOCSDTR, 0); 306 } 307 cour_write(FD, "\rAT Z\r", 6); 308 return (0); 309 } 310 311 static void 312 cour_write(int fd, char *cp, int n) 313 { 314 #ifdef notdef 315 if (boolean(value(VERBOSE))) 316 write(1, cp, n); 317 #endif 318 tcdrain(fd); 319 cour_nap(); 320 for ( ; n-- ; cp++) { 321 write(fd, cp, 1); 322 tcdrain(fd); 323 cour_nap(); 324 } 325 } 326 327 #ifdef DEBUG 328 static void 329 cour_verbose_read(void) 330 { 331 int n = 0; 332 char buf[BUFSIZ]; 333 334 if (ioctl(FD, FIONREAD, &n) < 0) 335 return; 336 if (n <= 0) 337 return; 338 if (read(FD, buf, n) != n) 339 return; 340 write(1, buf, n); 341 } 342 #endif 343 344 /* Give the courier 50 milliseconds between characters */ 345 static void 346 cour_nap(void) 347 { 348 struct timespec ts; 349 350 ts.tv_sec = 0; 351 ts.tv_nsec = 50 * 1000000; 352 353 nanosleep(&ts, NULL); 354 } 355