// My File Manager (MFM).
//
// Copyright 2005-2006 by Stefano Gatti.
//
// This program 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
// of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
//=====================================================================

#include <locale.h>
#include <stdio.h>
#include <sys/stat.h>
#include <FL/fl_draw.H>

#include "mfmmount_ui.hxx"

#define TIMEOUT_RELOAD 5

class_mfmmount *ptr_mfmmount;


/**************************************************************************
*
* Function: idle_function
*
* function to call every TIMEOUT_RELOAD seconds during idle
*  - refresh mount list
*
****************************************************************************/

void idle_function (void *) {

  static time_t time = 0;   
  
  struct stat stat_buffer;

  stat("/etc/mtab", &stat_buffer);
  
  if (time == 0)
  
    time = stat_buffer.st_mtime;
    
  else if (stat_buffer.st_mtime > time) {
   
    ptr_mfmmount->find_mounted();

    time = stat_buffer.st_mtime;
    
  }
  
  Fl::repeat_timeout(TIMEOUT_RELOAD, idle_function);

}


/**************************************************************************
* Metodi di class_mount_table
****************************************************************************/

/**************************************************************************
* Costruttore
****************************************************************************/

class_mount_table::class_mount_table(int x, int y, int w, int h) : class_table(x, y, w, h, NULL) {


}


/**************************************************************************
*
* double_click_cb
*
* Double click callback
*
****************************************************************************/

void class_mount_table::double_click_cb(int row) {

  select_row(row);

  if (strcmp(cell_label(2, row), "Unmounted") == 0)    

    ((class_mfmmount *)class_mfm_mount_ptr)->mfmmount_temp_callback();
  
  else
  
    ((class_mfmmount *)class_mfm_mount_ptr)->mfmmount_open_callback(); 

} // double_click_cb


/**************************************************************************
*
* button_3_cb
*
* Click on button 3 callback
*
****************************************************************************/

void class_mount_table::button_3_cb(int row) {

  select_row(row);

  if (strcmp(cell_label(2, row), "Unmounted") == 0)    

    ((class_mfmmount *)class_mfm_mount_ptr)->mfmmount_mount_callback();
  
  else
  
    ((class_mfmmount *)class_mfm_mount_ptr)->mfmmount_umount_callback();      
     
} // button_3_cb


/**************************************************************************
* Metodi di class_mfmmount
****************************************************************************/

/**************************************************************************
* Costruttore
****************************************************************************/

class_mfmmount::class_mfmmount() : class_mfmmount_fluid() {

  char *line = NULL;
  
  size_t dim_line = 0;
  
  int i, flag;

  int nr = 0;
  int start_dev = 0;
  int start_mount_point = 0;
  
  Fl_Group::current((Fl_Group *) mfmmount_table_group); 
  
  mfmmount_table = new class_mount_table(mfmmount_table_group->x(), mfmmount_table_group->y(), mfmmount_table_group->w(), mfmmount_table_group->h());  
  
  mfmmount_table->class_mfm_mount_ptr = this;

  FILE *stream;

// Load configuration

  mfmmount_loadcfg();  

// Ricerca delle partizioni esistenti in fstab

  for (int cycle=0; cycle<2; cycle++) {

    if ((stream = fopen ("/etc/fstab","r"))!=NULL) {
    
      nr = 0;

      while (getline(&line, &dim_line, stream)>0) {
    
        if (strncmp(line, "/dev/", 5) == 0) {

// Find start of device

          for (i = 0, flag = 0; flag == 0; i++) {
        
            if (line[i] == 0) {

              flag = 11;

            }
        
            else if (line[i] == '#')
          
              flag = 10;

            else if (line[i] != ' ') {

              start_dev = i;
            
              flag = 1;
            
            }
          
          }
          
// Find end of device
          
          if (flag < 2) {

            for (i = start_dev, flag = 0; flag == 0; i++) {
          
              if (line[i] == 0) {

                flag = 12;

              }

              else if (line[i] == ' ') {

                line[i] = 0;

                start_mount_point = i + 1;
            
                flag = 1;

              }
            
            }
            
          }

// Find start of mount point

          if (flag < 2) {
        
            for (i = start_mount_point, flag = 0; flag == 0; i++) {

              if (line[i] == 0) {

                flag = 13;

              }

              else if (line[i] != ' ') {

                start_mount_point = i;

                flag = 1;
              
              }
            
            }
            
          }
          
// Find end of mount point

          if (flag < 2) {
        
            if (line[start_mount_point] == '/') {

              for (i = start_mount_point, flag = 0; flag == 0; i++) {
          
                if (line[i] == 0) {

                  flag = 1;

                }

                else if (line[i] == ' ') {

                  line[i] = 0;

                  flag = 1;

                }
            
              }
            
            }
            
            else
            
              flag = 20;
              
          }

          if (flag < 2) {

            if (cycle==1) {
            
              mfmmount_table->cell_label(0, nr, line+start_dev);
              mfmmount_table->cell_label(1, nr, line+start_mount_point);
              
            }
            
            nr++;

	        }

        }

      }
      
      fclose(stream);

    }

    if (cycle==0) {

      mfmmount_table->create_header(3, false);

      mfmmount_table->create_table(nr, true);

    }

  }

  mfmmount_table->row_select_mode(SELECT_MODE_SINGLE);

  mfmmount_table->header_label(0, "Device");
  mfmmount_table->header_label(1, "Mount point");
  mfmmount_table->header_label(2, "Free");

  mfmmount_table->col_width(0, 100);
  mfmmount_table->col_width(1, mfmmount_table_group->w() - 198);
  mfmmount_table->col_width(2, 80);

  if (line != NULL) 
  
    free(line);  

  find_mounted();
  
  mfmmount->show();  

  ptr_mfmmount = this;

  Fl::add_timeout(0, idle_function);
  
} // class_mfmmount::class_mfmmount


