// dunstat.c - Winmain (built with dun.bat, dr.bat for resources)
//             XP manifest included in dunstat.rc

// Version 2.1

// Date January 1, 2005

// Copyright NAT Software, 2005

#include <windows.h>
#include <stdio.h>
#include "sockio.h"
#include "..\src\h\dunstat.h"

HANDLE hThread;
HANDLE hSem;
HINSTANCE hInst;
HWND ghDlg;
HWND hCtrlHangup;
HWND hCtrlDial;
HWND hCtrlList;
HWND hCtrlEdit;
HWND hCtrlOK;
HMENU hMenu;

NOTIFYICONDATA iconData;

#define MYWM_NOTIFYICON 200

int icon_state;

#define DOWN         0
#define DISCONNECTED 1
#define CONNECTED    2
#define BUSY         3
int dial;

int  busy, flag, wake_flag, stop_thread, tid;
char gateway[256];
char mac_str[256];
char connection[1500];
char gbuf[1500];
char xbuf[1500];
int  mac[6];            // int not char because of sscanf

int wait_time;

// Function prototypes

BOOL APIENTRY DunDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL APIENTRY HelpDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
int parse(LPSTR CmdLine);
int exec(char *cmdline, short flag);
BOOL CenterWindow(HWND hWin);

//
// kprintf - low-level printf
//
int kprintf(char *fmt, ...)
{
    va_list args;
    char buf[0x8000];

    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);

    return MessageBox(NULL, buf, "DUN Status", MB_OKCANCEL | MB_SETFOREGROUND);
}

//
// dprintf - low-level printf via OutputDebugString
//           Run www.sysinternals.com DebugView.exe
//           to view this output.
//

int dprintf(char *fmt, ...)
{
    va_list args;
    char buf[0x8000];
    int n;

    va_start(args, fmt);

    n = vsprintf(buf, fmt, args);

    va_end(args);

    if (n < 0)
        return SYSERR;

    buf[n] = 0;

    OutputDebugString(buf);

    return n;
}
/*------------------------------------------------------------------------
 *
 *  Add items to list box, but only if buf has changed
 *
 *------------------------------------------------------------------------
*/
int AddItems(HWND hDlg, char *buf) {

    char *ptr1;
    char *ptr2;
    char tmp[1500];

    if (!strcmp(buf, gbuf) && strlen(buf))
        return 0;

    strcpy(gbuf, buf);
    strcpy(tmp, buf);

    SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_RESETCONTENT, 0, 0);

    ptr1 = tmp;
    while (1) {
        ptr2 = (char *) strchr(ptr1, '\n');
        if (ptr2 == 0)
            break;
        *ptr2 = 0;
        SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_ADDSTRING, 0, (LPARAM) ptr1);
        ptr1 = ++ptr2;
    }
    return 0;
}

/*------------------------------------------------------------------------
 *
 *  Status thread function
 *
 *------------------------------------------------------------------------
*/

