// initially created by QuickCase:W KNB Version 1.00
/*
  Windows Sockets FTP Application

  Written by: John A. Junod            Internet: <junodj@gordon-emh2.army.mil>
              267 Hillwood Street                <zj8549@trotter.usma.edu>
              Martinez, GA 30907     Compuserve: 72321,366 

  This program executable and all source code is released into the public
  domain.  The primary purpose of this application was to learn what it
  takes to write a Window Sockets Application and this is NOT a full 
  implementation of an FTP client.  A later release of this program MAY
  be a complete implementation.

  Problems:
  1) Only binary transfers are allowed.
  2) Return code checking is incomplete.
  3) Restarts are not supported.
  4) Needs to use non-blocking sockets.

  MODULE: WS_MAIN.C  (main window functions and some dialog boxes)
*/

//----------------------
#include "ws_glob.h"
#include "WS_ftp.H"
//----------------------

BOOL bAutoStart=FALSE;

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
                   LPSTR lpszCmdLine, int nCmdShow)
{
  /***********************************************************************/
  /* HANDLE hInstance;       handle for this instance                    */
  /* HANDLE hPrevInstance;   handle for possible previous instances      */
  /* LPSTR  lpszCmdLine;     long pointer to exec command line           */
  /* int    nCmdShow;        Show code for main window display           */
  /***********************************************************************/
  MSG        msg;           // MSG structure to store your messages
  int        nRc;           // return value from Register Classes
  long       nWndunits;     // window units for size and location
  int        nWndx;         // the x axis multiplier
  int        nWndy;         // the y axis multiplier
  int        nX;            // the resulting starting point (x, y)
  int        nY;
  int        nWidth;        // the resulting width and height for this
  int        nHeight;       // window
  int        err;

  strcpy(szAppName, "WS_FTP");
  hInst = hInstance;
  if(!hPrevInstance)
  {
    // register window classes if first instance of application
    if ((nRc = nCwRegisterClasses()) == -1)
    {
      // registering one of the windows failed
      LoadString(hInst, IDS_ERR_REGISTER_CLASS, (LPSTR) szString, 128); 
      MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
      return nRc;    
    }
  }

  // Create a device independant size and location
  nWndunits = GetDialogBaseUnits();
  nWndx = LOWORD(nWndunits);
  nWndy = HIWORD(nWndunits);
  nX = ((18 * nWndx) / 4);
  nY = ((18 * nWndy) / 8);
  nWidth = ((200 * nWndx) / 4);
  nHeight = ((200 * nWndy) / 8);

  // create application's Main window
  hWndMain = CreateWindow(
           szAppName,            // Window class name
           "WinSock_FTP",        // Window's title
           WS_CAPTION      |     // Title and Min/Max
           WS_SYSMENU      |     // Add system menu box
           WS_MINIMIZEBOX  |     // Add minimize box
           WS_MAXIMIZEBOX  |     // Add maximize box
           WS_THICKFRAME   |     // thick sizeable frame
           WS_VSCROLL      |
//         ES_AUTOVSCROLL  |
           WS_CLIPCHILDREN |     // don't draw in child windows areas
           WS_OVERLAPPED,
           nX,nY,
           nWidth, nHeight,
           NULL,                 // Parent window's handle
           NULL,                 // Default to Class Menu
           hInst,                // Instance of window
           NULL);                // Create struct for WM_CREATE

  if(hWndMain == NULL)
  {
    LoadString(hInst, IDS_ERR_CREATE_WINDOW, (LPSTR)szString,128);
    MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
    return IDS_ERR_CREATE_WINDOW;
  }

//  MessageBox(hWndMain,lpszCmdLine,"WS_FTP",MB_OK);
  if(strncmp(lpszCmdLine,"-d",2)==0)
    bAutoStart=FALSE;

  if (err = WSAStartup( 0x0101, &WSAData))  // register task with
  {                                         // winsock tcp/ip API
    ReportWSError(err);            
  } else {
    GetLocalInfo();
    ShowWindow(hWndMain, nCmdShow);         // display main window
    while(GetMessage(&msg, NULL, 0, 0))     // Until WM_QUIT message
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    WSACleanup();
    ReleaseDisplayMem();
  }
  // Do clean up before exiting from the application
  CwUnRegisterClasses();
  return msg.wParam;
} //  End of WinMain

