ftp.nice.ch/pub/next/unix/communication/zm_tip_modified.NI.bs.tar.gz#/zm_tip/hayes.c

This is hayes.c in view mode; [Download] [Up]

/*
 * Copyright (c) 1983 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that: (1) source distributions retain this entire copyright
 * notice and comment, and (2) distributions including binaries display
 * the following acknowledgement:  ``This product includes software
 * developed by the University of California, Berkeley and its contributors''
 * in the documentation or other materials provided with the distribution
 * and in all advertising materials mentioning features or use of this
 * software. Neither the name of the University nor the names of its
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */


/*
 * Routines for calling up on a Hayes Modem
 * (based on the old VenTel driver).
 * The modem is expected to be strapped for "echo".
 * Also, the switches enabling the DTR and CD lines
 * must be set correctly.
 * NOTICE:
 * The easy way to hang up a modem is always simply to
 * clear the DTR signal. However, if the +++ sequence
 * (which switches the modem back to local mode) is sent
 * before modem is hung up, removal of the DTR signal
 * has no effect (except that it prevents the modem from
 * recognizing commands).
 * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 
 */
/*
 * TODO:
 * It is probably not a good idea to switch the modem
 * state between 'verbose' and terse (status messages).
 * This should be kicked out and we should use verbose 
 * mode only. This would make it consistent with normal
 * interactive use thru the command 'tip dialer'.
 */
/*
 * Added support for more result codes - we need 2400.
 * Made sure that it works with Hayes compatible Supra 2400.
 * (Michal Jaegermann)
 */
/*
 * Rehack to make it work with my ZyXEL which communicates with
 * my computer at a fixed speed of 38400.  It is using verbose
 * modem messages to recognize speed of a telephone connection
 * to get reasonable estimates for transfer times.  It may or may
 * not work with some other modem.  You may need to modify
 * code somewhere in vicinity of line 155.  (Michal J.)
 */

#include "tip.h"
#include <string.h>

#define	min(a,b)	((a < b) ? a : b)

static	void sigALRM();
static	int timeout = 0;
static	jmp_buf timeoutbuf;
static 	int gobble();
#define DUMBUFLEN	80
static char dumbuf[DUMBUFLEN];
static char *dpos = dumbuf;

void goodbye(void);
int hay_sync(void);
void hay_disconnect(void);
int ioctl();
int write(int fd, char *buf, int nbytes);
int read(int fd, char *buf, int nbytes);
int sleep();
unsigned int alarm();
int close(int fd);


#define	DIALING		1
#define IDLE		2
#define CONNECTED	3
#define	FAILED		4
static	int state = IDLE;
int     Cbaudrate;   /* baud rate of connection we got - it does not
			have to be the same as a speed of DCE-DTE link */

