/**
**  @file       url_encoder.c
**
**  @author     Daniel Roelker <droelker@sourcefire.com>
**              Copyright (C) 2003
**
**  @brief      Program to obfuscate HTTP URLs by directory and
**              encoding obfuscation.
**
**  This program is for use in security research
**
**  CONTRIBUTORS:
**    -Marc Norton
**    -Matt Watchinski
**
**  NOTES
**    - Initial development: 5.4.03
**    - Research/QA to try this out and get back to me for more features.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifdef WIN32

#include <winsock.h>
#include <fcntl.h>
#include <io.h>

#define random  rand
#define srandom srand

#else

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>

#endif

#define MAX_BUF_LEN 100
#define MAX_CP_STR  100
#define UTF_8_SHORT 0
#define UTF_8_LONG  1
#define SLASH       0
#define BACKSLASH   1
#define D_SIMPLE    0
#define D_DOUBLE    1
#define D_LAST      2
#define D_MISMATCH  3

int g_iSocket = 0;
int g_iStdout = 0;
int g_iEOF    = 0;

/*
**  NAME
**    egetc::
*/
/**
**  Read the different format types that the encoder accepts:
**    - \eX           (where the next character is encoded)
**    - \e{text}      (where the characters in brackets are encoded)
**    - \e[codepoint] (where the codepoint/integer is encoded)
**
**  @param FILE * pointer to the file stream
**  @param int *  pointer to the encoding function
**  
**  @return integer
**
**  @retval EOF hit an error while reading or no more chars to encode for
**              encoding type.
**  @retval >=0 character value
*/
static int egetc(FILE *fFile, int (*encode)(int))
{
    char acNum[MAX_CP_STR];
    char *pcEnd;
    int  iCtr;
    int  iChar;

    if((iChar = fgetc(fFile)) != EOF)
    {
        /*
        **  The text to encode.
        */ 
        if((u_char)iChar == '{')
        {
            while((iChar = fgetc(fFile)) != '}')
            {
                if(iChar == EOF || (u_char)iChar == '\n')
                    return -1;

                if((*encode)(iChar))
                {
                    printf("** Problem encoding char.\n");
                    return -1;
                }
            }
        }
        /*
        **  The codepoint/integer to encode.
        */
        else if((u_char)iChar == '[')
        {
            for(iCtr = 0; iCtr < MAX_CP_STR; iCtr++)
            {
                if((iChar = fgetc(fFile)) == EOF)
                {
                    return -1;
                }
                else if((u_char)iChar == '\n')
                {
                    return -1;
                }
                else if((u_char)iChar == ']')
                {
                    acNum[iCtr] = 0x00;

                    iChar = strtol(acNum, &pcEnd, 0);
                    if(*pcEnd)
                    {
                        printf("** Invalid codepoint value\n");
                        return -1;
                    }

                    if((*encode)(iChar))
                    {
                        printf("** Problem encoding codepoint.\n");
                        return -1;
                    }

                    return 0;
                }

                acNum[iCtr] = (char)iChar;
            }

            printf("** No closing brace in codepoint.\n");
            return -1;
        }
        /*
        **  This is the case where just one char is encoded
        */
        else
        {
            if((*encode)(iChar))
            {
                printf("** Problem encoding char.");
                return -1;
            }
        }
    }
    
    return 0;
} 

int ReadBracketLength(FILE *fFile)
{
    static char acBuffer[MAX_BUF_LEN];
    char *pcEnd;
    int iCtr;
    int iChar;
    int iLen;
    int iBracket = 0;

    iCtr = 0;
    while(iCtr < (MAX_BUF_LEN-1))
    {
        if((iChar = fgetc(fFile)) == EOF)
            return -1;
        if((u_char)iChar == '}')
        {
            iBracket = 1;
            break;
        }

        acBuffer[iCtr] = (u_char)iChar;
        iCtr++;
    }

    if(!iBracket)
    {
        printf("** End bracket not present.  Invalid encoding.\n");
        return -1;
    }

    if(iCtr < (MAX_BUF_LEN-1))
    {
        acBuffer[iCtr] = 0x00;
        iLen = strtol((u_char *)acBuffer, &pcEnd, 0);
        if(pcEnd)
        {
            if(*pcEnd)
            {
                printf("** Invalid Length\n");
                return -1;
            }
        }
    }
    else
    {
        printf("** Bracket length too long.  Must be "
               "below %d.\n", MAX_BUF_LEN);
        return -1;
    }

    return iLen;
}

