/*********************************************************************
 *
 *            EZFM---EZWGL based file manager for X11
 *
 *             Copyright (C) 1998  Maorong Zou
 *
 *
 *  This file is part of EZFM.
 *
 *  EZFM is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * EZFM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EZFM; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 *************************************************************************/




/**********************************************************************************
 *
 *  interface with removable drives, such as CDROM/FLOPPY/ZIP.
 *  We need /etc/fstab to make things work.
 *
 *  This  is part of my /etc/fstab.
 *
/dev/hdc       /cdrom  iso9660  user,noauto,ro,exec,unhide
/dev/fd0      /floppy    msdos  user,noauto,rw
/dev/hdb4     /zip       msdos  user,noauto,rw
#
/dev/fd0      /floppy2   ext2   user,noauto,rw,exec
/dev/hdb      /zip2      ext2   user,noauto,rw,exec
 *
 * Basically, we need to make the devices are mountable by a normal user.
 *
 */
#define _DRIVES_C_
#include "ezfm.h"

/**********************************************************************************/

#ifdef REMOVABLE_DRIVES

/**********************************************************************************/
int   setupDrivesButtons    MY_ANSIARGS((EZ_Widget *toolbar, int start_idx));
void  updateDriveMenu       MY_ANSIARGS((EZ_Widget *menu, void *data));
void  addRemovableDevice    MY_ANSIARGS((char *buf));
void  updateDriveMenusAndButtons MY_ANSIARGS((void));
/**********************************************************************************/
static int targetStartFilter MY_ANSIARGS((void *obj, void *data, char *msg, int len));
static int decodeFileName   MY_ANSIARGS((void *obj, void *data, char *message, int length));
static int decodeFileContent MY_ANSIARGS((void *obj, void *data, char *message, int length));
static int decodeFileTaredContent MY_ANSIARGS((void *obj, void *data, char *message, int length));
static void driveBtnCallback MY_ANSIARGS((void *widget, void *data));
static void driveBtnDestroyCallback MY_ANSIARGS((void *widget, void *data));
static void driveBtnEHandler MY_ANSIARGS ((EZ_Widget* widget,void *data, int etype, XEvent *xev));
/**********************************************************************************/

int setupDrivesButtons(frame, start_idx)
     EZ_Widget *frame; int start_idx;
{
  int i, j;
  char tstr[128], ttstr[128];
  EZ_Widget *btn;
  EZ_UnknownDataType dd;
  EZ_Widget *parent = frame;
  
  dd.p = NULL;
  for(i = 10; i >= 0; i--)  EZ_SetWidgetUnknownData(frame, i, dd);

  for(i = 0; i < 8; i++)
    {
      if(ezfmDrives[i].status >= 0)
	{
	  j = ezfmDrives[i].status; 
	  sprintf(tstr, "mount/umount %s", ezfmDrives[i].name);
	  sprintf(ttstr, "move/copy drag to %s", ezfmDrives[i].name);
	  btn =  EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, parent,
				 EZ_LABEL_STRING,        ezfmDrives[i].name,
				 EZ_BITMAP_FILE,         ezfmDrives[i].xpmlable[j],
				 EZ_BUBBLE_HELP,         tstr,
				 EZ_DND_BUBBLE_HELP,     ttstr,
				 EZ_GRID_CELL_GEOMETRY,  start_idx+i, 0, 1, 1, /* x, y, w, h */
				 EZ_CLIENT_INT_DATA,     i,
				 EZ_PADX,                0,
				 EZ_PADY,                0,
				 EZ_PROPAGATE,           False,
				 NULL);
	  dd.p= btn;
	  EZ_SetWidgetUnknownData(frame, i, dd);
	  if(btn)
	    {
	      FileInfo *finfo = ezfmDrives[i].finfo;
	      EZ_AddWidgetCallBack(btn, EZ_CALLBACK, driveBtnCallback, finfo, 0);
	      EZ_AddWidgetCallBack(btn, EZ_DESTROY_CALLBACK, driveBtnDestroyCallback, NULL, 0);
	      EZ_AddEventHandler(btn, driveBtnEHandler, NULL, 0);
	      EZ_WidgetAddDnDDataDecoder(btn, EZ_DND_DROP_START_ATOM, /* drop setup    */
					 0, targetStartFilter, (void *)i, NULL, NULL);

	      /* move file (by name only) */
	      EZ_WidgetAddDnDDataDecoder(btn, ezfmMoveFileByNameAtom, 0,
					 ezfmMoveToDirByName, finfo, NULL, NULL);
	      /* copy file */
	      EZ_WidgetAddDnDDataDecoder(btn, ezfmCopyFileByNameAtom, ControlMask,
					 ezfmCopyToDirByName, finfo, NULL, NULL);
	      EZ_WidgetAddDnDDataDecoder(btn, ezfmCopyFileByContentAtom, ControlMask,
					 ezfmCopyToDirByContent, finfo, NULL, NULL);
	      EZ_WidgetAddDnDDataDecoder(btn, ezfmCopyFileByTarAtom, ControlMask,
					 ezfmCopyToDirByTar, finfo, NULL, NULL);
	      /* link file */	      
	      EZ_WidgetAddDnDDataDecoder(btn, ezfmLinkFileByNameAtom, ShiftMask,
					 ezfmLinkToDirByName, finfo, NULL, NULL);
	    }
	}
      else break;
    }
  return(i);
}
/**********************************************************************************
 *
 *  If a file is draged to one of the drives buttons, DnD action will work only
 *  if the device is mounted. For DnD action, the buttons are treated essentially
 *  as folders.
 */