DWORD WINAPI status(void *param) {

    int i, len, s, result;
    char buf[1500];
    char tmp[256];
    
    result = 0;
    busy = 0;

    while (!stop_thread) {

        // Use a new socket each time, or sReadT won't work
        // TODO: fix sReadT

        s = connectUDP(gateway, "echo");

        if (result == 0)
            sWrite(s, "connect", 8);
        else
            sWrite(s, xbuf, strlen(xbuf) + 1);

        len = sReadT(s, buf, 1400, 1000);

        // If we got an ICMP response, retry the sReadT

        if (len == -1)
            len = sReadT(s, buf, 1400, 1000);
 
        if (len == -3) {

            // Server Unreachable
            
            if (busy) {
                strcpy(tmp, "Server is busy");
                for (i=0; i<busy; i++)
                    strcat(tmp, ".");

                busy++;
                wait_time = 500;                    // Fast .5 sec poll
                if (busy == 240) {                  // 2 minute maximum
                    busy = 0;
                    wait_time = 10000;              // Slow 10 sec poll
                }
            }
            else {
                sprintf(tmp, "No response from %s", gateway);
                wait_time = 10000;                  // Slow 10 sec poll
            }

            if (!busy && icon_state != DOWN) {
                dial = 0;
                iconData.hIcon = LoadIcon(hInst, "ICON2_DUN");
                strcpy(iconData.szTip, tmp);
                Shell_NotifyIcon(NIM_MODIFY, &iconData);
                icon_state = DOWN;
                EnableWindow(hCtrlDial, 0);
                EnableWindow(hCtrlHangup, 0);
            }
            SendDlgItemMessage(ghDlg, IDC_LISTBOX1, LB_RESETCONTENT, 0, 0);
            SetDlgItemText(ghDlg, IDC_EDIT2, tmp);
            gbuf[0] = 0;
            goto done;
        }
                            
        if (buf[0] == '0') {

            // Server is disconnected
            
            busy = 0;
            dial = 0;
            strcpy(tmp, "Disconnected");

            if (icon_state != DISCONNECTED) {
                iconData.hIcon = LoadIcon(hInst, "ICON3_OFF");
                strcpy(iconData.szTip, tmp);
                Shell_NotifyIcon(NIM_MODIFY, &iconData);
                icon_state = DISCONNECTED;
            }
            SetDlgItemText(ghDlg, IDC_EDIT2, tmp);
            AddItems(ghDlg, &buf[1]);
            wait_time = 10000;                      // Slow 10 sec poll
            goto done;
        }

        if (buf[0] == '1') {

            // Server is connected
            
            busy = 0;
            dial = 0;
            strcpy(tmp, "Connected");

            if (icon_state != CONNECTED) {
                iconData.hIcon = LoadIcon(hInst, "ICON4_ON");
                strcpy(iconData.szTip, tmp);
                Shell_NotifyIcon(NIM_MODIFY, &iconData);
                icon_state = CONNECTED;
            }
            SetDlgItemText(ghDlg, IDC_EDIT2, tmp);
            AddItems(ghDlg, &buf[1]);
            wait_time = 10000;                      // Slow 10 sec poll
            goto done;
        }

        if (buf[0] == '2') {

            // Server is busy
            
            busy++;

            strcpy(tmp, "Busy");

            sprintf(tmp, "Sent command: %s", xbuf);

            if (icon_state != BUSY) {
                if (dial)
                    iconData.hIcon = LoadIcon(hInst, "ICON6_DIAL");
                else
                    iconData.hIcon = LoadIcon(hInst, "ICON5_BUSY");
                strcpy(iconData.szTip, tmp);
                Shell_NotifyIcon(NIM_MODIFY, &iconData);
                EnableWindow(hCtrlDial, 0);
                EnableWindow(hCtrlHangup, 0);
                icon_state = BUSY;
            }
            SetDlgItemText(ghDlg, IDC_EDIT2, tmp);
            wait_time = 500;                        // Fast .5 sec poll
        }

done:
        sClose(s);
        result = WaitForSingleObject(hSem, wait_time);
        if (result == WAIT_TIMEOUT)
            result = 0;
        else
            result = 1;
    }
    sClose(s);    
    return 0;
}

int WINAPI WinMain(HINSTANCE hExe, HINSTANCE hPrev, LPSTR CmdLine, int CmdShow)
{
    WSADATA data;
    int result;
    WNDCLASS wc;
      
    int status;

    if (FindWindow("DunStatusDlgClass", NULL))
        return OK;

    hInst = hExe;
    
    status = WSAStartup(MAKEWORD(1,1), &data);
    if (status) {
        kprintf("WINSOCK startup error");
        return 0;
    }

    wait_time = 10000;      // Slow 10 sec poll

    hSem = CreateSemaphore(NULL, 0, 1, 0);

    parse(CmdLine);

    // Create the dialog box

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = DefDlgProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = DLGWINDOWEXTRA;
    wc.hInstance = hInst;
    wc.hIcon = LoadIcon(hInst, "ICON1_DUNSTAT");
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) COLOR_WINDOW + 1;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "DunStatusDlgClass";
    RegisterClass(&wc);

    result = DialogBox(hInst, "DUN", NULL, DunDlgProc);
    if (result == 0)
        kprintf("FATAL ERROR: unable to create DUN dialog\n");
                
    if (hThread)
        CloseHandle(hThread);
        
    Shell_NotifyIcon(NIM_DELETE, &iconData);

    status = WSACleanup();
    if (status)
        kprintf("WINSOCK cleanup error");

    return 0;
}

