root/usr/src/cmd/tip/aculib/hayes.c
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved. The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#include "tip.h"

static int      hayes_sync(int);
static void     sigALRM(void);
static sigjmp_buf       timeoutbuf;

void    hayes_disconnect(void);

/*
 * Dial up on a Hayes Smart Modem 1200 or 2400
 */
/* ARGSUSED */
int
hayes_dialer(char *num, char *acu)
{
        char code = 0, cr = 0;
        sig_handler_t   f;
        struct termios buf;

        f = signal(SIGALRM, (sig_handler_t)sigALRM);

        if (!hayes_sync(FD)) {
                (void) printf("can't synchronize with hayes\n");
#ifdef ACULOG
                logent(value(HOST), num, "hayes", "can't synch up");
#endif
                (void) signal(SIGALRM, f);
                return (0);
        }
        if (boolean(value(VERBOSE)))
                (void) printf("\ndialing...");
        (void) fflush(stdout);
        (void) ioctl(FD, TCGETS, &buf);
        buf.c_cflag |= HUPCL;
        (void) ioctl(FD, TCSETS, &buf);
        (void) ioctl(FD, TCFLSH, TCIOFLUSH);

        if (sigsetjmp(timeoutbuf, 1)) {
#ifdef ACULOG
                char line[80];

                (void) sprintf(line, "%d second dial timeout",
                    number(value(DIALTIMEOUT)));
                logent(value(HOST), num, "hayes", line);
#endif
                hayes_disconnect();
                (void) signal(SIGALRM, f);
                return (0);
        }
        (void) alarm(number(value(DIALTIMEOUT)));
        (void) ioctl(FD, TCFLSH, TCIOFLUSH);
        if (*num == 'S')
                (void) write(FD, "AT", 2);
        else
                (void) write(FD, "ATDT", 4);    /* use tone dialing */
        (void) write(FD, num, strlen(num));
        (void) write(FD, "\r", 1);
        (void) read(FD, &code, 1);
        (void) read(FD, &cr, 1);
        if (code == '1' && cr == '0')
                (void) read(FD, &cr, 1);
        (void) alarm(0);
        (void) signal(SIGALRM, f);
        if ((code == '1' || code == '5') && cr == '\r')
                return (1);
        return (0);
}

void
hayes_disconnect(void)
{
        (void) close(FD);
}

void
hayes_abort(void)
{
        int dtr = TIOCM_DTR;

        (void) alarm(0);
        (void) ioctl(FD, TIOCMBIC, &dtr);
        (void) sleep(2);
        (void) ioctl(FD, TCFLSH, TCIOFLUSH);
        (void) close(FD);
}

static void
sigALRM(void)
{
        siglongjmp(timeoutbuf, 1);
}

/*
 * This piece of code attempts to get the hayes in sync.
 */
static int
hayes_sync(int fd)
{
        int tries;
        char code = 0, cr = 0;
        int dtr = TIOCM_DTR;

        /*
         * Toggle DTR to force anyone off that might have left
         * the modem connected, and insure a consistent state
         * to start from.
         */
        (void) ioctl(fd, TIOCMBIC, &dtr);
        (void) sleep(1);
        (void) ioctl(fd, TIOCMBIS, &dtr);
        for (tries = 0; tries < 3; tries++) {
                /*
                 * After reseting the modem, initialize all
                 * parameters to required vaules:
                 *
                 *      V0      - result codes are single digits
                 *      Q0      - result codes ARE sent
                 *      E0      - do not echo
                 *      S0=1    - automatically answer phone
                 *      S2=255  - disable escape character
                 *      S12=255 - longest possible escape guard time
                 */
                (void) write(fd, "ATV0Q0E0S0=1S2=255S12=255\r", 26);
                (void) sleep(1);
                /* flush any echoes or return codes */
                (void) ioctl(fd, TCFLSH, TCIOFLUSH);
                /* now see if the modem is talking to us properly */
                (void) write(fd, "AT\r", 3);
                if (sigsetjmp(timeoutbuf, 1) == 0) {
                        (void) alarm(2);
                        (void) read(FD, &code, 1);
                        (void) read(FD, &cr, 1);
                        if (code == '0' && cr == '\r')
                                return (1);
                }
        }
        return (0);
}