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