/************************************************************************/
/* Main Window Procedure                                                */
/* This procedure provides service routines for the Windows events      */
/* (messages) that Windows sends to the window, as well as the user     */
/* initiated events (messages) that are generated when the user selects */
/* the action bar and pulldown menu controls or the corresponding       */
/* keyboard accelerators.                                               */
/************************************************************************/
LONG FAR PASCAL WndProc(HWND hWnd,WORD Message,WORD wParam,LONG lParam)
{
// int nRC;

  switch (Message)
  {
    case WM_TIMER:
      if(wParam==10){
        KillTimer(hWndMain,10);
        if(WSAIsBlocking()) {
          DoAddLine("Timer cancelled blocking call");    
          WSACancelBlockingCall();
        }
      }
      break;
    case WM_COMMAND:
      if(wParam==WM_CLOSE || wParam==IDM_EXIT) {
          if(WSAIsBlocking()){
            DoAddLine("Close cancelled blocking call");
            WSACancelBlockingCall();
          }
          command((SOCKET)ctrl_socket,"QUIT");
          if(shutdown(ctrl_socket,2)==SOCKET_ERROR)
            ReportWSError(WSAGetLastError());
          ctrl_socket=(SOCKET)DoClose((SOCKET)ctrl_socket);
          if(wParam==IDM_EXIT)
            SendMessage(hWnd,WM_CLOSE,0,0L);
          break;
      } else if(bCmdInProgress) return(FALSE);
      switch (wParam)
      {
        case IDM_CONNECT:
          ctrl_socket=(SOCKET)DoClose((SOCKET)ctrl_socket);
          { FARPROC lpfnMsgProc;
            lpfnMsgProc=MakeProcInstance((FARPROC)WS_HostMsgProc,hInst);
            DialogBox(hInst,(LPSTR)"DLG_HOST",hWnd,lpfnMsgProc);
            FreeProcInstance(lpfnMsgProc);
          }
          ctrl_socket=(SOCKET)DoConnect(pinghost);
          break;

        case CMD_LIST:
          if(DoDirList((SOCKET)ctrl_socket,"LIST")==FTP_COMPLETE)
          {
            wsprintf(szMsgBuf,"notepad %s",szTmpFile);
            WinExec(szMsgBuf,SW_SHOW);
          }
          break;

        case CMD_NLST:
          if(DoDirList((SOCKET)ctrl_socket,"NLST")==FTP_COMPLETE)
          {
            wsprintf(szMsgBuf,"notepad %s",szTmpFile);
            WinExec(szMsgBuf,SW_SHOW);
          }
          break;

        case CMD_HELP:
          command((SOCKET)ctrl_socket,"HELP");
          break;

        case CMD_STATUS:
          DoSTAT((SOCKET)ctrl_socket);
          break;

        case CMD_PWD:
          DoPWD((SOCKET)ctrl_socket);
          break;

        case CMD_QUOTE:
          { FARPROC lpfnMsgProc;
            lstrcpy(dlg_prompt,"Enter command for remote host:");
            dlg_edit[0]=0;
            lpfnMsgProc=MakeProcInstance((FARPROC)WS_InputMsgProc,hInst);
            DialogBox(hInst,(LPSTR)"DLG_INPUT",hWnd,lpfnMsgProc);
            FreeProcInstance(lpfnMsgProc);
          }
          DoQUOTE((SOCKET)ctrl_socket,dlg_edit);
          break;

        case CMD_CWD:
          { FARPROC lpfnMsgProc;
            lstrcpy(dlg_prompt,"Enter remote directory name:");
            dlg_edit[0]=0;
            lpfnMsgProc=MakeProcInstance((FARPROC)WS_InputMsgProc,hInst);
            DialogBox(hInst,(LPSTR)"DLG_INPUT",hWnd,lpfnMsgProc);
            FreeProcInstance(lpfnMsgProc);
          }
          DoCWD((SOCKET)ctrl_socket,dlg_edit);
          break;

        case IDM_CLOSE:
        case IDM_EXIT:
          command((SOCKET)ctrl_socket,"QUIT");
          if(shutdown(ctrl_socket,2)==SOCKET_ERROR)
            ReportWSError(WSAGetLastError());
          ctrl_socket=(SOCKET)DoClose((SOCKET)ctrl_socket);
          if(wParam==IDM_EXIT)
            SendMessage(hWnd,WM_CLOSE,0,0L);
          break; 

        case IDM_ABOUT:
          { FARPROC lpfnMsgProc;
            lpfnMsgProc = MakeProcInstance((FARPROC)WS_AboutMsgProc, hInst); 
            DialogBox(hInst, (LPSTR)"DLG_ABOUT", hWnd, lpfnMsgProc);
            FreeProcInstance(lpfnMsgProc);
          }
          break;

        case IDM_MAIN:
          { FARPROC lpfnMsgProc;
            lpfnMsgProc = MakeProcInstance((FARPROC)WS_MainMsgProc, hInst);
            DialogBox(hInst, (LPSTR)"DLG_MAIN", hWnd, lpfnMsgProc);
            FreeProcInstance(lpfnMsgProc);
          }
          break;

        default:
          return DefWindowProc(hWnd, Message, wParam, lParam);
      }
      break;
    case WM_SETCURSOR:
      if(bCmdInProgress)
        SetCursor(hWaitCursor);
      else
        return DefWindowProc(hWnd, Message, wParam, lParam);
        // SetCursor(hStdCursor);
      break;

    case WM_CREATE:
      hStdCursor=LoadCursor(NULL,IDC_ARROW);
      hWaitCursor=LoadCursor(NULL,IDC_WAIT);
      GetPrivateProfileString("WS_FTP", "HOSTNAME",
           "192.108.177.2",pinghost,79,"WINSOCK.INI");
      GetPrivateProfileString("WS_FTP", "USERID",
           "junodj", userid, 80,"WINSOCK.INI");
      SetScrollRange(hWnd, SB_VERT, 0, 100, FALSE);
      sVPos = 0;    // scroll bar is initially 0
      if(bAutoStart)
        PostMessage(hWnd,WM_COMMAND,IDM_MAIN,0L);
      break;

    case WM_MOVE:   // code for moving the window 
      break;
    
    case WM_SIZE:   // code for sizing client area
      break;

    case WM_PAINT:  // code for the window's client area
      DoPaint((HWND)hWnd);
      break;

    case WM_CLOSE:  // close the window 
      // Destroy child windows, modeless dialogs, then, this window
      if(bConnected || ctrl_socket!=INVALID_SOCKET) 
        ctrl_socket=(SOCKET)DoClose((SOCKET)ctrl_socket);
      WritePrivateProfileString("WS_FTP", "HOSTNAME",pinghost,"WINSOCK.INI");
      WritePrivateProfileString("WS_FTP", "USERID", userid,"WINSOCK.INI");
      DestroyWindow(hWnd);
      if (hWnd == hWndMain)
        PostQuitMessage(0);  // Quit the application
      break;

    case WM_VSCROLL:
      switch(wParam)
      {
        case SB_LINEDOWN:
          if(sVPos<(ptrhGMem-1)) sVPos++;
          break;
        case SB_LINEUP:
          if(sVPos>0) --sVPos;
          break;
        case SB_THUMBPOSITION:
          sVPos = min(ptrhGMem, LOWORD(lParam));
          break;
        case SB_PAGEUP:
          if(sVPos>10) sVPos-=10; else sVPos=0;
          break;
        case SB_PAGEDOWN:
          if(sVPos<(ptrhGMem-10)) sVPos+=10; else sVPos=ptrhGMem;
          break;
        default:
          return FALSE;
      }
      SetScrollPos(hWnd,SB_VERT,sVPos,TRUE);
      InvalidateRect(hWnd,NULL,TRUE);
      break;

    default:
      /* For any message for which you don't specifically provide a  */
      /* service routine, you should return the message to Windows   */
      /* for default message processing.                             */
      return DefWindowProc(hWnd, Message, wParam, lParam);
  }
  return 0L;
} // End of WndProc