//
// copy string into mac array
//
int str2mac(char *str) {
    return sscanf(str, "%x-%x-%x-%x-%x-%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
}

//
// parse
//
int parse(LPSTR CmdLine)
{
    char *ptr;
    int n;

    ptr = strchr(CmdLine, ' ');
    if (ptr) {
        *ptr++ = 0;
        strcpy(gateway, CmdLine);
        strcpy(mac_str, ptr);
        n = str2mac(ptr);
        if (n != 6) {
            kprintf("ERROR: MAC Address format: xx-xx-xx-xx-xx-xx");
            return -1;
        }
        wake_flag = 1;
    }
    else
        strcpy(gateway, CmdLine);

    return 0;
}

int wol() {
    unsigned char wake[102] = {0xff,0xff,0xff,0xff,0xff,0xff};
    char *ptr;
    int i, j, ns;

    ns = connectUDP("255.255.255.255", "echo");
    ptr = wake + 6;
    for (i=0; i<16; i++) {
        for (j=0; j<6; j++)
            *ptr++ = mac[j] & 0xff;
    }
    sWrite(ns, wake, 102);        // 17x6
    sClose(ns);
    return 0;
}

int str_esc(unsigned char *str)
{
    unsigned i;

    // Replace 0x20 with 0xA0 in a string

    for (i=0; i<strlen(str); i++)
        if (str[i] == (unsigned char) 0x20)
            str[i] = 0xA0;
    return i;
}

//
// DunDlgProc - all the work is done here
//

BOOL APIENTRY DunDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    int  len, param, wmID, result;
    char tmp[256];
    HWND hCtrl;
    char *ptr;

    switch (msg) {

        case WM_INITDIALOG:

            ghDlg = hDlg;
            
            hCtrlHangup = GetDlgItem(hDlg, IDC_PUSHBUTTON1);
            hCtrlDial = GetDlgItem(hDlg, IDC_PUSHBUTTON2);
            hCtrlEdit = GetDlgItem(hDlg, IDC_EDIT1);
            hCtrlList = GetDlgItem(hDlg, IDC_LISTBOX1);
            hCtrlOK = GetDlgItem(hDlg, IDOK);
            SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_SETHORIZONTALEXTENT, (WPARAM) 128*8 /* pixels, max 32767 */, (LPARAM) 0);
    
            iconData.cbSize = sizeof(iconData);
            iconData.hWnd = hDlg;
            iconData.uID = 1;   // any old value
            iconData.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
            iconData.uCallbackMessage = MYWM_NOTIFYICON;
            iconData.hIcon = LoadIcon(hInst, "ICON2_DUN");
            sprintf(tmp, "DUN Status");
            strcpy(iconData.szTip, tmp);

            icon_state = DOWN;
    
            Shell_NotifyIcon(NIM_ADD, &iconData);

            CenterWindow(hDlg);
            
            if (strlen(mac_str))
                SetDlgItemText(hDlg, IDC_EDIT3, mac_str);

            if (wake_flag)
                EnableWindow(GetDlgItem(hDlg, IDC_PUSHBUTTON3), 1);
            else
                EnableWindow(GetDlgItem(hDlg, IDC_PUSHBUTTON3), 0);

            if (strlen(gateway)) {
                SetDlgItemText(hDlg, IDC_EDIT1, gateway);
                PostMessage(hDlg, WM_COMMAND, IDOK, 0);
            }
            else {
                SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_RESETCONTENT, 0, 0);
                SetDlgItemText(hDlg, IDC_EDIT2, "Please specify a gateway address");
                flag = 1;
            }
            return TRUE;

        case WM_DESTROY:
            
            PostQuitMessage(0);
            break;

        case WM_CLOSE:

            flag = 0;
            ShowWindow(hDlg, SW_HIDE);
            return TRUE;
            
        case MYWM_NOTIFYICON:

            param = (UINT) lParam;    

            if (param == WM_LBUTTONDBLCLK) {
                wol();                          // Wake on LAN
                break;
            }

            if (param == WM_RBUTTONUP) {

                switch (icon_state) {
                    case DOWN:  if (strlen(gateway))
                                    sprintf(tmp, "No response from %s", gateway);
                                else
                                    sprintf(tmp, "Please specify a gateway");
                                hCtrl = hCtrlEdit;
                                break;
                
                    case DISCONNECTED:  strcpy(tmp, "Disconnected");
                                        hCtrl = hCtrlDial;
                                        break;
                
                    case CONNECTED: strcpy(tmp, "Connected");
                                    hCtrl = hCtrlHangup;
                                    break;

                    case BUSY: strcpy(tmp, "Busy");
                               hCtrl = hCtrlOK;
                               break;
                }
                SetDlgItemText(hDlg, IDC_EDIT2, tmp);

                if (flag == 0) {
                    SetForegroundWindow(hDlg);
                    ShowWindow(hDlg, SW_RESTORE);
                    flag = 1;
                }
                else {
                    ShowWindow(hDlg, SW_HIDE);
                    flag = 0;
                }
                return TRUE;
            }

            if (param == WM_LBUTTONDOWN) {

                POINT p;

                if (flag == 1) {
                    flag = 0;
                    ShowWindow(hDlg, SW_HIDE);
                    return TRUE;
                }

                SetForegroundWindow(hDlg);

                hMenu = CreatePopupMenu();

                AppendMenu(hMenu, MF_STRING, 1, "Exit");
                AppendMenu(hMenu, MF_SEPARATOR, 2, 0);
                AppendMenu(hMenu, MF_STRING, 3, "Show");
                if (wake_flag)
                    AppendMenu(hMenu, MF_STRING, 4, "Wake");
                else
                    AppendMenu(hMenu, MF_STRING | MF_GRAYED, 4, "Wake");

                GetCursorPos(&p);

                result = TrackPopupMenuEx(hMenu,
                                        TPM_RIGHTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL|TPM_NONOTIFY|TPM_RETURNCMD,
                                        p.x, p.y-8, hDlg, NULL);
                switch (result) {

                    case 1: EndDialog(hDlg, IDOK);  // Exit
                            return TRUE;

                    case 2: break;

                    case 3: flag = 1;
                            ShowWindow(hDlg, SW_SHOWNORMAL);
                            break;

                    case 4: wol();                  // Wake on LAN
                            break;

                    default: break;
                }
                DestroyMenu(hMenu);
            }
            return TRUE;

        case WM_COMMAND:

