1 /* $NetBSD: courier.c,v 1.11 1998/12/19 23:02:02 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93"; 40 #endif 41 __RCSID("$NetBSD: courier.c,v 1.11 1998/12/19 23:02:02 christos Exp $"); 42 #endif /* not lint */ 43 44 /* 45 * Routines for calling up on a Courier modem. 46 * Derived from Hayes driver. 47 */ 48 #include "tip.h" 49 50 #define MAXRETRY 5 51 52 static int timeout = 0; 53 static int connected = 0; 54 static jmp_buf timeoutbuf; 55 56 static int cour_connect __P((void)); 57 static void cour_nap __P((void)); 58 static void cour_napx __P((int)); 59 static int cour_swallow __P((char *)); 60 static int coursync __P((void)); 61 #ifdef DEBUG 62 static void cour_verbose_read __P((void)); 63 #endif 64 static void cour_write __P((int, char *, int)); 65 static void sigALRM __P((int)); 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)snprintf(line, sizeof line, "%d second dial timeout", 116 (int)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 129 /* first hang up the modem*/ 130 ioctl(FD, TIOCCDTR, 0); 131 sleep(1); 132 ioctl(FD, TIOCSDTR, 0); 133 coursync(); /* reset */ 134 close(FD); 135 } 136 137 void 138 cour_abort() 139 { 140 141 cour_write(FD, "\r", 1); /* send anything to abort the call */ 142 cour_disconnect(); 143 } 144 145 static void 146 sigALRM(dummy) 147 int dummy; 148 { 149 150 printf("\07timeout waiting for reply\n"); 151 timeout = 1; 152 longjmp(timeoutbuf, 1); 153 } 154 155 static int 156 cour_swallow(match) 157 char *match; 158 { 159 sig_t f; 160 char c; 161 162 #if __GNUC__ /* XXX pacify gcc */ 163 (void)&match; 164 #endif 165 166 f = signal(SIGALRM, sigALRM); 167 timeout = 0; 168 do { 169 if (*match =='\0') { 170 signal(SIGALRM, f); 171 return (1); 172 } 173 if (setjmp(timeoutbuf)) { 174 signal(SIGALRM, f); 175 return (0); 176 } 177 alarm(number(value(DIALTIMEOUT))); 178 read(FD, &c, 1); 179 alarm(0); 180 c &= 0177; 181 #ifdef DEBUG 182 if (boolean(value(VERBOSE))) 183 putchar(c); 184 #endif 185 } while (c == *match++); 186 #ifdef DEBUG 187 if (boolean(value(VERBOSE))) 188 fflush(stdout); 189 #endif 190 signal(SIGALRM, SIG_DFL); 191 return (0); 192 } 193 194 struct baud_msg { 195 char *msg; 196 int baud; 197 } baud_msg[] = { 198 { "", B300 }, 199 { " 1200", B1200 }, 200 { " 2400", B2400 }, 201 { " 9600", B9600 }, 202 { " 9600/ARQ", B9600 }, 203 { 0, 0 } 204 }; 205 206 static int 207 cour_connect() 208 { 209 char c; 210 int nc, nl, n; 211 char dialer_buf[64]; 212 struct baud_msg *bm; 213 sig_t f; 214 215 #if __GNUC__ /* XXX pacify gcc */ 216 (void)&nc; 217 (void)&nl; 218 #endif 219 220 if (cour_swallow("\r\n") == 0) 221 return (0); 222 f = signal(SIGALRM, sigALRM); 223 again: 224 memset(dialer_buf, 0, sizeof(dialer_buf)); 225 timeout = 0; 226 for (nc = 0, nl = sizeof(dialer_buf) - 1 ; nl > 0 ; nc++, nl--) { 227 if (setjmp(timeoutbuf)) 228 break; 229 alarm(number(value(DIALTIMEOUT))); 230 n = read(FD, &c, 1); 231 alarm(0); 232 if (n <= 0) 233 break; 234 c &= 0x7f; 235 if (c == '\r') { 236 if (cour_swallow("\n") == 0) 237 break; 238 if (!dialer_buf[0]) 239 goto again; 240 if (strcmp(dialer_buf, "RINGING") == 0 && 241 boolean(value(VERBOSE))) { 242 #ifdef DEBUG 243 printf("%s\r\n", dialer_buf); 244 #endif 245 goto again; 246 } 247 if (strncmp(dialer_buf, "CONNECT", 248 sizeof("CONNECT")-1) != 0) 249 break; 250 for (bm = baud_msg ; bm->msg ; bm++) 251 if (strcmp(bm->msg, 252 dialer_buf+sizeof("CONNECT")-1) == 0) { 253 struct termios cntrl; 254 255 tcgetattr(FD, &cntrl); 256 cfsetospeed(&cntrl, bm->baud); 257 cfsetispeed(&cntrl, bm->baud); 258 tcsetattr(FD, TCSAFLUSH, &cntrl); 259 signal(SIGALRM, f); 260 #ifdef DEBUG 261 if (boolean(value(VERBOSE))) 262 printf("%s\r\n", dialer_buf); 263 #endif 264 return (1); 265 } 266 break; 267 } 268 dialer_buf[nc] = c; 269 #ifdef notdef 270 if (boolean(value(VERBOSE))) 271 putchar(c); 272 #endif 273 } 274 printf("%s\r\n", dialer_buf); 275 signal(SIGALRM, f); 276 return (0); 277 } 278 279 /* 280 * This convoluted piece of code attempts to get 281 * the courier in sync. 282 */ 283 static int 284 coursync() 285 { 286 int already = 0; 287 int len; 288 char buf[40]; 289 290 while (already++ < MAXRETRY) { 291 tcflush(FD, TCIOFLUSH); 292 cour_write(FD, "\rAT Z\r", 6); /* reset modem */ 293 memset(buf, 0, sizeof(buf)); 294 sleep(1); 295 ioctl(FD, FIONREAD, &len); 296 if (len) { 297 len = read(FD, buf, sizeof(buf)); 298 #ifdef DEBUG 299 buf[len] = '\0'; 300 printf("coursync: (\"%s\")\n\r", buf); 301 #endif 302 if (strchr(buf, '0') || 303 (strchr(buf, 'O') && strchr(buf, 'K'))) 304 return(1); 305 } 306 /* 307 * If not strapped for DTR control, 308 * try to get command mode. 309 */ 310 sleep(1); 311 cour_write(FD, "+++", 3); 312 sleep(1); 313 /* 314 * Toggle DTR to force anyone off that might have left 315 * the modem connected. 316 */ 317 ioctl(FD, TIOCCDTR, 0); 318 sleep(1); 319 ioctl(FD, TIOCSDTR, 0); 320 } 321 cour_write(FD, "\rAT Z\r", 6); 322 return (0); 323 } 324 325 static void 326 cour_write(fd, cp, n) 327 int fd; 328 char *cp; 329 int n; 330 { 331 332 #ifdef notdef 333 if (boolean(value(VERBOSE))) 334 write(1, cp, n); 335 #endif 336 tcdrain(fd); 337 cour_nap(); 338 for ( ; n-- ; cp++) { 339 write(fd, cp, 1); 340 tcdrain(fd); 341 cour_nap(); 342 } 343 } 344 345 #ifdef DEBUG 346 static void 347 cour_verbose_read() 348 { 349 int n = 0; 350 char buf[BUFSIZ]; 351 352 if (ioctl(FD, FIONREAD, &n) < 0) 353 return; 354 if (n <= 0) 355 return; 356 if (read(FD, buf, n) != n) 357 return; 358 write(1, buf, n); 359 } 360 #endif 361 362 #define setsa(sa, a) \ 363 sa.sa_handler = a; sigemptyset(&sa.sa_mask); sa.sa_flags = 0 364 365 static int napms = 50; /* Give the courier 50 milliseconds between characters */ 366 367 static int ringring; 368 369 void 370 cour_nap() 371 { 372 373 struct itimerval itv, oitv; 374 struct itimerval *itp = &itv; 375 struct sigaction sa, osa; 376 sigset_t sm, osm; 377 378 timerclear(&itp->it_interval); 379 timerclear(&itp->it_value); 380 if (setitimer(ITIMER_REAL, itp, &oitv) < 0) 381 return; 382 383 sigemptyset(&sm); 384 sigaddset(&sm, SIGALRM); 385 (void)sigprocmask(SIG_BLOCK, &sm, &osm); 386 387 itp->it_value.tv_sec = napms/1000; 388 itp->it_value.tv_usec = ((napms%1000)*1000); 389 390 setsa(sa, cour_napx); 391 (void)sigaction(SIGALRM, &sa, &osa); 392 393 (void)setitimer(ITIMER_REAL, itp, NULL); 394 395 sm = osm; 396 sigdelset(&sm, SIGALRM); 397 398 for (ringring = 0; !ringring; ) 399 sigsuspend(&sm); 400 401 (void)sigaction(SIGALRM, &osa, NULL); 402 (void)setitimer(ITIMER_REAL, &oitv, NULL); 403 (void)sigprocmask(SIG_SETMASK, &osm, NULL); 404 } 405 406 static void 407 cour_napx(dummy) 408 int dummy; 409 { 410 411 ringring = 1; 412 } 413