/************************************************************************/
/* Misc Dialog Window Procedures                                        */
/************************************************************************/
BOOL FAR PASCAL WS_AboutMsgProc(HWND hWndDlg, WORD Message, 
                                WORD wParam, LONG lParam)
{ 
 switch(Message)
 {
   case WM_INITDIALOG:
     cwCenter(hWndDlg, 0);
     break;
   case WM_CLOSE:
     PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L);
     break;
   case WM_COMMAND:
     switch(wParam)
     {
       case IDOK:
         EndDialog(hWndDlg, TRUE);
         break;
       case IDCANCEL:
         EndDialog(hWndDlg, FALSE);
         break;
     }
     break;
    default:
        return FALSE;
  }
  return TRUE;
}

BOOL FAR PASCAL WS_HostMsgProc(HWND hWndDlg, WORD Message,
                               WORD wParam, LONG lParam)
{ 
  switch(Message)
  {
    case WM_INITDIALOG:
      SetDlgItemText(hWndDlg,EDIT_HOST,pinghost);
      SetDlgItemText(hWndDlg,EDIT_USERID,userid);
      SetDlgItemText(hWndDlg,EDIT_PASSWD,passwd);
      cwCenter(hWndDlg, 0);
      break;
    case WM_CLOSE:
      PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L);
      break;
    case WM_COMMAND:
      switch(wParam)
      {
        case IDOK:
          GetDlgItemText(hWndDlg,EDIT_HOST,pinghost,70);
          GetDlgItemText(hWndDlg,EDIT_USERID,userid,15);
          GetDlgItemText(hWndDlg,EDIT_PASSWD,passwd,50);
          EndDialog(hWndDlg, TRUE);
          break;
        case IDCANCEL:
          EndDialog(hWndDlg, FALSE);
          break;
      }
      break;
    default:
      return FALSE;
  }
  return TRUE;
}

