Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / tip / libacu / hayes.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)hayes.c     8.1 (Berkeley) 6/6/93";
36 #endif /* not lint */
37
38 /*
39  * Routines for calling up on a Hayes Modem
40  * (based on the old VenTel driver).
41  * The modem is expected to be strapped for "echo".
42  * Also, the switches enabling the DTR and CD lines
43  * must be set correctly.
44  * NOTICE:
45  * The easy way to hang up a modem is always simply to
46  * clear the DTR signal. However, if the +++ sequence
47  * (which switches the modem back to local mode) is sent
48  * before modem is hung up, removal of the DTR signal
49  * has no effect (except that it prevents the modem from
50  * recognizing commands).
51  * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
52  */
53 /*
54  * TODO:
55  * It is probably not a good idea to switch the modem
56  * state between 'verbose' and terse (status messages).
57  * This should be kicked out and we should use verbose
58  * mode only. This would make it consistent with normal
59  * interactive use thru the command 'tip dialer'.
60  */
61 #include "tipconf.h"
62 #include "tip.h"
63
64 #define min(a,b)        ((a < b) ? a : b)
65
66 static  void sigALRM();
67 static  int timeout = 0;
68 static  jmp_buf timeoutbuf;
69 static  char gobble();
70 #define DUMBUFLEN       40
71 static char dumbuf[DUMBUFLEN];
72
73 #define DIALING         1
74 #define IDLE            2
75 #define CONNECTED       3
76 #define FAILED          4
77 static  int state = IDLE;
78
79 hay_dialer(num, acu)
80         register char *num;
81         char *acu;
82 {
83         register char *cp;
84         register int connected = 0;
85         char dummy;
86 #if ACULOG
87         char line[80];
88 #endif
89         if (hay_sync() == 0)            /* make sure we can talk to the modem */
90                 return(0);
91         if (boolean(value(VERBOSE)))
92                 printf("\ndialing...");
93         fflush(stdout);
94         acu_hupcl ();
95         acu_flush ();
96         write(FD, "ATv0\r", 5); /* tell modem to use short status codes */
97         gobble("\r");
98         gobble("\r");
99         write(FD, "ATTD", 4);   /* send dial command */
100         write(FD, num, strlen(num));
101         state = DIALING;
102         write(FD, "\r", 1);
103         connected = 0;
104         if (gobble("\r")) {
105                 if ((dummy = gobble("01234")) != '1')
106                         error_rep(dummy);
107                 else
108                         connected = 1;
109         }
110         if (connected)
111                 state = CONNECTED;
112         else {
113                 state = FAILED;
114                 return (connected);     /* lets get out of here.. */
115         }
116         ioctl(FD, TIOCFLUSH, 0);
117 #if ACULOG
118         if (timeout) {
119                 sprintf(line, "%d second dial timeout",
120                         number(value(DIALTIMEOUT)));
121                 logent(value(HOST), num, "hayes", line);
122         }
123 #endif
124         if (timeout)
125                 hay_disconnect();       /* insurance */
126         return (connected);
127 }
128
129
130 hay_disconnect()
131 {
132         char c;
133         int len, rlen;
134
135         /* first hang up the modem*/
136 #ifdef DEBUG
137         printf("\rdisconnecting modem....\n\r");
138 #endif
139         ioctl(FD, TIOCCDTR, 0);
140         sleep(1);
141         ioctl(FD, TIOCSDTR, 0);
142         goodbye();
143 }
144
145 hay_abort()
146 {
147
148         char c;
149
150         write(FD, "\r", 1);     /* send anything to abort the call */
151         hay_disconnect();
152 }
153
154 static void
155 sigALRM()
156 {
157
158         printf("\07timeout waiting for reply\n\r");
159         timeout = 1;
160         longjmp(timeoutbuf, 1);
161 }
162
163 static char
164 gobble(match)
165         register char *match;
166 {
167         char c;
168         sig_t f;
169         int i, status = 0;
170
171         f = signal(SIGALRM, sigALRM);
172         timeout = 0;
173 #ifdef DEBUG
174         printf("\ngobble: waiting for %s\n", match);
175 #endif
176         do {
177                 if (setjmp(timeoutbuf)) {
178                         signal(SIGALRM, f);
179                         return (0);
180                 }
181                 alarm(number(value(DIALTIMEOUT)));
182                 read(FD, &c, 1);
183                 alarm(0);
184                 c &= 0177;
185 #ifdef DEBUG
186                 printf("%c 0x%x ", c, c);
187 #endif
188                 for (i = 0; i < strlen(match); i++)
189                         if (c == match[i])
190                                 status = c;
191         } while (status == 0);
192         signal(SIGALRM, SIG_DFL);
193 #ifdef DEBUG
194         printf("\n");
195 #endif
196         return (status);
197 }
198
199 error_rep(c)
200         register char c;
201 {
202         printf("\n\r");
203         switch (c) {
204
205         case '0':
206                 printf("OK");
207                 break;
208
209         case '1':
210                 printf("CONNECT");
211                 break;
212
213         case '2':
214                 printf("RING");
215                 break;
216
217         case '3':
218                 printf("NO CARRIER");
219                 break;
220
221         case '4':
222                 printf("ERROR in input");
223                 break;
224
225         case '5':
226                 printf("CONNECT 1200");
227                 break;
228
229         default:
230                 printf("Unknown Modem error: %c (0x%x)", c, c);
231         }
232         printf("\n\r");
233         return;
234 }
235
236 /*
237  * set modem back to normal verbose status codes.
238  */
239 goodbye()
240 {
241         int len, rlen;
242         char c;
243
244         ioctl(FD, TIOCFLUSH, &len);     /* get rid of trash */
245         if (hay_sync()) {
246                 sleep(1);
247 #ifndef DEBUG
248                 ioctl(FD, TIOCFLUSH, 0);
249 #endif
250                 write(FD, "ATH0\r", 5);         /* insurance */
251 #ifndef DEBUG
252                 c = gobble("03");
253                 if (c != '0' && c != '3') {
254                         printf("cannot hang up modem\n\r");
255                         printf("please use 'tip dialer' to make sure the line is hung up\n\r");
256                 }
257 #endif
258                 sleep(1);
259                 ioctl(FD, FIONREAD, &len);
260 #ifdef DEBUG
261                 printf("goodbye1: len=%d -- ", len);
262                 rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
263                 dumbuf[rlen] = '\0';
264                 printf("read (%d): %s\r\n", rlen, dumbuf);
265 #endif
266                 write(FD, "ATv1\r", 5);
267                 sleep(1);
268 #ifdef DEBUG
269                 ioctl(FD, FIONREAD, &len);
270                 printf("goodbye2: len=%d -- ", len);
271                 rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
272                 dumbuf[rlen] = '\0';
273                 printf("read (%d): %s\r\n", rlen, dumbuf);
274 #endif
275         }
276         ioctl(FD, TIOCFLUSH, 0);        /* clear the input buffer */
277         ioctl(FD, TIOCCDTR, 0);         /* clear DTR (insurance) */
278         close(FD);
279 }
280
281 #define MAXRETRY        5
282
283 hay_sync()
284 {
285         int len, retry = 0;
286
287         while (retry++ <= MAXRETRY) {
288                 write(FD, "AT\r", 3);
289                 sleep(1);
290                 ioctl(FD, FIONREAD, &len);
291                 if (len) {
292                         len = read(FD, dumbuf, min(len, DUMBUFLEN));
293                         if (index(dumbuf, '0') ||
294                         (index(dumbuf, 'O') && index(dumbuf, 'K')))
295                                 return(1);
296 #ifdef DEBUG
297                         dumbuf[len] = '\0';
298                         printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
299 #endif
300                 }
301                 ioctl(FD, TIOCCDTR, 0);
302                 ioctl(FD, TIOCSDTR, 0);
303         }
304         printf("Cannot synchronize with hayes...\n\r");
305         return(0);
306 }