int PrintAscii(int iChar)
{
    if(iChar < 0 || iChar > 255)
    {
        printf("** Invalid byte value for ASCII conversion.  Must "
               "be between 0 and 255.\n");
        return -1;
    }
    
    printf("%%%.2x", (iChar&0xff));

    return 0;
}

/*
int PrintAscii(FILE *fFile)
{
    int iChar;
    int iNibble;

    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            while(1)
            {
                if((iChar = fgetc(fFile)) == EOF)
                    return -1;

                if((u_char)iChar == '}')
                    break;

                printf("%%");
                printf("%.2x", iChar);
            }
        }
        else
        {
            printf("%%");
            printf("%.2x", iChar);
        }

    }

    return 0;
}
*/

static int PrintMultiBackSlash(int iNum)
{
    int iCtr;

    if(iNum < 0)
    {
        printf("** Invalid number of multi-backslashes\n");
        return -1;
    }

    for(iCtr = 0; iCtr < iNum; iCtr++)
        printf("/");

    return 0;
}

static int PrintMultiSlash(int iNum)
{
    int iCtr;

    if(iNum < 0)
    {
        printf("** Invalid number of multi-slashes\n");
        return -1;
    }

    for(iCtr = 0; iCtr < iNum; iCtr++)
        printf("\\");

    return 0;
}

/*
int PrintMultiSlash(FILE *fFile, int iType)
{
    int iChar;
    int iSlashes;
    int iCtr;

    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            iSlashes = ReadBracketLength(fFile);
            if(iSlashes < 1)
                return -1;
        }
        else
        {
            iSlashes = atoi((u_char *)&iChar);
        }

        if(iSlashes < 1)
        {
            printf("** Invalid slash number.\n");
            return -1;
        }

        if(iType == SLASH)
            for(iCtr = 0; iCtr < iSlashes; iCtr++)
                printf("/");
        else if(iType == BACKSLASH)
            for(iCtr = 0; iCtr < iSlashes; iCtr++)
                printf("\\");
    }

    return 0;
}
*/

static int PrintSelfDir(int iNum)
{
    int iCtr;

    if(iNum < 1)
        return -1;

    printf("/./");
    for(iCtr = 0; iCtr < iNum; iCtr++)
        printf("./");

    return 0;
}

static int PrintDirTravNum(int iNum)
{
    int iCtr;

    if(iNum < 1)
        return -1;

    printf("/../");
    for(iCtr = 1; iCtr < iNum; iCtr++)
        printf("../");
    
    return 0;
}

/*
int PrintDirTravNum(FILE *fFile)
{
    int iChar;
    int iCtr;
    int iDirTravNum;

    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            iDirTravNum = ReadBracketLength(fFile);
            if(iDirTravNum < 1)
            {
                return -1;
            }
        }
        else
        {
            printf("** \\T must be followed by the directory traversal "
                   "number in brackets.\n");
            return -1;
        }

        printf("/../");
        for(iCtr = 1; iCtr < iDirTravNum; iCtr++)
        {
            printf("../");
        }
    }

    return 0;
}
*/

static int PrintRandDirTrav(int iNum)
{
    int iChar;
    int iCtr;

    if(iNum < 1)
        return -1;

    printf("/");
    srandom((unsigned int)random());

    
    for(iCtr = 0; iCtr < iNum; iCtr++)
    {
        while(1)
        {
            iChar = toascii((int)random());
            if(isalpha(iChar) || isdigit(iChar))
                break;
        }

        printf("%c", iChar);
    }

    printf("/../");

    return 0;
}