static int targetStartFilter(obj, data, msg, len)
     void *obj; void *data; char *msg; int len;
{
  int           which = (int)data;
  
  if(ezfmDrives[which].status == 1)
    {
      FileInfo *finfo = ezfmDrives[which].finfo;
      dirDnDTargetStartFilter(obj, finfo, msg, len);
    }
  else
    {
      Atom          *atomsInOut;
      int           *natomsInOut;
      unsigned int  *atypeOut;
      char          *name = ezfmDrives[which].name;

      EZ_DnDGetMatchedConversionTargets(&atomsInOut,&natomsInOut, &atypeOut);  
      if( *natomsInOut > 0)
	{
	  ezfmWarning(name, "is not mounted");      
	  *natomsInOut = 0;
	}
    }
  return (EZ_DND_SUCCESS);
}
/***************************************************************************/

static void openDriveInFolder(widget, data) EZ_Widget *widget; void *data;
{
  OpenFolder(data, NULL, 1, defaultFolderType);
}
/***************************************************************************/
#define     MT_MOUNT      0
#define     MT_UMOUNT     1
#define     MT_OPEN       2
void  updateDriveMenu(menu, data) EZ_Widget *menu; void *data;
{
  int idx = (int)data;
  if(EZ_WidgetExist(menu) && idx >= 0 && idx < 8)
    {
      int status = ezfmDrives[idx].status;
      EZ_Widget *mt, *umt, *opn;
      EZ_UnknownDataType ud;      
      EZ_GetWidgetUnknownData(menu, MT_MOUNT, &ud);      
      mt = ud.p;
      EZ_GetWidgetUnknownData(menu, MT_UMOUNT, &ud);            
      umt = ud.p;
      EZ_GetWidgetUnknownData(menu, MT_OPEN, &ud);            
      opn = ud.p;

      if(status)
	{
	  EZ_DisableWidget(mt);  
	  EZ_EnableWidget(umt); 
	  EZ_EnableWidget(opn); 
	}
      else 
	{
	  EZ_DisableWidget(umt);  
	  EZ_EnableWidget(mt);
	  EZ_DisableWidget(opn);  
	}
    }
}

static void mitemDoMount(widget, data) EZ_Widget *widget; void *data;
{
  int idx = (int)data;
  if(idx >= 0 && idx < 8 )  
    {
      char *mpt = ezfmDrives[idx].mntPt;  
      mountDrive(mpt, idx, NULL);
    }
}