/**************************************************************************
*
* function: mfmmount_loadcfg
*
* Load configuration
*
****************************************************************************/

void class_mfmmount::mfmmount_loadcfg() {

  FILE *stream;
  
  char *cfg_file,
       *stringa = NULL,
       command[21];

  size_t dim;

  Fl_Color color = FL_BLACK;

// Changed default mounted to green:
//mounted_color = FL_BLACK;
  mounted_color = FL_DARK_GREEN;

// Changed default unmounted to red:
//unmounted_color = FL_BLACK;
  unmounted_color = FL_RED;


  asprintf(&cfg_file, "%s/.mfm/mfm.cfg", getenv("HOME"));
   
  if ((stream = fopen (cfg_file,"r"))!=NULL) {
	
    int int_col;

    while (getline(&stringa, &dim, stream)>0) {

      sscanf(stringa, "%20s %i", command, &int_col);
			
 			color = (Fl_Color) int_col;			

      if (strcmp(command, "mounted") == 0)

        mounted_color = color;


      else if (strcmp(command, "unmounted") == 0)

        unmounted_color = color;
  
    }

    fclose(stream);

    if (stringa != NULL) 
    
      free(stringa);

  }

} // class_mfmmount::mfmmount_loadcfg


/**************************************************************************
*
* function: find_mounted
*
* Find mounted partitions in /etc/mtab 
*
****************************************************************************/

void class_mfmmount::find_mounted() {

  char *line = NULL;
  
  size_t dim_line = 0;
  
  int i, j, flag;

  int start_dev = 0;

  FILE *stream;
  
  struct stat buf_fstab, buf_mtab;

  for (j = 0; j < mfmmount_table->get_rows(); j++) {
          
    mfmmount_table->cell_label(2, j, "Unmounted");

    mfmmount_table->set_row_color(j, unmounted_color);	  
	    
  }    

// Ricerca delle partizioni montate in mtab

  if ((stream = fopen ("/etc/mtab","r"))!=NULL) {
  
    while (getline(&line, &dim_line, stream)>0) {

      if (strncmp(line, "/dev/", 5) == 0) {

// Find start of device

        for (i = 0, flag = 0; flag == 0; i++) {

          if (line[i] == 0) {

            flag = 11;

          }

          else if (line[i] == '#')

            flag = 10;

          else if (line[i] != ' ') {

            start_dev = i;

            flag = 1;

          }

        }

// Find end of device

        if (flag < 2) {

          for (i = start_dev, flag = 0; flag == 0; i++) {

            if (line[i] == 0) {

              flag = 1;

            }

            else if (line[i] == ' ') {

              line[i] = 0;

              flag = 1;

            }

          }

        }
        
        for (j = 0; j < mfmmount_table->get_rows(); j++)
	    	  
// Check if the file in /etc/fstab and the file in /etc/mtab are the same. 
// The file in /etc/fstab could be a link and the filename could be different

          if (stat(mfmmount_table->cell_label(0, j), &buf_fstab) == 0)
					
					  if (stat(line, &buf_mtab) == 0)

              if (buf_fstab.st_ino == buf_mtab.st_ino) {

                mfmmount_table->cell_label(2, j, "Mounted");
            
                mfmmount_table->set_row_color(j, mounted_color);	 
								
// If possible write free space in partition
								
                FILE *stream;
               
		char *line = NULL,
                *command;

                size_t dim_line;

                asprintf(&command, "df %s", mfmmount_table->cell_label(1, j));

                if ((stream = popen(command,"r")) > 0) { 
																									
                  getline(&line, &dim_line, stream);

                  if (getline(&line, &dim_line, stream)>0) { 
                  
                    long long int free_space;
                    
                    char *label;
       
                    sscanf(line+40, "%lli", &free_space);      
                   
                    if (free_space < 10240)
                  
                      asprintf(&label, "%lli KB", free_space);
                      
                    else if (free_space < 10485760)  
                    
                      asprintf(&label, "%lli MB", free_space/1024);
                                            
                    else 
                    
                      asprintf(&label, "%lli GB", free_space/1048576);
                                                                  
                    mfmmount_table->cell_label(2, j, label);
                    
                    free(label);
                  
                  }
								
                  if (line != NULL) 
                  
                    free(line);                
									
	            pclose(stream);
									   
                }
                
                free(command);
	      
              } 
	  
      }

    }

    fclose(stream);
    
  }


  mfmmount->redraw();  

    if (line != NULL)
  
    free(line);

} // class_mfmmount::class_mfmmount


