// $Id: util.c,v 1.75 2014/05/21 20:17:01 lpoulsen Exp $
// Copyright (c) 2014 Afar Communications Inc, Santa Barbara, CA 93117 USA
// Copyright (c) 2012 Afar Communications Inc, Santa Barbara, CA 93117 USA
// Copyright (c) 2011 Afar Communications Inc, Santa Barbara, CA 93117 USA
// Copyright (c) 2008 Afar Communications Inc, Santa Barbara, CA 93117 USA

#ifdef OEM
#define OEM_COMPANY "Afar Communications, Inc"
#endif

// $Log: util.c,v $
// Revision 1.75  2014/05/21 20:17:01  lpoulsen
// Update copyright notice year to say 2014
//
// Revision 1.74  2014/05/21 20:05:57  lpoulsen
// uint32 is not long anymore, so remove long qualifiers in printf formats
//
// Revision 1.73  2013/03/22 21:46:57  lpoulsen
// Make -i filename work together with -r name
//
// Revision 1.72  2013/03/22 17:37:17  lpoulsen
// Allow "econ -r name" to make one connection with the named radio
//     without ever entering the Econsole> command prompt.
//
// Revision 1.71  2012/05/08 18:24:00  lpoulsen
// Compile all modules with -pthread on Linux
// Clean up all compiler warnings
// Count packets in OUT OF MEMORY message
//
// Revision 1.70  2012/04/19 20:20:22  lpoulsen
// Move declaration of console_out_filename[] from util.c to connect.c
//
// Revision 1.69  2011/07/08 22:54:27  lpoulsen
// Change command line option -d to take a string argument for initial
//     value of debug_flags (instead of making it count up debug_level).
//
// Revision 1.68  2011/07/08 21:50:30  lpoulsen
// Eliminate (almost all) use of debug_level, use debug_flags instead.
//
// Revision 1.67  2011/05/09 19:32:27  lpoulsen
// Reject device range (1-7) where a single radio is required
//
// Revision 1.66  2011/05/06 22:15:14  lpoulsen
// Preparing for ECON 04.07 release
//
// Revision 1.65  2011/03/22 00:26:10  lpoulsen
// Resolve sequence errors on very weak links
// Resolve hangs when Ctrl-C between "dir" and "download"
// Resolve conflicting build date information
//
// Revision 1.64  2011/02/23 20:38:10  lpoulsen
// Suppress a debug message for normal users
//
// Revision 1.63  2011/02/21 22:32:41  lpoulsen
// Get rid of compiler warnings
//
// Revision 1.62  2011/02/04 22:29:07  lpoulsen
// Many little fixes.
//
// Revision 1.61  2010/12/22 17:36:34  lpoulsen
// Select/Deselect list of ranges
// Expand to up to 511 radios
// Protocol fixes
//
// Revision 1.60  2009/06/15 22:08:08  lpoulsen
// Add fixes to work on Vista64
//
// Revision 1.59  2008/08/05 23:58:37  lpoulsen
// User interface updates.
//
// Revision 1.58  2008/07/30 07:11:42  lpoulsen
// New option "Connect keyboard=yes"
// Fixes for timeout probelm at end of file.
//
// Revision 1.57  2008/07/25 00:43:27  lpoulsen
// Added "select all" and "edit" commands.
// Optional OEM_COMPANY personalization
//
// Revision 1.56  2008/07/16 23:26:08  lpoulsen
// Only one cvs_tag variable allowed. Use the one in cmd_loop.cpp
//
// Revision 1.55  2008/07/11 17:10:27  lpoulsen
// Resolve compiler warnings.
//
// Revision 1.54  2008/07/11 16:28:46  lpoulsen
// Econ 4.00 release candidate supports UPDATE and SELECT commands.
//
// Revision 1.53  2008/06/10 00:06:10  lpoulsen
// New -X option is now working
// Updated -I and -O implementation
//
// Revision 1.52  2008/05/31 00:35:09  lpoulsen
// Econ 4.x preview - now with command shell
//
// Revision 1.51  2008/05/10 01:17:37  lpoulsen
// Making econ -x filename work (not yet complete)
//
// Revision 1.50  2008/04/26 00:48:25  lpoulsen
// Rename selectedAdapterId global var to option_C
//
// Revision 1.49  2007/05/15 18:53:00  lpoulsen
// ECON98 version 03.05
//     Now correctly enumerates the devices on Windows98 first edition.
//
// Revision 1.48  2006/10/05 17:45:22  lpoulsen
// Increase buffer size for XP GetAdapterInfo call
//
// Revision 1.47  2006/06/06 02:03:29  lpoulsen
// First attempt at compiling on MAC OS X
//
// Revision 1.46  2006/04/27 19:27:14  lpoulsen
// Allow for pathnames longer than 24 bytes.
//
// Revision 1.45  2006/02/20 22:31:27  lpoulsen
// Add macro definition for _ftol2() for VC6 / VC7 library compatibility
//
// Revision 1.44  2005/05/11 17:04:33  lpoulsen
// Solve problems on WinXP by moving to WinPCap 3.1 beta 4
// Use IP helper API to get MAC addresses (no longer works on Win95)
// Change references to "radios" to say "devices"
//
// Revision 1.43  2005/05/09 23:23:19  lpoulsen
// Our website is now at http://www.afar.net
//
// Revision 1.42  2004/07/13 18:56:14  lpoulsen
// Fix copyright date to 2004
//
// Revision 1.41  2004/07/13 18:37:22  lpoulsen
// Fix bug where F3 or F4 did not send CLOSE_REQUEST
//
// Revision 1.40  2003/12/23 04:35:42  lpoulsen
// EConsole protocol version 2 support.
// Respond to IDENTIFY_REQUEST (version 1 and version 2 format) with
//      version 2 format IDENTIFY_RESPONSE.
//
// Revision 1.39  2003/12/17 18:19:08  lpoulsen
// Respond to IDENTIFY_REQUEST (to support "show econ" on radio/mux)
//
// Revision 1.38  2003/08/25 18:07:36  lpoulsen
// Removed the dummy malloc() of 1MB that was immediately free'd
//
// Revision 1.37  2003/08/21 23:46:51  lpoulsen
// Improved handling of -r option to allow selection by name
// Miscellaneous minor cleanup
//
// Revision 1.36  2003/08/19 03:08:25  lpoulsen
// Remove many compiler warnings.
//
// Revision 1.35  2003/03/11 01:31:58  lpoulsen
// Correct compile warnings. (Some remain.)
//
// Revision 1.34  2003/03/11 01:14:13  lpoulsen
// Correct compile errors found in Calgary.
//
// Revision 1.33  2002/10/16 16:59:47  mourlouk
// Improved way of retrieving MAC addresses - VAL support
//
// Revision 1.31  2002/05/21 19:52:27  lpoulsen
// Fix for PSR int236: Econsole uses 100% CPU
//     Code inspection confirmed that the thread that reads from the
//     console terminal has set the TTY to always return immediately
//     from a read. After changing the TTY mode to return only if
//     a character was received or 200 ms passed, CPU usage has
//     dropped to the expected minimal amount.
// Also some readability cleanup.
//
// Revision 1.30  2002/05/21 17:53:50  lpoulsen
// Fix many compiler warnings.
//
// Revision 1.29  2002/05/20 20:23:32  lpoulsen
// Clean up version banner.
//
// Revision 1.28  2002/05/16 17:14:58  mourlouk
// 1.19 Release candidate
//
// Revision 1.27  2002/05/15 00:22:16  mourlouk
// Ok, finished with the linux compilation
//
// Revision 1.26  2002/05/14 23:44:01  mourlouk
// more minor changes ...
//
// Revision 1.25  2002/05/14 23:21:14  mourlouk
// *** empty log message ***
//
// Revision 1.24  2002/04/23 21:51:30  mourlouk
// Another bug fixed: We discarding invalid CLOSE REQUEST messages, that
// were resulting in "Connection with other host terminated", and also
// changed code in alreadyReceivedMessage
//
// Revision 1.23  2002/04/19 19:04:44  mourlouk
// Release 1.15 - It fixes a bug that was introduced in version 1.13
// (econ unable to read properly multiple MAC addresses)
//
// Revision 1.21  2001/11/30 19:53:15  lpoulsen
// Fix bug in argument processing for -c <adapter>
//
// Revision 1.20  2001/11/30 19:27:46  lpoulsen
// Allow "econ -c 1" to specify adapter #1 on command line.
//
// Revision 1.19  2001/11/14 22:48:17  mourlouk
// Add some code to check the number of command line arguments
//
// Revision 1.18  2001/11/13 01:40:26  lpoulsen
// Fix version printout
//
// Revision 1.16  2001/11/13 00:38:51  mourlouk
// ....................
//
// Revision 1.15  2001/11/12 22:52:32  mourlouk
// making compiler happy (I)
//
// Revision 1.14  2001/11/10 01:06:08  mourlouk
// ......
//
// Revision 1.13  2001/11/09 19:03:02  mourlouk
// .........
//
// Revision 1.12  2001/11/07 00:02:41  mourlouk
// Fixed a small bug on Linux client - now if an error occurs, and return
//    to Linux environment, everything is normal
//
// Revision 1.11  2001/11/06 23:24:23  mourlouk
// ....
//
// Revision 1.10  2001/11/06 22:59:08  mourlouk
// ...
//
// Revision 1.9  2001/11/06 18:20:24  mourlouk
// commented "setconsoletitle" for linux
//
// Revision 1.8  2001/11/02 19:38:22  mourlouk
// Nothing important
//
// Revision 1.7  2001/10/31 21:24:46  lpoulsen
// Display the RIGHT text in the title bar!
//
// Revision 1.6  2001/10/31 19:14:57  mourlouk
// Set the console title ...
//
// Revision 1.5  2001/10/31 17:47:31  lpoulsen
// Correctly display time of engineering version.
//
// Revision 1.4  2001/10/31 17:38:03  lpoulsen
// Generate version display from CVS tag.
//
// Revision 1.3  2001/10/30 01:07:45  lpoulsen
// Add "module ID" statement, audit trail generator and copyright line
// Remove "win_or_linux.h" and use a -D in Linux makefile instead.
//
//