/*
int PrintDirTrav(FILE *fFile)
{
    char acDirLen[MAX_BUF_LEN];
    int iRet;
    int iChar;
    char pcChar;
    int iDirLen;
    int iCtr = 0;

    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            iDirLen = ReadBracketLength(fFile);
            if(iDirLen < 1)
            {
                return -1;
            }
        }
        else
        {
            iDirLen = atoi((u_char *)&iChar);
        }


        if(iDirLen < 1)
        {
            printf("** Invalid directory length.\n");
            return -1;
        }

        printf("/");

        srandom((unsigned int)random());

        for(iCtr = 0; iCtr < iDirLen; iCtr++)
        {
            while(1)
            {
                iChar = toascii((int)random());
                if(isalpha(iChar) || isdigit(iChar))
                    break;
            }

            printf("%c", iChar);
        }

        printf("/../");
    }

    return 0;
}
*/

static int PrintLongUTF8(int iCP)
{
    int iEncode;

    if(iCP < 0 || iCP > 65535)
        return -1;

    printf("%%");

    iEncode = (0xe0)|(iCP>>12);
    printf("%.2x%%", (u_char)iEncode);

    iEncode = (0x80)|((iCP>>6)&0x3f);
    printf("%.2x%%", (u_char)iEncode);

    iEncode = (0x80)|(iCP & 0x3f);
    printf("%.2x", (u_char)iEncode);
    
    return 0;
}

static int PrintShortUTF8(int iCP)
{
    int iEncode;

    if(iCP < 0 || iCP > 65535)
        return -1;

    if(iCP < 0x800)
    {
        printf("%%");

        iEncode = (0xc0)|(iCP>>6);
        printf("%.2x%%", (u_char)iEncode);

        iEncode = (0x80) | (iCP & 0x3f);
        printf("%.2x", (u_char)iEncode);
    }
    else
    {
        if(PrintLongUTF8(iCP))
            return -1;
    }
    
    return 0;
}

int PrintUTF(FILE *fFile, int iType)
{
    char acCP[MAX_BUF_LEN];
    int iChar;
    int iCP;
    int iCtr;
    int iSeq;
    int iEncode;
    char *pcEnd;

    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            iCP = ReadBracketLength(fFile);
            if(iCP < 1)
            {
                return -1;
            }
        }
        else
        {
            iCP = iChar;
        }

        if(iCP < 0x800 && iType == UTF_8_SHORT)
        {
            printf("%%");

            iEncode = (0xc0)|(iCP>>6);
            printf("%.2x%%", (u_char)iEncode);

            iEncode = (0x80) | (iCP & 0x3f);
            printf("%.2x", (u_char)iEncode);
        }
        else if(iCP < 0x10000)
        {
            printf("%%");

            iEncode = (0xe0)|(iCP>>12);
            printf("%.2x%%", (u_char)iEncode);

            iEncode = (0x80)|((iCP>>6)&0x3f);
            printf("%.2x%%", (u_char)iEncode);

            iEncode = (0x80)|(iCP & 0x3f);
            printf("%.2x", (u_char)iEncode);
        }
    }
        
    return 0;
}

static int PrintUEncoding(int iCP)
{
    if(iCP < 0 || iCP > 65535)
        return -1;

    printf("%%u%.4x", (iCP&0xffff));
    
    return 0;
}

/*
int PrintUEncoding(FILE *fFile)
{
    int iChar;
    int iCP;

    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            iCP = ReadBracketLength(fFile);
            if(iCP < 1)
                return -1;
        }
        else
        {
            iCP = iChar;
        }

        if(iCP < 0x10000)
        {
            printf("%%u%.4x", iCP);
        }
        else
        {
            printf("** U encode error - Invalid codepoint.\n");
            return -1;
        }
    }

    return 0;
}
*/

