1 /* $NetBSD: courier.c,v 1.13 2004/04/23 22:11:44 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.13 2004/04/23 22:11:44 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 __P((void)); 53 static void cour_nap __P((void)); 54 static void cour_napx __P((int)); 55 static int cour_swallow __P((const char *)); 56 static int coursync __P((void)); 57 #ifdef DEBUG 58 static void cour_verbose_read __P((void)); 59 #endif 60 static void cour_write __P((int, const char *, int)); 61 static void sigALRM __P((int)); 62 63 int 64 cour_dialer(num, acu) 65 char *num; 66 char *acu; 67 { 68 char *cp; 69 #ifdef ACULOG 70 char line[80]; 71 #endif 72 struct termios cntrl; 73 74 if (boolean(value(VERBOSE))) 75 printf("Using \"%s\"\n", acu); 76 77 tcgetattr(FD, &cntrl); 78 cntrl.c_cflag |= HUPCL; 79 tcsetattr(FD, TCSAFLUSH, &cntrl); 80 /* 81 * Get in synch. 82 */ 83 if (!coursync()) { 84 badsynch: 85 printf("can't synchronize with courier\n"); 86 #ifdef ACULOG 87 logent(value(HOST), num, "courier", "can't synch up"); 88 #endif 89 return (0); 90 } 91 cour_write(FD, "AT E0\r", 6); /* turn off echoing */ 92 sleep(1); 93 #ifdef DEBUG 94 if (boolean(value(VERBOSE))) 95 cour_verbose_read(); 96 #endif 97 tcflush(FD, TCIOFLUSH); 98 cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); 99 if (!cour_swallow("\r\nOK\r\n")) 100 goto badsynch; 101 fflush(stdout); 102 cour_write(FD, "AT D", 4); 103 for (cp = num; *cp; cp++) 104 if (*cp == '=') 105 *cp = ','; 106 cour_write(FD, num, strlen(num)); 107 cour_write(FD, "\r", 1); 108 connected = cour_connect(); 109 #ifdef ACULOG 110 if (timeout) { 111 (void)snprintf(line, sizeof line, "%d second dial timeout", 112 (int)number(value(DIALTIMEOUT))); 113 logent(value(HOST), num, "cour", line); 114 } 115 #endif 116 if (timeout) 117 cour_disconnect(); 118 return (connected); 119 } 120 121 void 122 cour_disconnect() 123 { 124 125 /* first hang up the modem*/ 126 ioctl(FD, TIOCCDTR, 0); 127 sleep(1); 128 ioctl(FD, TIOCSDTR, 0); 129 coursync(); /* reset */ 130 close(FD); 131 } 132 133 void 134 cour_abort() 135 { 136 137 cour_write(FD, "\r", 1); /* send anything to abort the call */ 138 cour_disconnect(); 139 } 140 141 static void 142 sigALRM(dummy) 143 int dummy; 144 { 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 const char *match; 154 { 155 sig_t f; 156 char c; 157 158 #if __GNUC__ /* XXX pacify gcc */ 159 (void)&match; 160 #endif 161 162 f = signal(SIGALRM, sigALRM); 163 timeout = 0; 164 do { 165 if (*match =='\0') { 166 signal(SIGALRM, f); 167 return (1); 168 } 169 if (setjmp(timeoutbuf)) { 170 signal(SIGALRM, f); 171 return (0); 172 } 173 alarm(number(value(DIALTIMEOUT))); 174 read(FD, &c, 1); 175 alarm(0); 176 c &= 0177; 177 #ifdef DEBUG 178 if (boolean(value(VERBOSE))) 179 putchar(c); 180 #endif 181 } while (c == *match++); 182 #ifdef DEBUG 183 if (boolean(value(VERBOSE))) 184 fflush(stdout); 185 #endif 186 signal(SIGALRM, SIG_DFL); 187 return (0); 188 } 189 190 struct baud_msg { 191 const char *msg; 192 int baud; 193 } baud_msg[] = { 194 { "", B300 }, 195 { " 1200", B1200 }, 196 { " 2400", B2400 }, 197 { " 9600", B9600 }, 198 { " 9600/ARQ", B9600 }, 199 { 0, 0 } 200 }; 201 202 static int 203 cour_connect() 204 { 205 char c; 206 int nc, nl, n; 207 char dialer_buf[64]; 208 struct baud_msg *bm; 209 sig_t f; 210 211 #if __GNUC__ /* XXX pacify gcc */ 212 (void)&nc; 213 (void)&nl; 214 #endif 215 216 if (cour_swallow("\r\n") == 0) 217 return (0); 218 f = signal(SIGALRM, sigALRM); 219 again: 220 memset(dialer_buf, 0, sizeof(dialer_buf)); 221 timeout = 0; 222 for (nc = 0, nl = sizeof(dialer_buf) - 1 ; nl > 0 ; nc++, nl--) { 223 if (setjmp(timeoutbuf)) 224 break; 225 alarm(number(value(DIALTIMEOUT))); 226 n = read(FD, &c, 1); 227 alarm(0); 228 if (n <= 0) 229 break; 230 c &= 0x7f; 231 if (c == '\r') { 232 if (cour_swallow("\n") == 0) 233 break; 234 if (!dialer_buf[0]) 235 goto again; 236 if (strcmp(dialer_buf, "RINGING") == 0 && 237 boolean(value(VERBOSE))) { 238 #ifdef DEBUG 239 printf("%s\r\n", dialer_buf); 240 #endif 241 goto again; 242 } 243 if (strncmp(dialer_buf, "CONNECT", 244 sizeof("CONNECT")-1) != 0) 245 break; 246 for (bm = baud_msg ; bm->msg ; bm++) 247 if (strcmp(bm->msg, 248 dialer_buf+sizeof("CONNECT")-1) == 0) { 249 struct termios cntrl; 250 251 tcgetattr(FD, &cntrl); 252 cfsetospeed(&cntrl, bm->baud); 253 cfsetispeed(&cntrl, bm->baud); 254 tcsetattr(FD, TCSAFLUSH, &cntrl); 255 signal(SIGALRM, f); 256 #ifdef DEBUG 257 if (boolean(value(VERBOSE))) 258 printf("%s\r\n", dialer_buf); 259 #endif 260 return (1); 261 } 262 break; 263 } 264 dialer_buf[nc] = c; 265 #ifdef notdef 266 if (boolean(value(VERBOSE))) 267 putchar(c); 268 #endif 269 } 270 printf("%s\r\n", dialer_buf); 271 signal(SIGALRM, f); 272 return (0); 273 } 274 275 /* 276 * This convoluted piece of code attempts to get 277 * the courier in sync. 278 */ 279 static int 280 coursync() 281 { 282 int already = 0; 283 int len; 284 char buf[40]; 285 286 while (already++ < MAXRETRY) { 287 tcflush(FD, TCIOFLUSH); 288 cour_write(FD, "\rAT Z\r", 6); /* reset modem */ 289 memset(buf, 0, sizeof(buf)); 290 sleep(1); 291 ioctl(FD, FIONREAD, &len); 292 if (len) { 293 len = read(FD, buf, sizeof(buf)); 294 #ifdef DEBUG 295 buf[len] = '\0'; 296 printf("coursync: (\"%s\")\n\r", buf); 297 #endif 298 if (strchr(buf, '0') || 299 (strchr(buf, 'O') && strchr(buf, 'K'))) 300 return(1); 301 } 302 /* 303 * If not strapped for DTR control, 304 * try to get command mode. 305 */ 306 sleep(1); 307 cour_write(FD, "+++", 3); 308 sleep(1); 309 /* 310 * Toggle DTR to force anyone off that might have left 311 * the modem connected. 312 */ 313 ioctl(FD, TIOCCDTR, 0); 314 sleep(1); 315 ioctl(FD, TIOCSDTR, 0); 316 } 317 cour_write(FD, "\rAT Z\r", 6); 318 return (0); 319 } 320 321 static void 322 cour_write(fd, cp, n) 323 int fd; 324 const char *cp; 325 int n; 326 { 327 328 #ifdef notdef 329 if (boolean(value(VERBOSE))) 330 write(1, cp, n); 331 #endif 332 tcdrain(fd); 333 cour_nap(); 334 for ( ; n-- ; cp++) { 335 write(fd, cp, 1); 336 tcdrain(fd); 337 cour_nap(); 338 } 339 } 340 341 #ifdef DEBUG 342 static void 343 cour_verbose_read() 344 { 345 int n = 0; 346 char buf[BUFSIZ]; 347 348 if (ioctl(FD, FIONREAD, &n) < 0) 349 return; 350 if (n <= 0) 351 return; 352 if (read(FD, buf, n) != n) 353 return; 354 write(1, buf, n); 355 } 356 #endif 357 358 #define setsa(sa, a) \ 359 sa.sa_handler = a; sigemptyset(&sa.sa_mask); sa.sa_flags = 0 360 361 static int napms = 50; /* Give the courier 50 milliseconds between characters */ 362 363 static int ringring; 364 365 void 366 cour_nap() 367 { 368 369 struct itimerval itv, oitv; 370 struct itimerval *itp = &itv; 371 struct sigaction sa, osa; 372 sigset_t sm, osm; 373 374 timerclear(&itp->it_interval); 375 timerclear(&itp->it_value); 376 if (setitimer(ITIMER_REAL, itp, &oitv) < 0) 377 return; 378 379 sigemptyset(&sm); 380 sigaddset(&sm, SIGALRM); 381 (void)sigprocmask(SIG_BLOCK, &sm, &osm); 382 383 itp->it_value.tv_sec = napms/1000; 384 itp->it_value.tv_usec = ((napms%1000)*1000); 385 386 setsa(sa, cour_napx); 387 (void)sigaction(SIGALRM, &sa, &osa); 388 389 (void)setitimer(ITIMER_REAL, itp, NULL); 390 391 sm = osm; 392 sigdelset(&sm, SIGALRM); 393 394 for (ringring = 0; !ringring; ) 395 sigsuspend(&sm); 396 397 (void)sigaction(SIGALRM, &osa, NULL); 398 (void)setitimer(ITIMER_REAL, &oitv, NULL); 399 (void)sigprocmask(SIG_SETMASK, &osm, NULL); 400 } 401 402 static void 403 cour_napx(dummy) 404 int dummy; 405 { 406 407 ringring = 1; 408 } 409