static void mitemDoUMount(widget, data) EZ_Widget *widget; void *data;
{
  int idx = (int)data;
  if(idx >= 0 && idx < 8 )  
    {
      char *mpt = ezfmDrives[idx].mntPt;  
      umountDrive(mpt, idx);
    }
}


static void driveBtnEHandler(widget, data, etype, xev)
     EZ_Widget *widget; void *data; int etype; XEvent *xev;
{
  if(xev->type == ButtonPress && xev->xbutton.button == EZ_Btn2)
    {
      int       idx = EZ_GetWidgetIntData(widget);
      int       status = ezfmDrives[idx].status;
      EZ_Widget *menu = (EZ_Widget *)EZ_GetWidgetPtrData(widget);
      if(menu == NULL)
	{
	  char  *name = ezfmDrives[idx].name;
	  char  *mntPt = ezfmDrives[idx].mntPt;
	  char  str[128];
	  EZ_UnknownDataType ud;
	  EZ_Widget *mitem;
	  
	  menu = EZ_CreateWidget(EZ_WIDGET_POPUP_MENU, NULL,
				 EZ_LABEL_STRING,      name,
				 NULL);
	  EZ_SetMenuSetupProcedure(menu, updateDriveMenu, (void *)idx);
	  EZ_SetWidgetPtrData(widget, menu);/* remember menu */
	  
	  sprintf(str, "Mount %s", name);
	  mitem = EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, menu,
				  EZ_LABEL_STRING,              str,
				  EZ_UNDERLINE,                 0,
				  EZ_CALLBACK,                  mitemDoMount, (void *)idx,
				  NULL);
	  ud.p = mitem;
	  EZ_SetWidgetUnknownData(menu, MT_MOUNT, ud);
	  sprintf(str, "UMount %s", name);
	  mitem = EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, menu,
				  EZ_LABEL_STRING,              str,
				  EZ_UNDERLINE,                 0,
				  EZ_CALLBACK,                  mitemDoUMount, (void *)idx,
				  NULL);
	  ud.p = mitem;
	  EZ_SetWidgetUnknownData(menu, MT_UMOUNT, ud);
	  mitem = EZ_CreateWidget(EZ_WIDGET_MENU_SEPARATOR,      menu,
				  NULL);
	  sprintf(str, "Open %s", mntPt);
	  mitem = EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, menu,
				  EZ_LABEL_STRING,              str,
				  EZ_UNDERLINE,                 0,
				  EZ_CALLBACK,                  openDriveInFolder, mntPt,
				  NULL);
	  ud.p = mitem;
	  EZ_SetWidgetUnknownData(menu, MT_OPEN, ud);
	}
      EZ_DoPopupX(widget, menu, -1);
    }
}
#undef     MT_MOUNT
#undef     MT_UMOUNT
#undef     MT_OPEN

/***************************************************************************
 * Destroy the associated menu when delete a drive-button.
 */
static void driveBtnDestroyCallback(widget,data) EZ_Widget *widget; void *data;
{
  EZ_Widget *menu = (EZ_Widget *)EZ_GetWidgetPtrData(widget);
  if(menu) EZ_DestroyWidget(menu);
}
 
/**********************************************************************************/
static void doMountUmount(widget, data) EZ_Widget *widget; void *data;
{
  EZ_Widget *entry = (EZ_Widget *)data;
  if(entry)
    {
      EZ_Widget *toplevel = EZ_GetWidgetPtrData(entry);
      int idx = EZ_GetWidgetIntData(entry);
      char *mpt = ezfmDrives[idx].mntPt;
      int  which = EZ_GetWidgetIntData(widget);
      EZ_ReleaseGrab();
      EZ_HideWidget(toplevel);
      if(which) mountDrive(mpt, idx, NULL);
      else umountDrive(mpt, idx);
      EZ_DestroyWidget(toplevel);
    }
}
/**********************************************************************************/
static void openMountedDrive(widget, data)
     EZ_Widget *widget; void *data;
{
  EZ_Widget *entry = (EZ_Widget *)data;
  EZ_Widget *toplevel = (EZ_Widget *)EZ_GetWidgetPtrData(entry);
  
  EZ_HideWidget(toplevel);
  openDrive(entry, NULL);
  EZ_DestroyWidget(toplevel);
}
/*************************************************************************************/
static void cancelCb(widget, data)
     EZ_Widget *widget; void *data;
{
  EZ_Widget     *toplevel = (EZ_Widget *)data;
  EZ_ReleaseGrab();
  EZ_DestroyWidget(toplevel);
}
/*************************************************************************************/