BOOL FAR PASCAL WS_InputMsgProc(HWND hWndDlg, WORD Message,
                                WORD wParam, LONG lParam)
{ 
  switch(Message)
  {
    case WM_INITDIALOG:
      SetDlgItemText(hWndDlg,DLG_PROMPT,dlg_prompt);
      SetDlgItemText(hWndDlg,DLG_EDIT,dlg_edit);
      cwCenter(hWndDlg, 0);
      break;
    case WM_CLOSE:
      PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L);
      break;
    case WM_COMMAND:
      switch(wParam)
      {
        case IDOK:
          GetDlgItemText(hWndDlg,DLG_EDIT,dlg_edit,70);
          EndDialog(hWndDlg, TRUE);
          break;
        case IDCANCEL:
          EndDialog(hWndDlg, FALSE);
          break;
      }
      break;
    default:
      return FALSE;
  }
  return TRUE;
}

/************************************************************************/
/*                                                                      */
/* nCwRegisterClasses Function                                          */
/*                                                                      */
/* The following function registers all the classes of all the windows  */
/* associated with this application. The function returns an error code */
/* if unsuccessful, otherwise it returns 0.                             */
/*                                                                      */
/************************************************************************/
int nCwRegisterClasses(void)
{
  WNDCLASS   wndclass;    // struct to define a window class
  memset(&wndclass, 0x00, sizeof(WNDCLASS));

  // load WNDCLASS with window's characteristics
  wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;
  wndclass.lpfnWndProc = WndProc;
  // Extra storage for Class and Window objects
  wndclass.cbClsExtra = 0;
  wndclass.cbWndExtra = 0;
  wndclass.hInstance = hInst;
  wndclass.hIcon = LoadIcon(hInst, "WS_FTP");
  wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  // Create brush for erasing background
  wndclass.hbrBackground = CreateSolidBrush(RGB(128, 128, 128));
  wndclass.lpszMenuName = szAppName;   /* Menu Name is App Name */
  wndclass.lpszClassName = szAppName; /* Class Name is App Name */
  if(!RegisterClass(&wndclass))
    return -1;
 
  return(0);
} // End of nCwRegisterClasses

/************************************************************************/
/*  cwCenter Function                                                   */
/*  centers a window based on the client area of its parent             */
/************************************************************************/
void cwCenter(hWnd, top)
HWND hWnd;
int top;
{
  POINT      pt;
  RECT       swp;
  RECT       rParent;
  int        iwidth;
  int        iheight;

  // get the rectangles for the parent and the child
  GetWindowRect(hWnd, &swp);
  GetClientRect(hWndMain, &rParent);

  // calculate the height and width for MoveWindow
  iwidth = swp.right - swp.left;
  iheight = swp.bottom - swp.top;

  // find the center point and convert to screen coordinates
  pt.x = (rParent.right - rParent.left) / 2;
  pt.y = (rParent.bottom - rParent.top) / 2;
  ClientToScreen(hWndMain, &pt);

  // calculate the new x, y starting point
  pt.x = pt.x - (iwidth / 2);
  pt.y = pt.y - (iheight / 2);

  // top will adjust the window position, up or down
  if(top)
    pt.y = pt.y + top;

  // move the window
  MoveWindow(hWnd, pt.x, pt.y, iwidth, iheight, FALSE);
} // end of cwCenter

/************************************************************************/
/*  CwUnRegisterClasses Function                                        */
/*  Deletes any refrences to windows resources created for this         */
/*  application, frees memory, deletes instance, handles and does       */
/*  clean up prior to exiting the window                                */
/************************************************************************/
void CwUnRegisterClasses(void)
{
  WNDCLASS   wndclass;    // struct to define a window class
  memset(&wndclass, 0x00, sizeof(WNDCLASS));

  GetClassInfo(hInst, szAppName, &wndclass);
  DeleteObject(wndclass.hbrBackground);
  UnregisterClass(szAppName, hInst);
} // End of CwUnRegisterClasses

