1 /* $OpenBSD: courier.c,v 1.9 2001/10/24 18:38:58 millert Exp $ */ 2 /* $NetBSD: courier.c,v 1.7 1997/02/11 09:24:16 mrg Exp $ */ 3 4 /* 5 * Copyright (c) 1986, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93"; 43 static char rcsid[] = "$OpenBSD: courier.c,v 1.9 2001/10/24 18:38:58 millert Exp $"; 44 #endif 45 #endif /* not lint */ 46 47 /* 48 * Routines for calling up on a Courier modem. 49 * Derived from Hayes driver. 50 */ 51 #include "tip.h" 52 #include <sys/ioctl.h> 53 #include <stdio.h> 54 55 #define MAXRETRY 5 56 57 static void sigALRM(); 58 static int timeout = 0; 59 static int connected = 0; 60 static jmp_buf timeoutbuf, intbuf; 61 static int coursync(), cour_connect(), cour_swallow(); 62 void cour_nap(); 63 static void cour_write(int fd, char *cp, int n); 64 65 void cour_disconnect(void); 66 67 int 68 cour_dialer(num, acu) 69 char *num; 70 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 (timeout) { 115 (void)sprintf(line, "%ld second dial timeout", 116 number(value(DIALTIMEOUT))); 117 logent(value(HOST), num, "cour", line); 118 } 119 #endif 120 if (timeout) 121 cour_disconnect(); 122 return (connected); 123 } 124 125 void 126 cour_disconnect() 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() 138 { 139 cour_write(FD, "\r", 1); /* send anything to abort the call */ 140 cour_disconnect(); 141 } 142 143 static void 144 sigALRM() 145 { 146 printf("\07timeout waiting for reply\n"); 147 timeout = 1; 148 longjmp(timeoutbuf, 1); 149 } 150 151 static int 152 cour_swallow(match) 153 char *match; 154 { 155 sig_t f; 156 char c; 157 158 f = signal(SIGALRM, sigALRM); 159 timeout = 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() 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 timeout = 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() 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(fd, cp, n) 315 int fd; 316 char *cp; 317 int n; 318 { 319 #ifdef notdef 320 if (boolean(value(VERBOSE))) 321 write(1, cp, n); 322 #endif 323 tcdrain(fd); 324 cour_nap(); 325 for ( ; n-- ; cp++) { 326 write(fd, cp, 1); 327 tcdrain(fd); 328 cour_nap(); 329 } 330 } 331 332 #ifdef DEBUG 333 cour_verbose_read() 334 { 335 int n = 0; 336 char buf[BUFSIZ]; 337 338 if (ioctl(FD, FIONREAD, &n) < 0) 339 return; 340 if (n <= 0) 341 return; 342 if (read(FD, buf, n) != n) 343 return; 344 write(1, buf, n); 345 } 346 #endif 347 348 /* Give the courier 50 milliseconds between characters */ 349 void 350 cour_nap() 351 { 352 struct timespec ts; 353 354 ts.tv_sec = 0; 355 ts.tv_nsec = 50 * 1000000; 356 357 nanosleep(&ts, NULL); 358 } 359