
#include "queso.h"

/***************************************************************************/

static const char *_version = VERSTAG;

struct Library *SocketBase;
struct Library *MiamiBase;
struct LocaleBase *LocaleBase;

struct Catalog *cat;

/***************************************************************************/

int main(int argc,char **argv)
{
    struct global           g;
    register char           *s, *p;
    char                    *endptr;
    register LONG           err;
    register int            res, c;
    register unsigned short port;

    /* start */
    memset(&g,0,sizeof(g));
    g.this = (struct Process *)FindTask(NULL);

    /* init stdout and sterr */
    g.stdOut = Output();

    if (g.stdErr = Open("CONSOLE:",MODE_NEWFILE)) g.flags  = QFLG_CloseStderr;
    else g.stdErr = g.stdOut;

    /* localization */
    if (LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",36))
        cat = OpenCatalogA(NULL,CATNAME,NULL);

    /* Miami must be running */
    if (!(SocketBase = OpenLibrary("bsdsocket.library",4)) ||
        !(MiamiBase = OpenLibrary("miami.library",6)))
    {
        res = RETURN_FAIL;
        err = ERR_NoBSDSocket;
        goto end;
    }

    /* allocate a signal */
    if ((g.sigBit = AllocSignal(-1))==-1)
    {
        res = RETURN_FAIL;
        err = ERR_NoMem;
        goto end;
    }
    g.flags |= QFLG_FreeSig;

    /* defaults */
    g.cfgFile = DEF_CFGFILE;
    g.timeout = DEF_TIMEOUT;
    g.times   = DEF_TIMES;
    g.delay   = DEF_DELAY;
    g.defPort = DEF_PORT;

    /* parse arguments */
    g.opterr = g.optind = 1;
    while ((c = getopt(&g,argc,argv,"vhdkVwt:p:z:n:c:"))!=EOF)
    {
        switch (c)
        {
            case 'v':
                FPrintf(g.stdOut,getString(STRING_Version),VRSTRING,DATE);
                res = RETURN_OK;
                err = 0;
                goto end;

            case 'h':
                FPrintf(g.stdOut,getString(STRING_Help),getString(STRING_Usage),DEF_TIMEOUT,DEF_PORT,DEF_DELAY,DEF_TIMES,DEF_CFGFILE);
                res = RETURN_OK;
                err = 0;
                goto end;

            case 'd':
                g.flags |= QFLG_Debug;
                break;

            case 'k':
                g.flags |= QFLG_CfgDebug;
                break;

            case 'V':
                g.flags |= QFLG_Verbose;
                break;

            case 'w':
                g.flags |= QFLG_CfgUpdate;
                break;

            case 't':
                g.timeout = strtoul(g.optarg,&endptr,10);
                if (*endptr || (g.timeout<0))
                {
                    printErr(&g,ERR_BadTimeout,g.optarg,DEF_TIMEOUT);
                    g.timeout = DEF_TIMEOUT;
                }
                break;

            case 'p':
                g.defPort = strtoul(g.optarg,&endptr,10);
                if (*endptr || (g.defPort<1) || (g.defPort>65535))
                {
                    printErr(&g,ERR_BadPort,g.optarg,DEF_PORT);
                    g.defPort = DEF_PORT;
                }
                break;

            case 'z':
                g.delay = strtoul(g.optarg,&endptr,10);
                if (*endptr || (g.delay<0))
                {
                    printErr(&g,ERR_BadDelay,g.optarg,DEF_TIMES);
                    g.delay = DEF_TIMES;
                }
                break;

            case 'n':
                g.times = strtoul(g.optarg,&endptr,10);
                if (*endptr || (g.times<0))
                {
                    printErr(&g,ERR_BadTimes,g.optarg,DEF_TIMES);
                    g.times = DEF_TIMES;
                }
                break;

            case 'c':
                g.cfgFile = g.optarg;
                break;

            default:
                FPrintf(g.stdOut,getString(STRING_Usage));
                res = RETURN_ERROR;
                err = 0;
                goto end;
        }
    }

    /* hosts? */
    if (g.optind>=argc)
    {
        printErr(&g,ERR_NoHostSupplied);
        FPrintf(g.stdErr,getString(STRING_Usage));
        res = RETURN_ERROR;
        err = 0;
        goto end;
    }

    /* open cfgfile */
    if (!(g.cfile = Open(g.cfgFile,MODE_OLDFILE)) &&
        (g.flags & QFLG_CfgUpdate) &&
        (g.cfile = Open(g.cfgFile,MODE_READWRITE))) printErr(&g,STRING_Created,g.cfgFile);
    if (!g.cfile)
    {
        printErr(&g,ERR_NoFile,g.cfgFile);
        res = RETURN_ERROR;
        err = 0;
        goto end;
    }

    /* init TCP/IP */
    if (err = initTCPIP(&g))
    {
        res = RETURN_FAIL;
        goto end;
    }

    /* init our port */
    INITPORT(&g.port,g.sigBit);

    /* create a timer */
    if (err = createTimer(&g))
    {
        res = RETURN_FAIL;
        goto end;
    }

    /* print info */
    if (g.flags & QFLG_Verbose)
        FPrintf(g.stdErr,getString(STRING_Info),
            g.cfgFile,(g.flags & QFLG_CfgUpdate) ? getString(STRING_UpdateMode) : (STRPTR)"",
            g.defPort,
            g.timeout,
            g.times,
            g.delay);

    /* init rand */
    srand(time(NULL));

    /* init semaphore (needed by packets monitor) */
    InitSemaphore(&g.sem);

    /* here we go (XXX "err = 0" could be omitted) */
    for (err = 0; !err && argv[g.optind]; g.optind++)
    {
        /* flush files */
        Flush(g.stdErr);
        Flush(g.stdOut);

        /* first host */
        s = argv[g.optind];

        /* "host:port" ? */
        if (p = strchr(s,':'))
        {
            *p = 0;

            port = strtoul(++p,&endptr,10);
            if (*endptr || (port<1) || (port>65535))
            {
                printErr(&g,ERR_BadPort,port,DEF_PORT);
                port = g.defPort;
            }
        }
        else port = g.defPort;

        /* resolve host */
        if (err = resolve(&g,s,&g.dest))
        {
            printErr(&g,err,s);
            err = 0;
            continue;
        }

        /* find if */
        if (err = ip2if(&g))
        {
            if (err==ERR_UnreachebleHost)
            {
                printErr(&g,ERR_UnreachebleHost,s);
                err = 0;
                continue;
            }

            res = RETURN_FAIL;
            goto end;
        }

        /* check it */
        if (err = checkOS(&g,port))
        {
            if (err==STRING_NotAccurate)
            {
                if (g.flags & QFLG_Verbose) printErr(&g,STRING_NotAccurate,s);
                err = 0;
            }
            else
            {
                res = RETURN_FAIL;
                goto end;
            }
        }
    }

    res = RETURN_OK;

end:
    return cleanExit(&g,res,err);
}

/***************************************************************************/