int Nibble2Ascii(int iNibble)
{
    if(iNibble < 10)
    {
        iNibble += 48;
    }
    else
    {
        iNibble += 55;
    }

    return iNibble;
}

static int DoubleHexEncoding(int iChar)
{
    if(iChar < 0 || iChar > 255)
        return -1;

    printf("%%25%.2x", (iChar&0xff));

    return 0;
}

static int DoubleNibbleEncoding(int iChar)
{
    int iNibble;

    if(iChar < 0 || iChar > 255)
        return -1;

    iNibble = Nibble2Ascii(iChar>>4);
    printf("%%%%%.2x", (iNibble&0xff));
    iNibble = Nibble2Ascii(iChar&0x0f);
    printf("%%%.2x", (iNibble&0xff));
    
    return 0;
}

static int FirstNibbleEncoding(int iChar)
{
    int iNibble;

    if(iChar < 0 || iChar > 255)
        return -1;

    iNibble = Nibble2Ascii(iChar>>4);
    printf("%%%%%.2x", (iNibble&0xff));
    iNibble = Nibble2Ascii(iChar&0x0f);
    printf("%c", (iNibble&0xff));
    
    return 0;
}

static int SecondNibbleEncoding(int iChar)
{
    int iNibble;

    if(iChar < 0 || iChar > 255)
        return -1;

    iNibble = Nibble2Ascii(iChar>>4);
    printf("%%%c", (iNibble&0xff));
    iNibble = Nibble2Ascii(iChar&0x0f);
    printf("%%%.2x", (iNibble&0xff));
    
    return 0;
}

static int MismatchEncoding1(int iChar)
{
    int iNibble;

    if(iChar < 0 || iChar > 255)
        return -1;

    printf("%%u0025%%550%%30%d", iChar>>4);
    iNibble = Nibble2Ascii(iChar&0x0f);
    printf("%%%.2x", (iNibble&0xff));

    return 0;
} 

int DoubleEncode(FILE *fFile, int iType)
{
    int iChar;
    int iNibble;

    if((iChar = fgetc(fFile)) != EOF)
    {
        switch(iType)
        {
            case D_SIMPLE:
                printf("%%25%.2x", iChar);
                break;
            case D_DOUBLE:
                iNibble = Nibble2Ascii(iChar>>4);
                printf("%%%%%.2x", iNibble);
                iNibble = Nibble2Ascii(iChar&0x0f);
                printf("%%%.2x", iNibble);
                break;
            case D_LAST:
                printf("%%%d", iChar>>4);
                iNibble = Nibble2Ascii(iChar&0x0f);
                printf("%%%.2x", iNibble);
                break;
            case D_MISMATCH:
                printf("%%u0025%%550%%30%d", iChar>>4);
                iNibble = Nibble2Ascii(iChar&0x0f);
                printf("%%%.2x", iNibble);
                break;
        }
    }

    return 0;
}

static int PrintLongBareByte(int iCP)
{
    int iEncode;

    if(iCP < 0 || iCP > 65535)
        return -1;

    if(iCP < 0x10000)
    {
        iEncode = (0xe0)|(iCP>>12);
        printf("%c", (u_char)iEncode);

        iEncode = (0x80)|((iCP>>6)&0x3f);
        printf("%c", (u_char)iEncode);

        iEncode = (0x80)|(iCP & 0x3f);
        printf("%c", (u_char)iEncode);
    }

    return 0;
}

static int PrintShortBareByte(int iCP)
{
    int iEncode;

    if(iCP < 0 || iCP > 65535)
        return -1;

    if(iCP < 0x800)
    {
        iEncode = (0xc0)|(iCP>>6);
        printf("%c", (u_char)iEncode);

        iEncode = (0x80) | (iCP & 0x3f);
        printf("%c", (u_char)iEncode);
    }
    else
    {
        if(PrintLongBareByte(iCP))
            return -1;
    }

    return 0;
}