//dprintf("WM_COMMAND low %x high %x", LOWORD(wParam), HIWORD(wParam));

            wmID = LOWORD(wParam);

            switch (wmID) {

                case IDOK:

                    len = GetDlgItemText(hDlg, IDC_EDIT5, tmp, 256);
                    if (len && tmp[0] != '#') {
                        char tmp1[256];
                        result = exec(tmp, SW_SHOW);
                        sprintf(tmp1, "Exec %s returned %d", tmp, result);
                        SetDlgItemText(hDlg, IDC_EDIT2, tmp1);
                        SetDlgItemText(hDlg, IDC_EDIT5, "");
                        return TRUE;
                    }

                    len = GetDlgItemText(hDlg, IDC_EDIT3, mac_str, 18);

                    if (len == 17) {
                        len = str2mac(mac_str);
                        if (len == 6) {
                            wake_flag = 1;
                            SetDlgItemText(hDlg, IDC_EDIT4, "");
                            EnableWindow(GetDlgItem(hDlg, IDC_PUSHBUTTON3), 1);
                        }
                        else {
                            SetDlgItemText(hDlg, IDC_EDIT4, "<- Format xx-xx-xx-xx-xx-xx");
                            wake_flag = 0;
                            EnableWindow(GetDlgItem(hDlg, IDC_PUSHBUTTON3), 0);
                        }
                    }
                    else {
                        if (len == 0)
                            SetDlgItemText(hDlg, IDC_EDIT4, "");
                        else
                            SetDlgItemText(hDlg, IDC_EDIT4, "<- Format xx-xx-xx-xx-xx-xx");
                        wake_flag = 0;
                        EnableWindow(GetDlgItem(hDlg, IDC_PUSHBUTTON3), 0);
                    }

                    len = GetDlgItemText(hDlg, IDC_EDIT1, gateway, 15);                

                    if (len >= 1) {
                        if (hThread == 0)
                            hThread = CreateThread(0, 0, status, 0, 0, &tid);
                        else {
                            stop_thread = 1;
                            ReleaseSemaphore(hSem, 1, NULL);
                            WaitForSingleObject(hThread, INFINITE);
                            stop_thread = 0;
                            hThread = CreateThread(0, 0, status, 0, 0, &tid);
                        }

                        sprintf(tmp, "DUN connection status for %s", gateway);
                        strcpy(iconData.szTip, tmp);
                        Shell_NotifyIcon(NIM_MODIFY, &iconData);
                    }

                    if (hThread) {
                        gbuf[0] = 0;
                        ShowWindow(hDlg, SW_HIDE);
                        flag = 0;
                        return TRUE;
                    }
                    SetDlgItemText(hDlg, IDC_EDIT2, "No gateway specified");
                    SetFocus(hCtrlEdit);
                    return FALSE;
                                
                case IDCANCEL:
                    EndDialog(hDlg, IDOK);
                    return TRUE;
                    
                case IDC_LISTBOX1:          // Selection

                    if (busy)
                        return TRUE;

                    connection[0] = 0;

                    len = SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_GETCURSEL, 0, 0);

                    if (len == LB_ERR)
                        return TRUE;

                    SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_GETTEXT, (WPARAM) len, (LPARAM) (LPCTSTR) tmp);
                    str_esc(tmp);
                    sscanf(tmp, "<%s", connection);
                    if (strlen(connection) > 0) {
                        ptr = strchr(connection, '>');
                        if (ptr)
                            *ptr = 0;
                        EnableWindow(hCtrlDial, 0);
                        EnableWindow(hCtrlHangup, 1);
                    }
                    else {
                        EnableWindow(hCtrlDial, 1);
                        EnableWindow(hCtrlHangup, 0);
                        strcpy(connection, tmp);
                    }

                    return TRUE;

                case IDC_PUSHBUTTON1:       // HANGUP

                    EnableWindow(hCtrlDial, 0);
                    EnableWindow(hCtrlHangup, 0);

                    sprintf(xbuf, "hangup %s", connection);

                    ReleaseSemaphore(hSem, 1, NULL);
                    dial = 0;

                    return TRUE;    

                case IDC_PUSHBUTTON2:       // DIAL
                
                    EnableWindow(hCtrlDial, 0);
                    EnableWindow(hCtrlHangup, 0);

                    sprintf(xbuf, "dial %s", connection);

                    ReleaseSemaphore(hSem, 1, NULL);
                    dial = 1;

                    return TRUE;    

                case IDC_PUSHBUTTON3:       // WAKE
                
                    EnableWindow(hCtrlDial, 0);
                    EnableWindow(hCtrlHangup, 0);

                    wol();
                    sprintf(tmp, "Magic Packet sent to %02X-%02X-%02X-%02X-%02X-%02X",
                                                        mac[0] & 0xff,
                                                        mac[1] & 0xff,
                                                        mac[2] & 0xff,
                                                        mac[3] & 0xff,
                                                        mac[4] & 0xff,
                                                        mac[5] & 0xff);
                    SetDlgItemText(hDlg, IDC_EDIT2, tmp);
                    return TRUE;
            }
        break;
    }
    return FALSE;
}


