ftp.nice.ch/pub/next/unix/communication/pcomm.NIHS.bs.tar.gz#/pcomm/Source/dial.c

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

/*
 * The routines that dial the modem and listen for the return codes.
 */

#define HZ	60
#undef USLEEP

#include <stdio.h>
#include "config.h"
#include "dial_dir.h"
#include "misc.h"
#include "modem.h"
#include "param.h"

#ifdef BSD
#include <sys/time.h>
#else /* BSD */
#include <sys/types.h>
#include <sys/times.h>
#endif /* BSD */

#ifdef UNIXPC
#include <sys/phone.h>
#endif /* UNIXPC */

/*
 * Get the dial string ready, send it to the modem.  The parameter is not
 * the actual entry number, it is an index into the queue.
 */

void
dial_it(num)
int num;
{
	extern int fd;
	int i, skip;
	char s[100], number[40], *strcpy(), *strcat(), *n, *strchr();
	void send_str();
#ifdef UNIXPC
	struct updata pbuf;
	unsigned int sleep();
#endif /* UNIXPC */

	/*
	 * Create the string to be sent to the modem.  The long distance
	 * codes are added if they are requested.
	 */
	s[0] = '\0';
	strcpy(s, modem->dial[modem->m_cur]);

	switch (dir->q_ld[num]) {
		case 0:			/* no ld code requested */
			break;
		case '+':
			strcat(s, param->ld_plus);
			break;
		case '-':
			strcat(s, param->ld_minus);
			break;
		case '@':
			strcat(s, param->ld_at);
			break;
		case '#':
			strcat(s, param->ld_pound);
			break;
	}
	/*
	 * Purify the phone number by removing all the pretty characters
	 * that don't need to be sent to the modem.  Typically the "-",
	 * "(", ")", and space characters are just for looks.  To prevent
	 * this action, prepend a "\" to the character.
	 */
	i = 0;
	skip = 0;
	n = dir->number[dir->q_num[num]];
	while (*n) {
		if (*n == '\\' && !skip) {
			skip++;
			n++;
			continue;
		}
		if (!strchr("-() ", *n) || skip)
			number[i++] = *n;
		n++;
		skip = 0;
	}
	number[i] = '\0';
					/* add it to the string */
	strcat(s, number);
	strcat(s, modem->suffix[modem->m_cur]);
#ifdef DEBUG
	fprintf(stderr, "raw dial string: \"%s\"\n", s);
#endif /* DEBUG */

#ifdef UNIXPC
					/* special case for OBM */
	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
					/* prepare the modem */
		pbuf.c_lineparam = DATA|DTMF;
		pbuf.c_waitdialtone = 5;
		pbuf.c_linestatus = 0;
		pbuf.c_feedback = SPEAKERON|NORMSPK;
		pbuf.c_waitflash = 500;
		ioctl(fd, PIOCSETP, &pbuf);
		sleep(1);
					/* connect the dialer */
		ioctl(fd, PIOCRECONN);
		sleep(1);
					/* dial each digit */
		n = s;
		while (*n) {
					/* switch tone/pulse dialing? */
			switch (*n) {
				case '^':
					pbuf.c_lineparam = DATA|PULSE;
					ioctl(fd, PIOCSETP, &pbuf);
					break;
				case '%':
					pbuf.c_lineparam = DATA|DTMF;
					ioctl(fd, PIOCSETP, &pbuf);
					break;
				default:
					ioctl(fd, PIOCDIAL, n);
					break;
			}
			n++;
		}
		/*
		 * It seems that the OBM doesn't always talk reliably to
		 * other types of modems (most notibly Telebits).  Here
		 * is some witchcraft to fix the problem.
		 */
		ioctl(fd, PIOCOVSPD);
		return;
	}
#endif /* UNIXPC */

	send_str(s, SLOW);
	return;
}

/*
 * Send a string to the modem.  Performs all the character synonym
 * translations.
 */

void
send_str(s, slow)
char *s;
int slow;
{
	extern int fd;
	int skip, has_pause;
	char *strchr();
	unsigned int sleep();
	static void do_pause();
					/* empty string? */
	if (s == NULL || *s == '\0')
		return;

					/* contains a pause? */
	has_pause = 0;
	if (strchr(s, '~'))
		has_pause++;

	tty_flush(fd, 1);
	/*
	 * Change the character synonyms to their real values.  Writes
	 * the characters to the modem.  To remove the special meaning
	 * of one of the characters, prepend a "\" to it.
	 */
	skip = 0;
	while (*s) {
					/* send the literal character */
		if (skip) {
			skip = 0;
			write(fd, s, 1);
			if (has_pause || slow)
				tty_drain(fd);
			if (slow)
				do_pause();
#ifdef DEBUG
			fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
#endif /* DEBUG */
			s++;
			continue;
		}
					/* turn off the special meaning */
		if (*s == '\\') {
			skip++;
			s++;
			continue;
		}
					/* pause synonym */
		if (*s == param->pause_char) {
			sleep(1);
			s++;
			continue;
		}
					/* carriage return synonym */
		if (*s == param->cr_char)
			*s = '\r';
					/* 2 character control sequence */
		if (*s == param->ctrl_char) {
			s++;
					/* premature EOF? */
			if (*s == '\0')
				break;
					/* upper and lower case */
			if (*s > '_')
				*s -= 96;
			else
				*s -= 64;
		}
					/* escape synonym */
		if (*s == param->esc_char)
			*s = ESC;
					/* modem break synonym */
		if (*s == param->brk_char) {
			tty_break(fd);
			sleep(1);
			s++;
			continue;
		}

		write(fd, s, 1);
#ifdef DEBUG
		fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
#endif /* DEBUG */
		/*
		 * Because the pause char makes the timing critical, we
		 * wait until the buffer is clear before we continue.
		 */
		if (has_pause || slow)
			tty_drain(fd);
		if (slow)
			do_pause();
		s++;
	}
	return;
}

