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