// 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 <string.h>
#include <unistd.h>
#include <time.h>
#include <locale.h>
#include <malloc.h>
#include <stdlib.h>
#include <sys/stat.h>

#include <FL/fl_draw.H>

#include "getline2.hxx"

#include "mfmburn_ui.hxx"

#define MAXSIZE 1000

class_mfmburn *ptr_mfmburn;

char *line = NULL;
	
size_t dim_line = 0;

FILE *command_pipe;

int count;

bool err_flag = false;


/**************************************************************************
*
* Function: idle_function
*
* function to call during idle
*
****************************************************************************/

void idle_function(void *) {

  char *command;
	
  switch (ptr_mfmburn->selector) { 
  
    case 0:
  
// Burning disk 

      ptr_mfmburn->mfmburn_browser->add("Burning disk.");

      command_pipe = popen(ptr_mfmburn->burning_command, "r");
      			
			if (command_pipe == NULL) { 
			
			  ptr_mfmburn->error = -1;
          
        ptr_mfmburn->mfmburn_browser->add("Error during burning disk.");
        
        ptr_mfmburn->selector = -1;
        
      }                 
			
			else
			
        ptr_mfmburn->selector++;
        
      break;
          
    case 1:    

      if (getline2(&line, &dim_line, command_pipe) > 0) { 

        ptr_mfmburn->mfmburn_browser->add(line);
    		
        if (ptr_mfmburn->mfmburn_browser->size() > MAXSIZE)
		
          ptr_mfmburn->mfmburn_browser->remove(1);		
   		
		    ptr_mfmburn->mfmburn_browser->bottomline(ptr_mfmburn->mfmburn_browser->size());
   		
      }			
		
      else 
    			            
        ptr_mfmburn->selector++;
     
      break;        
			
    case 2:
    
  	  if (pclose(command_pipe) == -1) {
         
        ptr_mfmburn->error = -1;
              
        ptr_mfmburn->mfmburn_browser->add("Error during burning disk.");
            
        ptr_mfmburn->selector = -1;
           
      }                 
        
      else { 
         
        ptr_mfmburn->mfmburn_browser->add("Burning finished.");        
            
        ptr_mfmburn->selector++;
                    
      }
            
      break;			
    
    case 3: 
  
      if (ptr_mfmburn->mfmburn_verify->value() != 0)  {  
  
// Mount disk to verify written data   

  	    asprintf(&command, "mount %s 2>&1", ptr_mfmburn->BURNERMOUNTPOINT);	  
         
        if (system(command) == -1) {  
				
          ptr_mfmburn->error = -1;

          ptr_mfmburn->mfmburn_browser->add("Error during mounting disk.");
        
          ptr_mfmburn->selector = -1;
        
        }   
        
        else { 
        
          ptr_mfmburn->selector++;                      
          
          count = 0;			
					
					err_flag = false;							
          
          ptr_mfmburn->error = 0;
          
        }         
        
        free(command);

      } 
        
      else
      
        ptr_mfmburn->selector = 6;                  
        
      break;  
      
    case 4: 

// Verify written data   

      if (count < ptr_mfmburn->n_files) {

	      asprintf(&command, "diff -rq %s %s/%s 2>&1", ptr_mfmburn->str_files[count], ptr_mfmburn->BURNERMOUNTPOINT, ptr_mfmburn->str_files[count]);	  

        command_pipe = popen(command,"r");

        while (getline(&ptr_mfmburn->line, &ptr_mfmburn->dim_line, command_pipe)>0) { 

          ptr_mfmburn->mfmburn_browser->add(ptr_mfmburn->line);

          if (ptr_mfmburn->mfmburn_browser->size() > MAXSIZE)
            ptr_mfmburn->mfmburn_browser->remove(1);		

		      ptr_mfmburn->mfmburn_browser->bottomline(ptr_mfmburn->mfmburn_browser->size());

        }	
				
        if (pclose(command_pipe) != 0)
				
					err_flag = true;				  
        
        free(command);  												
      
        count++;	

      }    			
      
      else {
			
			  if (err_flag)
			
          ptr_mfmburn->mfmburn_browser->add("ERROR ! Bad written file(s) !");			
					
				else	
					
          ptr_mfmburn->mfmburn_browser->add("All written files are identical to originals.");								
        
        ptr_mfmburn->selector++;                                                                  
        
      }	                  

      break;  
      
    case 5: 
  
// Umount disk   

// Changed to sudo for Tiny Core:
	    asprintf(&command, "sudo umount %s 2>&1", ptr_mfmburn->BURNERMOUNTPOINT);	  
         
      if (system(command) == -1) {  
			
        ptr_mfmburn->error = -1;			

        ptr_mfmburn->mfmburn_browser->add("Error during unmounting disk.");
        
        ptr_mfmburn->selector = -1;
        
      }   
        
      else
        
        ptr_mfmburn->selector++;    
        
      free(command);                          
        
      break;  
      
    default:       

      unlink(ptr_mfmburn->list_file);  

      free(ptr_mfmburn->list_file);  

      ptr_mfmburn->mfmburn_burn->activate();  
      ptr_mfmburn->mfmburn_refresh->activate();
      ptr_mfmburn->mfmburn_exit->activate();  
      ptr_mfmburn->mfmburn_cd->activate();  
      ptr_mfmburn->mfmburn_dvd->activate();         
      ptr_mfmburn->mfmburn_erase->activate(); 
      ptr_mfmburn->mfmburn_verify->activate(); 
      ptr_mfmburn->mfmburn->redraw();
    
  		Fl::remove_idle(idle_function);	

      break;
      
  }   
      
} // idle_function