int hay_dialer(num, acu)
	register char *num;
	char *acu;
{
	register int connected = 0;
/*	void error_rep();  */
	int len;
	char *strp;
#ifdef ACULOG
	char line[80];
#endif
	if (hay_sync() == 0)	/* make sure we can talk to the modem */
		return(0);
	if (boolean(value(VERBOSE)))
		printf("\ndialing... %s ", num);
	fflush(stdout);
	ioctl(FD, TIOCHPCL, 0);
	ioctl(FD, TIOCFLUSH, 0);	/* get rid of garbage */
/*	write(FD, "ATV0\r", 5);	*//* tell modem to use short status codes */
	write(FD, "ATV1\r", 5);	/* tell modem to use long status codes */
 	(void) gobble("\r");
	(void) gobble("\r");
	write(FD, "ATDP", 4);	/* send dial command */
	write(FD, num, strlen(num));
	state = DIALING;
	write(FD, "\r", 1);
	connected = 0;
	sleep(2);
	gobble("\n");
	ioctl(FD, FIONREAD, &len);
	len = read(FD, dumbuf, min(len, DUMBUFLEN));
#ifdef DEBUG
	dumbuf[len] = '\0';
	printf("\n****%d %s\r\n*****", len, dumbuf);
	if (boolean(value(VERBOSE)))
		printf(" %s ", num);
#endif
	ioctl(FD, TIOCFLUSH, 0);		    
	dumbuf[0] = '\0';
	if (0 != gobble("\r")) {
		while(1) {
#if 0
		    ioctl(FD, FIONREAD, &len);
		    len = read(FD, dumbuf, min(len, DUMBUFLEN));
		    ioctl(FD, TIOCFLUSH, 0);		    
		    dumbuf[len] = '\0';
#endif
		    dpos = dumbuf;
		    gobble("\r");
		    strp = dumbuf;
		    while (' ' > *strp && *strp > '\0')
			strp++;
		    if ('A' == *strp ||		/* "AT" */
			'O' == *strp ||		/* "OK" */
			'R' == *strp ||		/* "RINGING" */
			'\0' == *strp)
			continue;
		    if (boolean(value(VERBOSE)))
			printf("%s\n", strp);
		    if ('R' != *strp)
			break;
		}
		connected = ( 'C' == *strp );
/*		error_rep(dummy);  */
/*
		if (1 != dummy && dummy < 10)
			error_rep(dummy);
		else
			connected = 1;
*/
	}
	if (connected) {
		state = CONNECTED;
		strp += sizeof("CONNECT 38400/V.32");
		if (sscanf((const char *)strp, "%d", &Cbaudrate) <= 0)
		    Cbaudrate = 300;
	}
	else {
		state = FAILED;
		return (connected);	/* lets get out of here.. */
	}
	ioctl(FD, TIOCFLUSH, 0);
#ifdef ACULOG
	if (timeout) {
		sprintf(line, "%d second dial timeout",
			number(value(DIALTIMEOUT)));
		logent(value(HOST), num, "hayes", line);
	}
#endif
	if (timeout)
		hay_disconnect();	/* insurance */
	return (connected);
}


void hay_disconnect(void)
{

	/* first hang up the modem*/
#ifdef DEBUG
	printf("\rdisconnecting modem....\n\r");
#endif
	ioctl(FD, TIOCCDTR, 0);
	sleep(1);
	ioctl(FD, TIOCSDTR, 0);
	goodbye();
}

void hay_abort(void)
{


	write(FD, "\r", 1);	/* send anything to abort the call */
	hay_disconnect();
}

static void
sigALRM()
{

	printf("\07timeout waiting for reply\n\r");
	timeout = 1;
	longjmp(timeoutbuf, 1);
}

static int
gobble(match)
	register char *match;
{
	char c;
	void (*f)();
	int status = 0;

	signal(SIGALRM, sigALRM);
	timeout = 0;
#ifdef DEBUG
	printf("\ngobble: waiting for (0x%x)\n%s **\n", *match, match);
#endif
	for(;;) {
		if (setjmp(timeoutbuf)) {
			signal(SIGALRM, f);
			return (-1);
		}
		alarm(number(value(DIALTIMEOUT)));
		read(FD, &c, 1);
		alarm(0);
		c &= 0177;
#ifdef DEBUG
		printf("%c 0x%x ", (c >= ' ' ? c : '_'), c);
#endif
		*dpos++ = c;
		if (NULL != index(match, c)) {
		    *dpos = '\0';
		     dpos = dumbuf;
		     status = 1;
		    break;
		}
#if 0
		if ('\r' == c || '\n' == c) {
		    if (c == *match)
			status = 1;
		    break;
		}
		for (i = 0; i < strlen(match); i++)
			if (c == match[i]) {
				status *= 10;
				status += i;
			}
#endif
	}
	signal(SIGALRM, SIG_DFL);
#ifdef DEBUG
	printf("\n");
	printf("status = %d\n", status);
#endif
	return (status);
}

#if 0

