home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / WIN_UTL2 / VULCAN.ZIP / VULSRC.ZIP / VULCAN.CPP < prev    next >
C/C++ Source or Header  |  1994-02-08  |  38KB  |  964 lines

  1. // VULCAN.CPP Part of VULCAN
  2. // Copyright (c) 1993 John Deurbrouck
  3.  
  4. // #define COMPRESSION to enable compression check box, misc. support
  5.  
  6. // comment out line following ==++== to enable WarnOnDoesntFit check box
  7. // this feature is disabled by default
  8.  
  9. #include<windows.h>
  10. #include<stdio.h>
  11. #include<commdlg.h>
  12. #include<shellapi.h>
  13. #include<ctype.h>
  14. #include<dos.h>
  15. #include<fcntl.h>
  16. #include<share.h>
  17. #include<sys\stat.h>
  18. #include<sys\types.h>
  19. #include"resource.h"
  20. #include"vulcan.hpp"
  21. #include"browse.hpp"
  22. #include"cancel.hpp"
  23. #include"vcn.hpp"
  24.  
  25. #define IDM_ABOUT (0x1010)
  26. #define IDM_HELP (0x1020)
  27. #define IDM_ONTOP (0x1030)
  28. #define IDM_BROWSE (0x1040)
  29. #define IDM_CONFIGURE (0x1050)
  30. #define IDM_VULCANIZE (0x1060)
  31. #define DC_FIRST '/'
  32. #define DC_MIDDLE '|'
  33. #define DC_LAST '\\'
  34. #define DC_LONER '<'
  35.  
  36. // globals
  37. ////////////////////// configuration details
  38. int IsDeleting=0,IsOnTop=0,MaxMegs=10,LeaveMegs=10,UseLeaveMegsNumber=0;
  39. int WarnOnOverwrite=1,WarnOnDeleteSome=1,WarnOnDoesntFit=1;
  40. int UseClassicIcons=0;
  41. #ifdef COMPRESSION
  42. int CompressFiles=1;
  43. #else
  44. int CompressFiles=0;
  45. #endif
  46. char szUserCaption[128]="";
  47. int configuration_info_successfully_read=0;
  48. ////////////////////// following used to avoid rewriting .INI
  49. int o_IsDeleting=-1,o_IsOnTop=-1;
  50. int o_MaxMegs=-1,o_LeaveMegs=-1,o_UseLeaveMegsNumber=-1;
  51. int o_WarnOnOverwrite=-1,o_WarnOnDeleteSome=-1,o_WarnOnDoesntFit=-1;
  52. #ifdef COMPRESSION
  53. int o_CompressFiles=-1;
  54. #else
  55. int o_CompressFiles=0;
  56. #endif
  57. char o_szUserCaption[sizeof(szUserCaption)]="";
  58. ////////////////////// main window/task data
  59. char szCaption[128]="Vulcan";
  60. HINSTANCE hMainInstance=NULL;
  61. HWND hMainWindow=NULL;
  62. HMENU gm=NULL;
  63. ////////////////////// general globals
  64. HICON hIconVault=NULL,hIconTrash=NULL,hIconVulcan=NULL,hIconCurrent=NULL;
  65. ////////////////////// tons o' strings
  66. char szIniFile[135];
  67. char szTargetDirectory[135];
  68. char *pszTargetDirFile;
  69. char szAppName[]="Vulcan";
  70. char szAppWarningTitle[]="Vulcan Warning";
  71. char szAppErrorTitle[]="Vulcan Error";
  72. char szVulcanVcn[]="VULCAN.VCN";
  73. char szTempFileName[]="~TEMP.VCN";
  74. char szClassName[]="VulcanClassDeurbrouck";
  75. char pacBigScratchBuffer[BSB_SIZE]="";
  76. char pacBigScratchBuffer2[BSB_SIZE]="";
  77. static char copyright[]=
  78.     "VULCAN.EXE  1.0\n"
  79.     "File storage and archiving utility. It's a vault and a trashcan!\n"
  80.     "Copyright ⌐ 1993 John Deurbrouck\n\n"
  81.     "First published in PC Magazine February 8, 1994 (Vol 13 Nbr 3)\n";
  82. static char helpstring_main[]=
  83.     "Use Add File... to put files into Vulcan, or drag and drop from Program Manager. "
  84.     "Use Browse... to examine your archive and restore files. "
  85.     "Configure... allows you to alter Vulcan's settings. "
  86.     "\n"
  87.     "Doubleclick Vulcan's caption to change between Vault and Trashcan modes. "
  88.     ;
  89. static char helpstring[]=
  90.     "Set archive size limits and deletion preference with this dialog "
  91.     "box. Cancel leaves previous settings (if any) unaltered."
  92.     "\n"
  93.     "Trashcan mode copies files then deletes the originals; Vault mode "
  94.     "only copies."
  95.     ;
  96. static char drag_drop_error[]=
  97.     "Error processing drag and drop. Files may not have been placed into "
  98.     "Vulcan archive. None of the original unstored files have been damaged "
  99.     "or deleted by Vulcan.";
  100.  
  101. // prototypes
  102. LRESULT CALLBACK MainWindowProc(HWND,UINT,WPARAM,LPARAM);
  103. BOOL CALLBACK ConfigureDialogProc(HWND,UINT,WPARAM,LPARAM);
  104. void set_redraw_main_cursor(int show_main_cursor);
  105. void adjust_to_configuration(void);
  106. void read_configuration_information(void);
  107. void write_configuration_information(void);
  108. int set_szIniFile(void);
  109. int set_szTargetDirectory(LPSTR cmdline);
  110. int verify_target_not_in_use(HWND *activate);
  111. int ProcessFile(LPSTR complete,LPSTR eight_three,int disp_char);
  112. static int store_filedata(unsigned i,unsigned o,long bytes);
  113.  
  114. // not using last int (nCmdShow)
  115. int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
  116. LPSTR lpszCmdLine,int){
  117.     { // try to get a larger message queue
  118.         int mqs;
  119.         for(mqs=8*6;mqs;mqs-=8){
  120.             if(SetMessageQueue(mqs))break;
  121.         }
  122.         if(!mqs){
  123.             char temp[128];
  124.             wsprintf(temp,"Internal error %d",__LINE__);
  125.             MessageBox(CURR_WINDOW,temp,szAppErrorTitle,MB_OK);
  126.             return 0;
  127.         }
  128.     }
  129.     hMainInstance=hInstance;
  130.     if(!set_szIniFile()){
  131.         char temp[128];
  132.         wsprintf(temp,"Internal error %d",__LINE__);
  133.         MessageBox(CURR_WINDOW,temp,szAppErrorTitle,MB_OK);
  134.         return 0;
  135.     }
  136.     for(;;){
  137.         if(!set_szTargetDirectory(lpszCmdLine))return 0;
  138.         { // coerce szTargetDirectory to all caps
  139.             char *p=szTargetDirectory;
  140.             while(*p){
  141.                 *p=toupper(*p);
  142.                 p++;
  143.             }
  144.         }
  145.         {
  146.                HWND old_one=NULL;
  147.             if(!verify_target_not_in_use(&old_one)){
  148.                 MessageBox(CURR_WINDOW,
  149.                     "This VULCAN archive already in use -- "
  150.                     "please choose another",
  151.                     szAppErrorTitle,MB_OK);
  152.                 //if(old_one!=NULL)SetActiveWindow(old_one);
  153.                 lpszCmdLine="";
  154.             }
  155.             else break;
  156.         }
  157.     }
  158.     read_configuration_information();
  159.     if(UseClassicIcons){
  160.         hIconVault=LoadIcon(hMainInstance,MAKEINTRESOURCE(IDI_VAULT_OLD));
  161.         hIconTrash=LoadIcon(hMainInstance,MAKEINTRESOURCE(IDI_TRASH_OLD));
  162.         hIconVulcan=LoadIcon(hMainInstance,MAKEINTRESOURCE(IDI_VULCAN_OLD));
  163.     }
  164.     else{
  165.         hIconVault=LoadIcon(hMainInstance,MAKEINTRESOURCE(IDI_VAULT));
  166.         hIconTrash=LoadIcon(hMainInstance,MAKEINTRESOURCE(IDI_TRASH));
  167.         hIconVulcan=LoadIcon(hMainInstance,MAKEINTRESOURCE(IDI_VULCAN));
  168.     }
  169.     if(hIconVault==NULL||hIconTrash==NULL||hIconVulcan==NULL){
  170.         MessageBox(CURR_WINDOW,"VULCAN.EXE corrupted\nExiting",
  171.             szAppErrorTitle,MB_ICONSTOP|MB_OK);
  172.         return 0;
  173.     }
  174.     hIconCurrent=IsDeleting?hIconTrash:hIconVault;
  175.     if(hPrevInstance==NULL){
  176.         WNDCLASS wc;
  177.         wc.style=CS_DBLCLKS;
  178.         wc.lpfnWndProc=(WNDPROC)MainWindowProc;
  179.         wc.cbClsExtra=wc.cbWndExtra=0;
  180.         wc.hInstance=hMainInstance;
  181.         wc.hIcon=NULL;
  182.         wc.hCursor=LoadCursor(NULL,IDC_ARROW);
  183.         wc.hbrBackground=NULL;
  184.         wc.lpszMenuName=NULL;
  185.         wc.lpszClassName=szClassName;
  186.         if(!RegisterClass(&wc)){
  187.             MessageBox(NULL,"Can't register\nExiting",
  188.                 szAppErrorTitle,MB_ICONSTOP|MB_OK);
  189.             return 0;
  190.         }
  191.     }
  192.     hMainWindow=CreateWindowEx(0/*WS_EX_ACCEPTFILES*/,szClassName,szAppName,
  193.         WS_OVERLAPPED|/*WS_VISIBLE|*/WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,CW_USEDEFAULT,
  194.         /*SW_MINIMIZE*/CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hMainInstance,NULL);
  195.     if(hMainWindow==NULL){
  196.         MessageBox(NULL,"Can't create window\nExiting",
  197.             szAppErrorTitle,MB_ICONSTOP|MB_OK);
  198.         return 0;
  199.     }
  200.     ShowWindow(hMainWindow,SW_MINIMIZE);
  201.     if(!vcnSetup())PostMessage(hMainWindow,WM_SYSCOMMAND,SC_CLOSE,0L); // set up queue, exit if error
  202.     UINT old_errormode=SetErrorMode(SEM_FAILCRITICALERRORS); // Critical error
  203.     MSG msg;
  204.     while(GetMessage(&msg,NULL,0,0)){
  205.         TranslateMessage(&msg);
  206.         DispatchMessage(&msg);
  207.     }
  208.     SetErrorMode(old_errormode);
  209.     vcnDestroy();
  210.     return msg.wParam;
  211. }
  212. LRESULT CALLBACK MainWindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,
  213. LPARAM lParam){
  214.     static int doubleclick_status=0,doubleclick_time_delta=550;
  215.     static DWORD doubleclick_time;
  216.     switch(uMsg){
  217.     case WM_NCLBUTTONDOWN:
  218.         doubleclick_status=1;
  219.         doubleclick_time=GetTickCount();
  220.         break;
  221.     case WM_INITMENUPOPUP:
  222.         if(doubleclick_status){
  223.             if((doubleclick_status==1)&&
  224.             (wParam==gm)&&
  225.             HIWORD(lParam))
  226.                 doubleclick_status=2;
  227.             else doubleclick_status=0;
  228.         }
  229.         break;
  230.     case WM_MENUSELECT:
  231.         if((doubleclick_status)&&(wParam==0)&&(lParam==0xFFFFL)){
  232.             doubleclick_status=(doubleclick_status==2)?3:0;
  233.         }
  234.         break;
  235.     case WM_NCLBUTTONUP:
  236.         if(doubleclick_status){
  237.             if((doubleclick_status==3)&&
  238.             (GetTickCount()<=(doubleclick_time+(DWORD)doubleclick_time_delta)))
  239.                 PostMessage(hMainWindow,WM_SYSCOMMAND,(WPARAM)IDM_BROWSE,0L);
  240.             doubleclick_status=0;
  241.         }
  242.         break;
  243.     case WM_NCLBUTTONDBLCLK: // quick toggle of delete mode
  244.         doubleclick_status=0;
  245.         ++IsDeleting%=2;
  246.         adjust_to_configuration();
  247.         break;
  248.     case WM_QUERYOPEN:
  249.         return 0;
  250.     case WM_CREATE: PostMessage(hWnd,WM_COMMAND,IDM_GETSTARTED,0L); return 0;
  251.     case WM_WININICHANGE:
  252.            doubleclick_time_delta=GetProfileInt("windows","DoubleClickSpeed",doubleclick_time_delta);
  253.         return 0;
  254.     case WM_COMMAND:
  255.         switch(wParam){
  256.         case IDM_GETSTARTED:
  257.             doubleclick_time_delta=GetProfileInt("windows","DoubleClickSpeed",doubleclick_time_delta);
  258.             gm=GetSystemMenu(hWnd,FALSE);
  259.             DeleteMenu(gm,SC_MINIMIZE,MF_BYCOMMAND);
  260.             DeleteMenu(gm,SC_RESTORE,MF_BYCOMMAND);
  261.             DeleteMenu(gm,SC_SIZE,MF_BYCOMMAND);
  262.             DeleteMenu(gm,SC_MAXIMIZE,MF_BYCOMMAND);
  263.             AppendMenu(gm,MF_SEPARATOR,0,NULL);
  264.             if(UseClassicIcons)AppendMenu(gm,MF_STRING,IDM_VULCANIZE,"&Vulcanize...");
  265.             else AppendMenu(gm,MF_STRING,IDM_VULCANIZE,"Add &File...");
  266.             AppendMenu(gm,MF_STRING,IDM_BROWSE,"&Browse...");
  267.             AppendMenu(gm,MF_STRING,IDM_CONFIGURE,"Con&figure...");
  268.             AppendMenu(gm,MF_STRING,IDM_ONTOP,"Always on &Top");
  269.             AppendMenu(gm,MF_STRING,IDM_HELP,"&Help...");
  270.             AppendMenu(gm,MF_STRING,IDM_ABOUT,"&About...");
  271.             adjust_to_configuration();
  272.             if(!configuration_info_successfully_read)
  273.                 PostMessage(hWnd,WM_SYSCOMMAND,IDM_CONFIGURE,0L);
  274.             return 0;
  275.         }
  276.         break;
  277.     case WM_SYSCOMMAND:
  278.         switch(wParam&0xFFF0){
  279.         case SC_CLOSE: // allow shift-close to save VULCAN.VCN
  280.             if(0x8000&GetAsyncKeyState(VK_SHIFT)){
  281.                 vcnSaveVcnFile();
  282.                 return 0;
  283.             }
  284.             break;
  285.         case IDM_ABOUT:
  286.             set_redraw_main_cursor(1);
  287.             MessageBox(hWnd,copyright,"About Vulcan",MB_OK);
  288.             set_redraw_main_cursor(0);
  289.             return 0;
  290.         case IDM_HELP:
  291.             set_redraw_main_cursor(1);
  292.             MessageBox(hWnd,helpstring_main,"Vulcan Help",MB_OK);
  293.             set_redraw_main_cursor(0);
  294.             return 0;
  295.         case IDM_VULCANIZE:
  296.             {
  297.             static DWORD last_filter=1;
  298.             static char directory[128]="";
  299.             char whole_file_name[128]="";
  300.             set_redraw_main_cursor(1);
  301.             OPENFILENAME ofn={sizeof(ofn),hWnd,hMainInstance,
  302.                 "All Files\0*.*\0Batch Files\0*.BAT\0"
  303.                 "Documents\0*.DOC;*.TXT;*.WRI\0",NULL,0,
  304.                 last_filter, // set to filter user chose last time
  305.                 whole_file_name,sizeof(whole_file_name),0,0,
  306.                 directory[0]?directory:NULL, // use last dir if possible
  307.                 IsDeleting?"Vulcan -- Select file for Trashcan":
  308.                     "Vulcan -- Select file for Vault",
  309.                 OFN_FILEMUSTEXIST| // user can't save nonexistent files!
  310.                     OFN_HIDEREADONLY| // IsDeleting covers this ground
  311.                     OFN_NOCHANGEDIR| // don't leave a mess behind us
  312.                     OFN_NOTESTFILECREATE, // shouldn't need this
  313.                 0,0,NULL,0L,NULL,NULL};
  314.             if(IsDeleting)ofn.Flags|=OFN_NOREADONLYRETURN; // can't delete!
  315.             if(GetOpenFileName(&ofn)&&whole_file_name[0]){
  316.                 char *p=&whole_file_name[ofn.nFileOffset]; // filename
  317.                 start_cancel_dialog_box();
  318.                 ProcessFile(whole_file_name,p,DC_LONER);
  319.                 end_cancel_dialog_box();
  320.                 *p=0;
  321.                 if(p[-2]!=':')p[-1]=0; // strip trailing backslash
  322.                 lstrcpy(directory,whole_file_name); // save dir
  323.                 last_filter=ofn.nFilterIndex;
  324.             }
  325.             set_redraw_main_cursor(0);
  326.             return 0;
  327.             }
  328.         case IDM_ONTOP:
  329.             ++IsOnTop%=2;
  330.             adjust_to_configuration();
  331.             return 0;
  332.         case IDM_BROWSE:
  333.             set_redraw_main_cursor(1);
  334.             start_browse_dialog_box();
  335.             set_redraw_main_cursor(0);
  336.             return 0;
  337.         case IDM_CONFIGURE:
  338.             set_redraw_main_cursor(1);
  339.             {
  340.                 DLGPROC dbp=(DLGPROC)MakeProcInstance(
  341.                     (FARPROC)ConfigureDialogProc,hMainInstance);
  342.                 if(NULL!=dbp){
  343.                     int retval=DialogBox(hMainInstance,
  344.                         MAKEINTRESOURCE(IDD_CONFIGURATION),hMainWindow,dbp);
  345.                     FreeProcInstance((FARPROC)dbp);
  346.                     if(retval){
  347.                         configuration_info_successfully_read=1;
  348.                         adjust_to_configuration();
  349.                     }
  350.                     else{
  351.                         set_redraw_main_cursor(0);
  352.                         if(!configuration_info_successfully_read){
  353.                             PostMessage(hWnd,WM_SYSCOMMAND,SC_CLOSE,0L);
  354.                         }
  355.                     }
  356.                 }
  357.             }
  358.             return 0;
  359.         }
  360.         break;
  361.     case WM_PAINT:
  362.         {
  363.         RECT rect;
  364.         PAINTSTRUCT ps;
  365.         if(GetUpdateRect(hMainWindow,&rect,FALSE)){
  366.             HDC hdc=BeginPaint(hMainWindow,&ps);
  367.             if(hdc!=NULL){
  368.                 DefWindowProc(hMainWindow, // erase bkgnd
  369.                     WM_ICONERASEBKGND,(WORD)ps.hdc,0L);
  370.                 DrawIcon(hdc,0,0,hIconCurrent);
  371.             }
  372.             EndPaint(hMainWindow,&ps);
  373.         }
  374.         return 0;
  375.         }
  376.     case WM_DROPFILES:
  377.         {
  378.         WORD total_files,current_file,x;
  379.         int disp_char;
  380.         char whole_name_buf[200],*p;
  381.         total_files=DragQueryFile((HDROP)wParam,-1,NULL,0);
  382.         if(total_files){
  383.             set_redraw_main_cursor(1);
  384.             start_cancel_dialog_box();
  385.             for(x=0;x<total_files;x++){
  386.                 // switch so that first in drag-drop block will be last
  387.                 // one sent to archive; on display, the first in the
  388.                 // drag-drop block will be at the _top_ of the list
  389.                 current_file=total_files-x-1;
  390.                 UINT dqf=DragQueryFile((HDROP)wParam,current_file,
  391.                     whole_name_buf,sizeof(whole_name_buf));
  392.                 if(dqf<1){
  393.                     MessageBox(hMainWindow,drag_drop_error,
  394.                         szAppErrorTitle,MB_OK|MB_ICONSTOP);
  395.                     break;
  396.                 }
  397.                 p=whole_name_buf;
  398.                 while(*p)p++; // point at null terminator
  399.                 p--; // points at last char in filename
  400.                 for(;;){
  401.                     if(p<=whole_name_buf)break; // don't go before start
  402.                     if(*p=='\\'||*p==':'){ // found path
  403.                         p++;
  404.                         break; // p points at filename
  405.                     }
  406.                     p--; // move back...
  407.                 }
  408.                 if(total_files==1)disp_char=DC_LONER;
  409.                 else if(current_file==0)disp_char=DC_FIRST;
  410.                 else if(current_file==(total_files-1))disp_char=DC_LAST;
  411.                 else disp_char=DC_MIDDLE;
  412.                 if(!ProcessFile(whole_name_buf,p,disp_char))break;
  413.             }
  414.             end_cancel_dialog_box();
  415.             set_redraw_main_cursor(0);
  416.         }
  417.         DragFinish((HDROP)wParam);
  418.         return 0;
  419.     }
  420.     case WM_QUERYDRAGICON:
  421.         if(hIconCurrent!=NULL)return (LRESULT)MAKELONG((UINT)hIconCurrent,0);
  422.         break;
  423.     case WM_QUERYENDSESSION:
  424.         vcnSaveVcnFile();
  425.         break;
  426.     case WM_DESTROY:
  427.         vcnDestroy();
  428.         PostQuitMessage(0);
  429.         return FALSE;
  430.     }
  431.     return DefWindowProc(hWnd,uMsg,wParam,lParam);
  432. }
  433. BOOL CALLBACK ConfigureDialogProc(HWND hWnd,UINT msg,WPARAM wParam,
  434. LPARAM lParam){
  435.     switch(msg){
  436.     case WM_INITDIALOG:
  437.         pszTargetDirFile[-1]=0; // cut off terminating backslash
  438.         wsprintf(pacBigScratchBuffer,"Configuring Vulcan archive stored in %s",
  439.             (LPSTR)szTargetDirectory);
  440.         pszTargetDirFile[-1]='\\'; // restore terminating backslash
  441.         SetWindowText(GetDlgItem(hWnd,IDC_LOCATIONSTATIC),pacBigScratchBuffer);
  442.         SetWindowText(GetDlgItem(hWnd,IDC_ICONCAPTION),szUserCaption);
  443.         SetDlgItemInt(hWnd,IDC_MAXMEGS,MaxMegs,FALSE);
  444.         SetDlgItemInt(hWnd,IDC_LEAVEMEGS,LeaveMegs,FALSE);
  445.         CheckRadioButton(hWnd,IDC_MAXMEGSRADIO,IDC_LEAVEMEGSRADIO,
  446.             UseLeaveMegsNumber?IDC_LEAVEMEGSRADIO:IDC_MAXMEGSRADIO);
  447.         EnableWindow(GetDlgItem(hWnd,
  448.             UseLeaveMegsNumber?IDC_MAXMEGS:IDC_LEAVEMEGS),FALSE);
  449.         CheckRadioButton(hWnd,IDC_VAULTRADIO,IDC_TRASHCANRADIO,
  450.             IsDeleting?IDC_TRASHCANRADIO:IDC_VAULTRADIO);
  451.         CheckDlgButton(hWnd,IDC_ALWAYSONTOP,IsOnTop?1:0);
  452.         CheckDlgButton(hWnd,IDC_WARNOVERWRITE,WarnOnOverwrite?1:0);
  453.         CheckDlgButton(hWnd,IDC_WARNDELETE,WarnOnDeleteSome?1:0);
  454.         CheckDlgButton(hWnd,IDC_WARNNOTFIT,WarnOnDoesntFit?1:0);
  455.         // next line disables WarnOnDoesntFit ==++==
  456.         ShowWindow(GetDlgItem(hWnd,IDC_WARNNOTFIT),SW_HIDE);
  457. #ifdef COMPRESSION
  458.         CheckDlgButton(hWnd,IDC_COMPRESSFILES,CompressFiles?1:0);
  459. #else
  460.         CheckDlgButton(hWnd,IDC_COMPRESSFILES,0);
  461.         ShowWindow(GetDlgItem(hWnd,IDC_COMPRESSFILES),SW_HIDE);
  462. #endif
  463.         return 1;
  464.     case WM_COMMAND:
  465.         switch(wParam){
  466.         case IDC_MAXMEGSRADIO:
  467.             if(BN_CLICKED==HIWORD(lParam)){
  468.                 EnableWindow(GetDlgItem(hWnd,IDC_MAXMEGS),TRUE);
  469.                 EnableWindow(GetDlgItem(hWnd,IDC_LEAVEMEGS),FALSE);
  470.             }
  471.             break;
  472.         case IDC_LEAVEMEGSRADIO:
  473.             if(BN_CLICKED==HIWORD(lParam)){
  474.                 EnableWindow(GetDlgItem(hWnd,IDC_LEAVEMEGS),TRUE);
  475.                 EnableWindow(GetDlgItem(hWnd,IDC_MAXMEGS),FALSE);
  476.             }
  477.             break;
  478.         case IDOK:
  479.             int iUseLeaveMegs,iNumber;
  480.             {
  481.                 BOOL iGotItOk=0;
  482.                 iUseLeaveMegs=IsDlgButtonChecked(hWnd,IDC_LEAVEMEGSRADIO)?1:0;
  483.                 iNumber=(int)GetDlgItemInt(hWnd,
  484.                     iUseLeaveMegs?IDC_LEAVEMEGS:IDC_MAXMEGS,&iGotItOk,FALSE);
  485.                 if((!iGotItOk)||iNumber<1||iNumber>1024){
  486.                     MessageBox(hWnd,"Must enter value from 1 to 1024",
  487.                         "Vulcan Configuration Error",MB_OK);
  488.                     SetFocus(GetDlgItem(hWnd,
  489.                         iUseLeaveMegs?IDC_LEAVEMEGS:IDC_MAXMEGS));
  490.                     return TRUE;
  491.                 }
  492.             }
  493.             GetWindowText(GetDlgItem(hWnd,IDC_ICONCAPTION),
  494.                 szUserCaption,(int)sizeof(szUserCaption)-1);
  495.             UseLeaveMegsNumber=iUseLeaveMegs;
  496.             if(UseLeaveMegsNumber)LeaveMegs=iNumber; else MaxMegs=iNumber;
  497.             IsDeleting=IsDlgButtonChecked(hWnd,IDC_TRASHCANRADIO)?1:0;
  498.             IsOnTop=IsDlgButtonChecked(hWnd,IDC_ALWAYSONTOP)?1:0;
  499.             WarnOnOverwrite=IsDlgButtonChecked(hWnd,IDC_WARNOVERWRITE)?1:0;
  500.             WarnOnDeleteSome=IsDlgButtonChecked(hWnd,IDC_WARNDELETE)?1:0;
  501.             WarnOnDoesntFit=IsDlgButtonChecked(hWnd,IDC_WARNNOTFIT)?1:0;
  502.             CompressFiles=IsDlgButtonChecked(hWnd,IDC_COMPRESSFILES)?1:0;
  503.             EndDialog(hWnd,TRUE);
  504.             return TRUE;
  505.         case IDCANCEL:
  506.             EndDialog(hWnd,FALSE);
  507.             return TRUE;
  508.         case IDC_BUTTONHELP:
  509.             MessageBox(hWnd,helpstring,"Vulcan Configuration Help",MB_OK);
  510.             return TRUE;
  511.         }
  512.     }
  513.     return 0;
  514. }
  515. void set_redraw_main_cursor(int show_main_cursor){
  516. // set and redraw cursor for main window
  517. //     cursor is IDI_VULCAN if show_main_cursor is nonzero
  518. // when called with 1, turns drag and drop receptivity off
  519. // turns drag and drop receptivity on when called with 0
  520.     hIconCurrent=show_main_cursor?hIconVulcan:
  521.         (IsDeleting?hIconTrash:hIconVault);
  522.     InvalidateRect(hMainWindow,NULL,TRUE);
  523.     UpdateWindow(hMainWindow);
  524.     DragAcceptFiles(hMainWindow,show_main_cursor?FALSE:TRUE);
  525. }
  526. void adjust_to_configuration(void){
  527.     if(IsOnTop){
  528.         CheckMenuItem(gm,IDM_ONTOP,MF_BYCOMMAND|MF_CHECKED);
  529.         SetWindowPos(hMainWindow,HWND_TOPMOST,0,0,0,0,
  530.             SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  531.     }
  532.     else{
  533.         CheckMenuItem(gm,IDM_ONTOP,MF_BYCOMMAND|MF_UNCHECKED);
  534.         SetWindowPos(hMainWindow,HWND_NOTOPMOST,0,0,0,0,
  535.             SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  536.     }
  537.     if(szUserCaption[0])
  538.         wsprintf(szCaption,"%s -- %s",(LPSTR)szAppName,(LPSTR)szUserCaption);
  539.     else wsprintf(szCaption,"%s",(LPSTR)szAppName);
  540.     SetWindowText(hMainWindow,szCaption);
  541.     DrawMenuBar(hMainWindow);
  542.     set_redraw_main_cursor(0);
  543.     write_configuration_information();
  544. }
  545. void read_configuration_information(void){
  546. // INI file is szIniFile, section is szTargetDirectory
  547. // if all items successfully read (but szUserCaption, optional),
  548. //   set configuration_info_successfully_read to 1
  549.     LPCSTR sec=szTargetDirectory;
  550.     int success=1,itemp;
  551.     *pszTargetDirFile=0; // get raw dirname
  552.     // MaxMegs
  553.     itemp=GetPrivateProfileInt(sec,"MaxMegs",-1,szIniFile);
  554.     if(itemp<1)success=0;
  555.     else o_MaxMegs=MaxMegs=itemp;
  556.     // LeaveMegs
  557.     itemp=GetPrivateProfileInt(sec,"LeaveMegs",-1,szIniFile);
  558.     if(itemp<1)success=0;
  559.     else o_LeaveMegs=LeaveMegs=itemp;
  560.     // UseLeaveMegsNumber
  561.     itemp=GetPrivateProfileInt(sec,"UseLeaveMegsNumber",-1,szIniFile);
  562.     if(itemp<0||itemp>1)success=0;
  563.     else o_UseLeaveMegsNumber=UseLeaveMegsNumber=itemp;
  564.     // IsOnTop
  565.     itemp=GetPrivateProfileInt(sec,"IsOnTop",-1,szIniFile);
  566.     if(itemp<0||itemp>1)success=0;
  567.     else o_IsOnTop=IsOnTop=itemp;
  568.     // IsDeleting
  569.     itemp=GetPrivateProfileInt(sec,"IsDeleting",-1,szIniFile);
  570.     if(itemp<0||itemp>1)success=0;
  571.     else o_IsDeleting=IsDeleting=itemp;
  572.     // UseClassicIcons
  573.     itemp=GetPrivateProfileInt("Globals","UseClassicIcons",0,szIniFile);
  574.     UseClassicIcons=itemp?1:0;
  575.     // CompressFiles
  576. #ifdef COMPRESSION
  577.     itemp=GetPrivateProfileInt(sec,"CompressFiles",-1,szIniFile);
  578.     if(itemp<0||itemp>1)success=0;
  579.     else o_CompressFiles=CompressFiles=itemp;
  580. #else
  581.     o_CompressFiles=CompressFiles=0;
  582. #endif
  583.     // WarnOnOverwrite
  584.     itemp=GetPrivateProfileInt(sec,"WarnOnOverwrite",-1,szIniFile);
  585.     if(itemp<0||itemp>1)success=0;
  586.     else o_WarnOnOverwrite=WarnOnOverwrite=itemp;
  587.     // WarnOnDeleteSome
  588.     itemp=GetPrivateProfileInt(sec,"WarnOnDeleteSome",-1,szIniFile);
  589.     if(itemp<0||itemp>1)success=0;
  590.     else o_WarnOnDeleteSome=WarnOnDeleteSome=itemp;
  591.     // WarnOnDoesntFit
  592.     itemp=GetPrivateProfileInt(sec,"WarnOnDoesntFit",-1,szIniFile);
  593.     if(itemp<0||itemp>1)success=0;
  594.     else o_WarnOnDoesntFit=WarnOnDoesntFit=itemp;
  595.     // szUserCaption
  596.     itemp=GetPrivateProfileString(sec,"IconCaption","",
  597.         szUserCaption,sizeof(szUserCaption),szIniFile);
  598.     if(!itemp)szUserCaption[0]=0;
  599.     if(success)configuration_info_successfully_read=1;
  600. }
  601. void write_configuration_information(void){
  602.     char number_buf[20];
  603.     *pszTargetDirFile=0;
  604.     char printstring[]="%d";
  605. #define WRITE_INI_INT_IF_NEEDED(x) if(x!=o_##x){\
  606.         wsprintf(number_buf,printstring,x);\
  607.         if(WritePrivateProfileString(szTargetDirectory,#x,\
  608.             number_buf,szIniFile))o_##x=x;\
  609.         else o_##x=-1;\
  610.     }
  611.     WRITE_INI_INT_IF_NEEDED(IsDeleting)
  612.     WRITE_INI_INT_IF_NEEDED(IsOnTop)
  613.     WRITE_INI_INT_IF_NEEDED(MaxMegs)
  614.     WRITE_INI_INT_IF_NEEDED(LeaveMegs)
  615.     WRITE_INI_INT_IF_NEEDED(UseLeaveMegsNumber)
  616.     WRITE_INI_INT_IF_NEEDED(WarnOnOverwrite)
  617.     WRITE_INI_INT_IF_NEEDED(WarnOnDeleteSome)
  618.     WRITE_INI_INT_IF_NEEDED(WarnOnDoesntFit)
  619.     WRITE_INI_INT_IF_NEEDED(CompressFiles)
  620.     if(lstrcmp(szUserCaption,o_szUserCaption)){
  621.         if(WritePrivateProfileString(szTargetDirectory,"IconCaption",
  622.             szUserCaption[0]?szUserCaption:NULL,szIniFile)){
  623.             lstrcpy(o_szUserCaption,szUserCaption);
  624.         }
  625.     }
  626. }
  627. int set_szIniFile(void){
  628.     // sets szIniFile name for use as private profile file
  629.     // return 0 if fail, 1 if success
  630.     if(!GetModuleFileName(hMainInstance,szIniFile,sizeof(szIniFile)))
  631.         lstrcpy(szIniFile,"VULCAN.EXE");
  632.     char *p=szIniFile;
  633.     while(*p)p++;
  634.     for(;;){
  635.         if(p==szIniFile)return 0;
  636.         if(*p=='.')break; // pointing at .EXE extension
  637.         p--;
  638.     }
  639.     lstrcpy(p,".INI");
  640.     return 1;
  641. }
  642. int set_szTargetDirectory(LPSTR cmdline){
  643.     // checks cmd line to see if VULCAN.VCN file specified with
  644.     // complete path. If not, uses common dialog to choose the
  645.     // file, then sets szTargetDirectory to the pathname (including
  646.     // trailing backslash
  647.     // also sets pszTargetDirFile to point at the spot _after_ the
  648.     // trailing backslash
  649.     int ok=0;
  650.     LPSTR candidate_name;
  651.     if(cmdline!=NULL&&*cmdline){
  652.         candidate_name=cmdline;
  653.         LPSTR p=cmdline;
  654.         for(;;){
  655.             int got_colon=0;
  656.             while(*p){
  657.                 if(*p==':')got_colon=1;
  658.                 *p=toupper(*p);
  659.                 p++;
  660.             } // point at null terminator
  661.             if(!got_colon)break; // can't be full path without one
  662.             for(;;){
  663.                 if(p==cmdline)break;
  664.                 if(*p==':'||*p=='\\'){p++;break;}
  665.                 p--;
  666.             } // point at filename
  667.             lstrcpy(p,szVulcanVcn); // coerce to right filename
  668.             if(lstrcmp(szVulcanVcn,p))break;
  669.             *p=0;
  670.             ok=1;
  671.             break;
  672.         }
  673.     }
  674.     else{
  675.         szTargetDirectory[0]=0;
  676.         OPENFILENAME ofn={sizeof(ofn),NULL,hMainInstance,
  677.             "Vulcan Index File\0VULCAN.VCN\0",NULL,0,
  678.             1,szTargetDirectory,sizeof(szTargetDirectory),0,0,
  679.             NULL, // use last dir if possible
  680.             "Vulcan -- Select directory for Trashcan/Vault",
  681.             OFN_HIDEREADONLY| // IsDeleting covers this ground
  682.             OFN_NOCHANGEDIR| // don't leave a mess behind us
  683.             OFN_PATHMUSTEXIST| // directory must exist
  684.             OFN_NOREADONLYRETURN| // can't be read-only for archive!
  685.             OFN_NOTESTFILECREATE| // shouldn't need this
  686.             OFN_ENABLETEMPLATE, // using custom template
  687.             0,0,NULL,0L,NULL,
  688.             MAKEINTRESOURCE(IDD_OPENFILE)}; // template
  689.         for(;;){
  690.             candidate_name=NULL;
  691.             if(!GetSaveFileName(&ofn)||!szTargetDirectory[0])break;
  692.             candidate_name=szTargetDirectory;
  693.             char *p=szTargetDirectory;
  694.             while(*p){
  695.                 *p=toupper(*p);
  696.                 p++;
  697.             } // point at end of string
  698.             for(;;){
  699.                 if(p==szTargetDirectory)break;
  700.                 if(*p==':'||*p=='\\'){p++;break;}
  701.                 p--;
  702.             } // point at filename
  703.             lstrcpy(p,szVulcanVcn); // coerce to right filename
  704.             if(lstrcmp(szVulcanVcn,p))break;
  705.             *p=0;
  706.             ok=1;
  707.             break;
  708.         }
  709.     }
  710.     if((!ok)&&(candidate_name!=NULL)){
  711.         char temp[160];
  712.         wsprintf(temp,"%s is not a valid, fully qualified name for "
  713.         "VULCAN.VCN",candidate_name);
  714.         MessageBox(CURR_WINDOW,temp,szAppErrorTitle,MB_OK); // ==++CURR_WINDOW
  715.     }
  716.     else{
  717.         lstrcpy(szTargetDirectory,candidate_name);
  718.         pszTargetDirFile=szTargetDirectory;
  719.         while(*pszTargetDirFile)pszTargetDirFile++;
  720.     }
  721.     return ok;
  722. }
  723. int verify_target_not_in_use(HWND *activate){
  724.     // returns 1 if all is OK i.e. target not yet in use
  725.     // returns 0 if target already in use
  726.     // first save our target directory...
  727.     lstrcpy(pacBigScratchBuffer2,szTargetDirectory);
  728.     HWND next=GetWindow(GetDesktopWindow(),GW_CHILD);
  729.     while(next!=NULL){ // process each child of the desktop window
  730.         // don't check our own!
  731.         for(;;){
  732.             if(hMainInstance==(HINSTANCE)GetWindowWord(next,GWW_HINSTANCE)){
  733.                 break; // same instance is us! don't check...
  734.             }
  735.             // get class name
  736.             if(!GetClassName(next,pacBigScratchBuffer,BSB_SIZE))break;
  737.             // if it's not ours, don't bother...
  738.             if(lstrcmp(pacBigScratchBuffer,szClassName))break;
  739.             // ok, it's a window of our class but not us
  740.             // let's find out what its szTargetDirectory is
  741.             // new get theirs
  742.             GetInstanceData(GetWindowWord(next,GWW_HINSTANCE),
  743.                 (unsigned char *)szTargetDirectory,
  744.                 sizeof(szTargetDirectory));
  745.             // strip string down to directory only
  746.             {
  747.                 char *p=szTargetDirectory;
  748.                 while(*p)p++;
  749.                 while((p>szTargetDirectory)&&(*p!='\\'))*p--=0;
  750.             }
  751.             // if they're the same, we've got trouble
  752.             if(!lstrcmp(szTargetDirectory,pacBigScratchBuffer2)){
  753.                 *activate=next;
  754.                 return 0;
  755.             }
  756.             break;
  757.         }
  758.         next=GetWindow(next,GW_HWNDNEXT);
  759.     }
  760.     lstrcpy(szTargetDirectory,pacBigScratchBuffer2);
  761.     return 1;
  762. }
  763. int ProcessFile(LPSTR complete,LPSTR eight_three,int disp_char){
  764. // returns 0 if user pressed cancel, 1 for success or file too large
  765. // also returns 1 if a single file failed and user knows...
  766. // handles whole process of confirmation, copy, rename, etc.
  767.     set_cancel_dialog_box_text(IsDeleting?"Copying and deleting"
  768.     :"Copying",complete);
  769.     if(check_cancel_dialog_box())return 0;
  770.     char dir[138],*p;
  771.     if(!complete||!*complete||!eight_three||!*eight_three||!disp_char){
  772.         wsprintf(pacBigScratchBuffer,"Internal error %d",__LINE__);
  773.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  774.         return 0;
  775.     }
  776.     lstrcpy(dir,complete);
  777.     p=dir;
  778.     while(*p)p++; // point at terminating null
  779.     p--; // last char of string
  780.     for(;;){
  781.         if(p==dir){
  782.             wsprintf(pacBigScratchBuffer,"Internal error %d",__LINE__);
  783.             MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  784.         }
  785.         if(*p=='\\'||*p==':'){
  786.             p[1]=0;
  787.             break;
  788.         }
  789.         p--;
  790.     }
  791.     // ok now we have verified original file's name
  792.     // now get file's size, attributes
  793.     vcn_info vi;
  794.     long t,b;
  795.     vcnGetFilenumberRange(b,t);
  796.     vi.version=1;
  797.     vi.signature=SIGNATURE;
  798.     vi.DispChar=disp_char;
  799.     vi.Index=t+1L;
  800.     int fh;
  801.     unsigned attrib;
  802.     lstrcpy(pacBigScratchBuffer,complete);
  803.     if(_dos_getfileattr(pacBigScratchBuffer,&attrib)||
  804.     _dos_open(pacBigScratchBuffer,_O_RDONLY,&fh)){
  805.         wsprintf(pacBigScratchBuffer,"Can't open %s\n\nFile not %s.",
  806.             (LPSTR)complete,(LPSTR)(IsDeleting?"moved":"copied"));
  807.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  808.         return 1; // user knows, now get rest of files
  809.     }
  810.     vi.Attrib=attrib;
  811.     struct _stat statbuf;
  812.     unsigned filedate,filetime;
  813.     if(_fstat(fh,&statbuf)||_dos_getftime(fh,&filedate,&filetime)){
  814.         _dos_close(fh);
  815.         wsprintf(pacBigScratchBuffer,"Error accessing %s\n\nFile not %s.",
  816.             (LPSTR)complete,(LPSTR)(IsDeleting?"moved":"copied"));
  817.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  818.         _dos_close(fh);
  819.         return 1; // get rest of files...
  820.     }
  821.     vi.FileSize=statbuf.st_size;
  822.     vi.FileDate=filedate;
  823.     vi.FileTime=filetime;
  824.     vi.compressed=CompressFiles?1:0;
  825.     vi.FullName=complete;
  826.     // ok, now vi is full
  827.     // now determine if file should be copied
  828.     // if it won't fit no matter what, we'll be punting
  829.     if(vcnGetTargetDiskBytes()<
  830.     vcnAdjustForClusterSize(vi.FileSize+INFLATION)){
  831.         if(WarnOnDoesntFit){
  832.             wsprintf(pacBigScratchBuffer,"Cannot put %s into archive -- "
  833.                 "alone it is larger than the space you have available "
  834.                 "for your VULCAN archive. File not %s.",
  835.                 (LPSTR)complete,
  836.                 (LPSTR)(IsDeleting?"moved":"copied"));
  837.             MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  838.         }
  839.         _dos_close(fh);
  840.         return 1; // user knows this one file didn't make it, why not
  841.                   // allow rest of files to move?
  842.     }
  843.     // ok, so it can fit. do we have to delete files to do it?
  844.     if(vcnAddBytesRequiresSomeDelete(vi.FileSize)){
  845.         if(WarnOnDeleteSome){ // give user the option...
  846.             wsprintf(pacBigScratchBuffer,"Must delete some files to %s "
  847.             "%s to VULCAN's archive. You may choose to allow this deletion "
  848.             "or cancel the operation.\n\n"
  849.             "YES means go ahead, add the new file and delete old files as "
  850.             "necessary.\n\n"
  851.             "NO means don't add the file, and don't delete any existing "
  852.             "files.",(LPSTR)(IsDeleting?"move":"copy"),(LPSTR)complete);
  853.             switch(MessageBox(CURR_WINDOW,pacBigScratchBuffer,
  854.             szAppErrorTitle,MB_YESNO)){
  855.             case IDYES:
  856.                 break;
  857.             default:
  858.             case IDNO:
  859.                 _dos_close(fh);
  860.                 return 0;
  861.             }
  862.         }
  863.         vcnForceToCorrectSize(vi.FileSize); // pare the archive
  864.     }
  865.     // ok, now we have adequate space and we want to copy the file
  866.     // first, get filename like C:\VULCAN\ARC\~TEMP.VCN -- target name
  867.     lstrcpy(pszTargetDirFile,szTempFileName);
  868.     // now delete any old ~TEMP.VCN
  869.     _dos_setfileattr(szTargetDirectory,_A_NORMAL);
  870.     remove(szTargetDirectory);
  871.     // now open ~TEMP.VCN
  872.     int ofh;
  873.     if(_dos_creatnew(szTargetDirectory,_A_NORMAL,&ofh)){
  874.         wsprintf(pacBigScratchBuffer,"Could not open %s. File not %s.",
  875.         (LPSTR)complete,(LPSTR)(IsDeleting?"moved":"copied"));
  876.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  877.         _dos_close(fh);
  878.         return 0;
  879.     }
  880.     // now both files open, fh for read and ofh for write
  881.     // first, write header data to ofh
  882.     int store_result=1,header_size=0;
  883.     if(vcnWriteEntry(vi,ofh,&header_size)){ // success
  884.         store_result=store_filedata(fh,ofh,vi.FileSize);
  885.     }
  886.     _dos_close(fh);
  887.     _dos_close(ofh);
  888.     switch(store_result){
  889.     case 1: // error forced quit
  890.         wsprintf(pacBigScratchBuffer,"Error copying %s. File not %s.",
  891.         (LPSTR)complete,(LPSTR)(IsDeleting?"moved":"copied"));
  892.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  893.         remove(szTargetDirectory); // delete the file
  894.         return 1; // user knows, let it ride
  895.     case 2: // user pressed cancel
  896.         remove(szTargetDirectory); // delete the file
  897.         return 0;
  898.     }
  899.     // ok, we have successfully copied file and closed it -- rename it
  900.     lstrcpy(pacBigScratchBuffer2,szTargetDirectory); // "C:\A\~TEMP.VCN"
  901.     wsprintf(pszTargetDirFile,"%08ld.VCN",vi.Index); // "C:\A\00000422.VCN"
  902.     if(rename(pacBigScratchBuffer2,szTargetDirectory)){
  903.         wsprintf(pacBigScratchBuffer,"Cannot rename %s to %s. File not %s.",
  904.         (LPSTR)pacBigScratchBuffer2,(LPSTR)szTargetDirectory,
  905.         (LPSTR)(IsDeleting?"moved":"copied"));
  906.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  907.         remove(pacBigScratchBuffer2);
  908.         return 0; // this means we're really messed up, force cancel
  909.     }
  910.     // now add StoredDate, StoredTime and StoredSize elements
  911.     // get data from file rather than computation to allow for
  912.     //  compression and variable header size
  913.     {
  914.         struct _stat ss;
  915.         if(!_stat(szTargetDirectory,&ss))vi.StoredSize=ss.st_size;
  916.         else vi.StoredSize=vi.FileSize+(long)header_size;
  917.         vi.StoredDate=vi.StoredTime=0;
  918.         if(!_dos_open(szTargetDirectory,_O_RDONLY,&fh)){
  919.             unsigned d,t;
  920.             if(!_dos_getftime(fh,&d,&t)){
  921.                 vi.StoredDate=d;
  922.                 vi.StoredTime=t;
  923.             }
  924.             _dos_close(fh);
  925.         }
  926.     }
  927.     // now add to queue
  928.     if(!vcnPutInfo(vi)){
  929.         wsprintf(pacBigScratchBuffer,"Out of memory adding %s. File not %s.",
  930.         (LPSTR)complete,(LPSTR)(IsDeleting?"moved":"copied"));
  931.         MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  932.         remove(szTargetDirectory); // delete the file
  933.         return 0; // we're messed up, force cancel
  934.     }
  935.     // now delete the original if necessary
  936.     if(IsDeleting){
  937.         set_cancel_dialog_box_text("Deleting",NULL);
  938.         lstrcpy(pacBigScratchBuffer,complete);
  939.         _dos_setfileattr(pacBigScratchBuffer,_A_NORMAL);
  940.         remove(pacBigScratchBuffer);
  941.     }
  942.     return 1;
  943. }
  944. static int store_filedata(unsigned i,unsigned o,long bytes){
  945.     // returns 0 for success, 1 for failure, 2 for user quit
  946.     // doesn't close files, does no renames or deletes on fail
  947.     unsigned numwanted,numdone;
  948.     while(bytes){
  949.         // copy BSB_SIZE bytes at a time from i to o
  950.         if(check_cancel_dialog_box())return 2;
  951.         numwanted=(unsigned)(BSB_SIZE<bytes?BSB_SIZE:bytes);
  952.         if(_dos_read(i,pacBigScratchBuffer,numwanted,&numdone)||
  953.         numdone!=numwanted){
  954.             return 1; // read failure
  955.         }
  956.         if(_dos_write(o,pacBigScratchBuffer,numwanted,&numdone)||
  957.         numwanted!=numdone){
  958.             return 1; // write failure
  959.         }
  960.         bytes-=(long)numwanted;
  961.     }
  962.     return 0;
  963. }
  964.