#include <time.h>
#include "afartype.h"
#include "epacket.h"
#include "util.h"
#include "eprotocol.h"
#include "cio.h"
#include "adapter.h"
#include "ucon.h"
#include "parser.h"

#ifdef LINUX
#include <unistd.h>
#include <pthread.h>
#include "win_emul.h"
#define Sleep(A) sleep(A/1000)
#else
#include <windows.h>            // for Sleep() definition
#include <stdlib.h>
#endif

#ifdef FTOL2_MACRO
extern long _ftol(double);      //defined by VC6 C libs

extern long 
_ftol2(double dblSource)
{
    return _ftol(dblSource);
}
#endif

extern char cvs_tag[];
extern Select debug_bit_defs[];

char software_version[16] = "Unknown Program";
time_t start_time = 0;

int gConnectionEstablished = FALSE;
char how2open[3];
FILE *console_out_file;
char console_in_filename[_MAX_PATH];
unsigned char lMACDefinition[6];

boolean showInputPercentage;
boolean showOutputToScreen;
int WhiteOnBlack = TRUE;
int howToPrint = PRINT_NORMAL;
int howToWritePrintFile;        //  0-> append
                                //  1-> destroy
                                //  2-> append, but no screen
                                //  3-> destroy, but no screen

int numOfRadiosFound = 0;