/**************************************************************************
* Metodi di class_mfmburn
****************************************************************************/

/**************************************************************************
* Constructor
****************************************************************************/

class_mfmburn::class_mfmburn(int argc, char **argv) : class_mfmburn_fluid() {

  char *string;
  
  struct stat stat_buffer;      

  n_files = argc - 1;
  
  str_files = argv + 1;
  
  for (int i=0; i<n_files; i++){
  
    stat(str_files[i], &stat_buffer);
      
    if (S_ISDIR(stat_buffer.st_mode) != 0) { 

      int len = strlen(str_files[i])-1;
      
      if (str_files[i][len] != '/') {
      
        asprintf(&string, "%s/", str_files[i]);
        
        str_files[i] = string;

      }        

    } 
     
  }    
  
  mfmburn_loadcfg();

  mfmburn_refresh_callback();
  
	ptr_mfmburn = this;
  
  dim_line = 0;
  
  line = NULL;
  
  mfmburn->show();

} // class_mfmburn


/**************************************************************************
*
* function: mfmburn_loadcfg
*
* Load configuration
*
****************************************************************************/

void class_mfmburn::mfmburn_loadcfg() {

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

  size_t dim = 0;
  
  size_t start;
 
  BURNERDEV = (char *) malloc(1);

  BURNERDEV[0] = 0;  
  
  BURNERMOUNTPOINT = (char *) malloc(1);

  BURNERMOUNTPOINT[0] = 0;   
  

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

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

      sscanf(stringa, "%20s", command);
        
      if (strcmp(command, "burner_dev") == 0) {

        free(BURNERDEV);

        for (start=strlen(command) + 1; start<strlen(stringa); start++)

          if (stringa[start] != ' ') break;

        for (size_t i=start+1; i<=strlen(stringa); i++)

          if (stringa[i] <= (char) 32) {

            stringa[i] = (char) 0;

            break;

          }

        asprintf(&BURNERDEV, "%s", stringa + strlen(command) + 1);

      }

      else if (strcmp(command, "burner_mount") == 0) {

        free(BURNERMOUNTPOINT);

        for (start=strlen(command) + 1; start<strlen(stringa); start++)

          if (stringa[start] != ' ') break;

        for (size_t i=start+1; i<=strlen(stringa); i++)

          if (stringa[i] <= (char) 32) {

            stringa[i] = (char) 0;

            break;

          }

        asprintf(&BURNERMOUNTPOINT, "%s", stringa + strlen(command) + 1);

      }        
        
    }

    fclose(stream);

    if (stringa != NULL) {
    
      free(stringa);
      
      dim = 0;
      
      stringa = NULL;
      
    }

  }

} // mfmburn_loadcfg


/**************************************************************************
* Callbacks
**************************************************************************/

