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