Logo Search packages:      
Sourcecode: xcdroast version File versions  Download package

io.c

/*
      io.c
      All the functions that interact with hardware and subprocesses
      and file IO. 
      28.3.99 tn
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "largefile.h"
#include "gettext.h"

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#if defined(linux) || defined(__FreeBSD__)
# include <sys/soundcard.h>
# include <sys/ioctl.h>
#endif
#if defined(sun) || defined(__OpenBSD__)
# include <sys/ioctl.h>
# include <sys/audioio.h>
#endif
#ifdef aix
#include <sys/audio.h>
#endif
#ifdef hpux 
# ifndef hpux_alib
#  include <sys/audio.h>
# endif
#endif
#if defined(__sgi)
#include <dmedia/audio.h>
#endif

#if ENABLE_NLS
# define _(String) gettext (String)
# define N_(String) gettext_noop (String)
#else
# define _(String) (String)
# define N_(String) (String)
#endif
#define GTK_ENABLE_BROKEN

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib.h>
#include "xcdrdata.h"
#include "xcdroast.h"
#include "main.h"

writerreader_devices_t **writerreaderdevs;
gchar **alt_scsidevices;
cd_info_t cdinfo;
track_info_t **trackinfo;
writer_driver_t **drivers;
writer_driver_t **blankmodes;
write_track_param_t writeparams;
gchar xcdroast_version_loaded[MAXLINE];
gint read_done;
gint read_abort_mark;

static gint scsicount;
static gint busnr;
static gint tocstate;
static gint tocnr;
static gint drvcount;
static gint dfrun;
static gint readcdda_callback;
static gint readcdda_callback2;
static gint readcdda_callback3;
static gint read_output_ctrl;
static gint read_tracknr;
static gchar readtrack_info_string[1024];
static gfloat pct_so_far, pct_this_track;
static pid_t mkisofs_pid;
static pid_t readcdda_pid, readcdda_pid2;
static gint readcd_startsector, readcd_endsector;
static gint readerr_count;
static gint matchnr;
static gint cddb_in;
static gchar cdinfo_cddb_title_bak[MAXLINE];
static gint cd_is_still_the_same;
static gint cdrecord_stdin, cdrecord_reload;
static gint delete_count, delete_start, delete_all;
static gint msinfo_nr1, msinfo_nr2;
static gint cdrtimer, count_mmaperror, checkmedium_found;
static time_t cdrcmdtimer;
static GtkWidget *getcdtoc_atapi_timeout_dialog;

extern gint debug;
extern gint dialog_done2, dialog_done, dialog_done3;
extern setup_data_t setupdata;
extern track_read_set_t trackreadset;
extern current_set_t curset;
extern gchar *system_platform;
extern GtkWidget *toplevel;
extern GtkWidget *viewmode_dialog; 
extern GtkWidget *readtrack_info_label, *readtrack_textview;
extern GtkWidget *readtrack_pbar1, *readtrack_pbar2, *readtrack_pbar3;
extern GtkWidget *readtrack_pbar4, *readtrack_spd;
extern GtkWidget *readtrack_small_info, *readtrack_small_info2;
extern gchar hostname[MAXLINE];
extern gchar username[MAXLINE];
extern gchar sharedir[MAXLINE];
extern gchar configdir[MAXLINE];
extern gchar prefixdir[MAXLINE];
extern GtkWidget *cddb_info_label;
extern GtkCList *cddb_clist;
extern master_param_t masterparam;
extern gchar **charset_types;
extern gchar *master_fname1;
extern gchar *master_fname2;
extern GdkFont *fixedfont;
extern gint support_ontheflyaudio;

static void verify_readcd_err(gpointer pid, gint source, GdkInputCondition cond);
static void read_write_out(gpointer data, gint source, GdkInputCondition cond); 
static gint getdevicecap(gchar *dev, gint *readmax, gint *cdrmax, gint *dvdmax, gint *iscdr, gint *isdvdrom, gint *isdvdr);
static gint check_medium_loaded(gint devnr);
static gint get_cdrecord_toc(gint devnr);
static void remove_tmp_writetracks_tocfile(gchar *tocfile);
static void edit_xinf_for_cd_text2(gchar *infname, gchar *title, gchar *artist, gchar *cdtitle, gchar *cdartist);
static pid_t full_dpl_pipe3(gint *out, gint *in, gint *err, gchar *cmd, 
      gint use_socketpair);


/* convert device-type-names back to numeric */
/* -1 means unknown */

static gint get_scsi_type(gchar *type) {

      if (strcmp(type,"Disk") == 0) {
            return 0;
      }
      if (strcmp(type,"Tape") == 0) {
            return 1;
      }
      if (strcmp(type,"Printer") == 0) {
            return 2;
      }
      if (strcmp(type,"Processor") == 0) {
            return 3;
      }
      if (strcmp(type,"WORM") == 0) {
            return 4;
      }
      if (strcmp(type,"CD-ROM") == 0) {
            return 5;
      }
      if (strcmp(type,"Scanner") == 0) {
            return 6;
      }
      if (strcmp(type,"Optical Storage") == 0) {
            return 7;
      }
      if (strcmp(type,"Juke Box") == 0) {
            return 8;
      }
      if (strcmp(type,"Communication") == 0) {
            return 9;
      }

      return -1;
}


/* convert the scsi-type-number back to string */

#if 0
static void get_scsi_type_string(gchar *str, gint type,  gint removeable) {

      switch(type) {
      case 0:
            if (removeable == 0) {
                  strcpy(str,_("Disk"));
            } else {
                  strcpy(str,_("Removable Disk"));
            }
            break;
      case 1:
            strcpy(str,_("Tape"));
            break;
      case 2:
            strcpy(str,_("Printer"));
            break;
      case 3:
            strcpy(str,_("Processor/Scanner"));
            break;
      case 4:
            strcpy(str,_("WORM"));
            break;
      case 5:
            strcpy(str,_("CD-ROM"));
            break;
      case 6:
            strcpy(str,_("Scanner"));
            break;
      case 7:
            strcpy(str,_("Optical Storage"));
            break;
      case 8:
            strcpy(str,_("Juke Box"));
            break;
      case 9:
            strcpy(str,_("Communication"));
            break;
      default:
            strcpy(str,"");
            break;
      }
}
#endif


static gint get_cur_audioread_speed() {
gint i;
      i = get_writerreaderdevs_index(curset.reader_devnr);
      return (writerreaderdevs[i]->audioread_speed);
}

static gint get_cur_audioread_overlap() {
gint i;
      i = get_writerreaderdevs_index(curset.reader_devnr);
      return (writerreaderdevs[i]->audioread_overlap);
}

static gint get_cur_audioread_sectorburst() {
gint i;
      i = get_writerreaderdevs_index(curset.reader_devnr);
      return (writerreaderdevs[i]->audioread_sectorburst);
}

static gint get_cur_audioread_useparanoia() {
gint i;
      i = get_writerreaderdevs_index(curset.reader_devnr);
      return (writerreaderdevs[i]->audioread_useparanoia);
}

static gint get_cur_audioread_paranoiaretries() {
gint i;
      i = get_writerreaderdevs_index(curset.reader_devnr);
      return (writerreaderdevs[i]->audioread_paranoiaretries);
}

static gint get_cur_writer_speed() {
gint i;
      i = get_writerreaderdevs_index(curset.writer_devnr);
      return (writerreaderdevs[i]->writer_speed);
}

static gint get_cur_writer_fifo() {
gint i;
      i = get_writerreaderdevs_index(curset.writer_devnr);
      return (writerreaderdevs[i]->writer_fifo);
}

static gint get_cur_writemode() {
gint i;
      i = get_writerreaderdevs_index(curset.writer_devnr);
      return (writerreaderdevs[i]->writer_mode);
}

static gint get_cur_writer_drvmode() {
gint i;
      i = get_writerreaderdevs_index(curset.writer_devnr);
      return (writerreaderdevs[i]->writer_drvmode);
}

 
/* look in given string for "' '" and return index to it */
/* return -1 if not found */

static gint look_for_scan_delimitor(gchar *str) {
gint i;

      for(i = 0; i < strlen(str)-2; i++) {

            if (str[i] == '\'' && str[i+1] == ' ' && str[i+2] == '\'') {
                  return i;
            }
      }
      return -1;
}


/* look in given string for "' " and return index to it */
/* return -1 if not found */

static gint look_for_scan_delimitor2(gchar *str) {
gint i;

      for(i = 0; i < strlen(str)-1; i++) {

            if (str[i] == '\'' && str[i+1] == ' ') {
                  return i;
            }
      }
      return -1;
}


/* interpret output of -scanbus and sort into memory structure */
/* if idx != -1 then we run in manual-device-mode */

static void parse_scan(gchar *line, gint idx, gint transport, scsi_devices_t **scsidevices) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p1, *p2;
gint s_id;
gchar s_vendor[9];
gchar s_model[17];
gchar s_rev[5];
gint s_removable;
gint s_type;
gint next;

      /* skip header */
      if (strncmp(line,"Cdrecord",8) == 0) {
            return;
      }
#if 0
      if (strncmp(line,"devname",7) == 0 ) {
            /* set current scsibus nr */
            strcpy(tmp,line+7);
            p1=strtok(tmp,":");
            /* now tmp2 contains the current busnr as string */
            devname = strdup(p1);
            return;
      }
#endif
       if (strncmp(line,"scsibus",7) == 0 ) {
                /* set current scsibus nr */
                strcpy(tmp,line+7);
                p1=strtok(tmp,":");
                strcpy(tmp2,p1);
                /* now tmp2 contains the current busnr as string */
                busnr = atoi(tmp2);
                return;
        }


      /* a line with an error message? */
      /* get_spawn_path(CDRECORD,tmp); */
      strcpy(tmp,"cdrecord: ");
      if (strncmp(line, tmp, strlen(tmp)) == 0) {
            return;
      }

      /* a line with device-info found (by checking for ")")*/
      p1 = index(line,')');
      if (p1 != NULL && !strstr(line,")\"") && 
         (strstr(line,"\t") || line[0] == ' ')) {
            strip_string(line); 

            /* get scsi-id */
            p1=strtok(line,")");
            if (!p1) return;

            strcpy(tmp,p1);
            strcpy(tmp2,p1);
            /* look for last tab or last space in tmp and remove 
               everything before */
            p1=rindex(tmp2,'\t');
            p2=rindex(tmp2,' ');
            if (p1 > p2) {
                  /* last interesting char was a tab - cut here */
                  if (p1 != NULL) {
                        strcpy(tmp,p1+1);
                  }     
            } else {
                  /* last interesting char was a space - cut here */
                  if (p2 != NULL) {
                        strcpy(tmp,p2+1);
                  }     
            }
            s_id = atoi(tmp); 
      
            /* strip host-id from scsi-id-number */
            s_id = s_id % 100;

            p1=strtok(NULL,"'");
            if (p1 == NULL) {
                  g_warning("cdrecord scanbus error: Try to remove all media from your CD-ROM drives before starting X-CD-Roast.\n");
                  return;
            }

            strcpy(tmp,p1);
            strip_string(tmp);

            if (*tmp == '*') {
                  /* no device found */
                  return;
            }

            if (*tmp == 'H') {
                  /* HOST ADAPTER found */
                  /* treat as no device for now */
                  return;
            }

            /* get full rest of line */
            p1=strtok(NULL,"");
            if (!p1) return;
            strcpy(tmp,p1);

            if (*tmp == '\'') {
                  /* empty device found? ignore */
                  return;
            }

            /* e.g. tmp=YAMAHA  ' 'CRW8424S        ' '1.0j' */ 
            /* get vendor */
            next = look_for_scan_delimitor(tmp);
            if (next < 0) {
                  g_error("cdrecord -scanbus output syntax error\n");
            }

            strcpy(s_vendor,"        ");
            if (next <= 8) {
                  strncpy(s_vendor,tmp,next);
            } else {
                  /* strip if to long */
                  strncpy(s_vendor,tmp,8);
            }     
            s_vendor[8] = '\0';

            /* get model */
            strcpy(tmp2,tmp+next+3);
            strcpy(tmp,tmp2);
            next = look_for_scan_delimitor(tmp);
            if (next < 0) {
                  g_error("cdrecord -scanbus output syntax error\n");
            }
            strcpy(s_model,"                ");
            if (next <= 16) {
                  strncpy(s_model,tmp,next);
            } else {
                  strncpy(s_model,tmp,16);
            }
            s_model[16] = '\0';

            /* get revision */
            strcpy(tmp2,tmp+next+3);
            strcpy(tmp,tmp2);
            next = look_for_scan_delimitor2(tmp);
            if (next < 0) {
                  g_error("cdrecord -scanbus output syntax error\n");
            }
            strcpy(s_rev,"    ");
            if (next <= 4) {
                  strncpy(s_rev,tmp,next);
            } else {
                  strncpy(s_rev,tmp,4);
            }
            s_rev[4] = '\0';

            /* get type */
            strcpy(tmp2,tmp+next+2);
            strcpy(tmp,tmp2);
            strip_string(tmp);

            if (strncmp(tmp,"Removable",9) == 0) {
                  s_removable = 1;
                  strcpy(tmp2,tmp+10);
                  strcpy(tmp,tmp2);
            } else {
                  s_removable = 0;
            }
            
            s_type = get_scsi_type(tmp);

            /* allocate and fill structure */
            scsidevices[scsicount]=g_new(scsi_devices_t,1);
            if (idx == -1) {
                  /* autoscan mode */
                  scsidevices[scsicount]->devnr = 
                        transport*1024+busnr*32+s_id;
                  scsidevices[scsicount]->alt_dev = -1;
            } else {
                  /* manual mode */
                  scsidevices[scsicount]->devnr = idx;
                  scsidevices[scsicount]->alt_dev = idx;
            }

            scsidevices[scsicount]->sector_size = DATASECTORSIZE;
            scsidevices[scsicount]->transport = transport;
            scsidevices[scsicount]->bus = busnr;
            scsidevices[scsicount]->id = s_id;
            strcpy(scsidevices[scsicount]->vendor,s_vendor);
            strcpy(scsidevices[scsicount]->model,s_model);
            strcpy(scsidevices[scsicount]->rev,s_rev);
            scsidevices[scsicount]->removable = s_removable;
            scsidevices[scsicount]->type = s_type;
            
            scsicount++;
            if (scsicount >= MAXDEVICES) {
                  g_error("Error: More than %d devices scanned\n",MAXDEVICES);
            }
      }
}


/* print memory-structure with scsidevices (debug purposes) */
#if 0
static void print_scsidevices(scsi_devices_t **scsidevices) {
gint count;

      dodebug(2,"------ cdrecord scsidevices-structure -----\n");
      count = 0;
      while(scsidevices[count] != NULL) {
            dodebug(2,"devnr=%d %d:%d %s %s %s %d,%d (alt: %d) (ssize: %d)\n",
                  scsidevices[count]->devnr,
                  scsidevices[count]->bus,
                  scsidevices[count]->id,
                  scsidevices[count]->vendor,
                  scsidevices[count]->model,
                  scsidevices[count]->rev,
                  scsidevices[count]->removable,
                  scsidevices[count]->type,
                  scsidevices[count]->alt_dev,
                  scsidevices[count]->sector_size);
                  
            count++;
      }
}
#endif

static void print_writerreaderdevs() {
gint count;

      dodebug(2,"------ cdrecord writerreaderdevs-structure -----\n");
      count = 0;
      while(writerreaderdevs[count] != NULL) {
            dodebug(2, "devnr=%d (%s) [%s %s %s] (ssize: %d)\n", 
                  writerreaderdevs[count]->devnr,
                  writerreaderdevs[count]->devicestr,
                  writerreaderdevs[count]->vendor,
                  writerreaderdevs[count]->model,
                  writerreaderdevs[count]->rev,
                  writerreaderdevs[count]->sector_size);
            dodebug(2, "  readmax: %d, cdrmax: %d, dvdmax: %d, is_cdrwriter: %d, is_dvdreader: %d, is_dvdwriter: %d\n",
                  writerreaderdevs[count]->writer_readmaxspeed,
                  writerreaderdevs[count]->writer_cdrmaxspeed,
                  writerreaderdevs[count]->writer_dvdmaxspeed,
                  writerreaderdevs[count]->is_cdrwriter,
                  writerreaderdevs[count]->is_dvdreader,
                  writerreaderdevs[count]->is_dvdwriter,
                  writerreaderdevs[count]->sector_size);
            dodebug(2, "  writer_flags: %s\n", 
                  writerreaderdevs[count]->writer_flags);
            dodebug(2, "  writer_modes: %s\n", 
                  writerreaderdevs[count]->writer_modes);
                  
            count++;
      }
}


/* create a new writer/reader entry */

static gint add_writerreader(scsi_devices_t *scsidev, gchar *transport, GtkWidget *txt) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar drvflags[MAXLINE], drvmodes[MAXLINE];
gint readmax, cdrmax, dvdmax, iscdr, isdvdr, isdvdrom;
gint count;
gint mmap_error;
gint i;
static const gchar *writemodes[] = WRITE_MODES;

      /* first search last entry of writerreader struct */
      count = 0;
      while(writerreaderdevs[count] != NULL) {
            if (count == MAXDEVICES-1) {
                  return 0;
            }
            count++;
      }

      /* only add type WORM and CD-ROM types */
      if (scsidev->type != 4 && scsidev->type != 5) {
            return 0;
      }

      /* build device string */
      if (scsidev->alt_dev == -1) {
            g_snprintf(tmp,MAXLINE,"%s%d,%d,%d",
                  transport, scsidev->bus, scsidev->id, 0);
      } else {
            strncpy(tmp, transport, MAXLINE);
      }     

      /* check if this device already exists */
      if (get_writerreaderdevs_index_from_devstr(tmp) != -1) {
            if (txt) {
                  g_snprintf(tmp2,MAXLINE,"([%s] %s %s %s)\n",
                        tmp, scsidev->vendor,
                        scsidev->model, scsidev->rev);
                  convert_for_gtk2_textwidget(tmp2);
                        gtk_text_insert(GTK_TEXT(txt), NULL, NULL, NULL, tmp2, strlen(tmp2));
                  wait_and_process_events();      
            }
            return 0;
      }

      /* create a new entry */
      writerreaderdevs[count]=g_new0(writerreader_devices_t,1);
      writerreaderdevs[count]->devnr = scsidev->devnr;
      writerreaderdevs[count]->devicestr = g_strdup(tmp);
      strncpy(writerreaderdevs[count]->vendor, scsidev->vendor,9);
      strncpy(writerreaderdevs[count]->model, scsidev->model,17);
      strncpy(writerreaderdevs[count]->rev, scsidev->rev,5);
      writerreaderdevs[count]->sector_size = scsidev->sector_size;

      getmodesflags(tmp, drvflags, drvmodes); 
      writerreaderdevs[count]->writer_flags = g_strdup(drvflags);
      writerreaderdevs[count]->writer_modes = g_strdup(drvmodes);

      /* get more detailed information about this device */
        mmap_error=getdevicecap(tmp, &readmax, &cdrmax, &dvdmax, &iscdr, &isdvdrom, &isdvdr);
      writerreaderdevs[count]->writer_readmaxspeed = readmax;
      writerreaderdevs[count]->writer_cdrmaxspeed = cdrmax;
      writerreaderdevs[count]->writer_dvdmaxspeed = dvdmax;
      writerreaderdevs[count]->is_cdrwriter = iscdr;
      writerreaderdevs[count]->is_dvdreader = isdvdrom;
      writerreaderdevs[count]->is_dvdwriter = isdvdr;
      

      /* workaround for non-mcc drives */
      if (writerreaderdevs[count]->is_cdrwriter == 0) {
            /* not detected as writer, but got write modes? */
            if (strlen(drvmodes) > 0) {
                  /* assume its really a writer then */
                  writerreaderdevs[count]->is_cdrwriter = 1;
            }
      }

      /* set defaults for other fields */
      writerreaderdevs[count]->writer_drvmode = -1;
      writerreaderdevs[count]->writer_speed = cdrmax;
      writerreaderdevs[count]->writer_fifo = 4096;

      /* get the first supported mode for that writer */
      i = 0;
      while (writemodes[i]) {
            if (writemode_supported(i, scsidev->devnr)) {
                  writerreaderdevs[count]->writer_mode = i; 
                  break;
            }     
            i++;
      }

      writerreaderdevs[count]->audioread_interface = 0;
      writerreaderdevs[count]->audioread_speed = readmax;
      writerreaderdevs[count]->audioread_overlap = 0;
      writerreaderdevs[count]->audioread_sectorburst = 75;
      writerreaderdevs[count]->audioread_useparanoia = 0;
      writerreaderdevs[count]->audioread_paranoiaretries = 20;

      /* add to dialog window */
        if (txt) {
            g_snprintf(tmp2,MAXLINE,"[%s] %s %s %s\n",
                  tmp, scsidev->vendor,
                  scsidev->model, scsidev->rev);
            convert_for_gtk2_textwidget(tmp2);
                gtk_text_insert(GTK_TEXT(txt), NULL, NULL, NULL, tmp2, strlen(tmp2));
                wait_and_process_events();      
      }

      return mmap_error;
}


/* does scan for a single device only */
/* return 1 when new device was found */

static gint scanbus_single(gchar *dev, gint newdevnr, GtkWidget *txt) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
FILE *fpin;
scsi_devices_t **scsidevices;
gint found;

      scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
      scsicount = 0;

      get_wrap_path_cdrecord(line);

      /* make sure we escape any critical chars in input */
      strncpy(tmp2,dev,MAXLINE);
      convert_escape(tmp2);

      g_snprintf(tmp,MAXLINE," -scanbus dev= \"%s\" 2>&1",tmp2);
      strcat(line,tmp);

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"scanbus: %s",line);
                parse_scan(line, newdevnr, 0, scsidevices);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      found = 0;
      if (scsidevices[0]) {
            add_writerreader(scsidevices[0], dev, txt);
            g_free(scsidevices[0]);
            found = 1;
      }
      g_free(scsidevices);

      return found;
}


#if (defined(__MACH__) && defined(__APPLE__)) 

/* interpret output of -inq and sort into memory structure */
/* if idx != -1 then we run in manual-device-mode */

static void parse_inq(gchar *line, gint idx, scsi_devices_t **scsidevices) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;
gchar s_vendor[9];
gchar s_model[17];
gchar s_rev[5];
gint s_removable;
gint s_type;


      if (strncmp("Device type",line,11) == 0) {
            p = strtok(line,":");
            if (p) {
                  p = strtok(NULL,"");
                  if (p) {
                        strcpy(tmp,p);
                        strip_string(tmp);
                        if (strncmp(tmp,"Removable",9) == 0) {
                              s_removable = 1;
                              strcpy(tmp2,tmp+10);
                              strcpy(tmp,tmp2);
                        } else {
                              s_removable = 0;
                        }
            
                        s_type = get_scsi_type(tmp);

                        /* allocate entry now */
                        scsidevices[scsicount]=g_new(scsi_devices_t,1);
                        scsidevices[scsicount]->sector_size = DATASECTORSIZE;
                        scsidevices[scsicount]->devnr = idx;
                        scsidevices[scsicount]->alt_dev = idx;
                        scsidevices[scsicount]->transport = 0;
                        scsidevices[scsicount]->bus = 0;
                        scsidevices[scsicount]->id = idx;
                        scsidevices[scsicount]->removable = s_removable;
                        scsidevices[scsicount]->type = s_type;
                  }
            }
      }

      if (strncmp("Vendor_info",line,11) == 0) {
            p = strtok(line,":");
            if (p) {
                  p = strtok(NULL,"");
                  if (p) {
                        strcpy(tmp2,p);
                        extract_singlequoted(tmp2);

                        strcpy(s_vendor,"        ");
                        if (strlen(tmp2) <= 8) {
                              strncpy(s_vendor,tmp2,strlen(tmp2));
                        } else {
                              /* strip if to long */
                              strncpy(s_vendor,tmp2,8);
                        }     
                        s_vendor[8] = '\0';

                        if (scsidevices[scsicount]) {
                              strcpy(scsidevices[scsicount]->vendor,s_vendor);
                        }
                  }
            }
      }

      if (strncmp("Identifikation",line,14) == 0) {
            p = strtok(line,":");
            if (p) {
                  p = strtok(NULL,"");
                  if (p) {
                        strcpy(tmp2,p);
                        extract_singlequoted(tmp2);

                        strcpy(s_model,"                ");
                        if (strlen(tmp2) <= 16) {
                              strncpy(s_model,tmp2,strlen(tmp2));
                        } else {
                              strncpy(s_model,tmp2,16);
                        }
                        s_model[16] = '\0';

                        if (scsidevices[scsicount]) {
                              strcpy(scsidevices[scsicount]->model,s_model);
                        }     
                  }
            }
      }

      if (strncmp("Revision",line,8) == 0) {
            p = strtok(line,":");
            if (p) {
                  p = strtok(NULL,"");
                  if (p) {
                        strcpy(tmp2,p);
                        extract_singlequoted(tmp2);

                        strcpy(s_rev,"    ");
                        if (strlen(tmp2) <= 4) {
                              strncpy(s_rev,tmp2,strlen(tmp2));
                        } else {
                              strncpy(s_rev,tmp2,4);
                        }
                        s_rev[4] = '\0';

                        if (scsidevices[scsicount]) {
                              strcpy(scsidevices[scsicount]->rev,s_rev);
                              scsicount++;
                        }
                  }
            }
      }

      if (scsicount >= MAXDEVICES) {
            g_error("Error: More than %d devices scanned\n",MAXDEVICES);
      }
}


/* does scan for a single device only via inq call (osX) */

static gint scanbus_via_inq(gchar *dev, gint newdevnr, GtkWidget *txt) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
FILE *fpin;
scsi_devices_t **scsidevices;
gint found;

        scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
        scsicount = 0;

      get_wrap_path_cdrecord(line);

      /* make sure we escape any critical chars in input */
      strncpy(tmp2,dev,MAXLINE);
      convert_escape(tmp2);

      g_snprintf(tmp,MAXLINE," -inq dev= \"%s\" 2>&1",tmp2);
      strcat(line,tmp);

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"scanbus: %s",line);
                parse_inq(line, newdevnr, scsidevices);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

        found = 0;
        if (scsidevices[0]) {
                add_writerreader(scsidevices[0], dev, txt);
                g_free(scsidevices[0]);
                found = 1;
        }
        g_free(scsidevices);

        return found;
}

#endif

/* scanbus scsi */

static void scan_traditional(GtkWidget *txt) {
gchar line[MAXLINE];
FILE *fpin;
gint count, errcount, ret;
scsi_devices_t **scsidevices;

      scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
      scsicount = 0;

      /* traditional scanning first */
      get_wrap_path_cdrecord(line);
      strcat(line," -scanbus 2>&1");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"scanbus: %s",line);
                parse_scan(line, -1, 0, scsidevices);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      /* add the found devices to the writerreader structure */
      count = 0;
      errcount = 0;
      while(scsidevices[count] != NULL) {
            errcount+=add_writerreader(scsidevices[count],"", txt);
            g_free(scsidevices[count]);
            count++;
      }
      g_free(scsidevices);

      /* historic mmap error check */
      if (errcount > 0) {
                ret = show_dialog(ICO_WARN, _("Warning: The cdrtools binaries you have installed are\nnot compatible with your system. You will NOT be\nable to read or write CDs. Please read the FAQ\non www.xcdroast.org for more information."), T_ANYWAY, _("Exit"), NULL, 1);
                if (ret == 1)
                        gtk_exit(1);
      }
}


/* alternative transport method scanning */
/* valid transport choices for now: ATAPI USCSI REMOTE */

static gint scan_other(gchar *transport, gint transid, GtkWidget *txt) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
FILE *fpin;
gint count;
scsi_devices_t **scsidevices;

      scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
      scsicount = 0;

      get_wrap_path_cdrecord(line);
      g_snprintf(tmp,MAXLINE," dev=%s -scanbus 2>&1", transport);
      strcat(line, tmp);
      
      dodebug(1, "calling: %s\n", line);
            if ((fpin = popen(line,"r")) == NULL) {
                   g_error("popen error\n");
            }

        for (;;) {
            if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"scanbus (%s): %s", transport, line);
                  parse_scan(line, -1, transid, scsidevices);
            }

            if (pclose(fpin) == -1) {
                  g_error("pclose error\n");
            }

      /* add the found devices to the writerreader structure */
      count = 0;
      g_snprintf(tmp,MAXLINE,"%s:", transport);
      while(scsidevices[count] != NULL) {
            add_writerreader(scsidevices[count], tmp, txt);
            g_free(scsidevices[count]);
            count++;
      }
      g_free(scsidevices);

      return count;
}


/* new scanbus version */

void scanbus_new(GtkWidget *txt, gint scanparam) {
gchar tmp[MAXLINE];
GdkFont *boldfont;
gint doscanbus;
gint i, devnr;

      /* allocate memory */
      if (!writerreaderdevs) {
            writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
      }

      boldfont = get_some_font(BOLDFONT);
      doscanbus = 1;

      /* output status texts? */
      if (txt) {
            strncpy(tmp,_("Starting to scan for devices...\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(txt), boldfont, NULL, NULL, tmp, strlen(tmp));
            wait_and_process_events();    
      }

      /* check if we have to do full scanbus, or only partial */
      if (alt_scsidevices[0] != NULL) {
            i = 0;
            while (alt_scsidevices[i] != NULL) {
                  /* look for a free device number (greater 8192) */
                  for (devnr = 8192; devnr < 8192 + MAXDEVICES; devnr++) {
                        if (get_writerreaderdevs_index(devnr) == -1) {
                              break;
                        }     
                  }     
                  scanbus_single(alt_scsidevices[i], devnr, txt);
                  i++;
            }           

            /* trigger not to scan the bus any futher */
            doscanbus = 0;
      }

#if (defined(__MACH__) && defined(__APPLE__)) 

      /* special handling for osX */
      /* try fixed list of devices */
      alt_scsidevices[0] = g_strdup("IOCompactDiscServices");
      alt_scsidevices[1] = g_strdup("IOCompactDiscServices/2");
      alt_scsidevices[2] = g_strdup("IOCompactDiscServices/3");
      alt_scsidevices[3] = g_strdup("IODVDServices");
      alt_scsidevices[4] = g_strdup("IODVDServices/2");
      alt_scsidevices[5] = g_strdup("IODVDServices/3");

      i = 0;
      while (alt_scsidevices[i] != NULL) {
            scanbus_via_inq(alt_scsidevices[i], 4096+i, txt);
            i++;
      }           
      
      /* trigger not to scan the bus any futher */
      doscanbus = 0;
#endif

      if (doscanbus) {
            /* scan for scsi devices */
            scan_traditional(txt);

            /* scan for alternatives */
#if defined(linux)
            if (scanparam) {
                  scan_other("ATA", 1, txt);
            }
#endif
#if defined(sun)
            if (scanparam) {
                  scan_other("USCSI", 2, txt);
            }
#endif
      }

      if (txt) {
            strncpy(tmp,_("Scan finished.\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(txt), boldfont, NULL, NULL, tmp, strlen(tmp));
            wait_and_process_events();    
      }

      gdk_font_unref(boldfont);


      if (debug) print_writerreaderdevs();

}



/* scan for remote scsi devices */

void scanbus_rscsi(gchar *devstr, GtkWidget *txt) {
gchar tmp[MAXLINE];
GdkFont *boldfont;
gint found;
gint i, highest;

      /* allocate memory */
      if (!writerreaderdevs) {
            writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
      }

      boldfont = get_some_font(BOLDFONT);

      /* output status texts? */
      if (txt) {
            strncpy(tmp,_("Starting to scan for remote devices...\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(txt), boldfont, NULL, NULL, tmp, strlen(tmp));
            wait_and_process_events();    
      }

      /* look for highest free devnr - but at least a multiple of 16384 */
      i = 0;
      highest = -1;
      while(writerreaderdevs[i] != NULL) {
            if (writerreaderdevs[i]->devnr > highest) {
                  highest = writerreaderdevs[i]->devnr;
            }
            i++;
      }
      highest++;

      /* when we scan multiple times always arange a new block to play safe */
      highest = ((highest/16384)+1)*16384;

      found = scan_other(devstr, highest/1024, txt);

      if (txt) {
            if (found == 0) {
                  strncpy(tmp,_("No devices found - check your remote scsi setup.\n"), MAXLINE);
                  convert_for_gtk2_textwidget(tmp);
                  gtk_text_insert(GTK_TEXT(txt), NULL, NULL, NULL, tmp, strlen(tmp));
            }
            strncpy(tmp,_("Scan finished.\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(txt), boldfont, NULL, NULL, tmp, strlen(tmp));
            wait_and_process_events();    
      }

      gdk_font_unref(boldfont);


      if (debug) print_writerreaderdevs();
}


/* special version where we scan only for a single device */

void scanbus_new_single(gchar *devstr, GtkWidget *txt) {
gchar tmp[MAXLINE];
GdkFont *boldfont;
gint devnr, found;

      /* allocate memory */
      if (!writerreaderdevs) {
            writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
      }

      boldfont = get_some_font(BOLDFONT);

      /* output status texts? */
      if (txt) {
            strncpy(tmp,_("Starting to scan for devices...\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(txt), boldfont, NULL, NULL, tmp, strlen(tmp));
            wait_and_process_events();    
      }

      /* look for a free device number (greater 8192) */
      for (devnr = 8192; devnr < 8192 + MAXDEVICES; devnr++) {
            if (get_writerreaderdevs_index(devnr) == -1) {
                  break;
            }     
      }     
      found = scanbus_single(devstr, devnr, txt);

      if (txt) {
            if (!found) {
                  strncpy(tmp,_("Device not found.\n"), MAXLINE);
                  convert_for_gtk2_textwidget(tmp);
                  gtk_text_insert(GTK_TEXT(txt), NULL, NULL, NULL, tmp, strlen(tmp));
            }
            strncpy(tmp,_("Scan finished.\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(txt), boldfont, NULL, NULL, tmp, strlen(tmp));
            wait_and_process_events();    
      }

      gdk_font_unref(boldfont);


      if (debug) print_writerreaderdevs();
}


/* interpret output of driver=help and sort into memory structure */

static void parse_driver(gchar *line) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar drv[MAXLINE];
gchar *p1;
gint n;
      if (strncmp(line,"Driver types:",13) != 0 ) {

            strcpy(tmp,line);
            p1=strtok(tmp," ");
            strcpy(drv,p1);   
            /* now drv contains the driver name */

            p1=strtok(NULL,"");
            strcpy(tmp2,p1);
            strip_string(tmp2);
            /* now tmp2 contains the description */

            /* cut "driver for" away */ 
            if (strncmp(tmp2,"driver for ",11) == 0 ){
                  strcpy(tmp,tmp2+11);
                  strcpy(tmp2,tmp);
            }

            /* allocate structure */
            drivers[drvcount]=g_new(writer_driver_t,1);

            n = strlen(drv)+1;
            drivers[drvcount]->driver=g_new(gchar,n);
            strcpy(drivers[drvcount]->driver,drv);

            n = strlen(tmp2)+1;
            drivers[drvcount]->desc=g_new(gchar,n);
            strcpy(drivers[drvcount]->desc,tmp2);

            drvcount++;
            if (drvcount >= MAXDRIVERS) {
                  g_error("Error: More than %d writer devices found\n",MAXDRIVERS);
            }
      }
}


/* print memory-structure with drivers (debug purposes) */

static void print_drivers() {
gint count;

      dodebug(2,"------ cdrecord drivers-structure -----\n");
      count = 0;
      while(drivers[count] != NULL) {
            dodebug(2, "%s:%s\n",
                  drivers[count]->driver,
                  drivers[count]->desc);
                  
            count++;
      }
}


/* call cdrecord driver=help */

void scandrivers() {
gchar line[MAXLINE];
FILE *fpin;

      /* allocate memory */
      drivers = g_new0(writer_driver_t *,MAXDRIVERS);
      drvcount = 0;

      get_wrap_path_cdrecord(line);
      strcat(line," driver=help 2>&1");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10, "driverlist: %s",line);
                parse_driver(line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      if (debug) print_drivers();
}


/* print memory-structure with charsets (debug purposes) */

static void print_charsets() {
gint count;
gchar tmp[MAXLINE];

      dodebug(2,"------ mkisofs-charsets-structure -----\n");
      count = 0;
      strcpy(tmp,"");   
      while(charset_types[count] != NULL) {

            strcat(tmp,charset_types[count]);

            if ((count+1) % 6) {
                  strcat(tmp, ", ");
            } else {
                  dodebug(2, "%s\n", tmp);
                  strcpy(tmp,"");   
            }
            count++;
      }
      if (strcmp(tmp,"") != 0) 
            dodebug(2, "%s\n", tmp);
}


/* call mkisofs -input-charset help */

void scancharsets() {
gchar line[MAXLINE];
FILE *fpin;
gint start,count,backcount;
gchar **tmp_types;

      /* allocate memory */
      charset_types = g_new0(gchar *,MAXCHARSETS+1);
      tmp_types = g_new0(gchar *,MAXCHARSETS+1);

      start = 0;
      count = 0;

      get_wrap_path("MKISOFS",line);
      strcat(line," -input-charset help 2>&1");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            /* wait for Known charsets.... line */
            if (strncmp("Known",line,5) == 0) {
                  start = 1;
                  continue;
            }
            if (start) {
                  dodebug(10, "mkisofs charsets: %s",line);

                  tmp_types[count] = g_strdup(strip_string(line));
                  count++;          
                  if (count >= MAXCHARSETS) {
                        g_error("Error: More than %d input charsets found\n",MAXCHARSETS);
                  }
            }
        }

      tmp_types[count] = g_strdup("default");
      
        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      /* now the types list is reversed, make it right */
      backcount = count;
      count = 0;
      while(backcount >= 0) {
            charset_types[count] = tmp_types[backcount];
            count++;
            backcount--;
      }
      g_free(tmp_types);

      if (debug) print_charsets();
}


/* call cdrecord -prcap to get some device information */
/* also checks for mmap errors and return 1 if one occured */

static gint getdevicecap(gchar *dev, gint *readmax, gint *cdrmax, gint *dvdmax, gint *iscdr, gint *isdvdrom, gint *isdvdr) {
gchar tmp[MAXLINE];
gchar line[MAXLINE];
gint tmpnr, errcount;
FILE *fpin;
gchar *p;

      /* set reasonable defaults */
      *readmax = 0;
      *cdrmax = 0;
      *dvdmax = 0;
      *iscdr = 0;
      *isdvdr = 0;
      *isdvdrom = 0;

        if (!dev) return 0;

        get_wrap_path_cdrecord(tmp);
        g_snprintf(line, MAXLINE, "%s dev= \"%s\" -prcap 2>&1", tmp, dev);

        dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      errcount = 0;
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
                dodebug(10, "prcap: %s",line);

                /* line with mmap error? */
                if (strstr(line,"annot get mmap for")) {
                        errcount++;
                }

            if (strstr(line, "Does write CD-R media")) {
                  *iscdr = 1;
            }
            if (strstr(line, "Does read DVD-ROM media")) {
                  *isdvdrom = 1;
            }
            if (strstr(line, "Does write DVD-R media")) {
                  *isdvdr = 1;
            }
            if (strstr(line, "Maximum read  speed:")) {
                  p = strtok(line,"(");
                  if (p) {
                        p = strtok(NULL,")");
                        if (p) {
                              strcpy(tmp,p);
                              sscanf(tmp,"CD %3dx, DVD %3d",
                                    readmax, &tmpnr);
                        }
                  }
            } else 
            if (strstr(line, "Maximum write speed:")) {
                  p = strtok(line,"(");
                  if (p) {
                        p = strtok(NULL,")");
                        if (p) {
                              strcpy(tmp,p);
                              sscanf(tmp,"CD %3dx, DVD %3d",
                                    cdrmax, dvdmax);
                        }
                  }
            }
      }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

        if (errcount > 0) {
                return 1;
        } else {
                return 0;
        }
}


/* get driverflags and modes from drive */

void getmodesflags(gchar *dev, gchar *drvflags, gchar *drvmodes) {
gchar tmp[MAXLINE];
gchar line[MAXLINE];
FILE *fpin;
gchar *p;

      strcpy(drvflags,"");
      strcpy(drvmodes,"");

        if (!dev) return;

        get_wrap_path("CDRECORD", tmp);
        g_snprintf(line, MAXLINE, "%s dev= \"%s\" -v -checkdrive 2>&1", tmp, dev);

        dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
                dodebug(10, "checkdrive: %s",line);

            if (strstr(line, "Driver flags   :")) {
                  p = strtok(line,":");
                  if (p) {
                        p = strtok(NULL,"");
                        if (p) {
                              strncpy(tmp,p,MAXLINE);
                              strip_string(tmp);
                              strncpy(drvflags,tmp,MAXLINE);
                        }
                  }
            } else 
            if (strstr(line, "Supported modes:")) {
                  p = strtok(line,":");
                  if (p) {
                        p = strtok(NULL,"");
                        if (p) {
                              strncpy(tmp,p,MAXLINE);
                              strip_string(tmp);
                              strncpy(drvmodes,tmp,MAXLINE);
                        }
                  }
            }
      }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }
}


static gint parse_freespace(gchar *line, gchar *fs) {
gchar tmp[MAXLINE];
gchar *p1;

      /* skip first line(s) */
      if (index(line,'/')) {
              strcpy(tmp,line);
#if defined (aix)
            /* filesystem label */
            p1=strtok(tmp," ");
            if (fs != NULL) {
                 /* get the filesystem */
                 strcpy(fs,p1);
            }
            /* size of filesystem */
            p1=strtok(NULL," ");
            if (p1 == NULL) { 
                  g_error("df -k output syntax error\n");
            }
            /* available blocks */
            p1=strtok(NULL," ");
            if (p1 == NULL) { 
                  g_error("df -k output syntax error\n");
            }
            return (atoi(p1));
#elif defined (hpux)
            /* mountpoint */
            p1=strtok(tmp,"(");
            if (p1 == NULL) { 
                  g_error("df -b output syntax error\n");
            }
            /* filesystem label */
            p1=strtok(NULL,")");
            if (fs != NULL) {
                 /* get the filesystem - avoid "(" at the beginning */
                 strcpy(fs,p1);
            }
            /* size in kb */
            p1=strtok(NULL,": ");
            if (p1 == NULL) { 
                  g_error("df -b output syntax error\n");
            }           
            return (atoi(p1));
#else

            /* skip the first 4 fields in output to come to "available" */

            /* are we handling the first line of two?*/
            p1=strtok(tmp," ");

            if (dfrun == 0) {
                  if (fs != NULL) {
                        /* get the filesystem */
                        strcpy(fs,p1);
                  }

                  p1=strtok(NULL," ");
                  if (p1 == NULL) {
                        /* ok..output splitted on two lines */
                        dfrun = 1;
                        return -1;
                  }
            }
            p1=strtok(NULL," ");
            if (p1 == NULL) {
                  g_error("df -k output syntax error\n");
            } 
            p1=strtok(NULL," ");
            if (p1 == NULL) { 
                  g_error("df -k output syntax error\n");
            }
            return (atoi(p1));
#endif
      }
      return -1;
}


/* get free diskspace. return in 1024byte blocks or -1 if not valid */
/* return filesystem if not set to NULL */
/* will handle if output is in two lines...like when the filesystem
   output is longer that 20 chars - e.g. on nfs-links */
/* will handle df-output like:

(Solaris)
Filesystem            kbytes    used   avail capacity  Mounted on
fileserv:/export/home
                     17502608 11609120 5718464    67%    /export/home

OR

(Linux)
Filesystem         1024-blocks  Used Available Capacity Mounted on
/dev/sda3            2494898 1606489   759428     68%   /

Système de
fichiers          1K-blocs    Utilisé Disponible U.% Monté sur
/dev/hda6             10080488   8043456   1524964  85% /

OR

(AIX)
Filesystem    1024-blocks      Free %Used    Iused %Iused Mounted on
/dev/hd4             8192      2968   64%     1319    33% /
/dev/hd2           573440     31644   95%    22280    16% /usr

OR

(HP-UXs df -b)
/tmp                   (/dev/vg00/lvol4       ) :   188158 Kbytes free
/usr                   (/dev/vg00/lvol5       ) :   286696 Kbytes free


*/

gint get_free_space(gchar *path, gchar *filesystem) {
gchar line[MAXLINE];
FILE *fpin;
gint space;

      space = -1;
      dfrun = 0;

      if (is_directory(path) != 1) {
            return -1;
      }

      if (stat_file(DF)) {
            strcpy(line,DF);
            strcat(line," \"");
            strcat(line,path);
            strcat(line,"\"");
      } else {
            strcpy(line,DF2);
            strcat(line," \"");
            strcat(line,path);
            strcat(line,"\"");
      }

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"df: %s",line);
                space = parse_freespace(line,filesystem);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      if (filesystem != NULL) {
            dodebug(2, "filesystem lookup for %s = %d blocks, fs = %s\n", 
                  path, space, filesystem);
      } else {
            dodebug(2, "filesystem lookup for %s = %d blocks, fs = %s\n", 
                  path, space, "(NULL)");
      }
 
      return space;
}


/* get a list of all audio-devices found on a system. This has to be
   done platform dependent */

GList *get_dsp_devices() {
GList *dsp;
GList *loop;
#if !(defined(__MACH__) && defined(__APPLE__)) 
struct stat buf;
#endif

#if defined(sun) || defined(aix) || defined(__OpenBSD__)
gchar *audiodev;
#endif
      dsp = NULL;

#if defined(linux) || defined(__FreeBSD__)
      /* for linux check if /dev/dsp or /dev/dsp1 exist */

      if (stat("/dev/dsp",&buf) == 0) {
            dsp = g_list_append(dsp,"/dev/dsp");
      }
      if (stat("/dev/dsp1",&buf) == 0) {
            dsp = g_list_append(dsp,"/dev/dsp1");
      }
#endif
#if defined(sun) || defined(__OpenBSD__)
      /* check if the user has any special audio-hardware running,
         which set the AUDIODEV-environment-variable */
      audiodev = getenv("AUDIODEV");
      if (audiodev != NULL) {

            if (stat(audiodev,&buf) == 0) {
                  dsp = g_list_append(dsp,g_strdup(audiodev));
            }
      } else {
            audiodev = "";
      }
      if (strcmp(audiodev,"/dev/audio") != 0) {

            if (stat("/dev/audio",&buf) == 0) {
                  dsp = g_list_append(dsp,"/dev/audio");
            }
      }
#endif
#ifdef aix
       audiodev = getenv ("AUDIODEV");
       if (audiodev != NULL) {

               if (stat (audiodev, &buf) == 0) {
                       dsp = g_list_append (dsp, g_strdup(audiodev));
               }
       }
       /* Try to use the device of a machine with PCI bus */
        if (stat ("/dev/paud0/1", &buf) == 0) {
               dsp = g_list_append (dsp, "/dev/paud0/1");
       }
        /* Try to use the device of a machine with MCA bus */
        if (stat ("/dev/baud0/1", &buf) == 0) {
               dsp = g_list_append (dsp, "/dev/baud0/1");
       }
#endif
#ifdef hpux
# ifndef hpux_alib

       /* for HP-UX check if /dev/audio exists - I've never seen */
       /* other audio devices under HP-UX                        */

       if (stat("/dev/audio",&buf) == 0) {
               dsp = g_list_append(dsp,"/dev/audio");
       }
# else
       /* for HP-UX with the Alib we dont need to check if the    */
       /* device exists - we actually do not know even the device */
       dsp = g_list_append(dsp,"AUDIO ENVIRONMENT");
# endif
#endif

#if (defined(__MACH__) && defined(__APPLE__))

      /* on macosX we always should have the build-in-audio device */
       dsp = g_list_append(dsp,"Apple CoreAudio");
#endif

#if defined(__sgi)
{
       int     i, rv;
       ALvalue devs [16];
       ALpv    q [1];
       char    devLabel [32];

       /*
        * Fetch the list of available output audio devices.
        */
       q[0].param = AL_TYPE;
       q[0].value.i = AL_OUTPUT_DEVICE_TYPE;
       if ((rv = alQueryValues(AL_SYSTEM, AL_DEVICES, devs, 16, q, 1)) >= 0) {

               for (i = 0; i < rv; i++) {
                       q[0].param = AL_LABEL;
                       q[0].value.ptr = devLabel;
                       q[0].sizeIn = 32;
                       alGetParams(devs[i].i, q, 1);
                       if (alIsSubtype(AL_DEVICE_TYPE, devs[i].i)) {
                               dsp = g_list_append(dsp, g_strdup(devLabel));
                       }
               }
       }
}
#endif

      /* do some debug output */
      if (debug) {
            loop = g_list_first(dsp);
            while(loop) {
                  if (loop->data != NULL) 
                        dodebug(10, "dspscan: %s\n", 
                              (gchar *) loop->data);
                  loop = loop->next;
            }
      }

      return g_list_first(dsp);
}


/* take a dsp-device and find the fitting mixer-device */

gchar *gen_mix_from_dspdev(gchar *dsp, gchar *ret) {
#if !(defined(__MACH__) && defined(__APPLE__)) 
gchar tmp[MAXLINE];
# ifndef aix
struct stat buf;
# endif
#endif
#if defined(linux) || defined(__FreeBSD__)
gchar tmp2[MAXLINE];
#endif

      strcpy(ret,"");

#if defined(linux) || defined(__FreeBSD__)

      if (strncmp(dsp,"/dev/dsp",8) == 0) {
            strcpy(tmp,dsp+8);
            g_snprintf(tmp2,MAXLINE,"/dev/mixer%s",tmp);

            /* does device exist? */
            if (stat(tmp2,&buf) == 0) {
                  strcpy(ret,tmp2);
            }     
      }     
#endif
#if defined(sun) || defined(__OpenBSD__)

      g_snprintf(tmp,MAXLINE,"%s%s",dsp,"ctl");

            /* does device exist? */
            if (stat(tmp,&buf) == 0) {
                  strcpy(ret,tmp);
            }
#endif
#ifdef aix
       /* The gain will be set via ioctl and the usual */
        /* output device                                */
       g_snprintf(tmp,MAXLINE,"%s",dsp);
       strcpy(ret,tmp);
#endif
#ifdef hpux
# ifndef hpux_alib
      g_snprintf(tmp,MAXLINE,"%s%s",dsp,"Ctl");

      /* does device exist? */
      if (stat(tmp,&buf) == 0) {
              strcpy(ret,tmp);
      }
# else
      /* We have no control or mixer device -> all is */
      /* done via the Aserver-daemon and its API      */
      strcpy(ret, "ASERVER"); 
# endif
#endif

      dodebug(10, "mixer: %s\n", ret);
      return ret;
}


/* call uname -a to get a nice system-id-string */

gchar *get_uname_info(gchar *str) {
FILE *fpin;

      if (stat_file(UNAME)) {
            dodebug(1, "calling: %s\n", UNAME);
                  if ((fpin = popen(UNAME,"r")) == NULL) {
                  g_error("popen error\n");
            }
        } else {
            dodebug(1, "calling: %s\n", UNAME2);
                  if ((fpin = popen(UNAME2,"r")) == NULL) {
                  g_error("popen error\n");
            }
      }

      strcpy(str,"");
      fgets(str,MAXLINE,fpin); 

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      dodebug(10, "uname: %s\n", str);

      return str;
}


/* Save the setup-configuration to a file - all strings are converted
   in a printable form first:  return 0 if ok, or 1 on error */

gint save_setup_config(gchar *confdir, gchar *fname) {
FILE *fd;
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
GList *loop;
gint count;

      /* no confdir? treat path absolute */
      if (strcmp(confdir,"") == 0) {
            strncpy(tmp,fname,MAXLINE);
      } else {

            /* now check if the confdir exists */
            if (!is_directory(confdir)) {
                  /* try to create directory */
                  mkdir(confdir, 0700);
                  dodebug(2, "trying to mkdir %s\n", confdir);
            }

            g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);
      }

      dodebug(1, "Opening %s for writing\n", tmp);
      dolog(3, "Saving config file %s\n", tmp);

      fd = fopen(tmp,"w"); 

      if (fd == NULL) { 
            /* error opening file */
            return 1;
      }

      /* write the config-file header */
      fputs("#\n",fd);
      g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s Configuration-File\n",XCDROAST_VERSION);
      fputs(tmp,fd);
      fputs("#\n",fd);
      fputs("# Automatically created by the X-CD-Roast-Setup\n",fd);
      fputs("# Don't edit! (Unless you REALLY know what you are doing)\n",fd);
      fputs("#\n\n",fd);

      /* write data */
      g_snprintf(tmp,MAXLINE,"VERSION = \"%s\"\n",XCDROAST_VERSION); 
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"PLATFORM = \"%s\"\n",system_platform); 
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITER_DEVNR = %d\n",setupdata.writer_devnr);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"READER_DEVNR = %d\n",setupdata.reader_devnr);
      fputs(tmp,fd);

      fputs("#\n",fd);

      /* write hardware structure */
      count = 0;
      while(writerreaderdevs[count] != NULL) {

            g_snprintf(tmp,MAXLINE,"WRITERREADER_DEVNR = %d\n",writerreaderdevs[count]->devnr);
            fputs(tmp,fd);

            strcpy(tmp2,writerreaderdevs[count]->devicestr);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_DEVICESTR = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);

            strcpy(tmp2,writerreaderdevs[count]->vendor);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_VENDOR = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);
            strcpy(tmp2,writerreaderdevs[count]->model);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_MODEL = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);
            strcpy(tmp2,writerreaderdevs[count]->rev);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_REV = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);
            
            g_snprintf(tmp,MAXLINE,"WRITERREADER_READMAXSPEED = %d\n",writerreaderdevs[count]->writer_readmaxspeed);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_CDRMAXSPEED = %d\n",writerreaderdevs[count]->writer_cdrmaxspeed);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_DVDMAXSPEED = %d\n",writerreaderdevs[count]->writer_dvdmaxspeed);
            fputs(tmp,fd);

            strcpy(tmp2,writerreaderdevs[count]->writer_flags);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_WRITER_FLAGS = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);
            strcpy(tmp2,writerreaderdevs[count]->writer_modes);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_WRITER_MODES = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);

            g_snprintf(tmp,MAXLINE,"WRITERREADER_IS_CDRWRITER = %d\n",writerreaderdevs[count]->is_cdrwriter);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_IS_DVDWRITER = %d\n",writerreaderdevs[count]->is_dvdwriter);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_IS_DVDREADER = %d\n",writerreaderdevs[count]->is_dvdreader);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_SECTOR_SIZE = %d\n",writerreaderdevs[count]->sector_size);
            fputs(tmp,fd);

            g_snprintf(tmp,MAXLINE,"WRITERREADER_DRVMODE = %d\n",writerreaderdevs[count]->writer_drvmode);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_MODE = %d\n",writerreaderdevs[count]->writer_mode);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_SPEED = %d\n",writerreaderdevs[count]->writer_speed);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_FIFO = %d\n",writerreaderdevs[count]->writer_fifo);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_INTERFACE = %d\n",writerreaderdevs[count]->audioread_interface);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_SPEED = %d\n",writerreaderdevs[count]->audioread_speed);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_OVERLAP = %d\n",writerreaderdevs[count]->audioread_overlap);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_SECTORBURST = %d\n",writerreaderdevs[count]->audioread_sectorburst);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_USEPARANOIA = %d\n",writerreaderdevs[count]->audioread_useparanoia);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_PARANOIARETRIES = %d\n",writerreaderdevs[count]->audioread_paranoiaretries);
            fputs(tmp,fd);


            fputs("#\n",fd);
            count++;
      }

      loop = g_list_first(setupdata.image_dirs);
      while(loop) {
            strcpy(tmp2,(gchar *)loop->data);
            g_snprintf(tmp,MAXLINE,"IMAGE_DIRS = \"%s\"\n",convert_escape(tmp2));
            fputs(tmp,fd);
            loop = loop->next;
      }

      strcpy(tmp2,setupdata.dsp_device);
      g_snprintf(tmp,MAXLINE,"DSP_DEVICE = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      strcpy(tmp2,setupdata.mix_device);
      g_snprintf(tmp,MAXLINE,"MIX_DEVICE = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"NOTIFY_VIA = %d\n",setupdata.notify_via);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"NOTIFY_AT = %d\n",setupdata.notify_at);
      fputs(tmp,fd);

      strcpy(tmp2,setupdata.cddb_host);
      g_snprintf(tmp,MAXLINE,"CDDB_HOST = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"CDDB_PORT = %d\n",setupdata.cddb_port);
      fputs(tmp,fd);
      strcpy(tmp2,setupdata.cddb_proxy_host);
      g_snprintf(tmp,MAXLINE,"CDDB_PROXY_HOST = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"CDDB_PROXY_PORT = %d\n",setupdata.cddb_proxy_port);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"CDDB_USE_HTTP = %d\n",setupdata.cddb_use_http);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"CDDB_USE_PROXY = %d\n",setupdata.cddb_use_proxy);
      fputs(tmp,fd);

      strcpy(tmp2,setupdata.logfile);
      g_snprintf(tmp,MAXLINE,"LOGFILE = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"LOGLEVEL = %d\n",setupdata.loglevel);
      fputs(tmp,fd);

      strcpy(tmp2,setupdata.language);
      g_snprintf(tmp,MAXLINE,"LANGUAGE = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);

      g_snprintf(tmp,MAXLINE,"OPTION_TOOLTIPS = %d\n",setupdata.option_tooltips);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_AUTORAISE = %d\n",setupdata.option_autoraise);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_SAVEPOS = %d\n",setupdata.option_savepos);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_PERSONIMAGE = %d\n",setupdata.option_personimage);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_OVERWRITEWARN = %d\n",setupdata.option_overwritewarn);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_AUTODELETE = %d\n",setupdata.option_autodelete);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_TITLEPROGRESS = %d\n",setupdata.option_titleprogress);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_DISPLAYCDTEXT = %d\n",setupdata.option_displaycdtext);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"OPTION_SELECTIONMODE = %d\n",setupdata.option_selectionmode);
      fputs(tmp,fd);

      strcpy(tmp2,setupdata.ProDVDkey);
      g_snprintf(tmp,MAXLINE,"PRODVD_KEY = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);

      /* save geometry data? */
      if (setupdata.option_savepos) {
            g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_X = %d\n", setupdata.mainwindow.x);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_Y = %d\n", setupdata.mainwindow.y);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_WIDTH = %d\n", setupdata.mainwindow.width);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_HEIGHT = %d\n", setupdata.mainwindow.height);
            fputs(tmp,fd);

            g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_X = %d\n", setupdata.burnwindow.x);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_Y = %d\n", setupdata.burnwindow.y);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_WIDTH = %d\n", setupdata.burnwindow.width);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_HEIGHT = %d\n", setupdata.burnwindow.height);
            fputs(tmp,fd);
      }

      /* do save the following information only when root */
      if (isroot()) {

            g_snprintf(tmp,MAXLINE,"ROOT_USERS_ACCESS = %d\n",setupdata.root_users_access);
            fputs(tmp,fd);

            loop = g_list_first(setupdata.root_users_lists);
            while(loop) {
                  strcpy(tmp2,(gchar *)loop->data);
                  g_snprintf(tmp,MAXLINE,"ROOT_USERS_LISTS = \"%s\"\n",convert_escape(tmp2));
                  fputs(tmp,fd);
                  loop = loop->next;
            }

            g_snprintf(tmp,MAXLINE,"ROOT_HOSTS_ACCESS = %d\n",setupdata.root_hosts_access);
            fputs(tmp,fd);

            loop = g_list_first(setupdata.root_hosts_lists);
            while(loop) {
                  strcpy(tmp2,(gchar *)loop->data);
                  g_snprintf(tmp,MAXLINE,"ROOT_HOSTS_LISTS = \"%s\"\n",convert_escape(tmp2));
                  fputs(tmp,fd);
                  loop = loop->next;
            }

            g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_WRITER = %d\n",setupdata.root_option_change_writer);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_WRITEPARAM = %d\n",setupdata.root_option_change_writeparam);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_READER = %d\n",setupdata.root_option_change_reader);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_READPARAM = %d\n",setupdata.root_option_change_readparam);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_IMAGEDIRS = %d\n",setupdata.root_option_change_imagedirs);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_LOGOPTIONS = %d\n",setupdata.root_option_change_logoptions);
            fputs(tmp,fd);
      }

      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      return 0;
}


/* Load the setup-configuration
   return 0 if ok, or 1 on error */
/* when rootconf is set, load all from file, else only what we are 
   allow */

gint load_setup_config(gchar *fname, gint rootconf) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gchar tmp[MAXLINE];
GList *tmp_image_dirs;
gint count, i, newadded;

      /* allocate memory if required */
      if (!writerreaderdevs) {
            writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
      }

      count = -1; 
      newadded = 0;
      tmp_image_dirs = NULL;

      /* prepare some data */
      if (rootconf) {
            free_glist(&setupdata.image_dirs);
      }
      if (rootconf) {
            free_glist(&setupdata.root_users_lists);
            free_glist(&setupdata.root_hosts_lists);
      }

      dodebug(1, "Opening config file %s for reading\n", fname);
      dolog(3, "Loading config file %s\n", fname);

      if ((fd = fopen(fname,"r")) == NULL) { 
            /* error opening file */
            return 1;
      }

      for (;;) {
            if (fgets(line,MAXLINE,fd) == NULL)
                  break;

            /* special case here to protect pro-dvd-key */
            if (strstr(line, "PRODVD_KEY") && strlen(line) > 50) {
                  strncpy(tmp,line,50);
                  tmp[50] = '\0';
                  dodebug(10,"config: %s...\n", tmp);
            } else {
                  dodebug(10,"config: %s", line);
            }

            /* skip empty or hashed lines */
            strip_string(line);
            if (*line == '#' || *line == '\0') 
                  continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  g_error("syntax error in config-file\n");
            }     

            if (strcmp("VERSION",id) == 0) {
                  strcpy(xcdroast_version_loaded,value); 
            }
            if (strcmp("PLATFORM",id) == 0) {
                  ;
            }

            if (rootconf || setupdata.root_option_change_writer) {
                  if (strcmp("WRITER_DEVNR",id) == 0) {
                        setupdata.writer_devnr = atoi(value);
                  }
            }
            if (rootconf || setupdata.root_option_change_reader) {
                  if (strcmp("READER_DEVNR",id) == 0) {
                        setupdata.reader_devnr = atoi(value);
                  }
            }

            /* marker for a new device - must be first entry! */
            if (strcmp("WRITERREADER_DEVNR",id) == 0) {
                  i = get_writerreaderdevs_index(atoi(value));

                  if (i == -1) {
                        /* new device */
                        if (rootconf || (setupdata.root_option_change_writer &&
                              setupdata.root_option_change_reader)) {
                        
                                    count = get_last_writerreaderdevs_index() +1;
                                    writerreaderdevs[count]=g_new0(writerreader_devices_t,1);
                                    writerreaderdevs[count]->devnr = atoi(value);
                                    newadded = 1;
                        } else {
                              /* no permission to add a new device */
                              /* ignore */
                              count = -1;
                              newadded = 0;
                        }
                  } else {
                        /* we seen such a device already */
                        count = i;
                        newadded = 0;
                  }
            }     
                  
            /* only load such data for newly allocated devices */
            if (newadded) {

                  if (strcmp("WRITERREADER_DEVICESTR",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->devicestr = g_strdup(value);
                        }     
                  }
                  if (strcmp("WRITERREADER_VENDOR",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              strncpy(writerreaderdevs[count]->vendor, value, 9);
                        }     
                  }
                  if (strcmp("WRITERREADER_MODEL",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              strncpy(writerreaderdevs[count]->model, value, 17);
                        }     
                  }
                  if (strcmp("WRITERREADER_REV",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              strncpy(writerreaderdevs[count]->rev, value, 5);
                        }     
                  }
                  if (strcmp("WRITERREADER_READMAXSPEED",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_readmaxspeed = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_CDRMAXSPEED",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_cdrmaxspeed = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_DVDMAXSPEED",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_dvdmaxspeed = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_WRITER_FLAGS",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_flags = g_strdup(value);
                        }     
                  }
                  if (strcmp("WRITERREADER_WRITER_MODES",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_modes = g_strdup(value);
                        }     
                  }
                  if (strcmp("WRITERREADER_IS_CDRWRITER",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->is_cdrwriter = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_IS_DVDREADER",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->is_dvdreader = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_IS_DVDWRITER",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->is_dvdwriter = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_SECTOR_SIZE",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->sector_size = atoi(value);
                        }
                  }
            }

            if (rootconf || newadded || setupdata.root_option_change_writeparam) {

                  if (strcmp("WRITERREADER_DRVMODE",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_drvmode = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_MODE",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_mode = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_SPEED",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_speed = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_FIFO",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->writer_fifo = atoi(value);
                        }
                  }
            }

            if (rootconf || newadded || setupdata.root_option_change_readparam) {

                  if (strcmp("WRITERREADER_AUDIOREAD_INTERFACE",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->audioread_interface = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_AUDIOREAD_SPEED",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->audioread_speed = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_AUDIOREAD_OVERLAP",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->audioread_overlap = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_AUDIOREAD_SECTORBURST",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->audioread_sectorburst = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_AUDIOREAD_USEPARANOIA",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->audioread_useparanoia = atoi(value);
                        }
                  }
                  if (strcmp("WRITERREADER_AUDIOREAD_PARANOIARETRIES",id) == 0) {
                        if (count >= 0 && writerreaderdevs[count]) {
                              writerreaderdevs[count]->audioread_paranoiaretries = atoi(value);
                        }
                  }
            }

            if (rootconf) {
                  if (strcmp("IMAGE_DIRS",id) == 0) {
                        setupdata.image_dirs = g_list_append(setupdata.image_dirs, g_strdup(value));  
                  }
            } else {
                  /* user config - load to tmp list */
                  if (strcmp("IMAGE_DIRS",id) == 0) {
                        tmp_image_dirs = g_list_append(tmp_image_dirs, g_strdup(value));  
                  }
            }
            if (strcmp("DSP_DEVICE",id) == 0) {
                  g_free(setupdata.dsp_device);
                  setupdata.dsp_device = g_strdup(value);
            }
            if (strcmp("MIX_DEVICE",id) == 0) {
                  g_free(setupdata.mix_device);
                  setupdata.mix_device = g_strdup(value);
            }
            if (strcmp("NOTIFY_VIA",id) == 0) {
                  setupdata.notify_via = atoi(value);
            }
            if (strcmp("NOTIFY_AT",id) == 0) {
                  setupdata.notify_at = atoi(value);
            }

            if (strcmp("CDDB_HOST",id) == 0) {
                  g_free(setupdata.cddb_host);
                  setupdata.cddb_host = g_strdup(value);
            }
            if (strcmp("CDDB_PORT",id) == 0) {
                  setupdata.cddb_port = atoi(value);
            }
            if (strcmp("CDDB_PROXY_HOST",id) == 0) {
                  g_free(setupdata.cddb_proxy_host);
                  setupdata.cddb_proxy_host = g_strdup(value);
            }
            if (strcmp("CDDB_PROXY_PORT",id) == 0) {
                  setupdata.cddb_proxy_port = atoi(value);
            }
            if (strcmp("CDDB_USE_HTTP",id) == 0) {
                  setupdata.cddb_use_http = atoi(value);
            }
            if (strcmp("CDDB_USE_PROXY",id) == 0) {
                  setupdata.cddb_use_proxy = atoi(value);
            }

            if (rootconf || setupdata.root_option_change_logoptions) {
                  if (strcmp("LOGFILE",id) == 0) {
                        g_free(setupdata.logfile);
                        setupdata.logfile = g_strdup(value);
                  }
                  if (strcmp("LOGLEVEL",id) == 0) {
                        setupdata.loglevel = atoi(value);
                  }
            }

            if (strcmp("LANGUAGE",id) == 0) {
                  g_free(setupdata.language);
                  setupdata.language = g_strdup(value);

                  /* check if that value is an integer */
                  if (atoi(value) != 0 || strcmp(value,"0") == 0) {
                        /* it is, so set empty language */
                        /* (we want to be backward compatible) */
                        g_free(setupdata.language);
                        setupdata.language = g_strdup("");
                  }
            }

            if (strcmp("OPTION_TOOLTIPS",id) == 0) {
                  setupdata.option_tooltips = atoi(value);
            }
            if (strcmp("OPTION_AUTORAISE",id) == 0) {
                  setupdata.option_autoraise = atoi(value);
            }
            if (strcmp("OPTION_SAVEPOS",id) == 0) {
                  setupdata.option_savepos = atoi(value);
            }
            if (strcmp("OPTION_PERSONIMAGE",id) == 0) {
                  setupdata.option_personimage = atoi(value);
            }
            if (strcmp("OPTION_OVERWRITEWARN",id) == 0) {
                  setupdata.option_overwritewarn = atoi(value);
            }
            if (strcmp("OPTION_AUTODELETE",id) == 0) {
                  setupdata.option_autodelete = atoi(value);
            }
            if (strcmp("OPTION_TITLEPROGRESS",id) == 0) {
                  setupdata.option_titleprogress = atoi(value);
            }
            if (strcmp("OPTION_DISPLAYCDTEXT",id) == 0) {
                  setupdata.option_displaycdtext = atoi(value);
            }
            if (strcmp("OPTION_SELECTIONMODE",id) == 0) {
                  setupdata.option_selectionmode = atoi(value);
            }
            if (strcmp("PRODVD_KEY",id) == 0) {
                  /* dont overwrite evtuelly set value with empty key */
                  if (strcmp(value,"") != 0) {
                        g_free(setupdata.ProDVDkey);
                        setupdata.ProDVDkey = g_strdup(value);
                  }
            }
            if (setupdata.option_savepos) {
                  if (strcmp("GEOMETRY_MAINWINDOW_X",id) == 0) {
                        setupdata.mainwindow.x = atoi(value);
                  }
                  if (strcmp("GEOMETRY_MAINWINDOW_Y",id) == 0) {
                        setupdata.mainwindow.y = atoi(value);
                  }
                  if (strcmp("GEOMETRY_MAINWINDOW_WIDTH",id) == 0) {
                        setupdata.mainwindow.width = atoi(value);
                  }
                  if (strcmp("GEOMETRY_MAINWINDOW_HEIGHT",id) == 0) {
                        setupdata.mainwindow.height = atoi(value);
                  }

                  if (strcmp("GEOMETRY_BURNWINDOW_X",id) == 0) {
                        setupdata.burnwindow.x = atoi(value);
                  }
                  if (strcmp("GEOMETRY_BURNWINDOW_Y",id) == 0) {
                        setupdata.burnwindow.y = atoi(value);
                  }
                  if (strcmp("GEOMETRY_BURNWINDOW_WIDTH",id) == 0) {
                        setupdata.burnwindow.width = atoi(value);
                  }
                  if (strcmp("GEOMETRY_BURNWINDOW_HEIGHT",id) == 0) {
                        setupdata.burnwindow.height = atoi(value);
                  }
            }

            /* do load the following information only when root */
            if (rootconf) {
                  if (strcmp("ROOT_USERS_ACCESS",id) == 0) {
                        setupdata.root_users_access = atoi(value);
                  }
                  if (strcmp("ROOT_USERS_LISTS",id) == 0) {
                        setupdata.root_users_lists = g_list_append(setupdata.root_users_lists, g_strdup(value));  
                  }
                  if (strcmp("ROOT_HOSTS_ACCESS",id) == 0) {
                        setupdata.root_hosts_access = atoi(value);
                  }
                  if (strcmp("ROOT_HOSTS_LISTS",id) == 0) {
                        setupdata.root_hosts_lists = g_list_append(setupdata.root_hosts_lists, g_strdup(value));  
                  }

                  if (strcmp("ROOT_OPTION_CHANGE_WRITER",id) == 0) {
                        setupdata.root_option_change_writer = atoi(value);
                  }
                  if (strcmp("ROOT_OPTION_CHANGE_WRITEPARAM",id) == 0) {
                        setupdata.root_option_change_writeparam = atoi(value);
                  }
                  if (strcmp("ROOT_OPTION_CHANGE_READER",id) == 0) {
                        setupdata.root_option_change_reader = atoi(value);
                  }
                  if (strcmp("ROOT_OPTION_CHANGE_READPARAM",id) == 0) {
                        setupdata.root_option_change_readparam = atoi(value);
                  }
                  if (strcmp("ROOT_OPTION_CHANGE_IMAGEDIRS",id) == 0) {
                        setupdata.root_option_change_imagedirs = atoi(value);
                  }
                  if (strcmp("ROOT_OPTION_CHANGE_LOGOPTIONS",id) == 0) {
                        setupdata.root_option_change_logoptions = atoi(value);
                  }
            }
      }
      /* now handle image dirs */
      if (!rootconf) {
            /* are we allowed to change image dirs? */
            if (setupdata.root_option_change_imagedirs) {
                  /* had we configured some yet? */
                  if (g_list_length(tmp_image_dirs) > 0) {
                        /* use user one */
                        copy_glist(&setupdata.image_dirs,
                              tmp_image_dirs);
                  }
            }
      }

      /* free temporary list */
      free_glist(&tmp_image_dirs);

      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      return 0;
}


/* parse a detailed toc line */

static void parse_toc_line(gchar *line) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar old_cddb_title[MAXLINE];
gchar old_cdtext_title[MAXLINE];
gchar old_cdtext_artist[MAXLINE];
gchar *p1;
gint min,sec,frm;
gint ret;

      /* to much tracks? */
      if (tocnr >= MAXTRACKS) {
            g_error("over %d tracks in toc\n",MAXTRACKS);
      }

      strcpy(old_cddb_title,"");
      strcpy(old_cdtext_title,"");
      strcpy(old_cdtext_artist,"");

      /* allocate memory for new line (free first old memory)*/
      if (trackinfo[tocnr] != NULL) {
            g_free(trackinfo[tocnr]->volname);

            /* backup old cdtext */
            if (trackinfo[tocnr]->title) {
                  strncpy(old_cdtext_title, trackinfo[tocnr]->title, MAXLINE);
            }
            g_free(trackinfo[tocnr]->title);
            /* backup old cdtext */
            if (trackinfo[tocnr]->artist) {
                  strncpy(old_cdtext_artist, trackinfo[tocnr]->artist, MAXLINE);
            }
            g_free(trackinfo[tocnr]->artist);

            /* backup old cddb-title  */
            if (trackinfo[tocnr]->cddb_ttitle != NULL) {
                  strncpy(old_cddb_title, trackinfo[tocnr]->cddb_ttitle, MAXLINE);
            }
            g_free(trackinfo[tocnr]->cddb_ttitle);
            g_free(trackinfo[tocnr]);
      }
      trackinfo[tocnr] = g_new0(track_info_t,1);

      /* when the cd is still the same as last time, restore cddb-title */
      if (cd_is_still_the_same == 1) {
            /* got a backuped title? */
            if (strcmp(old_cddb_title,"") != 0) {
                  trackinfo[tocnr]->cddb_ttitle = g_strdup(old_cddb_title); 
            }
      }

      /* now we are prepared to fill structure */
      strcpy(tmp,line+1);
      p1 = strtok(tmp,":");
      if (p1 == NULL) {
            g_error("Unexpected output in cdda2wav toc-output\n");
      }
      trackinfo[tocnr]->track_nr = atoi(p1);
      trackinfo[tocnr]->isosize = -1;

      /* reststring into tmp2 - strip to remove leading spaces */
      p1 = strtok(NULL,"");
      strcpy(tmp2,p1);
      strip_string(tmp2);

      p1 = strtok(tmp2," ");
      trackinfo[tocnr]->start_sec = atoi(p1);

      p1 = strtok(NULL,"");
      if (p1 == NULL) {
            g_error("Unexpected output in cdda2wav toc-output\n");
      }
      strcpy(tmp,p1);
      strip_string(tmp);

      /* now get tracklength - convert to frames */
      p1 = strtok(tmp," ");
      sscanf(p1,"%d:%d.%d",&min,&sec,&frm);
      trackinfo[tocnr]->size = (min*60+sec)*75 + frm;

      /* tracktype */
      p1 = strtok(NULL," ");
      if (strncmp(p1,"data",4) == 0) {
            /* data-track */
            trackinfo[tocnr]->type = 0;

            p1 = strtok(NULL," ");
            if (strncmp(p1,"uninterrupted",13) == 0) {
                  trackinfo[tocnr]->rec_type = 1;
            } else {
                  trackinfo[tocnr]->rec_type = 0;
            }

            p1 = strtok(NULL," ");
            if (strncmp(p1,"copydenied",10) == 0) {
                  trackinfo[tocnr]->copyperm = 0;
            } else {
                  trackinfo[tocnr]->copyperm = 1;
            }     
            if (cd_is_still_the_same == 1) {
                  /* use cached cd-text */
                  trackinfo[tocnr]->title = g_strdup(old_cdtext_title);
                  trackinfo[tocnr]->artist = g_strdup(old_cdtext_artist);
            }
      } else {
            /* audio-track */
            trackinfo[tocnr]->type = 1;
            
            p1 = strtok(NULL," ");
            if (strncmp(p1,"linear",6) == 0) {
                  trackinfo[tocnr]->preemp = 0;
            } else {
                  trackinfo[tocnr]->preemp = 1;
            }

            p1 = strtok(NULL," ");
            if (strncmp(p1,"copydenied",10) == 0) {
                  trackinfo[tocnr]->copyperm = 0;
            } else {
                  trackinfo[tocnr]->copyperm = 1;
            }     

            p1 = strtok(NULL," ");
            if (strncmp(p1,"stereo",6) == 0) {
                  trackinfo[tocnr]->stereo = 1;
            } else {
                  trackinfo[tocnr]->stereo = 0;
            }     

            p1 = strtok(NULL," ");
            p1 = strtok(NULL,"");
            if (p1) {
                  strcpy(tmp2,p1);
                  strip_string(tmp2);
                  ret = decode_title_artist(tmp2,tmp,tmp3);
                  if (ret != 0) {
                        g_error("got unexpected artist/title\n");
                  }

                  if (cd_is_still_the_same == 1) {
                        if (tmp[0] == '\0') {
                              /* no new data, use cached */
                              trackinfo[tocnr]->title = g_strdup(old_cdtext_title);
                        }  else {
                              trackinfo[tocnr]->title = g_strdup(tmp);
                        }
                        if (tmp3[0] == '\0') {
                              /* no new data, use cached */
                              trackinfo[tocnr]->artist = g_strdup(old_cdtext_artist);
                        } else {
                              trackinfo[tocnr]->artist = g_strdup(tmp3);
                        }     
                  } else {
                        trackinfo[tocnr]->title = g_strdup(tmp);
                        trackinfo[tocnr]->artist = g_strdup(tmp3);
                  }
            } else {
                  trackinfo[tocnr]->title = g_strdup("");
                  trackinfo[tocnr]->artist = g_strdup("");
            }
      }     

      
      tocnr++;
}


/* print memory-structure with toc-data (debug purposes) */

static void print_cdinfo() {
gint i;
gchar *p1, *p2, *p3, *p4;
gchar tmp[] = "(NULL)";

      dodebug(2,"------ cdinfo-structure -----\n");
      dodebug(2,"nr_tracks: %d\n",cdinfo.nr_tracks);
      dodebug(2,"total_size: %d\n",cdinfo.total_size);
      dodebug(2,"cddb_discid: %s\n",cdinfo.cddb_discid);
      dodebug(2,"have_cdtext: %d, have_cdextra: %d\n",cdinfo.have_cdtext,
             cdinfo.have_cdextra);
      if (cdinfo.title != NULL && cdinfo.artist != NULL) {
            dodebug(2,"title/artist: %s/%s\n",cdinfo.title,cdinfo.artist);
      } else {
            dodebug(2,"title/artist: (NULL)/(NULL)\n");
      }
      if (cdinfo.cddb_dtitle != NULL) {
            dodebug(2,"cddb_dtitle: %s\n",cdinfo.cddb_dtitle);
      } else {
            dodebug(2,"cddb_dtitle: (NULL)\n");
      }
      dodebug(2,"leadout: %d\n", cdinfo.leadout);

      for (i = 0; i < cdinfo.nr_tracks; i++) {

            dodebug(2,"track: %d start: %d size: %d\n",trackinfo[i]->track_nr,
                  trackinfo[i]->start_sec, trackinfo[i]->size);
            dodebug(2,"       type: %d, rec_type: %d, preemp: %d, copyperm: %d, stereo: %d\n", 
                  trackinfo[i]->type, trackinfo[i]->rec_type,
                  trackinfo[i]->preemp, trackinfo[i]->copyperm,
                  trackinfo[i]->stereo);
            /* check if we have any null-pointers lying around */
            p1 = trackinfo[i]->title;
            p2 = trackinfo[i]->artist;
            p3 = trackinfo[i]->cddb_ttitle;
            p4 = trackinfo[i]->volname;
            if (p1 == NULL) p1 = tmp;
            if (p2 == NULL) p2 = tmp;
            if (p3 == NULL) p3 = tmp;
            if (p4 == NULL) p4 = tmp;

            dodebug(2,"       title/artist: %s/%s cddb_title: %s volname: %s\n", 
                  p1, p2, p3, p4);
      }
}


/* interpret line for line the output of cdda2wav */

static gint parse_toc(gchar *line) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar *p,*p1;
gint min,sec,frm;
gint ret;
gint mmaperror;

      mmaperror = 0;

      /* initial state */
      if (tocstate == 0) {
            /* mmap error? */
            if (strstr(line,"annot get mmap for")) {
                  mmaperror = 1;
            }

            /* first look for "Tracks" line */
            if (strncmp(line,"Tracks:",7) == 0) {
                  strcpy(tmp,line+7);
                  p1 = strtok(tmp," ");
                  strcpy(tmp2,p1);
                  cdinfo.nr_tracks = atoi(tmp2);
                  p1 = strtok(NULL,"");
                  strcpy(tmp2,p1);
                  sscanf(tmp2,"%d:%d.%d",&min,&sec,&frm);               
                  cdinfo.total_size = (min*60+sec)*75 + frm;
            }
            if (strncmp(line,"CDINDEX",7) == 0) {
                  /* we dont support cdindex right now */
                  ;
            }
            if (strncmp(line,"CDDB",4) == 0) {
                  strcpy(tmp,line+15);
                  strip_string(tmp);
                  strcpy(cdinfo.cddb_discid,tmp);

                  /* check if the cd we have in the drive is the same
                     as the last cd we got */
                  if (strcmp(cdinfo_cddb_title_bak, cdinfo.cddb_discid) == 0) {
                        cd_is_still_the_same = 1;
                  }
      
                  /* finished with state 0 */
                  tocstate = 1;
            }

            /* get next line from output */
            return mmaperror;
      }

      /* cd-text state */
      if (tocstate == 1) {
            if (strncmp(line,"CD-Text: detected",17) == 0) {
                  cdinfo.have_cdtext = 1;
            }
            if (strncmp(line,"CD-Text: not detected",21) == 0) {
                  cdinfo.have_cdtext = 0;
            }

            /* ignore any cd-text-output for now */
            ;

            if (strncmp(line,"CD-Extra: ",10) == 0) {
                  /* see this as endmarker of cd-text section */
                  tocstate = 2;
            }
            
            /* dont return here because we may need the current line */
      }

      /* cd-extra state */
      if (tocstate == 2) {
            if (strncmp(line,"CD-Extra: detected",18) == 0) {
                  cdinfo.have_cdextra = 1;
            }
            if (strncmp(line,"CD-Extra: not detected",22) == 0) {
                  cdinfo.have_cdextra = 0;
            }

            /* ignore any cd-extra-output for now */
            ;
            
            if (strstr(line,"Album title:") != NULL) {
                  /* see this as endmarker of cd-extra section */
                  tocstate = 3;
            }
            /* dont return here because we may need the current line */
      }
      
      /* toc-listing mode */
      if (tocstate == 3) {
            if ((p = strstr(line,"Album title:")) != NULL) {
                  strcpy(tmp,p+13);
                  strip_string(tmp);
                  ret = decode_title_artist(tmp,tmp2,tmp3);
                  if (ret != 0) {
                        g_error("got unexpected artist/title\n");
                  }     
                  g_free(cdinfo.title);
                  cdinfo.title = g_strdup(tmp2);
                  g_free(cdinfo.artist);
                  cdinfo.artist = g_strdup(tmp3);
            }

            /* now the most complex part: the toc-list itself */
            if (line[0] == 'T' && line[3] == ':') {
                  parse_toc_line(line);
            }     

            if (strncmp(line,"Leadout:",8) == 0) {
                  strcpy(tmp,line+8);
                  strip_string(tmp);
                  cdinfo.leadout = atoi(tmp);
            }
      }

      return 0;
}


/* called when reading the TOC of ATAPI cdroms takes to long */

static gint getcdtoc_atapi_timeout_func(gpointer data) {

      getcdtoc_atapi_timeout_dialog = show_dialog_wait(ICO_INFO,
            _("Checking drive for a medium.\n\nUsing scsi-emulation for that drive would speed up\nthis considerably. Please note that inserting a\nmedium would also reduce the wait time."));

      return (FALSE);
}


static void getcdtoc_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];


        /* read output of getcdtoc */
        n = read_line_wait(source, line, MAXLINE);

        /* getcdtoc finished */
        if (n <= 0) {
                gtk_input_remove(readcdda_callback);

                /* pick up return status of child */
                wait(&ret);

                /* tell our caller that we are done here */
                read_done = WEXITSTATUS(ret);

                return;
        }

      dodebug(10,"readtoc: %s\n", line);

      count_mmaperror += parse_toc(line);
}


/* call cdda2wav -J to get the cd-toc */
/* add ATAPI long-delay warning window */

void get_cd_toc(gint devnr) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gint ret, dvdsize, read_out;
gchar old_cdtext_title[MAXLINE];
gchar old_cdtext_artist[MAXLINE];
gint getcdtoc_timeout;

      /* get bus,id,lun string */
      if (convert_devnr2busid(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      getcdtoc_atapi_timeout_dialog = NULL;
      getcdtoc_timeout = 0;

      /* ATAPI device? (only on linux) */
      if (strstr(tmp, "ATAPI")) {
            /* if it does take longer than 5 seconds, display warning */
            getcdtoc_timeout = gtk_timeout_add(5000,
                  getcdtoc_atapi_timeout_func, NULL);
      }
      
      /* check if cd is loaded */
      if (!check_medium_loaded(devnr)) {
            /* not loaded */
            cdinfo.nr_tracks = -1;
      
            if (getcdtoc_timeout) {
                  /* remove timeout, if it did not kick in yet */
                  gtk_timeout_remove(getcdtoc_timeout);
            }     
            if (getcdtoc_atapi_timeout_dialog) {
                  /* and remove the dialog wait window */
                  show_dialog_wait_remove(getcdtoc_atapi_timeout_dialog);
            }     

            return;
      }

      cdinfo.have_cdtext = -1;
      cdinfo.have_cdextra = -1;
      cdinfo.nr_tracks = -1;
      
      read_done = 999;
      tocstate = 0;
      tocnr = 0;
      cd_is_still_the_same = 0;
      count_mmaperror = 0;


      /* backup cddb-value to check if the new cd is the same as
         the last we read */
      strncpy(cdinfo_cddb_title_bak, cdinfo.cddb_discid, MAXLINE);

      /* backup current cd-text album info */
      if (cdinfo.title) {
            strncpy(old_cdtext_title, cdinfo.title, MAXLINE);
      } else {
            strcpy(old_cdtext_title, "");
      }
      if (cdinfo.artist) {
            strncpy(old_cdtext_artist, cdinfo.artist, MAXLINE);
      } else {
            strcpy(old_cdtext_artist, "");
      }

      /* build command line */
      get_wrap_path("CDDA2WAV",tmp2);
      g_snprintf(line,MAXLINE,"%s -D \"%s\" -J -g -Q -H -v toc,summary,sectors,titles", tmp2,tmp);

      dodebug(1,"spawning: %s\n", line);

        readcdda_pid = full_dpl_pipe3(NULL,NULL,&read_out,line,0);
        readcdda_pid2 = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);

        readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
                (GdkInputFunction) getcdtoc_out, NULL);

        /* now wait until toc is read */
        while (read_done == 999) {
                wait_and_process_events();
        }

        close(read_out);

      ret = read_done;

      /* error while reading tracks? */
      if (ret != 0 && cdinfo.nr_tracks != tocnr) {
            cdinfo.nr_tracks = -2;
      }

      /* cd loaded but not readable = empty recordable? */
      if (ret != 0 && cdinfo.nr_tracks < 1 ) {
            cdinfo.nr_tracks = -2;
      }

      /* if cd changed, clear out cddb_dtitle */
      if (cd_is_still_the_same == 0) {
            g_free(cdinfo.cddb_dtitle);
            cdinfo.cddb_dtitle = NULL;
      } else {
            /* cd stayed the same, restore album cd-text */
            if (cdinfo.title[0] == '\0' && old_cdtext_title[0] != '\0') {
                  g_free(cdinfo.title);
                  cdinfo.title = g_strdup(old_cdtext_title);
            }
            if (cdinfo.artist[0] == '\0' && old_cdtext_artist[0] != '\0') {
                  g_free(cdinfo.artist);
                  cdinfo.artist = g_strdup(old_cdtext_artist);
            }
      }

      /* now a workaround for a broken cdda2wav when it comes to
         read the toc of a DVD - use cdrecord -toc instead */
      if (cdinfo.nr_tracks == 1 && (cdinfo.leadout == 1151850 || cdinfo.leadout == 1151849 || cdinfo.leadout == 449849)) {
            /* this is slow, so only use it in that rare case */  
            dvdsize = get_cdrecord_toc(devnr);
            if (dvdsize > 0) {
                  /* overwrite faulty values by the real ones */
                  cdinfo.leadout = dvdsize;
                  trackinfo[0]->size = dvdsize;

                  /* 1152000 is 256:00.00 which is not right */
                  /* 449999 is  100:00.00 -1 frame */
/*                if (cdinfo.total_size == 1152000 || cdinfo.total_size == 1151999 || cdinfo.total_size == 449999) {
                        cdinfo.total_size = dvdsize + 150;
                  } */
                  cdinfo.total_size = dvdsize + 150;
            }
      }

      /* have we hit the mmap error? */
      if (count_mmaperror > 0) {
                ret = show_dialog(ICO_WARN, _("Warning: The cdrtools binaries you have installed are\nnot compatible with your system. You will NOT be\nable to read or write CDs. Please read the FAQ\non www.xcdroast.org for more information."), T_ANYWAY, _("Exit"), NULL, 1);
                if (ret == 1) 
                        gtk_exit(1);
      }

      if (getcdtoc_timeout) {
            /* remove timeout, if it did not kick in yet */
            gtk_timeout_remove(getcdtoc_timeout);
      }     
      if (getcdtoc_atapi_timeout_dialog) {
            /* and remove the dialog wait window */
            show_dialog_wait_remove(getcdtoc_atapi_timeout_dialog);
      }     

      if (debug) print_cdinfo();

}


/* start subprocess and reroute stdin and stdout */
/* use /bin/sh to spawn subprocess */

pid_t full_dpl_pipe_shell(gint *out, gint *in, gchar *cmd) {
gint fd1[2], fd2[2];
pid_t pid;

      if (pipe(fd1) <0 || pipe(fd2) <0) {
            g_error("pipe error\n");
      }

      if (( pid = fork()) < 0) {
            g_error("fork error\n");
      } else 
      if (pid > 0) {
            /* parent */
            close(fd1[0]);
            close(fd2[1]);

            /* return new stdout/stdin of child */
            if (in != NULL) 
                  *in = fd1[1];
            else
                  close(fd1[1]);

            if (out != NULL)
                  *out = fd2[0];
            else
                  close(fd2[0]);

      } else {

            /* needed for correct rights in nonroot mode */
            /* fix_guid(); */

            /* child */
            close(fd1[1]);
            close(fd2[0]);

            /* reroute stdin from child */
            if (fd1[0] != STDIN_FILENO) {
                  if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
                        g_error("dup2 error on stdin\n");
                  }
                  close(fd1[0]);
            }
            /* reroute stdout from child */
            if (fd2[1] != STDOUT_FILENO) {
                  if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
                        g_error("dup2 error on stdout\n");
                  }
                  close(fd2[1]);
            }

            /* startup child */
            if (execl("/bin/sh", "sh", "-c", cmd ,(void *)NULL) < 0) {
                  g_error("execl error\n");
            }
 
      }

      return(pid);
}


/* rebuild a cmdline-string into a list of arguments..handle quotes and
   escaped chars nicely */

static void rebuild_cmdline(char **arglist, gchar *cmd, gchar *callpath) {
gchar tmp[MAXLINE*10];
gchar *p;
gint n, count, start, in_quotes;
gchar oldc, c;

      n = 0;
      count = 0;
      start = 0;
      in_quotes = 0;
      oldc = '\0';
      for (n = 0; n <= strlen(cmd); n++) {
            c = cmd[n];

            /* quotes found? search for closing quote */
            /* ignore escaped quotes */
            if (c == '\"' && oldc != '\\') {
                  if (in_quotes == 0) {
                        in_quotes = 1;
                  } else {
                        /* end-quote found */
                        in_quotes = 0;
                  }
            }
            oldc = c;

            /* space is delimitor between args */
            if (in_quotes == 0 && (c == ' ' || c == '\0')) {
                  strncpy(tmp,cmd+start,n-start);
                  tmp[n-start] = '\0';

                  /* skip empty args */
                  if (n-start == 0) {
                        continue;
                  }
                  strip_string(tmp);

                  /* tmp does contain now our substr -
                     remove surrounding quotes if any and
                     remove any escaped-chars */
                  if (tmp[0] == '\"') {
                        p = tmp + 1;
                  } else {
                        p = tmp;
                  }
 
                  if (tmp[strlen(tmp)-1] == '\"') {
                        tmp[strlen(tmp)-1] = '\0';
                  }
                  escape_parse(p); 

                  /* empty unquoted string? skip */
                  if (p == tmp && strcmp(p,"") == 0) {
                        continue;
                  }
      
                  arglist[count] = g_strdup(p);
                  count++;
                  start = n+1;
            }     

            if (count >= MAXPIPEARGS) {
                  g_error("Error: More than %d cmd arguments given\n",MAXPIPEARGS);
            }
      }

      /* now remove path from first argument */
      strncpy(callpath,arglist[0], MAXLINE);
      strncpy(tmp,arglist[0], MAXLINE*10);
      p = rindex(tmp,'/');
      if (p != NULL) {
            g_free(arglist[0]);
            arglist[0] = g_strdup(p+1);
      }     

      /* now arglist is finished */

      /* output generated argument-list */
      if (debug) {
            dodebug(11,"----- created argument array for execv -----\n");
            count = 0;
            dodebug(11,":%s:\n",callpath);
            while(arglist[count]) {
                  dodebug(11,":%s:\n",arglist[count]);
                  count++;
            }
      }
}



/* create a bidirectional pipe */

static gint my_s_pipe(gint fd[2], gint use_socketpair) {

      if (use_socketpair == 1) {
#if defined(HAVE_SOCKETPAIR) && HAVE_SOCKETPAIR == 1
            return (socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
#else
            /* socketpair not available - fallback */
            return (pipe(fd));
#endif
      } else {
            return (pipe(fd));
      }
}


/* start subprocess and reroute stdin, stderr and stdout */
/* does NOT use the shell as spawner */

static pid_t full_dpl_pipe3(gint *out, gint *in, gint *err, gchar *cmd, 
      gint use_socketpair) { 
gint fd1[2], fd2[2], fd3[2];
gchar **arglist;
gchar callpath[MAXLINE];
pid_t pid;
gint count;

      /* rebuild cmdline to array of args for execv */
      arglist = g_new0(gchar *, MAXPIPEARGS);
      rebuild_cmdline(arglist, cmd, callpath);

      /* do the pipe-stuff */
      if (my_s_pipe(fd1, use_socketpair) < 0 || 
          my_s_pipe(fd2, use_socketpair) < 0 || 
          my_s_pipe(fd3, use_socketpair) < 0) {
            g_error("pipe error\n");
      }

      if (( pid = fork()) < 0) {
            g_error("fork error\n");
      } else 
      if (pid > 0) {
            /* parent */
            close(fd1[0]);
            close(fd2[1]);
            close(fd3[1]);

            /* return new stdout/stdin/stderr of child */
            if (in != NULL) 
                  *in = fd1[1];
            else
                  close(fd1[1]);

            if (out != NULL)
                  *out = fd2[0];
            else
                  close(fd2[0]);

            if (err != NULL)
                  *err = fd3[0];
            else 
                  close(fd3[0]);
      } else {

            /* needed for correct rights in nonroot mode */
            /* fix_guid(); */

            /* child */
            close(fd1[1]);
            close(fd2[0]);
            close(fd3[0]);

            /* reroute stdin from child */
            if (fd1[0] != STDIN_FILENO) {
                  if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
                        g_error("dup2 error on stdin\n");
                  }
                  close(fd1[0]);
            }
            /* reroute stdout from child */
            if (fd2[1] != STDOUT_FILENO) {
                  if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
                        g_error("dup2 error on stdout\n");
                  }
                  close(fd2[1]);
            }
            /* reroute stderr from child */
            if (fd3[1] != STDERR_FILENO) {
                  if (dup2(fd3[1], STDERR_FILENO) != STDERR_FILENO) {
                        g_error("dup2 error on stderr\n");
                  }
                  close(fd3[1]);
            }

            /* startup child */
            if (execv(callpath,arglist) < 0) {
                  g_error("execv error\n");
            }
 
      }

      /* free arglist */
      count = 0;
      while(arglist[count]) {
            g_free(arglist[count]);
            count++;
      }
      g_free(arglist);

      return(pid);
}


/* start two subprocesses and connect stdout of the first with stdin
   of the second (proc1 | proc2) and reroute stdin and stderr of the
   first and stdout and stderr of the second */
/* returns pidnr1 and pidnr2 */

static void full_dpl_pipe4(pid_t *pidnr1, pid_t *pidnr2, gint *in1, gint *err1, 
                gchar *cmd, gint *out2, gint *err2, gchar *cmd2,
                gint use_socketpair) {
gint fd1[2], fd2[2], fd3[2], fd4[2], pipefd[2];
gchar **arglist;
gchar **arglist2;
gchar callpath[MAXLINE];
gchar callpath2[MAXLINE];
pid_t pid, pid2;
gint count;

      /* rebuild cmdline to array of args for execv */
      arglist = g_new0(gchar *, MAXPIPEARGS);
      arglist2 = g_new0(gchar *, MAXPIPEARGS);
      rebuild_cmdline(arglist, cmd, callpath);
      rebuild_cmdline(arglist2, cmd2, callpath2);

      /* do the pipe-stuff */
      if (my_s_pipe(fd1, use_socketpair) < 0 || 
          my_s_pipe(fd2, use_socketpair) < 0 || 
          my_s_pipe(fd3, use_socketpair) < 0 ||
          my_s_pipe(fd4, use_socketpair) < 0 || 
          my_s_pipe(pipefd, use_socketpair) < 0) {
            g_error("pipe error\n");
      }

      /* fork for first process */
      if (( pid = fork()) < 0) {
            g_error("fork error\n");
      } else 
      if (pid > 0) {
            /* parent */
            close(fd1[0]);
            close(fd2[1]);
            close(pipefd[1]);

            /* return new fds of child */
            if (in1 != NULL) 
                  *in1 = fd1[1];
            else
                  close(fd1[1]);

            if (err1 != NULL)
                  *err1 = fd2[0];
            else
                  close(fd2[0]);

      } else {
            /* needed for correct rights in nonroot mode */
            /* fix_guid(); */

            /* child */
            close(fd1[1]); 
            close(fd2[0]);
            close(pipefd[0]);

            /* reroute stdin from child */
            if (fd1[0] != STDIN_FILENO) {
                  if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
                        g_error("dup2 error on stdin\n");
                  }
                  close(fd1[0]);
            }

            /* reroute stderr from child */
            if (fd2[1] != STDERR_FILENO) {
                  if (dup2(fd2[1], STDERR_FILENO) != STDERR_FILENO) {
                        g_error("dup2 error on stderr\n");
                  }
                  close(fd2[1]);
            }

            /* reroute stdout from child to second child */
            if (pipefd[1] != STDOUT_FILENO) {
                  if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
                        g_error("dup2 error on stdout\n");
                  }
                  close(pipefd[1]); 
            } 

            /* startup first child */
            if (execv(callpath,arglist) < 0) {
                  g_error("execv error\n");
            }
      }


      /* fork for second process */
      if (( pid2 = fork()) < 0) {
            g_error("fork error\n");
      } else 
      if (pid2 > 0) {
            /* parent */
            close(fd3[1]);
            close(fd4[1]);
            close(pipefd[0]);

            /* return new fds of child */
            if (out2 != NULL)
                  *out2 = fd3[0];
            else
                  close(fd3[0]);

            if (err2 != NULL)
                  *err2 = fd4[0];
            else 
                  close(fd4[0]);

      } else {

            /* needed for correct rights in nonroot mode */
            /* fix_guid(); */

            /* child */
            close(fd3[0]);
            close(fd4[0]);
            close(pipefd[1]);

            /* reroute stdin from first child */
            if (pipefd[0] != STDIN_FILENO) {
                  if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
                        g_error("dup2 error on stdin\n");
                  }
                  close(pipefd[0]); 
            }

            /* reroute stderr from child */
            if (fd4[1] != STDERR_FILENO) {
                  if (dup2(fd4[1], STDERR_FILENO) != STDERR_FILENO) {
                        g_error("dup2 error on stdout\n");
                  }
                  close(fd4[1]);
            }

            /* reroute stdout from child to second child */
            if (fd3[1] != STDOUT_FILENO) {
                  if (dup2(fd3[1], STDOUT_FILENO) != STDOUT_FILENO) {
                        g_error("dup2 error on stdout\n");
                  }
                  close(fd3[1]);
            }

            /* startup second child */
            if (execv(callpath2,arglist2) < 0) {
                  g_error("execv error\n");
            }
      }

      /* free arglists */
      count = 0;
      while(arglist[count]) {
            g_free(arglist[count]);
            count++;
      }
      g_free(arglist);
      count = 0;
      while(arglist2[count]) {
            g_free(arglist2[count]);
            count++;
      }
      g_free(arglist2);

      /* return pids by call by reference */
      *pidnr1 = pid;
      *pidnr2 = pid2;
}


/* get the master-volume */
/* return val 0..100 or -1 or error */

gint query_mixer() {
#if !(defined(__MACH__) && defined(__APPLE__)) 
gint mix;
#endif
#if defined(linux) || defined(__FreeBSD__)
gint val;
#endif
#if defined(sun) || defined(__OpenBSD__)
audio_info_t ainfo;
#endif
#ifdef hpux
# ifndef hpux_alib
struct audio_gain again;
# endif
#endif


      if (strcmp(setupdata.mix_device,"") == 0) {
            /* no mixer found - ignore */
            return -1;
      }

#if defined(linux) || defined(__FreeBSD__)

      dodebug(10,"quering mixer %s\n", setupdata.mix_device);
      mix = open(setupdata.mix_device, O_RDWR);
      if (mix < 0) {
            g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
            return -1;
      }

      if (ioctl(mix,MIXER_READ(0),&val) == -1) {
            g_warning("Error reading mixer\n");
            return -1;
      }     

      close(mix);

      /* average val of both channels */
      return ((val & 0x7f) + ((val >> 8) & 0x7f))/2;

#endif
#if defined(sun) || defined(__OpenBSD__)

      dodebug(10,"quering mixer %s\n", setupdata.mix_device);
      mix = open(setupdata.mix_device, O_RDONLY);
      if (mix < 0) {
            g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
            return -1;
      }

      if (ioctl(mix, AUDIO_GETINFO, &ainfo) == -1) {
            g_warning("Error reading mixer\n");
            return -1;
      }

      close(mix);

      return ((gint) ((gfloat) ainfo.play.gain / 2.55));

#endif
#ifdef aix
       /* Due we are using the raw aix audio api, we    */
       /* are not able to query the gain settings :-(   */
       /* set the gain to the max. value and return 100 */
       memset ( & achange, '\0', sizeof (achange));
       memset ( & acontrol, '\0', sizeof (acontrol));

       /* Initialise with the max gain =2147418112      */
       achange.balance        = 0x3fff0000;
       achange.balance_delay  = 0;
       achange.volume         = 2147418112;
       achange.volume_delay   = 0;
       achange.input          = AUDIO_IGNORE;
       achange.output         = AUDIO_IGNORE;
       achange.output         = AUDIO_IGNORE;
       achange.treble         = AUDIO_IGNORE;
       achange.bass           = AUDIO_IGNORE;
       achange.pitch          = AUDIO_IGNORE;
       achange.monitor        = AUDIO_IGNORE;
       achange.dev_info       = (char *) NULL;
       acontrol.ioctl_request = AUDIO_CHANGE;
       acontrol.position      = 0;
       acontrol.request_info  = (char *) & achange;

       if ((mix = open(setupdata.mix_device, O_RDONLY)) == -1) {
                g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
                return -1;
        }
       if (ioctl (mix, AUDIO_CONTROL, & acontrol) == -1) {
               g_warning("Error reading mixer\n");
               return -1;
       }
       close(mix);

       return (100);
#endif
#ifdef hpux
# ifndef hpux_alib
        dodebug(10,"quering mixer %s\n", setupdata.mix_device);
      if ((mix = open(setupdata.mix_device, O_RDONLY)) == -1) {
                g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
                return -1;
        }
      if (ioctl(mix, AUDIO_GET_GAINS, &again) == -1) {
                g_warning("Error reading mixer\n");
            return -1;
      }
      close(mix);
      return ((gint) ((gfloat) (again.transmit_gain - AUDIO_OFF_GAIN)
                  / (gfloat) (AUDIO_MAX_GAIN - AUDIO_OFF_GAIN) * 100.0));
# else
      /* The audio tranmission gains are set by some */
      /* environment variables or a fancy program    */
      /* like the AudioCP                            */
      return (0);
# endif
#endif

      return 0;
}


/* set the master-volume */
/* returns 0 on ok, -1 on error */

gint set_mixer(gint val) {
#if !(defined(__MACH__) && defined(__APPLE__)) 
gint mix;
#endif
#if defined(sun) || defined(__OpenBSD__)
audio_info_t ainfo;
#endif
#ifdef aix
audio_change   achange;
audio_control  acontrol;
#endif
#ifdef hpux
# ifndef hpux_alib
struct audio_gain again;
# endif
#endif

      if (strcmp(setupdata.mix_device,"") == 0) {
            /* no mixer found - ignore */
            return -1;
      }

#if defined(linux) || defined(__FreeBSD__)

      dodebug(10,"setting mixer %s to %d\n", setupdata.mix_device, val);
      mix = open(setupdata.mix_device, O_RDWR);
      if (mix < 0) {
            g_warning("Can't open mixer-device\n");
            return -1;
      }

      val |= val << 8;
      if (ioctl(mix, MIXER_WRITE(0), &val) == -1) {
            g_warning("Error writing mixer\n");
            return -1;
      }

      close(mix);

#endif 
#if defined(sun) || defined(__OpenBSD__)

      dodebug(10,"setting mixer %s to %d\n", setupdata.mix_device, val);
      mix = open(setupdata.mix_device, O_WRONLY);
      if (mix < 0) {
            g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
            return -1;
      }

      AUDIO_INITINFO(&ainfo);
      ainfo.play.gain = (gint) (2.55 * (gfloat) val);

      if (ioctl(mix, AUDIO_SETINFO, &ainfo) == -1) {
            g_warning("Error writing mixer\n");
            return -1;
      }

      close(mix);
#endif
#ifdef aix
       memset ( & achange, '\0', sizeof (achange));
       memset ( & acontrol, '\0', sizeof (acontrol));

       /* Initialise with the max gain =2147418112      */
       achange.balance        = AUDIO_IGNORE;
       achange.balance_delay  = AUDIO_IGNORE;
       achange.volume         = (long) (21474181.12 * (gfloat) val);
       achange.volume_delay   = 0;
       achange.input          = AUDIO_IGNORE;
       achange.output         = AUDIO_IGNORE;
       achange.output         = AUDIO_IGNORE;
       achange.treble         = AUDIO_IGNORE;
       achange.bass           = AUDIO_IGNORE;
       achange.pitch          = AUDIO_IGNORE;
       achange.monitor        = AUDIO_IGNORE;
       achange.dev_info       = (char *) NULL;
       acontrol.ioctl_request = AUDIO_CHANGE;
       acontrol.position      = 0;
       acontrol.request_info  = (char *) & achange;

       if ((mix = open(setupdata.mix_device, O_RDONLY)) == -1) {
                g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
                return -1;
        }
       if (ioctl (mix, AUDIO_CONTROL, & acontrol) == -1) {
               g_warning("Error reading mixer\n");
               return -1;
       }
       close (mix);
#endif
#ifdef hpux
# ifndef hpux_alib
        dodebug(10,"setting mixer %s to %d\n", setupdata.mix_device, val);
      if ((mix = open(setupdata.mix_device, O_RDWR)) == -1) {
                g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
                return -1;
        }
      /* Query the receive/transmit/monitor gains */
      again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
      ioctl(mix,AUDIO_GET_GAINS,&again);

      /* Calculate the new transmit gain */
      again.cgain[0].transmit_gain = AUDIO_OFF_GAIN 
              + (gfloat) ((AUDIO_MAX_GAIN - AUDIO_OFF_GAIN) * val) * 0.01;
      again.cgain[1].transmit_gain = again.cgain[0].transmit_gain;
      again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;

      /* Set the new gains (only transmit gain actually changed) */
      if (ioctl(mix, AUDIO_SET_GAINS, &again) == -1) {
              g_warning("Error setting audio gain\n");
                return -1;
      }
      close(mix);
# else
      /* The audio tranmission gains are set by some */
      /* environment variables or a fancy program    */
      /* like the AudioCP                            */
      return 0;
# endif
#endif

      return 0;   
}


/* send SIGINT to a cdda2wav/readcd/cdrecord process (btw to its child) 
   and hope that it terminates at it own */

void kill_readcdda() {

      /* stop any timers watching for cdrecord output */
      if (cdrtimer) {
            gtk_timeout_remove(cdrtimer);
            cdrtimer = 0;
      }

      if (readcdda_pid != -1) {

            dodebug(2,"sending SIGINT to %d\n", (gint) readcdda_pid);
            kill(readcdda_pid, SIGINT);
      }
      if (readcdda_pid2 != -1) {

            dodebug(2,"sending SIGINT to %d\n", (gint) readcdda_pid2);
            kill(readcdda_pid2, SIGINT);
      }
}


/* in bulk mode update the info-label of read tracks */

static void update_bulk_readlabel() {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gint frms;

      frms = writeparams.frames[read_tracknr];
      convert_frames2mbminstring(frms, tmp);
      g_snprintf(tmp2,MAXLINE,_("Reading audio track %d/%d [%s]"), read_tracknr,
                  writeparams.nrtracks, tmp);
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), tmp2);
}


/* parse output of cdda2wav and update sliders */

static void read_cdda2wav_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;
gint val, tnr, bulk;
gfloat pval, pval2;

      /* called for bulk or not? */
      bulk = GPOINTER_TO_INT(data);

      /* read output of cdda */
      n = read_line(source, line, MAXLINE);

      /* cdda-finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback);

            /* pick up return status of child */
            wait(&ret);

            /* tell our caller that we are done here */
            read_done = WEXITSTATUS(ret);
            return;
      }

      strip_string(line);
      dodebug(10,"cdda2wav: %s\n", line);

      /* scanning for indexes? */
      if (strncmp(line,"index scan:", 11) == 0) {
            strcpy(tmp,line+11);
            p = strtok(tmp,".");
            if (p != NULL) {
                  tnr = atoi(p);
            } else {
                  tnr = 0;
            }
            g_snprintf(tmp,MAXLINE,_("Scanning track %d for indices..."),tnr);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
      }

      /* found indices? */
      if (strncmp(line,"track", 5) == 0) {
            strcpy(tmp,line);
            /* just output until first comma - looks nicer */
            p = strtok(tmp,",");
            if (p != NULL) {
                  strcpy(tmp2,p);
            } else {
                  strcpy(tmp2,tmp);
            }     
            strcat(tmp2,"\n");
            convert_for_gtk2_textwidget(tmp2);
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL, tmp2, strlen(tmp2));
      }

      /* scanning for MCN? */
      if (strncmp(line,"scanning for MCN", 16) == 0) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Scanning for MCN (Media Catalog Number)..."));  
      }     

      /* scanning for ISRC? */
      if (strncmp(line,"scanning for ISRCs:", 19) == 0) {
            strcpy(tmp,line+20);
            p = strtok(tmp,".");
            if (p != NULL) {
                  tnr = atoi(p);
            } else {
                  tnr = 0;
            }
            g_snprintf(tmp,MAXLINE,_("Scanning track %d for ISRC..."),tnr);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
      }
      
      /* done with scanning? */
      if (strncmp(line,"recording", 9) == 0) {
            if (bulk == 0) {
                  /* restore original info text */
                  gtk_label_set_text(GTK_LABEL(readtrack_info_label),
                        readtrack_info_string); 
            } else {
                  update_bulk_readlabel();
            }
      }

      /* look for a percent value */
      if (line[strlen(line)-1] == '%') {
            /* skip leading linefeed if any */
            if (line[0] == '\r') 
                  line[0] = ' ';
      
            /* look for last space */
            p = rindex(line,' ');
            if (p != NULL) 
                  strcpy(tmp,p);
            else 
                  strcpy(tmp,line);

            tmp[strlen(tmp)-1] = '\0';    
            strip_string(tmp);
            val = atoi(tmp);
            pval = (gfloat)val/100;
            if (pval > 1.0) pval = 1.0;
            gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1),
                  pval);

            /* now calculate how much percent he have at all */
            if (bulk == 0) {
                  pval2 = (pct_so_far + (pval * pct_this_track)) /100;
                  if (pval2 > 1.0) pval2 = 1.0;
            } else {
                  pval2 = (writeparams.pct_so_far_arr[read_tracknr] +
                        (pval * writeparams.pct_this_track_arr[read_tracknr]))/100;
            }
      
            gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar2),
                  pval2);
            set_xcdr_title(toplevel, viewmode_dialog, (gint)(pval2*100+0.5));

            /* now update info for small view */
            g_snprintf(tmp,MAXLINE,"%d%% / %d%%",(gint)(pval*100+0.5),
                     (gint)(pval2*100+0.5));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info2),tmp);   
            
            return;
      }

      /* track successfully recorded? */
      if (strlen(line) > strlen("successfully recorded")) {
            strcpy(tmp, line+strlen(line)-strlen("successfully recorded"));
            if (strcmp(tmp, "successfully recorded") == 0 ||
                strcmp(tmp, "recorded successfully") == 0) {
                  gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1), 1.0);
                  /* look for last % */
                  p = rindex(line,'%');
                  if (p != NULL) {
                        strcpy(tmp,p+1);
                        strip_string(tmp);
                  } else 
                        strcpy(tmp,line);

                  /* strips the 100% value from the string */
                  strip_string(tmp);
                  strcpy(line,tmp); 

                  if (bulk == 1) {
                        /* in bulkmode this means we switched tracks */
                        read_tracknr++;
                        update_bulk_readlabel();
                  }     
            }
      } 
            
      /* get subprocess pid */
      if (strncmp(line,"child pid", 9) == 0) {
            strcpy(tmp, line+12);
            readcdda_pid= (pid_t) atoi(tmp);
            return;
      }     
      
      /* error-text? do display these in the next block */
      if (strncmp(line,"Error",5) == 0 || strstr(line,"open audio sample file") != NULL) {
            read_output_ctrl = 1;
      }     

      /* forward most other output to textview-window */
      if (strncmp(line,"record",6) == 0 || read_output_ctrl == 1) {
            read_output_ctrl = 1;
            /* skip lines that do not interest us */
            if (strncmp(line,"percent_done",12) == 0) {
                  return;
            }
            if (strncmp(line,"overlap:min",11) == 0) {
                  return;
            }
            strcat(line,"\n");
            convert_for_gtk2_textwidget(line);
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL, line, strlen(line));
      }     
}


/* parse dummy output of cdda2wav */
/* output stdout of cdda2wav where never should any data be delivered */

static void read_cdda2wav_dummyout(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gchar line[MAXLINE];

      /* read output of cdda */
      n = read_line(source, line, MAXLINE);

      /* cdda-finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback2);
            return;
      }

      strcat(line,"\n");
      convert_for_gtk2_textwidget(line);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL, line, strlen(line));
}


/* call cdda2wav to read an audio-track 
   return 0 on success, 1 on error */

gint read_audio_track(gint devnr, gint starttrack, gint endtrack, gint kbyte, 
                  gchar *fname, gint startoffset, gint endoffset,
                  gint nrtracks, gfloat percent, gfloat percent_done,
                  gint viewtrack) {
gchar cmd[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar tmp4[MAXLINE];
gchar tmp5[MAXLINE];
gchar tmp6[MAXLINE];
gchar tmpfname[MAXLINE];
gint read_in, read_out, read_dummy;

      /* if another read running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* no filename given? */
      if (fname == NULL) {
            return 1;
      }
      strncpy(tmpfname, fname, MAXLINE);

      /* mark our read-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      readcdda_pid = -1;
      readcdda_pid2 = -1;
      read_abort_mark = 0;

      /* set info-label */
      convert_kbytes2mbminstring(kbyte, tmp);
      g_snprintf(tmp2,MAXLINE,_("Reading audio track %d/%d [%s]"), viewtrack, nrtracks, tmp);
      gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   
      strcpy(readtrack_info_string, tmp2);

      g_snprintf(tmp2,MAXLINE,_("Reading %d/%d:"), viewtrack, nrtracks);
      gtk_label_set_text(GTK_LABEL(readtrack_small_info),tmp2);   
      
      /* get bus,id,lun string */
      if (convert_devnr2busid(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* some stuff to have our slider moving smoothly no matter how
         big the tracks are */
      pct_so_far = percent_done;
      pct_this_track = percent;

      /* build command line */
      if (endtrack != 0) {
            g_snprintf(tmp2,MAXLINE,"%d+%d",starttrack,endtrack);
      } else {
            g_snprintf(tmp2,MAXLINE,"%d",starttrack);
      }

      /* set speed only when not zero */
      if (get_cur_audioread_speed() > 0) {
            g_snprintf(tmp3,MAXLINE,"-S %d", get_cur_audioread_speed()); 
      } else {
            strcpy(tmp3,"");
      }

      /* have to scan for indexes? */
      if (curset.indexscan != 0) {
            strcpy(tmp4,"-i 1 -v all");
      } else {
            strcpy(tmp4,"-v toc,summary,sectors,titles");
      }


      if (get_cur_audioread_useparanoia()) {
            g_snprintf(tmp6, MAXLINE, "-paranoia -paraopts=retries=%d", get_cur_audioread_paranoiaretries());
      } else {
            strcpy(tmp6,"");
      }

      get_wrap_path("CDDA2WAV",tmp5);
      g_snprintf(cmd,MAXLINE,
               "%s -D \"%s\" -g -O wav -t %s %s %s -P %d -n %d %s \"%s\"",
               tmp5,tmp,tmp2,tmp3,tmp4,
               get_cur_audioread_overlap(), get_cur_audioread_sectorburst(),
               tmp6, 
               convert_escape(tmpfname));

      dodebug(1, "spawning: %s\n",cmd);
      dolog(2,"Read audio track %s\n", fname);
      dolog(3,"Executing: %s\n",cmd);

      /* start child and get new fds */
      readcdda_pid = full_dpl_pipe3(&read_dummy,&read_in,&read_out,cmd,0);
      readcdda_pid2 = -1;

      /* set output to nonblocking - otherwise our callback would block */
      fcntl(read_out, F_SETFL, O_NONBLOCK); 
      fcntl(read_dummy, F_SETFL, O_NONBLOCK); 

      /* catch output of child */
      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ, 
            (GdkInputFunction) read_cdda2wav_out, GINT_TO_POINTER(0));
      readcdda_callback2 = gdk_input_add(read_dummy, GDK_INPUT_READ,    
            (GdkInputFunction) read_cdda2wav_dummyout,NULL);

      /* now wait until track is read */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_out);
      close(read_in);
      close(read_dummy);

      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, "\n", 1);

      /* error while reading? */
      if (read_done != 0 && read_abort_mark == 0) {
            g_snprintf(tmp,MAXLINE,_("Error reading audio track %d/%d"), starttrack, nrtracks);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Read-Error:"));   
            return 1;
      }
      /* aborted? */
      if (read_abort_mark == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Read aborted..."));     
            return 1;
      }

      return 0;
}


/* call cdda2wav to read all audio tracks from a cd */

gint start_bulk_read_action(gint devnr, gfloat percent_done, gint startnr) {
GList *loop;
track_read_param_t *trackparam;
char tmp[MAXLINE];
char tmptmp[MAXLINE];
char tmp3[MAXLINE];
char tmp4[MAXLINE];
char tmp5[MAXLINE];
char tmp6[MAXLINE];
char cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
gint read_in, read_out, read_dummy;
gint tracknr;

        /* if another read running, ignore */
        if (read_done == 999) {
                return -1;
        }

        /* mark our read-process as running */
        read_done = 999;
        read_output_ctrl = 0;
      pct_so_far = percent_done;
      read_tracknr = startnr;
        readcdda_pid = -1;
      readcdda_pid2 = -1;
        read_abort_mark = 0;

      /* init track-label */
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Initializing CD-Reader..."));
      strcpy(readtrack_info_string, "");

        /* reset writeparams-arrays */
      /* lets reuse this structure - even when we just read now */
        g_free(writeparams.tracktype);
        g_free(writeparams.frames);
        g_free(writeparams.pct_so_far_arr);
        g_free(writeparams.pct_this_track_arr);
        writeparams.tracktype = g_new0(gint,MAXTRACKS);
        writeparams.frames = g_new0(gint,MAXTRACKS);
        writeparams.pct_so_far_arr = g_new0(gfloat,MAXTRACKS);
        writeparams.pct_this_track_arr = g_new0(gfloat,MAXTRACKS);
        writeparams.nrtracks = 0;
        writeparams.simulation = curset.writesimul;

        /* get bus,id,lun string */
        if (convert_devnr2busid(devnr,tmp) != 0) {
                g_error("non existing cdrom?");
        }

        /* set speed only when not zero */
        if (get_cur_audioread_speed() > 0) {
                g_snprintf(tmp3,MAXLINE,"-S %d", get_cur_audioread_speed()); 
        } else {
                strcpy(tmp3,"");
        }

        /* have to scan for indexes? */
        if (curset.indexscan != 0) {
                strcpy(tmp4,"-v all");
        } else {
                strcpy(tmp4,"-v toc,summary,sectors,titles");
        }

      if (get_cur_audioread_useparanoia()) {
            g_snprintf(tmp6, MAXLINE, "-paranoia -paraopts=retries=%d", get_cur_audioread_paranoiaretries());
      } else {
            strcpy(tmp6,"");
      }

      get_wrap_path("CDDA2WAV",tmp5);
        g_snprintf(cmd,MAXLINE,
                   "%s -D \"%s\" -g -O wav %s %s -P %d -n %d %s -B",
                   tmp5,tmp,tmp3,tmp4,
               get_cur_audioread_overlap(), get_cur_audioread_sectorburst(),
               tmp6);

      tracknr = startnr;
      /* now add all track-filenames (only audio) */
        loop = g_list_first(trackreadset.trackparams);
        while(loop) {
                trackparam = loop->data;
                if (trackparam->trackfile != NULL && 
                  trackparam->tracktype == 1) {
                  strcpy(tmptmp, trackparam->trackfile);
                        g_snprintf(tmp, MAXLINE, " \"%s\"",
                                convert_escape(tmptmp));
                        strcat(cmd, tmp);

                  /* fill up percent values for percentbar */
                  writeparams.tracktype[tracknr] = trackparam->tracktype;
                  writeparams.frames[tracknr] = trackparam->frames;
                  writeparams.pct_this_track_arr[tracknr] = trackparam->percent;
                  writeparams.pct_so_far_arr[tracknr] = pct_so_far;
                  pct_so_far += trackparam->percent;
                  writeparams.nrtracks++;
                  tracknr++;

                }
                loop = loop->next;
        }
      /* correct full nr of tracks (so we have the full count of tracks) */
      writeparams.nrtracks+=startnr-1;

        dodebug(1, "spawning: %s\n",cmd);
        dolog(2,"Read all audio tracks\n");
        dolog(3,"Executing: %s\n",cmd);

        /* start child and get new fds */
        readcdda_pid = full_dpl_pipe3(&read_dummy,&read_in,&read_out,cmd,0);
      readcdda_pid2 = -1;

        /* set output to nonblocking - otherwise our callback would block */
        fcntl(read_out, F_SETFL, O_NONBLOCK); 

        /* catch output of child */
        readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,     
                (GdkInputFunction) read_cdda2wav_out, GINT_TO_POINTER(1));
      readcdda_callback2 = gdk_input_add(read_dummy, GDK_INPUT_READ,    
            (GdkInputFunction) read_cdda2wav_dummyout,NULL);

        /* now wait until track is read */
        while (read_done == 999) {
                wait_and_process_events();
        }

        close(read_out);
        close(read_in);
      close(read_dummy);

        gtk_text_insert(GTK_TEXT(readtrack_textview),
                fixedfont,NULL,NULL, "\n", 1);

        /* error while reading? */
        if (read_done != 0 && read_abort_mark == 0) {
                g_snprintf(tmp,MAXLINE,_("Error reading audio track %d/%d"), read_tracknr, 
                  writeparams.nrtracks);
                gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);        
                gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Read-Error:"));  
                return 1;
        }
        /* aborted? */
        if (read_abort_mark == 1) {
                gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Read aborted..."));  
                return 1;
        }

      return 0;
}


/* parse output of readcd and update sliders */

static void read_readcd_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gint val;
gfloat pval, pval2;

      /* read output of readcd */
      n = read_line(source, line, MAXLINE);

      /* readcd-finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback);

            /* pick up return status of child */
            wait(&ret);

            /* tell our caller that we are done here */
            if (WEXITSTATUS(ret) == 0 && read_output_ctrl == 0) {
                  /* readcd does return status 0 when killed - override */
                  read_done = 1;
            } else {
                  read_done = WEXITSTATUS(ret);
            }
            return;
      }

      dodebug(10,"readcd: %s\n", line);

      /* look for end value */
      if (strncmp(line,"end:",4) == 0) {
            strcpy(tmp,line+4);
            strip_string(tmp);
            readcd_endsector = atoi(tmp);
            return;
      }

      /* look for a percent value */
      if (strncmp(line,"addr:",5) == 0) {
            /* skip leading linefeed if any */
            if (line[0] == '\r') 
                  strcpy(tmp,line+6);
            else 
                  strcpy(tmp,line+5);

            strip_string(tmp);
            strcpy(tmp2,strtok(tmp," "));
            val = atoi(tmp2) - readcd_startsector;

            /* if not set yet, do nothing */
            if (readcd_endsector == 0) 
                  return;

            pval = (gfloat)val/(gfloat)(readcd_endsector - readcd_startsector);
            if (pval > 1.0) pval = 1.0;

            gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1),
                  pval);

            /* now calculate how much percent he has at all */
            pval2 = (pct_so_far + (pval * pct_this_track)) /100;
            if (pval2 > 1.0) pval2 = 1.0;
            gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar2),
                  pval2);
            set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval2*100+0.5));

            /* now update info for small view */
            g_snprintf(tmp,MAXLINE,"%d%% / %d%%",(gint)(pval*100+0.5),
                     (gint)(pval2*100+0.5));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info2),tmp);   
            
            return;
      }

      /* look if last expected line from readcd came */
      if (strncmp(line,"Read",4) == 0) {
            /* ok...now we can expect that we were not aborted */
            if (read_output_ctrl != 2) {
                  read_output_ctrl = 1;
            }
      }

      /* look if we got an read error */
      if (line[0] == '.') {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Failed to read sector - retrying"));      
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Retrying..."));   
      }

      /* now look if the got an error which could not corrected */
      if (strstr(line,"not corrected")) {
            read_output_ctrl = 2;
      }

      /* write error on disk? */
      if (strstr(line,"annot write")) {
            read_output_ctrl = 2;
      }

        /* some blocked output of tracks came through */
        if (strstr(line, " cnt: ")) {
                /* kick it */
                return;
        }

      /* forward most other output to textview-window */
      strcat(line,"\n");
      convert_for_gtk2_textwidget(line);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, line, strlen(line));
}


/* call readcd to read a data-track 
   return 0 on success, 1 on error */

gint read_data_track(gint devnr, gint starttrack, gint kbyte, 
                  gchar *fname, gint startoffset, gint endoffset,
                  gint nrtracks, gfloat percent, gfloat percent_done,
                  gint viewtrack) {
gchar cmd[MAXLINE];
gchar tmp[MAXLINE];
gchar tmptmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gint read_in, read_out, sectsize;

      /* if another read running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* no filename given? */
      if (fname == NULL) {
            return 1;
      }

      /* mark our read-process as running */
      read_done = 999;
      readcdda_pid = -1;
      readcdda_pid2 = -1;
      read_output_ctrl = 0;
      readcd_startsector = startoffset;
      readcd_endsector = 0;
      read_abort_mark = 0;

      /* set info-label */
      convert_kbytes2mbminstring(kbyte, tmp);
      g_snprintf(tmp2,MAXLINE,_("Reading data track %d/%d [%s]"), viewtrack, nrtracks, tmp);
      gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   

      g_snprintf(tmp2,MAXLINE,_("Reading %d/%d:"), viewtrack, nrtracks);
      gtk_label_set_text(GTK_LABEL(readtrack_small_info),tmp2);   
      
      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* some stuff to have our slider moving smoothly no matter how
         big the tracks are */
      pct_so_far = percent_done;
      pct_this_track = percent;

        /* now check which sectorsize we got */
        sectsize = get_sectorsize(devnr);
      if (sectsize == 2352) {
            /* workaround for buggy drives */
            endoffset = ((endoffset * DATASECTORSIZE) / sectsize) + 1;
      }

      get_wrap_path("READCD",tmp3);
      strcpy(tmptmp,fname);
      g_snprintf(cmd,MAXLINE,
               "%s %s sectors=%d-%d -s retries=32 f= \"%s\"",
               tmp3, tmp, startoffset, endoffset, 
               convert_escape(tmptmp));
      dodebug(1, "spawning: %s\n",cmd);
      dolog(2,"Read data track %s\n", fname);
      dolog(3,"Executing: %s\n",cmd);

      /* start child and get new fds */
      readcdda_pid = full_dpl_pipe3(NULL,&read_in,&read_out,cmd,0); 
      readcdda_pid2 = -1;

      /* set output to nonblocking - otherwise our callback would block */
      fcntl(read_out, F_SETFL, O_NONBLOCK);  

      /* catch output of child */
      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ, 
            (GdkInputFunction) read_readcd_out, NULL);

      /* now wait until track is read */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_out);
      close(read_in);

      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, "\n", 1);

      /* error while reading? */
      if ((read_done != 0 && read_abort_mark == 0) || read_output_ctrl == 2) {
            g_snprintf(tmp,MAXLINE,_("Error reading data track %d/%d"), starttrack, nrtracks);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Read-Error:"));   
            return 1;
      }
      /* aborted? */
      if (read_abort_mark == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Read aborted..."));     
            return 1;
      }

      return 0;
}


static void checkmedium_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret, devnr, sectsize;
gchar tmp[MAXLINE];
gchar line[MAXLINE];
gchar *p;


        /* read output of readcd */
        n = read_line(source, line, MAXLINE);

        /* readcd finished */
        if (n <= 0) {
                gtk_input_remove(readcdda_callback);

                /* pick up return status of child */
                wait(&ret);

                /* tell our caller that we are done here */
                read_done = WEXITSTATUS(ret);

                return;
        }

      dodebug(10,"check_medium_loaded: %s\n", line);

      /* got the message that no medium is present?
         in this case, ignore return code */ 
      if (strstr(line,"medium not present")) {
            checkmedium_found = 1;
      }
      if (strstr(line,"Device not ready")) {
                checkmedium_found = 1;
        }

        /* get a line about sectorsize? */
        if (strstr(line,"Sectorsize:")) {
                /* extract the bytes given there */
                strcpy(tmp,line+12);
                p = strtok(tmp," ");
                if (p) {
                        sectsize = atoi(p);
                        dodebug(10,"-> Detected sectorsize of %d bytes\n", sectsize);
                  devnr = GPOINTER_TO_INT(data);
                        set_sectorsize(devnr,sectsize);
                }
        }
}


/* checks if a disk is loaded in drive 
   return 0 if not, 1 if loaded and ready */
 
static gint check_medium_loaded(gint devnr) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar line[MAXLINE];
gint read_out;

      checkmedium_found = 0;
      read_done = 999;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* build command line */
      get_wrap_path("READCD",tmp2);
      g_snprintf(line,MAXLINE,"%s %s f=- sectors=0-0",
            tmp2,tmp);

      dodebug(1, "spawning: %s\n", line);

        readcdda_pid = full_dpl_pipe3(NULL,NULL,&read_out,line,0);
        readcdda_pid2 = -1;

        readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
                (GdkInputFunction) checkmedium_out, GINT_TO_POINTER(devnr));

        /* now wait until toc is read */
        while (read_done == 999) {
                wait_and_process_events();
        }

        close(read_out);

      dodebug(10, "medium loaded return code: %d\n", read_done);

      if (read_done == 0 && checkmedium_found == 0) 
            return 1;
      else
            return 0;
}


/* save the contents of a text-widget to a file 
   return 0 on success, 1 on error */

gint save_text2file(char *fname, GtkWidget *txt) {
gchar *buf;
gint n;
gint fd;

      /* get text from textwidget */
      n = gtk_text_get_length(GTK_TEXT(txt));
      buf = gtk_editable_get_chars(GTK_EDITABLE(txt),0,n);

      dodebug(2, "saving extended output to %s\n", fname);
      dolog(3, "Saving extended output to %s\n", fname);

      /* write to file */
      fd = open(fname,O_WRONLY | O_CREAT);
      if (fd < 0) {
            g_warning("Can't open file %s for writing\n",fname);
            return 1;
      }

      if (write(fd,buf,n) != n) {
            g_warning("Can't write file %s\n",fname);
            return 1;
      }

      g_free(buf);
      close(fd);
      chmod(fname,0644);

      return 0;
}


/* write the toc-file when copying full CDs */

gint write_copy_cd_toc_file(gchar *tocfile) {
GList *loop;
track_read_param_t *trackparam;
FILE *fd;
time_t acttime;
gchar timestr[MAXLINE];
gint tracknr;
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];

      if (tocfile == NULL) return 1;

      dodebug(2, "writing cd toc file %s\n", tocfile);

        /* is a link? */
        if (check_islink(tocfile, NULL)) {
            g_warning("Warning, won't overwrite a link at %s\n", tocfile);
            return 1;
        }

      /* write to file */
      fd = fopen(tocfile,"w"); 

      if (fd == NULL) {
            g_warning("Can't open file %s for writing\n",tocfile);
            return 1;
      }

      /* get current time */
      acttime = time((time_t *) 0);
      strcpy(timestr,ctime(&acttime));
      timestr[strlen(timestr)-1] = '\0';

      /* write header */
      
      fputs("#\n",fd);
      g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - TOC-File\n",XCDROAST_VERSION);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
      fputs(tmp,fd);
      fputs("#\n",fd);

      /* write disk-info */

      convert_frames2minstring(cdinfo.total_size, tmp2);
      g_snprintf(tmp,MAXLINE,"# Tracks: %d [%s]\n", 
            cdinfo.nr_tracks, tmp2);
      fputs(tmp,fd);
      if (cdinfo.title && cdinfo.artist) {
            g_snprintf(tmp,MAXLINE,"# title/artist: %s / %s\n",
                  cdinfo.title, cdinfo.artist);
            fputs(tmp,fd);
      }
      if (cdinfo.cddb_dtitle != NULL) {
            g_snprintf(tmp,MAXLINE,"# cddb: %s\n", cdinfo.cddb_dtitle);
            fputs(tmp,fd);
      }
      fputs("#\n",fd);

      /* generate disk-title */
      if (cdinfo.cddb_dtitle != NULL) {
            strcpy(tmp2,cdinfo.cddb_dtitle);
            g_snprintf(tmp,MAXLINE,"cdtitle = \"%s\"\n", convert_escape(tmp2));
      } else 
      if (cdinfo.title && cdinfo.artist && cdinfo.title[0] != '\0') {
            g_snprintf(tmp2,MAXLINE,"%s / %s", 
                  cdinfo.title, cdinfo.artist);
            g_snprintf(tmp,MAXLINE,"cdtitle = \"%s\"\n", convert_escape(tmp2));
      } else {
            /* no title available? */
            /* if data-track get track-label (better than nothing) */
            /* get first track */
            loop = g_list_first(trackreadset.trackparams);
            if (loop) {
                  trackparam = loop->data;
                  tracknr = trackparam->trackinfo_index;
                  if (trackinfo[tracknr]->title != NULL) {
                        strcpy(tmp2,trackinfo[tracknr]->title);
                  } else {
                        strcpy(tmp2,"");
                  }
                  g_snprintf(tmp,MAXLINE,"cdtitle = \"%s\"\n", 
                        convert_escape(tmp2));
            } else {    
                  g_snprintf(tmp,MAXLINE,"cdtitle = \"\"\n");
            }
      }     
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"cdsize = %d\n",cdinfo.total_size);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"discid = \"%s\"\n",cdinfo.cddb_discid);
      fputs(tmp,fd);


      /* write a section for each track */

      loop = g_list_first(trackreadset.trackparams);
      while (loop) {
            trackparam = loop->data;

            tracknr = trackparam->trackinfo_index;

            /* make sure to get some NULLs wasted */
            if (trackinfo[tracknr]->title == NULL) {
                  trackinfo[tracknr]->title = g_strdup("");
            }
            if (trackinfo[tracknr]->artist == NULL) {
                  trackinfo[tracknr]->artist = g_strdup("");
            }

            fputs("\n",fd);
            if (trackinfo[tracknr]->type == 0) {
                  convert_frames2mbstring(trackinfo[tracknr]->size, tmp2);
                  g_snprintf(tmp,MAXLINE,"# data: %s [%"LL_FORMAT" bytes / %s]\n",
                        trackinfo[tracknr]->title,
                        (gint64) trackinfo[tracknr]->size * DATASECTORSIZE,
                        tmp2);
                  fputs(tmp,fd);
            } else {
                  convert_frames2minstring(trackinfo[tracknr]->size, tmp2);
                  g_snprintf(tmp,MAXLINE,"# audio: %s / %s [%"LL_FORMAT" bytes / %s]\n",
                        trackinfo[tracknr]->title,
                        trackinfo[tracknr]->artist,
                        (gint64) trackinfo[tracknr]->size * CDDAFRAME, tmp2);
                  fputs(tmp,fd);
                  if (trackinfo[tracknr]->cddb_ttitle != NULL) {
                        g_snprintf(tmp,MAXLINE,"# cddb: %s\n",
                              trackinfo[tracknr]->cddb_ttitle);
                        fputs(tmp,fd);
                  }
            }

            g_snprintf(tmp,MAXLINE,"track = %02d\n", trackparam->starttrack);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"type = %d\n", trackinfo[tracknr]->type);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"size = %d\n", trackinfo[tracknr]->size);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"startsec = %d\n", trackinfo[tracknr]->start_sec);
            fputs(tmp,fd);

            if (trackparam->trackfile != NULL) {
                  strcpy(tmp2, trackparam->trackfile);
            } else {
                  strcpy(tmp2,"");
            }
            g_snprintf(tmp,MAXLINE,"file = \"%s\"\n", 
                  convert_escape(tmp2));
            fputs(tmp,fd);

            loop = loop->next;
      }

      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      return 0;
}


/* print trackparams-structure for debug reasons */

void print_trackreadset() {
GList *loop;
track_read_param_t *trackparam;

      dodebug(2,"------ trackreadset-structure -----\n");
      dodebug(2,"nrtracks: %d\n",trackreadset.nrtracks);
      dodebug(2,"cdsize: %d\n",trackreadset.cdsize);
      dodebug(2,"tocfile: %s\n",trackreadset.tocfile);
      dodebug(2,"cdtitle: %s\n",trackreadset.cdtitle);

      loop = g_list_first(trackreadset.trackparams);
      while(loop) {
            trackparam = loop->data;
            dodebug(2,"\ntrackinfo_index: %d\n", trackparam->trackinfo_index);
            dodebug(2,"starttrack: %d\n", trackparam->starttrack);
            dodebug(2,"endtrack: %d\n", trackparam->endtrack);
            dodebug(2,"tracktype: %d\n", trackparam->tracktype);
            dodebug(2,"start_sec: %d\n", trackparam->start_sec);
            dodebug(2,"startoffset: %d\n", trackparam->startoffset);
            dodebug(2,"endoffset: %d\n", trackparam->endoffset);
            dodebug(2,"percent: %f\n", trackparam->percent);
            dodebug(2,"kbyte: %d\n", trackparam->kbyte);
            dodebug(2,"frames: %d\n", trackparam->frames);
            if (trackparam->trackfile != NULL) {
                  dodebug(2,"trackfile: %s\n", trackparam->trackfile);
            } else {
                  dodebug(2,"trackfile: (NULL)\n");
            }     
            loop = loop->next;
      }
}


/* read the toc-file when copying full CDs */

gint read_copy_cd_toc_file(gchar *tocfile) {
FILE *fd;
GList *loop;
track_read_param_t *trackparam;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gint cdsize;
gfloat per;

      /* keep compiler shut about uninitialized warning */
      trackparam = NULL;

      /* prepare trackreadset for refilling */
      loop = g_list_first(trackreadset.trackparams);
      while (loop) {
            trackparam = loop->data;
            g_free(trackparam->trackfile);
            g_free(trackparam);
            loop = loop->next;
      }
      g_list_free(trackreadset.trackparams);
      trackreadset.trackparams = NULL;

      trackreadset.nrtracks = 0;
      trackreadset.cdsize = 0;
      cdsize = 0;
      g_free(trackreadset.tocfile);
      trackreadset.tocfile=g_strdup(tocfile);
      g_free(trackreadset.cdtitle);
      trackreadset.cdtitle = g_strdup("");

      dodebug(2, "reading cd toc file %s\n", tocfile);
      /* open file */
      fd = fopen(tocfile,"r");

      if (fd == NULL) {
            g_warning("Can't open file %s for reading\n",tocfile);
            return 1;
      }

      for (;;) {
            if (fgets(line,MAXLINE,fd) == NULL)
                  break;

            dodebug(10,"read tocfile: %s", line);
            /* skip empty or hashed lines */
            strip_string(line);
            if (*line == '#' || *line == '\0')
                  continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  dodebug(10,"invalid line in tocfile");
                  fclose(fd);
                  return 1;
            }     

            if (strcmp("cdtitle",id) == 0) {
                  g_free(trackreadset.cdtitle);
                  trackreadset.cdtitle = g_strdup(value);
            }
            if (strcmp("discid",id) == 0) {
                  g_free(trackreadset.cd_discid);
                  trackreadset.cd_discid = g_strdup(value);
            }
            if (strcmp("cdsize",id) == 0) {
                  trackreadset.cdsize = atoi(value);
            }
            if (strcmp("track",id) == 0) {
                  /* allocate memory */
                  trackparam = g_new0(track_read_param_t,1);
                  trackparam->trackinfo_index = -1;
                  trackparam->starttrack = atoi(value);
                  trackparam->endtrack = 0;
                  trackreadset.nrtracks++;      
            }
            if (strcmp("type",id) == 0) {
                  trackparam->tracktype = atoi(value);
            }
            if (strcmp("size",id) == 0) {
                  trackparam->frames = atoi(value);
                  cdsize += trackparam->frames;
            }
            if (strcmp("startsec",id) == 0) {
                  trackparam->start_sec = atoi(value);
            }
            if (strcmp("file",id) == 0) {
                  g_free(trackparam->trackfile);
                  trackparam->trackfile = g_strdup(value); 
                  
                  trackreadset.trackparams = g_list_append(
                        trackreadset.trackparams, trackparam);
            }

      }

      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      /* ok..all data read - now calculate the percentages */
      loop = g_list_first(trackreadset.trackparams);
      while(loop) {
            trackparam = loop->data;
            per = (gfloat)trackparam->frames / cdsize;
            trackparam->percent = per;

            loop = loop->next;
      }

      if (debug > 1) 
            print_trackreadset();

      return 0;
}

      
/* write the info-file for each read track */

gint write_inf_file(track_read_param_t *trackparam) {
FILE *fd;
time_t acttime;
gchar timestr[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;
gint tracknr;

      /* get current time */
      acttime = time((time_t *) 0);
      strcpy(timestr,ctime(&acttime));
      timestr[strlen(timestr)-1] = '\0';

      if (trackparam->trackfile == NULL) {
            return 1;
      }

      /* generate filename */
      /* (remove extension and put .xinf there) */
      strncpy(tmp,trackparam->trackfile,MAXLINE - 4);
      p = rindex(tmp,'.');
      if (!p) return 1;
      *p = '\0';
      strcpy(tmp2,tmp);
      strcat(tmp2,XCDROAST_INFO_EXT);

      dodebug(1,"writing inffile %s\n", tmp2);

        /* is a link? */
        if (check_islink(tmp2, NULL)) {
            g_warning("Warning, won't overwrite a link at %s\n", tmp2);
            return 1;
        }

      /* write to file */
      fd = fopen(tmp2,"w"); 

      if (fd == NULL) {
            g_warning("Can't open file %s for writing\n",tmp2);
            return 1;
      }

      /* write header */
      fputs("#\n",fd);
      g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - INF-File\n",XCDROAST_VERSION);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
      fputs(tmp,fd);
      fputs("#\n",fd);

      tracknr = trackparam->trackinfo_index;
      
      g_snprintf(tmp,MAXLINE,"file = \"%s\"\n",trackparam->trackfile);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"track = %d of %d\n",
                  trackinfo[tracknr]->track_nr,
                  cdinfo.nr_tracks);
      fputs(tmp,fd);
      if (trackinfo[tracknr]->title) {
            strcpy(tmp2,trackinfo[tracknr]->title);
      } else {
            strcpy(tmp2,"");
      }
      g_snprintf(tmp,MAXLINE,"title = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      if (trackinfo[tracknr]->artist) {
            strcpy(tmp2,trackinfo[tracknr]->artist);
      } else {
            strcpy(tmp2,"");
      }
      g_snprintf(tmp,MAXLINE,"artist = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      if (trackinfo[tracknr]->cddb_ttitle != NULL) {
            strcpy(tmp2,trackinfo[tracknr]->cddb_ttitle);
            g_snprintf(tmp,MAXLINE,"cddb_ttitle = \"%s\"\n",
                  convert_escape(tmp2));
            fputs(tmp,fd);
      }
      g_snprintf(tmp,MAXLINE,"size = %d\n", trackinfo[tracknr]->size);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"type = %d\n", trackinfo[tracknr]->type);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"rec_type = %d\n", trackinfo[tracknr]->rec_type);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"preemp = %d\n", trackinfo[tracknr]->preemp);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"copyperm = %d\n", trackinfo[tracknr]->copyperm);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"stereo = %d\n", trackinfo[tracknr]->stereo);
      fputs(tmp,fd);
      fputs("# from CD:\n",fd);
      if (cdinfo.title) {
            strcpy(tmp2,cdinfo.title);
      } else {
            strcpy(tmp2,"");
      }
      g_snprintf(tmp,MAXLINE,"cd_title = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      if (cdinfo.artist) {
            strcpy(tmp2,cdinfo.artist);
      } else {
            strcpy(tmp2,"");
      }
      g_snprintf(tmp,MAXLINE,"cd_artist = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      if (cdinfo.cddb_dtitle != NULL) {
            strncpy(tmp2,cdinfo.cddb_dtitle, MAXLINE);
            g_snprintf(tmp,MAXLINE,"cd_cddb_dtitle = \"%s\"\n",
                  convert_escape(tmp2));
            fputs(tmp,fd);
      }

      strncpy(tmp2,cdinfo.cddb_discid, MAXLINE);
      g_snprintf(tmp,MAXLINE,"cd_discid = \"%s\"\n",
            convert_escape(tmp2));
      fputs(tmp,fd);

      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      return 0;
}


/* read the titles/artists from an inf-file */

gint get_inf_tracktitle(gchar *path, image_files_t *entry) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;
gint istoc;

      /* generate filename */
      /* (remove extension and put .inf there) */
      istoc = 0;
      strncpy(tmp,path,MAXLINE - 4);
      p = rindex(tmp,'.');
      if (!p) return 1;
      if (strcmp(p,".toc") == 0) {
            /* we are currently handling a toc file */
            istoc = 1;
      }
      *p = '\0';
      strcpy(tmp2,tmp);
      strcat(tmp2,XCDROAST_INFO_EXT);

      if (istoc) 
            strcpy(tmp2,path);

      dodebug(1, "reading titles from %s\n", tmp2);

      if ((fd = fopen(tmp2,"r")) == NULL) { 
            return 1;
      }

      for (;;) {
            if (fgets(line,MAXLINE,fd) == NULL)
                  break;

            dodebug(10,"inffile: %s", line);

            /* skip empty or hashed lines */
            strip_string(line);
            if (*line == '#' || *line == '\0')
                  continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  dodebug(10,"invalid line in infofile");
                  fclose(fd);
                  return 1;
            }     

            /* if we are handling a toc file only the title entry
               is interesting */
            if (istoc) {
                  if (strcmp("cdtitle",id) == 0) {
                        g_free(entry->cddb_ttitle);
                        entry->cddb_ttitle = g_strdup(value);
                        break;
                  }
            }

            if (strcmp("track",id) == 0) {
                  /* extract track nr */
                  p = strtok(value," ");
                  if (p != NULL) {
                        entry->from_track = atoi(p);
                  }
            }

            if (strcmp("title",id) == 0) {
                  g_free(entry->title);
                  entry->title = g_strdup(value);
            }
            if (strcmp("artist",id) == 0) {
                  g_free(entry->artist);
                  entry->artist = g_strdup(value);
            }
            if (strcmp("cddb_ttitle",id) == 0) {
                  g_free(entry->cddb_ttitle);
                  entry->cddb_ttitle = g_strdup(value);
            }
            if (strcmp("cd_discid",id) == 0) {
                  g_free(entry->cd_discid);
                  entry->cd_discid = g_strdup(value);
            }
            if (strcmp("last_session_start",id) == 0) {
                  entry->last_session_start = atoi(value);
            }
            if (strcmp("next_session_start",id) == 0) {
                  entry->next_session_start = atoi(value);
            }
      }

      if (fclose(fd) != 0) {
            return 1;
      }

      return 0;
}


/* call cdrecord -prcap */

void fill_device_info(gint devnr, GtkWidget *txt) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
FILE *fpin;
gchar *p;
gint errcount;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* build command line */
      get_wrap_path_cdrecord(tmp3);
      g_snprintf(line,MAXLINE,"%s %s -prcap 2>&1",
            tmp3,tmp);

      dodebug(1, "calling: %s\n", line);
      dolog(3, "Executing: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      errcount = 0;
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            strcpy(tmp,line);

            dodebug(10, "prcap: %s", line);

            /* error condition? */
            p = strtok(tmp,":");
            if (p != NULL) {
                  p = strtok(NULL,"");
                  if (p != NULL) {
                        strcpy(tmp2,p);
                        strip_string(tmp2);
                        if (strncmp(tmp2,"I/O error",9) == 0) {
                              errcount++;
                              /* more then once an i/o-error? */
                              if (errcount > 1) 
                                    break; 
                        }
                  }
            }     
            convert_for_gtk2_textwidget(line);
            gtk_text_insert(GTK_TEXT(txt), 
                  fixedfont,NULL,NULL, line, strlen(line));
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }
}


/* eject CD in drive */

void eject_cd(gint devnr) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
FILE *fpin;
gchar *p;
gint errcount;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* build command line */
      get_wrap_path_cdrecord(tmp3);
      g_snprintf(line,MAXLINE,"%s %s -eject 2>&1",
            tmp3,tmp);

      dodebug(1, "calling: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      /* do actually nothing here ... */
      errcount = 0;
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            strcpy(tmp,line);

            /* error condition? */
            p = strtok(tmp,":");
            if (p != NULL) {
                  p = strtok(NULL,"");
                  if (p != NULL) {
                        strcpy(tmp2,p);
                        strip_string(tmp2);
                        if (strncmp(tmp2,"I/O error",9) == 0) {
                              errcount++;
                              /* more then once an i/o-error? */
                              if (errcount > 1) 
                                    break; 
                        }
                  }
            }     
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }
}


/* load CD in drive */

void load_cd(gint devnr) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
FILE *fpin;
gchar *p;
gint errcount;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* build command line */
      get_wrap_path_cdrecord(tmp3);
      g_snprintf(line,MAXLINE,"%s %s -load 2>&1",
            tmp3,tmp);

      dodebug(1, "calling: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      /* do actually nothing here ... */
      errcount = 0;
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            strcpy(tmp,line);

            /* error condition? */
            p = strtok(tmp,":");
            if (p != NULL) {
                  p = strtok(NULL,"");
                  if (p != NULL) {
                        strcpy(tmp2,p);
                        strip_string(tmp2);
                        if (strncmp(tmp2,"I/O error",9) == 0) {
                              errcount++;
                              /* more then once an i/o-error? */
                              if (errcount > 1) 
                                    break; 
                        }
                  }
            }     
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }
}


/* use cdrecord to get the leadout of a TOC */
/* (used for DVDs where cddawav fails ) */

static gint get_cdrecord_toc(gint devnr) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar *p;
FILE *fpin;
gint found;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      found = 0;
      
      /* build command line */
      get_wrap_path_cdrecord(tmp3);
      g_snprintf(line,MAXLINE,"%s %s -toc 2>&1",
            tmp3,tmp);

      dodebug(1, "calling: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            strcpy(tmp,line);
            dodebug(10, "cdrecord -toc: %s", line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      /* tmp is now the last line of the output */
      if (strncmp(tmp,"track:lout", 10) == 0) {

            /* extract leadout sector */
            p = strtok(tmp,"(");
            if (p) {
                  strncpy(tmp2,p,MAXLINE);
                  p = rindex(tmp2,':');
                  if (p) {
                        strcpy(tmp,p+1);
                        strip_string(tmp);
                        found = atoi(tmp);
                  }
            }           
      }

      return found;
}


/* call cdrecord -atip */

void get_atip_info(gint devnr, GtkWidget *txt) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar *p;
FILE *fpin;
gint found_atip,errcount;

      found_atip = 0;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

            get_wrap_path("CDRECORD", tmp3);
      g_snprintf(line,MAXLINE,"%s %s -atip 2>&1",
            tmp3,tmp);

      dodebug(1,"calling: %s\n", line);
      dolog(3, "Executing: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      /* syntax for dvd-atip is different */
      if (is_dvdwriter(curset.writer_devnr)) {
            found_atip = 1;
      }

      errcount = 0;
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            strcpy(tmp,line);

            dodebug(10,"atip: %s", line),

            /* error condition? */
            p = strtok(tmp,":");
            if (p != NULL) {
                  p = strtok(NULL,"");
                  if (p != NULL) {
                        strcpy(tmp2,p);
                        strip_string(tmp2);
                        if (strncmp(tmp2,"I/O error",9) == 0) {
                              errcount++;
                              /* more then once an i/o-error? */
                              if (errcount > 1) 
                                    break; 
                        }
                  }
            }     

            /* look for atip-signature */
            if (strncmp(line,"ATIP",4) == 0) {
                  found_atip = 1;
            }
            if (found_atip) {
                  gtk_text_insert(GTK_TEXT(txt), 
                        fixedfont,NULL,NULL, line, strlen(line));
            }
        }

      /* no atip-information available? */
      if (found_atip == 0) {
            /* generate error-message */
            strncpy(line,_("\nNo ATIP-Information available.\n\n(Possible reasons: No CD-R/RW loaded or your device\n does not support reading ATIP info)"),MAXLINE);
            convert_for_gtk2_textwidget(line);
            gtk_text_insert(GTK_TEXT(txt), 
                  NULL,NULL,NULL, line, strlen(line));
      }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }
}


/* get output of cdrecord -msinfo */

static void read_msinfo_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gint nr1, nr2;
gchar *p;

        n = read_line(source, line, MAXLINE);

        /* finished? */
        if (n <= 0) {
                gtk_input_remove(readcdda_callback);
                gtk_input_remove(readcdda_callback2);

                /* pick up return status of child */
            wait(&ret);

                read_done = WEXITSTATUS(ret);

            dodebug(10,"Finished in read_msinfo_out with status: %d\n", 
                  read_done);
            return;
      }

        dodebug(10, "msinfo (stdout): %s\n", line);

         /* look for the reload media command */
         if (strcmp(line,"Re-load disk and hit <CR>") == 0) {
                cdrecord_reload = 1;
            return;
      }

      strcpy(tmp, line);

      /* parse msinfo output */
      p = strtok(tmp,",");
      if (p) {
            nr1 = atoi(p);
            p = strtok(NULL,"");
            if (p) {
                  nr2 = atoi(p);

                  /* if parsing was sucessful use new values */
                  msinfo_nr1 = nr1;
                  msinfo_nr2 = nr2;
            }
      }
}


/* get output of cdrecord -msinfo (stderr) */

static void read_msinfo_stderr(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];

      
      n = read_line(source, line, MAXLINE);

        /* finished? */
        if (n <= 0) {
                gtk_input_remove(readcdda_callback);
                gtk_input_remove(readcdda_callback2);

                /* pick up return status of child */
                wait(&ret);

                read_done = WEXITSTATUS(ret);

            return;
      }

      dodebug(10, "msinfo (stderr): %s\n", line);
}


/* call cdrecord -msinfo */
/* returns the start sector and the next writeable adress */
/* or both values -1 when no offset could be found...*/

void get_msinfo_info(gint devnr, gint *nr1, gint *nr2) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp3[MAXLINE];
gint read_out, read_err;

        /* if another msinfo running, ignore */
        if (read_done == 999) {
                return;
        }

        /* mark our msinfo-process as running */
        read_done = 999;
        read_output_ctrl = 0;
        readerr_count = 0;
        cdrecord_reload = 0;
      msinfo_nr1 = -1;
      msinfo_nr2 = -1;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* build command line */
      get_wrap_path_cdrecord(tmp3);
      g_snprintf(line,MAXLINE,"%s %s -msinfo",
            tmp3,tmp);

      dodebug(1,"calling: %s\n", line);
      dolog(3, "Executing: %s\n", line);

      readcdda_pid = full_dpl_pipe3(&read_out,&cdrecord_stdin,&read_err,line,1);
      readcdda_pid2 = -1;

        fcntl(read_out, F_SETFL, O_NONBLOCK);
        fcntl(read_err, F_SETFL, O_NONBLOCK);

        readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
                (GdkInputFunction) read_msinfo_out, NULL);
        readcdda_callback2 = gdk_input_add(read_err, GDK_INPUT_READ,
                (GdkInputFunction) read_msinfo_stderr, NULL);

        /* now wait until msinfo is finished */
        while (read_done == 999) {
                wait_and_process_events();

                /* check if writer is waiting for reload medium */
                if (cdrecord_reload > 0) {
                        cdrecord_reload = 0;
                        show_dialog(ICO_WARN, _("Please reload the CD-R in the writer"), T_OK, NULL, NULL, -1);
                        
                        /* now send CR to cdrecord to let it continue */
                        if (write(cdrecord_stdin, "\n", 1) != 1) {
                                g_warning("write error to cdrecord pipe\n");
                        }
                }

      }

        close(read_err);
        close(read_out);
      close(cdrecord_stdin);

      dodebug(2,"received msinfo: %d,%d\n", msinfo_nr1, msinfo_nr2);

      /* workaround for drives reporting 0,0 instead of -1,-1 */
      if (msinfo_nr1 == 0 && msinfo_nr2 == 0) {
            msinfo_nr1 = -1;
            msinfo_nr2 = -1;
      }

      *nr1 = msinfo_nr1;
      *nr2 = msinfo_nr2; 
}


/* interpret output of blank=help and sort into memory structure */

static void parse_blankmode(gchar *line) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar drv[MAXLINE];
gchar *p1;
gint n;

      if (strncmp(line,"Blanking options:",17) != 0 ) {

            strcpy(tmp,line);
            strip_string(tmp);

            p1=strtok(tmp," \t");
            strcpy(drv,p1);   
            /* now drv contains the driver name */

            p1=strtok(NULL,"");
            strcpy(tmp2,p1);
            strip_string(tmp2);
            /* now tmp2 contains the description */

            /* now get the description of last mode to ensure
               we dont have double modes */
            if (drvcount != 0) {
                  if (strcmp(tmp2,blankmodes[drvcount-1]->desc) == 0) {
                        /* double drive mode - ignore */
                        return;
                  }
            }

            /* allocate structure */
            blankmodes[drvcount]=g_new(writer_driver_t,1);

            n = strlen(drv)+1;
            blankmodes[drvcount]->driver=g_new(gchar,n);
            strcpy(blankmodes[drvcount]->driver,drv);

            n = strlen(tmp2)+1;
            blankmodes[drvcount]->desc=g_new(gchar,n);
            strcpy(blankmodes[drvcount]->desc,tmp2);

            drvcount++;
            if (drvcount >= MAXBLANKMODES) {
                  g_error("Error: More than %d blank modes found\n",
                        MAXBLANKMODES);
            }
      }
}


/* print memory-structure with drivers (debug purposes) */

static void print_blankmodes() {
gint count;

      dodebug(2,"--------- cdrecord blankmodes-structure --------\n");
      count = 0;
      while(blankmodes[count] != NULL) {
            dodebug(2,"%s:%s\n",
                  blankmodes[count]->driver,
                  blankmodes[count]->desc);
                  
            count++;
      }
}


/* call cdrecord blank=help */

void scanblankmodes() {
gchar line[MAXLINE];
FILE *fpin;

      /* allocate memory */
      blankmodes = g_new0(writer_driver_t *,MAXBLANKMODES);
      drvcount = 0;

      get_wrap_path_cdrecord(line);
      strcat(line," blank=help 2>&1");

      dodebug(1, "calling: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10, "blankmodes: %s", line);
                parse_blankmode(line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      
      if (debug) print_blankmodes();
}


/* open a file and read one sector into a memory-buffer */
/* return 1 on success */

gint read_info_sector_from_file(gchar *isoname, gchar *buf, gint bsize) {
gint fd;

      dodebug(1, "read iso header from %s\n", isoname);

      fd = open (isoname, O_RDONLY, 0);
      if (fd == -1) {
            return 0;
      }

      /* forward to info-sector */
      if(lseek(fd, 32768, SEEK_SET) < 0) {
            close(fd);
            return 0;
      }

      /* read one sector */
      if (read(fd, buf, bsize) != bsize) {
            close(fd);
            return 0;
      }

      close(fd);
      return 1;
}


/* call readcd to read the info-sector from a data-track into a
   memory buffer. return 1 if all ok */

gint read_info_sector_from_dev(gint devnr, gchar *buf, gint bsize, gint startsector) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar cmd[MAXLINE];
FILE *fpin;
gint s1, s2;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

        s1 = startsector+16;
        s2 = startsector+17;

      /* build command-line */
      get_wrap_path("READCD",tmp2);
      g_snprintf(cmd,MAXLINE,"%s %s sectors=%d-%d -s f=- 2>/dev/null",
            tmp2, tmp, s1, s2);
      
      dodebug(1, "calling: %s\n", cmd);

      if ((fpin = popen(cmd,"r")) == NULL) {
            g_error("popen error\n");
      }

      /* read into buffer */
      if (fread(buf, bsize, 1, fpin) != 1) {
            pclose(fpin);
            return 0;
      }

      if (pclose(fpin) == -1) {
            g_error("pclose error\n");
      }

      return 1;
}


/* get output of cdrecord -blank */

static void read_blank_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];

        n = read_line(source, line, MAXLINE);

      /* finished? */
      if (n <= 0) {

            gtk_input_remove(readcdda_callback);
            gtk_input_remove(readcdda_callback2);

            /* pick up return status of child */
            wait(&ret);

            read_done = WEXITSTATUS(ret);

            /* perhaps the are-you-sure-you-want-to-abort dialog
               is still running? remove to be sure we can continue */
            if (dialog_done == 999) {
                  dialog_done = -1;
            }

            /* or cdrecord died by signal? e.g. SIGALRM */
            if (WIFSIGNALED(ret) && read_done == 0) {

                  /* most likely invalid prodvd key */
                  if (curset.isProDVD) {
                        strncpy(tmp, "\nReceived ALARM from cdrecord-ProDVD. Aborting blank...\nInvalid ProDVD key?\n", MAXLINE);

                        convert_for_gtk2_textwidget(tmp);
                        gtk_text_insert(GTK_TEXT(readtrack_textview),
                              fixedfont,NULL,NULL,tmp, strlen(tmp));
                        read_done = 1;
                  }
            }

                dodebug(10,"Finished in read_blank_out with status: %d\n", 
                        read_done);
            return;
      }

      dodebug(10, "blank (stdout): %s\n", line);

        strip_string(line);
 
         /* look for the reload media command */
         if (strcmp(line,"Re-load disk and hit <CR>") == 0) {
                 cdrecord_reload = 1;
                 /* if there was a fileselector running, cancel it */
                 dialog_done3 = -1;
                 return;
         }
 
      /* skip all lines that end with "seconds." */
      if (n > 8) {
            if (strstr(line, "seconds.")) {
                  return;
            }
      }

      strcpy(tmp,line);
      strcat(tmp,"\n");

      convert_for_gtk2_textwidget(tmp);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,tmp, strlen(tmp));

}


/* get output of cdrecord -blank (stderr) */

static void read_blank_stderr(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;

      n = read_line(source, line, MAXLINE);

      /* finished? */
      if (n <= 0) {

                  gtk_input_remove(readcdda_callback);
                  gtk_input_remove(readcdda_callback2);

                  /* pick up return status of child */
                  wait(&ret);

                  read_done = WEXITSTATUS(ret);

                  /* perhaps the are-you-sure-you-want-to-abort dialog
                   is still running? remove to be sure we can continue */
                  if (dialog_done == 999) {
                        dialog_done = -1;
                  }

                dodebug(10,"Finished in read_blank_stderr with status: %d\n", 
                        read_done);

            return;
      }

      dodebug(10, "blank (stderr): %s\n", line);

      /* check if we have an medium-i/o-error */
      strcpy(tmp,line);
      p = strtok(tmp,":");
      if (p != NULL) {
            p = strtok(NULL,"");
            if (p != NULL) {
                  strcpy(tmp2,p);
                  strip_string(tmp2);
                  if (strncmp(tmp2,"I/O error",9) == 0) {
                        readerr_count++;
                        /* more then once an i/o-error? */
                        if (readerr_count > 1) {
                              kill_readcdda();
                              dialog_done2 = 999;
                              read_output_ctrl = 2;
                        }
                  }
            }
      }     

      /* check if we got an error because of no disk */
      if (n > 21) {
            strcpy(tmp, line+(strlen(line)-21));
            if (strcmp(tmp, "No disk / Wrong disk!") == 0) {
                  /* mark we got no disk */
                  read_output_ctrl = 2;
            }
      }     

      strcpy(tmp,line);
      strcat(tmp,"\n");

      convert_for_gtk2_textwidget(tmp);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,tmp, strlen(tmp));

}


/* call cdrecord -blank */

gint start_blanking_process(gint devnr, GtkWidget *text_window) {
char tmp[MAXLINE];
char tmp2[MAXLINE];
char tmp3[MAXLINE];
char tmp4[MAXLINE];
char tmp5[MAXLINE];
char tmp6[MAXLINE];
char cmd[MAXLINE];
gint read_out, read_err;
gint ret;

      /* if another blank running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* mark our blanking-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      readerr_count = 0;
      cdrecord_reload = 0;

      /* save text-window */
      readtrack_textview = text_window;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* get blankmode and settings */
      strcpy(tmp2, blankmodes[curset.blankmode]->driver);

      strcpy(tmp3,"");
      if (curset.blank_force) {
            strcat(tmp3, "-force ");
      }
      if (curset.blank_eject) {
            strcat(tmp3, "-eject ");
      }
        if (curset.writeignsize == 1) {
                strcat(tmp3,"-ignsize ");
        }
        if (curset.writeimmed == 1) {
                strcat(tmp3,"-immed ");
        }

        if (get_cur_writer_speed() >= 0) {
                g_snprintf(tmp4,MAXLINE,"speed=%d ", get_cur_writer_speed()); 
                strcat(tmp3, tmp4);
        }
      
        get_wrap_path("CDRECORD", tmp5);

      g_snprintf(cmd, MAXLINE,
            "%s %s gracetime=%d -v %sblank=%s", 
            tmp5, tmp, get_gracetime(), tmp3, tmp2);

      dodebug(1, "spawning: %s\n",cmd);
      dolog(1, "Blanking CD with mode %s\n",tmp2);
      dolog(3, "Executing: %s\n", cmd);

      readcdda_pid = full_dpl_pipe3(&read_out,&cdrecord_stdin,&read_err,cmd,1);
      readcdda_pid2 = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_blank_out, NULL);
      readcdda_callback2 = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) read_blank_stderr, NULL);

      /* now wait until blank is finished */
      while (read_done == 999) {
            wait_and_process_events();

                /* check if writer is waiting for reload medium */
                if (cdrecord_reload > 0) {
                        cdrecord_reload = 0;
                        show_dialog(ICO_WARN, _("Please reload the CD-R in the writer"), T_OK, NULL, NULL, -1);
                        
                        /* now send CR to cdrecord to let it continue */
                        if (write(cdrecord_stdin, "\n", 1) != 1) {
                                g_warning("write error to cdrecord pipe\n");
                        }
                }

            /* check if somebody clicked on cancel */
            if (dialog_done2 != 999) {
                  ret = show_dialog(ICO_WARN, _("Are you sure you want to abort the writing?\nAborting may damage the CD-RW and may require that you have\nto power-cycle the burner to get working again."),
                        T_YES, T_NO, NULL, 1);
                  if (ret == 0) {
                        /* really abort */
                        kill_readcdda();
                        /* mark we aborted */
                        read_output_ctrl = 1;
                        dialog_done2 = 999;
                  } else {
                        /* not abort - undo button press */
                        dialog_done2 = 999;
                  }
            }
      }

      close(read_err);
      close(read_out);
      close(cdrecord_stdin);

      /* no disk */
      if (read_output_ctrl == 2) {
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL,"\n",1);  

            strncpy(tmp6, _("No disk or wrong disk loaded."), MAXLINE);
            convert_for_gtk2_textwidget(tmp6);
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL,tmp6,strlen(tmp6));
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL,"\n\n",2);      
      }

      /* error while blanking */
      if (read_done != 0) {
            return 1;
      }

      /* we killed the process */
      if (read_output_ctrl == 1) {
            return 2;
      }

      return 0; 
}


/* a timer function to see if there is output from cdrecord within a given
   time */

static gint cdrtimer_callback(gpointer data) {
time_t acttime;
gint diff;
gint ret;

      /* how many time passed since the last output of cdrecord? */
      acttime = time((time_t *) 0);
      diff = (gint) (acttime - cdrcmdtimer);    
      
      /* we counting down seconds, but not receiving output since over 5? */
      if (diff > 5) {
            gtk_timeout_remove(cdrtimer);
            cdrtimer = 0;

            dodebug(10,"cdrecord.prodvd output-timer run out - assume termination.\n");
            /* force termination of cdrecord.prodvd */
            read_write_out(NULL, -1, 0);

            /* if mkisofs is marked as running, kill it too */
            if (mkisofs_pid != -1) {
                  dodebug(2,"sending SIGINT to mkisofs (pid %d)\n", 
                        (gint) mkisofs_pid);
                  kill(mkisofs_pid, SIGINT);
                  waitpid(mkisofs_pid, &ret, 0);
            }

            return(FALSE);
      }

      return(TRUE);
}


/* special case to try to get some last output from stderr after
   cdrecord terminated */

static void read_write_stderr_last(gint source) {
gint n;
gchar line[MAXLINE];
gchar tmp[MAXLINE];

      /* get as many output left in the pipe as possible */
      while (1) {
            n = read_line(source, line, MAXLINE);

            if (n <= 0) {
                  /* pipe empty */
                  return;
            }

            dodebug(10,"cdrecord (stderr-last): %s\n", line);

            strcpy(tmp,line);
            strcat(tmp,"\n");

            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL,tmp, strlen(tmp));
      }
}


/* get output of cdrecord */

static void read_write_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p, *p2;
gint tnr, donemb, fullmb, fifoval, intbufval;
gfloat pval, pval2, pval3, pval4, avgspd;
static gint writecompleted;
gint cdrecord_stderr;

      if (source != -1) {
            n = read_line(source, line, MAXLINE);
      } else {
            /* force finish */
            n = -1;
      }

      /* finished? */
      if (n <= 0) {
            if (data) {
                  /* try to get some last output from stderr */
                  cdrecord_stderr = GPOINTER_TO_INT(data);
                  read_write_stderr_last(cdrecord_stderr);
            }

            dodebug(10,"cdrecord (stdout): EOF\n");
            gtk_input_remove(readcdda_callback);
            gtk_input_remove(readcdda_callback2); 

            /* pick up return status of child */
            waitpid((pid_t)readcdda_pid, &ret, WNOHANG);

            read_done = WEXITSTATUS(ret);

            if (writecompleted == 1 && read_done == 0) {    
                  /* set total progress bar to 100% */
                  gtk_progress_set_percentage(
                        GTK_PROGRESS(readtrack_pbar2), 1.0);
                  set_xcdr_title(toplevel,viewmode_dialog,100);

                  /* and small view too */
                  g_snprintf(tmp,MAXLINE,"%d%% / %d%%",100,100);
                  gtk_label_set_text(
                        GTK_LABEL(readtrack_small_info2),tmp);    
            }

            /* perhaps the are-you-sure-you-want-to-abort dialog
               is still running? remove to be sure we can continue */
            if (dialog_done == 999) {
                  dialog_done = -1;
            }

            /* or cdrecord died by signal? e.g. SIGALRM */
            if (WIFSIGNALED(ret) && read_done == 0) {

                  /* most likely invalid prodvd key */
                  if (curset.isProDVD && curset.cdrtype > 1000) {
                        read_done = 2;
                  }
            }

                dodebug(10,"Finished in read_write_out with status: %d\n", 
                        read_done);
            return;
      }

      dodebug(10,"cdrecord (stdout): %s\n", line);
      cdrcmdtimer = time((time_t *) 0);

      strip_string(line);

      /* look for the reload media command */
      if (strcmp(line,"Re-load disk and hit <CR>") == 0) {
            cdrecord_reload = 1;
            /* if there was a fileselector running, cancel it */
            dialog_done3 = -1;
            return;
      }

      /* cdrecord will wait for SIGUSR1 while waiting for reload? */
      if (strstr(line, "send SIGUSR1 to continue")) {
                cdrecord_reload = 2;
            return;
      }

      /* prodvd and beginning to write soon? */
      if (curset.isProDVD && curset.cdrtype > 1000) {
            if (strstr(line,"Last chance to quit")) {
                  cdrtimer = gtk_timeout_add(1000, 
                              cdrtimer_callback, NULL);
            }

            /* if we get that far, we are sure we are over the key
               check */
            if (strstr(line,"1 second")) {
                  if (cdrtimer) {
                        gtk_timeout_remove(cdrtimer);
                        cdrtimer = 0;
                  }
            }
      }

      /* skip all lines that contain "seconds." */
      if (n > 8) {
            if (strstr(line, "seconds.")) {
                  /* mark we are now ready to rumble */
                  read_output_ctrl = 3;

                  /* starting the write here */
                  writecompleted = 0;
                  return;
            }
      }

      /* track lines */
      if (read_output_ctrl > 0 && strncmp(line,"Track",5) == 0 &&
            !strstr(line,"audio") && !strstr(line,"data")) {

            /* parser */
            avgspd = 0.0;
            strcpy(tmp, line+6);
            p = strtok(tmp,":");
            if (p == NULL) return;
            tnr = atoi(p);
            p = strtok(NULL," ");
            if (p == NULL) return;
            if ((strncmp(p,"Total",5) != 0) && 
                (strncmp(p,"writing",7) != 0)) {
                  /* not the Total bytes written line? */
                  donemb = atoi(p);

                  p = strtok(NULL," ");
                  p = strtok(NULL," ");
                  if (p == NULL) return;
                  fullmb = atoi(p);

                  p = strtok(NULL,"%");
                  p2 = strtok(NULL,"");
                  if (p2 == NULL) {
                        /* no fifo value available - start of track */
                        fifoval = 0;
                        intbufval = 0;
                        avgspd = 0.0;
                        if (writeparams.tracktype[tnr] == 0) {
                              /* data track */
                              convert_frames2mbstring(
                                    writeparams.frames[tnr],tmp);
                              g_snprintf(tmp2,MAXLINE, _("Writing data track %d/%d [%s]"),
                                    tnr, 
                                    writeparams.nrtracks, tmp);
                              if (writeparams.simulation) 
                                    strcat(tmp2,_(" [Simulation]"));
                              gtk_label_set_text(
                                    GTK_LABEL(readtrack_info_label), 
                                    tmp2);
                        } else {
                              /* audio track */
                              convert_frames2minstring(
                                    writeparams.frames[tnr],tmp);
                              g_snprintf(tmp2,MAXLINE, _("Writing audio track %d/%d [%s]"),
                                    tnr, 
                                    writeparams.nrtracks, tmp);
                              if (writeparams.simulation) 
                                    strcat(tmp2,_(" [Simulation]"));
                              gtk_label_set_text(
                                    GTK_LABEL(readtrack_info_label), 
                                    tmp2);
                        }
                        /* small view label */ 
                        g_snprintf(tmp2,MAXLINE, _("Writing %d/%d:"),
                              tnr, writeparams.nrtracks);
                        gtk_label_set_text(
                              GTK_LABEL(readtrack_small_info),tmp2);
                  } else {
                        /* extract fifo value */
                        strcpy(tmp2,p);
                        p = rindex(tmp2,' ');
                        if (p == NULL) return;
                        fifoval = atoi(p);
                        
                        /* extract buf/spd value */
                        strcpy(tmp2,p2);
                        p = strtok(tmp2,"%");
                        if (p) {
                              p2 = strtok(NULL,"");
                              strcpy(tmp,p);
                              p = rindex(tmp,' ');    
                              if (p == NULL) return;
                              if (strstr(tmp, "buf")) {
                                    intbufval = atoi(p);
                              } else {
                                    /* no buf value? speed next */
                                    intbufval = 0;
                                    strcpy(tmp2,tmp);
                                    p2 = tmp2;
                              }
                              if (p2) {
                                    strcpy(tmp,p2);
                                    p = strtok(tmp,"x");
                                    if (p) {
                                          strcpy(tmp2,p);
                                          p = rindex(tmp2,' ');   
                                          if (p == NULL) return;
                                          avgspd = (gfloat)atof(p);
                                    }
                              }
                        } else {
                              intbufval = 0;
                              avgspd = 0.0;
                        }
                  }
                  /* done with parsing */

                  /* calculate current track progressbar values */
                  if (fullmb != 0) {
                        pval = (gfloat)donemb/(gfloat)fullmb;
                        if (pval > 1.0) pval = 1.0;

                        gtk_progress_set_percentage(
                              GTK_PROGRESS(readtrack_pbar1), pval);
                  } else {
                        pval = 0.0;
                  }

                  /* calculate total track progressbar */
                  pval2 = (writeparams.pct_so_far_arr[tnr] + 
                        (pval * writeparams.pct_this_track_arr[tnr]));
                  /* go only up to 99% */
                  if (pval2 >= 0.99) pval2 = 0.99;

                  if (writeparams.nrtracks != 1) {
                        gtk_progress_set_percentage(
                              GTK_PROGRESS(readtrack_pbar2), pval2);
                        set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval2*100+0.5));
                  } else {
                        /* just one track? total is the same as track */
                        if (pval < 1.0) {
                              gtk_progress_set_percentage(
                                    GTK_PROGRESS(readtrack_pbar2), 
                                    pval);
                              set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval*100+0.5));
                        } else {
                              gtk_progress_set_percentage(
                                    GTK_PROGRESS(readtrack_pbar2), 
                                    0.99);
                              set_xcdr_title(toplevel,viewmode_dialog,99);
                        }
                  }     

                  /* fifo value */
                  pval3 = (gfloat)fifoval /100; 
                  if (pval3 > 1.0) pval3 = 1.0;
                  gtk_progress_set_percentage(
                        GTK_PROGRESS(readtrack_pbar3), pval3);

                  /* add internal buffer and average speed too */
                  pval4 = (gfloat)intbufval /100;     
                  if (pval4 > 1.0) pval4 = 1.0;
                  gtk_progress_set_percentage(
                        GTK_PROGRESS(readtrack_pbar4), pval4);

                  if (avgspd > 0.0) {
                        g_snprintf(tmp,MAXLINE,"%.1fx",avgspd);
                        gtk_label_set_text(GTK_LABEL(readtrack_spd), tmp);
                  }

                  /* now update info for small view */
                  g_snprintf(tmp,MAXLINE,"%d%% / %d%%",
                        (gint)(pval*100+0.5), (gint)(pval2*100+0.5));
                  gtk_label_set_text(
                        GTK_LABEL(readtrack_small_info2),tmp);    

                  return;
            }
      }

      /* fixating */
      if (strncmp(line,"Fixating...",11) == 0) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Fixating..."));
            /* ok, write is finished I guess */
            writecompleted = 1;
      }

      /* avg speed line */
      if (strncmp(line,"Average write speed", 19) == 0) {
            strcpy(tmp,line);
            p = strtok(tmp,"x");
            if (p) {
                  strcpy(tmp2,p);
                  p = rindex(tmp2,' ');   
                  if (p) {
                        avgspd = (gfloat)atof(p);
                        g_snprintf(tmp,MAXLINE,"%.1fx",avgspd);
                        gtk_label_set_text(GTK_LABEL(readtrack_spd), tmp);
                  }
            }
      }

      strcpy(tmp,line);
      strcat(tmp,"\n");

      convert_for_gtk2_textwidget(tmp);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,tmp, strlen(tmp));

}


static void read_write_stderr (gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;

      n = read_line(source, line, MAXLINE);

      /* finished? */
      if (n <= 0) {
                dodebug(10,"cdrecord (stderr): EOF\n");
                gtk_input_remove(readcdda_callback);
                gtk_input_remove(readcdda_callback2);
 
                /* pick up return status of child */
                waitpid((pid_t)readcdda_pid, &ret, WNOHANG);
 
                read_done = WEXITSTATUS(ret);
 
                /* perhaps the are-you-sure-you-want-to-abort dialog
                   is still running? remove to be sure we can continue */
                if (dialog_done == 999) {
                        dialog_done = -1;
                }

            return;
      }

      dodebug(10,"cdrecord (stderr): %s\n", line);

      /* check if we have an medium-i/o-error */
      strcpy(tmp,line);
      p = strtok(tmp,":");
      if (p != NULL) {
            p = strtok(NULL,"");
            if (p != NULL) {
                  strcpy(tmp2,p);
                  strip_string(tmp2);
                  if (strncmp(tmp2,"I/O error",9) == 0) {
                        readerr_count++;
                        /* more then once an i/o-error? */
                        if (readerr_count > 1) {
                              kill_readcdda();
                              dialog_done2 = 999;
                              read_output_ctrl = 2;
                        }
                  }
                  /* check also if cannot send CUE sheet */
                  if (strncmp(tmp2,"Cannot send CUE sheet", 21) == 0) {
                        read_output_ctrl = 4;
                  }
                  /* check for common error on TAO only devices */
                  if (strncmp(tmp2,"Cannot open new session.",24) == 0 && get_cur_writemode() == 0) {
                        read_output_ctrl = 4;
                  } 
                  /* check Medium error/buffer underrun */
                  if (strncmp(tmp2,"Input/output error",18) == 0) {
                        read_output_ctrl = 5;
                  }
            }
      }     


      /* check if we got an error because of no disk */
      if (n > 21) {
            strcpy(tmp, line+(strlen(line)-21));
            if (strcmp(tmp, "No disk / Wrong disk!") == 0) {
                  /* mark we got no disk */
                  read_output_ctrl = 2;
            }
      }     

      strcpy(tmp,line);
      strcat(tmp,"\n");

      convert_for_gtk2_textwidget(tmp);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,tmp, strlen(tmp));
}


/* display an error when useing prodvd and cdrecord aborts */

static void display_invalid_prodvdkey() {

      if (curset.isProDVD && curset.cdrtype > 1000) {
            show_dialog(ICO_WARN, _("cdrecord-ProDVD terminated.\n\nMost likely because you have entered\nan invalid key. Please check if it is correct."), T_OK, NULL, NULL, 0);
      }
}


/* call cdrecord to write some tracks */

gint start_write_action(gint devnr) {
GList *loop;
track_read_param_t *trackparam;
gchar tmp[MAXLINE];
gchar tmptmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
gchar outcmd[MAXLINE];
gint read_out, read_err;
gint ret, tracknr;
gint varirec_on, tmp_writer_speed;
gint wrmode;

      /* if another write running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* mark our write-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      pct_so_far = 0.0;
      cdrecord_reload = 0;
      cdrtimer = 0;
      
      strcpy(outcmd,"");

      /* set info label */
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Initializing CD-Writer..."));

      /* reset writeparams-arrays */
      g_free(writeparams.tracktype);
      g_free(writeparams.frames);
      g_free(writeparams.pct_so_far_arr);
      g_free(writeparams.pct_this_track_arr);
      writeparams.tracktype = g_new0(gint,MAXTRACKS);
      writeparams.frames = g_new0(gint,MAXTRACKS);
      writeparams.pct_so_far_arr = g_new0(gfloat,MAXTRACKS);
      writeparams.pct_this_track_arr = g_new0(gfloat,MAXTRACKS);
      writeparams.nrtracks = 0;
      writeparams.simulation = curset.writesimul;

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }
      
      /* get driveropts */
      varirec_on = do_driveropts(tmp3, curset.writer_devnr);

      /* build command line */
      get_wrap_path_cdrecord(tmp2);
      g_snprintf(cmd, MAXLINE*10,
            "%s %s gracetime=%d fs=%dk %s -v -useinfo", 
            tmp2, tmp, get_gracetime(), get_cur_writer_fifo(), tmp3);

      if (get_cur_writer_drvmode() >= 0) {
            if (drivers[get_cur_writer_drvmode()] != NULL) {
                  g_snprintf(tmp,MAXLINE," driver=%s", 
                        drivers[get_cur_writer_drvmode()]->driver);
                  strcat(cmd,tmp);
            }
      }
      
      /* special case with varirec - always use 4x here */
      if (varirec_on) {
            tmp_writer_speed = 4;
      } else {
            tmp_writer_speed = get_cur_writer_speed();
      }
      if (get_cur_writer_speed() >= 0) {
            g_snprintf(tmp,MAXLINE," speed=%d", tmp_writer_speed);      
            strcat(cmd, tmp);
      }

      if (curset.multisession == 0) {
            wrmode = get_cur_writemode();
            if (wrmode == 0) {
                  strcat(cmd," -dao");
            }
            if (wrmode == 2) {
                  strcat(cmd," defpregap=0");
            }
            if (wrmode == 3) {
                  strcat(cmd," -raw96r");
            }
            if (wrmode == 4) {
                  strcat(cmd," -raw96p");
            }
            if (wrmode == 5) {
                  strcat(cmd," -raw16");
            }
      }

      if (curset.writesimul == 1) {
            strcat(cmd," -dummy");
      }
      if (curset.writeeject == 1) {
            strcat(cmd," -eject");
      }
      if (curset.nofixate == 1) {
            strcat(cmd," -nofix");
      }
      if (curset.multisession == 1) {
            if (is_a_sony(devnr)) {
                  strcat(cmd," -multi -data");
            } else {
                  strcat(cmd," -multi");
            }
      }
      if (curset.writepad == 1) {
            strcat(cmd," -pad");
      }
      if (curset.writeswap == 1) {
            strcat(cmd," -swab");
      }
      if (curset.writeoverburn == 1) {
            strcat(cmd," -overburn");
      }
      if (curset.writeignsize == 1) {
            strcat(cmd," -ignsize");
      }
      if (curset.writeimmed == 1) {
            strcat(cmd," -immed");
      }
      if (curset.writecdtext == 1) {
            strcat(cmd," -text");
      }

      /* now loop through all tracks to write */
      loop = g_list_first(trackreadset.trackparams);
      while(loop) {
            trackparam = loop->data;

            if (trackparam->tracktype == 0) {
                  /* datatrack */
                  strcat(cmd," -data");
            } else {
                  /* audiotrack */
                  strcat(cmd," -audio");
            }
            if (trackparam->trackfile != NULL) {
                  strcpy(tmptmp, trackparam->trackfile);
                  g_snprintf(tmp, MAXLINE, " \"%s\"",
                        convert_escape(tmptmp));
                  strcat(cmd, tmp);
            }

            /* save partial command line to view in progress window */
            if (strcmp(outcmd,"") == 0) {
                  g_snprintf(outcmd, MAXLINE,"Calling: %s ...\n\n", cmd);
            }

            /* fill up percent values for nice progressbar movement */
            tracknr = trackparam->starttrack;
            writeparams.tracktype[tracknr] = trackparam->tracktype;
            writeparams.frames[tracknr] = trackparam->frames;
            writeparams.pct_this_track_arr[tracknr] = trackparam->percent;    
            writeparams.pct_so_far_arr[tracknr] = pct_so_far;
            pct_so_far += trackparam->percent;
            writeparams.nrtracks++;

            loop = loop->next;
      }

      dodebug(1, "spawning: %s\n",cmd);
      dolog(1,"Write CD with %d tracks\n", writeparams.nrtracks);
      dolog(3,"Executing: %s\n", cmd);

      /* output command to get better debug output */
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,outcmd, strlen(outcmd));

      /* yes...command line is done */
      readcdda_pid = full_dpl_pipe3(&read_out,&cdrecord_stdin,&read_err,cmd,1);
      readcdda_pid2 = -1;
      mkisofs_pid = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_write_out, GINT_TO_POINTER(read_err));
      readcdda_callback2 = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) read_write_stderr, NULL);

      /* now wait until write is finished */
      while (read_done == 999) {
            wait_and_process_events();

            /* check if writer is waiting for reload medium */
            if (cdrecord_reload > 0) {
                  cdrecord_reload = 0;
                  show_dialog(ICO_WARN, _("Please reload the CD-R in the writer"), T_OK, NULL, NULL, -1);
                  
                  /* now send CR to cdrecord to let it continue */
                  if (write(cdrecord_stdin, "\n", 1) != 1) {
                        g_warning("write error to cdrecord pipe\n");
                  }
            }

            /* check if somebody clicked on cancel */
            if (dialog_done2 != 999) {
                  ret = show_dialog(ICO_WARN, _("Are you sure you want to abort the writing?\nAborting may damage the CD-RW and may require that you have\nto power-cycle the burner to get working again."),
                        T_YES, T_NO, NULL, 1);
                  if (ret == 0) {
                        /* really abort */
                        kill_readcdda();
                        /* mark we aborted */
                        read_output_ctrl = 1;   
                        dialog_done2 = 999;
                  } else {
                        /* not abort - undo button press */
                        dialog_done2 = 999;
                  }
            }
      }

      close(read_err);
      close(read_out);
      close(cdrecord_stdin);

      /* no disk */
      if (read_output_ctrl == 2) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("No disk or wrong disk loaded."));
            return 1;
      }
      /* cannot send cue sheet */
      if (read_output_ctrl == 4) {
            show_dialog(ICO_WARN,_("Your CD-Writer did not accept the CUE sheet needed for\nDAO writing. This could mean that cdrecord does not support DAO\nwith your writer. Select TAO mode and try again."),T_OK, NULL, NULL, 0);
      }

      /* aborted write ? */
      if (read_output_ctrl == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Writing aborted..."));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
            return 1;
      }

      /* error while writing ?*/
      if (read_done != 0 || read_output_ctrl == 5) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Error writing tracks"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
            if (read_done == 2) {
                  /* invalid cdrecord key - show window */
                  display_invalid_prodvdkey();
            }
            return 1;
      } else {
            /* all ok */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Tracks successfully written"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Successful:"));
            return 0;
      }
}


/* call cdda2wav to only create temporary .inf files - and let xcdroast
   patch CD-Text data into them if requested */

static void create_onthefly_inf_files(gint devnr) {
GList *loop;
track_read_param_t *trackparam;
char tmp[MAXLINE];
char tmptmp[MAXLINE];
char tmp4[MAXLINE];
char tmp5[MAXLINE];
char line[MAXLINE];
char cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
FILE *fpin;
gint ret, i, orgcdtextused;
gchar title[MAXLINE], artist[MAXLINE];
gchar cdtitle[MAXLINE], cdartist[MAXLINE];

        /* get bus,id,lun string */
        if (convert_devnr2busid(devnr,tmp) != 0) {
                g_error("non existing cdrom?");
        }

        /* have to scan for indexes? */
        if (curset.indexscan != 0) {
                strcpy(tmp4,"-v all");
        } else {
                strcpy(tmp4,"-v toc,summary,sectors,titles");
        }

        get_wrap_path("CDDA2WAV",tmp5);
        g_snprintf(cmd,MAXLINE,
                   "%s -D \"%s\" %s -info-only -B", tmp5,tmp,tmp4);

        /* now add all track-filenames (only audio) */
        loop = g_list_first(trackreadset.trackparams);
        while(loop) {
                trackparam = loop->data;
                if (trackparam->trackfile != NULL && 
                    trackparam->tracktype == 1) {
                        strcpy(tmptmp, trackparam->trackfile);
                        g_snprintf(tmp, MAXLINE, " \"%s\"",
                                convert_escape(tmptmp));
                        strcat(cmd, tmp);
            }
                loop = loop->next;
        }
      strcat(cmd, " 2>&1");

        dodebug(1,"calling: %s\n", cmd);
        if ((fpin = popen(cmd,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
                dodebug(10,"cdda2wav_info_only: %s", line);
        }

        ret = pclose(fpin);
        if (ret == -1) {
                g_error("pclose error\n");
        }

      /* info files now (hopefully) created */

      /* check for invalid mcn or isrc infoormation */
        loop = g_list_first(trackreadset.trackparams);
        while(loop) {
                trackparam = loop->data;
                if (trackparam->trackfile != NULL && 
                    trackparam->tracktype == 1) {

                  /* silently fix any broken .inf file */
                  if (check_valid_isrc_mcn(trackparam->trackfile)) {
                        clear_isrc_mcn_from_inffile(trackparam->trackfile);
                  }
            }
            loop = loop->next;
      }

      /* patch updated cd-text info */
      if (curset.writecdtext) {

            /* get title and artist for the given CD */
              strcpy(cdtitle,""); 
            strcpy(cdartist,"");
            orgcdtextused = 0;
                if (setupdata.option_displaycdtext) {
                       if (cdinfo.title && cdinfo.artist && cdinfo.title[0] != '\0') {
                                strncpy(cdtitle, cdinfo.title, MAXLINE);
                                strncpy(cdartist, cdinfo.artist, MAXLINE);
                                orgcdtextused = 1;
                        }
                }
                if (orgcdtextused == 0) {
                        if (cdinfo.cddb_dtitle) {
                                get_artist_and_title_from_cddb(cdinfo.cddb_dtitle,
                                cdartist, cdtitle);
                        } else {
                                /* try cd-text as fallback */
                                if (cdinfo.title && cdinfo.artist &&
                                    cdinfo.title[0] != '\0') {
                                        strncpy(cdtitle, cdinfo.title, MAXLINE);
                                        strncpy(cdartist, cdinfo.artist, MAXLINE);                                }
                        }
                }
            
/*
            g_print("cdtitle/artist %s %s\n", cdtitle, cdartist);
*/
            loop = g_list_first(trackreadset.trackparams);
              while(loop) {
                    trackparam = loop->data;
                      if (trackparam->trackfile != NULL && 
                      trackparam->tracktype == 1) {

                        /* get the cd-text data */
                        i = trackparam->trackinfo_index;
                            strcpy(title,"");
                              strcpy(artist,"");
                              orgcdtextused = 0;
                        if (setupdata.option_displaycdtext) {
                                    if (trackinfo[i]->title != NULL &&
                                        trackinfo[i]->title[0] != '\0' ) {
                                          /* cd-text found.. use it */
                                          strncpy(title, trackinfo[i]->title, MAXLINE);
                                          orgcdtextused = 1;
                                    }
                                    if (trackinfo[i]->artist != NULL &&
                                          trackinfo[i]->artist[0] != '\0' ) {
                                          strncpy(artist, trackinfo[i]->artist, MAXLINE);
                                    }
                        }
                            /* no cd-text in use? try cddb */
                            if (orgcdtextused == 0) {
                                    if (trackinfo[i]->cddb_ttitle != NULL) {
                                          /* use cddb-information */
                                          strncpy(title, trackinfo[i]->cddb_ttitle,
                                                MAXLINE);
                                    } else {
                                          /* fall back to try cd-text again */
                                          if (trackinfo[i]->title != NULL &&
                                                trackinfo[i]->title[0] != '\0' ) {
                                                strncpy(title, trackinfo[i]->title, MAXLINE);
                                          }
                                          if (trackinfo[i]->artist != NULL &&
                                                    trackinfo[i]->artist[0] != '\0' ) {
                                                strncpy(artist, trackinfo[i]->artist, MAXLINE);
                                          }
                                    }     
                        }

                        /* now we have all cd-text info for the given track */
                        edit_xinf_for_cd_text2(trackparam->trackfile, title, artist, cdtitle, cdartist);
                   
                  }     
                  loop = loop->next;
            }
      }
}


/* after the on-the-fly write remove the temporary-inf files again */

static void remove_onthefly_inf_files() {
GList *loop;
track_read_param_t *trackparam;
char tmptmp[MAXLINE];

        loop = g_list_first(trackreadset.trackparams);
        while(loop) {
                trackparam = loop->data;
                if (trackparam->trackfile != NULL && 
                    trackparam->tracktype == 1) {
                        strcpy(tmptmp, trackparam->trackfile);
                  remove_tmp_writetracks_tocfile(tmptmp);
            }
                loop = loop->next;
        }
}


/* call cdrecord to write a cd on the fly */
/* works currently only for cds with a single data-track and pure 
   audio CDs */ 

gint start_write_onthefly_action(gint read_devnr, gint write_devnr) {
GList *loop;
track_read_param_t *trackparam;
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar tmp4[MAXLINE];
gchar atmp3[MAXLINE];
gchar tmptmp[MAXLINE];
gchar atmp6[MAXLINE];
gchar cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
gchar cmd2[MAXLINE*10];
gchar outcmd[MAXLINE];
gchar tmpprefix[MAXLINE];
gint read_out, read_err, read_err2;
gint ret, tracknr, i;
pid_t pid1, pid2;
gint endsector, sectsize;
gint varirec_on, tmp_writer_speed;
gint wrmode;
gint datacount, audiocount;
gint isaudiocd;
gfloat per;

      /* if another write running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* what we got to do here? */
      datacount = 0;
      audiocount = 0;
      isaudiocd = 0;
        for (i = 0; i < cdinfo.nr_tracks; i++) {
                if (trackinfo[i]->type == 0) { 
                        datacount++;
                } else {
                        audiocount++;
                }
        }
      if (datacount == 0 && audiocount > 0) {
            isaudiocd = 1;
      }
      /* special case - cd extra? */
      if (datacount == 1 && audiocount > 0 && trackinfo[0]->type == 1) {
            /* treat just like an audio cd - ignore data track */
            isaudiocd = 1;
      }
      
      /* fetch a prefix we might need */
      generate_tmp_prefix_name(tmpprefix);

      /* audio on the fly - rebuild our structure for the tracks to read */
      if (isaudiocd) {

            clear_trackreadset();
            trackreadset.nrtracks = cdinfo.nr_tracks;

            /* create a list of temporary track files */
            for(i=0; i<cdinfo.nr_tracks; i++) {

                  trackparam = g_new0(track_read_param_t,1);
                  trackparam->trackinfo_index = i;
                  trackparam->starttrack = trackinfo[i]->track_nr;
                  trackparam->endtrack = 0;
                  trackparam->tracktype = trackinfo[i]->type;
                  per = (gfloat)trackinfo[i]->size * 100.0  / cdinfo.total_size;
                  trackparam->percent = per/100.0;
                  trackparam->frames = trackinfo[i]->size;

                  g_snprintf(tmp,MAXLINE, "%s-%02d.inf",
                        tmpprefix, i);
                  trackparam->trackfile = g_strdup(tmp);

                  trackreadset.trackparams = g_list_append(
                        trackreadset.trackparams, trackparam);
            }

            create_onthefly_inf_files(read_devnr);
      } 

      /* mark our write-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      pct_so_far = 0.0;
      cdrecord_reload = 0;
      cdrtimer = 0;
      endsector = 0;
      sectsize = 0;
      strcpy(outcmd,"");

      /* set info label */
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Initializing CD-Writer..."));

      /* reset writeparams-arrays */
      g_free(writeparams.tracktype);
      g_free(writeparams.frames);
      g_free(writeparams.pct_so_far_arr);
      g_free(writeparams.pct_this_track_arr);
      writeparams.tracktype = g_new0(gint,MAXTRACKS);
      writeparams.frames = g_new0(gint,MAXTRACKS);
      writeparams.pct_so_far_arr = g_new0(gfloat,MAXTRACKS);
      writeparams.pct_this_track_arr = g_new0(gfloat,MAXTRACKS);
      writeparams.nrtracks = 0;
      writeparams.simulation = curset.writesimul;


      /* build command line of readprocess */


      if (!isaudiocd) {

            /* get bus,id,lun string */
            if (convert_devnr2busid_dev(read_devnr,tmp) != 0) {
                  g_error("non existing cdrom?");
            }
            /* because we have only a single track on the cd this is our
               endsector to read */
            endsector = cdinfo.leadout - 2;

              sectsize = get_sectorsize(read_devnr);
            if (sectsize == 2352) {
                  /* workaround for buggy drives */
                        endsector = ((endsector * DATASECTORSIZE) / sectsize) + 1;
            }

            get_wrap_path("READCD", tmp2);
            g_snprintf(cmd,MAXLINE,
                  "%s %s sectors=0-%d -s f=-",
                  tmp2, tmp, endsector);

      } else {
            /* audio CD */

              /* get bus,id,lun string */
              if (convert_devnr2busid(read_devnr,tmp) != 0) {
                        g_error("non existing cdrom?");
            }

              /* set speed only when not zero */
                  if (get_cur_audioread_speed() > 0) {
                  g_snprintf(atmp3,MAXLINE,"-S %d", get_cur_audioread_speed());         
            } else {
                  strcpy(atmp3,"");
            }
              if (get_cur_audioread_useparanoia()) {
                  g_snprintf(atmp6, MAXLINE, "-paranoia -paraopts=retries=%d", get_cur_audioread_paranoiaretries());
            } else {
                  strcpy(atmp6,"");
            }

              get_wrap_path("CDDA2WAV", tmp2);
              g_snprintf(cmd,MAXLINE,
                   "%s -D \"%s\" -g -Oraw %s -P %d -n %d %s -no-infofile -B -",
                   tmp2,tmp,atmp3,
                   get_cur_audioread_overlap(), get_cur_audioread_sectorburst(),
                   atmp6);
      }


      /* build command line of write process */

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(write_devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* get driveropts */
      varirec_on = do_driveropts(tmp4, curset.writer_devnr);

      get_wrap_path_cdrecord(tmp3);
      g_snprintf(cmd2, MAXLINE*10,
            "%s %s gracetime=%d fs=%dk %s -v -useinfo",  
            tmp3, tmp, get_gracetime(), get_cur_writer_fifo(), tmp4);

      if (get_cur_writer_drvmode() >= 0) {
            if (drivers[get_cur_writer_drvmode()] != NULL) {
                  g_snprintf(tmp,MAXLINE," driver=%s", 
                        drivers[get_cur_writer_drvmode()]->driver);
                  strcat(cmd2,tmp);
            }
      }
      
      /* special case with varirec - always use 4x here */
      if (varirec_on) {
            tmp_writer_speed = 4;
      } else {
            tmp_writer_speed = get_cur_writer_speed();
      }
      if (get_cur_writer_speed() >= 0) {
            g_snprintf(tmp,MAXLINE," speed=%d", tmp_writer_speed);      
            strcat(cmd2, tmp);
      }
      if (curset.multisession == 0) {
            wrmode = get_cur_writemode();
            if (wrmode == 0) {
                  strcat(cmd2," -dao");
            }
            if (wrmode == 2) {
                  strcat(cmd2," defpregap=0");
            }
            if (wrmode == 3) {
                  strcat(cmd2," -raw96r");
            }
            if (wrmode == 4) {
                  strcat(cmd2," -raw96p");
            }
            if (wrmode == 5) {
                  strcat(cmd2," -raw16");
            }
      }
      if (curset.writesimul == 1) {
            strcat(cmd2," -dummy");
      }
      if (curset.writeeject == 1) {
            strcat(cmd2," -eject");
      }
      if (curset.nofixate == 1) {
            strcat(cmd2," -nofix");
      }
#if 0
            /* allow multisession only for data */
            if (curset.multisession == 1) {
                  if (is_a_sony(write_devnr)) {
                        strcat(cmd2," -multi -data");
                  } else {
                        strcat(cmd2," -multi");
                  }
            }
#endif
      if (curset.writepad == 1) {
            strcat(cmd2," -pad");
      }
      if (curset.writeswap == 1) {
            strcat(cmd2," -swab");
      }
      if (curset.writeoverburn == 1) {
            strcat(cmd2," -overburn");
      }
      if (curset.writeignsize == 1) {
            strcat(cmd2," -ignsize");
      }
      if (curset.writeimmed == 1) {
            strcat(cmd2," -immed");
      }
      if (curset.writecdtext == 1) {
            strcat(cmd2," -text");
      }

      if (!isaudiocd) {
            /* now add track-specification: one data track, known length */
             if (sectsize == SUNDATASECTORSIZE) {
                        g_snprintf(tmp, MAXLINE, " tsize=%db", endsector);
            } else {
                  g_snprintf(tmp, MAXLINE, " tsize=%ds", endsector);
            }

            strcat(cmd2, tmp);
            strcat(cmd2," -waiti -data -");

            /* fill up percent values for nice progressbar movement */
            tracknr = 1;
            writeparams.tracktype[tracknr] = 0; /* data */
            writeparams.frames[tracknr] = endsector;
            writeparams.pct_this_track_arr[tracknr] = 1.0;  
            writeparams.pct_so_far_arr[tracknr] = 0.0;
            writeparams.nrtracks = 1;

      } else {

            strcat(cmd2," -waiti -audio");

            /* audio mode - add info-file list */
              loop = g_list_first(trackreadset.trackparams);
            while(loop) {
                  trackparam = loop->data;
                  if (trackparam->trackfile != NULL && 
                            trackparam->tracktype == 1) {
                              strcpy(tmptmp, trackparam->trackfile);
                              g_snprintf(tmp, MAXLINE, " \"%s\"",
                                    convert_escape(tmptmp));
                              strcat(cmd2, tmp);
                  }
                  /* fill up percent values for nice progressbar movement */
                  tracknr = trackparam->starttrack;
                  writeparams.tracktype[tracknr] = trackparam->tracktype;
                  writeparams.frames[tracknr] = trackparam->frames;
                  writeparams.pct_this_track_arr[tracknr] = trackparam->percent;
                  writeparams.pct_so_far_arr[tracknr] = pct_so_far;
                  pct_so_far += trackparam->percent;
                  writeparams.nrtracks++;

                  loop = loop->next;
            }

      }

      /* save partial command line to view in progress window */
      g_snprintf(outcmd, MAXLINE,"Calling: %s\n\n", cmd2);

      dodebug(1, "spawning: %s | %s \n",cmd, cmd2);
      dolog(1,"Write CD on the fly\n");
      dolog(3,"Executing: %s | %s\n", cmd, cmd2);

      /* output command to get better debug output */
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,outcmd, strlen(outcmd));

      /* yes...command line is done */
      full_dpl_pipe4(&pid1,&pid2,NULL,&read_err,cmd,&read_out,&read_err2,cmd2,1);
      mkisofs_pid = -1;
      readcdda_pid = pid2;
      readcdda_pid2 = pid1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);
      fcntl(read_err2, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_write_out, GINT_TO_POINTER(read_err2));
      readcdda_callback2 = gdk_input_add(read_err2, GDK_INPUT_READ,
            (GdkInputFunction) read_write_stderr, NULL);
      readcdda_callback3 = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) verify_readcd_err, GINT_TO_POINTER(pid1));

      /* now wait until write is finished */
      while (read_done == 999) {
            wait_and_process_events();

            /* check if writer is waiting for reload medium */
            if (cdrecord_reload > 0) {
                  show_dialog(ICO_WARN, _("Please reload the CD-R in the writer"), T_OK, NULL, NULL, -1);
                  
                  /* now send CR to cdrecord to let it continue */
                  if (cdrecord_reload == 1) {
                        if (write(read_err2, "\n", 1) != 1) {
                              g_warning("write error to cdrecord pipe\n");
                        }
                  }

                  /* cdrecord also accepts a SIGUSR1 to continue */
                  /* send wakeup signal */
                  if (cdrecord_reload == 2) {
                        dodebug(1,"Sending SIGUSR1 to cdrecord (pid: %d) after reload.\n", (gint) pid2);
                        kill(pid2, SIGUSR1);
                  }
                  cdrecord_reload = 0;
            }

            /* check if somebody clicked on cancel */
            if (dialog_done2 != 999) {
                  ret = show_dialog(ICO_WARN, _("Are you sure you want to abort the writing?\nAborting may damage the CD-RW and may require that you have\nto power-cycle the burner to get working again."),
                        T_YES, T_NO, NULL, 1);
                  if (ret == 0) {
                        /* really abort */
                        kill_readcdda();
                        /* mark we aborted */
                        read_output_ctrl = 1;   
                        dialog_done2 = 999;
                  } else {
                        /* not abort - undo button press */
                        dialog_done2 = 999;
                  }
            }
      }

      close(read_err2);
      close(read_err);
      close(read_out);

      /* remove temporary inf files */
      if (isaudiocd) {
            remove_onthefly_inf_files();
      }

      /* no disk */
      if (read_output_ctrl == 2) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("No disk or wrong disk loaded."));
            return 1;
      }

      /* cannot send cue sheet */
      if (read_output_ctrl == 4) {
            show_dialog(ICO_WARN,_("Your CD-Writer did not accept the CUE sheet needed for\nDAO writing. This could mean that cdrecord does not support DAO\nwith your writer. Select TAO mode and try again."),T_OK, NULL, NULL, 0);
      }

      /* aborted write ? */
      if (read_output_ctrl == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Writing aborted..."));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
            return 1;
      }

      /* error while reading ?*/
      if (read_done != 0 || read_output_ctrl == 5) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Error writing tracks"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
                if (read_done == 2) {
                        /* invalid cdrecord key - show window */
                  display_invalid_prodvdkey();
                }
            return 1;
      } else {
            /* all ok */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Tracks successfully written"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Successful:"));
            return 0;
      }
}


/* call cdrecord to fixate a disk */

gint start_write_fixate_only(gint devnr) {
char tmp[MAXLINE];
char tmp2[MAXLINE];
char cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
gint read_out, read_err;
gint ret;
gint wrmode;

      /* if another write running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* mark our write-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      pct_so_far = 0.0;
      cdrecord_reload = 0;
      cdrtimer = 0;
      
      /* set info label */
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Initializing CD-Writer..."));

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }
            
      /* build command line */
      get_wrap_path_cdrecord(tmp2);
      g_snprintf(cmd, MAXLINE*10,
            "%s %s gracetime=%d -v -fix", tmp2, tmp, get_gracetime());

      if (get_cur_writer_drvmode() >= 0) {
            if (drivers[get_cur_writer_drvmode()] != NULL) {
                  g_snprintf(tmp,MAXLINE," driver=%s", 
                        drivers[get_cur_writer_drvmode()]->driver);
                  strcat(cmd,tmp);
            }
      }
      
      if (get_cur_writer_speed() >= 0) {
            g_snprintf(tmp,MAXLINE," speed=%d", get_cur_writer_speed());      
            strcat(cmd, tmp);
      }
      if (curset.multisession == 0) {
            wrmode = get_cur_writemode();
            if (wrmode == 0) {
                  strcat(cmd," -dao");
            }
            if (wrmode == 2) {
                  strcat(cmd," defpregap=0");
            }
            if (wrmode == 3) {
                  strcat(cmd," -raw96r");
            }
            if (wrmode == 4) {
                  strcat(cmd," -raw96p");
            }
            if (wrmode == 5) {
                  strcat(cmd," -raw16");
            }
      }
      if (curset.writesimul == 1) {
            strcat(cmd," -dummy");
      }
      if (curset.writeeject == 1) {
            strcat(cmd," -eject");
      }
      if (curset.multisession == 1) {
            strcat(cmd," -multi");
      }
        if (curset.writeignsize == 1) {
                strcat(cmd," -ignsize");
        }
        if (curset.writeimmed == 1) {
                strcat(cmd," -immed");
        }

      dodebug(1, "spawning: %s\n",cmd);
      dolog(1,"Fixate CD\n");
      dolog(3,"Executing: %s\n", cmd);

      /* yes...command line is done */
      readcdda_pid = full_dpl_pipe3(&read_out,&cdrecord_stdin,&read_err,cmd,1);
      readcdda_pid2 = -1;
      mkisofs_pid = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_write_out, GINT_TO_POINTER(read_err));
      readcdda_callback2 = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) read_write_stderr, NULL);

      /* now wait until write is finished */
      while (read_done == 999) {
            wait_and_process_events();

            /* check if writer is waiting for reload medium */
            if (cdrecord_reload > 0) {
                  cdrecord_reload = 0;
                  show_dialog(ICO_WARN, _("Please reload the CD-R in the writer"), T_OK, NULL, NULL, -1);
                  
                  /* now send CR to cdrecord to let it continue */
                  if (write(cdrecord_stdin, "\n", 1) != 1) {
                        g_warning("write error to cdrecord pipe\n");
                  }
            }

            /* check if somebody clicked on cancel */
            if (dialog_done2 != 999) {
                  ret = show_dialog(ICO_WARN, _("Are you sure you want to abort the writing?\nAborting may damage the CD-RW and may require that you have\nto power-cycle the burner to get working again."),
                        T_YES, T_NO, NULL, 1);
                  if (ret == 0) {
                        /* really abort */
                        kill_readcdda();
                        /* mark we aborted */
                        read_output_ctrl = 1;   
                        dialog_done2 = 999;
                  } else {
                        /* not abort - undo button press */
                        dialog_done2 = 999;
                  }
            }
      }

      close(read_err);
      close(read_out);
      close(cdrecord_stdin);

      /* no disk */
      if (read_output_ctrl == 2) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("No disk or wrong disk loaded."));
            return 1;
      }
      /* cannot send cue sheet */
      if (read_output_ctrl == 4) {
            show_dialog(ICO_WARN,_("Your CD-Writer did not accept the CUE sheet needed for\nDAO writing. This could mean that cdrecord does not support DAO\nwith your writer. Select TAO mode and try again."),T_OK, NULL, NULL, 0);
      }

      /* aborted write ? */
      if (read_output_ctrl == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Writing aborted..."));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
            return 1;
      }

      /* error while reading ?*/
      if (read_done != 0 || read_output_ctrl == 5) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Error writing tracks"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
                if (read_done == 2) {
                        /* invalid cdrecord key - show window */
                  display_invalid_prodvdkey();
                }
            return 1;
      } else {
            /* all ok */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Tracks successfully written"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Successful:"));
            return 0;
      }
}


/* parse output of rmtool and update sliders and textbox */

static void read_delete_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gint val;
gfloat pval;

      /* read output of readcd */
      n = read_line(source, line, MAXLINE);

      /* delete finished */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback);

            /* pick up return status of child */
            wait(&ret);

            /* tell our caller that we are done here */
            if (WEXITSTATUS(ret) == 0 && read_output_ctrl != 100) {
                  /* aborted */
                  read_done = 2;
            } else {
                  read_done = WEXITSTATUS(ret);
            }
            return;
      }

      dodebug(10,"rmtool: %s\n", line);

      /* look for a percent value */
      if (line[strlen(line)-1] == '%') {
            strcpy(tmp,line);
            tmp[strlen(tmp)-1] = '\0';
            strip_string(tmp);
            val = atoi(tmp);
            read_output_ctrl = val;
            pval = (gfloat)val/100;
            pval = (pval*delete_count + delete_start) /delete_all;
            if (pval > 1.0) pval = 1.0;
            gtk_progress_set_percentage(
                  GTK_PROGRESS(readtrack_pbar1), pval);
            set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval*100+0.5));
            return;
      }     
                  
      strcat(line,"\n");
      convert_for_gtk2_textwidget(line);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, line, strlen(line));

}


/* does do the real deletion of some files */

static gint do_delete_files(gchar *cmd, gint count, gint start, gint all) {
gint read_out;

      /* set some global vars we need for progress-bar */
      delete_count = count;
      delete_start = start;
      delete_all = all;

      dodebug(1,"spawning: %s\n",cmd);
      dolog(2,"Deleting %d files\n", count);
      dolog(3,"Executing: %s\n", cmd);

      readcdda_pid = full_dpl_pipe3(&read_out,NULL,NULL,cmd,0);
      readcdda_pid2 = -1;
      
      fcntl(read_out, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_delete_out, NULL);


      /* now wait until tracks are deleted */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_out);

      return read_done;
}


/* do delete some tracks from the HD */
/* do split the bulk in pieces of 50 files...to ensure there is no
   overrun of shell-arguments */

gint start_delete_action(GList *delfiles) {
GList *loop;
gchar *fname;
gint length, broke;
gint count,lastcount;
gchar tmp[MAXLINE];
gchar tmptmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar infname[MAXLINE];
gchar infname2[MAXLINE];
char orgcmd[MAXLINE];
char cmd[MAXLINE*10];
gchar *p;

      /* if another delete running, ignore */
      if (read_done == 999) {
            return -1;
      }

      read_done = 999;
      read_output_ctrl = 0;
      lastcount = 0;
      broke = 0;

      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Deleting tracks..."));

      /* build of command line */
      g_snprintf(orgcmd,MAXLINE,"%s/%s ", sharedir, RMTOOL);
      strcpy(cmd,orgcmd);

      length = g_list_length(delfiles);
      count = 0;

      loop = g_list_first(delfiles);
      while(loop) {
            fname = (gchar *)loop->data;

            /* remove extension and put .inf there */
            strncpy(tmp,fname,MAXLINE - 4);
            p = rindex(tmp,'.');
            if (p == NULL) return -1;
            strcpy(tmp2,p);
            *p = '\0';
            if (strcmp(tmp2,".toc") == 0) {
                  strcpy(tmptmp,fname);
                  g_snprintf(tmp2, MAXLINE, "\"%s\" ",
                        convert_escape(tmptmp));
            } else {
                  strcpy(infname,tmp);
                  strcat(infname,XCDROAST_INFO_EXT);
                  strcpy(infname2,tmp);
                  strcat(infname2,CDDA2WAV_INFO_EXT);
                  strcpy(tmptmp,fname);
                  g_snprintf(tmp2, MAXLINE, "\"%s\" \"%s\" \"%s\" ",
                        convert_escape(tmptmp),
                        convert_escape(infname), 
                        convert_escape(infname2));
            }
            strcat(cmd,tmp2);

            count++;
            if (count%50 == 0) {
                  /* part of commandline complete */
                  read_done = do_delete_files(cmd, count-lastcount, lastcount, length);
                  lastcount = count;
                  strcpy(cmd,orgcmd);

                  /* this run was successful? */
                  if (read_done == 0) {
                        read_done = 999;
                        read_output_ctrl = 0;
                  } else {
                        broke = 1;
                        break;
                  }
            }
            loop = loop->next;
      }

      /* any parts left over? (and no error before) */
      if (count%50 != 0 && broke == 0) {
                  /* part of commandline complete */
                  read_done = do_delete_files(cmd, count-lastcount, lastcount, length);
      }

      /* all ok? */
      if (read_done == 0) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Delete successful"));
      } else 
      if (read_done == 2) {
            /* delete canceled */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Delete aborted..."));
      } else {
            /* some error */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Error deleting tracks"));
      }

      return 0;
}


/* parse output of verfify-tool and update sliders */

static void verify_readcd_out(gpointer pid, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gint val;
gfloat pval, pval2;

      /* read output of vrfytool  */
      n = read_line(source, line, MAXLINE);

      /* readcd-finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback);

            /* pick up return status of child */
            waitpid((pid_t)GPOINTER_TO_INT(pid), &ret, WNOHANG);

            /* tell our caller that we are done here */
            read_done = WEXITSTATUS(ret);
            return;
      }

      dodebug(10,"vry-readcd (stdout): %s\n", line);

      /* look for a percent value */
      if (line[strlen(line)-1] == '%') {

            strcpy(tmp,line);
            tmp[strlen(tmp)-1] = '\0';
            strip_string(tmp);
            val = atoi(tmp);

            pval = (gfloat)val/100;
            if (pval > 1.0) pval = 1.0;

            gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1),
                  pval);

            /* now calculate how much percent he has at all */
            pval2 = (pct_so_far + (pval * pct_this_track));
            if (pval2 > 1.0) pval2 = 1.0;
            gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar2),
                  pval2);
            set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval2*100+0.5));

            /* now update info for small view */
            g_snprintf(tmp,MAXLINE,"%d%% / %d%%",(gint)(pval*100+0.5),
                     (gint)(pval2*100+0.5));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info2),tmp);   
            
            return;
      }

      /* forward all other output to textview-window */
      strcat(line,"\n");
      convert_for_gtk2_textwidget(line);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, line, strlen(line));
}


/* do just swallow all output we get from stderr... and wait if the
   process terminated */

static void verify_readcd_err(gpointer pid, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];

      /* read output of vrfytool */
      n = read_line(source, line, MAXLINE);

      /* readcd-finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback3);

                /* pick up return status of child */
            waitpid((pid_t)GPOINTER_TO_INT(pid), &ret, WNOHANG);

                dodebug(10,"Finished in verify_readcd_err\n");

            return;
      }

      dodebug(10,"readcd/cdda2wav (stderr): %s\n", line);
}


/* does call readcd | vrfytool to do verifying */

gint verify_data_track(gint devnr, gint starttrack, gint kbyte, 
                  gchar *fname, gint startoffset, gint endoffset,
                  gint nrtracks, gfloat percent, gfloat percent_done,
                  gint viewtrack) {
gchar cmd[MAXLINE];
gchar cmd2[MAXLINE];
gchar tmp[MAXLINE];
gchar tmptmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gint read_out, read_err, sectsize;
pid_t pid1, pid2;

      /* if another read running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* no filename given? */
      if (fname == NULL) {
            return 1;
      }

      /* mark our read-process as running */
      read_done = 999;
      readcdda_pid = -1;
      readcdda_pid2 = -1;
      read_output_ctrl = 0;
      read_abort_mark = 0;

      /* set info-label */
      convert_kbytes2mbminstring(kbyte, tmp);
      g_snprintf(tmp2,MAXLINE,_("Verifying data track %d/%d [%s]"), viewtrack, nrtracks, tmp);
      gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   

      g_snprintf(tmp2,MAXLINE,_("Verifying %d/%d:"), viewtrack, nrtracks);
      gtk_label_set_text(GTK_LABEL(readtrack_small_info),tmp2);   
      
      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* some stuff to have our slider moving smoothly no matter how
         big the tracks are */
      pct_so_far = percent_done;
      pct_this_track = percent;

        /* now check which sectorsize we got */
        sectsize = get_sectorsize(devnr);
      if (sectsize == 2352) {
            /* workaround for buggy drives */
            endoffset = ((endoffset * DATASECTORSIZE) / sectsize) + 1;
      }

      get_wrap_path("READCD", tmp3);
      g_snprintf(cmd,MAXLINE,
               "%s %s sectors=%d-%d -s f=-",
               tmp3, tmp, startoffset, endoffset);
      
      strcpy(tmptmp, fname);

      /* always verify in 512 bytes blocks */
      g_snprintf(cmd2,MAXLINE,"%s/%s -b \"%s\" -", 
               sharedir, VRFYTOOL, convert_escape(tmptmp));

      dodebug(1, "spawning: %s | %s\n",cmd,cmd2);
      dolog(2, "Verify data track %s\n", fname);
      dolog(3, "Executing: %s | %s\n", cmd, cmd2);

      /* start childs and get new fds */
      full_dpl_pipe4(&pid1,&pid2,NULL,&read_err,cmd,&read_out,NULL,cmd2,0);
      readcdda_pid = pid1;
      readcdda_pid2 = -1;

      /* set output to nonblocking - otherwise our callback would block */
      fcntl(read_out, F_SETFL, O_NONBLOCK);  
      fcntl(read_err, F_SETFL, O_NONBLOCK);  

      /* catch output of child */
      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ, 
            (GdkInputFunction) verify_readcd_out, GINT_TO_POINTER(pid2));
      readcdda_callback3 = gdk_input_add(read_err, GDK_INPUT_READ,      
            (GdkInputFunction) verify_readcd_err, GINT_TO_POINTER(pid1));

      /* now wait until track is read */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_out);
      close(read_err);

      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, "\n", 1);

      /* error while reading? */
      if (read_done != 0 && read_abort_mark == 0) {
            g_snprintf(tmp,MAXLINE,_("Verifying data track %d/%d failed"), starttrack, nrtracks);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Verify-Error:")); 
            return 1;
      }
      /* compare aborted? */
      if (read_abort_mark != 0) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Verify aborted..."));  
            return 2;
      }

      return 0;
}


/* does call cdda2wav | vrfytool to do verifying */

gint verify_audio_track(gint devnr, gint starttrack, gint endtrack, gint kbyte, 
                  gchar *fname, gint startoffset, gint endoffset,
                  gint nrtracks, gfloat percent, gfloat percent_done,
                  gint viewtrack) {
gchar cmd[MAXLINE];
gchar cmd2[MAXLINE];
gchar tmp[MAXLINE];
gchar tmptmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar tmp4[MAXLINE];
gchar tmp6[MAXLINE];
gint read_out, read_err;
pid_t pid1, pid2;

      /* if another read running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* no filename given? */
      if (fname == NULL) {
            return 1;
      }

      /* mark our read-process as running */
      read_done = 999;
      readcdda_pid = -1;
      readcdda_pid2 = -1;
      read_output_ctrl = 0;
      read_abort_mark = 0;

      /* set info-label */
      convert_kbytes2mbminstring(kbyte, tmp);
      g_snprintf(tmp2,MAXLINE,_("Verifying audio track %d/%d [%s]"), viewtrack, nrtracks, tmp);
      gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   

      g_snprintf(tmp2,MAXLINE,_("Verifying %d/%d:"), viewtrack, nrtracks);
      gtk_label_set_text(GTK_LABEL(readtrack_small_info),tmp2);   
      
      /* get bus,id,lun string */
      if (convert_devnr2busid(devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* some stuff to have our slider moving smoothly no matter how
         big the tracks are */
      pct_so_far = percent_done;
      pct_this_track = percent;

      /* build command line */
      if (endtrack != 0) {
            g_snprintf(tmp2,MAXLINE,"%d+%d",starttrack,endtrack);
      } else {
            g_snprintf(tmp2,MAXLINE,"%d",starttrack);
      }

      /* set speed only when not zero */
      if (get_cur_audioread_speed() > 0) {
            g_snprintf(tmp3,MAXLINE,"-S %d", get_cur_audioread_speed()); 
      } else {
            strcpy(tmp3,"");
      }

      if (get_cur_audioread_useparanoia()) {
            g_snprintf(tmp6, MAXLINE, "-paranoia -paraopts=retries=%d", get_cur_audioread_paranoiaretries());
      } else {
            strcpy(tmp6,"");
      }

      get_wrap_path("CDDA2WAV", tmp4);
      g_snprintf(cmd,MAXLINE,
              "%s -D \"%s\" -g -H -v toc -O wav -t %s %s -P %d -n %d %s -",
              tmp4,tmp,tmp2,tmp3,
              get_cur_audioread_overlap(), get_cur_audioread_sectorburst(),
              tmp6);
      
      strcpy(tmptmp,fname);
      g_snprintf(cmd2,MAXLINE,"%s/%s -a \"%s\" -", 
               sharedir, VRFYTOOL, convert_escape(tmptmp));

      dodebug(1, "spawning: %s | %s\n",cmd,cmd2);
      dolog(2, "Verify audio track %s\n", fname);
      dolog(3, "Executing: %s | %s\n", cmd, cmd2);

      /* start childs and get new fds */
      full_dpl_pipe4(&pid1,&pid2,NULL,&read_err,cmd,&read_out,NULL,cmd2,0);
      readcdda_pid = pid1;
      readcdda_pid2 = -1;

      /* set output to nonblocking - otherwise our callback would block */
      fcntl(read_out, F_SETFL, O_NONBLOCK);  
      fcntl(read_err, F_SETFL, O_NONBLOCK);  

      /* catch output of child */
      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ, 
            (GdkInputFunction) verify_readcd_out, GINT_TO_POINTER(pid2));
      readcdda_callback3 = gdk_input_add(read_err, GDK_INPUT_READ,      
            (GdkInputFunction) verify_readcd_err, GINT_TO_POINTER(pid1));

      /* now wait until track is read */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_out);
      close(read_err);

      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL, "\n", 1);

      /* error while reading? */
      if (read_done != 0 && read_abort_mark == 0) {
            g_snprintf(tmp,MAXLINE,_("Verifying audio track %d/%d failed"), starttrack, nrtracks);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Verify-Error:")); 
            return 1;
      }
      /* compare aborted? */
      if (read_abort_mark != 0) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Verify aborted..."));  
            return 2;
      }

      return 0;
}


/* parse output of cddbtool and update textbox */

static void read_cddbtool_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gint code, mode;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar *p;
gchar *rowdata[1];

      /* mode 0 for cd, mode 1 for tocfile, mode 2 for on-the-fly */
      mode = GPOINTER_TO_INT(data);

      /* read output of readcd */
      n = read_line(source, line, MAXLINE);

      /* cddbtool finished */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback);

            /* pick up return status of child */
            wait(&ret);

            read_done = WEXITSTATUS(ret);
            return;
      }

      dodebug(10, "cddbtool: %s\n", line);

      /* got we the number of matches? */
      if (line[0] == '%') {
            strcpy(tmp,line+1);
            matchnr = atoi(tmp);
            return;
      }

      /* got we a entry for the match list? */
      if (line[0] == '#') {
            /* end-delimitor found */
            if (strncmp(line,"#--",3) == 0) {
                  /* now see if we have only one match - preselect */
                  if (matchnr == 1) {
                        gtk_clist_select_row(cddb_clist,0,0);
                  }
                  return;
            }
            /* add this to the clist */
            strcpy(tmp,line);
            if (extract_quoted(tmp) != 0) 
                  return;

            /* now add decoded string to clist */
            rowdata[0] = convert_for_gtk2(tmp);
            gtk_clist_append(cddb_clist,rowdata);
            return;
      }

      /* get output id of read line */
      strcpy(tmp,line);
      p = strtok(tmp,":");
      if (p == NULL) {
            return;
      }
      code = atoi(p);

      strcpy(tmp,"");

      /* display fitting text */
      switch(code) {
      case 0: 
            g_snprintf(tmp,MAXLINE,_("Connecting to %s:%d"), 
                  setupdata.cddb_host, setupdata.cddb_port);
            break;
      case 1: 
            strcpy(tmp,_("Connect ok: Sending handshake"));
            break;
      case 2: 
            strcpy(tmp,_("Sending CDDB-query"));
            break;
      case 3: 
            strcpy(tmp,_("No matches found - unknown CD"));
            break;
      case 4: 
            /* close matches */
            if (matchnr == 1) {
                  strcpy(tmp,_("Found one close match"));
            } else {
                  g_snprintf(tmp,MAXLINE,_("Found %d close matches - Please select"), matchnr);
            }
            break;
      case 5: 
            /* exact matches */
            if (matchnr == 1) {
                  strcpy(tmp,_("Found one exact match"));
            } else {
                  g_snprintf(tmp,MAXLINE,_("Found %d exact matches - Please select"), matchnr);
            }
            break;
      case 6: 
            strcpy(tmp,_("Requesting data - Please wait"));
            break;
      case 7:
            /* got disc-title */
            strcpy(tmp,line);
            if (extract_quoted(tmp) != 0) 
                  return;

            /* we want title first, then artist */
            if (mode == 0) {
                  switch_artist_title(tmp);     
                  g_free(cdinfo.cddb_dtitle);
                  cdinfo.cddb_dtitle = g_strdup(tmp);

                  dolog(3, "CDDB lookup done for %s\n", cdinfo.cddb_dtitle);
            } else {
                  cdtext_set_dtitle(tmp);
                  dolog(3, "CDDB lookup done for %s\n", tmp);
            }

            /* recycle matchnr-var as track-counter */
            matchnr = 0;

            return;
      case 8:
            /* got track-title */
            strcpy(tmp,line);
            if (extract_quoted(tmp) != 0) 
                  return;

            if (mode == 0) {
                  if (matchnr >= cdinfo.nr_tracks) {
                        g_warning("invalid track count from cddb-server\n");
                        return;
                  }

                  g_free(trackinfo[matchnr]->cddb_ttitle);
                  trackinfo[matchnr]->cddb_ttitle = g_strdup(tmp);
            } else {
                  cdtext_set_ttitle(tmp, matchnr+1);
            }
            matchnr++;
            return;
            
      /* Error-codes */
      case -1:
            strcpy(tmp,_("Error: Hostname lookup failure"));
            break;
      case -2:
            strcpy(tmp,_("Error: Can't open stream socket"));
            break;
      case -3:
            strcpy(tmp,_("Error: Connection refused"));
            break;
      case -4:
            strcpy(tmp,_("Error: No response from server"));
            break;
      case -5:
            strcpy(tmp,_("Error: No answer within timeout"));
            break;
      case -6:
            strcpy(tmp,_("Handshake failed - No valid CDDB-server?"));
            break;
      case -7:
            strcpy(tmp,_("Error: CDDB-query failed"));
            break;
      case -8:
            strcpy(tmp,_("Error: CDDB-read failed"));
            break;
      case -9:
            strcpy(tmp,_("Warning: CDDB-logout failed"));
            break;
      case -10:
            strcpy(tmp,_("Error: CDDB write error on socket"));
            break;
      case -11:
            strcpy(tmp,_("Error: CDDB read error on socket"));
            break;
      }

      gtk_label_set_text(GTK_LABEL(cddb_info_label), tmp);
}


/* do lookup the cddb-database */
/* mode = 0, cddb lookup based on CD
   mode = 1, cddb lookup based on toc-file 
   mode = 2, cddb lookup based on CD but called from edit-cdtext */

gint start_cddb_lookup_action(gint mode) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp_cddbhost[MAXLINE];
gchar tmp_cddbproxy[MAXLINE];
char cmd[MAXLINE];
track_read_param_t *trackparam;
GList *loop;
gint read_out;
gint i;

      /* if another lookup running, ignore */
      if (read_done == 999) {
            return -1;
      }

      read_done = 999;
      read_output_ctrl = 0;
      matchnr = 0;

      /* build of command line */
      if (mode == 0 || mode == 2) {
            g_snprintf(tmp,MAXLINE,"cddb query %s %d ",
                  cdinfo.cddb_discid, cdinfo.nr_tracks);
            for (i = 0; i < cdinfo.nr_tracks; i++) {
                  g_snprintf(tmp2,MAXLINE,"%d ",
                        trackinfo[i]->start_sec + 150);
                  strcat(tmp,tmp2);
            }
            g_snprintf(tmp2,MAXLINE,"%d",cdinfo.total_size / 75);
            strcat(tmp,tmp2);
      } else {
            /* get data from toc file */
            g_snprintf(tmp,MAXLINE,"cddb query %s %d ",
                  trackreadset.cd_discid, trackreadset.nrtracks);
            loop = g_list_first(trackreadset.trackparams);
            for (i = 0; i < trackreadset.nrtracks; i++) {
                  trackparam = loop->data;
                  if (trackparam) {
                        g_snprintf(tmp2,MAXLINE,"%d ",
                              trackparam->start_sec + 150);
                        strcat(tmp,tmp2);
                  } else {
                        g_warning("trackreadset corruption detected.\n");
                  }
                  loop = loop->next;
            }
            g_snprintf(tmp2,MAXLINE,"%d",trackreadset.cdsize / 75);
            strcat(tmp,tmp2);
      }

      strncpy(tmp_cddbhost, setupdata.cddb_host, MAXLINE);
      convert_escape(tmp_cddbhost);
      strncpy(tmp_cddbproxy, setupdata.cddb_proxy_host, MAXLINE);
      convert_escape(tmp_cddbproxy);

      if (setupdata.cddb_use_http == 0) {
            g_snprintf(cmd,MAXLINE,
            "%s/%s -s \"%s\" -p %d -u \"%s\" -h \"%s\" -q \"%s\"", 
            sharedir, CDDBTOOL, tmp_cddbhost, setupdata.cddb_port,
            username, hostname, tmp);
      } else {
            /* we want to use http */
            if (setupdata.cddb_use_proxy == 0) {
                  /* but no proxy */
                  g_snprintf(cmd,MAXLINE,
                  "%s/%s -s \"%s\" -u \"%s\" -h \"%s\" -H -q \"%s\"", 
                  sharedir, CDDBTOOL, tmp_cddbhost, 
                  username, hostname, tmp);
            } else {
                  /* http with proxy */
                  g_snprintf(cmd,MAXLINE,
                  "%s/%s -s \"%s\" -u \"%s\" -h \"%s\" -U \"%s\" -P %d -q \"%s\"", 
                  sharedir, CDDBTOOL, tmp_cddbhost, 
                  username, hostname, tmp_cddbproxy,
                  setupdata.cddb_proxy_port, tmp);
            }
      }     
      dodebug(1, "spawning: %s\n",cmd);
      if (mode == 0 || mode == 2) {
            dolog(2, "CDDB lookup for discid %s\n", cdinfo.cddb_discid);
      } else {
            dolog(2, "CDDB lookup for discid %s (from toc-file)\n", trackreadset.cd_discid);
      }
      dolog(3, "Executing: %s\n", cmd);
      
      readcdda_pid = full_dpl_pipe3(&read_out,&cddb_in,NULL,cmd,0);
      readcdda_pid2 = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_cddbtool_out, GINT_TO_POINTER(mode));


      /* now wait until track is read */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_out);
      close(cddb_in);

      return read_done;
}


/* the user selected a specific row on cddb-window */

gint continue_cddb_lookup_action(gint match) {
gchar tmp[MAXLINE];

      dodebug(2, "sending %d to cddbtool\n", match);

      /* send this match back to our cddbtool-process */
      g_snprintf(tmp,MAXLINE,"%d\n",match);
      if (write(cddb_in, tmp, strlen(tmp)) != strlen(tmp)) {
            g_warning("write error to cddbtool pipe\n");
            return 1;
      }
      return 0;
}


/* call wavplay test.wav */

void test_dspdevice_play() {
gchar line[MAXLINE];
FILE *fpin;

      /* allocate memory */
      g_snprintf(line,MAXLINE,"%s/%s -d \"%s\" \"%s/%s\" 2>&1", sharedir, 
                  WAVPLAY, setupdata.dsp_device, sharedir, DSPTESTSOUND);

      dodebug(1, "calling: %s\n", line);

        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10, "dsptest: %s", line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

}


/* Save the current iso-options to a file - all strings are converted
   in a printable form first:  return 0 if ok, or 1 on error */

gint save_isooptions_file(gchar *confdir, gchar *fname) {
FILE *fd;
gchar tmp[MAXLINE];
gint i;

        /* now check if the confdir exists */
        if (!is_directory(confdir)) {
                /* try to create directory */
                mkdir(confdir, 0700);
                dodebug(2, "trying to mkdir %s\n", confdir);
        }

      g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);

        dodebug(1, "Opening %s for writing\n", tmp);
        dolog(3, "Saving isooptions file %s\n", tmp);

        fd = fopen(tmp,"w"); 

        if (fd == NULL) { 
                /* error opening file */
                return 1;
        }

        /* write the config-file header */
        fputs("#\n",fd);
        g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s Iso-Options-File\n",XCDROAST_VERSION);
        fputs(tmp,fd);
        fputs("#\n",fd);
        fputs("# Automatically created by the X-CD-Roast-Setup\n",fd);
        fputs("# Don't edit! (Unless you REALLY know what you are doing)\n",fd);
        fputs("#\n\n",fd);

        /* write data */
        g_snprintf(tmp,MAXLINE,"VERSION = \"%s\"\n",XCDROAST_VERSION); 
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"PLATFORM = \"%s\"\n",system_platform); 
        fputs(tmp,fd);

      for (i=0; i<24; i++) {
            g_snprintf(tmp,MAXLINE,"OPT_%d = %d\n", i, 
                  masterparam.opt[i]);
            fputs(tmp,fd);
      }

        g_snprintf(tmp,MAXLINE,"IN_CHARSET = \"%s\"\n",
            charset_types[masterparam.charset]);
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"OUT_CHARSET = \"%s\"\n",
            charset_types[masterparam.outcharset]);
        fputs(tmp,fd);

      g_snprintf(tmp,MAXLINE,"SHOW_ONLY_DIRS = %d\n", 
                  masterparam.show_only_dirs);
            fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"SHOW_HIDDEN_FILES = %d\n", 
                  masterparam.show_hidden_files);
            fputs(tmp,fd);

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* Load the iso-options-default file  
   return 0 if ok, or 1 on error */

gint load_isooptions_file(gchar *fname) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gchar tmp[MAXLINE];
gint optval, optnr, i;

        if ((fd = fopen(fname,"r")) == NULL) { 
                /* error opening file */
            dodebug(1, "Failed to open iso options file %s\n", fname);
            dolog(3, "Failed loading iso options file %s\n", fname);
                return 1;
        }

        dodebug(1, "Opening iso options file %s for reading\n", fname);
        dolog(3, "Loading iso options file %s\n", fname);

        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                dodebug(10,"isooptions: %s", line),

                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0') 
                        continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  g_error("syntax error in isooptions-file\n");
            }     

            if (strncmp("OPT_",id,4) == 0) {
                  strcpy(tmp,id+4);
                  optnr = atoi(tmp);
                  optval = atoi(value);
                  if (optnr < 24) 
                        masterparam.opt[optnr] = optval;
            }

                if (strncmp("IN_CHARSET",id,7) == 0) {
                        masterparam.charset = 0;
                        i = 0;
                        while (charset_types[i] != NULL) {
                                if (strcmp(charset_types[i],value) == 0) {
                                        masterparam.charset = i;
                                        break;
                                }
                                i++;
                        }
                }
                if (strncmp("OUT_CHARSET",id,7) == 0) {
                        masterparam.outcharset = 0;
                        i = 0;
                        while (charset_types[i] != NULL) {
                                if (strcmp(charset_types[i],value) == 0) {
                                        masterparam.outcharset = i;
                                        break;
                                }
                                i++;
                        }
                }

            if (strcmp("SHOW_ONLY_DIRS",id) == 0) {
                  masterparam.show_only_dirs = atoi(value);
            }
            if (strcmp("SHOW_HIDDEN_FILES",id) == 0) {
                  masterparam.show_hidden_files = atoi(value);
            }

      }

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* Save the current iso-headers to a file - all strings are converted
   in a printable form first:  return 0 if ok, or 1 on error */

gint save_isoheaders_file(gchar *confdir, gchar *fname) {
FILE *fd;
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];

        /* now check if the confdir exists */
        if (!is_directory(confdir)) {
                /* try to create directory */
                mkdir(confdir, 0700);
                dodebug(2, "trying to mkdir %s\n", confdir);
        }

      g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);

        dodebug(1, "Opening %s for writing\n", tmp);
        dolog(3, "Saving isoheaders file %s\n", tmp);

        fd = fopen(tmp,"w"); 

        if (fd == NULL) { 
                /* error opening file */
                return 1;
        }

        /* write the config-file header */
        fputs("#\n",fd);
        g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s Iso-Headers-File\n",XCDROAST_VERSION);
        fputs(tmp,fd);
        fputs("#\n",fd);
        fputs("# Automatically created by the X-CD-Roast-Setup\n",fd);
        fputs("# Don't edit! (Unless you REALLY know what you are doing)\n",fd);
        fputs("#\n\n",fd);

        /* write data */
        g_snprintf(tmp,MAXLINE,"VERSION = \"%s\"\n",XCDROAST_VERSION); 
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"PLATFORM = \"%s\"\n",system_platform); 
        fputs(tmp,fd);

      strcpy(tmp2,masterparam.publisher);
      g_snprintf(tmp,MAXLINE,"PUBLISHER = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      strcpy(tmp2,masterparam.preparer);
      g_snprintf(tmp,MAXLINE,"PREPARER = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      /*
      strcpy(tmp2,masterparam.application);
      g_snprintf(tmp,MAXLINE,"APPLICATION = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      */
      strcpy(tmp2,masterparam.abstract);
      g_snprintf(tmp,MAXLINE,"ABSTRACT = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      strcpy(tmp2,masterparam.biblio);
      g_snprintf(tmp,MAXLINE,"BIBLIO = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);
      strcpy(tmp2,masterparam.copyright);
      g_snprintf(tmp,MAXLINE,"COPYRIGHT = \"%s\"\n",convert_escape(tmp2));
      fputs(tmp,fd);

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* Load the iso-headers-default file  
   return 0 if ok, or 1 on error */

gint load_isoheaders_file(gchar *fname) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];

        if ((fd = fopen(fname,"r")) == NULL) { 
                /* error opening file */
            dodebug(1, "Failed to open iso headers file %s\n", fname);
            dolog(3, "Failed loading iso headers file %s\n", fname);
                return 1;
        }

        dodebug(1, "Opening iso headers file %s for reading\n", fname);
        dolog(3, "Loading iso headers file %s\n", fname);

        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                dodebug(10,"isoheaders: %s", line),

                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0') 
                        continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  g_error("syntax error in isoheaders-file\n");
            }     

            if (strcmp("PUBLISHER",id) == 0) {
                  g_free(masterparam.publisher);
                  masterparam.publisher = g_strdup(value);
            }
            if (strcmp("PREPARER",id) == 0) {
                  g_free(masterparam.preparer);
                  masterparam.preparer = g_strdup(value);
            }
            if (strcmp("APPLICATION",id) == 0) {
                  g_free(masterparam.application);
                  masterparam.application = g_strdup(value);
            }
            if (strcmp("ABSTRACT",id) == 0) {
                  g_free(masterparam.abstract);
                  masterparam.abstract = g_strdup(value);
            }
            if (strcmp("BIBLIO",id) == 0) {
                  g_free(masterparam.biblio);
                  masterparam.biblio = g_strdup(value);
            }
            if (strcmp("COPYRIGHT",id) == 0) {
                  g_free(masterparam.copyright);
                  masterparam.copyright = g_strdup(value);
            }
      }

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* print master dirs and excludes (debug purposes) */

static void print_master_dirs() {
GList *loop;
mstr_redirect_t *mstr;
gchar *p;

      dodebug(2,"------ directories to master -----\n");
      loop = g_list_first(masterparam.mstr_redir);
      while (loop) {
            mstr = (mstr_redirect_t *) loop->data;

            if (mstr) {
                  if (mstr->mstr_path && !mstr->redir_path) {
                        dodebug(2,"master-dir: %s\n", mstr->mstr_path);
                  }
                  if (mstr->mstr_path && mstr->redir_path) {
                        dodebug(2,"master-dir: %s -> %s\n", 
                              mstr->mstr_path, mstr->redir_path);
                  }
            }
            loop = loop->next;
      }

      dodebug(2,"------ directories to excluded from master -----\n");
      loop = g_list_first(masterparam.exclude_paths);
      while (loop) {
            p = (gchar *)loop->data;
            if (p) {
                  dodebug(2,"master-exclude: %s\n", p);
            }
            loop = loop->next;
      }
}


/* build mkisofs-commandline */

static void build_mkisofs_cmdline(gchar *ret, gint printsize, gchar *outfile, gint verbose) {
gchar line[MAXLINE*10];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmp3[MAXLINE];
gchar tmp34[MAXLINE];
gchar tmp35[MAXLINE];
gchar tmp4[MAXLINE];
gchar tmp5[MAXLINE];
gchar tmp6[MAXLINE];
gchar tmp7[MAXLINE];
gchar tmptmp[MAXLINE];
gchar tmptmp2[MAXLINE];
gchar tmptmp3[MAXLINE];
GList *loop;
mstr_redirect_t *mstr;
gchar *p;
FILE *fd;
gint pathcount;

      /* check first if we got our temporary files? */
      if (!master_fname1 || !master_fname2) {
            g_warning("no temporary files for master? aborting...\n");

            /* return some command that will fail eventually gracefully */
            strcpy(ret, "false");
            return;
      }

      if (debug > 1) {
            print_master_dirs();
      }

      get_wrap_path("MKISOFS",tmp);

      /* extract iso-options */
      if (verbose) {
            strcpy(tmp2,"-gui -v ");
      } else {
            strcpy(tmp2," ");
      }

      if (masterparam.opt[0]) {
            strcat(tmp2,"-r ");
      }
      if (masterparam.opt[1]) {
                strcat(tmp2,"-J ");
      }
      if (masterparam.charset != 0) {
                strcat(tmp2,"-input-charset ");
                strcat(tmp2,charset_types[masterparam.charset]);
                strcat(tmp2," ");
      }
      if (masterparam.outcharset != 0) {
                strcat(tmp2,"-output-charset ");
                strcat(tmp2,charset_types[masterparam.outcharset]);
                strcat(tmp2," ");
      }
      if (masterparam.opt[2]) {
            strcat(tmp2,"-R ");
      }
      if (masterparam.opt[3]) {
            strcat(tmp2,"-f ");
      }
      if (masterparam.opt[4]) {
            strcat(tmp2,"-l ");
      }
      if (masterparam.opt[5]) {
            strcat(tmp2,"-T ");
      }
      if (masterparam.opt[6]) {
            strcat(tmp2,"-D ");
      }
      if (masterparam.opt[7]) {
            strcat(tmp2,"-allow-leading-dots ");
      }
      if (masterparam.opt[8]) {
            strcat(tmp2,"-d ");
      }
      if (masterparam.opt[9]) {
            strcat(tmp2,"-N ");
      }
      if (masterparam.opt[10]) {
            strcat(tmp2,"-U ");
      }
      if (masterparam.opt[11]) {
            strcat(tmp2,"-no-bak ");
      }
      if (masterparam.opt[12]) {
            strcat(tmp2,"-hide-rr-moved ");
      }
      if (masterparam.opt[13]) {
            strcat(tmp2,"-hide-joliet-trans-tbl ");
      }
      if (masterparam.opt[14]) {
            strcat(tmp2,"-no-rr ");
      }
        if (masterparam.opt[15]) {
                strcat(tmp2,"-no-iso-translate ");
        }
        if (masterparam.opt[16]) {
                strcat(tmp2,"-joliet-long ");
        }
        if (masterparam.opt[17]) {
                strcat(tmp2,"-allow-lowercase ");
        }
        if (masterparam.opt[18]) {
                strcat(tmp2,"-allow-multidot ");
        }
        if (masterparam.opt[19]) {
                strcat(tmp2,"-max-iso9660-filenames ");
        }
        if (masterparam.opt[20]) {
                strcat(tmp2,"-relaxed-filenames ");
        }
        if (masterparam.opt[21]) {
                strcat(tmp2,"-dvd-video ");
        }
        if (masterparam.opt[23] > 0) {
            g_snprintf(tmptmp3,MAXLINE,"-iso-level %d ", 
                  masterparam.opt[23]);
                strcat(tmp2,tmptmp3);
        }

      if (printsize) {
            strcat(tmp2,"-print-size ");
      }

      /* extract bootable stuff */
      strcpy(tmp3,"");

      if (masterparam.bootable == 1) {
            /* el torito */
            if (masterparam.boot_image && masterparam.boot_catalog) {
                  strcpy(tmptmp, masterparam.boot_image);
                  strcpy(tmptmp2, masterparam.boot_catalog);
                  g_snprintf(tmp3,MAXLINE,"-b \"%s\" -c \"%s\"",
                        convert_escape(tmptmp),
                        convert_escape(tmptmp2));

                  switch(masterparam.boot_type) {
                  case 1:
                        strcat(tmp3," -hard-disk-boot");
                        break;
                  case 2:
                        strcat(tmp3," -no-emul-boot");
                        if (masterparam.boot_load_size >= 0) {
                              g_snprintf(tmptmp,MAXLINE," -boot-load-size %d", masterparam.boot_load_size);
                              strcat(tmp3, tmptmp);   
                        }     
                        break;
                  case 3:
                        strcat(tmp3," -no-boot");
                        break;
                  default:
                        break;
                  }     

                  if (masterparam.boot_info_table) {
                        strcat(tmp3," -boot-info-table");
                  }
            }
      }
      if (masterparam.bootable == 2) {
            /* sparc boot */
            if (masterparam.sparc_boot) {
                  strcpy(tmptmp, masterparam.sparc_boot);
                  g_snprintf(tmp3,MAXLINE,"-B \"%s\"",
                        convert_escape(tmptmp));
            }
      }

      /* multisession info */
      strcpy(tmp35,"");

      if (curset.multisession == 1) {
            if (masterparam.next_session_start != -1) {

                  if (convert_devnr2busid(curset.writer_devnr,tmp34) != 0) {
                        g_error("failed to get devicenr for writer in build_mkisofs_cmdline\n");
                  }
      
                  /* appending a session to an audio CD? */
                  if (cdinfo.nr_tracks > 0 && trackinfo[0]->type == 1) {
                        /* dont import old session */
                        g_snprintf(tmp35,MAXLINE,"-C %d,%d ",
                              masterparam.last_session_start,
                              masterparam.next_session_start);
                  } else {
                          g_snprintf(tmp35,MAXLINE,"-C %d,%d -M \"%s\"",
                              masterparam.last_session_start,
                              masterparam.next_session_start,
                              tmp34);     
                  }
            }
      }

      /* extract headers */
      strcpy(tmp4,"");

      if (masterparam.volid) {
            strcpy(tmptmp, masterparam.volid);
            g_snprintf(tmp5,MAXLINE,"-V \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     
      if (masterparam.publisher) {
            strcpy(tmptmp, masterparam.publisher);
            g_snprintf(tmp5,MAXLINE,"-publisher \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     
      if (masterparam.preparer) {
            strcpy(tmptmp, masterparam.preparer);
            g_snprintf(tmp5,MAXLINE,"-preparer \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     
      /*
      if (masterparam.application) {
            strcpy(tmptmp, masterparam.application);
            g_snprintf(tmp5,MAXLINE,"-A \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     
      */
      if (masterparam.abstract) {
            strcpy(tmptmp, masterparam.abstract);
            g_snprintf(tmp5,MAXLINE,"-abstract \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     
      if (masterparam.biblio) {
            strcpy(tmptmp, masterparam.biblio);
            g_snprintf(tmp5,MAXLINE,"-biblio \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     
      if (masterparam.copyright) {
            strcpy(tmptmp, masterparam.copyright);
            g_snprintf(tmp5,MAXLINE,"-copyright \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp4,tmp5);
      }     

      /* now the excluded directories */
      /* write to temporary file */
      strcpy(tmp6,"");

      fd = fopen(master_fname2,"w");
      if (!fd) {
            g_warning("failed to open %s for writing! aborting...\n",
                  master_fname2);
            strcpy(ret,"false");
            return;
      }

      loop = g_list_first(masterparam.exclude_paths);
        while (loop) {
            p = (gchar *)loop->data;
            if (p) {
                  strcpy(tmptmp,p);
                  g_snprintf(tmp5,MAXLINE,"%s\n",
                        convert_escape(tmptmp));
                  fputs(tmp5,fd);
            }
                loop = loop->next;
        }
      fclose(fd);

      /* if we actually got excludes, add the tmp-excl file */
      if (g_list_length(masterparam.exclude_paths) != 0) {
            strcpy(tmptmp,master_fname2);
            g_snprintf(tmp5,MAXLINE,"-exclude-list \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp6,tmp5);
      }

      /* output-file given? */
      if (outfile) {
            strcpy(tmptmp,outfile);
            g_snprintf(tmp5,MAXLINE,"-o \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp6,tmp5);
      }
      
      /* the last are the master-paths with redirects */
      strcpy(tmp7,"");

      fd = fopen(master_fname1,"w");
      if (!fd) {
            g_warning("failed to open %s for writing! aborting...\n",
                  master_fname1);
            strcpy(ret,"false");
            return;
      }

      /* the first path is to be added on the command line..all others
         to temporary file */
      pathcount = 0;
        loop = g_list_first(masterparam.mstr_redir);
        while (loop) {
                mstr = (mstr_redirect_t *) loop->data;
            if (mstr) {
                        if (mstr->mstr_path && !mstr->redir_path) {
                        /* no redir available */
                        strcpy(tmptmp,mstr->mstr_path);
                        if (pathcount == 0) {
                              g_snprintf(tmp5,MAXLINE,"\"%s\" ",
                                    convert_escape3(tmptmp));
                              strcat(tmp7,tmp5);
                        } else {
                              /* write to file */
                              g_snprintf(tmp5,MAXLINE,"%s\n",
                                    convert_escape2(tmptmp));
                              fputs(tmp5,fd);
                        }
                  }
                  if (mstr->mstr_path && mstr->redir_path) {
                        strcpy(tmptmp,mstr->mstr_path);
                        strcpy(tmptmp2,mstr->redir_path);
                        if (pathcount == 0) {
                              g_snprintf(tmp5,MAXLINE,"\"%s=%s\" ",
                                    convert_escape3(tmptmp2),
                                    convert_escape3(tmptmp));
                              strcat(tmp7,tmp5);
                        } else {
                              /* write to file */
                              g_snprintf(tmp5,MAXLINE,"%s=%s\n",
                                    convert_escape2(tmptmp2),
                                    convert_escape2(tmptmp));
                              fputs(tmp5,fd);
                        }
                  }
                  pathcount++;
            }
                loop = loop->next;
        }
      fclose(fd);

      /* if we got more than one path add master-file */
      if (g_list_length(masterparam.mstr_redir) > 1) {
            strcpy(tmptmp,master_fname1);
            g_snprintf(tmp5,MAXLINE,"-path-list \"%s\" ",
                  convert_escape(tmptmp));
            strcat(tmp6,tmp5);
      }

      /* now put all together */
      g_snprintf(line,MAXLINE*10, "%s %s %s %s %s %s -graft-points %s", 
            tmp, tmp2, tmp3, tmp35, tmp4, tmp6, tmp7);

      strcpy(ret,line);
}


/* get output of mkisofs  */

static void read_mkisofs_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gchar line[MAXLINE];
gchar tmp[MAXLINE];

      n = read_line(source, line, MAXLINE);

      /* finished? */
      if (n <= 0) {
            return;
      }

      dodebug(10, "mkisofs (stdout): %s\n", line);


      strcpy(tmp,line);
      strcat(tmp,"\n");

      convert_for_gtk2_textwidget(tmp);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,tmp, strlen(tmp));
}


/* get output of mkisofs (stderr) */

static void read_mkisofs_stderr(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar *p;

      n = read_line(source, line, MAXLINE);

      /* finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback);
            gtk_input_remove(readcdda_callback2);

            /* pick up return status of child */
            wait(&ret);

            read_done = WEXITSTATUS(ret);

            return;
      }

      dodebug(10, "mkisofs (stderr): %s\n", line);

      if (strncmp(line, "Total extents",13) == 0) {
            strcpy(tmp,line);
            p = strtok(tmp,"=");
            if (p) {
                  p = strtok(NULL,"");
                  if (p) {
                        masterparam.session_size = atoi(p);
                  }
            }
      }

      strcpy(tmp,line);
      strcat(tmp,"\n");

      convert_for_gtk2_textwidget(tmp);
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,tmp, strlen(tmp));

}


/* call mkisofs -print-size */

gint fill_mkisofs_check_info(GtkWidget *text_window) {
gchar cmd[MAXLINE*10];
gint read_out, read_err;
gchar tmp[MAXLINE];

      /* if another process running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* mark our process as running */
      read_done = 999;
      read_output_ctrl = 0;
      readerr_count = 0;

      /* be sure to overwrite old value */
      masterparam.session_size = 0;

      /* save text-window */
      readtrack_textview = text_window;

      /* get commandline */
      build_mkisofs_cmdline(cmd,1,NULL,masterparam.opt[22]);

      dodebug(1, "spawning: %s\n",cmd);
      dolog(1, "Getting size of mkisofs-image\n");
      dolog(3, "Executing: %s\n", cmd);

      readcdda_pid = full_dpl_pipe3(&read_out,NULL,&read_err,cmd,0);
      readcdda_pid2 = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_mkisofs_out, NULL);
      readcdda_callback2 = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) read_mkisofs_stderr, NULL);

      /* now wait until get_size is finished */
      while (read_done == 999) {
            wait_and_process_events();

            /* check if somebody clicked on cancel */
            if (dialog_done != 999) {
                        kill_readcdda();
                        /* mark we aborted */
                        read_output_ctrl = 1;
                        dialog_done = 999;
            }
      }

      close(read_err);
      close(read_out);


      /* we killed the process */
      if (read_output_ctrl == 1) {
            strncpy(tmp, _("\nScanning aborted!\n"), MAXLINE);
            convert_for_gtk2_textwidget(tmp);
            gtk_text_insert(GTK_TEXT(readtrack_textview),
                  fixedfont,NULL,NULL,tmp, strlen(tmp));
            return 2;
      }

      return 0; 
}


/* get output of mkisofs */

static void read_master_out(gpointer data, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p, *p2;
gfloat pval;

        n = read_line(source, line, MAXLINE);

        /* finished? */
        if (n <= 0) {
            gtk_input_remove(readcdda_callback);

                /* pick up return status of child */
                wait(&ret);

                read_done = WEXITSTATUS(ret);
                return;
        }

        dodebug(10,"mkisofs: %s\n", line);

      /* see if we finished with mastering - set to 100% */
      if (strncmp(line,"Total translation table size", 28) == 0) {
            gtk_progress_set_percentage( GTK_PROGRESS(readtrack_pbar1),
                                    1.0);
            set_xcdr_title(toplevel,viewmode_dialog,100);
            gtk_label_set_text(GTK_LABEL(readtrack_small_info2),
                                    "100%");
            /* mark we are really finished */
            read_output_ctrl = 3;
      }     

      /* we are finished with scanning directories - update infotext */
      if (read_output_ctrl == 1) {
            /* update only once */
            read_output_ctrl = 2;

            convert_kbytes2mbstring(masterparam.session_size * 2, tmp);
            g_snprintf(tmp2,MAXLINE,_("Mastering data track [%s]"), tmp);
            gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   

            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Mastering:"));    
      }


      /* see if we got a percentage value and set progress bar */
      strcpy(tmp,line);
      p = strtok(tmp,",");
      if (p != NULL) {
            p2 = strtok(NULL,"");
            if (p2 != NULL) {
                  strcpy(tmp2,p2);
                  strip_string(tmp2);
                  if (strncmp(tmp2,"estimate finish",15) == 0) {
                        /* ok..its a percentage line */
                        if (read_output_ctrl == 0) {
                              read_output_ctrl = 1;
                        }
                        strcpy(tmp2,p);
                        p = strtok(tmp2,"%");
                        if (p != NULL) {
                              strcpy(tmp,p);
                              pval = atof(tmp);
                              pval = pval/100;
                              if (pval > 1.0) pval = 1.0;
                              gtk_progress_set_percentage(
                                    GTK_PROGRESS(readtrack_pbar1),
                                    pval);
                              set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval*100+0.5));
                              /* update small view */
                              g_snprintf(tmp,MAXLINE,"%d%%",
                                    (gint)(pval*100+0.5));
                              gtk_label_set_text(
                                 GTK_LABEL(readtrack_small_info2),
                                    tmp);
                              return;
                        }     
                  }
            }
      }

        /* forward most other output to textview-window */
        strcat(line,"\n");
        gtk_text_insert(GTK_TEXT(readtrack_textview),
                fixedfont,NULL,NULL, line, strlen(line));

}


/* call mkisofs to master a image */

gint start_master_action() {
char cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
gint read_dummy, read_err;

      /* if another write running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* mark our write-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      read_abort_mark = 0;
      
      /* set info label */
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Scanning master directories..."));

      /* build command line */
      build_mkisofs_cmdline(cmd, 0, masterparam.image_filename, masterparam.opt[22]);

      dodebug(1, "spawning: %s\n",cmd);
      dolog(1,"Master image %s\n", masterparam.image_filename);
      dolog(3,"Executing: %s\n", cmd);

      /* yes...command line is done */
      readcdda_pid = full_dpl_pipe3(&read_dummy,NULL,&read_err,cmd,0);
      readcdda_pid2 = -1;

      fcntl(read_dummy, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) read_master_out, NULL);
      readcdda_callback2 = gdk_input_add(read_dummy, GDK_INPUT_READ,
            (GdkInputFunction) read_cdda2wav_dummyout, NULL);

      /* now wait until write is finished */
      while (read_done == 999) {
            wait_and_process_events();
      }

      close(read_err);
      close(read_dummy);

      /* aborted master ? */
      if (read_abort_mark == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Mastering aborted..."));
            return 1;
      }

      /* all ok? */
      if (read_done == 0 && read_output_ctrl == 3) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Mastering successful"));
      } else {
            /* some error? */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Error mastering data track"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Master-Error:")); 
      }

      return 0;
}


/* do just swallow all output we get from stderr... and wait if the
   process terminated */

static void mkisofs_err(gpointer pid, gint source, GdkInputCondition cond) {
gint n;
gint ret;
gchar line[MAXLINE];

      n = read_line(source, line, MAXLINE);

      /* readcd-finished? */
      if (n <= 0) {
            gtk_input_remove(readcdda_callback3);

                /* pick up return status of child */
            waitpid((pid_t)GPOINTER_TO_INT(pid), &ret, WNOHANG);

            dodebug(10,"Finished in mkisofs_err\n");

            return;
      }     

      dodebug(10,"mkisofs (stderr): %s\n", line);
}



/* call cdrecord to write a master-image on the fly */

gint start_onthefly_master_action(gint write_devnr) {
gchar tmp[MAXLINE];
gchar tmp3[MAXLINE];
gchar tmp4[MAXLINE];
gchar cmd[MAXLINE*10];  /* extra big buffer for very long mkisofs options */
gchar cmd2[MAXLINE*10];
gchar outcmd[MAXLINE];
gint read_out, read_err, read_err2;
gint ret, tracknr;
pid_t pid1, pid2;
gint varirec_on, tmp_writer_speed;
gint wrmode;

      /* if another write running, ignore */
      if (read_done == 999) {
            return -1;
      }

      /* mark our write-process as running */
      read_done = 999;
      read_output_ctrl = 0;
      pct_so_far = 0.0;
      cdrecord_reload = 0;
      cdrtimer = 0;

      strcpy(outcmd,"");
            
      /* set info label */
      gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Initializing CD-Writer..."));

      /* reset writeparams-arrays */
      g_free(writeparams.tracktype);
      g_free(writeparams.frames);
      g_free(writeparams.pct_so_far_arr);
      g_free(writeparams.pct_this_track_arr);
      writeparams.tracktype = g_new0(gint,MAXTRACKS);
      writeparams.frames = g_new0(gint,MAXTRACKS);
      writeparams.pct_so_far_arr = g_new0(gfloat,MAXTRACKS);
      writeparams.pct_this_track_arr = g_new0(gfloat,MAXTRACKS);
      writeparams.nrtracks = 0;
      writeparams.simulation = curset.writesimul;

      /* build command line of masterprocess */
      build_mkisofs_cmdline(cmd, 0, NULL, 0);

      /* build command line of write process */

      /* get bus,id,lun string */
      if (convert_devnr2busid_dev(write_devnr,tmp) != 0) {
            g_error("non existing cdrom?");
      }

      /* get driveropts */
      varirec_on = do_driveropts(tmp4, curset.writer_devnr);

      get_wrap_path_cdrecord(tmp3);
      g_snprintf(cmd2, MAXLINE*10,
            "%s %s gracetime=%d fs=%dk -v %s ",  
            tmp3, tmp, get_gracetime(), get_cur_writer_fifo(), tmp4);

      if (get_cur_writer_drvmode() >= 0) {
            if (drivers[get_cur_writer_drvmode()] != NULL) {
                  g_snprintf(tmp,MAXLINE," driver=%s", 
                        drivers[get_cur_writer_drvmode()]->driver);
                  strcat(cmd2,tmp);
            }
      }
      
        /* special case with varirec - always use 4x here */
        if (varirec_on) {
                tmp_writer_speed = 4;
        } else {
                tmp_writer_speed = get_cur_writer_speed();
        }

      if (get_cur_writer_speed() >= 0) {
            g_snprintf(tmp,MAXLINE," speed=%d", tmp_writer_speed);      
            strcat(cmd2, tmp);
      }

      /* Ignore write-mode in multisession-mode */
      if (curset.multisession == 0) {
            wrmode = get_cur_writemode();
            if (wrmode == 0) {
                  strcat(cmd2," -dao");
            }
            if (wrmode == 2) {
                  strcat(cmd2," defpregap=0");
            }
            if (wrmode == 3) {
                  strcat(cmd2," -raw96r");
            }
            if (wrmode == 4) {
                  strcat(cmd2," -raw96p");
            }
            if (wrmode == 5) {
                  strcat(cmd2," -raw16");
            }
      }

      if (curset.writesimul == 1) {
            strcat(cmd2," -dummy");
      }
      if (curset.writeeject == 1) {
            strcat(cmd2," -eject");
      }
      if (curset.nofixate == 1) {
            strcat(cmd2," -nofix");
      }
      if (curset.multisession == 1) {
            if (is_a_sony(write_devnr)) {
                  strcat(cmd2," -multi -data");
            } else {
                  strcat(cmd2," -multi");
            }
      }
      if (curset.writepad == 1) {
            strcat(cmd2," -pad");
      }
      if (curset.writeswap == 1) {
            strcat(cmd2," -swab");
      }
      if (curset.writeoverburn == 1) {
            strcat(cmd2," -overburn");
      }
      if (curset.writeignsize == 1) {
            strcat(cmd2," -ignsize");
      }
      if (curset.writeimmed == 1) {
            strcat(cmd2," -immed");
      }

      /* now add track-specification: one data track */
      g_snprintf(tmp, MAXLINE, " -waiti tsize=%ds", 
            masterparam.session_size);
      strcat(cmd2, tmp);
      strcat(cmd2," -");

      /* save command line to view in progress window */
      g_snprintf(outcmd,MAXLINE, "Calling: %s\n\n", cmd2);

      /* fill up percent values for nice progressbar movement */
      tracknr = 1;
      writeparams.tracktype[tracknr] = 0; /* data */
      writeparams.frames[tracknr] = masterparam.session_size;
      writeparams.pct_this_track_arr[tracknr] = 1.0;  
      writeparams.pct_so_far_arr[tracknr] = 0.0;
      writeparams.nrtracks = 1;

      dodebug(1, "spawning: %s | %s \n",cmd, cmd2);
      dolog(1,"Master CD on the fly\n");
      dolog(3,"Executing: %s | %s\n", cmd, cmd2);

      /* output command to get better debug output */
      gtk_text_insert(GTK_TEXT(readtrack_textview),
            fixedfont,NULL,NULL,outcmd, strlen(outcmd));

      /* yes...command line is done */
      full_dpl_pipe4(&pid1,&pid2,NULL,&read_err,cmd,&read_out,&read_err2,cmd2,0);
      mkisofs_pid = pid1;
      readcdda_pid = pid2;
      readcdda_pid2 = -1;

      fcntl(read_out, F_SETFL, O_NONBLOCK);
      fcntl(read_err, F_SETFL, O_NONBLOCK);
      fcntl(read_err2, F_SETFL, O_NONBLOCK);

      readcdda_callback = gdk_input_add(read_out, GDK_INPUT_READ,
            (GdkInputFunction) read_write_out, GINT_TO_POINTER(read_err2));
      readcdda_callback2 = gdk_input_add(read_err2, GDK_INPUT_READ,
            (GdkInputFunction) read_write_stderr, NULL);
      readcdda_callback3 = gdk_input_add(read_err, GDK_INPUT_READ,
            (GdkInputFunction) mkisofs_err, GINT_TO_POINTER(pid1));

      /* now wait until write is finished */
      while (read_done == 999) {
            wait_and_process_events();

            /* check if writer is waiting for reload medium */
            if (cdrecord_reload > 0) {
                  show_dialog(ICO_WARN, _("Please reload the CD-R in the writer"), T_OK, NULL, NULL, -1);
                  
                  /* now send CR to cdrecord to let it continue */
                  if (cdrecord_reload == 1) {
                        if (write(read_err2, "\n", 1) != 1) {
                              g_warning("write error to cdrecord pipe\n");
                        }
                  }

                  /* cdrecord also accepts a SIGUSR1 to continue */
                  /* send wakeup signal */
                  if (cdrecord_reload == 2) {
                        dodebug(1,"Sending SIGUSR1 to cdrecord (pid: %d) after reload.\n", (gint) pid2);
                        kill(pid2, SIGUSR1);
                  }
                  cdrecord_reload = 0;
            }

            /* check if somebody clicked on cancel */
            if (dialog_done2 != 999) {
                  ret = show_dialog(ICO_WARN, _("Are you sure you want to abort the writing?\nAborting may damage the CD-RW and may require that you have\nto power-cycle the burner to get working again."),
                        T_YES, T_NO, NULL, 1);
                  if (ret == 0) {
                        /* really abort */
                        kill_readcdda();
                        /* mark we aborted */
                        read_output_ctrl = 1;   
                        dialog_done2 = 999;
                  } else {
                        /* not abort - undo button press */
                        dialog_done2 = 999;
                  }
            }
      }

      close(read_err2);
      close(read_err);
      close(read_out);

      /* no disk */
      if (read_output_ctrl == 2) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("No disk or wrong disk loaded."));
            return 1;
      }

      /* cannot send cue sheet */
      if (read_output_ctrl == 4) {
            show_dialog(ICO_WARN,_("Your CD-Writer did not accept the CUE sheet needed for\nDAO writing. This could mean that cdrecord does not support DAO\nwith your writer. Select TAO mode and try again."),T_OK, NULL, NULL, 0);
      }

      /* aborted write ? */
      if (read_output_ctrl == 1) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Writing aborted..."));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
            return 1;
      }

      /* error while reading ?*/
      if (read_done != 0 || read_output_ctrl == 5) {
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Error writing tracks"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Write-Error:"));
                if (read_done == 2) {
                        /* invalid cdrecord key - show window */
                  display_invalid_prodvdkey();
                }
            return 1;
      } else {
            /* all ok */
            gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Tracks successfully written"));
            gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Successful:"));
            return 0;
      }
}


/* check the version of cdrecord */
/* return 1 if not correct (to old) */

gint check_version_cdrecord(gchar *match, gchar *found, gint *isProDVD) {
gchar line[MAXLINE];
gchar vline[MAXLINE];
gchar ver[MAXLINE];
FILE *fpin;
gchar *p;

      *isProDVD = 0;
      strcpy(ver,"");
      get_wrap_path("CDRECORD",line);
      strcat(line," -version 2>/dev/null");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      strcpy(line,"");
      strcpy(vline,"");
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"got: %s",line);

            /* only get first line */
            if (strcmp(vline,"") == 0) {
                  strncpy(vline, line, MAXLINE);
            }
            if (strstr(line, "This version is an unofficial (modified) version with DVD support")) {
                  dodebug(1, "WARNING: Inoffical cdrecord version found!\n", line);
                  *isProDVD = 1;
            }
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      if (strcmp(vline,"") == 0 || strstr(vline,"sh:") != NULL) {
            /* failed to open - permission denied */
            return 2;
      }

      /* now line contains the version string of cdrecord */
      /* try to extract the version number */

      p = strstr(vline,"release");
      if (p != NULL) {
            p = strtok(p+8, " ");
            if (p != NULL) {
                  strcpy(ver,p);
            }
      } else {
            p = strstr(vline, "ProDVD");
            if (p != NULL) {
                  *isProDVD = 1;
                  p = strtok(p, " ");
                  if (p != NULL) {
                    p = strtok(NULL, " ");
                    if (p != NULL) {
                        strcpy(ver,p);
                    }
                  }
            }     
            if (strcmp(ver,"") == 0) {
                  p = strstr(vline,"Cdrecord");
                  if (p != NULL) {
                        p = strtok(p+7, " ");
                        if (p != NULL) {
                              p = strtok(NULL, " ");
                              if (p) {
                                    strcpy(ver,p);
                              }
                        }
                  }
            }
      }

      /* not even a version-string found */
      if (strcmp(ver,"") == 0) {
            strcpy(found,"-unknown-");
            return 1;
      }

      /* check if the version is new enough to support 
         on the fly audio */
      if (compare_versions(ver,CDRECORD_VERSION_WITH_ONTHFLYAUDIO) >= 0) {
            support_ontheflyaudio = 1;
      }

      /* now compare the version string */
      if (compare_versions(ver,match) >= 0) {
            strcpy(found,ver);
            return 0;
      } else {
            strcpy(found,ver);
            return 1;
      }
}

/* check the version of mkisofs */
/* return 1 if not correct (to old) */

gint check_version_mkisofs(gchar *match, gchar *found) {
gchar line[MAXLINE];
gchar ver[MAXLINE];
FILE *fpin;
gchar *p;

      strcpy(ver,"");
      get_wrap_path("MKISOFS",line);
      strcat(line," -version 2>/dev/null");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      strcpy(line,"");
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"got: %s",line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      if (strcmp(line,"") == 0 || strstr(line,"sh:") != NULL) {
            /* failed to open - permission denied */
            return 2;
      }


      /* now line contains the version string of mkisofs */
      /* try to extract the version number */

      p = strstr(line,"mkisofs");
      if (p != NULL) {
            p = strtok(p+8, " ");
            if (p != NULL) {
                  strcpy(ver,p);
            }
      }

      /* not even a version-string found */
      if (strcmp(ver,"") == 0) {
            strcpy(found,"-unknown-");
            return 1;
      }
      
      /* now compare the version string */
      if (compare_versions(ver,match) >= 0) {
            strcpy(found,ver);
            return 0;
      } else {
            strcpy(found,ver);
            return 1;
      }
}

/* check the version of cdda2wav */
/* return 1 if not correct (to old) */

gint check_version_cdda2wav(gchar *match, gchar *found) {
gchar line[MAXLINE];
gchar ver[MAXLINE];
FILE *fpin;
gchar *p;

      strcpy(ver,"");
      get_wrap_path("CDDA2WAV",line);
      strcat(line," -version 2>&1");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      strcpy(line,"");
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"got: %s",line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      if (strcmp(line,"") == 0 || strstr(line,"sh:") != NULL) {
            /* failed to open - permission denied */
            return 2;
      }

      /* now line contains the version string of cdda2wav */
      /* try to extract the version number */

      p = strstr(line,"version");
      if (p != NULL) {
            p = strtok(p+8, " _");
            if (p != NULL) {
                  strcpy(ver,p);
            }
      } else {
            p = strstr(line,"cdda2wav");
            if (p != NULL) {
                  p = strtok(p+9, " ");
                  if (p != NULL) {
                        strcpy(ver,p);
                  }
            }
      }

      /* not even a version-string found */
      if (strcmp(ver,"") == 0) {
            strcpy(found,"-unknown-");
            return 1;
      }
      
      /* now compare the version string */
      if (compare_versions(ver,match) >= 0) {
            strcpy(found,ver);
            return 0;
      } else {
            strcpy(found,ver);
            return 1;
      }
}


/* check the version of readcd */
/* return 1 if not correct (to old) */

gint check_version_readcd(gchar *match, gchar *found) {
gchar line[MAXLINE];
gchar ver[MAXLINE];
FILE *fpin;
gchar *p;

      strcpy(ver,"");
      get_wrap_path("READCD",line);
      strcat(line," -version 2>/dev/null");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      strcpy(line,"");
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"got: %s",line);
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      if (strcmp(line,"") == 0 || strstr(line,"sh:") != NULL) {
            /* failed to open - permission denied */
            return 2;
      }


      /* now line contains the version string of readcd */
      /* try to extract the version number */

      p = strstr(line,"readcd");
      if (p != NULL) {
            p = strtok(p+7, " ");
            if (p != NULL) {
                  strcpy(ver,p);
            }
      }

      /* not even a version-string found */
      if (strcmp(ver,"") == 0) {
            strcpy(found,"-unknown-");
            return 1;
      }
      
      /* now compare the version string */
      if (compare_versions(ver,match) >= 0) {
            strcpy(found,ver);
            return 0;
      } else {
            strcpy(found,ver);
            return 1;
      }
}


/* check the version of the wrapper */
/* return 1 if not correct */
/* return 2 if user denied */
/* return 3 if rootconfig unreadable */

gint check_version_wrapper(gchar *tmp) {
gchar line[MAXLINE];
gchar xcdrver[MAXLINE];
gchar sharever[MAXLINE];
gchar prefixver[MAXLINE];
FILE *fpin;
gint ret;
gint unreadable;

      strcpy(xcdrver,"-unknown-");
      strcpy(sharever,"-unknown-");
      strcpy(prefixver,"-unknown-");
      strncpy(line,tmp, MAXLINE);
      strcat(line," -V");
      ret = 0;
      unreadable = 0;

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      strcpy(line,"");
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            dodebug(10,"got: %s",line);

            if (strncmp(line,"X-CD-Roast ", 11) == 0) {
                  strcpy(xcdrver,line+11);
            }
            if (strncmp(line,"sharedir: ", 10) == 0) {
                  strcpy(sharever,line+10);
            }
            if (strncmp(line,"prefixdir: ", 11) == 0) {
                  strcpy(prefixver,line+11);
            }
            if (strncmp(line,"Warning: rootconfig unreadable", 30) == 0) {
                  unreadable = 1;
            }
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      strip_string(xcdrver);
      strip_string(sharever);
      strip_string(prefixver);

      if (strcmp(xcdrver,"ACCESS DENIED") == 0) {
            return 2;
      }
      if (unreadable) {
            return 3;
      }
      if (strcmp(xcdrver,XCDROAST_VERSION) != 0) {
            fprintf(stderr, "CRITICAL: Wrapper %s from\n\tVersion %s instead of %s\n", 
                  tmp, xcdrver, XCDROAST_VERSION);
            ret = 1;
      }
      if (strcmp(sharever,sharedir) != 0) {
            fprintf(stderr, "WARNING: Wrapper %s configured\n\tsharedir %s instead of %s\n", 
                  tmp, sharever, sharedir);
            ret = 0;
      }
      if (strcmp(prefixver,prefixdir) != 0) {
            fprintf(stderr, "CRITICAL: Wrapper %s configured\n\tprefixdir %s instead of %s\n", 
                  tmp, prefixver, prefixdir);
            ret = 1;
      }

      return ret;
}


/* check if this user is allowed to write in the given directory */
/* uses the wrapper to have real conditions */
/* return 0 if writeable, 1 if not */

gint is_dir_writeable(gchar *dir) {
gchar line[MAXLINE];
gchar tmp[MAXLINE];
FILE *fpin;
gint stat;

      get_wrap_path("WRITETEST", tmp);
      g_snprintf(line,MAXLINE,"%s \"%s\"", tmp, dir);

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
        }

      stat = pclose(fpin);
        if (stat == -1) {
                g_error("pclose error\n");
        }

      return (WEXITSTATUS(stat));
}


/* return the commands to use to activate non-root-mode */
/* return 0 if all checks ok */

gint get_commands_to_change_nrm(gchar *ret, gint mode) {
gchar tmp[MAXLINE];
gchar bin[MAXLINE];
gint groupaddok;
gchar cmd_chown[MAXLINE], cmd_chmod[MAXLINE];
#if 0
gchar cmd_chgrp[MAXLINE];
nonroot_flags_t *entry;
GList *nrs_vals, *loop;
gchar tmp2[MAXLINE];
#endif

      strcpy(ret,"");
      groupaddok = 0;

      /* check if basic commands are available */
      get_chown_cmd(cmd_chown);
      if (cmd_chown[0] == '\0') {
            strcat(ret,"\nError: No chown command found");
            return 1;
      }

#if 0
      get_chgrp_cmd(cmd_chgrp);
      if (cmd_chgrp[0] == '\0') {
            strcat(ret,"\nError: No chgrp command found");
            return 1;
      }
#endif

      get_chmod_cmd(cmd_chmod);
      if (cmd_chmod[0] == '\0') {
            strcat(ret,"\nError: No chmod command found");
            return 1;
      }

      /* activate non-root-mode */
      if (mode == 0) {
#if 0
       /* check if we need to create a group for the wrapper */
       if (!check_group_exists(NONROOTMODEGROUP)) {
            /* we have to create a group here */
            if (stat(GROUPADD,&buf) == 0) {
                  if (buf.st_mode & S_IEXEC) {
                        /* groupadd exists and is an exectable */
                        groupaddok = 1;
                  }
            }
            if (!groupaddok) {
                  g_snprintf(tmp,MAXLINE,_("Warning: No \"groupadd\" command found on your system.\n - Edit \"/etc/group\" and add a group \"%s\" manually.\n    Please try again then."), NONROOTMODEGROUP);
                  strcat(ret,tmp);
                  /* abort, without group its no way for us */
                  return 1;
            } else {
                  /* create command to create new group */
#if defined(__FreeBSD__)
                  g_snprintf(tmp,MAXLINE,"%s groupadd -n %s\n", GROUPADD, NONROOTMODEGROUP);
#else
                  g_snprintf(tmp,MAXLINE,"%s %s\n", GROUPADD, NONROOTMODEGROUP);
#endif
                  strcat(ret,tmp);
            }     
       }
#endif
      
       /* set the correct permissions to the wrapper */
       g_snprintf(bin,MAXLINE,"%s/%s", sharedir, WRAPPER);
       g_snprintf(tmp,MAXLINE,"%s root %s\n", cmd_chown, bin);
       strcat(ret,tmp);
#if 0
       g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, NONROOTMODEGROUP, bin);
       strcat(ret,tmp);
#endif
       /* old nonroot mode - 2755 */
       g_snprintf(tmp,MAXLINE,"%s 4755 %s\n", cmd_chmod, bin);
       strcat(ret,tmp);


#if 0 
       /* set correct permissions for cdrtools */
       get_spawn_path(CDRECORD,bin);
       g_snprintf(tmp,MAXLINE,"%s root %s\n", cmd_chown, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, NONROOTMODEGROUP, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s 4710 %s\n", cmd_chmod, bin);
       strcat(ret,tmp);

       get_spawn_path(CDRECORDPRODVD,bin);
       if (is_file(bin)) {
            g_snprintf(tmp,MAXLINE,"%s root %s\n", cmd_chown, bin);
            strcat(ret,tmp);
            g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, NONROOTMODEGROUP, bin);
            strcat(ret,tmp);
            g_snprintf(tmp,MAXLINE,"%s 4710 %s\n", cmd_chmod, bin);
            strcat(ret,tmp);
       }

       get_spawn_path(MKISOFS,bin);
       g_snprintf(tmp,MAXLINE,"%s root %s\n", cmd_chown, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, NONROOTMODEGROUP, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s 4710 %s\n", cmd_chmod, bin);
       strcat(ret,tmp);

       get_spawn_path(READCD,bin);
       g_snprintf(tmp,MAXLINE,"%s root %s\n", cmd_chown, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, NONROOTMODEGROUP, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s 4710 %s\n", cmd_chmod, bin);
       strcat(ret,tmp);

       get_spawn_path(CDDA2WAV,bin);
       g_snprintf(tmp,MAXLINE,"%s root %s\n", cmd_chown, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, NONROOTMODEGROUP, bin);
       strcat(ret,tmp);
       g_snprintf(tmp,MAXLINE,"%s 4710 %s\n", cmd_chmod, bin);
       strcat(ret,tmp);
#endif

      } else {
            /* deactivate non-root-mode */

#if 0
            nrs_vals = NULL;
            /* try to load original flags from file */
            load_nonrootvalues(configdir, NONROOTBAK, &nrs_vals);

            /* loop through all values */
            loop = g_list_first(nrs_vals);
            while(loop) {
                  entry = (nonroot_flags_t *)loop->data;

                  return_user_name(entry->uid, tmp2);
                  g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chown,
                        tmp2, entry->path);
                  strcat(ret,tmp);
                  return_group_name(entry->gid, tmp2);
                  g_snprintf(tmp,MAXLINE,"%s %s %s\n", cmd_chgrp, 
                        tmp2, entry->path);
                  strcat(ret,tmp);
                  g_snprintf(tmp,MAXLINE,"%s %o %s\n", cmd_chmod, 
                        (gint) entry->mode, entry->path);
                  strcat(ret,tmp);

                  loop = loop->next;  
            }
            free_nonrootvalues(&nrs_vals);
#endif
            g_snprintf(bin,MAXLINE,"%s/%s", sharedir, WRAPPER);
            g_snprintf(tmp,MAXLINE,"%s 755 %s\n", cmd_chmod, bin);
            strcat(ret,tmp);
      }
      return 0;
}


/* save the current file owners and permissions to a file */
#if 0
gint save_current_nonrootvalues(gchar *confdir, gchar *fname) {
gchar bin[MAXLINE];
gchar tmp[MAXLINE];
gchar share[MAXLINE];
struct stat buf;
uid_t uid;
gid_t gid;
mode_t mode;
FILE *fd;
      
      /* make sharedir absolute if is not yet */
      if (sharedir[0] != '/') {
            getcwd(tmp,MAXLINE);
            g_snprintf(share,MAXLINE,"%s/%s", tmp, sharedir);     
      } else {
            strcpy(share,sharedir);
      } 

      /* first create directory to store nonrootconfig */
      if (!is_directory(confdir)) {
            /* try to create directory */
            mkdir(confdir, 0700);
            dodebug(2, "trying to mkdir %s\n", confdir);
      }
      g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);

      dodebug(1, "Opening %s for writing\n", tmp);

      fd = fopen(tmp,"w"); 
      if (fd == NULL) { 
            /* error opening file */
            return 1;
      }

      /* write the config-file header */
      fputs("#\n",fd);
      g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s Non-Root-Mode Configuration\n",XCDROAST_VERSION);
      fputs(tmp,fd);
      fputs("#\n",fd);
      fputs("# Contains the files with their flags before they got changed\n",fd);
      fputs("# by X-CD-Roast Non-Root-Mode activation.\n", fd);
      fputs("# Used to restore the original values when disabling Non-Root-Mode.\n",fd);
      fputs("#\n",fd);
 
      /* get details about the wrapper */
      g_snprintf(bin,MAXLINE,"%s/%s", share, WRAPPER);
      if (stat(bin,&buf) == 0) {
            uid = buf.st_uid;
            gid = buf.st_gid;
            mode = buf.st_mode & 07777;

            g_snprintf(tmp,MAXLINE,"%s: %d %d 0%o\n", bin, 
                  (gint) uid, (gint) gid, (gint) mode);
            fputs(tmp,fd);
      }

      /* now the cdrtools - make path absolute */
      get_spawn_path(CDRECORD,bin);
      if (bin[0] != '/') {
            getcwd(tmp,MAXLINE);
            g_snprintf(bin2,MAXLINE,"%s/%s", tmp, bin);     
      } else {
            strcpy(bin2,bin);
      } 
      if (stat(bin2,&buf) == 0) {
            uid = buf.st_uid;
            gid = buf.st_gid;
            mode = buf.st_mode & 07777;

            g_snprintf(tmp,MAXLINE,"%s: %d %d 0%o\n", bin2, 
                  (gint) uid, (gint) gid, (gint) mode);
            fputs(tmp,fd);
      }

      get_spawn_path(MKISOFS,bin);
      if (bin[0] != '/') {
            getcwd(tmp,MAXLINE);
            g_snprintf(bin2,MAXLINE,"%s/%s", tmp, bin);     
      } else {
            strcpy(bin2,bin);
      } 
      if (stat(bin2,&buf) == 0) {
            uid = buf.st_uid;
            gid = buf.st_gid;
            mode = buf.st_mode & 07777;

            g_snprintf(tmp,MAXLINE,"%s: %d %d 0%o\n", bin2, 
                  (gint) uid, (gint) gid, (gint) mode);
            fputs(tmp,fd);
      }

      get_spawn_path(READCD,bin);
      if (bin[0] != '/') {
            getcwd(tmp,MAXLINE);
            g_snprintf(bin2,MAXLINE,"%s/%s", tmp, bin);     
      } else {
            strcpy(bin2,bin);
      } 
      if (stat(bin2,&buf) == 0) {
            uid = buf.st_uid;
            gid = buf.st_gid;
            mode = buf.st_mode & 07777;

            g_snprintf(tmp,MAXLINE,"%s: %d %d 0%o\n", bin2, 
                  (gint) uid, (gint) gid, (gint) mode);
            fputs(tmp,fd);
      }

      get_spawn_path(CDDA2WAV,bin);
      if (bin[0] != '/') {
            getcwd(tmp,MAXLINE);
            g_snprintf(bin2,MAXLINE,"%s/%s", tmp, bin);     
      } else {
            strcpy(bin2,bin);
      } 
      if (stat(bin2,&buf) == 0) {
            uid = buf.st_uid;
            gid = buf.st_gid;
            mode = buf.st_mode & 07777;

            g_snprintf(tmp,MAXLINE,"%s: %d %d 0%o\n", bin2, 
                  (gint) uid, (gint) gid, (gint) mode);
            fputs(tmp,fd);
      }
      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      return 0;
      
}
#endif 


/* run a simple non-output-command and return exit status */

gint simple_exec(gchar *cmd) {
gchar line[MAXLINE];
FILE *fpin;
gint stat;

      dodebug(1, "calling: %s\n", cmd);
        if ((fpin = popen(cmd,"r")) == NULL) {
                g_error("popen error\n");
        }

        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
        }

      stat = pclose(fpin);
        if (stat == -1) {
            return -1;
        }

      return (WEXITSTATUS(stat));
}


/* load nonroot-values from file */
/* if some values not found, generate default */

#if 0

gint load_nonrootvalues(gchar *confdir, gchar *fname, GList **ret) {
gchar tmp[MAXLINE];
gchar line[MAXLINE];
gchar path[MAXLINE];
FILE *fd;
gchar *p;
gint uid, gid, mode;
gint foundwrapper, foundcdrecord, foundmkisofs, foundcdda2wav, foundreadcd;

      foundwrapper = 0;
      foundcdrecord = 0;
      foundmkisofs = 0;
      foundcdda2wav = 0;
      foundreadcd = 0;

      g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);

      /* open file */
        if ((fd = fopen(tmp,"r")) != NULL) { 

         dodebug(1, "Opened %s for reading\n", tmp);


         for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                dodebug(10,"non-root-values: %s", line),

                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0') 
                        continue;

            uid = -1;
            gid = -1;
            mode = -1;

            /* extract path */
            strncpy(path,line,MAXLINE);
            p = rindex(path,':');
            if (p) {
                  *p = '\0';
                  
                  strncpy(tmp, p+1, MAXLINE);
                  strip_string(tmp);
                  
                  /* extract uid, gid and mode */
                  p = strtok(tmp," ");
                  if (p) {
                        uid = atoi(p);
                        p = strtok(NULL," ");
                        if (p) {
                              gid = atoi(p);
                              p = strtok(NULL,"");
                              if (p) {
                                    mode = strtol(p, (char **)NULL,  8);
                              }
                        }
                  }                       
            } else {
                  *path = '\0';
            }

            /* all data extracted successfully? */
            if (*path != '\0' && uid != -1 && gid != -1 && mode != -1) {
                  
                  add_to_nonrootvalues(ret, path, uid, gid, mode);

                  /* check what entry we just added */
                  if (strstr(path, WRAPPER)) {
                        foundwrapper = 1;
                  }
                  if (strstr(path, CDRECORD)) {
                        foundcdrecord = 1;
                  }
                  if (strstr(path, MKISOFS)) {
                        foundmkisofs = 1;
                  }
                  if (strstr(path, READCD)) {
                        foundreadcd = 1;
                  }
                  if (strstr(path, CDDA2WAV)) {
                        foundcdda2wav = 1;
                  }
            }

       }

       fclose(fd);
      }

      /* now we read the file (or not, if it was not found) and add
         default values for any things we are missing */
      if (!foundwrapper) {
            g_snprintf(path,MAXLINE,"%s/%s", sharedir, WRAPPER);
            add_to_nonrootvalues(ret, path, 0, 0, 0755);
      }
      if (!foundcdrecord) {
            get_spawn_path(CDRECORD,path);
            add_to_nonrootvalues(ret, path, 0, 0, 0755);
      }
      if (!foundmkisofs) {
            get_spawn_path(MKISOFS,path);
            add_to_nonrootvalues(ret, path, 0, 0, 0755);
      }
      if (!foundreadcd) {
            get_spawn_path(READCD,path);
            add_to_nonrootvalues(ret, path, 0, 0, 0755);
      }
      if (!foundcdda2wav) {
            get_spawn_path(CDDA2WAV,path);
            add_to_nonrootvalues(ret, path, 0, 0, 0755);
      }

      return 0;
}
#endif 

/* reads the .xinf file for a given track and writes a new .inf file
   with the updated cd-text information */

void edit_xinf_for_cd_text(gchar *trackfile, gchar *tocfile) {
gchar xinfname[MAXLINE], infname[MAXLINE];
gchar tmp[MAXLINE];
gchar *p;
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gchar title[MAXLINE], artist[MAXLINE], cddbtitle[MAXLINE];
gchar cdtitle[MAXLINE], cdartist[MAXLINE];

/*
      g_print("tocfile: %s, file: %s\n", tocfile, trackfile);
*/

      /* generate xinf and inf filenames */
      strncpy(tmp,trackfile,MAXLINE - 4);
      p = rindex(tmp,'.');
      if (!p) return;
      *p = '\0';
      strcpy(xinfname,tmp);
      strcpy(infname,tmp);
      strcat(xinfname,XCDROAST_INFO_EXT);
      strcat(infname,".inf");

      dodebug(10, "reading cdtext from %s\n", xinfname);
      
      if ((fd = fopen(xinfname,"r")) == NULL) { 
            return;
      }

      strcpy(title,"");
      strcpy(artist,"");
      strcpy(cddbtitle,"");

      for (;;) {
            if (fgets(line,MAXLINE,fd) == NULL)
                  break;

            /* skip empty or hashed lines */
            strip_string(line);
            if (*line == '#' || *line == '\0')
                  continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  dodebug(10,"invalid line in infofile");
                  fclose(fd);
                  return;
            }     

            if (strcmp("title",id) == 0) {
                  strncpy(title, value, MAXLINE);
            }
            if (strcmp("artist",id) == 0) {
                  strncpy(artist, value, MAXLINE);
            }
            if (strcmp("cddb_ttitle",id) == 0) {
                  strncpy(cddbtitle, value, MAXLINE);
            }
      }

      if (fclose(fd) != 0) {
            return;
      }


      /* decide if we use cddb info rather than cd-text info? */
      if (strcmp(title,"") == 0) {
            if (strcmp(cddbtitle,"") != 0) {
                  /* no title, but cddb given */
                  strncpy(title, cddbtitle, MAXLINE);
            }
      }

      strcpy(cdtitle,"");
      strcpy(cdartist,"");

      /* now read toc file for cd-title/artist */
      if (strcmp(tocfile,"-") != 0) {
            dodebug(10, "reading cdtext from %s\n", tocfile);

            fd = fopen(tocfile,"r");
      
            if (fd) {
                  for (;;) {
                        if (fgets(line,MAXLINE,fd) == NULL)
                              break;

                        /* skip empty or hashed lines */
                        strip_string(line);
                        if (*line == '#' || *line == '\0')
                              continue;

                        /* parse lines */
                        if (parse_config_line(line,id,value)) {
                              dodebug(10,"invalid line in toc");
                              fclose(fd);
                              return;
                        }
                        if (strcmp("cdtitle",id) == 0) {
                              strncpy(tmp, value, MAXLINE);
                              get_artist_and_title_from_cddb(
                                    tmp, cdartist, cdtitle);
                        }     
                  }     
                  fclose(fd);
            }
      }

      /* now we have read all the info from the xinf and toc file */

      /* edit the original .inf file */
      edit_xinf_for_cd_text2(infname, title, artist, cdtitle, cdartist);
}


/* patch the given cd-text information the the inffile */

static void edit_xinf_for_cd_text2(gchar *infname, gchar *title, gchar *artist, gchar *cdtitle, gchar *cdartist) {
gchar tmpinfname[MAXLINE];
gchar tmp[MAXLINE];
gchar line[MAXLINE];
FILE *fd, *fd2;
gchar timestr[MAXLINE];
gint found, found2, found3, found4;
time_t acttime;

      dodebug(10, "cd-text info: %s, %s, %s, %s\n", title, artist, cdtitle, cdartist);    

      /* get current time */
      acttime = time((time_t *) 0);
      strcpy(timestr,ctime(&acttime));
      timestr[strlen(timestr)-1] = '\0';

      g_snprintf(tmpinfname,MAXLINE,"%s-%d", infname, (gint) getpid()); 

      /* now modify the original inf file */
      fd = fopen(infname,"r");
      if (!fd) {
            /* no inf file? - generate one */
            fd2 = fopen(infname,"w");
            if (!fd2) return;
            
            /* write releveant data to new inf file */
            g_snprintf(tmp,MAXLINE,"#created by X-CD-Roast %s at %s\n", XCDROAST_VERSION, timestr);
            fputs(tmp, fd2);
            fputs("#\n",fd2);

            g_snprintf(tmp,MAXLINE,"Performer=\t'%s'\n", artist);
            fputs(tmp, fd2);

            g_snprintf(tmp,MAXLINE,"Albumtitle=\t'%s'\n", cdtitle);
            fputs(tmp, fd2);

            g_snprintf(tmp,MAXLINE,"Tracktitle=\t'%s'\n", title);
            fputs(tmp, fd2);

            g_snprintf(tmp,MAXLINE,"Albumperformer=\t'%s'\n", cdartist);
            fputs(tmp, fd2);
      
            fclose(fd2);

            dodebug(10, "created cd-text-info as %s\n", infname);
      } else {
            /* inf file openend - open now tmpfile */
            fd2 = fopen(tmpinfname,"w");
            if (!fd2) {
                  fclose(fd);
                  return;
            }

            found = 0;
            found2 = 0;
            found3 = 0;
            found4 = 0;
      
            for (;;) {
                  if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                  /* write modifcation date of xcdroast in new file */
                  if (strncmp(line,"#created", 8) == 0) {
                        fputs(line, fd2);
                        g_snprintf(tmp,MAXLINE,"#modified by X-CD-Roast %s at %s\n", XCDROAST_VERSION, timestr);
                        fputs(tmp, fd2);
                        continue;
                  }     

                  /* skip old modfied lines */
                  if (strncmp(line,"#modified by X-CD-Roast", 23) == 0) {
                        continue;
                  }

                  /* replace performer */
                  if (strncmp(line,"Performer=", 10) == 0) {
                        g_snprintf(tmp,MAXLINE,"Performer=\t'%s'\n", artist);
                        fputs(tmp, fd2);
                        found = 1;
                        continue;
                  }

                  /* replace title */
                  if (strncmp(line,"Tracktitle=", 11) == 0) {
                        g_snprintf(tmp,MAXLINE,"Tracktitle=\t'%s'\n", title);
                        fputs(tmp, fd2);
                        found2 = 1;
                        continue;
                  }

                  /* replace albumtitle */
                  if (strncmp(line,"Albumtitle=", 11) == 0) {
                        g_snprintf(tmp,MAXLINE,"Albumtitle=\t'%s'\n", cdtitle);
                        fputs(tmp, fd2);
                        found3 = 1;
                        continue;
                  }

                  /* replace albumperformer */
                  if (strncmp(line,"Albumperformer=", 11) == 0) {
                        g_snprintf(tmp,MAXLINE,"Albumperformer=\t'%s'\n", cdartist);
                        fputs(tmp, fd2);
                        found4 = 1;
                        continue;
                  }

                  fputs(line,fd2);
            }

            /* could not replace all the original lines? add any
               missing now */
            if (found == 0) {
                  g_snprintf(tmp,MAXLINE,"Performer=\t'%s'\n", artist);
                  fputs(tmp, fd2);
            }
            if (found3 == 0) {
                  g_snprintf(tmp,MAXLINE,"Albumtitle=\t'%s'\n", cdtitle);
                  fputs(tmp, fd2);
            }
            if (found2 == 0) {
                  g_snprintf(tmp,MAXLINE,"Tracktitle=\t'%s'\n", title);
                  fputs(tmp, fd2);
            }
            if (found4 == 0) {
                  g_snprintf(tmp,MAXLINE,"Albumperformer=\t'%s'\n", cdartist);
                  fputs(tmp, fd2);
            }

            fclose(fd2);
            fclose(fd);
            
            /* now move the temporary file over the original inf file */
            move_textfile(tmpinfname, infname);

            dodebug(10, "modified cd-text-info in %s\n", infname);
      }

}


/* does overwrite the artist and title information in the given toc file */

void edit_title_artist_in_toc_file(gchar *tocfile, gchar *title, gchar *artist) {
FILE *fd, *fd2;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmptitle[MAXLINE];
gchar tmpartist[MAXLINE];
gchar tmptocfile[MAXLINE];
gint found;
struct stat buf;

      /* check first if file exists before overwriting it */
      if (lstat(tocfile, &buf) == 0) {

            /* file real and owner is also yourself? */
            if (buf.st_uid != getuid() || S_ISLNK(buf.st_mode)) {
                  dodebug(1, "cannot edit tocfile %s, because file already exists and it belongs not to us, or is a link\n", tocfile);
                  return;     
            }
      }

      found = 0;
      g_snprintf(tmptocfile,MAXLINE,"%s-%d", tocfile, (gint) getpid()); 

      dodebug(10, "updating toc file %s with new title/artist\n", tocfile);

      /* open toc file for reading */
        if ((fd = fopen(tocfile,"r")) == NULL) { 
            /* no file? */
                return;
        }

      /* open temporary tocfile to copy */
        if ((fd2 = fopen(tmptocfile,"w")) == NULL) { 
            /* no file? */
            fclose(fd);
                return;
        }

      /* copy all lines and change the one with the cdtitle */
        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

            /* replace the line with the cdtitle */
            if (strncmp(line,"cdtitle", 7) == 0) {
                  strncpy(tmptitle, title, MAXLINE);
                  strncpy(tmpartist, artist, MAXLINE);
                  g_snprintf(tmp,MAXLINE,"cdtitle = \"%s / %s\"\n", convert_escape(tmptitle), convert_escape(tmpartist));
                  fputs(tmp, fd2);
                  found = 1;
                  continue;
            }

            fputs(line,fd2);
      }

      /* no line with cdtitle found? */
      if (found == 0) {
            /* add it */
            g_snprintf(tmp,MAXLINE,"cdtitle = \"%s / %s\"\n", title, artist);
            fputs(tmp, fd2);
      }
      fclose(fd2);
      fclose(fd);

        /* now move the temporary file over the original inf file */
        move_textfile(tmptocfile, tocfile);

}


/* edits or creates a xinf file with updated information of title and artist */

void edit_title_artist_in_xinf_file(gchar *trackfile, gchar *title, gchar *artist) {
FILE *fd, *fd2;
gchar line[MAXLINE];
gchar tmp[MAXLINE];
gchar tmptitle[MAXLINE];
gchar tmpartist[MAXLINE];
gchar xinfname[MAXLINE];
gchar tmpxinfname[MAXLINE];
gint found, found2;
gchar *p;
time_t acttime;
gchar timestr[MAXLINE];

        /* get current time */
        acttime = time((time_t *) 0);
        strcpy(timestr,ctime(&acttime));
        timestr[strlen(timestr)-1] = '\0';

      found = 0;
      found2 = 0;

        strncpy(tmp,trackfile,MAXLINE - 4);
        p = rindex(tmp,'.');
        if (!p) return;
        *p = '\0';
        strcpy(xinfname,tmp);
        strcat(xinfname,XCDROAST_INFO_EXT);
        g_snprintf(tmpxinfname,MAXLINE,"%s-%d", xinfname, (gint) getpid());

      /* try to open the xinf file */
        if ((fd = fopen(xinfname,"r")) == NULL) { 
            /* no such file? try to create a new */
            fd = fopen(xinfname,"w");
            if (!fd) return;

            dodebug(10, "creating xinf-file %s with new title/artist\n", xinfname);

              /* write header */
              fputs("#\n",fd);
                  g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - INF-File\n",XCDROAST_VERSION);
            fputs(tmp,fd);
                  g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
            fputs(tmp,fd);
            g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
            fputs(tmp,fd);
            fputs("#\n",fd);

              g_snprintf(tmp,MAXLINE,"file = \"%s\"\n",trackfile);
              fputs(tmp,fd);
            strncpy(tmptitle, title, MAXLINE);
              g_snprintf(tmp,MAXLINE,"title = \"%s\"\n",convert_escape(tmptitle));
              fputs(tmp,fd);
            strncpy(tmpartist, artist, MAXLINE);
              g_snprintf(tmp,MAXLINE,"artist = \"%s\"\n",convert_escape(tmpartist));
            fputs(tmp,fd);

            fclose(fd);
            return;
        }

        /* open temporary xinffile to copy */
        if ((fd2 = fopen(tmpxinfname,"w")) == NULL) { 
                /* no file? */
                fclose(fd);
                return;
        }

        /* copy a lines and change the one with the cdtitle */
        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                /* replace the line with the title */
                if (strncmp(line,"title", 5) == 0) {
                  strncpy(tmptitle, title, MAXLINE);
                        g_snprintf(tmp,MAXLINE,"title = \"%s\"\n", convert_escape(tmptitle));
                        fputs(tmp, fd2);
                        found = 1;
                        continue;
                }

                /* replace the line with the artist */
                if (strncmp(line,"artist", 6) == 0) {
                  strncpy(tmpartist, artist, MAXLINE);
                        g_snprintf(tmp,MAXLINE,"artist = \"%s\"\n", convert_escape(tmpartist)); 
                        fputs(tmp, fd2);
                        found2 = 1;
                        continue;
                }

                fputs(line,fd2);
        }

      /* lines missing? add them */
      if (found == 0) {
            strncpy(tmptitle, title, MAXLINE);
            g_snprintf(tmp,MAXLINE,"title = \"%s\"\n", convert_escape(tmptitle));
                fputs(tmp, fd2);
      }
      if (found2 == 0) {
            strncpy(tmpartist, artist, MAXLINE);
            g_snprintf(tmp,MAXLINE,"artist = \"%s\"\n", convert_escape(tmpartist));
            fputs(tmp, fd2);
      }

        fclose(fd2);
        fclose(fd);

      dodebug(10, "updated xinf-file %s with new title/artist\n", xinfname);

        /* now move the temporary file over the original inf file */
        move_textfile(tmpxinfname, xinfname);
}


/* will write a temporary toc file just to save the album title and performer
   of the tracks to be written in the write-tracks menu */

gint create_tmp_writetracks_tocfile(gchar *tocfile) {
FILE *fd;
time_t acttime;
gchar timestr[MAXLINE];
gchar tmp[MAXLINE];
struct stat buf;

      if (tocfile == NULL) return 1;

      /* check first if file exists before overwriting it */
      if (lstat(tocfile, &buf) == 0) {

            /* file real and owner is also yourself? */
            if (buf.st_uid != getuid() || S_ISLNK(buf.st_mode)) {
                  dodebug(1, "cannot create temporary tocfile %s, because file already exists and it belongs not to us, or is a link\n", tocfile);
                  return 1;   
            }
      }

      dodebug(8, "creating temporary tocfile %s\n", tocfile);
      fd = fopen(tocfile,"w"); 

        if (fd == NULL) {
                g_warning("Can't open file %s for writing\n",tocfile);
                return 1;
        }

        /* get current time */
        acttime = time((time_t *) 0);
        strcpy(timestr,ctime(&acttime));
        timestr[strlen(timestr)-1] = '\0';

        /* write header */
        fputs("#\n",fd);
        g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - temporary TOC-File\n",XCDROAST_VERSION);
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
        fputs(tmp,fd);
        fputs("#\n",fd);

      /* write empty cdtitle */
      g_snprintf(tmp,MAXLINE,"cdtitle = \"\"\n");
        fputs(tmp,fd);

      fclose(fd);

      return 0;
}


/* removes the temporary tocfile again */
/* makes plenty of security checks to remove only a "sane" file */

static void remove_tmp_writetracks_tocfile(gchar *tocfile) {
struct stat buf;

      /* check first if file exists before delting it */
      if (lstat(tocfile, &buf) == 0) {

            /* file real and owner is also yourself? */
            if (buf.st_uid == getuid() && !S_ISLNK(buf.st_mode)) {

                  dodebug(2, "removing temporary file %s\n", tocfile);
                  unlink(tocfile);  
            } else {
                  g_warning("Trying to remove file %s which does not belong us or is a link!\n", tocfile);
            }
      }
}


/* just read the line with the cdtitle from a tocfile and returns it */

void get_cdtitle_from_tmp_tocfile(gchar *tocfile, gchar *cdtitle) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];

      strcpy(cdtitle, "");

      dodebug(2, "reading temporary toc file %s\n", tocfile);
        fd = fopen(tocfile,"r");

        if (fd == NULL) {
            return;
        }

        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                dodebug(10,"read tocfile: %s", line);
                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0')
                        continue;

                /* parse lines */
                if (parse_config_line(line,id,value)) {
                        dodebug(10,"invalid line in tocfile");
                        fclose(fd);
                        return;
                }       

                if (strcmp("cdtitle",id) == 0) {
                        strncpy(cdtitle, value, MAXLINE);
                }
      }

      fclose(fd);
}


/* saves the current list of paths to master to a file */

gint save_master_list(gchar *fname) {
FILE *fd;
gchar tmp[MAXLINE];
gchar tmpexcl[MAXLINE];
gchar tmppath1[MAXLINE];
gchar tmppath2[MAXLINE];
struct stat buf;
gint ret;
time_t acttime;
gchar timestr[MAXLINE];
mstr_redirect_t *mstr;
gchar *excl;
GList *loop;

      /* first check if this file does already exist */
      if (lstat(fname, &buf) == 0) {
            g_snprintf(tmp,1024,_("File %s already exists.\nAre you sure you want to overwrite it?"), fname);
            ret = show_dialog(ICO_WARN, tmp, T_OK, T_CANCEL, NULL, 1);
            if (ret == 1) {
                  return -1;
            }
      }

      dodebug(1, "Opening %s for writing (master paths)\n", fname);

        fd = fopen(fname,"w"); 
        if (fd == NULL) { 
                /* error opening file */
                return 1;
        }

        /* get current time */
        acttime = time((time_t *) 0);
        strcpy(timestr,ctime(&acttime));
        timestr[strlen(timestr)-1] = '\0';

        /* write header */
        
        fputs("#\n",fd);
        g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - Master-Paths\n",XCDROAST_VERSION);
      fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
        fputs(tmp,fd);
        fputs("#\n",fd);

      /* get all paths */
      loop = g_list_first(masterparam.mstr_redir);
      while (loop) {
                mstr = (mstr_redirect_t *) loop->data;
                if (mstr) {
                  if (mstr->mstr_path && !mstr->redir_path) {
                        strncpy(tmppath1, mstr->mstr_path, MAXLINE);
                        g_snprintf(tmp,MAXLINE,"ADD1 = \"%s\"\n", convert_escape(tmppath1));
                  } else 
                  if (mstr->mstr_path && mstr->redir_path) {
                        strncpy(tmppath1, mstr->mstr_path, MAXLINE);
                        strncpy(tmppath2, mstr->redir_path, MAXLINE);
                        g_snprintf(tmp,MAXLINE,"ADD2 = \"%s\",\"%s\"\n", convert_escape(tmppath1), convert_escape(tmppath2));
                  }
                  fputs(tmp,fd);
            }
            loop = loop->next;
      }

        /* get exclude-dirs */
        loop = g_list_first(masterparam.exclude_paths);
        while (loop) {
                excl = (gchar *)loop->data;
            if (excl) {
                  strncpy(tmpexcl, excl, MAXLINE);
                  g_snprintf(tmp,MAXLINE,"EXCL = \"%s\"\n", convert_escape(tmpexcl));
                  fputs(tmp,fd);
            }
            loop = loop->next;
      }

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

      return 0;
}


/* loads the master-paths from a file */

gint load_master_list(gchar *fname) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gchar value2[MAXLINE];
mstr_redirect_t *mstr;

      dodebug(1, "Opening config file %s for reading (master paths)\n", fname);

        if ((fd = fopen(fname,"r")) == NULL) { 
                /* error opening file */
                return 1;
        }

      /* could open the file, now clear the master data */
      clear_mstr_glist(&masterparam.mstr_redir);
      free_glist(&masterparam.exclude_paths);


        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                dodebug(10,"master-paths: %s", line),

                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0') 
                        continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  g_warning("syntax error in master-paths-file\n");
                  continue;
            }     

            if (strcmp("ADD1", id) == 0) {
                  if (strcmp(value,"") != 0) {
                        /* add this value to the list */
                        mstr = g_new0(mstr_redirect_t,1);
                        mstr->mstr_path = g_strdup(value);
                        masterparam.mstr_redir = g_list_append(masterparam.mstr_redir, mstr);
                  }
            }
            if (strcmp("ADD2", id) == 0) {
                  parse_config_line2(line,id,value,value2);             
                  if (strcmp(value,"") != 0) {
                        /* add this value to the list */
                        mstr = g_new0(mstr_redirect_t,1);
                        mstr->mstr_path = g_strdup(value);
                        masterparam.mstr_redir = g_list_append(masterparam.mstr_redir, mstr);
                        /* add add redirection if given */
                        if (strcmp(value2,"") != 0) {
                              add_redir_mstr_glist(
                                    &masterparam.mstr_redir,
                                    value, value2);
                        }
                  }
            }
            if (strcmp("EXCL", id) == 0) {
                  if (strcmp(value,"") != 0) {
                        /* add exclude */
                        masterparam.exclude_paths = g_list_append(
                                    masterparam.exclude_paths, 
                              g_strdup(value));
                  }
            }
      }

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* writes an info-file with the multisession-information after a
   track was mastered */

gint write_inf_file_for_master(gchar *fname, gint tracknr) {
FILE *fd;
time_t acttime;
gchar timestr[MAXLINE];
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;

      /* get current time */
      acttime = time((time_t *) 0);
      strcpy(timestr,ctime(&acttime));
      timestr[strlen(timestr)-1] = '\0';

      if (!fname || !*fname) {
            return 1;
      }

      /* generate filename */
      /* (remove extension and put .xinf there) */
      strncpy(tmp,fname,MAXLINE -4);
      p = rindex(tmp,'.');
      if (!p) return 1;
      *p = '\0';
      strcpy(tmp2,tmp);
      strcat(tmp2,XCDROAST_INFO_EXT);

      dodebug(1,"writing inffile %s\n", tmp2);

        /* is a link? */
        if (check_islink(tmp2, NULL)) {
            g_warning("Warning, won't overwrite a link at %s\n", tmp2);
            return 1;
        }

      /* write to file */
      fd = fopen(tmp2,"w"); 

      if (fd == NULL) {
            g_warning("Can't open file %s for writing\n",tmp2);
            return 1;
      }

      /* write header */
      fputs("#\n",fd);
      g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - INF-File\n",XCDROAST_VERSION);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
      fputs(tmp,fd);
      fputs("#\n",fd);

      g_snprintf(tmp,MAXLINE,"file = \"%s\"\n",fname);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"track = %d of %d\n",
                  tracknr, tracknr);
      fputs(tmp,fd);

      g_snprintf(tmp,MAXLINE,"size = %d\n", masterparam.session_size);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"type = %d\n", 0);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"last_session_start = %d\n", masterparam.last_session_start);
      fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"next_session_start = %d\n", masterparam.next_session_start);
      fputs(tmp,fd);

      if (fclose(fd) != 0) {
            /* error closing file */
            return 1;
      }

      return 0;
}


/* Save the current write-options to a file 
   return 0 if ok, or 1 on error */

gint save_writeoptions_file(gchar *confdir, gchar *fname) {
FILE *fd;
gchar tmp[MAXLINE];

        /* now check if the confdir exists */
        if (!is_directory(confdir)) {
                /* try to create directory */
                mkdir(confdir, 0700);
                dodebug(2, "trying to mkdir %s\n", confdir);
        }

      g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);

        dodebug(1, "Opening %s for writing\n", tmp);
        dolog(3, "Saving write-options file %s\n", tmp);

        fd = fopen(tmp,"w"); 

        if (fd == NULL) { 
                /* error opening file */
                return 1;
        }

        /* write the config-file header */
        fputs("#\n",fd);
        g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s Write-Options-File\n",XCDROAST_VERSION);
        fputs(tmp,fd);
        fputs("#\n",fd);
        fputs("# Automatically created by the X-CD-Roast-Setup\n",fd);
        fputs("# Don't edit! (Unless you REALLY know what you are doing)\n",fd);
        fputs("#\n\n",fd);

        /* write data */
        g_snprintf(tmp,MAXLINE,"VERSION = \"%s\"\n",XCDROAST_VERSION); 
        fputs(tmp,fd);
        g_snprintf(tmp,MAXLINE,"PLATFORM = \"%s\"\n",system_platform); 
        fputs(tmp,fd);

      g_snprintf(tmp,MAXLINE,"WRITE_SIMUL = %d\n", curset.writesimul);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_EJECT = %d\n", curset.writeeject);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_PAD = %d\n", curset.writepad);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_SWAP = %d\n", curset.writeswap);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_NOFIXATE = %d\n", curset.nofixate);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_CDTEXT = %d\n", curset.writecdtext);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_OVERBURN = %d\n", curset.writeoverburn);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_BURNFREE = %d\n", curset.writeburnfree);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_AUDIOMASTER = %d\n", curset.writeaudiomaster);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_FORCESPEED = %d\n", curset.writeforcespeed);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_VARIREC = %d\n", curset.writevarirec);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_IGNSIZE = %d\n", curset.writeignsize);
        fputs(tmp,fd);
      g_snprintf(tmp,MAXLINE,"WRITE_IMMED = %d\n", curset.writeimmed);
        fputs(tmp,fd);

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* Load the write-options-default file  
   return 0 if ok, or 1 on error */

gint load_writeoptions_file(gchar *fname) {
FILE *fd;
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];

        if ((fd = fopen(fname,"r")) == NULL) { 
                /* error opening file */
            dodebug(1, "Failed to open write options file %s\n", fname);
            dolog(3, "Failed loading write options file %s\n", fname);
                return 1;
        }

        dodebug(1, "Opening write options file %s for reading\n", fname);
        dolog(3, "Loading write options file %s\n", fname);

        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                dodebug(10,"isooptions: %s", line),

                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0') 
                        continue;

                /* parse lines */
            if (parse_config_line(line,id,value)) {
                  g_error("syntax error in isooptions-file\n");
            }     

            if (strcmp("WRITE_SIMUL", id) == 0) {
                  curset.writesimul = atoi(value);
            }
            if (strcmp("WRITE_EJECT", id) == 0) {
                  curset.writeeject = atoi(value);
            }
            if (strcmp("WRITE_PAD", id) == 0) {
                  curset.writepad = atoi(value);
            }
            if (strcmp("WRITE_SWAP", id) == 0) {
                  curset.writeswap = atoi(value);
            }
            if (strcmp("WRITE_NOFIXATE", id) == 0) {
                  curset.nofixate = atoi(value);
            }
            if (strcmp("WRITE_CDTEXT", id) == 0) {
                  curset.writecdtext = atoi(value);
            }
            if (strcmp("WRITE_OVERBURN", id) == 0) {
                  curset.writeoverburn = atoi(value);
            }
            if (strcmp("WRITE_BURNFREE", id) == 0) {
                  curset.writeburnfree = atoi(value);
            }
            if (strcmp("WRITE_AUDIOMASTER", id) == 0) {
                  curset.writeaudiomaster = atoi(value);
            }
            if (strcmp("WRITE_FORCESPEED", id) == 0) {
                  curset.writeforcespeed = atoi(value);
            }
            if (strcmp("WRITE_VARIREC", id) == 0) {
                  curset.writevarirec = atoi(value);
            }
            if (strcmp("WRITE_IGNSIZE", id) == 0) {
                  curset.writeignsize = atoi(value);
            }
            if (strcmp("WRITE_IMMED", id) == 0) {
                  curset.writeimmed = atoi(value);
            }
      }

        if (fclose(fd) != 0) {
                /* error closing file */
                return 1;
        }

        return 0;
}


/* remove the temporarary toc files */

void remove_tmp_xcdr_files() {
gchar tmptoc[MAXLINE];

        /* delete tmp masterfiles first */
        generate_tmp_tocfile_name(tmptoc);
        remove_tmp_writetracks_tocfile(tmptoc);
        if (master_fname1) {
                remove_tmp_writetracks_tocfile(master_fname1);
                g_free(master_fname1);
                master_fname1 = NULL;
        }
        if (master_fname2) {
                remove_tmp_writetracks_tocfile(master_fname2);
                g_free(master_fname2);
                master_fname2 = NULL;
        }
}


/* used on OS X only - find out the pid of the autodiskmount daemon */
/* return -1 when not found */

gint get_autodiskmount_pid() {
gchar line[MAXLINE];
FILE *fpin;
gchar *p;
gint pid;

      g_snprintf(line,MAXLINE,"/bin/ps -ax | /usr/bin/fgrep autodiskmount");

      dodebug(1, "calling: %s\n", line);
        if ((fpin = popen(line,"r")) == NULL) {
                g_error("popen error\n");
        }

      pid = -1;
        for (;;) {
                if (fgets(line,MAXLINE,fpin) == NULL) 
                        break;
            strip_string(line);

            /* line found that not contains grep? should be the one */
            if (!strstr(line, "grep")) {
                  p = strtok(line, " \t");
                  if (p && pid == -1) {
                        /* save first match */
                        pid = atoi(p);
                  }
            }
        }

        if (pclose(fpin) == -1) {
                g_error("pclose error\n");
        }

      return pid;
}


/* run a single command with sudo and return the exitstatus. */

gint run_sudo_command(gchar *cmd) {
gchar line[MAXLINE], tmp[MAXLINE];
FILE *fpin;
gint stat,ret;

      g_snprintf(line, MAXLINE, "%s -S %s", SUDO, cmd);

        if ((fpin = popen(line,"w")) == NULL) {
                g_error("popen error\n");
        }

      /* send password */
      g_snprintf(tmp, MAXLINE, "%s\n", curset.sudo_passwd);
      fputs(tmp, fpin);

      /* command should be executed as root now */

      ret = pclose(fpin);
      stat = WEXITSTATUS(ret);

        dodebug(1, "Executed command \"%s\" with sudo. (exitstatus %d)\n", cmd, stat);

      return stat;
}


/* check .inf file for a given audio track for invalid ISRC and MCN entries */
/* return 0 when all ok (or file not found), 1 when invalid data found */

gint check_valid_isrc_mcn(gchar *tname) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar line[MAXLINE];
gchar id[MAXLINE];
gchar value[MAXLINE];
gchar *p;
FILE *fd;
gint errfound;

      errfound = 0;

      /* generate filename of .inf file */
        strncpy(tmp,tname,MAXLINE - 3);
        p = rindex(tmp,'.');
        if (!p) return 0;
        *p = '\0';
        strcpy(tmp2,tmp);
        strcat(tmp2,".inf");

      if ((fd = fopen(tmp2,"r")) == NULL) { 
            /* file not found or readable - thats ok */
            return 0;
      }

      dodebug(11, "Checking %s for invalid ISRC or MCN\n", tmp2);

        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

                /* skip empty or hashed lines */
                strip_string(line);
                if (*line == '#' || *line == '\0') 
                        continue;

                if (parse_config_line(line,id,value)) {
                  continue;
            }

            if (strcmp("MCN",id) == 0) {
                  errfound += verify_mcn(value);
            }
            if (strcmp("ISRC",id) == 0) {
                  errfound += verify_isrc(value);
            }
      }

      fclose(fd);

      if (errfound > 0) {
            /* invalid data found */
            return 1;
      } else {
            return 0;
      }
}


/* comment the ISRC and MCN numbers in a given track inf file */
/* return 0 if we were able to do so, 1 on error */

gint clear_isrc_mcn_from_inffile(gchar *tname) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar tmpname[MAXLINE];
gchar line[MAXLINE];
gchar *p;
FILE *fd, *fd2;
gint stat;
time_t acttime;
gchar timestr[MAXLINE];

      /* get current time */
      acttime = time((time_t *) 0);
      strcpy(timestr,ctime(&acttime));
      timestr[strlen(timestr)-1] = '\0';

      /* generate filename of .inf file */
        strncpy(tmp,tname,MAXLINE - 3);
        p = rindex(tmp,'.');
        if (!p) return 0;
        *p = '\0';
        strcpy(tmp2,tmp);
        strcat(tmp2,".inf");
      g_snprintf(tmpname,MAXLINE,"%s-%d", tmp2, (gint) getpid());

        /* try to open the inf file */
        if ((fd = fopen(tmp2,"r")) == NULL) { 
            /* no source file - thats ok */
            return 0;
      }

      /* create temporary file */
        if ((fd2 = fopen(tmpname,"w")) == NULL) { 
                fclose(fd);
            /* we couldnt create the working copy? report error */
                return 1;
        }

        /* copy a lines and change the one with ISRC and MCN */
        for (;;) {
                if (fgets(line,MAXLINE,fd) == NULL)
                        break;

            /* write modifcation date of xcdroast in new file */
            if (strncmp(line,"#created", 8) == 0) {
                  fputs(line, fd2);
                  g_snprintf(tmp,MAXLINE,"#modified by X-CD-Roast %s at %s\n", XCDROAST_VERSION, timestr);
                  fputs(tmp, fd2);
                  continue;
            }     

            /* skip old modfied lines */
            if (strncmp(line,"#modified by X-CD-Roast", 23) == 0) {
                  continue;
            }

                if (strncmp(line,"ISRC=", 5) == 0) {
                        g_snprintf(tmp,MAXLINE,"# %s", line);
                        fputs(tmp, fd2);
                        continue;
                }
                if (strncmp(line,"MCN=", 4) == 0) {
                        g_snprintf(tmp,MAXLINE,"# %s", line);
                        fputs(tmp, fd2);
                        continue;
                }

            fputs(line,fd2);
      }

      /* finished modified copy */
        fclose(fd2);
        fclose(fd);

      dodebug(10, "cleared inf-file %s from invalid ISRC or MCN id\n", tmp2);

        /* now move the temporary file over the original inf file */
        stat = move_textfile(tmpname, tmp2);

      if (stat == 1) {
            /* remove temporary file if move failed */
            unlink(tmpname);
      }

      return stat;
}


Generated by  Doxygen 1.6.0   Back to index