/* 4m v2.15 (clientserve.c)
 * (C) Copyright 1990 by Carrick Sean Casey
 * (C) Copyright 1993 by Scott Chasin and Michaeljon Miller
 *
 * 3-22-93 See file COPYING for copyright information.
 *
 * Client server
 *
 */

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>

#ifdef NEEDS_SELECT
# include "select.h"
#endif

#include "ipcf.h"
#include "../client/ctcp.h"
#include "externs.h"
#include "../client/4m.h"
#include "../h/protocol.h"

extern int errno;
extern char *sys_errlist[];
extern XFER xfer_tab[MAX_XFERS];
extern SECURE secure_tab[MAX_XFERS];
int sock;
fd_set fdr;
struct Cbuf buf;
int timeisup = 0;

SIGTYPE gotalarm();


extern void bzero ();
extern int setitimer ();
extern void perror ();
static void cdoinput ();
extern int close ();
extern int fprintf ();
extern void c_didpoll();
extern void c_userchar();
extern void c_packet();
extern void c_lostcon();
extern void c_xfersend();
extern void c_xferget();
extern void chat_read();
extern int select();
extern int shutdown();


extern int _readpacket ();
extern int _sendpacket ();

int clientserve()
{
    int ret;

    sock = port_fd;
    send_fd = -1;
    get_fd = -1;

 /* make socket read and write errors detectable */
    signal(SIGPIPE, SIG_IGN);

    buf.new = 1;

 /* initialize fdset for select */
    FD_ZERO(&fdset);
 /* look at server fd */
    FD_SET(sock, &fdset); /**/
 /* look at tty fd */
    FD_SET(0, &fdset);  /**/
    timeisup = 0;

    signal(SIGALRM, gotalarm);

#ifndef SYSV  /* set it once */
    if (polldelay) {
        if (setitimer(ITIMER_REAL, polldelay, 0) < 0) {
            perror("client: setitimer failed");
            exit(-1);
        }
    }
#endif  /* SYSV */

    for (;;) {
#ifdef SYSV /* reset every time */
        if (polldelay) {
            if (setitimer(ITIMER_REAL, polldelay, 0) < 0) {
                perror("client: setitimer failed");
                exit(-1);
            }
        }
#endif  /* SYSV */

        fdr = fdset;  /* should be a bcopy if larger than int */

        if ((ret = select(FD_SETSIZE, &fdr, 0, 0, polltimeout)) < 1) {
            if (ret == 0 || errno == EINTR) {
                c_didpoll();
                timeisup = 0;
            } else {
                perror("client: select");
                exit(-1);
            }
        }
        if (ret > 0)
            cdoinput();

        if (timeisup) {
            c_didpoll();
            timeisup = 0;
        }
    }
    /* NOTREACHED */
}

static void cdoinput()
{
    int i;
      
    signal(SIGALRM, SIG_IGN);

    if (FD_ISSET(0, &fdr)) {
        c_userchar();
    }

    if (FD_ISSET(sock, &fdr)) {
        switch (_readpacket(sock, (char *)&buf)) {
            case 1:
            /* complete packet */
                c_packet(buf.buf);
                break;
            case 0:
            /* incomplete packet */
            /* fprintf(stderr,"warn: client got incomplete\n"); */
                break;
            case -1:
            /* error */
                shutdown(sock, 2);
                close(sock);
                c_lostcon();
                break;
            case -2:
            /* lost connection with server */
                shutdown(sock, 2);
                close(sock);
                c_lostcon();
                break;
        }
    }
    for (i = 0; i < MAX_XFERS; i++) {
        if (xfer_tab[i].s != -1 
            && FD_ISSET(xfer_tab[i].s, &fdr) 
            && xfer_tab[i].size > 0)
        {
            if (xfer_tab[i].type == SEND)
                c_xfersend(i);
            else
                c_xferget(i);
        }
    }

/*    for (i = 0; i < MAX_XFERS; i++) 
        if (secure_tab[i].s != -1 && FD_ISSET(secure_tab[i].s, &fdr) &&
           secure_tab[i].active != '\0')
        chat_read(i); */
    

    signal(SIGALRM, gotalarm);

    return;
}

void sendit(pkt)
     char *pkt;
{
    switch (_sendpacket(sock, pkt)) {
        case 1:
        /* ok */
            break;
        case 0:
        /* incomplete packet */
            fprintf(stderr, "DEBUG: send blocked  - panic stop\n");
            exit(1);
            break;
        case -1:
        /* error */
            fprintf(stderr, "DEBUG: error in send - panic stop\n");
            exit(1);
            break;
        case -2:
        /* lost connection */
            fprintf(stderr, "server connection lost - bye\n");
            shutdown(sock, 2);
            close(sock);
            exit(1);
    }

    return;
}

SIGTYPE gotalarm()
{
    timeisup = 1;
    signal(SIGALRM, gotalarm);
}

/* disconnect from the server */
void closecon()
{
    shutdown(sock, 2);
    close(sock);
    return;
}