int PrintBareByte(FILE *fFile, int iType)
{
    int iEncode;
    int iChar;
    int iCP;
    
    if((iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '{')
        {
            iCP = ReadBracketLength(fFile);
            if(iCP < 1)
                return -1;
        }
        else
        {
            printf("** Value must be enclosed in brackets.\n");
            return -1;
        }

        if(iCP < 0x800 && iType == UTF_8_SHORT)
        {
            iEncode = (0xc0)|(iCP>>6);
            printf("%c", (u_char)iEncode);

            iEncode = (0x80) | (iCP & 0x3f);
            printf("%c", (u_char)iEncode);
        }
        else if(iCP < 0x10000)
        {
            iEncode = (0xe0)|(iCP>>12);
            printf("%c", (u_char)iEncode);

            iEncode = (0x80)|((iCP>>6)&0x3f);
            printf("%c", (u_char)iEncode);

            iEncode = (0x80)|(iCP & 0x3f);
            printf("%c", (u_char)iEncode);
        }
    }

    return 0;
}

static int PrintHexChar(FILE *fFile)
{
    int iNibble;
    int iChar = 0;

    if((iNibble = fgetc(fFile)) != EOF)
    {
        if(!isxdigit(iNibble))
        {
            printf("** Invalid hex char.\n");
            return -1;
        }

        iChar = (isdigit(iNibble)) ? (iNibble-'0') : (toupper(iNibble)-'A'+10);

        if((iNibble = fgetc(fFile)) != EOF)
        {
            if(!isxdigit(iNibble))
            {
                printf("** Invalid hex char.\n");
                return -1;
            }
        }
        else
        {
            return -1;
        }

        iChar <<= 4;
        iChar |= isdigit(iNibble)?(iNibble-'0'):(toupper(iNibble)-'A'+10);
    }
    else
    {
        return -1;
    }

    printf("%c", (u_char)iChar);
        
    return 0;
}

void Help()
{
    printf("url_encoder -- Version 1.1\n");
    printf("Author: Daniel Roelker\n");
    printf("Contributors:\n");
    printf("  Marc Norton\n");
    printf("  Matt Watchinski\n\n");
    printf("Usage:\n");
    printf("  url_encoder [file] [-dst dst_host:dst_port]\n\n");
    printf("  Encoding Types:\n");
    printf("    \\a       encode chars in ASCII\n");
    printf("    \\b       encode codepoint in short byte UTF-8\n");
    printf("    \\B       encode codepoint in long byte UTF-8\n");
    printf("    \\d       encode char in %%25xx encoding\n");
    printf("    \\D       encode char in %%%%XX%%%XX encoding\n");
    printf("    \\e       encode char/codepoint in %%U encoding\n");
    printf("    \\E       encode char in mismatch encoding\n");
    printf("    \\i       encode char in first nibble encoding\n");
    printf("    \\I       encode char in last nibble encoding\n");
    printf("    \\u       encode char/codepoint in short UTF-8\n");
    printf("    \\U       encode char/codepoint in long UTF-8\n\n");
    printf("  Obfuscations:\n");
    printf("    \\m[num]  number of multi-slashes\n");
    printf("    \\M[num]  number of mulit-backslashes\n");
    printf("    \\s       self-referential directory traversal\n");
    printf("    \\S[num]  self-referential directory traversal\n");
    printf("    \\t[num]  length of directory to traverse\n");
    printf("    \\T[num]  traverse path # of directories\n\n");
    printf("  Other Encodings:\n");
    printf("    \\\\       write a backslash\n");
    printf("    \\n       encode LF in string\n");
    printf("    \\r       encode CR in string\n");
    printf("    \\x       encode a byte (common C sytax)\n\n");

    printf("Examples:\n");
    printf("  /foo\\m3bar    == /foo///bar\n");
    printf("  /foo\\U/bar    == /foo%%e0%%80%%afbar\n");
    printf("  /foo\\t{10}bar == /foo/AL2354jki0/../bar\n\n");

    return;
}