BOOL CenterWindow(HWND hWin) 
{
    int result;
    HWND hDesktop;

    RECT rc;
    RECT rcd;
        
    hDesktop = GetDesktopWindow();
    result = GetWindowRect(hWin, &rc);

    if (result)
        result = GetWindowRect(hDesktop, &rcd);
    
    if (result == 0)
        return -1;
        
    SetWindowPos(hWin, HWND_TOP,
                 rcd.right/2 - (rc.right - rc.left)/2,
                 rcd.bottom/2 - (rc.bottom - rc.top)/2,
                 0, 0,
                 SWP_NOSIZE);
    return 0;
}

/* sockio.c -   connectUDP connectTCP passiveUDP passiveTCP 
                sRead sWrite sReadFrom sWriteTo sClose sShutdown 
                wname2ip wip2name */

u_short portbase = 0;        /* port base, for non-root servers */

/*------------------------------------------------------------------------
 * connectUDP - connect to a specified UDP service on a specified host
 *------------------------------------------------------------------------
*/
int P32API
connectUDP( host, service )
char	*host;		/* name of host to which connection is desired	*/
char	*service;	/* service associated with the desired port	*/
{
    return connectsock(host, service, "udp");
}

/*------------------------------------------------------------------------
 * connectTCP - connect to a specified TCP service on a specified host
 *------------------------------------------------------------------------
*/
int P32API
connectTCP( host, service )
char	*host;		/* name of host to which connection is desired	*/
char	*service;	/* service associated with the desired port	*/
{
	return connectsock( host, service, "tcp");
}
/*------------------------------------------------------------------------
 * passiveUDP - create a passive socket for use in a UDP server
 *------------------------------------------------------------------------
*/
int P32API
passiveUDP( service )
char    *service;           /* service associated with the desired port */
{
    return passivesock(service, "udp", 0);
}

/*------------------------------------------------------------------------
 * passiveTCP - create a passive socket for use in a TCP server
 *------------------------------------------------------------------------
*/
int P32API
passiveTCP( service, qlen )
char    *service;           /* service associated with the desired port */
int qlen;                   /* maximum server request queue length      */
{
	return passivesock(service, "tcp", qlen);
}

/*------------------------------------------------------------------------
 * sAccept - accept a TCP connection
 *------------------------------------------------------------------------
*/
int P32API
sAccept( s, saddr)
SOCKET s;
struct saddr *saddr;
{
    int alen = sizeof(struct sockaddr);
    return accept(s, (struct sockaddr *) saddr, &alen);
}

/*------------------------------------------------------------------------
 *  sRead - receive from a connected socket
 *------------------------------------------------------------------------
*/
int P32API
sRead(s, buf, len)
SOCKET s;
char *buf;
int len;
{ 
    return recv(s, buf, len, 0);
}