boolean gTranferErrorFlag;
boolean gForceFlag;

extern boolean fileExist(char *filename);
extern int isWinNT;

#ifdef LINUX                    // for Windows it's already there ...
void 
itoa(int num, char *charbuf, int base)
{
    sprintf(charbuf, "%d", num);
}
extern pthread_cond_t *download_Completed;
extern pthread_cond_t *command_Completed;
#else
extern HANDLE download_Completed;
extern HANDLE command_Completed;
extern void start_babysitter();
#endif

uint16 
swap_uint16(uint16 i)
{
    return (uint16) (((i & 0x00FF) << 8) | ((i & 0xFF00) >> 8));
}

uint32
swap_uint32(uint32 i)
{
    return (((i & 0x000000FF) << 24)
            | ((i & 0x0000FF00) << 8)
            | ((i & 0x00FF0000) >> 8)
            | ((i & 0xFF000000) >> 24));
}

void
getShort(short *num, BYTE * source)
{
    BYTE tmp[2];
    tmp[0] = source[1];
    tmp[1] = source[0];
    memcpy(num, tmp, 2);
}

void
getLong(uint32 *num, BYTE * source)
{
    BYTE tmp[4];
    tmp[0] = source[3];
    tmp[1] = source[2];
    tmp[2] = source[1];
    tmp[3] = source[0];
    memcpy(num, tmp, 4);
}