int EscapedChar(FILE *fFile)
{
    int iChar;
    int iRet;

    switch((iChar = fgetc(fFile)))
    {
        case 'a':
            if(egetc(fFile, PrintAscii))
            {
                printf("** PrintAscii() Error.\n");
                return -1;
            }

            break;
        case 'b':
            if(egetc(fFile, PrintShortBareByte))
            {
                printf("** PrintShortBareByte() Error.\n");
                return -1;
            }
            break;
        case 'B':
            if(egetc(fFile, PrintLongBareByte))
            {
                printf("** PrintLongBareByte() Error.\n");
                return -1;
            }
            break;
        case 'd':
            if(egetc(fFile, DoubleHexEncoding))
            {
                printf("** DoubleHexEncoding() Error.\n");
                return -1;
            }
            break;
        case 'D':
            if(egetc(fFile, DoubleNibbleEncoding))
            {
                printf("** DoubleNibbleEncoding() Error.\n");
                return -1;
            }
            break;
        case 'i':
            if(egetc(fFile, FirstNibbleEncoding))
            {
                printf("** FirstNibbleEncoding() Error.\n");
                return -1;
            }
            break;
        case 'I':
            if(egetc(fFile, SecondNibbleEncoding))
            {
                printf("** SecondNibbleEncoding() Error.\n");
                return -1;
            }
            break;
        case 'E':
            if(egetc(fFile, MismatchEncoding1))
            {
                printf("** MismatchEncoding1() Error.\n");
                return -1;
            }
            break;
        case 'e':
            if(egetc(fFile, PrintUEncoding))
            {
                printf("** PrintUEncoding() Error.\n");
                return -1;
            }
            break;
        case 'u':
            if(egetc(fFile, PrintShortUTF8))
            {
                printf("** PrintShortUTF8() Error.\n");
                return -1;
            }
            break;
        case 'U':
            if(egetc(fFile, PrintLongUTF8))
            {
                printf("** PrintLongUTF8() Error.\n");
                return -1;
            }
            break;
        case 'm':
            if(egetc(fFile, PrintMultiSlash))
            {
                printf("** PrintMultiSlash() Error.\n");
                return -1;
            }
            break;
        case 'M':
            if(egetc(fFile, PrintMultiBackSlash))
            {
                printf("** PrintMultiBackSlash() Error.\n");
                return -1;
            }
            break;
        case 's':
            if((iRet = PrintSelfDir(1)))
            {
                printf("** PrintSelfDir() Error.\n");
                return -1;
            }
            break;
        case 'S':
            if(egetc(fFile, PrintSelfDir))
            {
                printf("** PrintSelfDir() Error.\n");
                return -1;
            }
            break;
        case 't':
            if(egetc(fFile, PrintRandDirTrav))
            {
                printf("** PrintRandDirTrav() Error.\n");
                return -1;
            }
            break;
        case 'T':
            if(egetc(fFile, PrintDirTravNum))
            {
                printf("** PrintDirTravNum() Error.\n");
                return -1;
            }
            break;
        case '\\':
            printf("\\");
            break;
        case 'r':
            printf("\r");
            break;
        case 'n':
            printf("\n");
            break;
        case 'x':
            if(PrintHexChar(fFile))
            {
                printf("** PrintHexChar() Error.\n");
                return -1;
            }
            break;
        default:
            printf("** Invalid encoding '%c'.\n\n", iChar);
            Help();
            return -1;
    }

    return 0;
}

