/*************************************************************************** Windows Sockets FTP Client Application Written by: John A. Junod Internet: 267 Hillwood Street Martinez, GA 30907 Compuserve: 72321,366 This program executable and all source code is released into the public domain. It would be nice (but is not required) to give me a little credit for any use of this code. The user interface for this FTP client is designed with the novice FTP user in mind. Usage should (??) be obvious with the possible exception of the the transfer mode; ascii, binary or l8. All controls are standard Windows controls. My development and testing was all completed at home on two 386 PC's using the Trumpet Windows Sockets DLL Alpha 15 with NCSA Telnet and WinQVT/Net 2.6 and 3.9 as the remote host. Source code may be compiled with Borland C++ in large mode. Some code concepts and names are based on code that is copyright by the Regents of the University of California or code published in UNIX Network Programming by W. Richard Stevens or code in WATTCP or other public sources. The rest is based on my knowledge of Windows programming and my interpretation of RFC 969 and the Windows Sockets API version 1.1. THE INFORMATION AND CODE PROVIDED IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL JOHN A. JUNOD BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF JOHN A. JUNOD HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. *****************************************************************************/ // modified extensively by l kahn for windows nt and multi threading // turn off list windows for mirror operation //---------------------- #include "ws_glob.h" #include "WS_ftp.H" #include "version.h" //---------------------- #include #include #include #include #include // lgk new debugging variable BOOLEAN DEBUGGING_ON = FALSE; int selects[256]; extern char szInitDir[]; HBRUSH hbrGray1,hbrGray2,hbrWhite; extern HWND hWndDbg; BOOLEAN connectpending = FALSE; volatile BOOLEAN aborttimerexpired = FALSE; // lgk new stuff for multiple threads extern int check_command_line(); CRITICAL_SECTION busy_variable; BOOLEAN busy = FALSE; HWND globalhWnd; WPARAM globalwParam; DWORD threadid; HANDLE threadhandle; #ifndef USEASYNC SubProcessAsync(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam) { return(FALSE); } #endif // lgk new routine to get the local search string extern char *localsearchstring(); int VerifyDelete(LPSTR fname) { wsprintf(szDlgPrompt,"Are you sure you want to delete \"%s\"?",fname); return(MessageBox(hWndMain,szDlgPrompt,"Verify Deletion",MB_YESNO)==IDYES); } VOID CALLBACK myaborttimerproc(wind,msg,idevent,systime) HWND wind; UINT msg; UINT idevent; DWORD systime; { KillTimer(wind,21); aborttimerexpired = TRUE; } void turnofflistwindows() { BOOL rv; rv = ShowWindow(hLbxLDir,SW_HIDE); rv = ShowWindow(hLbxLFiles,SW_HIDE); rv = ShowWindow(hLbxRDir,SW_HIDE); rv = ShowWindow(hLbxRFiles,SW_HIDE); EnableWindow(hBtnLCWD,FALSE); EnableWindow(hBtnLMKD,FALSE); EnableWindow(hBtnLRMD,FALSE); EnableWindow(hLdirBox,FALSE); EnableWindow(hRdirBox,FALSE); EnableWindow(hBtnLDisplay,FALSE); EnableWindow(hBtnLREN,FALSE); EnableWindow(hBtnLDEL,FALSE); } void turnonlistwindows() { BOOL rv; rv = ShowWindow(hLbxLDir,SW_SHOW); rv = ShowWindow(hLbxLFiles,SW_SHOW); rv = ShowWindow(hLbxRDir,SW_SHOW); rv = ShowWindow(hLbxRFiles,SW_SHOW); EnableWindow(hBtnLCWD,TRUE); EnableWindow(hBtnLMKD,TRUE); EnableWindow(hBtnLRMD,TRUE); EnableWindow(hLdirBox,TRUE); EnableWindow(hRdirBox,TRUE); EnableWindow(hBtnLDisplay,TRUE); EnableWindow(hBtnLREN,TRUE); EnableWindow(hBtnLDEL,TRUE); } void MakeLower(LPSTR str) { while(*str) { *str=tolower(*str); str++; } } // lgk function to set busy variable so that we don't get collisions void set_busy(invalue) BOOLEAN invalue; { EnterCriticalSection(&busy_variable); busy = invalue; LeaveCriticalSection(&busy_variable); } BOOLEAN check_busy() { BOOLEAN rvalue; EnterCriticalSection(&busy_variable); rvalue = busy; LeaveCriticalSection(&busy_variable); return rvalue; } /* ------------------------------------------------------------------------------------------- */ // lgk new functions that will run in a thread DWORD local_to_remote_fx() { int nIndex,nRC; u_char tmp[300]; char localname[256]; char remotename[256]; int count; count=SendMessage(hLbxLFiles, LB_GETSELITEMS,256,(LPARAM)(int far *)selects); if(count>0 && count!=LB_ERR) { EnableWindow(hBtnAbort,TRUE); for(nIndex=0;nIndex0 && count!=LB_ERR) { EnableWindow(hBtnAbort,TRUE); for(nIndex=0;nIndex0 && count!=LB_ERR) { /* Get the current working directory: */ if (_getcwd(ldirsave, _MAX_PATH ) != NULL ) { SendMessage(hTxtRDir,WM_GETTEXT,_MAX_PATH,(LONG)rdirsave); EnableWindow(hBtnAbort,TRUE); turnofflistwindows(); for(nIndex=0;nIndex0 && count2!=LB_ERR) { count3=SendMessage(hLbxLFiles,LB_SELITEMRANGEEX, (WPARAM)0 ,(LPARAM) count2); if (count3 != LB_ERR) { // now that this worked ok call the function to get them set_busy(TRUE); local_to_remote_fx2(); set_busy(FALSE); } else { DoPrintf("Aborting since local file selection failed..."); set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); turnonlistwindows(); return 0; } } // now we got all files in this directory so select all dirs // under it and recall ourself // then cd back to orig directory so we can continue // with next dir at this level // ignore first dir which is always .. count2=SendMessage(hLbxLDir,LB_GETCOUNT,0,0); if(count2>1 && count2!=LB_ERR) { count3=SendMessage(hLbxLDir,LB_SELITEMRANGEEX, (WPARAM)1 ,(LPARAM) count2); if (count3 != LB_ERR) { // now that this worked ok call ourself to recurse local_to_remote_mirror_fx(); } } // now cd back to the original dir so we can continue chdir(ldirsave); GetLocalDirForWnd(globalhWnd); nRC=DoCWD(ctrl_socket,rdirsave); if(nRC==FTP_COMPLETE) { GetRemoteDirForWnd(globalhWnd); --totalfilestransfered; // decrement twice for both remote operations } else { DoPrintf("Aborting since remote cwd failed..."); set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); turnonlistwindows(); return 0; } } // skip drive selection } // skip bogus .. selection // continue the loop } // end of loop } // end of getcwd ok } // end of count ok // print the totals if (totalfilestransfered > 0) { char str1[30]; char str2[30]; if (totalfilestransfered == 1) strcpy(str1,"file"); else strcpy(str1,"files"); if (totaldirscreated == 1) strcpy(str2,"directory"); else strcpy(str2,"directories"); DoPrintf("%ld %s tranmitted, %ld %s created.", totalfilestransfered,str1,totaldirscreated,str2); } if (totaltimefortransfer > 0) { DoPrintf("%ld bytes tranfered in %.2f seconds, (%3.2fKbytes/sec).", totalbytestransfered,(float)totaltimefortransfer, (float)totalbytestransfered/1024.000/(float)totaltimefortransfer); } mirrorinprogress = FALSE; set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); turnonlistwindows(); return 0; } /* -------------------------------------------------------------- */ DWORD remote_mkdir_fx() { int nRC; if(StdInput(NULL,"Enter new remote directory name:")) if((nRC=DoMKD(ctrl_socket,szDlgEdit))==FTP_COMPLETE) { GetRemoteDirForWnd(globalhWnd); } set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); return 0; } /* ---------------------------------------- */ DWORD remote_rmdir_fx() { int nIndex,nRC; if((nIndex=SendMessage(hLbxRDir,LB_GETCURSEL,0,0L))!=LB_ERR) { SendMessage(hLbxRDir,LB_GETTEXT,nIndex,(LONG)szMsgBuf2); if(VerifyDelete(szMsgBuf2)) if((nRC=DoRMD(ctrl_socket,szMsgBuf2))==FTP_COMPLETE) GetRemoteDirForWnd(globalhWnd); } set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); return 0; } /* ------------------------------------------------- */ DWORD remote_list_fx() { GetRemoteDirForWnd(globalhWnd); EnableWindow(hBtnAbort,TRUE); set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); return 0; } /* ----------------------------- */ DWORD remote_delete_fx() { int nIndex,nRC; int count; count=SendMessage(hLbxRFiles,LB_GETSELITEMS, 256,(LPARAM)(int far *)selects); if(count>0 && count!=LB_ERR) { for(nIndex=0;nIndex 1) { DoPrintf("Only 1 directory can be selected for the chdir operation."); } else if (count == 0) { // ok case so ask if(StdInput(NULL,"Enter remote directory name:")) if((nRC=DoCWD((SOCKET)ctrl_socket,szDlgEdit))==FTP_COMPLETE) GetRemoteDirForWnd(globalhWnd); } else // (count == 1) { count2=SendMessage(hLbxRDir, LB_GETSELITEMS,256,(LPARAM)(int far *)selects); nIndex = selects[0]; EnableWindow(hBtnAbort,TRUE); SendMessage(hLbxRDir,LB_GETTEXT,nIndex, (LONG)szMsgBuf2); nRC=DoCWD(ctrl_socket,szMsgBuf2); if(nRC==FTP_COMPLETE) GetRemoteDirForWnd(globalhWnd); } set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); return 0; } /* ----------------------------------------------------------- */ DWORD remote_to_local_fx() { char tmp[300]; char remotename[256]; char localname[256]; char shortname[80]; int count; int nIndex,nRC; count=SendMessage(hLbxRFiles,LB_GETSELITEMS, 256,(LPARAM)(int far *)selects); if(count>0 && count!=LB_ERR) { EnableWindow(hBtnAbort,TRUE); for(nIndex=0;nIndex0 && count!=LB_ERR) { /* Get the current working directory: */ if (_getcwd(ldirsave, _MAX_PATH ) != NULL ) { SendMessage(hTxtRDir,WM_GETTEXT,_MAX_PATH,(LONG)rdirsave); EnableWindow(hBtnAbort,TRUE); turnofflistwindows(); for(nIndex=0;nIndex0 && count2!=LB_ERR) { count3=SendMessage(hLbxRFiles,LB_SELITEMRANGEEX, (WPARAM)0 ,(LPARAM) count2); if (count3 != LB_ERR) { // now that this worked ok call the function to get them set_busy(TRUE); remote_to_local_fx(); set_busy(FALSE); } else { DoPrintf("Aborting since remote file selection failed..."); set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); turnonlistwindows(); return 0; } } // now we got all files in this directory so select all dirs // under it and recall ourself // then cd back to orig directory so we can continue // with next dir at this level // ignore first dir which is always .. count2=SendMessage(hLbxRDir,LB_GETCOUNT,0,0); if(count2>1 && count2!=LB_ERR) { count3=SendMessage(hLbxRDir,LB_SELITEMRANGEEX, (WPARAM)1 ,(LPARAM) count2); if (count3 != LB_ERR) { // now that this worked ok call ourself to recurse remote_to_local_mirror_fx(); } } // now cd back to the original dir so we can continue chdir(ldirsave); GetLocalDirForWnd(globalhWnd); nRC=DoCWD(ctrl_socket,rdirsave); if(nRC==FTP_COMPLETE) { GetRemoteDirForWnd(globalhWnd); --totalfilestransfered; } else { DoPrintf("Aborting since remote cwd failed..."); set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); turnonlistwindows(); return 0; } } // skip bogus .. selection // continue the loop } // end of loop } // end of getcwd ok } // end of count ok // print the totals if (totalfilestransfered > 0) { char str1[30]; char str2[30]; if (totalfilestransfered == 1) strcpy(str1,"file"); else strcpy(str1,"files"); if (totaldirscreated == 1) strcpy(str2,"directory"); else strcpy(str2,"directories"); DoPrintf("%ld %s tranmitted, %ld %s created.", totalfilestransfered,str1,totaldirscreated,str2); } if (totaltimefortransfer > 0) { DoPrintf("%ld bytes received in %.2f seconds, (%3.2fKbytes/sec).", totalbytestransfered,(float)totaltimefortransfer, (float)totalbytestransfered/1024.000/(float)totaltimefortransfer); } mirrorinprogress = FALSE; set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); turnonlistwindows(); return 0; } /* --------------------------------------------------------- */ DWORD remote_display_fx() { int nIndex,nRC; char tmp[300]; char remotename[80]; if((nIndex=SendMessage(hLbxRFiles,LB_GETCURSEL, 0,0L))!=LB_ERR) { SendMessage(hLbxRFiles,LB_GETTEXT,nIndex, (LONG)remotename); wsprintf(tmp,"RETR %s",remotename); EnableWindow(hBtnAbort,TRUE); nRC=RetrieveFile((SOCKET)ctrl_socket,(LPSTR)tmp, (LPSTR)szTmp1File,(LPSTR)szTmp1File,TYPE_A); if(nRC==2) { wsprintf(szString,"%s %s",szViewer,szTmp1File); if(strchr(szTmp1File,'.')==NULL) strcat(szString,"."); WinExec(szString,SW_SHOW); } GetLocalDirForWnd(globalhWnd); } set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); return 0; } /* ----------------------------------------------------------- */ DWORD connect_fx() { int nRC; connectpending = TRUE; if(ctrl_socket==INVALID_SOCKET) { EnableWindow(hBtnConnect,FALSE); use_gateway=0; nRC=DialogBox(hInst,(LPSTR)"DLG_HOST",globalhWnd,WS_HostMsgProc); if(nRC) { EnableWindow(hBtnAbort,TRUE); ctrl_socket=(SOCKET)DoConnect(szRemoteHost); if(ctrl_socket!=INVALID_SOCKET) { if(szInitDir[0]!=0) DoCWD(ctrl_socket,szInitDir); } else // didn't connect so renable button EnableWindow(hBtnConnect,TRUE); if(LOWORD(globalwParam)==BTN_CONNECT) GetRemoteDirForWnd(globalhWnd); } // ok nrc } else SendMessage(hTxtStatus,WM_SETTEXT,0,(LPARAM)"Already connected"); set_busy(FALSE); connectpending = FALSE; EnableWindow(hBtnAbort,FALSE); return 0; } /* ---------------------------------------------------------- */ DWORD drop_files_fx() { int nRC; POINT pt; WORD cFiles, a; char szFile[256]; char szRemoteName[256]; u_char tmp[2300]; LPSTR lpszBaseName; DragQueryPoint((HANDLE) globalwParam, &pt); cFiles = DragQueryFile((HANDLE) globalwParam, 0xFFFF, (LPSTR) NULL, 0); if(!bConnected) DoPrintf("NOT CONNECTED!! File(s) ignored."); else if(bCmdInProgress) DoPrintf("We are already busy!! File(s) ignored."); else { for(a = 0; a < cFiles; pt.y += 20, a++) { DragQueryFile((HANDLE) globalwParam, a, szFile, sizeof(szFile)); MakeLower(szFile); if((lpszBaseName=strrchr(szFile,'\\'))!=NULL) { lstrcpy(szRemoteName,++lpszBaseName); if(bInteractive) StdInput(szRemoteName,"Enter remote file name for %s:",lpszBaseName); EnableWindow(hBtnAbort,TRUE); wsprintf(tmp,"sending %s as %s (%u of %u)",szFile,szRemoteName,a,cFiles); SendMessage(hTxtStatus,WM_SETTEXT,0,(LPARAM)tmp); wsprintf(tmp,"STOR %s",szRemoteName); nRC=SendFile(ctrl_socket,tmp,szFile,fType); if(nRC!=2) break; } } // end of loop GetRemoteDirForWnd(globalhWnd); } // end ok case DragFinish((HANDLE) globalwParam); set_busy(FALSE); EnableWindow(hBtnAbort,FALSE); return 0; } /* -------------------------------------------- */ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; int nRc; long nWndunits; int nX; int nY; int nWidth; int nHeight; int err; // HINSTANCE hWinSock; InitializeCriticalSection(&busy_variable); if (strstr(lpszCmdLine,"-d") != NULL) { // we want debugging DEBUGGING_ON = TRUE; } if ((err = WSAStartup((WORD)0x0101, &WSAData))!=0) // register task with { // winsock tcp/ip API MessageBox(NULL,ReturnWSError(err,NULL),"WS_FTP - WSAStartup", MB_OK|MB_ICONEXCLAMATION); } else { 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 MessageBox((HWND)NULL, "Window creation failed", 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 = ((247 * nWndx) / 4); nHeight = ((211 * nWndy) / 8); // create application's Main window hWndMain = CreateWindow( szAppName, "WinSock_FTP", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_OVERLAPPED, nX,nY, nWidth, nHeight, (HWND)NULL, (HMENU)NULL, hInst, NULL); if(hWndMain == (HWND)NULL) { MessageBox((HWND)NULL, "Error registering class", NULL, MB_ICONEXCLAMATION); return 2; } ShowWindow(hWndMain, nCmdShow); // display main window GetLocalInfo(); if(bAutoStart) PostMessage(hWndMain,WM_COMMAND,BTN_CONNECT,0L); // lgk now check if command line stuff if (check_command_line() == 1) { // use to exit here when not multi-threaded but now returns immediately } while(GetMessage(&msg, (HWND)NULL, 0, 0)) // Until WM_QUIT message { // lgk add extra code to check for carriage return in our dir boxes if (msg.message == WM_KEYDOWN && msg.wParam == VK_RETURN) // ok we have it now do it { if (msg.hwnd == hLdirBox) { GetLocalDirForWnd(msg.hwnd); } else if (msg.hwnd == hRdirBox) { if (check_busy()) DoPrintf("Currently Busy with another remote operation ...\n"); else { globalhWnd = msg.hwnd; globalwParam = msg.wParam; set_busy(TRUE); // create thread and start remote list fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)remote_list_fx,NULL,0,&threadid); } } } TranslateMessage(&msg); DispatchMessage(&msg); } WSACleanup(); ReleaseDisplayMem(); // Do clean up before exiting from the application CwUnRegisterClasses(); } return msg.wParam; } // End of WinMain int StdInput(LPSTR dest,LPSTR fmt,...) { va_list args; // FARPROC lpfnMsgProc; int iRetCode; va_start(args,fmt); vsprintf(szDlgPrompt,fmt,args); va_end(args); if (dest != NULL) // lgk fix for nt caused access violation lstrcpy(szDlgEdit,dest); else szDlgEdit[0] = 0; // lpfnMsgProc=MakeProcInstance((FARPROC)WS_InputMsgProc,hInst); iRetCode=DialogBox(hInst,(LPSTR)"DLG_INPUT",hWndMain,WS_InputMsgProc); // FreeProcInstance(lpfnMsgProc); if(iRetCode && dest) // lgk fix here since if dest was null we cannot copy to it if (dest != NULL) lstrcpy(dest,szDlgEdit); return(iRetCode); } int StdInputPassword(LPSTR dest,LPSTR fmt,...) { va_list args; //FARPROC lpfnMsgProc; int iRetCode; va_start(args,fmt); vsprintf(szDlgPrompt,fmt,args); va_end(args); lstrcpy(szDlgEdit,dest); // lpfnMsgProc=MakeProcInstance((FARPROC)WS_InputMsgProc,hInst); iRetCode=DialogBox(hInst,(LPSTR)"DLG_INPUT_PASSWORD",hWndMain,WS_InputMsgProc); // FreeProcInstance(lpfnMsgProc); if(iRetCode && dest) lstrcpy(dest,szDlgEdit); return(iRetCode); } /************************************************************************/ /* Main Window Procedure */ /************************************************************************/ LRESULT CALLBACK WndProc(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam) { int nIndex; //,nRC; char tempdirectoryname[256]; switch (Message) { case WM_COMMAND: if(LOWORD(wParam)==BTN_CLOSE || LOWORD(wParam)==BTN_EXIT || LOWORD(wParam)==CMD_CLOSE || LOWORD(wParam)==IDM_EXIT) { BOOLEAN rfile = FALSE; BOOLEAN sfile = FALSE; bAborted=TRUE; // kill remote thread first if (check_busy()) { DoAddLine("Aborting thread before closing/exiting\n"); TerminateThread(threadhandle,1); mirrorinprogress = FALSE; turnonlistwindows(); set_busy(FALSE); bCmdInProgress = 0; } if(data_socket!=INVALID_SOCKET) { // DWORD waitval = 0; int tid = 0; data_socket=DoClose(data_socket); // now wait for the abort message DoPrintf("Waiting for Abort Response message. (550)\n"); // create thread and start remote list fx // threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)waitfor550,NULL,0,&threadid); aborttimerexpired = FALSE; SetTimer(hWnd,21,15000,(TIMERPROC)myaborttimerproc); waitfor550((SOCKET)ctrl_socket); KillTimer(hWnd,21); // waitval = WaitForSingleObject(threadhandle,15000); // wait 15 seconds if this fails terminate the thread /* if (waitval == WAIT_TIMEOUT) { DoPrintf("Abort Timeout has Expired\n"); DoPrintf("Abort Failed... Recommend you close/reconnect\n"); TerminateThread(threadhandle,1); mirrorinprogress = FALSE; turnonlistwindows(); set_busy(FALSE); bCmdInProgress = 0; } */ // now check if files were open and close them closefilesonabort(&rfile,&sfile); } bAborted=TRUE; bCmdInProgress = 0; if(listen_socket!=INVALID_SOCKET) listen_socket=DoClose(listen_socket); if(ctrl_socket!=INVALID_SOCKET) { command(ctrl_socket,"QUIT"); ctrl_socket=DoClose(ctrl_socket); bConnected=FALSE; } bCmdInProgress = 0; SetWindowText(hWnd,"WS_FTP32"); if(LOWORD(wParam)==IDM_EXIT || LOWORD(wParam)==BTN_EXIT) SendMessage(hWnd,WM_CLOSE,0,0L); else { // close not exit so enable windows correctly EnableWindow(hBtnConnect,TRUE); EnableWindow(hBtnAbort,FALSE); EnableWindow(hBtnClose,FALSE); GetRemoteDirForWnd(hWnd); } // if we are closing we still need to close files that were open or if we // were receiving we need to update display // we don't care about remote since this is updated anyway if (rfile) GetLocalDirForWnd(hWnd); break; } //else if ((bCmdInProgress) return(FALSE); switch (LOWORD(wParam)) { // child windows messages ************************************ // local buttons and boxes // lgk new case for abort case BTN_ABORT: // kill remote thread first // problem here if we abort during a connect we also need to close the control socket // check this via the connect flag // since we cant get this to work correctly disable it for now // DoPrintf("Abort is Not Yet Implemented Due to problems.\n"); if (check_busy()) { BOOLEAN rfile = FALSE; BOOLEAN sfile = FALSE; DoPrintf("Aborting Remote thread\n"); DoPrintf("WARNING: If the abort fails you may have to close/exit"); TerminateThread(threadhandle,1); mirrorinprogress = FALSE; turnonlistwindows(); set_busy(FALSE); if(data_socket!=INVALID_SOCKET) { //DWORD waitval = 0; int tid = 0; // shutdown(data_socket,2); data_socket=DoClose((SOCKET)data_socket); // now wait for the abort message DoPrintf("Waiting for Abort Response message. (550)\n"); // create thread and start remote list fx // threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)waitfor550,(LPVOID)ctrl_socket,0,&threadid); // myctrlsocket = (SOCKET)ctrl_socket; aborttimerexpired = FALSE; SetTimer(hWnd,21,15000,(TIMERPROC)myaborttimerproc); waitfor550((SOCKET)ctrl_socket); KillTimer(hWnd,21); // waitval = WaitForSingleObject(threadhandle,20000); // wait 20 seconds if this fails terminate the thread // ok now close any open files closefilesonabort(&rfile,&sfile); } bAborted=TRUE; bCmdInProgress = 0; if(listen_socket!=INVALID_SOCKET) listen_socket=DoClose((SOCKET)listen_socket); bCmdInProgress = 0; if (connectpending) { int err = 0; if (ctrl_socket!=INVALID_SOCKET) { command((SOCKET)ctrl_socket,"QUIT"); ctrl_socket = DoClose((SOCKET)ctrl_socket); } bConnected = FALSE; DoPrintf("Remote Connect Aborted\n"); connectpending = FALSE; bCmdInProgress = 0; EnableWindow(hBtnConnect,TRUE); EnableWindow(hBtnAbort,FALSE); EnableWindow(hBtnClose,FALSE); SetWindowText(hWnd,"WS_FTP32"); iCode = 0; } else { DoPrintf("Remote Operation Aborted\n"); // only do this if no connect pending if (sfile) GetRemoteDirForWnd(hWnd); } // now if we were sending or receiving a file update the windows accordingly if (rfile) GetLocalDirForWnd(hWnd); } break; // lgk new case for changing txt in directory search routine case TXT_LDIRSEL: { // check if carriage return char *temp = localsearchstring(); if ((HIWORD(wParam) == EN_KILLFOCUS) && SendMessage(hLdirBox,EM_GETMODIFY,0,0)) { GetLocalDirForWnd(hWnd); } // bug in redraw so force it if (HIWORD(wParam) == EN_UPDATE) { SendMessage(hLdirBox,WM_SETFONT,0,MAKELPARAM(TRUE,0)); } } break; case LST_LDIRS: if (HIWORD(wParam) !=LBN_DBLCLK) return(FALSE); case BTN_LCHANGE: { int count = SendMessage(hLbxLDir,LB_GETSELCOUNT, 0,0L); int count2 = 0; if (count > 1) { DoPrintf("Only 1 directory can be selected for the chdir operation."); } else if (count == 0) { // ok case so ask if(StdInput(NULL,"Enter local directory name:")) { if(szDlgEdit[1]==':') #ifdef _MSC_ _chdrive(tolower(szDlgEdit[0])-0x60); #else setdisk(tolower(szDlgEdit[0])-'a'); #endif chdir(szDlgEdit); GetLocalDirForWnd(hWnd); } } else // (count == 1) { count2=SendMessage(hLbxLDir, LB_GETSELITEMS,256,(LPARAM)(int far *)selects); nIndex = selects[0]; SendMessage(hLbxLDir,LB_GETTEXT,nIndex, (LONG)szMsgBuf2); if(strncmp(szMsgBuf2,"[-",2)==0) { #ifdef _MSC_ _chdrive(tolower(szMsgBuf2[2])-0x60); #else setdisk(szMsgBuf2[2]-'a'); #endif GetLocalDirForWnd(hWnd); } else if(chdir(szMsgBuf2)==0) GetLocalDirForWnd(hWnd); } } break; case LST_LFILES: if(HIWORD(wParam) !=LBN_DBLCLK) return(FALSE); case BTN_LOCAL_TO_REMOTE: { globalhWnd = hWnd; globalwParam = wParam; // lgk new code first check if busy and if so print out a message if (check_busy()) DoPrintf("Currently Busy with another remote operation ...\n"); else { globalhWnd = hWnd; globalwParam = wParam; set_busy(TRUE); { int dircount,filecount = 0; filecount = SendMessage(hLbxLFiles,LB_GETSELCOUNT,0,0); dircount = SendMessage(hLbxLDir,LB_GETSELCOUNT,0,0); if ((dircount > 0) && (filecount == 0)) { mirrorinprogress = TRUE; totalbytestransfered = 0L; totaltimefortransfer = 0L; totalfilestransfered = 0; totaldirscreated = 0; // create thread and start remote to local fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)local_to_remote_mirror_fx,NULL,0,&threadid); } else { // create and call button to remote thread here threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)local_to_remote_fx,NULL,0,&threadid); } } } // end of not busy } // end of btn local to remote break; // lgk allow local commands while remote are running case BTN_LMKDIR: if(StdInput(NULL,"Enter new local directory name:")) { mkdir(szDlgEdit); GetLocalDirForWnd(hWnd); } break; case BTN_LRMDIR: if((nIndex=SendMessage(hLbxLDir,LB_GETCURSEL, 0,0L))!=LB_ERR) { SendMessage(hLbxLDir,LB_GETTEXT,nIndex, (LONG)szMsgBuf2); if(VerifyDelete(szMsgBuf2)) if(rmdir(szMsgBuf2)==0) GetLocalDirForWnd(hWnd); } break; case BTN_LDELETE: { int count; count=SendMessage(hLbxLFiles, LB_GETSELITEMS,256,(LPARAM)(int far *)selects); if(count>0 && count!=LB_ERR) { for(nIndex=0;nIndex 0) && (filecount == 0)) { mirrorinprogress = TRUE; totalbytestransfered = 0L; totaltimefortransfer = 0L; totalfilestransfered = 0; totaldirscreated = 0; // create thread and start remote to local fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)remote_to_local_mirror_fx,NULL,0,&threadid); } else { // create thread and start remote to local fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)remote_to_local_fx,NULL,0,&threadid); } } } break; case BTN_RDISPLAY: // lgk new code first check if busy and if so print out a message if (check_busy()) DoPrintf("Currently Busy with another remote operation ...\n"); else { globalhWnd = hWnd; globalwParam = wParam; set_busy(TRUE); // create thread and start remote display fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)remote_display_fx,NULL,0,&threadid); } break; case RB_ASCII: fType=TYPE_A; ShowType: case RB_SHOWCHECKS: SendMessage(hRBascii, BM_SETCHECK,fType==TYPE_A,0L); SendMessage(hRBbinary,BM_SETCHECK,fType==TYPE_I,0L); SendMessage(hRBl8, BM_SETCHECK,fType==TYPE_L,0L); break; case RB_BINARY: fType=TYPE_I; goto ShowType; case RB_L8: fType=TYPE_L; goto ShowType; // end of child window message processing ******************* case BTN_CONNECT: case CMD_CONNECT: // lgk new code first check if busy and if so print out a message if (check_busy()) DoPrintf("Currently Busy with another remote operation ...\n"); else { globalhWnd = hWnd; globalwParam = wParam; set_busy(TRUE); // create thread and start connect fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)connect_fx,NULL,0,&threadid); } break; case BTN_LONG: if(bConnected) { wsprintf(szMsgBuf2,"%s %s",szViewer,szTmpFile); WinExec(szMsgBuf2,SW_SHOW); } break; case BTN_OPTION: { //FARPROC lpfnMsgProc; // lpfnMsgProc = MakeProcInstance((FARPROC)WS_StatMsgProc, hInst); DialogBox(hInst, (LPSTR)"DLG_STATUS", hWnd, WS_StatMsgProc); // FreeProcInstance(lpfnMsgProc); } SendMessage(hWnd,WM_COMMAND,RB_SHOWCHECKS,0l); break; case BTN_ABOUT: case IDM_ABOUT: { DialogBox(hInst, (LPSTR)"DLG_ABOUT", hWnd, WS_AboutMsgProc); } break; default: if(!SubProcessAsync(hWnd,Message,wParam,lParam)) return DefWindowProc(hWnd, Message, wParam, lParam); } break; case WM_VSCROLL: switch(LOWORD(wParam)) { case SB_LINEUP: ScrollStatus(-1); break; case SB_LINEDOWN: ScrollStatus(1); break; } break; case WM_CREATE: hStdCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW); hWaitCursor=LoadCursor((HINSTANCE)NULL,IDC_APPSTARTING); LoadUserInfo(); hbrGray1= CreateSolidBrush(RGB(192,192,192)); hbrGray2=CreateSolidBrush(RGB(128,128,128)); hbrWhite=CreateSolidBrush(RGB(255,255,255)); if (DEBUGGING_ON) CreateDebugWindow(hWnd,hInst); CreateSubWindows(hWnd,hInst); SendMessage(hLdirBox,EM_LIMITTEXT,(WPARAM)50,0); SendMessage(hRdirBox,EM_LIMITTEXT,(WPARAM)50,0); SendMessage(hLdirBox,WM_SETTEXT,0,(LPARAM)""); SendMessage(hRdirBox,WM_SETTEXT,0,(LPARAM)""); SendMessage(hLdirBox,EM_GETMODIFY,0,0); SendMessage(hRdirBox,EM_GETMODIFY,0,0); SendMessage(hLdirBox,EM_FMTLINES,(WPARAM)1,0); SendMessage(hRdirBox,EM_FMTLINES,(WPARAM)1,0); GetLocalDirForWnd(hWnd); GetRemoteDirForWnd(hWnd); SendMessage(hWnd,WM_COMMAND,RB_SHOWCHECKS,0L); GetCurrentDirectory(140,tempdirectoryname); GetTempFileName(tempdirectoryname,"DIR",0,szTmpFile); GetTempFileName(tempdirectoryname,"DSP",0,szTmp1File); DragAcceptFiles(hWnd,TRUE); // lgk limit the text for both dir boxes and initialize them to blank break; // lgk timer messages do not work between threads so use a timer proc now case WM_TIMER: if(wParam==10) { KillTimer(hWndMain,10); if(WSAIsBlocking()) { // lgk if we are blocking in another thread here we need to kill // it also if (check_busy()) { DoAddLine("Timer cancelled blocking call"); bAborted=TRUE; WSACancelBlockingCall(); TerminateThread(threadhandle,1); mirrorinprogress = FALSE; turnonlistwindows(); set_busy(FALSE); } else { DoAddLine("Timer cancelled blocking call"); bAborted=TRUE; WSACancelBlockingCall(); } } } break; case WM_CTLCOLORBTN: if(LOWORD(lParam)<10) return((LRESULT)NULL); // lgk add suport for background color change for our edit box case WM_CTLCOLORSTATIC: SelectObject((HDC)wParam, GetStockObject(ANSI_VAR_FONT)); SetBkColor((HDC) wParam, RGB(192,192,192)); return(LRESULT)hbrGray1; break; case WM_CTLCOLOREDIT: SelectObject((HDC)wParam, GetStockObject(ANSI_VAR_FONT)); SetBkColor((HDC) wParam, RGB(255, 255, 255)); return(LRESULT)hbrWhite; break; case WM_SETCURSOR: if(bCmdInProgress) { SetCursor(hWaitCursor); return(TRUE); } else return DefWindowProc(hWnd, Message, wParam, lParam); case WM_DROPFILES: // lgk new code first check if busy and if so print out a message if (check_busy()) DoPrintf("Currently Busy with another remote operation ...\n"); else { globalhWnd = hWnd; globalwParam = wParam; set_busy(TRUE); // create thread and start dropfiles fx threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)drop_files_fx,NULL,0,&threadid); } break; case WM_PAINT: // code for the window's client area DoMainPaint(hWnd); break; case WM_CLOSE: // close the window // Destroy child windows, modeless dialogs, then, this window if (hWnd == hWndMain) { if(data_socket!=INVALID_SOCKET) data_socket=DoClose(data_socket); if(listen_socket!=INVALID_SOCKET) listen_socket=DoClose(data_socket); if(ctrl_socket!=INVALID_SOCKET) ctrl_socket=DoClose(ctrl_socket); DestroyWindow(hWnd); SaveUserInfo(); DeleteObject(hbrGray1); DeleteObject(hbrGray2); DeleteObject(hbrWhite); _unlink(szTmpFile); _unlink(szTmp1File); DragAcceptFiles(hWnd,FALSE); // lgk if we are busy here we must kill any active task if (check_busy()) { DoPrintf("Killing active thread ... \n"); TerminateThread(threadhandle,1); mirrorinprogress = FALSE; turnonlistwindows(); set_busy(FALSE); } PostQuitMessage(0); // Quit the application } else DestroyWindow(hWnd); DeleteCriticalSection(&busy_variable); break; default: if(!SubProcessAsync(hWnd,Message,wParam,lParam)) return DefWindowProc(hWnd, Message, wParam, lParam); } return 0L; } // End of WndProc /************************************************************************/ /* Misc Dialog Window Procedures */ /************************************************************************/ BOOL CALLBACK WS_AboutMsgProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam) { char buf[40]; switch(Message) { case WM_INITDIALOG: { { struct hostent FAR *hostptr; struct in_addr *iptr; cwCenter(hWndDlg, 0); if(gethostname((LPSTR)buf, MAXHOSTNAMELEN)!=SOCKET_ERROR) { if((hostptr=gethostbyname(buf))!=NULL) { iptr=(struct in_addr *)*(hostptr->h_addr_list); wsprintf(szString,"%s [%s]",buf,inet_ntoa(*iptr)); } else lstrcpy(szString,buf); SetDlgItemText(hWndDlg,DLG_ABT_L2,szString); } } SetDlgItemText(hWndDlg,DLG_ABT_L1, (LPSTR)WSAData.szDescription); wsprintf(buf,"Version %s",VERSION); SetDlgItemText(hWndDlg,DLG_VERSION,buf); break; } case WM_CTLCOLORBTN: if(LOWORD(lParam)<10) return((BOOL)NULL); case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: SetBkColor((HDC) wParam, RGB(192,192,192)); return (BOOL)hbrGray1; break; case WM_CLOSE: PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: EndDialog(hWndDlg, TRUE); break; case IDCANCEL: EndDialog(hWndDlg, FALSE); break; } break; default: return FALSE; } return TRUE; } BOOL CALLBACK WS_InputMsgProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_GETDLGCODE: return DLGC_WANTALLKEYS; break; case WM_KEYDOWN: DoPrintf("a key is down"); break; case WM_CHAR: DoPrintf("wmchar a key is down"); break; case WM_INITDIALOG: SetDlgItemText(hWndDlg,DLG_PROMPT,szDlgPrompt); SetDlgItemText(hWndDlg,DLG_EDIT,szDlgEdit); cwCenter(hWndDlg, 0); break; case WM_CTLCOLORBTN: if(LOWORD(lParam)<10) return((LRESULT)NULL); case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: SetBkColor((HDC) wParam, RGB(192,192,192)); return(LRESULT)hbrGray1; break; case WM_CLOSE: PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: GetDlgItemText(hWndDlg,DLG_EDIT,szDlgEdit,70); EndDialog(hWndDlg, TRUE); break; case IDCANCEL: EndDialog(hWndDlg, FALSE); break; } break; default: return FALSE; } return TRUE; } BOOL CALLBACK WS_StatMsgProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_INITDIALOG: SetDlgItemText(hWndDlg,DLG_EDIT,szViewer); SetDlgItemText(hWndDlg,DLG_MAILADDR,szMailAddress); if(fType==TYPE_A) CheckRadioButton(hWndDlg,RB_ASCII,RB_L8,RB_ASCII); else if(fType==TYPE_I) CheckRadioButton(hWndDlg,RB_ASCII,RB_L8,RB_BINARY); else CheckRadioButton(hWndDlg,RB_ASCII,RB_L8,RB_L8); CheckDlgButton(hWndDlg,CKB_VERBOSE,bVerbose); CheckDlgButton(hWndDlg,CKB_BELL,bBell); CheckDlgButton(hWndDlg,CKB_GLOBBING,bDoGlob); CheckDlgButton(hWndDlg,CKB_HASH,bHash); CheckDlgButton(hWndDlg,CKB_PROMPT,bInteractive); CheckDlgButton(hWndDlg,CKB_MCASE,bMCase); CheckDlgButton(hWndDlg,CKB_PORT_CMDS,bSendPort); CheckDlgButton(hWndDlg,CKB_RECV_UNIQUE,bRecvUniq); CheckDlgButton(hWndDlg,CKB_STOR_UNIQUE,bStorUniq); CheckDlgButton(hWndDlg,CKB_CRSTRIP,bCRstrip); CheckDlgButton(hWndDlg,CKB_AUTOSTART,bAutoStart); break; case WM_CLOSE: PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L); break; case WM_SETCURSOR: if(bCmdInProgress) SetCursor(hWaitCursor); else return FALSE; break; case WM_CTLCOLORBTN: if(LOWORD(lParam)<10) return((LRESULT)NULL); case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: SetBkColor((HDC) wParam, RGB(192,192,192)); return(LRESULT)hbrGray1; break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: if(IsDlgButtonChecked(hWndDlg,RB_ASCII)) fType=TYPE_A; else if(IsDlgButtonChecked(hWndDlg,RB_BINARY)) fType=TYPE_I; else fType=TYPE_L; bVerbose=IsDlgButtonChecked(hWndDlg,CKB_VERBOSE); bBell=IsDlgButtonChecked(hWndDlg,CKB_BELL); bDoGlob=IsDlgButtonChecked(hWndDlg,CKB_GLOBBING); bHash=IsDlgButtonChecked(hWndDlg,CKB_HASH); bInteractive=IsDlgButtonChecked(hWndDlg,CKB_PROMPT); bMCase=IsDlgButtonChecked(hWndDlg,CKB_MCASE); bSendPort=IsDlgButtonChecked(hWndDlg,CKB_PORT_CMDS); bRecvUniq=IsDlgButtonChecked(hWndDlg,CKB_RECV_UNIQUE); bStorUniq=IsDlgButtonChecked(hWndDlg,CKB_STOR_UNIQUE); bCRstrip=IsDlgButtonChecked(hWndDlg,CKB_CRSTRIP); bAutoStart=IsDlgButtonChecked(hWndDlg,CKB_AUTOSTART); GetDlgItemText(hWndDlg,DLG_EDIT,szViewer,70); GetDlgItemText(hWndDlg,DLG_MAILADDR,szMailAddress,127); EndDialog(hWndDlg, TRUE); break; case IDCANCEL: EndDialog(hWndDlg, FALSE); break; } break; // End of WM_COMMAND 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, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); // Create brush for erasing background wndclass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(192,192,192)); wndclass.lpszMenuName = NULL; // 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); // calculate the height and width for MoveWindow iwidth = swp.right - swp.left; iheight = swp.bottom - swp.top; if(IsIconic(hWndMain)) MoveWindow(hWnd, 0, 0, iwidth, iheight, FALSE); else { GetClientRect(hWndMain, &rParent); // 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,max(0,pt.x),max(0,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); UnregisterClass(DBUGWNDCLASS,hInst); } // End of CwUnRegisterClasses