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
cour_dialer(char * num,char * acu)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
cour_disconnect(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
cour_abort(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
sigALRM(int signo)135 sigALRM(int signo)
136 {
137 printf("\07timeout waiting for reply\n");
138 dialtimeout = 1;
139 longjmp(timeoutbuf, 1);
140 }
141
142 static int
cour_swallow(char * match)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
cour_connect(void)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
coursync(void)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
cour_write(int fd,char * cp,int n)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
cour_verbose_read(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
cour_nap(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