void
letLong(BYTE * dest, long *num)
{
    BYTE tmp[4];
    memcpy(tmp, num, 2);
    dest[3] = tmp[0];
    dest[2] = tmp[1];
    dest[1] = tmp[2];
    dest[0] = tmp[3];
}

uint16 
getRandomID()
{
    static int first_time = TRUE;

    /*
       ** Seed the random number generator with the current time
       ** of day if we haven't done so yet.
     */
    if (first_time)
    {
        first_time = FALSE;
        srand((unsigned int) time(NULL));
    }
    return rand();              // a random number from 0 up to 2^15

}

char
upper(char c)
{
    // returns the uppercase version of the character
    if ((c > 96) && (c < 123))
        return (c - 32);
    else
        return c;
}

int
isDigit(char c)
{
    if ((c < 48) || (c > 57))
        return 0;
    else
        return 1;
}

int
decval(char c)
{
    switch (c)
    {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        return (c - '0');
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
        return (c - 'A' + 10);
    default:
        return -1;
    }
}

boolean 
isHexDigit(char c)
{
    if (decval(c) != -1)
        return TRUE;
    else
        return FALSE;
}

int
hexToInt(char c1, char c2)
{
    if (isHexDigit(c1) && isHexDigit(c2))
        return (decval(c1) * 16 + decval(c2));
    else
        return -1;
}

boolean
isnumeric(char *string)
{
    int     i;

    for (i = 0; i < 8; i++)
    {
        if (string[i] == 0)
            return true;
        if ((string[i] < '0') || (string[i] > '9'))
            return false;
    }
    // More than 8 digits - would overflow
    return false;
}

void
set_config_defaults()
{
    // define default values - might be overwritten by the config file
    howToWritePrintFile = 0;    // append, other values: 1-> destroy
    //                       2-> append, but no screen
    //                       3-> destroy, but no screen

    showInputPercentage = FALSE;
    showOutputToScreen = TRUE;
}

int
extractSerialNumber(macAddr mac, char serialNumber[])
{
    // serial number is the last 32 bits of the MAC address
    long serialNum;
    serialNum = mac[3] * 16 * 16 * 16 * 16 + mac[4] * 16 * 16 + mac[5] * 1;
    // itoa(serialNum, serialNumber, 10);
    sprintf(serialNumber, "%5ld", serialNum);
    return 0;                   //everything OK

}

boolean 
isValidMAC(char *mac_string, byte curMACAddr[])
{
    int i, j = 0;
    char second[64];
    byte emptyEntry[6] = {0, 0, 0, 0, 0, 0};

    if (strlen(mac_string) != 17)
        return FALSE;
    else
    {
        for (i = 0; i < 17; i++)
            if (!isHexDigit(upper(mac_string[i])))
            {
                if (mac_string[i] != ':')
                    return FALSE;
            }
            else
            {
                second[j++] = upper(mac_string[i]);
            }
        second[j] = 0;

        if (strlen(second) != 12)
            return FALSE;

        for (i = 0; i < 6; i++)
        {
            int res = hexToInt(second[2 * i], second[2 * i + 1]);
            if (res == -1)
            {
                memcpy(curMACAddr, emptyEntry, 6);
                return FALSE;
            }
            else
                curMACAddr[i] = (byte) res;
        }
    }

    return TRUE;
}

long
pwr(int p)
{
    int i;
    long pr = 1;
    for (i = 0; i < p; i++)
        pr = pr * 10;
    return pr;
}

boolean 
isValidSerialNum(char *radio_serial_num, byte curMACAddr[])
{
    int i, slen, d;
    long snum = 0;

    slen = strlen(radio_serial_num);
    for (i = 0; i < slen; i++)
    {
        d = radio_serial_num[i] - 48;
        if ((d < 0) || (d > 9))
            return FALSE;       // not a digit

        snum = snum + d * pwr(slen - i - 1);
    }

    // now convert snum into a MAC address
    curMACAddr[0] = curMACAddr[1] = curMACAddr[2] = 0xFF;
    curMACAddr[3] = (uint8)(snum >> 16) & 0xFF;
    curMACAddr[4] = (uint8)(snum >> 8) & 0xFF;
    curMACAddr[5] = (uint8)snum & 0xFF;

    return TRUE;
}