/*------------------------------------------------------------------------
 *  sReadT - receive from a connected socket with TIMEOUT in msec
 *------------------------------------------------------------------------
*/
int P32API
sReadT(s, buf, len, time)
SOCKET s;
char *buf;
int len;
int time;
{ 
    struct timeval timeout;
    int    result;
    fd_set rfds;

    timeout.tv_sec = 0;
    timeout.tv_usec = time * 1000;


    FD_ZERO(&rfds);
    FD_SET(s, &rfds);

    result = select(FD_SETSIZE, &rfds, (fd_set *) 0, (fd_set *) 0, &timeout);

    switch (result) {
        
        case 0: return TIMEOUT;

        case 1: return recv(s, buf, len, 0);
                
        case SOCKET_ERROR: dprintf("sReadT: select returned SOCKET_ERROR %d\n", WSAGetLastError());
                           return SYSERR;
                           
        default: return SYSERR;
    }
}
/*------------------------------------------------------------------------
 *  sReadFrom - receive a datagram from a connected or unconnected socket
 *------------------------------------------------------------------------
*/
int P32API
sReadFrom(s, buf, len, saddr)
SOCKET s;
char *buf;
int len;
struct saddr *saddr;
{ 
    int alen = sizeof(struct saddr);
    
    saddr->sin_family = AF_INET;
    return recvfrom(s, buf, len, 0, (struct sockaddr *) saddr, &alen);
}

/*------------------------------------------------------------------------
 *  sReadFromT - receive a datagram with timeout from (un)connected socket
 *------------------------------------------------------------------------
*/
int P32API
sReadFromT(s, buf, len, saddr, time)
SOCKET s;
char *buf;
int len;
struct saddr *saddr;
int time;
{ 
    struct timeval timeout;
    int    result;
    fd_set rfds;
    int alen = sizeof(struct saddr);

    timeout.tv_sec = 0;
    timeout.tv_usec = time * 1000;

    FD_ZERO(&rfds);
    FD_SET(s, &rfds);

    result = select(FD_SETSIZE, &rfds, (fd_set *) 0, (fd_set *) 0, &timeout);

    switch (result) {
        
        case 0: return TIMEOUT;

        case 1: saddr->sin_family = AF_INET;
                return recvfrom(s, buf, len, 0, (struct sockaddr *) saddr, &alen);
                
        case SOCKET_ERROR: printf("sReadT: select returned SOCKET_ERROR\n");
                           return SYSERR;
                           
        default: return SYSERR;
    }
}

/*------------------------------------------------------------------------
 *  sWrite - send to a connected socket
 *------------------------------------------------------------------------
*/
int P32API
sWrite(s, buf, len)
SOCKET s;
char *buf;
int len;
{
    return send(s, buf, len, 0);
}

/*------------------------------------------------------------------------
 *  sWriteTo - send to an unconnected socket
 *------------------------------------------------------------------------
*/
int P32API
sWriteTo(s, buf, len, saddr)
SOCKET s;
char *buf;
int len;
struct saddr *saddr;
{
    int alen = sizeof(struct saddr);
    saddr->sin_family = AF_INET;
    if (sendto(s, buf, len, 0, (struct sockaddr *) saddr, alen) <= 0)
        return h_errno;
    return OK;
//    return sendto(s, buf, len, 0, (struct sockaddr *) saddr, alen);
}

/*------------------------------------------------------------------------
 *  sClose  --  close a socket
 *------------------------------------------------------------------------
*/

int P32API
sClose(SOCKET s)
{

    if (s == SYSERR)
        return SYSERR;
           
    return closesocket(s);
}

/*------------------------------------------------------------------------
 *  sShutdown  --  shutdown a socket
 *------------------------------------------------------------------------
*/

int P32API
sShutdown(SOCKET s)
{
    int status;

    status = shutdown(s, 1);    /* disable sends */
    if (status)
        printf("\nsockio: shutdown failed\n");

    return status;
}

/*------------------------------------------------------------------------
 * sockalloc - allocate a UDP socket
 *------------------------------------------------------------------------
*/
int P32API
sockalloc()
{
    SOCKET s;
        
    if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
        printf("\nsockio: can't create socket: error %d\n", h_errno);
        return SYSERR;
    }
    return s;
}

