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

#include "4m.h"
#include "externs.h"
#include "ctcp.h"
#include "../h/term.h"
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "../common/select.h"

extern fd_set fdset;

extern int accept();

extern void dispatch ();
extern int check_mail ();
extern void putl ();
extern void do_exit ();
extern void exitmsg ();
extern int do_edit ();
extern void *memset ();
extern int close ();
extern time_t time ();
extern int read ();
extern int write ();
extern char *strncpy ();
extern char *strcat ();
extern void cipher ();
extern void decipher ();

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

extern int parse_packet ();
extern int getline ();
extern void mbreakprint ();
extern void xfer_erase ();

void 
c_packet(pkt)
     char *pkt;
{
    dispatch(pkt);
}

void 
c_didpoll()
{
    extern int status();

    if (check_mail())
        status(1);
    else
        status(0);
}

void 
c_lostcon()
{
    putl("[Lost connection with the server]", PL_ALL);
    do_exit();
}

void 
c_userchar()
{
    int ret;
    static char s[MAX_INPUTSTR + 1];  /* user input string */
    extern char inputbuffer[];

    if (dumb) {
        if ((ret = getline(s, NULL, 1)) < 0)
            exitmsg();  /* EOF on stdin */

        else if (ret == 0)  /* user killed line */
            return;
        else
            parse_packet(s);
    } else {
        gotoxy(ipos, lines - 2);
        if ((ret = do_edit())) {
            if (parse_packet(inputbuffer) != -1) {
               memset(inputbuffer, 0, MAX_INPUTSTR);
               inputbuf = inputbuffer;
              *inputbuf = '\0';
               ipos = 0;
               gotoxy(ipos, lines - 2);
               clear_eol();
               gotoxy(ipos, lines - 2);
            }
        } else
            gotoxy(ipos, lines - 2);
    }
}

void c_xfersend(xindex)
     int xindex;
{
    struct sockaddr_in remaddr;
    int sra, ret, ns;
    char buffer[1024 + 1], filename[20];
    u_long bytesrecvd;
    double sent;

    if (xfer_tab[xindex].status == WAIT) {
        sra = sizeof(struct sockaddr_in);
        ns = accept(xfer_tab[xindex].s, (struct sockaddr *) & remaddr, &sra);
        FD_CLR(xfer_tab[xindex].s, &fdset);
        close(xfer_tab[xindex].s);
        xfer_tab[xindex].s = ns;
        FD_SET(xfer_tab[xindex].s, &fdset);
        sprintf(mbuf, "[Xfer] Data transfer connection established to %s.",
                xfer_tab[xindex].who);
        putl(mbuf, PL_ALL);

        if ((xfer_tab[xindex].fd = open(xfer_tab[xindex].filename, O_RDONLY)) == -1) {
            sprintf(mbuf, "[Send] Unable to open %s (aborting send).",
                    xfer_tab[xindex].filename);
            putl(mbuf, PL_ALL);
            close(xfer_tab[xindex].fd);
            FD_CLR(xfer_tab[xindex].s, &fdset);
            close(xfer_tab[xindex].s);
            xfer_erase(xindex);
            return;
        }
        xfer_tab[xindex].status = ACTIVE;
        xfer_tab[xindex].bytes = 0L;
        xfer_tab[xindex].start = time(NULL);
    } else {
        if (read(xfer_tab[xindex].s, &bytesrecvd, sizeof(u_long)) < sizeof(u_long)) {
            sprintf(mbuf, "[Xfer] Connection lost for \"%s\" to %s.",
                    xfer_tab[xindex].filename, xfer_tab[xindex].who);
            putl(mbuf, PL_ALL);
            close(xfer_tab[xindex].fd);
            FD_CLR(xfer_tab[xindex].s, &fdset);
            close(xfer_tab[xindex].s);
            xfer_erase(xindex);
            return;
        } else if (ntohl(bytesrecvd) != xfer_tab[xindex].bytes)
            return;
    }

    if ((ret = read(xfer_tab[xindex].fd, buffer, 1024 + 1)) > 0) {
        write(xfer_tab[xindex].s, buffer, ret);
        xfer_tab[xindex].bytes += ret;
    } else {
        sent = (double) xfer_tab[xindex].size;
        sent /= (double) 1024.0;
        xfer_tab[xindex].end = time(NULL) - xfer_tab[xindex].start;
        if (xfer_tab[xindex].end <= 0)
            xfer_tab[xindex].end = 1;

        if (strlen(xfer_tab[xindex].filename) > 10) {
            strncpy(filename, xfer_tab[xindex].filename, 10);
            if (strlen(xfer_tab[xindex].filename) > 10)
                filename[10] = 0;
            strcat(filename, "...");
        } else
            strcpy(filename, xfer_tab[xindex].filename);

        sprintf(mbuf, "[Xfer] Transfer of \"%s\" to %s complete.",
                filename, xfer_tab[xindex].who);
        putl(mbuf, PL_ALL);
        sprintf(mbuf, "[Xfer] %d bytes received in %d seconds (%2.4g Kbytes/s).",
                xfer_tab[xindex].size,
                xfer_tab[xindex].end,
                (sent / (double) xfer_tab[xindex].end));
        putl(mbuf, PL_ALL);

        close(xfer_tab[xindex].fd);
        FD_CLR(xfer_tab[xindex].s, &fdset);
        close(xfer_tab[xindex].s);
        xfer_erase(xindex);
    }
}

