/*  QWKImport.c
 */

#include <exec/types.h>
#include <clib/exec_protos.h>
#include <dos/dos.h>
#include <clib/dos_protos.h>
#include <libraries/ums.h>
#include <clib/ums_protos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <ctype.h>

#include "QWKImport.v"

extern ULONG *RDArgs_Array;
char *RDArgs_Template = "SITE/A,PASSWORD,SERVER/K,KEEP/S";
char *RDArgs_Help =
"$VER: QWKImport "__VERSION__" ("__COMMODORE_DATE__") © 1993, 1994 Iain Hibbert\n"
"\n"
"  SITE         BBS to Import from (\"qwk.\" is prepended to make the username)\n"
"  PASSWORD     Password\n"
"  SERVER       Server\n"
"  KEEP         Keep the .QWK bundle after importing\n"
"\n";

#define Site        ((char *)RDArgs_Array[0])
#define Password    (RDArgs_Array[1] ? (char *)RDArgs_Array[1] : "")
#define Server      ((char *)RDArgs_Array[2])
#define Keep        ((BOOL)RDArgs_Array[3])

struct conference {
    int number;
    char name[13];
};

void chkabort(void) { } // disable ^C checking for DICE

//  ReadUMSVar()
//              a wrapper for ReadUMSConfig that is guaranteed to return
//  a default, just so I don't have to check the return value.
//
char *
ReadUMSVar(UMSUserAccount login, char *varname, char *def)
{
char *t1 = ReadUMSConfigTags(login, UMSTAG_CfgName, varname, TAG_DONE);
char *t2 = NULL;

    if( t1 ) {
        t2 = strdup(t1);
        FreeUMSConfig(login, t1);
    }

    return( t2 ? t2 : def);
}

//  command()
//           takes printf style arguments, assembles the command in its
//           buffer, prints it in highlighted colour, and executes it.
void
command(char *fmt, ...)
{
va_list va;
char buffer[256];

    va_start(va,fmt);

    vsprintf(buffer, fmt, va);
    printf("\033[2m> %s\033[0m\n", buffer);
    system(buffer);

    va_end(va);
}

// neaten_case()
//              converts 'IAIN HIBBERT' to 'Iain Hibbert' etc..
//
void
neaten_case(char *string)
{
int caps = TRUE;

    while( *string ) {
        if( caps ) {
            *string = (char)toupper(*string);
            caps = FALSE;
        }
        else
            *string = (char)tolower(*string);

        if( !isalpha(*string) ) caps = TRUE;
        string++;
    }
}

// getfield()
//              extract a portion of the buffer, with null termination
//              and trailing space stripping
char *
getfield(char *buffer, unsigned char *to, int size, int offset)
{
unsigned char *p = to + size - 1;

    strncpy(to, buffer + offset, size - 1);

    do {
        *p-- = '\0';
    } while( p > to && *p == ' ' );

    return(to);
}

