/******************************************************************************
*                                                                             *
* Module Name      : ddxfer.c                                                 *
*                                                                             *
* Descriptive name : Drag-and-Drop File Transfer                              *
*                                                                             *
* Author:  IBM                                                                *
* Date Written:  1996                                                         *
* For use with IBM Personal Communications/3270 for Windows 95                *
*                                                                             *
* Notes:                                                                      *
*        This sample uses the Windows Drag and Drop interface. It displays    *
*        the name of the files in a list box, that are dragged from           *
*        FileManager on this app.                                             *
*                                                                             *
* Compiler: Microsoft Visual C++ version 4.00                                 *
*                                                                             *
* Required                                                                    *
*  header : ddxfer.h hapi_c.h hapi_c32.h                                      *
*  lib    : pcscal32.lib                                                      *
*                                                                             *
******************************************************************************/
/*----------------------------------------------------------------------------*
| Common header files                                                         |
*----------------------------------------------------------------------------*/
#include <windows.h>    // Windows definitions
#include <windowsx.h>   // Windows Macro APIs, window message crackers
#include <shellapi.h>   // Contains Drag/Drop APIs
#include <string.h>     // String

/*----------------------------------------------------------------------------*
| Local header files                                                          |
*----------------------------------------------------------------------------*/
#include "ddxfer.h"
#include "hapi_c.h"

/*----------------------------------------------------------------------------*
| Local variables                                                             |
*----------------------------------------------------------------------------*/
HANDLE   ghInst;
HWND     ghListBox;
HWND     ghMainWnd;
POINT    gpointDrop = {0,0};  // Point where the files were dropped
WORD     gwFilesDropped = 0;  // Total number of files dropped
BOOL     fAscii = TRUE;
BOOL     fCrlf  = TRUE;
BOOL     fTopmost = TRUE;
BOOL     fTerm = FALSE;
HANDLE   hHllBuffer;
char     szOptions[128];
char     szVMDisk[3];
char     szSessID[2];
/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)                              |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function creates the main window and the list box, registers the      |
|   main window to accept Drag/Drop messages, and goes in the message loop.    |
|                                                                              |
*-----------------------------------------------------------------------------*/
int PASCAL WinMain (hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
HANDLE   hInstance;
HANDLE   hPrevInstance;
LPSTR    lpszCmdLine;
int      nCmdShow;
{
   MSG         msg;
   WNDCLASS    wc;
   RECT        rectMain;
   LPSTR       lpHllBuffer ;
   char        szBuffer1[BUFFER_LENGTH] ;
   char        szBuffer2[BUFFER_LENGTH] ;

   // Allocate buffer
   if (!(hHllBuffer = GlobalAlloc(FGString, (DWORD)HLLAPIBUFFER)))
      return FALSE ;

   if (!(lpHllBuffer = GlobalLock(hHllBuffer)))
   {
      GlobalFree(hHllBuffer) ;
      return FALSE ;
   }

   if (lstrlen(lpszCmdLine))
      lstrcpy(lpHllBuffer, lpszCmdLine) ;

   if (!hPrevInstance)
   {
      LoadString(hInstance, LS_MENU, (LPSTR)szBuffer1, sizeof(szBuffer1));
      LoadString(hInstance, LS_CLASS, (LPSTR)szBuffer2, sizeof(szBuffer2));
      wc.style         = (unsigned int)NULL;
      wc.lpfnWndProc   = MainWndProc;
      wc.cbClsExtra    = 0;
      wc.cbWndExtra    = 0;
      wc.hInstance     = hInstance;
      wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(DDXFER));
      wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
      wc.hbrBackground = GetStockObject (WHITE_BRUSH);
      wc.lpszMenuName  = (LPSTR)szBuffer1;
      wc.lpszClassName = (LPSTR)szBuffer2;

      if (!RegisterClass (&wc))
         return FALSE;
   }

   LoadString(hInstance, LS_TITLE, (LPSTR)szBuffer1, sizeof(szBuffer1));
   ghMainWnd = CreateWindow((LPSTR)szBuffer2,
                            (LPSTR)szBuffer1,
                            WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
                            WS_MINIMIZEBOX,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            MAIN_WIDTH,
                            MAIN_HEIGHT,
                            NULL,
                            NULL,
                            hInstance,
                            NULL);

   if (!ghMainWnd)
       return FALSE;

   GetClientRect(ghMainWnd, &rectMain);

   LoadString(hInstance, LS_LISTBOX, (LPSTR)szBuffer1, sizeof(szBuffer1));
   ghListBox = CreateWindow((LPSTR)szBuffer1,
                            NULL,
                            WS_CHILD | WS_VSCROLL | WS_HSCROLL
                            | LBS_NOINTEGRALHEIGHT | WS_VISIBLE
                            | LBS_NOTIFY | LBS_SORT,
                            0,
                            0,
                            rectMain.right - rectMain.left,
                            rectMain.bottom - rectMain.top,
                            ghMainWnd,
                            (HMENU)IDD_LIST,
                            hInstance,
                            NULL);

   if (!ghListBox)
      return FALSE;

   // Register the the main window for Drag/Drop messages.
   DragAcceptFiles(ghMainWnd, TRUE);

   ShowWindow(ghMainWnd, nCmdShow);
   UpdateWindow(ghMainWnd);

   ghInst = hInstance;

   while (GetMessage (&msg, NULL, (unsigned int)NULL, (unsigned int)NULL))
   {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
   }
   return msg.wParam;
}


