/*
 * this file is a part of yabbs - yet another bulletin board system.
 * Copyright (C) 1993, 1994 Alex Wetmore.  
 * email: alex@phred.org
 * address: 6 rech ave
 *          oreland pa 19075
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * sockets interface for yabbslib
 */


#include <stdio.h>                          /* standard i/o stuff           */
#include <unistd.h>                         /* more standard stuff          */
#include <stdlib.h>                         /* standard library             */
#include <strings.h>                        /* string utils                 */
#include <time.h>                           /* time stuff                   */
#include <socket.h>                         /* DJGPP socket support         */
#include <stdarg.h>                         /* variable argument macros     */
#include <errno.h>                          /* error numbers (EAGAIN)       */

#include "yabbslib.h"                       /* yabbslib definations         */
extern int  bbs_s;                          /* server socket                */
extern char bbs_waitkey[64];                /* message to wait for          */
extern int  bbs_debug;                      /* don't print debug messages   */
extern int  bbs_loggedout;                  /* set when we have logged out  */

#define send(s, buf, len, flags) write_s(s, buf, len)

/*
 * read one character from a socket.  busywaits until there is a character
 * there.
 */
int readone(int s, char *c) {
    int i;

    do {
        i = read_s(s, c, 1);
    } while ((i == -1) && (errno == EAGAIN));

    return i;
}


/*
 * function: bbsi_csendp(int n, char *key, char *command, char *arg, ...);
 * input:    n is the number of arguments (including the command)
 *           key a key used by the server when responding to this message
 *           command is the command to do
 *           args are a variable number of arguments for the command
 *
 * notes:    for more information on this see the protocol documentation if
 *           they're ever written.
 */
void bbsi_csendp(int n, char *key, char *command, ...) {
    va_list ap;
    char *parameter, p2[1024], buf[1024];
    int i, x, y;

    va_start(ap, command);
    strcpy(buf, key); strcat(buf, ":");
    strcat(buf, command);

    for (i = 1; i < n; i++) {
        strcat(buf, ":"); 
        parameter = va_arg(ap, char *);
        for (x = 0, y = 0; parameter[x] != 0; x++) {
            if (parameter[x] == ':') p2[y++] = '\\'; 
            if (parameter[x] == '\\') p2[y++] = '\\'; 
            p2[y++] = parameter[x];
        }
        p2[y] = 0;
        strcat(buf, p2);
    }
    strcat(buf, "\n");
    if (bbs_debug & DBG_SEND) printf("send: %s", buf);
    send(bbs_s, buf, strlen(buf), 0);
}

/*
 * function: char *bbsi_creadp()
 * returns:  a pointer to a string from the server
 * notes:    the string is statically allocated
 */
char *bbsi_creadp() {
    int reading = 1, i = 0;
    char x, c;
    static char buf[1024];

    /* read characters until we get a NL or end of a packet                 */
    while (reading) {
        x = readone(bbs_s, &c);
        if ((x < 1) || (c == '\n') || (i == 510)) reading = 0;
        else buf[i++] = c;
    }
    buf[i] = 0;

    /* bleed off any extra characters before the packet end                 */
    if ((c != '\n') && (i == 510))
        do readone(bbs_s, &c); while (c != '\n');

    /* if we read 0 characters then the server died                         */
    if (i == 0) {
        if (!bbs_loggedout) 
            cli_fatalerror("The yabbs server closed your connection.");
        else cli_fatalerror("connection closed");
    }

    if (bbs_debug & DBG_RECV) printf("recv: %s\n", buf);
    return buf;
}

/*
 * function: bbs_connect_port(char *server, int port);
 * input:    server - the server to connect to
 *           port - the port to connect to
 * returns:  none
 * notes:    if this couldn't connect it will return a fatal error explaining
 *           why.
 */
void bbs_connect_port(char *server, int port) {
    struct sockaddr_in sin, peersin;
    longword hostip;

    SocketInit();
    if (!(hostip = resolve(server))) {
        cli_fatalerror("yabbslib: bbs_connect: invalid server hostname\n");
        return;
    }
    hostip = intel(hostip);
    bzero((char *) &sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = 9664;

    peersin.sin_family = AF_INET;
    peersin.sin_addr.s_addr = hostip;
    peersin.sin_port = htons(port);

    bbs_s = socket(AF_INET, SOCK_STREAM, 0);

    if (bind(bbs_s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
        cli_fatalerror("yabbslib: bbs_connect: bind failed\n");
        return;
    }

    if (connect(bbs_s, (struct sockaddr *) &peersin, sizeof(peersin)) == -1) {
        cli_fatalerror("The yabbs server is down.  Try again later.");
        return;
    }

    strcpy(bbs_waitkey, "_NEWCLI");
    if (!bbs_handlemsg()) {
        cli_fatalerror("Doesn't look like a yabbs server");
    }
}

/*
 * function: bbs_done()
 * input:    none
 * returns:  none
 * notes:    this should be called when host program is done with the yabbs
 *           library.
 */
void bbs_done(void) {
    SocketClose();
}