static void driveBtnCallback(widget,data) EZ_Widget *widget; void *data;
{
  int idx = EZ_GetWidgetIntData(widget);
  char *name = ezfmDrives[idx].name;
  char *mpt =  ezfmDrives[idx].mntPt;
  int status = ezfmDrives[idx].status;
  EZ_Widget  *toplevel, *label, *gbox, *entry, *btn, *focus=NULL;
  char command[256];
  
  toplevel = EZ_CreateWidgetXrm(EZ_WIDGET_FRAME,    NULL, 
				"MountDialogue", "mountDialogue",
				EZ_FILL_MODE,      EZ_FILL_BOTH,
				EZ_TRANSIENT,      True,
				EZ_BG_PIXMAP,      bigPixmap,
				EZ_EVENT_HANDLER,  ConfigureNotifyHandler, NULL,
				NULL);
					
  gbox  = EZ_CreateWidget(EZ_WIDGET_FRAME,    toplevel,
			  EZ_PADX,            6, 
			  EZ_PADY,            6,       /*idx   min weight pad */
			  EZ_GRID_CONSTRAINS, EZ_COLUMN,  0,   340, 30,   0,
			  EZ_GRID_CONSTRAINS, EZ_COLUMN,  1,   60,  0,    0,
			  EZ_GRID_CONSTRAINS, EZ_ROW,     0,   16,  0,    0,
			  NULL);
  label = EZ_CreateWidget(EZ_WIDGET_LABEL,         gbox,
			  EZ_GRID_CELL_GEOMETRY,   0, 0, 2, 1,
			  EZ_LABEL_POSITION,       EZ_CENTER,
			  EZ_FOREGROUND,           "red",
			  EZ_LABEL_STRING,         "Please choose an action",
			  EZ_FONT_NAME, "-Adobe-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*",
			  NULL);

  
  sprintf(command, "%s %s", BIN_MOUNT, mpt);
  entry = EZ_CreateWidget(EZ_WIDGET_ENTRY,         gbox,
			  EZ_SELECTION_BACKGROUND, SelectionBackground,
			  EZ_GRID_CELL_GEOMETRY,   0, 0 , 1, 1,
			  EZ_GRID_CELL_PLACEMENT,  EZ_FILL_HORIZONTALLY, EZ_CENTER,
			  EZ_BORDER_WIDTH,         1,
			  EZ_ENTRY_STRING,         command,
			  EZ_CLIENT_INT_DATA,      idx,
			  EZ_CLIENT_PTR_DATA,      toplevel,
			  NULL);
  EZ_EntryEditBeginningOfInput(entry);
  EZ_DisableWidget(entry);
  
  sprintf(command, "Mount %s", name);
  btn   = EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, gbox,
			  EZ_GRID_CELL_GEOMETRY,   1, 0, 1, 1,
			  EZ_BORDER_WIDTH,         1,
			  EZ_PADX,                 6,
			  EZ_PADY,                 4,
			  EZ_LABEL_STRING,         command,
			  EZ_UNDERLINE,            0,
			  EZ_CLIENT_PTR_DATA,      entry,
			  EZ_CLIENT_INT_DATA,      1,
			  EZ_GRID_CELL_PLACEMENT,  EZ_FILL_BOTH, EZ_CENTER,
			  EZ_LABEL_POSITION,       EZ_LEFT,
			  NULL);
  if(status) EZ_DisableWidget(btn);
  else focus = btn;
  EZ_SetWidgetCallBack(btn,   doMountUmount, entry);

  sprintf(command, "%s %s", BIN_UMOUNT, mpt);
  entry = EZ_CreateWidget(EZ_WIDGET_ENTRY,         gbox,
			  EZ_SELECTION_BACKGROUND, SelectionBackground,
			  EZ_GRID_CELL_GEOMETRY,   0, 1 , 1, 1,
			  EZ_GRID_CELL_PLACEMENT,  EZ_FILL_HORIZONTALLY, EZ_CENTER,
			  EZ_BORDER_WIDTH,         1,
			  EZ_ENTRY_STRING,         command,
			  EZ_CLIENT_INT_DATA,      idx,
			  EZ_CLIENT_PTR_DATA,      toplevel,
			  NULL);
  EZ_EntryEditBeginningOfInput(entry);
  EZ_DisableWidget(entry);
		  
  sprintf(command, "Umount %s", name);
  btn   = EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, gbox,
			  EZ_GRID_CELL_GEOMETRY,   1, 1, 1, 1,
			  EZ_BORDER_WIDTH,         1,
			  EZ_PADX,                 6,
			  EZ_PADY,                 4,
			  EZ_LABEL_STRING,         command,
			  EZ_UNDERLINE,            0,
			  EZ_CLIENT_PTR_DATA,      entry,
			  EZ_CLIENT_INT_DATA,      0,
			  EZ_GRID_CELL_PLACEMENT,  EZ_FILL_BOTH, EZ_CENTER,
			  EZ_LABEL_POSITION,       EZ_LEFT,
			  NULL);
  if(!status) EZ_DisableWidget(btn);
  EZ_SetWidgetCallBack(btn,   doMountUmount, entry);

  /* open in a new folder */
  sprintf(command, "OpenDir %s", mpt);
  entry = EZ_CreateWidget(EZ_WIDGET_ENTRY,         gbox,
			  EZ_SELECTION_BACKGROUND, SelectionBackground,
			  EZ_GRID_CELL_GEOMETRY,   0, 2 , 1, 1,
			  EZ_GRID_CELL_PLACEMENT,  EZ_FILL_HORIZONTALLY, EZ_CENTER,
			  EZ_BORDER_WIDTH,         1,
			  EZ_ENTRY_STRING,         command,
			  EZ_CLIENT_INT_DATA,      idx,
			  EZ_CLIENT_PTR_DATA,      toplevel,
			  NULL);
  EZ_EntryEditBeginningOfInput(entry);
  EZ_DisableWidget(entry);
		  
  sprintf(command, "Open %s", name);
  btn   = EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, gbox,
			  EZ_GRID_CELL_GEOMETRY,   1, 2, 1, 1,
			  EZ_BORDER_WIDTH,         1,
			  EZ_PADX,                 6,
			  EZ_PADY,                 4,
			  EZ_LABEL_STRING,         command,
			  EZ_UNDERLINE,            0,
			  EZ_CLIENT_PTR_DATA,      entry,
			  EZ_GRID_CELL_PLACEMENT,  EZ_FILL_BOTH, EZ_CENTER,
			  EZ_LABEL_POSITION,       EZ_LEFT,
			  NULL);
  if(!status) EZ_DisableWidget(btn);
  else focus = btn;
  EZ_SetWidgetCallBack(btn,   openMountedDrive, entry);

  /*  a cancel button */
  {
    EZ_Widget *cancel  = EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, gbox,
					 EZ_GRID_CELL_GEOMETRY,   0, 3, 2, 1,
					 EZ_BORDER_WIDTH,         1,
					 EZ_PADX,                 6,
					 EZ_PADY,                 4,
					 EZ_SIZE,                 0, 0,
					 EZ_LABEL_STRING,         "Cancel",
					 EZ_UNDERLINE,            0,
					 EZ_GRID_CELL_PLACEMENT,  EZ_FILL_NONE, EZ_CENTER,
					 EZ_CALLBACK,             cancelCb, toplevel,
					 NULL);	    
  }
  
  if(focus != NULL)
    {
      EZ_DisplayWidgetUnderPointer(focus, -10, -10);
      /*EZ_SetGrab(toplevel);*/
      EZ_SetFocusTo(focus);
    }
  else EZ_DisplayWidget(toplevel);
}
/*************************************************************************************
 *
 *   Add an entry for a removable drive.
 *   
 */