/*------------------------------------------------------------------------
 * connectsock - allocate & connect a socket using TCP or UDP
 *------------------------------------------------------------------------
*/
int P32API
connectsock( host, service, protocol )
char	*host;		/* name of host to which connection is desired	*/
char	*service;	/* service associated with the desired port	*/
char	*protocol;	/* name of protocol to use ("tcp" or "udp")	*/
{
	struct hostent	*phe;	/* pointer to host information entry	*/
	struct servent	*pse;	/* pointer to service information entry	*/
	struct protoent *ppe;	/* pointer to protocol information entry*/
    struct sockaddr_in sin; /* an Internet endpoint address     */
    SOCKET s;               /* socket descriptor */
    int    type;            /* socket type    */
    char   option = TRUE;   /* enable the Boolean option */
        
    memset((char *)&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;

    /* Map service name to port number */
    
	if ( pse = getservbyname(service, protocol) )
		sin.sin_port = pse->s_port;
    else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 ) {
        printf("\nsockio: can't get %s service entry\n", service);
        return SYSERR;
    }

    /* Map host name to IP address, allowing for dotted decimal */

    /* CAUTION: inet_addr interprets an address such as 192.168.000.010
                as 192.168.0.8 and NOT 192.168.0.10
                In other words, it assumes that a leading zero indicates
                octal notation
                                                                      */
                
    if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
        if ( phe = gethostbyname(host) )
            memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
        else {
            kprintf("\nsockio: can't get %s host entry\n", host);
            return SYSERR;
        }

    /* Map protocol name to protocol number */

    if ( (ppe = getprotobyname(protocol)) == 0) {
        printf("\nsockio: can't get %s protocol entry\n", protocol);
        return SYSERR;
    }

    /* Use protocol to choose a socket type */

    if (strcmp(protocol, "udp") == 0)
        type = SOCK_DGRAM;
	else
        type = SOCK_STREAM;

    /* Allocate a socket */

    s = socket(PF_INET, type, ppe->p_proto);

    if (s == INVALID_SOCKET) {
        printf("\nsockio: can't create socket: error %d\n", h_errno);
        return SYSERR;
    }

    /* Connect the socket */

    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        printf("\nsockio: can't connect to %s:%s error %d\n", host, service, h_errno);
        return SYSERR;
    }

    /* Enable UDP broadcasts */
    
    if (type == SOCK_DGRAM)
        setsockopt(s, SOL_SOCKET, SO_BROADCAST, &option, sizeof(BOOL));
    return s;
}

/*------------------------------------------------------------------------
 * passivesock - allocate & bind a server socket using TCP or UDP
 *------------------------------------------------------------------------
 */
int P32API
passivesock( service, protocol, qlen )
char	*service;	/* service associated with the desired port	*/
char	*protocol;	/* name of protocol to use ("tcp" or "udp")	*/
int qlen;           /* maximum length of the server request queue   */
{
	struct servent	*pse;	/* pointer to service information entry	*/
	struct protoent *ppe;	/* pointer to protocol information entry*/
	struct sockaddr_in sin;	/* an Internet endpoint address		*/
    int s, type;            /* socket descriptor and socket type    */
    char   option = TRUE;   /* enable the Boolean option */
    
    memset((char *)&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;

    /* Map service name to port number */
    
    if ( pse = getservbyname(service, protocol) )
        sin.sin_port = htons(ntohs((u_short)((u_short)pse->s_port + portbase)));
    else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 ) {
        printf("\nsockio: can't get %s service entry\n", service);
        return SYSERR;
    }

    /* Map protocol name to protocol number */

    if ( (ppe = getprotobyname(protocol)) == 0) {
        printf("\nsockio: can't get %s protocol entry\n", protocol);
        return SYSERR;
    }

    /* Use protocol to choose a socket type */

    if (strcmp(protocol, "udp") == 0)
        type = SOCK_DGRAM;
	else
        type = SOCK_STREAM;

    /* Allocate a socket */

    s = socket(PF_INET, type, ppe->p_proto);

    if (s < 0) {
        printf("\nsockio: can't create socket: error %d\n", h_errno);
        return SYSERR;
    }

    /* Bind the socket */

    if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        closesocket(s);
        return SYSERR;
    }

    if (type == SOCK_STREAM && listen(s, qlen) < 0) {
        printf("\nsockio: can't listen on %s port: error %d\n", service, h_errno);
        return SYSERR;
    }

    /* Enable UDP broadcasts */
    
    if (type == SOCK_DGRAM)
        setsockopt(s, SOL_SOCKET, SO_BROADCAST, &option, sizeof(BOOL));

    return s;
}