void class_mfmburn::mfmburn_burn_callback() {

  char *command = NULL;
  
  int len;
       
  FILE *stream;     
  
  error = 0;     
  
  mfmburn_burn->deactivate();  
  mfmburn_refresh->deactivate();
  mfmburn_exit->deactivate();  
  mfmburn_cd->deactivate();  
  mfmburn_dvd->deactivate();         
  mfmburn_erase->deactivate(); 
  mfmburn_verify->deactivate(); 
  mfmburn_browser->clear();       
  mfmburn->redraw();
  
  asprintf(&list_file, "%s/.mfm/mfmburn.lst", getenv("HOME"));
   
  if ((stream = fopen (list_file,"w")) != NULL) {

    for (int i=0; i<n_files; i++) {
    
      len = strlen(str_files[i])-1;
           
      if (str_files[i][len] == '/') { 
      
        int j;
        
        for (j = len-1; j>=0; j--)
        
          if (str_files[i][j] == '/'){ 
          
            j++;
          
            break;    
            
          } 
          
        if (j<0) 
        
          j=0;  
          
        asprintf(&command, "%s%s", str_files[i]+j, str_files[i]);
        
        command[len+j] = '=';

        fprintf(stream, "%s\n", command);
        
        free(command);
        
      } 
      
      else

        fprintf(stream, "%s\n", str_files[i]);
      
    }  
 
    fclose(stream);  
       
  }
  
  else {
  
    mfmburn_browser->add("List file writing error");
  
    error = -1;  
    
  }
	
// Unmount disk, if mounted

// Changed to sudo for Tiny Core:
  asprintf(&command, "sudo umount %s 2>&1", BURNERMOUNTPOINT);	  
	
	system(command);

  free(command);

  if (error == 0) {

// Prepare CD burning    
 
    if (mfmburn_cd->value() != 0) {

      if (mfmburn_erase->value() == 0) {
    
        asprintf(&burning_command, "cdrecord -msinfo dev=%s 2>&1", BURNERDEV);

        command_pipe = popen(burning_command,"r");

        while (getline(&line, &dim_line, command_pipe) > 0);
				
				for (size_t i=0; i<strlen(line); i++)
				
				  if (line[i] == '\n') {
					
					  line[i] = 0;
						
						break;
					
					}
								        
        error = pclose(command_pipe);
        
        free(burning_command);
        
        burning_command = NULL;
			               
        if  (error > 0)
				
				  error = 0;
                
        if (error == 0) {
        
          if (strncmp(line, "cdrecord: Cannot", 16) != 0)        
        
            asprintf(&burning_command, "mkisofs -C %s -M %s -r -J -U -v -graft-points -path-list %s | cdrecord -v -multi fs=16m dev=%s - 2>&1", line, BURNERDEV, list_file, BURNERDEV);
            
          else  
          
            asprintf(&burning_command, "mkisofs -r -J -U -v -graft-points -path-list %s | cdrecord -v -multi fs=16m dev=%s - 2>&1", list_file, BURNERDEV);          

        }            
          
        free(line);  
        
        dim_line = 0;
  
        line = NULL;        
			      
      }
		
      if (mfmburn_erase->value() != 0)
							
        asprintf(&burning_command, "mkisofs -r -J -U -v -graft-points -path-list %s | cdrecord blank=fast -v -multi fs=16m driveropts=burnfree dev=%s - 2>&1", list_file, BURNERDEV);

      }

    }

// Prepare DVD Burning    
          
    else if (mfmburn_dvd->value() != 0) { 
    
      if (mfmburn_erase->value() != 0)
		
        asprintf(&burning_command, "growisofs -use-the-force-luke -Z %s -r -J -U -v -graft-points -path-list %s 2>&1", BURNERDEV, list_file);
				      
      else
		
        asprintf(&burning_command, "growisofs -M %s -r -J -U -v -graft-points -path-list %s 2>&1", BURNERDEV, list_file);				  
    
    }      

// Unknown/unspecified media
        
    else {
  
      mfmburn_browser->add("Media not specified");
  
      error = -1;  
    
    }     
    
  if (error == 0) {
     
    selector = 0;
    
    Fl::add_idle(idle_function);    
    
  }    
  
} // mfmburn_burn_callback


void class_mfmburn::mfmburn_refresh_callback() {

  char *command = NULL,
       *line = NULL; 
       
  size_t dim_line = 0;
  
  int flag;
       
  FILE *pipe;     

  mfmburn_browser->clear();

  for (int i=0; i<n_files; i++)
  
    mfmburn_browser->add(str_files[i]);    
    
  asprintf(&command, "dvd+rw-mediainfo %s 2>&1", BURNERDEV);
   
  pipe = popen(command,"r");
  
  getline(&line, &dim_line, pipe);
  getline(&line, &dim_line, pipe);
  
  flag = getline(&line, &dim_line, pipe);
        
  // DVD detected    
  
  if (pclose(pipe) == 0 && flag > 0 && strncmp(line," Mounted Media", 14) == 0){
   
    mfmburn_cd->clear();
    mfmburn_dvd->set();
          
  }     
      
  else {

    free(command);

    asprintf(&command, "cdrecord -toc dev=%s 2>&1", BURNERDEV);

    pipe = popen(command,"r");

    while (getline(&line, &dim_line, pipe)>0);		

// CD detected    

    if (pclose(pipe) == 0 && strncmp(line,"cdrecord: No disk", 17) != 0){

      mfmburn_cd->set();
      mfmburn_dvd->clear();
      
    }       

  }       

  free(command);
  free(line);
  
  mfmburn->redraw();
        
} // mfmburn_refresh_callback


void class_mfmburn::mfmburn_exit_callback() {

  delete this->mfmburn;
  delete this;

} // mfmburn_exit_callback

void class_mfmburn::mfmburn_help_callback() {

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

} // mfmburn_help_callback