static char *ret_message[] = {
    "OK",		/* 0 */
    "CONNECT",		/* 1 */
    "RING",		/* 2 */
    "NO CARRIER",	/* 3 */
    "ERROR in input",	/* 4 */
    "CONNECT 1200",	/* 5 */
    "NO DIALTONE",	/* 6 */
    "BUSY",		/* 7 */
    "NO ANSWER",	/* 8 */
    "RINGING",		/* 9 */
    "CONNECT 2400",	/* 10 */
    "CONNECT 4800",	/* 11 */
    "CONNECT 9600",	/* 12 */
    "",			/* 13 */
    "CONNECT 19200",	/* 14 */
    "CONNECT 7200",	/* 15 */
    "CONNECT 12000",	/* 16 */
    "CONNECT 14400",	/* 17 */
    "CONNECT 16800",	/* 18 */
    "CONNECT 38400",	/* 19 */
    "CONNECT 57600",	/* 20 */
    "CONNECT 76800"	/* 21 */
    };


void
error_rep(c)
	register int c;
{
	printf("\n\r");
	if (c < sizeof(ret_message)/sizeof(char *)) {
	    printf("%s", ret_message[c]);
	}
	else {
	    printf("Unknown Modem error: %c (0x%x)", c, c);
	}
	printf("\n\r");
	return;
}
#endif

/*
 * set modem back to normal verbose status codes.
 */
void goodbye(void)
{
	int len, rlen;

	ioctl(FD, TIOCFLUSH, &len);	/* get rid of trash */
	if (hay_sync()) {
		sleep(1);
#ifndef DEBUG
		ioctl(FD, TIOCFLUSH, 0);
#endif
		write(FD, "ATH0\r", 5);		/* insurance */
#ifndef DEBUG
		write(FD, "ATV0\r", 5);
		sleep(2);
		c = gobble("03");
		if (c != 0 && c != 1) {
			printf("cannot hang up modem\n\r");
			printf("please use 'tip dialer' to make sure the line is hung up\n\r");
		}
#endif
		sleep(1);
		ioctl(FD, FIONREAD, &len);
#ifdef DEBUG
		printf("\ngoodbye1: len=%d -- ", len);
		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
		dumbuf[rlen] = '\0';
		printf("read (%d): %s\r\n", rlen, dumbuf);
	    {
		int ii;
		for (ii = 0; ii < rlen; ii++)
		    printf("0x%x ", dumbuf[ii]);
		printf("\r\n\n");
	    }
#endif
		write(FD, "ATV1\r", 5);
		sleep(1);
#ifdef DEBUG
		ioctl(FD, FIONREAD, &len);
		printf("goodbye2: len=%d -- ", len);
		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
		dumbuf[rlen] = '\0';
		printf("read (%d): %s\r\n", rlen, dumbuf);
	    {
		int ii;
		for (ii = 0; ii < rlen; ii++)
		    printf("0x%x ", dumbuf[ii]);
		printf("\r\n\n");
	    }
#endif
	}
	ioctl(FD, TIOCFLUSH, 0);	/* clear the input buffer */
	ioctl(FD, TIOCCDTR, 0);		/* clear DTR (insurance) */
	close(FD);
}

#define MAXRETRY	5

int hay_sync(void)
{
	int len, retry = 0;

	while (retry++ <= MAXRETRY) {
		write(FD, "AT\r", 3);
		sleep(1);
		ioctl(FD, FIONREAD, &len);
		if (len) {
			len = read(FD, dumbuf, min(len, DUMBUFLEN));
			if (index(dumbuf, '0') || 
		   	(index(dumbuf, 'O') && index(dumbuf, 'K')))
				return(1);
#ifdef DEBUG
			dumbuf[len] = '\0';
			printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
#endif
		}
		ioctl(FD, TIOCCDTR, 0);
		ioctl(FD, TIOCSDTR, 0);
	}
	printf("Cannot synchronize with hayes...\n\r");
	return(0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.