/*------------------------------------------------------------------------
 * wname2ip - resolve a DNS name                              
 *------------------------------------------------------------------------
*/
int P32API
wname2ip(ip, nam)
IPaddr  ip;             /* resolved IP address */
char    *nam;           /* name to resolve */
{
    struct hostent  *phe;       /* pointer to host information entry */
    struct sockaddr_in sin;     /* an Internet endpoint address */

    memset((char *)&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;

    /* Map host name to IP address, allowing for dotted decimal */

    if ((sin.sin_addr.s_addr = inet_addr(nam)) == INADDR_NONE)
        if ( phe = gethostbyname(nam))
            memcpy(ip, phe->h_addr, phe->h_length);
        else 
            return SYSERR;
    else {
        memcpy(ip, &sin.sin_addr.s_addr, 4);
        return OK;
    }
    return OK;
}

/*------------------------------------------------------------------------
 * wip2name - find the DNS name for a given IP address                              
 *------------------------------------------------------------------------
*/
int P32API
wip2name(nam, ip)
IPaddr  ip;             /* IP address to resolve */
char    *nam;           /* resolved name */
{
    struct hostent  *phe;   /* pointer to host information entry */
    
    if (phe=gethostbyaddr(ip, 4, AF_INET)) {
        strcpy(nam, phe->h_name);
        return OK;
    }
    return SYSERR;
}

/*------------------------------------------------------------------------
 *  wip2dot - create the dotted decimal form of ip in pdot
 *------------------------------------------------------------------------
 */
int P32API wip2dot(pdot, ip)
char	*pdot;
IPaddr	ip;
{
	char	*pch = pdot;
	int	i;

    sprintf(pch, "%u", ip[0] & 0xff);
	pch += strlen(pch);
	for (i=1; i<IP_ALEN; ++i) {
        sprintf(pch, ".%u", ip[i] & 0xff);
		pch += strlen(pch);
	}
    *pch = 0;
    return OK;
}

/*------------------------------------------------------------------------
 *  hl2net - convert long from host to net byte order
 *------------------------------------------------------------------------
 */
unsigned long P32API hl2net(unsigned long hlong)
{
    return htonl(hlong);
}

/*------------------------------------------------------------------------
 *  hs2net - convert short from host to net byte order
 *------------------------------------------------------------------------
 */
unsigned short P32API hs2net(unsigned short hshort)
{
    return htons(hshort);
}

/*------------------------------------------------------------------------
 *  net2hl - convert long from net to host byte order
 *------------------------------------------------------------------------
 */
unsigned long P32API net2hl(unsigned long hlong)
{
    return ntohl(hlong);
}

/*------------------------------------------------------------------------
 *  net2hs - convert short from net to host byte order
 *------------------------------------------------------------------------
 */
unsigned short P32API net2hs(unsigned short hshort)
{
    return ntohs(hshort);
}

/*------------------------------------------------------------------------
 *  getInfo - get socket info
 *------------------------------------------------------------------------
 */
int P32API getInfo(SOCKET s, char *buf)
{
    struct saddr info;
    int len = sizeof(struct saddr);
    unsigned short port;
    char tmp[16];
    
    if (getsockname(s, (struct sockaddr *) &info, &len) == SOCKET_ERROR) {
        strcpy(buf, "no info");
        return OK;
    }

    wip2dot(buf, info.sin_addr);
    strcat(buf, ":");
    port = net2hs(info.sin_port);
    sprintf(tmp, "%d", port);
    strcat(buf, tmp);
          
    return OK;
}

/*------------------------------------------------------------------------
 *  sCleanup  --  close all sockets for the specified PID
 *------------------------------------------------------------------------
*/

int P32API
sCleanup(int pid)
{
    return 0;
}

BOOL APIENTRY HelpDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	int wmID;
    
    switch (msg) {              /* these values are defined in winuser.h */

        case WM_INITDIALOG:
            return TRUE;

        case WM_DESTROY:
            break;

        case WM_COMMAND:

            wmID = LOWORD(wParam);
  
            switch (wmID) {

                case IDOK:
                case IDCANCEL:
                
                    EndDialog(hDlg, IDOK);
                    return TRUE;

            }
            break;
    }
    return FALSE;
}

// Display the Help dialog box

int EnterDialogBoxHelp()
{    
    int result;

    result = DialogBox(hInst, "HELP", NULL, HelpDlgProc);
    if (result == -1) {
        kprintf("unable to create HELP dialog\n");
        return -1;
    }

    return 1;
}

//
// exec - execute an application and don't wait for completion
//
int exec(char *cmdline, short flag)
{
    BOOL result;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;    

    GetStartupInfo(&si);

    si.dwFlags |= STARTF_USESHOWWINDOW;
    si.wShowWindow = flag;

    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
        
    result = CreateProcess(
    (LPCTSTR)               NULL,
    (LPTSTR)                cmdline,
    (LPSECURITY_ATTRIBUTES) NULL,
    (LPSECURITY_ATTRIBUTES) NULL,
    (BOOL)                  FALSE,
    (DWORD)                 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
    (LPVOID)                NULL,
    (LPCTSTR)               NULL,
    (LPSTARTUPINFO)         &si,
    (LPPROCESS_INFORMATION) &pi);
    
    if (result)
         return 0;

    return GetLastError();
}