//  do_Import()
//              do the actual importing to UMS
int
do_Import(UMSUserAccount login)
{
FILE *Mp, *Cp;
int err = 0, succ = 0;
struct conference *conf = NULL;
char *nohiconf = ReadUMSVar(login, "qwk.no-hi-conf", "N");

    Cp = fopen("CONTROL.DAT", "r");
    if( Cp ) {
    int c, areas;
    unsigned char line[256];

        printf("Scanning CONTROL.DAT for groupnames\n");

        for( c = 0 ; c < 11 ; c++ )
            fgets(line, sizeof(line), Cp);

        sscanf(line, "%d", &areas);
        areas += 1;

        conf = calloc(sizeof(struct conference), areas + 1);
        if( conf ) {
            for( c = 0 ; c < areas ; c++ ) {
            unsigned char *p = line;

                fgets(line, sizeof(line), Cp);
                sscanf(line, "%d", &conf[c].number);

                fgets(line, sizeof(line), Cp);

                while( *p ) p++;
                while( p-- > line && isspace(*p) ) *p = '\0';

                strncpy(conf[c].name, line, 12);
            }

            conf[c].number = -1;
        }

        fclose(Cp);
    }

    Mp = fopen("MESSAGES.DAT", "r");
    if( Mp ) {
    char addr[32];
    unsigned char hdr[128], *text = NULL;
    int maxblocks = 0;

        printf("Importing MESSAGES.DAT\n");

        sprintf(addr, "%s@qwk", Site);

        // the packet header
        fread(hdr, sizeof(hdr), 1, Mp);
        printf("%.*s\n", sizeof(hdr), hdr);

        // message loop
        while( fread(hdr, sizeof(hdr), 1, Mp) ) {
        char from[26], to[26], subject[26], date[9], time[6];
        char created[20], group[128], *attributes;
        int blocks, area;
        struct conference *c = conf;

            neaten_case(getfield(hdr, from, sizeof(from), 46));
            neaten_case(getfield(hdr, to, sizeof(to), 21));
            getfield(hdr, subject, sizeof(subject), 71);

            getfield(hdr, date, sizeof(date), 8);
            getfield(hdr, time, sizeof(time), 16);
            sprintf(created, "%s %s", time, date);

            area = (nohiconf[0] == 'Y' ? 0x00 : hdr[124]) * 256 + hdr[123];

            while( TRUE ) {
                if( !c || c->number == -1 ) {
                    sprintf(group, "qwk.%s.%d", Site, area);
                    break;
                }
                if( c->number == area ) {
                    sprintf(group, "qwk.%s.%d `%s'", Site, area, c->name);
                    break;
                }
                c++;
            }

            if( hdr[0] == '*' || hdr[0] == '+' )
                attributes = "private";
            else
                attributes = "";

            sscanf(hdr + 116, "%6d", &blocks);
            blocks -= 1;

            // make sure we have enough memory for the message text
            if( blocks > maxblocks ) {
                text = realloc(text, blocks * 128 + 1);
                maxblocks = blocks;
                if( !text ) {
                    fprintf(stderr, "ERROR: Out of Memory\n");
                    err = 1;
                    break;
                }
            }

            if( fread(text, 128, blocks, Mp) ) {
            unsigned char *ptr;

                text[blocks * 128] = '\0';

                // convert #227 to newline
                for( ptr = text ; *ptr ; ptr++ )
                    if( *ptr == 227) *ptr = '\n';

                // strip trailing spaces
                while( ptr > text && *--ptr == ' ' )
                    *ptr = '\0';

                if( WriteUMSMsgTags(login, UMSTAG_WFromName,     from,
                                           UMSTAG_WFromAddr,     addr,
                                           UMSTAG_WToName,       to,
                                           UMSTAG_WSubject,      subject,
                                           UMSTAG_WGroup,        group,
                                           UMSTAG_WCreationDate, created,
                                           UMSTAG_WAttributes,   attributes,
                                           UMSTAG_WMsgText,      text,
                                           TAG_DONE) ) {
                    printf(".");
                    fflush(stdout);
                    succ++;
                }
                else {
                    printf("ERROR: #%d, %s\n", UMSErrNum(login), UMSErrTxt(login));
                    err++;
                }
            }
            else {
                fprintf(stderr, "ERROR: Read Error on MESSAGES.DAT\n");
                err++;
                break;
            }
        }

        if( text ) free(text);
        fclose(Mp);
    }
    else
        fprintf(stderr, "ERROR: MESSAGES.DAT not found!\n");

    printf("\nImported %d message%s, with %d error%s\n", succ, succ == 1 ? "" : "s", err, err == 1 ? "" : "s");

    if( conf ) free(conf);
    return(err);
}

// main()
//          CLI entry point.
int
main(int ac, char *av[])
{
char name[128];
UMSUserAccount login;

    sprintf(name, "qwk.%s", Site);
    login = UMSRLogin(Server, name, Password);

    if( login > 0 ) {
    char *inbound = ReadUMSVar(login, "qwk.inbound", "Comms:Downloads/");
    char *unpacker = ReadUMSVar(login, "qwk.unpacker", "lharc x %s");
    char *tempdir = ReadUMSVar(login, "qwk.tempdir", "T:");
    char *keeppacket = ReadUMSVar(login, "qwk.keeppacket", "No");
    char filename[256];
    int err;

        sprintf(filename, "%s%s.QWK", inbound, Site);
        if( access(filename, 4) == 0 ) {

            if( chdir(tempdir) == 0 || ((mkdir(tempdir, 0) == 0) && (chdir(tempdir) == 0)) ) {

                command(unpacker, filename);

                err = do_Import(login); // scan MESSAGES.DAT

                command("delete #? force");

                if( !err && !Keep && *keeppacket != 'Y')
                    command("delete %s force", filename);
            }
            else
                fprintf(stderr, "Can't CD to %s!\n", tempdir);
        }

        UMSLogout(login);
    }
    else
        fprintf(stderr, "Can't login as %s\n", name);

    exit(0);
}