int SetupSocket(u_char *ip, u_char *port)
{
    struct hostent *HostName;
    struct sockaddr_in saHost;
    int iPort;
    int iSocket;

    iPort = atoi(port);
    if(iPort < 0 || iPort > 65535)
    {
        printf("** Invalid port number.\n");
        return -1;
    }

    HostName = gethostbyname(ip);
    if(!HostName)
    {
        printf("** Invalid host name.\n");
        return -1;
    }

    saHost.sin_addr.s_addr = ((struct in_addr *)HostName->h_addr)->s_addr;
    saHost.sin_family      = AF_INET;
    saHost.sin_port        = htons((u_short)iPort);

    printf("IP Address: %s\n", inet_ntoa(saHost.sin_addr));
    printf("Port:       %s\n", port);

    iSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(iSocket < 0)
    {
        printf("** Error opening socket.\n");
        return -1;
    }

    if(connect(iSocket, (struct sockaddr *)&saHost, sizeof(saHost)))
    {
        printf("** Error connecting socket.\n");
        return -1;
    }

    return iSocket;
}

int ReadSocket(int iSocket)
{
    char Buffer;

    if(!iSocket)
        return 0;

    dup2(g_iStdout, fileno(stdout));
    close(g_iStdout);

    while(read(iSocket, &Buffer, 1) > 0)
    {
        printf("%c", Buffer);
    }

    return 0;
}

void Shutdown(int iSignal)
{
    if(ReadSocket(g_iSocket))
    {
        printf("** Did not read socket.\n");
    }

    if(g_iSocket)
        close(g_iSocket);

    exit(iSignal);
}

int main(int argc, char **argv)
{
    FILE *fFile = NULL;
    int iChar;
    int iRet;
    int iCtr;
    u_char *ip;
    u_char *port;
    int iSocket = 0;
    int iFile;

#ifdef WIN32

    _setmode( _fileno( stdout ), _O_BINARY );
    _setmode( _fileno( stderr ), _O_BINARY );

#else

    signal(SIGHUP,  Shutdown);
    signal(SIGQUIT, Shutdown);
    signal(SIGINT,  Shutdown);
    signal(SIGSEGV, Shutdown);
    signal(SIGTERM, Shutdown);

#endif

    if(argc > 1)
    {
        for(iCtr = 1; iCtr < argc; iCtr++)
        {
            if(!strcmp(argv[iCtr], "-dst"))
            {
                iCtr++;
                if(iCtr < argc)
                {
                    ip   = argv[iCtr];
                    port = strchr(argv[iCtr], ':');
                    if(!port)
                    {
                        printf("** No port specified with IP address.  "
                               "Use colon to separate IP and port.\n");
                        return -1;
                    }
                    
                    *port = 0x00;
                    port++;
                    
                    iSocket = SetupSocket(ip, port);
                    if(iSocket < 0)
                    {
                        printf("** Error setting up socket.\n");
                        return -1;
                    }

                    /*
                    **  Set up the global socket.
                    */
                    g_iSocket = iSocket;

                    /*
                    **  Setup stdout to be what we print too.
                    */
                    g_iStdout = dup(fileno(stdout));
                    dup2(iSocket, fileno(stdout));
                }
                else
                {
                    printf("** No argument to '-d' option.\n");
                    return -1;
                }
            }
            else if(*argv[iCtr] == '-')
            {
                Help();
                return -1;
            }
            else if(fFile == NULL)
            {
                fFile = fopen(argv[iCtr], "r");
                if(!fFile)
                {
                    printf("** Could not open file %s.\n", argv[1]);
                    return -1;
                }
            }
        }
    }

    if(fFile == NULL)
    {
        fFile = stdin;
        iFile = fileno(fFile);
    }

    while(!g_iEOF && (iChar = fgetc(fFile)) != EOF)
    {
        if((u_char)iChar == '\\')
        {
            if((iRet = EscapedChar(fFile)))
            {
                printf("** error in EscapedChar()\n");
                close(iSocket);
                return -1;
            }

            continue;
        }
        else if((u_char)iChar == '\r' || (u_char)iChar == '\n')
            break;

        printf("%c", (unsigned char)iChar);
    }

    if(ReadSocket(iSocket))
    {
        printf("** Did not read socket.\n");
        return -1;
    }

    if(iSocket)
        close(iSocket);

    return 0;
}
