1/*	$OpenBSD: biz31.c,v 1.10 2006/03/17 19:17:13 moritz Exp $	*/
2/*	$NetBSD: biz31.c,v 1.5 1997/02/11 09:24:14 mrg Exp $	*/
3
4/*-
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Copyright (c) 1983, 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#include "tip.h"
36
37#define MAXRETRY	3		/* sync up retry count */
38#define DISCONNECT_CMD	"\21\25\11\24"	/* disconnection string */
39
40static int	biz_dialer(char *, char *);
41static int	bizsync(int);
42static int	echo(char *);
43static void	sigALRM(int);
44static int	detect(char *);
45static int	flush(char *);
46static int	bizsync(int);
47
48static	int timeout = 0;
49static	jmp_buf timeoutbuf;
50
51/*
52 * Dial up on a BIZCOMP Model 1031 with either
53 * 	tone dialing (mod = "f")
54 *	pulse dialing (mod = "w")
55 */
56static int
57biz_dialer(char *num, char *mod)
58{
59	int connected = 0;
60
61	if (!bizsync(FD)) {
62		logent(value(HOST), "", "biz", "out of sync");
63		printf("bizcomp out of sync\n");
64		delock(uucplock);
65		exit(0);
66	}
67	if (boolean(value(VERBOSE)))
68		printf("\nstarting call...");
69	echo("#\rk$\r$\n");			/* disable auto-answer */
70	echo("$>$.$ #\r");			/* tone/pulse dialing */
71	echo(mod);
72	echo("$\r$\n");
73	echo("$>$.$ #\re$ ");			/* disconnection sequence */
74	echo(DISCONNECT_CMD);
75	echo("\r$\n$\r$\n");
76	echo("$>$.$ #\rr$ ");			/* repeat dial */
77	echo(num);
78	echo("\r$\n");
79	if (boolean(value(VERBOSE)))
80		printf("ringing...");
81	/*
82	 * The reply from the BIZCOMP should be:
83	 *	`^G NO CONNECTION\r\n^G\r\n'	failure
84	 *	` CONNECTION\r\n^G'		success
85	 */
86	connected = detect(" ");
87#ifdef ACULOG
88	if (timeout) {
89		char line[80];
90
91		(void)snprintf(line, sizeof line, "%ld second dial timeout",
92			number(value(DIALTIMEOUT)));
93		logent(value(HOST), num, "biz", line);
94	}
95#endif
96	if (!connected)
97		flush(" NO CONNECTION\r\n\07\r\n");
98	else
99		flush("CONNECTION\r\n\07");
100	if (timeout)
101		biz31_disconnect();	/* insurance */
102	return (connected);
103}
104
105int
106biz31w_dialer(char *num, char *acu)
107{
108	return (biz_dialer(num, "w"));
109}
110
111int
112biz31f_dialer(char *num, char *acu)
113{
114	return (biz_dialer(num, "f"));
115}
116
117void
118biz31_disconnect(void)
119{
120	write(FD, DISCONNECT_CMD, sizeof(DISCONNECT_CMD)-1);
121	sleep(2);
122	tcflush(FD, TCIOFLUSH);
123}
124
125void
126biz31_abort(void)
127{
128	write(FD, "\33", 1);
129}
130
131static int
132echo(char *s)
133{
134	char c;
135
136	while (c = *s++) switch (c) {
137
138	case '$':
139		read(FD, &c, 1);
140		s++;
141		break;
142
143	case '#':
144		c = *s++;
145		write(FD, &c, 1);
146		break;
147
148	default:
149		write(FD, &c, 1);
150		read(FD, &c, 1);
151	}
152}
153
154/*ARGSUSED*/
155static void
156sigALRM(int signo)
157{
158	timeout = 1;
159	longjmp(timeoutbuf, 1);
160}
161
162static int
163detect(char *s)
164{
165	sig_t f;
166	char c;
167
168	f = signal(SIGALRM, sigALRM);
169	timeout = 0;
170	while (*s) {
171		if (setjmp(timeoutbuf)) {
172			printf("\07timeout waiting for reply\n");
173			biz31_abort();
174			break;
175		}
176		alarm(number(value(DIALTIMEOUT)));
177		read(FD, &c, 1);
178		alarm(0);
179		if (c != *s++)
180			break;
181	}
182	signal(SIGALRM, f);
183	return (timeout == 0);
184}
185
186static int
187flush(char *s)
188{
189	sig_t f;
190	char c;
191
192	f = signal(SIGALRM, sigALRM);
193	while (*s++) {
194		if (setjmp(timeoutbuf))
195			break;
196		alarm(10);
197		read(FD, &c, 1);
198		alarm(0);
199	}
200	signal(SIGALRM, f);
201	timeout = 0;			/* guard against disconnection */
202}
203
204/*
205 * This convoluted piece of code attempts to get
206 *  the bizcomp in sync.  If you don't have the capacity or nread
207 *  call there are gory ways to simulate this.
208 */
209static int
210bizsync(int fd)
211{
212#ifdef FIOCAPACITY
213	struct capacity b;
214#	define chars(b)	((b).cp_nbytes)
215#	define IOCTL	FIOCAPACITY
216#endif
217#ifdef FIONREAD
218	long b;
219#	define chars(b)	(b)
220#	define IOCTL	FIONREAD
221#endif
222	int already = 0;
223	char buf[10];
224
225retry:
226	if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0 && chars(b) > 0)
227		tcflush(FD, TCIOFLUSH);
228	write(fd, "\rp>\r", 4);
229	sleep(1);
230	if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0) {
231		if (chars(b) != 10) {
232	nono:
233			if (already > MAXRETRY)
234				return (0);
235			write(fd, DISCONNECT_CMD, 4);
236			sleep(2);
237			already++;
238			goto retry;
239		} else {
240			read(fd, buf, 10);
241			if (strncmp(buf, "p >\r\n\r\n>", 8))
242				goto nono;
243		}
244	}
245	return (1);
246}
247