void addRemovableDevice(buf)
     char *buf;
{
  char name[128], mpt[128], mxpm[128], uxpm[128];
  if(sscanf(buf, "%s %s %s %s", name, mpt, uxpm, mxpm) == 4)
    {
      if(ezfmIsInFstab(mpt,1))
	{
	  int plen, i = 0;
	  FileInfo *finfo;
	  
	  while(ezfmDrives[i].status >= 0 ) i++;
	  if(i >= 8) {fprintf(stderr,"Cannot handle more than 8 removable drives\n"); return;}
	  ezfmDrives[i].name = (char *)EZ_Malloc( (strlen(name)+1)*sizeof(char));
	  strcpy(ezfmDrives[i].name, name);
	  ezfmDrives[i].mntPt = (char *)EZ_Malloc( (strlen(mpt)+1)*sizeof(char));
	  strcpy(ezfmDrives[i].mntPt, mpt);
	  ezfmDrives[i].xpmlable[0] = (char *)EZ_Malloc( (strlen(uxpm)+1)*sizeof(char));
	  strcpy(ezfmDrives[i].xpmlable[0], uxpm);
	  ezfmDrives[i].xpmlable[1] = (char *)EZ_Malloc( (strlen(mxpm)+1)*sizeof(char));
	  strcpy(ezfmDrives[i].xpmlable[1], mxpm);
	  ezfmDrives[i].status = ezfmIsMounted(mpt, 1);
	  
	  ezfmDrives[i].finfo = finfo =  (FileInfo *)EZ_Malloc( sizeof(FileInfo));
	  memset(finfo, 0, sizeof(FileInfo));
	  finfo->pathname = ezfmDrives[i].mntPt;
	  finfo->type = NOTHING;
	  finfo->host = NULL;
	  finfo->obj = NULL;
	  finfo->ezfmData = NULL;
	}
      else fprintf(stderr, "Warning: %s is not in /etc/fstab\n", mpt);
    }
}
/********************************************************************************/
void updateDriveMenusAndButtons()
{
  Folder     *folder = NULL, *ptr = ezfmGetFolderList();
  
  while(ptr != NULL)
    {
      Toplevel  *tp = ptr->toplevel;
      EZ_Widget *frame = tp->toolbar;
      EZ_UnknownDataType   *ud;

      if(frame && (ud = EZ_GetWidgetUnknownDataPtr(frame)) != NULL)
	{
	  int i, status;
	  for(i = 0; i < 8; i++)
	    {
	      EZ_Widget *menu, *drive = (EZ_Widget *)ud[i].p;
	  
	      if(drive && (status = ezfmDrives[i].status) >= 0)
		{
		  EZ_ConfigureWidget(drive, EZ_PIXMAP_FILE, ezfmDrives[i].xpmlable[status], NULL);
		  menu = (EZ_Widget *)EZ_GetWidgetPtrData(drive);
		  updateDriveMenu(menu, (void *)i);
		}
	      else break;
	    }
	}
      ptr = ptr->next;
    }
  if(EZ_WidgetExist(ezfmToolBar))
    {
      EZ_Widget *frame = ezfmToolBar;
      EZ_UnknownDataType   *ud;
      
      if(frame && (ud = EZ_GetWidgetUnknownDataPtr(frame)) != NULL)
	{
	  int i, status;
	  for(i = 0; i < 8; i++)
	    {
	      EZ_Widget *menu, *drive = (EZ_Widget *)ud[i].p;
	  
	      if(drive && (status = ezfmDrives[i].status) >= 0)
		{
		  EZ_ConfigureWidget(drive, EZ_PIXMAP_FILE, ezfmDrives[i].xpmlable[status], NULL);
		  menu = (EZ_Widget *)EZ_GetWidgetPtrData(drive);
		  updateDriveMenu(menu, (void *)i);
		}
	      else break;
	    }
	}
    }
}

/*************************************************************************************/
#endif

#undef _DRIVES_C_