/**************************************************************************
* Callback dei widget dell'interfaccia
****************************************************************************/

void class_mfmmount::mfmmount_mount_callback() {

  if (mfmmount_table->row_selected()>=0 && strcmp(mfmmount_table->cell_label(2, mfmmount_table->row_selected()), "Unmounted") == 0) {
	
    char *exec;	
				
    asprintf(&exec, "mfmexec 'Mount partitions' '.' 'mount %s 2>&1'", mfmmount_table->cell_label(0, mfmmount_table->row_selected()));
 
    system(exec);

    free(exec); 

    find_mounted();
    
  }

} // class_mfmmount::mfmmount_mount_callback


void class_mfmmount::mfmmount_open_callback() {

  if (mfmmount_table->row_selected()>=0 && strcmp(mfmmount_table->cell_label(2, mfmmount_table->row_selected()), "Unmounted") == 0) {

// Added 4 lines below so partiton mounted status updates in MFMR Mount GUI when Open button utilized:
    char *exec;					
    asprintf(&exec, "mfmexec 'Mount partitions' '.' 'mount %s 2>&1'", mfmmount_table->cell_label(0, mfmmount_table->row_selected())); 
    system(exec);
    free(exec);

    char *command;

//  Changed for new mfmr executable:
//  asprintf(&command, "mfm -m=%s &", mfmmount_table->cell_label(1, mfmmount_table->row_selected()));
     asprintf(&command, "mfmr -m=%s &", mfmmount_table->cell_label(1, mfmmount_table->row_selected()));

    system(command);
  
    free(command);

    find_mounted();

  } 

  else if (mfmmount_table->row_selected()>=0 && strcmp(mfmmount_table->cell_label(2, mfmmount_table->row_selected()), "Unmounted") != 0) {
  
    char *command;

    asprintf(&command, "mfmr -m=%s &", mfmmount_table->cell_label(1, mfmmount_table->row_selected()));

    system(command);
  
    free(command);

    find_mounted();

  }    
 
} // class_mfmmount::mfmmount_open_callback


void class_mfmmount::mfmmount_temp_callback() {

  if (mfmmount_table->row_selected()>=0 && strcmp(mfmmount_table->cell_label(2, mfmmount_table->row_selected()), "Unmounted") == 0) {

// Added 4 lines below so partiton mounted status updates in MFMR Mount GUI when Open button utilized:
    char *exec;					
    asprintf(&exec, "mfmexec 'Mount partitions' '.' 'mount %s 2>&1'", mfmmount_table->cell_label(0, mfmmount_table->row_selected())); 
    system(exec);
    free(exec);

    char *command;

//  Changed for new mfmr executable
//  asprintf(&command, "mfm -t=%s &", mfmmount_table->cell_label(1, mfmmount_table->row_selected()));
     asprintf(&command, "mfmr -t=%s &", mfmmount_table->cell_label(1, mfmmount_table->row_selected()));

    system(command);
  
    free(command);

    find_mounted();

  } 

  else if (mfmmount_table->row_selected()>=0 && strcmp(mfmmount_table->cell_label(2, mfmmount_table->row_selected()), "Unmounted") != 0) {
  
    char *command;

    asprintf(&command, "mfmr -t=%s &", mfmmount_table->cell_label(1, mfmmount_table->row_selected()));

    system(command);
  
    free(command);

    find_mounted();

  }    
 
} // class_mfmmount::mfmmount_temp_callback


void class_mfmmount::mfmmount_umount_callback() {

  char *exec;

  if (mfmmount_table->row_selected()>=0 && strcmp(mfmmount_table->cell_label(2, mfmmount_table->row_selected()), "Unmounted") != 0) {

// TC requires sudo for umount but not for mount:
//  asprintf(&exec, "mfmexec 'Umount partitions' '.' 'umount %s 2>&1'", mfmmount_table->cell_label(0, mfmmount_table->row_selected())); 
    asprintf(&exec, "mfmexec 'Umount partitions' '.' 'sudo umount %s 2>&1'", mfmmount_table->cell_label(0, mfmmount_table->row_selected())); 

    system(exec);

    free(exec);    

    find_mounted();

  }

} // class_mfmmount::mfmmount_umount_callback


// Added refresh:
void class_mfmmount::mfmmount_refresh_callback() {

    find_mounted();

} // class_mfmmount::mfmmount_refresh_callback


void class_mfmmount::mfmmount_exit_callback() {

	Fl::remove_idle(idle_function);

  delete this->mfmmount;
  delete this;

} // class_mfmmount::mfmmount_exit_callback


void class_mfmmount::mfmmount_help_callback() {

  system("mfmhelp /usr/local/share/doc/mfm.html#menu_mount &");

} // class_mfmmount::mfmmount_help_callback