void c_xferget(xindex)
     int xindex;
{
    char buffer[1024 + 1];
    struct stat stb;
    int ret;
    u_long bytesrecvd;
    double sent;

    if (xfer_tab[xindex].status == WAIT) {
        if ((xfer_tab[xindex].fd = open(xfer_tab[xindex].filename,
                            O_WRONLY | O_TRUNC | O_CREAT, 0666)) == -1) {
            sprintf(mbuf, "[Get] Unable to open %s (aborting get).",
                    xfer_tab[xindex].filename);
            return;
        }
        xfer_tab[xindex].status = ACTIVE;
        xfer_tab[xindex].bytes = 0L;
        xfer_tab[xindex].start = (long) time(NULL);
    }
    ret = read(xfer_tab[xindex].s, buffer, 1024 + 1);

    if (ret > 0) {
        write(xfer_tab[xindex].fd, buffer, ret);
        xfer_tab[xindex].bytes += ret;
        bytesrecvd = htonl(xfer_tab[xindex].bytes);
        write(xfer_tab[xindex].s, &bytesrecvd, sizeof(u_long));
        return;
    }
    stat(xfer_tab[xindex].filename, &stb);
    xfer_tab[xindex].bytes = stb.st_size;
    sent = (double) xfer_tab[xindex].bytes;
    sent /= (double) 1024.0;
    xfer_tab[xindex].end = time(NULL) - xfer_tab[xindex].start;
    if (xfer_tab[xindex].end <= 0)
        xfer_tab[xindex].end = 1;

    sprintf(mbuf, "[Xfer] Transfer of \"%s\" from %s complete.",
            xfer_tab[xindex].filename, xfer_tab[xindex].who);
    putl(mbuf, PL_ALL);

    sprintf(mbuf, "[Xfer] %d bytes received in %d seconds (%2.4g Kbytes/s).",
            xfer_tab[xindex].bytes,
            xfer_tab[xindex].end,
            (sent / (double) xfer_tab[xindex].end));
    putl(mbuf, PL_ALL);

    close(xfer_tab[xindex].fd);
    FD_CLR(xfer_tab[xindex].s, &fdset);
    close(xfer_tab[xindex].s);
    xfer_erase(xindex);
}

void chat_write(slot, text)
     int slot;
     char *text;
{
    if (secure_tab[slot].crypt)
        cipher(text, strlen(text), secure_tab[slot].key);

    _sendpacket(secure_tab[slot].s, text);
}

void chat_read(slot)
     int slot;
{
    struct sockaddr_in remaddr;
    int sra, ret, ns;
    char buffer[1024 + 1];

    if (secure_tab[slot].status == WAIT && secure_tab[slot].initiator) {
        sra = sizeof(struct sockaddr_in);
        ns = accept(secure_tab[slot].s, (struct sockaddr *) & remaddr, &sra);
        FD_CLR(secure_tab[slot].s, &fdset);
        close(secure_tab[slot].s);
        secure_tab[slot].s = ns;
        FD_SET(secure_tab[slot].s, &fdset);
        sprintf(mbuf, "[Chat] Secure link established with %s.",
                secure_tab[slot].who);
        putl(mbuf, PL_ALL);
        secure_tab[slot].status = ACTIVE;
        secure_tab[slot].bytes = 0L;
        secure_tab[slot].start = time(NULL);
        return;
    }
    ret = _readpacket(secure_tab[slot].s, buffer);

    if (ret > 0) {
        if (secure_tab[slot].crypt)
            decipher(buffer, strlen(buffer), secure_tab[slot].key);

        mbreakprint(3, secure_tab[slot].who, buffer);
        return;
    }
    secure_tab[slot].status = -1;
    secure_tab[slot].active = 0;
    close(secure_tab[slot].s);
    FD_CLR(secure_tab[slot].s, &fdset);
    sprintf(mbuf, "[Chat] Connection lost with %s.", secure_tab[slot].who);
    putl(mbuf, PL_ALL);
}