/*
 * Read the result codes coming back from the modem.  Test for the 6
 * "connect" strings and the 4 "no connect" strings.  Return the connected
 * baud rate (as a string) or the error message.
 */

int rc_index;

char *
read_codes()
{
	extern int fd;
	int i;
	static int match();
	char c;
	static char rc_buf[512];
#ifdef UNIXPC
	unsigned int sleep();
	struct updata pbuf;
					/* special case for OBM */
	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
		ioctl(fd, PIOCGETP, &pbuf);

		/*
		 * The OBM doesn't use a return message to announce the
		 * connection to a remote, so we fake one.  The 1200
		 * is quite arbitrary... it is not an indicator of the
		 * connected baud rate.
		 */
		if (pbuf.c_linestatus & MODEMCONNECTED)
			return("1200");

		sleep(1);
		return(NULL);
	}
#endif /* UNIXPC */
					/* search for key words */
	for (; rc_index<511; rc_index++) {
		if ((i = getc_line(1)) <= 0)
			return(NULL);

		c = i & 0x7f;
#ifdef DEBUG
		fprintf(stderr, "read_codes: \"%c\", %02x, %03o, %d\n", c, c, c, c);
#endif /* DEBUG */
					/* no NULLs please */
		if (c == '\0') {
			if (rc_index)
				rc_index--;
			continue;
		}
		rc_buf[rc_index] = c;
		rc_buf[rc_index+1] = '\0';
					/* the connect strings */
		if (match(rc_buf, modem->con_3[modem->m_cur]))
			return("300");

		if (match(rc_buf, modem->con_12[modem->m_cur]))
			return("1200");

		if (match(rc_buf, modem->con_24[modem->m_cur]))
			return("2400");

		if (match(rc_buf, modem->con_48[modem->m_cur]))
			return("4800");

		if (match(rc_buf, modem->con_96[modem->m_cur]))
			return("9600");

		if (match(rc_buf, modem->con_192[modem->m_cur]))
			return("19200");

					/* the no connect strings */
		if (match(rc_buf, modem->no_con1[modem->m_cur]))
			return(modem->no_con1[modem->m_cur]);

		if (match(rc_buf, modem->no_con2[modem->m_cur]))
			return(modem->no_con2[modem->m_cur]);

		if (match(rc_buf, modem->no_con3[modem->m_cur]))
			return(modem->no_con3[modem->m_cur]);

		if (match(rc_buf, modem->no_con4[modem->m_cur]))
			return(modem->no_con4[modem->m_cur]);
	}
					/* ran out of buffer? */
	return("ERROR");
}

/*
 * Test for a match between two character strings.  A non-zero return code
 * means that s2 was found at the end of s1.
 */

static int
match(s1, s2)
char *s1, *s2;
{
	register int i;
	int skip, diff;
	char new[40];
					/* if no string to match */
	if (*s2 == '\0')
		return(0);
					/* translate synonyms */
	i = 0;
	skip = 0;
	while (*s2) {
					/* literal character */
		if (skip) {
			skip = 0;
			new[i++] = *s2;
			s2++;
			continue;
		}
					/* turn off the special meaning */
		if (*s2 == '\\') {
			skip++;
			s2++;
			continue;
		}
					/* carriage return synonym */
		if (*s2 == param->cr_char)
			*s2 = '\r';

					/* 2 character control sequence */
		if (*s2 == param->ctrl_char) {
			s2++;
			if (*s2 == '\0')
				break;
			if (*s2 > '_')
				*s2 -= 96;
			else
				*s2 -= 64;
		}
					/* escape synonym */
		if (*s2 == param->esc_char)
			*s2 = ESC;

		new[i++] = *s2;
		s2++;
	}
	new[i] = '\0';

	diff = strlen(s1) - strlen(new);
					/* is it possible? */
	if (diff < 0)
		return(0);
					/* test it out */
	if (!strcmp(&s1[diff], new))
		return(1);
	return(0);
}

/*
 * Apparently some modems can't take input at the rated speed while
 * in the command mode.  Therefore, a 0.10 sec pause a required between
 * characters.
 */

static void
do_pause()
{
#ifdef USLEEP
	usleep(100000);
#else /* USLEEP */
				/* Hey! I know these routines are a hack */
#ifdef BSD
	struct timeval tv;
	struct timezone tz;
	double t1;

	gettimeofday(&tv, &tz);
	t1 = tv.tv_sec + (tv.tv_usec / 1000000.0);
	do
		gettimeofday(&tv, &tz);
	while ((tv.tv_sec + (tv.tv_usec / 1000000.0) - t1) < 0.1);
#else /* BSD */
	struct tms t;
	long t1;

	t1 = times(&t);
	while ((times(&t) - t1) < HZ/10)
		;
#endif /* BSD */
#endif /* USLEEP */
	return;
}

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