#if 0
void
print_help(int session_id)
{
    int i;
    char horstring[80];
    char thorstring[80];
#ifdef LINUX
    char upleft = 32, upright = 32, downleft = 124, downright = 124, vertical = 124,
      horizontal = 95, midleft = 124, midright = 124, thorizontal = 95, enterKey = 13;
#else
    char upleft = (char) 201, upright = (char) 187, downleft = (char) 200, downright = (char) 188,
      vertical = (char) 186, horizontal = (char) 205, midleft = (char) 199, midright = (char) 182,
      thorizontal = (char) 196, enterKey = (char) 13;
#endif

    for (i = 0; i < 72; i++)
        horstring[i] = horizontal;
    horstring[i] = 0;

    for (i = 0; i < 72; i++)
        thorstring[i] = thorizontal;
    thorstring[i] = 0;

    printf("\n\n%c%s%c\n", upleft, horstring, upright);
    printf
        ("%c Function keys:                                                         %c\n",
         vertical, vertical);
    printf
        ("%c F1 - Help screen                                                       %c\n",
         vertical, vertical);
    printf
        ("%c F3 - Terminate active session                                          %c\n",
         vertical, vertical);
    printf
        ("%c F4 - Start new session                                                 %c\n",
         vertical, vertical);
#ifndef LINUX
    printf
        ("%c F5 - Reverse screen colors                                             %c\n",
         vertical, vertical);
    if (isWinNT)
        printf
            ("%c F6 - Increases console buffer                                          %c\n",
             vertical, vertical);
#endif
    printf("%c%s%c\n", midleft, thorstring, midright);
    printf
        ("%c Command line arguments:                                                %c\n",
         vertical, vertical);
    printf
        ("%c  -o filename  Specify Output File: the output to the screen is also    %c\n",
         vertical, vertical);
    printf
        ("%c               saved into the specified output file.If the file already %c\n",
         vertical, vertical);
    printf
        ("%c               exists it is overwritten.                                %c\n",
         vertical, vertical);
    printf
        ("%c               Example: >econ -o outfile.txt                            %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
    printf
        ("%c  -i filename  Specify Input File: the input commands are read from the %c\n",
         vertical, vertical);
    printf
        ("%c               specified file instead of the keyboard.The last command  %c\n",
         vertical, vertical);
    printf
        ("%c               in the file should be 'logout'.                          %c\n",
         vertical, vertical);
    printf
        ("%c               Example: > econ -I infile.txt                            %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
    printf
        ("%c  -r MAC-addr  Establish a connection to the radio with the specified   %c\n",
         vertical, vertical);
    printf
        ("%c               MAC address only, instead of performing  a discovery     %c\n",
         vertical, vertical);
    printf
        ("%c               operation.                                               %c\n",
         vertical, vertical);
    printf
        ("%c               Example: >econ -r 00:0d:39:00:00:06                      %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
    printf
        ("%c  -r serial#   Establish a connection to the radio with the specified   %c\n",
         vertical, vertical);
    printf
        ("%c               serial number only, instead of performing a discovery    %c\n",
         vertical, vertical);
    printf
        ("%c               operation. Example: >econ -r 11282                       %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
#ifndef LINUX
    printf
        ("%c  -l lines     Sets the number of lines of the MS-DOS console. Not all  %c\n",
         vertical, vertical);
    printf
        ("%c               values are permitted.                                    %c\n",
         vertical, vertical);
    printf
        ("%c               Example: >econ -l 50                                     %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
    printf
        ("%c  -b           Changes the default background, from grey on black to    %c\n",
         vertical, vertical);
    printf
        ("%c               black on white.                                          %c\n",
         vertical, vertical);
    printf
        ("%c               Example: >econ -b                                        %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
#endif
    printf
        ("%c  -h           Prints the help screen                                   %c\n",
         vertical, vertical);
    printf
        ("%c                                                                        %c\n",
         vertical, vertical);
    printf
        ("%c               Multiple arguments can be combined in any order.         %c\n",
         vertical, vertical);
    printf
        ("%c               The input and output files are plain text files.         %c\n",
         vertical, vertical);
    printf
        ("%c               The .txt extension is recommended but not required.      %c\n",
         vertical, vertical);
    printf("%c%s%c\n\n", downleft, horstring, downright);

    // show again the prompt - by forcing the enter key
    if ((active_session.state == SESSION_COMMAND_MODE)
        && (option_I == NULL))
        ether_send(&active_session, &enterKey, 1);
}
#endif

void 
terminate(int exitCode, int errorCode)
{
    switch (errorCode)
    {
        // graceful termination
    case 29:
        printf("Local command exit executed ...\n");
        printf("\nTerminating application ...\n");
        break;
        // error conditions
    case -18:
        printf("Error: Invalid adapter");
        printf("\nTerminating application ...\n");
        break;
    case -19:
        printf("Error: Thread failure");
        printf("\nTerminating application ...\n");
        break;
    case -20:
        printf("Sorry, no devices found");
        printf("\nTerminating application ...\n");
        break;
    case -21:
        printf("Unable to establish connection with the radio");
        printf("\nTerminating application ...\n");
        break;
    case -22:
        printf("Error: Read thread failed");
        printf("\nTerminating application ...\n");
        break;
    case -23:
        printf("Error: Send thread failed");
        printf("\nTerminating application ...\n");
        break;
    case -24:
        printf("Error: Receive thread failed");
        printf("\nTerminating application ...\n");
        break;
    case -25:
        printf("Error: Unable to send data");
        printf("\nTerminating application ...\n");
        break;
    default:
        printf("\nTerminating application with error code:%d\n\n", errorCode);
    }

    fflush(stdout);

    if (exitCode != 100)
    {
        terminate_all_threads(1);
        close_all_adapters();
    }
    else
    {
        // no thread terminations, since there are no threads running
        close_all_adapters();
    }
    exit(0);
}

void 
init_econ()
{
    unsigned char emptyMAC[6] =
    {0, 0, 0, 0, 0, 0};

    LastReceivedPacketBuf = (char *) malloc(1514);

    if (memcmp(lMACDefinition, emptyMAC, 6))
        memcpy(my_mac_address, lMACDefinition, 6);
}

void 
close_econ()
{
    // close adapter
    close_all_adapters();
}

void
clean_session(int dummy)
{
    active_session.state = SESSION_CLOSED;
    active_session.ConnectionID = -2;  // NOT -1!!! It will crash the
    // session table on the server side!

}

void
process_command_arguments(int argc, char **argv)
{
    char lMACSelection[64];
    char vlan_vid[64];
    int i;

    set_config_defaults();

    if (argc == 1)
    {
        // no arguments - simple case
        howToPrint = PRINT_NORMAL;
        return;
    }

    // initialize them
    lMACSelection[0] = 0;
    vlan_vid[0] = 0;
    gForceFlag = FALSE;

    for (i = 1; i < (argc); i++)
    {
        if (argv[i][0] != '-')
        {
            printf("Bad argument %s - ignoring\n", argv[i]);
            continue;
        }

        if (argc == (i + 1))
        {
            switch (argv[i][1])
            {
            case 'u':
                printf("-u is Update all radios\n");
                printf("-u srcfile#dstfile#action#retry_count#retry_interval\n");
                printf("as in: -u tdd_ram.bz#tdd_0825#1#2#2\n");
                printf("action: 1: load-and-sdp - 3: load-only\n");
                exit(-1);
            case 'x':
                printf("-x is eXecute command file on all radios\n");
                printf("-x cmdfile#retry_cnt#retry_interval\n");
                exit(-1);
            case 'c':
            case 'i':
            case 'I':
            case 'o':
            case 'r':
            case 'R':
            case 'm':
            case 'l':
            case 'v':
                printf("missing parameter for argument %s -ignoring\n", argv[i]);
                continue;
            default:
                break;          // arguments without parameters, for instance -h

            }
        }

        switch (argv[i][1])
        {
        case 'a':
            howToWritePrintFile = 0;  // append to output file

            break;
#ifndef LINUX
        case 'b':
            setReverseTextBackground();
            break;
#endif
        case 'c':
            option_C = atoi(argv[i + 1]);
            i++;
            break;
        case 'd':
            debug_flags = parse_bitmask(argv[i+1], debug_bit_defs);
            i++;
            break;
        case 'f':
            gForceFlag = TRUE;
            break;
        case 'i':
        case 'I':
            option_I = malloc(strlen(argv[i + 1]) + 1);
            strcpy(option_I, argv[i + 1]);
            i++;
            break;
#ifndef LINUX
        case 'l':
            if (atoi(argv[i + 1]))
            {
                char lcom[64];
                sprintf(lcom, "mode con:cols=80 lines=%s", argv[i + 1]);
                system(lcom);
            }
            i++;
            break;
#endif
        case 'm':
            strcpy(lMACSelection, argv[i + 1]);
            i++;
            break;
        case 'o':
            option_O = malloc(strlen(argv[i + 1]) + 1);
            strcpy(option_O, argv[i + 1]);
            i++;
            break;
        case 'r':
        case 'R':
            option_R = malloc(strlen(argv[i + 1]) + 1);
            strcpy(option_R, argv[i + 1]);
            i++;
            break;
        case 'v':
            strcpy(vlan_vid, argv[i + 1]);
            i++;
            break;
        case 'z':
        case 'Z':
            option_Z = TRUE;
            break;
        default:
            printf("Bad argument %s - ignoring\n", argv[i]);
        }
    }

    if (strlen(lMACSelection))
    {
        if (isValidMAC(lMACSelection, lMACDefinition))
            printf("\nUsing as local MAC address: %s\n",
                   fmt_mac_addr(lMACDefinition));
    }
    else
    {
        unsigned char emptyMAC[6] =
        {0, 0, 0, 0, 0, 0};
        memcpy(lMACDefinition, emptyMAC, 6);
    }

    if (strlen(vlan_vid))
    {
        gVLAN_mode = atoi(vlan_vid);
        if (gVLAN_mode)
        {
            gVLAN_tag.tpid = swap_uint16(0x8100);
            gVLAN_tag.tci = swap_uint16((uint16) atoi(vlan_vid));
        }
    }
}

void 
show_logo()
{
    int i;
    char horstring[80];
    char thorstring[80];
#ifdef LINUX
    unsigned char upleft = 32, upright = 32, downleft = 124, downright = 124,
      vertical = 124, horizontal = 95, middown = 95, midup = 124, thorizontal = 196;
#else
    unsigned char upleft = 201, upright = 187, downleft = 200, downright = 188,
      vertical = 186, horizontal = 205, middown = 203, midup = 202, thorizontal = 196;
#endif

    char econ_title[64];

    for (i = 0; i < 36; i++)
        horstring[i] = horizontal;
    horstring[i] = 0;

    for (i = 0; i < 72; i++)
        thorstring[i] = thorizontal;
    thorstring[i] = 0;

    for (i = 0; i < sizeof(econ_title); i++)
        econ_title[i] = 0;

    if (strlen(cvs_tag) > 9)
    {
        size_t i;

        for (i = 8; i < strlen(cvs_tag); i++)
        {
            switch (cvs_tag[i])
            {
            case '_':
                cvs_tag[i] = ' ';
                break;
            case '-':
                cvs_tag[i] = '.';
                break;
            case '$':
                cvs_tag[i] = 0;
                break;
            default:
                ;
            }
        }
        strncpy(software_version, &cvs_tag[7], 16);
        sprintf(econ_title, "EConsole rev %s", &cvs_tag[7]);
    }
    else
    {
        sprintf(econ_title,
                "EConsole engineering build of %s %s",
                bld_date, bld_time);
        strncpy(software_version, "ECON engr bld", 16);
    }
    start_time = time(0);

#ifndef LINUX
    SetConsoleTitle(econ_title);
#endif

    printf("\n\n%c%s%c%s%c\n", upleft, horstring, middown, horstring, upright);
    printf
        ("%c Econsole %-20.20s      %c                                    %c\n",
         vertical, (strlen(cvs_tag) > 9 ? &cvs_tag[7] : &econ_title[30]),
         vertical, vertical);
#ifdef OEM_COMPANY
    printf("%c Copyright (c) 2014 %-52.52s %c\n",
           vertical, OEM_COMPANY, vertical);
    printf("%c                    %-52.52s %c\n",
           vertical, "Ethernet Console Program", vertical);
#else
    printf
        ("%c AFAR Communications Inc. (c) 2014  %c  For updates & fixes visit:        %c\n",
         vertical, vertical, vertical);
    printf
        ("%c Ethernet Console Program           %c  http://www.afar.net               %c\n",
         vertical, vertical, vertical);
#endif
    printf("%c%s%c%s%c\n", downleft, horstring, midup, horstring, downright);
}

int
verifyPrefix(char *filename_with_prefix, char *prefixString,
             char *filename_without_prefix)
{
    int j, rj, isPrefix;
    char *pChar;

    isPrefix = TRUE;
    pChar = filename_with_prefix;

    rj = 0;
    for (j = 0; j < 128; j++)
    {
        if (!(*pChar))
            break;

        if (isPrefix)
        {
            if (((*pChar) != '/') && ((*pChar) != 92))  // 92='\'

            {
                prefixString[j] = (*pChar);
            }
            else
            {
                prefixString[j] = 0;
                isPrefix = FALSE;
                if (strcmp(prefixString, "flash"))
                    if (strcmp(prefixString, "tmp"))
                    {
                        return 1;  // invalid prefix

                        filename_without_prefix[0] = 0;
                    }
            }
        }
        else
        {
            filename_without_prefix[rj++] = (*pChar);
        }

        pChar++;
    }

    if ((isPrefix) && (rj == 0))
    {
        prefixString[j] = 0;
        strcpy(filename_without_prefix, prefixString);
    }
    else
        filename_without_prefix[rj] = 0;

    return 0;
}

void 
print_hex(unsigned char *data, int data_size)
{
    int i;

    if (data_size == 1)
    {
        printf("%02X\n", *data);
        return;
    }

    for (i = 0; i < data_size - 1; i++)
        printf("%02X:", *(data + i));
    printf("%02X\n", *(data + data_size - 1));

}

char *
fmt_mac_addr(uint8 * mac_addr)
{
    static char fbuf[2][24] =
    {"00:00:00:00:00:00", "00:00:00:00:00:00"};
    static int i;

    i = (i + 1) % 2;

    sprintf(fbuf[i], "%02X:%02X:%02X:%02X:%02X:%02X",
            mac_addr[0] & 0xFF,
            mac_addr[1] & 0xFF,
            mac_addr[2] & 0xFF,
            mac_addr[3] & 0xFF,
            mac_addr[4] & 0xFF,
            mac_addr[5] & 0xFF);
    return fbuf[i];
}

char *
format_ip_addr(ip_addr *ipa)
{
    static int ii = 0;
    static char ipastr[4][16];
    u_char *ipc = (void *)ipa;

    ii += 1;
    ii &= 0x00000003;

    if ( *(uint32 *)ipa == 0)
        return "";

    sprintf(&ipastr[ii][0], "%d.%d.%d.%d",
            ipc[0],
            ipc[1],
            ipc[2],
            ipc[3]);
    return &ipastr[ii][0];
}

char *
format_mac_addr(u_char *map)
{
    static int  ii = 0;
    static char macastr[4][20];

    ii += 1;
    ii &= 0x00000003;

    sprintf(&macastr[ii][0], "%02X:%02X:%02X:%02X:%02X:%02X",
            map[0],
            map[1],
            map[2],
            map[3],
            map[4],
            map[5]);
    return &macastr[ii][0];
}

void
diagnostic_message(char *econ_diagnostic_msg)
{
    if (debug_level)
        printf("%s\n", econ_diagnostic_msg);
}

char *
get_cvs_tag(void)
{
    return &cvs_tag[0];
}

enum econ_phases
get_econ_phase(void)
{
    return econ_phase;
}

char *
get_option_I(void)
{
    return option_I;
}

char *
get_option_R(void)
{
    return option_R;
}

long
timeval_subtract(struct timeval *x, struct timeval *y)
{

    int nsec;

    /* Perform the carry for the later subtraction by updating y. */

    if (x->tv_usec < y->tv_usec)
    {
        nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
        y->tv_usec -= 1000000 * nsec;
        y->tv_sec += nsec;
    }
    if (x->tv_usec - y->tv_usec > 1000000)
    {
        nsec = (y->tv_usec - x->tv_usec) / 1000000;
        y->tv_usec += 1000000 * nsec;
        y->tv_sec -= nsec;
    }

    /* Compute the time remaining to wait.
       tv_usec is certainly positive. */
    return (x->tv_sec - y->tv_sec) * 1000 + (x->tv_usec - y->tv_usec) / 1000;
}