/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: MainWndProc()                                                    |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function handles messages belonging to the main window.               |
|   It also handles and processes Drag/Drop messages.                          |
|                                                                              |
*-----------------------------------------------------------------------------*/
LONG FAR PASCAL MainWndProc (hWnd, iMessage, wParam, lParam)
HWND     hWnd;
UINT     iMessage;
WPARAM   wParam;
LPARAM   lParam;
{
   FARPROC  lpDialogProc;
   HANDLE   hFilesInfo;
   WORD     wIndex;
   HANDLE   hMenu;
   int      iPlace;
   int      iCount ;
   char     szFileName[FILENAME_LENGTH];
   char     szHostFile[FILENAME_LENGTH];
   char     szFormat[BUFFER_LENGTH];
   char     szList[BUFFER_LENGTH];
   char     szSpace[2] ;
   LPSTR    lpHllBuffer;
   LPSTR    lpToken ;

   switch (iMessage)
   {
      case WM_DROPFILES:
         hFilesInfo = (HANDLE) wParam;

         // Retrieve the window coordinates of the mouse
         // pointer when the drop was made
         DragQueryPoint ((HANDLE) wParam, (LPPOINT) &gpointDrop);

         // Get the total number of files dropped
         gwFilesDropped = DragQueryFile (hFilesInfo,
                                        (UINT)-1,
                                        NULL,
                                        0);

         // Reset terminate flag
         fTerm = FALSE ;

         // Retrieve each file name and add to the list box
         for (wIndex=0 ; wIndex < gwFilesDropped ; wIndex++)
         {
            DragQueryFile(hFilesInfo,
                          wIndex,
                          (LPSTR)szFileName,
                          FILENAME_LENGTH);

            GenerateHostFile((LPSTR)szFileName, (LPSTR)szHostFile);
            SendParmProc(hWnd, (LPSTR)szFileName, (LPSTR)szHostFile, ID_SEND);

            if (!(lpHllBuffer = GlobalLock(hHllBuffer)))
               break;
            AnsiLower(lpHllBuffer);

            lpToken = _fstrchr((LPSTR)szHostFile, ':') ;
            LoadString(ghInst, LS_LIST, (LPSTR)szFormat, sizeof(szFormat)) ;
            wsprintf((LPSTR)szList, (LPSTR)szFormat, (LPSTR)szFileName,
                     (LPSTR)(lpToken + 1), szSessID[0]) ;
            AnsiLower((LPSTR)szList) ;
            SendMessage(ghListBox, LB_SETHORIZONTALEXTENT, (WPARAM)500, 0L);
            SendMessage(ghListBox,
                        LB_ADDSTRING,
                        0,
                        (LONG)(LPSTR)szList);

            GlobalUnlock(hHllBuffer);

            if (fTerm)
               break;
         }
         DragFinish(hFilesInfo);
         break;

      case WM_COMMAND:
         switch (GET_WM_COMMAND_ID(wParam,lParam))
         {
            case IDD_LIST:
               if (GET_WM_COMMAND_CMD(wParam,lParam) == LBN_DBLCLK)
               {
                  if (!(lpHllBuffer = GlobalLock(hHllBuffer)))
                     break;

                  // Get one line
                  SendDlgItemMessage(hWnd, IDD_LIST, LB_GETTEXT, 0,
                                     (LONG)(LPSTR)szList) ;
                  szSpace[0] = ' ' ;
                  szSpace[1] = (char)NULL ;

                  // DOS file name
                  lpToken = _fstrtok((LPSTR)szList, (LPSTR)szSpace) ;
                  lstrcpy(lpHllBuffer, lpToken) ;
                  lstrcat(lpHllBuffer, (LPSTR)szSpace) ;
                  iPlace = lstrlen(lpHllBuffer) ;  // Store place of session ID
                  // Add dummy spaces
                  lstrcat(lpHllBuffer, (LPSTR)szSpace) ;
                  lstrcat(lpHllBuffer, (LPSTR)szSpace) ;

                  // "-->" (skipped)
                  lpToken = _fstrtok(NULL, (LPSTR)szSpace) ;

                  for (iCount = 0 ; iCount < 3 ; iCount++)
                  {
                     // Host file name/type/mode
                     lpToken = _fstrtok(NULL, (LPSTR)szSpace) ;
                     lstrcat(lpHllBuffer, lpToken) ;
                     lstrcat(lpHllBuffer, (LPSTR)szSpace) ;
                  }

                  // "(Session"
                  lpToken = _fstrtok(NULL, (LPSTR)szSpace) ;
                  // Session ID
                  lpToken = _fstrtok(NULL, (LPSTR)szSpace) ;

                  *(lpHllBuffer + iPlace) = *lpToken ;
                  *(lpHllBuffer + iPlace + 1) = ':' ;

                  lpToken = (lpHllBuffer + lstrlen(lpHllBuffer));
                  *(lpToken++) = ' ';
                  GetOption(lpToken);

                  GlobalUnlock(hHllBuffer);
                  SendArgProc(hWnd) ;
               }
               break;

            case IDM_ABOUT:
               lpDialogProc = MakeProcInstance (About, ghInst);
               DialogBox (ghInst,
                          MAKEINTRESOURCE(ABOUTBOX),
                          hWnd,
                          lpDialogProc);
               FreeProcInstance (lpDialogProc);
               break;

            case IDM_TEXT:
               lpDialogProc = MakeProcInstance(TextDlgProc, ghInst);
               DialogBox(ghInst,
                         MAKEINTRESOURCE(TEXTBOX),
                         hWnd,
                         lpDialogProc);
               FreeProcInstance (lpDialogProc);
               break;

            case IDM_TITLE:
               lpDialogProc = MakeProcInstance(TitleDlgProc, ghInst);
               DialogBox(ghInst,
                         MAKEINTRESOURCE(TITLEBOX),
                         hWnd,
                         lpDialogProc);
               FreeProcInstance (lpDialogProc);
               break;

            case  IDM_TOP:
               hMenu = GetMenu(hWnd);
               if (fTopmost)
               {
                  fTopmost = FALSE;
                  CheckMenuItem(hMenu, IDM_TOP, MF_UNCHECKED) ;
               }
               else
               {
                  fTopmost = TRUE;
                  CheckMenuItem(hMenu, IDM_TOP, MF_CHECKED) ;
               }
               SetWindowPos(hWnd, (fTopmost ? HWND_TOPMOST : HWND_NOTOPMOST),
                            0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE |
                            SWP_NOMOVE);
               break;

            case  IDM_TERM:
               fTerm = TRUE;
               break;

            case  IDM_CLEAR :
               SendDlgItemMessage(hWnd, IDD_LIST, LB_RESETCONTENT, 0, 0L);
               break;

            default:
               return (DefWindowProc (hWnd, iMessage, wParam, lParam));
         }
         break;

      case WM_DESTROY:
         GlobalFree(hHllBuffer) ;
         PostQuitMessage (0);
         break;

      case WM_CREATE:
         // Set default VM disk
         szVMDisk[0] = 'A' ;
         szVMDisk[1] = (char)NULL ;

         // Set default Session ID
         szSessID[0] = 'A' ;
         szSessID[1] = (char)NULL ;

         // Check menu
         hMenu = GetMenu(hWnd) ;
         if (fTopmost)
         {
            CheckMenuItem(hMenu, IDM_TOP, MF_CHECKED) ;
            SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
                         SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
         }
         else
         {
            CheckMenuItem(hMenu, IDM_TOP, MF_UNCHECKED) ;
            SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
                         SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
         }

      default:
         return DefWindowProc (hWnd, iMessage, wParam, lParam);

   }
   return 0L;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: About()                                                          |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
*-----------------------------------------------------------------------------*/
BOOL FAR PASCAL About (hDlg, iMessage, wParam, lParam)
HWND     hDlg;
UINT     iMessage;
WPARAM   wParam;
LPARAM   lParam;
{
   switch (iMessage)
   {
      case WM_INITDIALOG:
         return TRUE;

      case WM_COMMAND:
         switch (GET_WM_COMMAND_ID(wParam,lParam))
         {
            case IDOK:
            case IDCANCEL:
               EndDialog (hDlg, TRUE);
               return TRUE;

            default:
               break;
         }
   }
   return FALSE;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: TextDlgProc                                                      |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function handles messages belonging to the "Options" dialog box.      |
|   It displays information of options.                                        |
|                                                                              |
*-----------------------------------------------------------------------------*/
BOOL FAR PASCAL TextDlgProc(hDlg, iMessage, wParam, lParam)
HWND     hDlg;
UINT     iMessage;
WPARAM   wParam;
LPARAM   lParam;
{
   switch (iMessage)
   {
      case WM_INITDIALOG:
         CheckDlgButton(hDlg, IDD_ASCII, fAscii);
         CheckDlgButton(hDlg, IDD_CRLF,  fCrlf);
         SetDlgItemText(hDlg, IDD_ADDITIONAL, (LPSTR)szOptions);
         SetDlgItemText(hDlg, IDD_VMDISK,     (LPSTR)szVMDisk);
         SetDlgItemText(hDlg, IDD_SESSID,     (LPSTR)szSessID);
         return TRUE;

      case WM_COMMAND:
         switch (GET_WM_COMMAND_ID(wParam,lParam))
         {
            case IDOK:
               fAscii = IsDlgButtonChecked(hDlg, IDD_ASCII);
               fCrlf  = IsDlgButtonChecked(hDlg, IDD_CRLF);
               GetDlgItemText(hDlg, IDD_ADDITIONAL, (LPSTR)szOptions,
                              sizeof(szOptions));

               GetDlgItemText(hDlg, IDD_VMDISK, (LPSTR)szVMDisk,
                              sizeof(szVMDisk));

               GetDlgItemText(hDlg, IDD_SESSID, (LPSTR)szSessID,
                              sizeof(szSessID));

               EndDialog (hDlg, TRUE);
               return TRUE;

            case IDCANCEL:
               EndDialog (hDlg, FALSE);
               return TRUE;

            default:
               break;
         }
   }
   return FALSE;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: TitleDlgProc                                                     |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function handles messages belonging to the "Change Title" dialog box. |
|   It displays information of options.                                        |
|                                                                              |
*-----------------------------------------------------------------------------*/
BOOL FAR PASCAL TitleDlgProc(hDlg, iMessage, wParam, lParam)
HWND     hDlg;
UINT     iMessage;
WPARAM   wParam;
LPARAM   lParam;
{
   char  szTitle[TITLE_LEN];

   switch (iMessage)
   {
      case WM_INITDIALOG:
         GetWindowText(ghMainWnd, (LPSTR)szTitle, sizeof(szTitle)) ;
         SetDlgItemText(hDlg, IDD_TITLE, (LPSTR)szTitle) ;
         return TRUE;

      case WM_COMMAND:
         switch (GET_WM_COMMAND_ID(wParam,lParam))
         {
            case IDOK:
               GetDlgItemText(hDlg, IDD_TITLE, (LPSTR)szTitle,
                              sizeof(szTitle));
               SetWindowText(ghMainWnd, (LPSTR)szTitle);
               EndDialog (hDlg, TRUE);
               return TRUE;

            case IDCANCEL:
               EndDialog (hDlg, FALSE);
               return TRUE;

            default:
               break;
         }
   }
   return FALSE;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: SendArgProc                                                      |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function calls hllapi send file function if parameters specified      |
|   in command argument of this exec.                                          |
|                                                                              |
*-----------------------------------------------------------------------------*/
VOID PASCAL SendArgProc(hWnd)
HWND  hWnd ;
{
   int   HllFunc, HllStrLen, HllRetCode;
   LPSTR lpHllBuffer;

   /*--------------------------------------------------------------------------*
   |                                                                           |
   |    HLLAPI call                                                            |
   |    Send file (90)                                                         |
   |                                                                           |
   *--------------------------------------------------------------------------*/
   if (!(lpHllBuffer = GlobalLock(hHllBuffer)))
      return;

   HllFunc   = 90;
   HllStrLen = lstrlen(lpHllBuffer);

   hllapi((LPINT)&HllFunc,
          (LPSTR)lpHllBuffer,
          (LPINT)&HllStrLen,
          (LPINT)&HllRetCode);

   GlobalUnlock(hHllBuffer);
   return;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: SendParmProc()                                                   |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function calls hllapi send file function using parameters from        |
|   options.                                                                   |
|                                                                              |
*-----------------------------------------------------------------------------*/
VOID PASCAL SendParmProc(hWnd, lpszPCFile, lpszHostFile, bSR)
HWND  hWnd;
LPSTR lpszPCFile;
LPSTR lpszHostFile;
BOOL  bSR;
{
   int      HllFunc, HllStrLen, HllRetCode;
   LPSTR    lpHllBuffer;
   LPSTR    lpToken;

   /*--------------------------------------------------------------------------*
   |                                                                           |
   |    HLLAPI call                                                            |
   |    Send file (90) / Receive file (91)                                     |
   |                                                                           |
   *--------------------------------------------------------------------------*/
   if (!(lpHllBuffer = GlobalLock(hHllBuffer)))
      return;

   strncpy(lpHllBuffer, lpszPCFile, lstrlen(lpszPCFile) + 1);
   lpToken = lpHllBuffer + lstrlen(lpszPCFile);
   *(lpToken++) = ' ';
   strncpy(lpToken, lpszHostFile, lstrlen(lpszHostFile) + 1);
   lpToken += lstrlen(lpszHostFile);
   *(lpToken++) = ' ';

   GetOption(lpToken);

   HllFunc   = 90 + bSR;
   HllStrLen = lstrlen(lpHllBuffer);

   hllapi((LPINT)&HllFunc,
          (LPSTR)lpHllBuffer,
          (LPINT)&HllStrLen,
          (LPINT)&HllRetCode);

   GlobalUnlock(hHllBuffer);
   return;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: GenerateHostFile()                                               |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function generates host file name from pc file name.                  |
|                                                                              |
*-----------------------------------------------------------------------------*/
BOOL PASCAL GenerateHostFile(lpszPCFile, lpszHostFile)
LPSTR lpszPCFile ;
LPSTR lpszHostFile ;
{
   LPSTR lpToken ;
   WORD  wLength ;
   char  szPCFile[FILENAME_LENGTH] ;
   char  szBuffer[BUFFER_LENGTH] ;

   if (lpToken = _fstrrchr(lpszPCFile, '\\'))
   {
      lstrcpy((LPSTR)szPCFile, lpToken + 1) ;
   }

   if (lpToken = _fstrchr((LPSTR)szPCFile, '.'))
   {
      *lpToken = (char)NULL ;
      wLength = lstrlen((LPSTR)szPCFile) ;

      // Get host file name (with session ID)
      szBuffer[0] = ':';
      szBuffer[1] = (char)NULL;
      lstrcpy(lpszHostFile, (LPSTR)szSessID);
      lstrcat(lpszHostFile, (LPSTR)szBuffer) ;
      lstrcat(lpszHostFile, (LPSTR)szPCFile);
      szBuffer[0] = ' ';
      lstrcat(lpszHostFile, (LPSTR)szBuffer);
      *(lpToken++) = '.';

      // Get host file type
      lstrcat(lpszHostFile, lpToken);
      lstrcat(lpszHostFile, (LPSTR)" ");

      // Add file mode
      lstrcat(lpszHostFile, (LPSTR)szVMDisk);
   }
   else
   {
      // File name only. No extension
      lstrcpy(lpszHostFile, lpszPCFile);

      // Add default file type
      LoadString(ghInst, LS_TYPE, (LPSTR)szBuffer, sizeof(szBuffer));
      lstrcat(lpszHostFile, (LPSTR)szBuffer);

      // Add file mode
      lstrcat(lpszHostFile, (LPSTR)szVMDisk);
   }

   return TRUE;
}

/*-----------------------------------------------------------------------------*
|                                                                              |
|   FUNCTION: GetOptions()                                                     |
|                                                                              |
|   PURPOSE:                                                                   |
|                                                                              |
|   This function generates host file name from pc file name.                  |
|                                                                              |
*-----------------------------------------------------------------------------*/
VOID PASCAL GetOption(lpToken)
LPSTR lpToken;
{
   char     szMessage[64];

   *(lpToken++) = '(';
   *(lpToken++) = ' ';

   if (fAscii)
   {
      LoadString(ghInst, LS_ASCII, (LPSTR)szMessage, sizeof(szMessage));
      strncpy(lpToken, (LPSTR)szMessage, 6);
      lpToken += 5;
      *(lpToken++) = ' ';
      *lpToken = (char)NULL;
   }

   if (fCrlf)
   {
      LoadString(ghInst, LS_CRLF, (LPSTR)szMessage, sizeof(szMessage));
      strncpy(lpToken, (LPSTR)szMessage, 5);
      lpToken += 4;
      *(lpToken++) = ' ';
      *lpToken = (char)NULL;
   }

   if (lstrlen(szOptions))
   {
      strncpy(lpToken, (LPSTR)szOptions, lstrlen((LPSTR)szOptions) + 1);
      lpToken += (lstrlen((LPSTR)szOptions) + 1);
      *lpToken = (char)NULL;
   }
}
