1 /* $OpenBSD: courier.c,v 1.15 2006/03/17 19:17:13 moritz Exp $ */ 2 /* $NetBSD: courier.c,v 1.7 1997/02/11 09:24:16 mrg Exp $ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Copyright (c) 1986, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Routines for calling up on a Courier modem. 37 * Derived from Hayes driver. 38 */ 39 #include "tip.h" 40 #include <sys/ioctl.h> 41 #include <stdio.h> 42 43 #define MAXRETRY 5 44 45 static int dialtimeout = 0; 46 static int connected = 0; 47 static jmp_buf timeoutbuf; 48 49 static void sigALRM(int); 50 static int cour_swallow(char *); 51 static int cour_connect(void); 52 static int coursync(void); 53 static void cour_write(int, char *, int); 54 static void cour_nap(void); 55 #ifdef DEBUG 56 static void cour_verbose_read(void); 57 #endif 58 59 int 60 cour_dialer(char *num, char *acu) 61 { 62 char *cp; 63 #ifdef ACULOG 64 char line[80]; 65 #endif 66 struct termios cntrl; 67 68 if (boolean(value(VERBOSE))) 69 printf("Using \"%s\"\n", acu); 70 71 tcgetattr(FD, &cntrl); 72 cntrl.c_cflag |= HUPCL; 73 tcsetattr(FD, TCSAFLUSH, &cntrl); 74 /* 75 * Get in synch. 76 */ 77 if (!coursync()) { 78 badsynch: 79 printf("can't synchronize with courier\n"); 80 #ifdef ACULOG 81 logent(value(HOST), num, "courier", "can't synch up"); 82 #endif 83 return (0); 84 } 85 cour_write(FD, "AT E0\r", 6); /* turn off echoing */ 86 sleep(1); 87 #ifdef DEBUG 88 if (boolean(value(VERBOSE))) 89 cour_verbose_read(); 90 #endif 91 tcflush(FD, TCIOFLUSH); 92 cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); 93 if (!cour_swallow("\r\nOK\r\n")) 94 goto badsynch; 95 fflush(stdout); 96 cour_write(FD, "AT D", 4); 97 for (cp = num; *cp; cp++) 98 if (*cp == '=') 99 *cp = ','; 100 cour_write(FD, num, strlen(num)); 101 cour_write(FD, "\r", 1); 102 connected = cour_connect(); 103 #ifdef ACULOG 104 if (dialtimeout) { 105 (void)snprintf(line, sizeof line, "%ld second dial timeout", 106 number(value(DIALTIMEOUT))); 107 logent(value(HOST), num, "cour", line); 108 } 109 #endif 110 if (dialtimeout) 111 cour_disconnect(); 112 return (connected); 113 } 114 115 void 116 cour_disconnect(void) 117 { 118 /* first hang up the modem*/ 119 ioctl(FD, TIOCCDTR, 0); 120 sleep(1); 121 ioctl(FD, TIOCSDTR, 0); 122 coursync(); /* reset */ 123 close(FD); 124 } 125 126 void 127 cour_abort(void) 128 { 129 cour_write(FD, "\r", 1); /* send anything to abort the call */ 130 cour_disconnect(); 131 } 132 133 /*ARGSUSED*/ 134 static void 135 sigALRM(int signo) 136 { 137 printf("\07timeout waiting for reply\n"); 138 dialtimeout = 1; 139 longjmp(timeoutbuf, 1); 140 } 141 142 static int 143 cour_swallow(char *match) 144 { 145 sig_t f; 146 char c; 147 148 f = signal(SIGALRM, sigALRM); 149 dialtimeout = 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(void) 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 dialtimeout = 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 printf("%s\r\n", dialer_buf); 253 signal(SIGALRM, f); 254 return (0); 255 } 256 257 /* 258 * This convoluted piece of code attempts to get 259 * the courier in sync. 260 */ 261 static int 262 coursync(void) 263 { 264 int already = 0; 265 int len; 266 char buf[40]; 267 268 while (already++ < MAXRETRY) { 269 tcflush(FD, TCIOFLUSH); 270 cour_write(FD, "\rAT Z\r", 6); /* reset modem */ 271 bzero(buf, sizeof(buf)); 272 sleep(1); 273 ioctl(FD, FIONREAD, &len); 274 if (len) { 275 len = read(FD, buf, sizeof(buf)); 276 #ifdef DEBUG 277 buf[len] = '\0'; 278 printf("coursync: (\"%s\")\n\r", buf); 279 #endif 280 if (strchr(buf, '0') || 281 (strchr(buf, 'O') && strchr(buf, 'K'))) 282 return(1); 283 } 284 /* 285 * If not strapped for DTR control, 286 * try to get command mode. 287 */ 288 sleep(1); 289 cour_write(FD, "+++", 3); 290 sleep(1); 291 /* 292 * Toggle DTR to force anyone off that might have left 293 * the modem connected. 294 */ 295 ioctl(FD, TIOCCDTR, 0); 296 sleep(1); 297 ioctl(FD, TIOCSDTR, 0); 298 } 299 cour_write(FD, "\rAT Z\r", 6); 300 return (0); 301 } 302 303 static void 304 cour_write(int fd, char *cp, int n) 305 { 306 #ifdef notdef 307 if (boolean(value(VERBOSE))) 308 write(1, cp, n); 309 #endif 310 tcdrain(fd); 311 cour_nap(); 312 for ( ; n-- ; cp++) { 313 write(fd, cp, 1); 314 tcdrain(fd); 315 cour_nap(); 316 } 317 } 318 319 #ifdef DEBUG 320 static void 321 cour_verbose_read(void) 322 { 323 int n = 0; 324 char buf[BUFSIZ]; 325 326 if (ioctl(FD, FIONREAD, &n) < 0) 327 return; 328 if (n <= 0) 329 return; 330 if (read(FD, buf, n) != n) 331 return; 332 write(1, buf, n); 333 } 334 #endif 335 336 /* Give the courier 50 milliseconds between characters */ 337 static void 338 cour_nap(void) 339 { 340 struct timespec ts; 341 342 ts.tv_sec = 0; 343 ts.tv_nsec = 50 * 1000000; 344 345 nanosleep(&ts, NULL); 346 } 347