"Fossies" - the Fresh Open Source Software Archive

Member "xcdroast-1.19/src/io.c" (9 Nov 2018, 307606 Bytes) of package /linux/misc/xcdroast-1.19.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "io.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.18_vs_1.19.

    1 /*
    2  *  io.c
    3  *
    4  *  All the functions that interact with hardware and subprocesses
    5  *  and file IO. 
    6  *  28.3.99 tn
    7  *
    8  *
    9  *  Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
   10  *
   11  *  This file is part of xcdroast.
   12  *
   13  *  This program is free software; you can redistribute it and/or modify
   14  *  it under the terms of the GNU General Public License as published by
   15  *  the Free Software Foundation; either version 2 of the License, or
   16  *  (at your option) any later version.
   17  *
   18  *  This program is distributed in the hope that it will be useful,
   19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   21  *  GNU General Public License for more details.
   22  *
   23  *  You should have received a copy of the GNU General Public License
   24  *  along with this program; if not, write to the Free Software
   25  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   26  */
   27 
   28 #ifdef HAVE_CONFIG_H
   29 # include <config.h>
   30 #endif
   31 
   32 #include "largefile.h"
   33 #include "gettext.h"
   34 
   35 #include <stdio.h>
   36 #include <string.h>
   37 #include <strings.h>
   38 #include <stdlib.h>
   39 #include <sys/stat.h>
   40 #include <fcntl.h>
   41 #include <unistd.h>
   42 #include <sys/socket.h>
   43 #include <sys/types.h>
   44 #include <sys/wait.h>
   45 #include <signal.h>
   46 #include <time.h>
   47 #if defined(linux)
   48 # include <alsa/asoundlib.h>
   49 #endif
   50 #if defined(__FreeBSD__)
   51 # include <sys/soundcard.h>
   52 # include <sys/ioctl.h>
   53 #endif
   54 #if defined(sun) || defined(__OpenBSD__)
   55 # include <sys/ioctl.h>
   56 # include <sys/audioio.h>
   57 #endif
   58 #ifdef aix
   59 #include <sys/audio.h>
   60 #endif
   61 #ifdef hpux 
   62 # ifndef hpux_alib
   63 #  include <sys/audio.h>
   64 # endif
   65 #endif
   66 #if defined(__sgi)
   67 #include <dmedia/audio.h>
   68 #endif
   69 
   70 #if ENABLE_NLS
   71 # define _(String) gettext (String)
   72 # define N_(String) gettext_noop (String)
   73 #else
   74 # define _(String) (String)
   75 # define N_(String) (String)
   76 #endif
   77 #define GTK_ENABLE_BROKEN
   78 
   79 #include <gtk/gtk.h>
   80 #include <gdk/gdk.h>
   81 #include <glib.h>
   82 #include "xcdrdata.h"
   83 #include "xcdroast.h"
   84 #include "main.h"
   85 
   86 writerreader_devices_t **writerreaderdevs;
   87 gchar **alt_scsidevices;
   88 cd_info_t cdinfo;
   89 track_info_t **trackinfo;
   90 writer_driver_t **drivers;
   91 writer_driver_t **blankmodes;
   92 write_track_param_t writeparams;
   93 gchar xcdroast_version_loaded[MAXLINE];
   94 gint read_done;
   95 gint read_abort_mark;
   96 
   97 static gint scsicount;
   98 static gint busnr;
   99 static gint tocstate;
  100 static gint tocnr;
  101 static gint drvcount;
  102 static gint dfrun;
  103 static gint readcdda_callback;
  104 static gint readcdda_callback2;
  105 static gint readcdda_callback3;
  106 static gint read_output_ctrl;
  107 static gint read_tracknr;
  108 static gchar readtrack_info_string[1024];
  109 static gfloat pct_so_far, pct_this_track;
  110 static pid_t mkisofs_pid;
  111 static pid_t readcdda_pid, readcdda_pid2;
  112 static gint readcd_startsector, readcd_endsector;
  113 static gint readerr_count;
  114 static gint matchnr;
  115 static gint writecompleted;
  116 static gint cddb_in;
  117 static gchar cdinfo_cddb_title_bak[MAXLINE];
  118 static gint cd_is_still_the_same;
  119 static gint cdrecord_stdin, cdrecord_reload;
  120 static gint delete_count, delete_start, delete_all;
  121 static gint msinfo_nr1, msinfo_nr2;
  122 static gint cdrtimer, count_mmaperror, checkmedium_found;
  123 static time_t cdrcmdtimer;
  124 static GtkWidget *getcdtoc_atapi_timeout_dialog;
  125 
  126 extern gint debug;
  127 extern setup_data_t setupdata;
  128 extern track_read_set_t trackreadset;
  129 extern current_set_t curset;
  130 extern gchar *system_platform;
  131 extern GtkWidget *toplevel;
  132 extern GtkWidget *viewmode_dialog; 
  133 extern GtkWidget *readtrack_info_label, *readtrack_textview;
  134 extern GtkWidget *readtrack_pbar1, *readtrack_pbar2, *readtrack_pbar3;
  135 extern GtkWidget *readtrack_pbar4, *readtrack_spd;
  136 extern GtkWidget *readtrack_small_info, *readtrack_small_info2;
  137 extern gchar hostname[MAXLINE];
  138 extern gchar username[MAXLINE];
  139 extern gchar sharedir[MAXLINE];
  140 extern gchar configdir[MAXLINE];
  141 extern gchar prefixdir[MAXLINE];
  142 extern GtkWidget *cddb_info_label;
  143 extern GtkCList *cddb_clist;
  144 extern master_param_t masterparam;
  145 extern gchar **charset_types;
  146 extern gchar *master_fname1;
  147 extern gchar *master_fname2;
  148 
  149 static gboolean verify_readcd_err(GIOChannel *source, GIOCondition cond, gpointer data);
  150 static void read_write_idle_loop(pid_t cdrecord_pid);
  151 static gboolean read_write_out(GIOChannel *source, GIOCondition cond, gpointer data);
  152 static gint getdevicecap(gchar *dev, gint *readmax, gint *cdrmax, gint *dvdmax, gint *iscdr, gint *isdvdrom, gint *isdvdr, gint *drvbuffer);
  153 static gint check_medium_loaded(gint devnr);
  154 static gint get_cdrecord_toc(gint devnr);
  155 static void remove_tmp_writetracks_tocfile(gchar *tocfile);
  156 static void edit_xinf_for_cd_text2(gchar *infname, gchar *title, gchar *artist, gchar *cdtitle, gchar *cdartist);
  157 static pid_t full_dpl_pipe3(gint *out, gint *in, gint *err, gchar *cmd, 
  158     gint use_socketpair);
  159 static void scroll_to_text_end(GtkWidget *txt);
  160 static gint get_wait_ret(pid_t pid);
  161 
  162 
  163 /*
  164  * convert device-type-names back to numeric
  165  * -1 means unknown
  166  */
  167 static gint get_scsi_type(gchar *type) {
  168 
  169     if (strcmp(type,"Disk") == 0) {
  170         return 0;
  171     }
  172     if (strcmp(type,"Tape") == 0) {
  173         return 1;
  174     }
  175     if (strcmp(type,"Printer") == 0) {
  176         return 2;
  177     }
  178     if (strcmp(type,"Processor") == 0) {
  179         return 3;
  180     }
  181     if (strcmp(type,"WORM") == 0) {
  182         return 4;
  183     }
  184     if (strcmp(type,"CD-ROM") == 0) {
  185         return 5;
  186     }
  187     if (strcmp(type,"Scanner") == 0) {
  188         return 6;
  189     }
  190     if (strcmp(type,"Optical Storage") == 0) {
  191         return 7;
  192     }
  193     if (strcmp(type,"Juke Box") == 0) {
  194         return 8;
  195     }
  196     if (strcmp(type,"Communication") == 0) {
  197         return 9;
  198     }
  199 
  200     return -1;
  201 }
  202 
  203 /*
  204  * construct functions which are used in the invocations of the cdrtools
  205  */
  206 static gint get_cur_audioread_speed() {
  207 gint i;
  208     i = get_writerreaderdevs_index(curset.reader_devnr);
  209     return (writerreaderdevs[i]->audioread_speed);
  210 }
  211 
  212 static gint get_cur_audioread_overlap() {
  213 gint i;
  214     i = get_writerreaderdevs_index(curset.reader_devnr);
  215     return (writerreaderdevs[i]->audioread_overlap);
  216 }
  217 
  218 static gint get_cur_audioread_showhiddentrack() {
  219 gint i;
  220     i = get_writerreaderdevs_index(curset.reader_devnr);
  221     return (writerreaderdevs[i]->audioread_showhiddentrack);
  222 }
  223 
  224 static gint get_cur_audioread_useparanoia() {
  225 gint i;
  226     i = get_writerreaderdevs_index(curset.reader_devnr);
  227     return (writerreaderdevs[i]->audioread_useparanoia);
  228 }
  229 
  230 static gint get_cur_audioread_paranoiaretries() {
  231 gint i;
  232     i = get_writerreaderdevs_index(curset.reader_devnr);
  233     return (writerreaderdevs[i]->audioread_paranoiaretries);
  234 }
  235 
  236 static gint get_cur_audioread_paranoiareadahead() {
  237 gint i;
  238     i = get_writerreaderdevs_index(curset.reader_devnr);
  239     return (writerreaderdevs[i]->audioread_paranoiareadahead);
  240 }
  241 
  242 static gint get_cur_audioread_paranoiaminoverlap() {
  243 gint i;
  244     i = get_writerreaderdevs_index(curset.reader_devnr);
  245     return (writerreaderdevs[i]->audioread_paranoiaminoverlap);
  246 }
  247 
  248 static gint get_cur_writer_speed() {
  249 gint i;
  250     i = get_writerreaderdevs_index(curset.writer_devnr);
  251     return (writerreaderdevs[i]->writer_speed);
  252 }
  253 
  254 static gint get_cur_writer_fifo() {
  255 gint i;
  256     i = get_writerreaderdevs_index(curset.writer_devnr);
  257     return (writerreaderdevs[i]->writer_fifo);
  258 }
  259 
  260 static gint get_cur_writemode() {
  261 gint i;
  262     i = get_writerreaderdevs_index(curset.writer_devnr);
  263     return (writerreaderdevs[i]->writer_mode);
  264 }
  265 
  266 static gint get_cur_writer_drvmode() {
  267 gint i;
  268     i = get_writerreaderdevs_index(curset.writer_devnr);
  269     return (writerreaderdevs[i]->writer_drvmode);
  270 }
  271 
  272  
  273 /*
  274  * look in given string for "' '" and return index to it
  275  * return -1 if not found
  276  */
  277 static gint look_for_scan_delimitor(gchar *str) {
  278 gint i;
  279 
  280     for(i = 0; i < strlen(str)-2; i++) {
  281 
  282         if (str[i] == '\'' && str[i+1] == ' ' && str[i+2] == '\'') {
  283             return i;
  284         }
  285     }
  286     return -1;
  287 }
  288 
  289 
  290 /*
  291  * look in given string for "' " and return index to it
  292  * return -1 if not found
  293  */
  294 static gint look_for_scan_delimitor2(gchar *str) {
  295 gint i;
  296 
  297     for(i = 0; i < strlen(str)-1; i++) {
  298 
  299         if (str[i] == '\'' && str[i+1] == ' ') {
  300             return i;
  301         }
  302     }
  303     return -1;
  304 }
  305 
  306 
  307 /*
  308  * interpret output of -scanbus and sort into memory structure
  309  * if idx != -1 then we run in manual-device-mode
  310  */
  311 static void parse_scan(gchar *line, gint idx, gint transport, scsi_devices_t **scsidevices) {
  312 gchar tmp[MAXLINE];
  313 gchar tmp2[MAXLINE];
  314 gchar *p1, *p2;
  315 gint s_id;
  316 gchar s_vendor[9];
  317 gchar s_model[17];
  318 gchar s_rev[5];
  319 gint s_removable;
  320 gint s_type;
  321 gint next;
  322 
  323     /* skip header */
  324     if (strncmp(line,"Cdrecord",8) == 0) {
  325         return;
  326     }
  327 
  328        if (strncmp(line,"scsibus",7) == 0 ) {
  329                 /* set current scsibus nr */
  330                 strcpy(tmp,line+7);
  331                 p1=strtok(tmp,":");
  332                 strcpy(tmp2,p1);
  333                 /* now tmp2 contains the current busnr as string */
  334                 busnr = atoi(tmp2);
  335                 return;
  336         }
  337 
  338     /* a line with an error message? */
  339     strcpy(tmp,"cdrecord: ");
  340     if (strncmp(line, tmp, strlen(tmp)) == 0) {
  341         return;
  342     }
  343 
  344     /* a line with device info found - by checking for ")" */
  345     p1 = index(line,')');
  346     if (p1 != NULL && !strstr(line,")\"") && 
  347        (strstr(line,"\t") || line[0] == ' ')) {
  348         strip_string(line); 
  349 
  350         /* get scsi-id */
  351         p1=strtok(line,")");
  352         if (!p1) return;
  353 
  354         strcpy(tmp,p1);
  355         strcpy(tmp2,p1);
  356         /*
  357          * look for last tab or last space in tmp
  358          * and remove everything before
  359          */
  360         p1=rindex(tmp2,'\t');
  361         p2=rindex(tmp2,' ');
  362         if (p1 > p2) {
  363             /* last interesting char was a tab - cut here */
  364             if (p1 != NULL) {
  365                 strcpy(tmp,p1+1);
  366             }   
  367         } else {
  368             /* last interesting char was a space - cut here */
  369             if (p2 != NULL) {
  370                 strcpy(tmp,p2+1);
  371             }   
  372         }
  373         s_id = atoi(tmp);   
  374     
  375         /* strip off host-id from scsi-id-number */
  376         s_id = s_id % 100;
  377 
  378         p1=strtok(NULL,"'");
  379         if (p1 == NULL) {
  380             g_warning("cdrecord scanbus error: Try to remove all media from your disc drives before starting X-CD-Roast.\n");
  381             return;
  382         }
  383 
  384         strcpy(tmp,p1);
  385         strip_string(tmp);
  386 
  387         if (*tmp == '*') {
  388             /* no device found */
  389             return;
  390         }
  391 
  392         if (*tmp == 'H') {
  393             /* HOST ADAPTER found -
  394                treat as no device for now */
  395             return;
  396         }
  397 
  398         /* get full rest of line */
  399         p1=strtok(NULL,"");
  400         if (!p1) return;
  401         strcpy(tmp,p1);
  402 
  403         if (*tmp == '\'') {
  404             /* empty device found? ignore */
  405             return;
  406         }
  407 
  408         /* e.g. tmp=YAMAHA  ' 'CRW8424S        ' '1.0j' */ 
  409         /* get vendor */
  410         next = look_for_scan_delimitor(tmp);
  411         if (next < 0) {
  412             g_error("cdrecord -scanbus output syntax error\n");
  413         }
  414 
  415         strcpy(s_vendor,"        ");
  416         if (next <= 8) {
  417             strncpy(s_vendor,tmp,next);
  418         } else {
  419             /* strip off if too long */
  420             strncpy(s_vendor,tmp,8);
  421         }   
  422         s_vendor[8] = '\0';
  423 
  424         /* get model */
  425         strcpy(tmp2,tmp+next+3);
  426         strcpy(tmp,tmp2);
  427         next = look_for_scan_delimitor(tmp);
  428         if (next < 0) {
  429             g_error("cdrecord -scanbus output syntax error\n");
  430         }
  431         strcpy(s_model,"                ");
  432         if (next <= 16) {
  433             strncpy(s_model,tmp,next);
  434         } else {
  435             strncpy(s_model,tmp,16);
  436         }
  437         s_model[16] = '\0';
  438 
  439         /* get revision */
  440         strcpy(tmp2,tmp+next+3);
  441         strcpy(tmp,tmp2);
  442         next = look_for_scan_delimitor2(tmp);
  443         if (next < 0) {
  444             g_error("cdrecord -scanbus output syntax error\n");
  445         }
  446         strcpy(s_rev,"    ");
  447         if (next <= 4) {
  448             strncpy(s_rev,tmp,next);
  449         } else {
  450             strncpy(s_rev,tmp,4);
  451         }
  452         s_rev[4] = '\0';
  453 
  454         /* get type */
  455         strcpy(tmp2,tmp+next+2);
  456         strcpy(tmp,tmp2);
  457         strip_string(tmp);
  458 
  459         if (strncmp(tmp,"Removable",9) == 0) {
  460             s_removable = 1;
  461             strcpy(tmp2,tmp+10);
  462             strcpy(tmp,tmp2);
  463         } else {
  464             s_removable = 0;
  465         }
  466         
  467         s_type = get_scsi_type(tmp);
  468 
  469         /* allocate and fill structure */
  470         scsidevices[scsicount]=g_new(scsi_devices_t,1);
  471         if (idx == -1) {
  472             /* autoscan mode */
  473             scsidevices[scsicount]->devnr = 
  474                 transport*1024+busnr*32+s_id;
  475             scsidevices[scsicount]->alt_dev = -1;
  476         } else {
  477             /* manual mode */
  478             scsidevices[scsicount]->devnr = idx;
  479             scsidevices[scsicount]->alt_dev = idx;
  480         }
  481 
  482         scsidevices[scsicount]->sector_size = DATASECTORSIZE;
  483         scsidevices[scsicount]->transport = transport;
  484         scsidevices[scsicount]->bus = busnr;
  485         scsidevices[scsicount]->id = s_id;
  486         strcpy(scsidevices[scsicount]->vendor,s_vendor);
  487         strcpy(scsidevices[scsicount]->model,s_model);
  488         strcpy(scsidevices[scsicount]->rev,s_rev);
  489         scsidevices[scsicount]->removable = s_removable;
  490         scsidevices[scsicount]->type = s_type;
  491         
  492         scsicount++;
  493         if (scsicount >= MAXDEVICES) {
  494             g_error("Error: More than %d devices scanned\n",MAXDEVICES);
  495         }
  496     }
  497 }
  498 
  499 
  500 static void print_writerreaderdevs() {
  501 gint count;
  502 
  503     dodebug(2,"------ cdrecord writerreaderdevs-structure -----\n");
  504     count = 0;
  505     while(writerreaderdevs[count] != NULL) {
  506         dodebug(2, "devnr=%d (%s) [%s %s %s] (ssize: %d)\n", 
  507             writerreaderdevs[count]->devnr,
  508             writerreaderdevs[count]->devicestr,
  509             writerreaderdevs[count]->vendor,
  510             writerreaderdevs[count]->model,
  511             writerreaderdevs[count]->rev,
  512             writerreaderdevs[count]->sector_size);
  513         dodebug(2, "  readmax: %d, cdrmax: %d, dvdmax: %d, is_cdrwriter: %d, is_dvdreader: %d, is_dvdwriter: %d\n",
  514             writerreaderdevs[count]->writer_readmaxspeed,
  515             writerreaderdevs[count]->writer_cdrmaxspeed,
  516             writerreaderdevs[count]->writer_dvdmaxspeed,
  517             writerreaderdevs[count]->is_cdrwriter,
  518             writerreaderdevs[count]->is_dvdreader,
  519             writerreaderdevs[count]->is_dvdwriter,
  520             writerreaderdevs[count]->sector_size);
  521         dodebug(2, "  writer_flags: %s\n", 
  522             writerreaderdevs[count]->writer_flags);
  523         dodebug(2, "  writer_modes: %s\n", 
  524             writerreaderdevs[count]->writer_modes);
  525             
  526         count++;
  527     }
  528 }
  529 
  530 
  531 /*
  532  * create a new writer/reader entry
  533  */
  534 static gint add_writerreader(scsi_devices_t *scsidev, gchar *transport, GtkWidget *txt) {
  535 gchar tmp[MAXLINE];
  536 gchar tmp2[MAXLINE];
  537 gchar drvflags[MAXLINE], drvmodes[MAXLINE];
  538 gint readmax, cdrmax, dvdmax, iscdr, isdvdr, isdvdrom, drvbuffer;
  539 gint count;
  540 gint mmap_error;
  541 gint i;
  542 static const gchar *writemodes[] = WRITE_MODES;
  543 
  544     /* first search last entry of writerreader struct */
  545     count = 0;
  546     while(writerreaderdevs[count] != NULL) {
  547         if (count == MAXDEVICES-1) {
  548             return 0;
  549         }
  550         count++;
  551     }
  552 
  553     /* only add type WORM and CD-ROM types */
  554     if (scsidev->type != 4 && scsidev->type != 5) {
  555         return 0;
  556     }
  557 
  558     /* build device string */
  559     if (scsidev->alt_dev == -1) {
  560         g_snprintf(tmp,MAXLINE,"%s%d,%d,%d",
  561             transport, scsidev->bus, scsidev->id, 0);
  562     } else {
  563         strncpy(tmp, transport, MAXLINE);
  564     }   
  565 
  566     /* check if this device already exists */
  567     if (get_writerreaderdevs_index_from_devstr(tmp) != -1) {
  568         if (txt) {
  569             g_snprintf(tmp2,MAXLINE,"([%s] %s %s %s)\n",
  570                 tmp, scsidev->vendor,
  571                 scsidev->model, scsidev->rev);
  572             append_to_text_view(txt, tmp2);
  573                     wait_and_process_events();      
  574         }
  575         return 0;
  576     }
  577 
  578     /* create a new entry */
  579     writerreaderdevs[count]=g_new0(writerreader_devices_t,1);
  580     writerreaderdevs[count]->devnr = scsidev->devnr;
  581     writerreaderdevs[count]->devicestr = g_strdup(tmp);
  582     strncpy(writerreaderdevs[count]->vendor, scsidev->vendor,9);
  583     strncpy(writerreaderdevs[count]->model, scsidev->model,17);
  584     strncpy(writerreaderdevs[count]->rev, scsidev->rev,5);
  585     writerreaderdevs[count]->sector_size = scsidev->sector_size;
  586 
  587     getmodesflags(tmp, drvflags, drvmodes); 
  588     writerreaderdevs[count]->writer_flags = g_strdup(drvflags);
  589     writerreaderdevs[count]->writer_modes = g_strdup(drvmodes);
  590 
  591     /* get more detailed information about this device */
  592         mmap_error=getdevicecap(tmp, &readmax, &cdrmax, &dvdmax, &iscdr, &isdvdrom, &isdvdr, &drvbuffer);
  593     writerreaderdevs[count]->writer_readmaxspeed = readmax;
  594     writerreaderdevs[count]->writer_cdrmaxspeed = cdrmax;
  595     writerreaderdevs[count]->writer_dvdmaxspeed = dvdmax;
  596     writerreaderdevs[count]->is_cdrwriter = iscdr;
  597     writerreaderdevs[count]->is_dvdreader = isdvdrom;
  598     writerreaderdevs[count]->is_dvdwriter = isdvdr;
  599     
  600 
  601     /* workaround for non-mcc drives */
  602     if (writerreaderdevs[count]->is_cdrwriter == 0) {
  603         /* not detected as writer, but got write modes? */
  604         if (strlen(drvmodes) > 0) {
  605             /* assume its really a writer then */
  606             writerreaderdevs[count]->is_cdrwriter = 1;
  607         }
  608     }
  609 
  610     /* set defaults for writer fields */
  611     writerreaderdevs[count]->writer_drvmode = -1;
  612     writerreaderdevs[count]->writer_speed = cdrmax;
  613     writerreaderdevs[count]->writer_fifo = 8;
  614 
  615     /* get the first supported mode for that writer */
  616     i = 0;
  617     while (writemodes[i]) {
  618         if (writemode_supported(i, scsidev->devnr)) {
  619             writerreaderdevs[count]->writer_mode = i; 
  620             break;
  621         }   
  622         i++;
  623     }
  624 
  625     /* set defaults for reader fields */
  626     writerreaderdevs[count]->audioread_speed = readmax;
  627     writerreaderdevs[count]->audioread_overlap = 1;
  628     writerreaderdevs[count]->audioread_showhiddentrack = 1;
  629     writerreaderdevs[count]->audioread_useparanoia = 1;
  630     writerreaderdevs[count]->audioread_paranoiaretries = 20;
  631     /* number of sectors for audio readahead buffer > drive buffer (1 audio sector = 2448 bytes) */
  632     writerreaderdevs[count]->audioread_paranoiareadahead = (gint) (drvbuffer / 244800 + 1) * 100;
  633     writerreaderdevs[count]->audioread_paranoiaminoverlap = 0;
  634 
  635     /* add to dialog window */
  636         if (txt) {
  637         g_snprintf(tmp2,MAXLINE,"[%s] %s %s %s\n",
  638             tmp, scsidev->vendor,
  639             scsidev->model, scsidev->rev);
  640         append_to_text_view(txt, tmp2);
  641                 wait_and_process_events();      
  642     }
  643 
  644     return mmap_error;
  645 }
  646 
  647 
  648 /*
  649  * does scan for a single device only
  650  * return 1 when new device was found
  651  */
  652 static gint scanbus_single(gchar *dev, gint newdevnr, GtkWidget *txt) {
  653 gchar line[MAXLINE];
  654 gchar tmp[MAXLINE];
  655 gchar tmp2[MAXLINE];
  656 FILE *fpin;
  657 scsi_devices_t **scsidevices;
  658 gint found;
  659 
  660     scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
  661     scsicount = 0;
  662 
  663     get_wrap_path("CDRECORD", line);
  664 
  665     /* make sure we escape any critical chars in input */
  666     strncpy(tmp2,dev,MAXLINE);
  667     convert_escape(tmp2);
  668 
  669     g_snprintf(tmp,MAXLINE," -scanbus dev= \"%s\" 2>&1",tmp2);
  670     strcat(line,tmp);
  671 
  672     dodebug(1, "calling: %s\n", line);
  673         if ((fpin = popen(line,"r")) == NULL) {
  674                 g_error("popen error\n");
  675         }
  676 
  677         for (;;) {
  678                 if (fgets(line,MAXLINE,fpin) == NULL) 
  679                         break;
  680         dodebug(10,"scanbus: %s",line);
  681                 parse_scan(line, newdevnr, 0, scsidevices);
  682         }
  683 
  684         if (pclose(fpin) == -1) {
  685                 g_error("pclose error\n");
  686         }
  687 
  688     found = 0;
  689     if (scsidevices[0]) {
  690         add_writerreader(scsidevices[0], dev, txt);
  691         g_free(scsidevices[0]);
  692         found = 1;
  693     }
  694     g_free(scsidevices);
  695 
  696     return found;
  697 }
  698 
  699 
  700 /*
  701  * scanbus scsi
  702  */
  703 static void scan_traditional(GtkWidget *txt) {
  704 gchar line[MAXLINE];
  705 FILE *fpin;
  706 gint count, errcount, ret;
  707 scsi_devices_t **scsidevices;
  708 
  709     scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
  710     scsicount = 0;
  711 
  712     /* traditional scanning first */
  713     get_wrap_path("CDRECORD", line);
  714     strcat(line," -scanbus 2>&1");
  715 
  716     dodebug(1, "calling: %s\n", line);
  717         if ((fpin = popen(line,"r")) == NULL) {
  718                 g_error("popen error\n");
  719         }
  720 
  721         for (;;) {
  722                 if (fgets(line,MAXLINE,fpin) == NULL) 
  723                         break;
  724         dodebug(10,"scanbus: %s",line);
  725                 parse_scan(line, -1, 0, scsidevices);
  726         }
  727 
  728         if (pclose(fpin) == -1) {
  729                 g_error("pclose error\n");
  730         }
  731 
  732     /* add the found devices to the writerreader structure */
  733     count = 0;
  734     errcount = 0;
  735     while(scsidevices[count] != NULL) {
  736         errcount+=add_writerreader(scsidevices[count],"", txt);
  737         g_free(scsidevices[count]);
  738         count++;
  739     }
  740     g_free(scsidevices);
  741 
  742     /* historic mmap error check */
  743     if (errcount > 0) {
  744                 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);
  745                 if (ret == 1)
  746                         gtk_exit(1);
  747     }
  748 }
  749 
  750 
  751 /*
  752  * alternative transport method scanning
  753  * valid transport choices for now: ATAPI USCSI REMOTE
  754  */
  755 static gint scan_other(gchar *transport, gint transid, GtkWidget *txt) {
  756 gchar line[MAXLINE];
  757 gchar tmp[MAXLINE];
  758 FILE *fpin;
  759 gint count;
  760 scsi_devices_t **scsidevices;
  761 
  762     scsidevices = g_new0(scsi_devices_t *, MAXDEVICES);
  763     scsicount = 0;
  764 
  765     get_wrap_path("CDRECORD", line);
  766     g_snprintf(tmp,MAXLINE," dev=%s -scanbus 2>&1", transport);
  767     strcat(line, tmp);
  768     
  769     dodebug(1, "calling: %s\n", line);
  770         if ((fpin = popen(line,"r")) == NULL) {
  771                  g_error("popen error\n");
  772         }
  773 
  774         for (;;) {
  775             if (fgets(line,MAXLINE,fpin) == NULL) 
  776                         break;
  777         dodebug(10,"scanbus (%s): %s", transport, line);
  778                 parse_scan(line, -1, transid, scsidevices);
  779         }
  780 
  781         if (pclose(fpin) == -1) {
  782                 g_error("pclose error\n");
  783         }
  784 
  785     /* add the found devices to the writerreader structure */
  786     count = 0;
  787     g_snprintf(tmp,MAXLINE,"%s:", transport);
  788     while(scsidevices[count] != NULL) {
  789         add_writerreader(scsidevices[count], tmp, txt);
  790         g_free(scsidevices[count]);
  791         count++;
  792     }
  793     g_free(scsidevices);
  794 
  795     return count;
  796 }
  797 
  798 
  799 /*
  800  * new scanbus version
  801  */
  802 void scanbus_new(GtkWidget *txt, gint scanparam) {
  803 gchar tmp[MAXLINE];
  804 gint doscanbus;
  805 gint i, devnr;
  806 
  807     /* allocate memory */
  808     if (!writerreaderdevs) {
  809         writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
  810     }
  811 
  812     doscanbus = 1;
  813 
  814     /* output status texts? */
  815     if (txt) {
  816         strncpy(tmp,_("Starting to scan for devices...\n"), MAXLINE);
  817         append_to_text_view_bold(txt, tmp);
  818         wait_and_process_events();  
  819     }
  820 
  821     /* check if we have to do full scanbus or only partial */
  822     if (alt_scsidevices[0] != NULL) {
  823         i = 0;
  824         while (alt_scsidevices[i] != NULL) {
  825             /* look for a free device number (greater 8192) */
  826             for (devnr = 8192; devnr < 8192 + MAXDEVICES; devnr++) {
  827                 if (get_writerreaderdevs_index(devnr) == -1) {
  828                     break;
  829                 }   
  830             }   
  831             scanbus_single(alt_scsidevices[i], devnr, txt);
  832             i++;
  833         }       
  834 
  835         /* trigger not to scan the bus any futher */
  836         doscanbus = 0;
  837     }
  838 
  839     if (doscanbus) {
  840         /* scan for scsi devices */
  841         scan_traditional(txt);
  842 
  843         /* scan for alternatives */
  844 #if defined(linux)
  845         if (scanparam) {
  846             scan_other("ATA", 1, txt);
  847         }
  848 #endif
  849 #if defined(sun)
  850         if (scanparam) {
  851             scan_other("USCSI", 2, txt);
  852         }
  853 #endif
  854     }
  855 
  856     if (txt) {
  857         strncpy(tmp,_("Scan finished.\n"), MAXLINE);
  858         append_to_text_view_bold(txt, tmp);
  859         wait_and_process_events();  
  860     }
  861 
  862     if (debug) print_writerreaderdevs();
  863 }
  864 
  865 
  866 
  867 /*
  868  * scan for remote scsi devices
  869  */
  870 void scanbus_rscsi(gchar *devstr, GtkWidget *txt) {
  871 gchar tmp[MAXLINE];
  872 gint found;
  873 gint i, highest;
  874 
  875     /* allocate memory */
  876     if (!writerreaderdevs) {
  877         writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
  878     }
  879 
  880     /* output status texts? */
  881     if (txt) {
  882         strncpy(tmp,_("Starting to scan for remote devices...\n"), MAXLINE);
  883         append_to_text_view_bold(txt, tmp);
  884         wait_and_process_events();  
  885     }
  886 
  887     /* look for highest free devnr - but at least a multiple of 16384 */
  888     i = 0;
  889     highest = -1;
  890     while(writerreaderdevs[i] != NULL) {
  891         if (writerreaderdevs[i]->devnr > highest) {
  892             highest = writerreaderdevs[i]->devnr;
  893         }
  894         i++;
  895     }
  896     highest++;
  897 
  898     /* when we scan multiple times always arange a new block to play safe */
  899     highest = ((highest/16384)+1)*16384;
  900 
  901     found = scan_other(devstr, highest/1024, txt);
  902 
  903     if (txt) {
  904         if (found == 0) {
  905             strncpy(tmp,_("No devices found - check your remote scsi setup.\n"), MAXLINE);
  906             append_to_text_view(txt, tmp);
  907         }
  908         strncpy(tmp,_("Scan finished.\n"), MAXLINE);
  909         append_to_text_view_bold(txt, tmp);
  910         wait_and_process_events();  
  911     }
  912 
  913     if (debug) print_writerreaderdevs();
  914 }
  915 
  916 
  917 /*
  918  * special version where we scan only for a single device
  919  */
  920 void scanbus_new_single(gchar *devstr, GtkWidget *txt) {
  921 gchar tmp[MAXLINE];
  922 gint devnr, found;
  923 
  924     /* allocate memory */
  925     if (!writerreaderdevs) {
  926         writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
  927     }
  928 
  929     /* output status texts? */
  930     if (txt) {
  931         strncpy(tmp,_("Starting to scan for devices...\n"), MAXLINE);
  932         append_to_text_view_bold(txt, tmp);
  933         wait_and_process_events();  
  934     }
  935 
  936     /* look for a free device number (greater 8192) */
  937     for (devnr = 8192; devnr < 8192 + MAXDEVICES; devnr++) {
  938         if (get_writerreaderdevs_index(devnr) == -1) {
  939             break;
  940         }   
  941     }   
  942     found = scanbus_single(devstr, devnr, txt);
  943 
  944     if (txt) {
  945         if (!found) {
  946             strncpy(tmp,_("Device not found.\n"), MAXLINE);
  947             append_to_text_view(txt, tmp);
  948         }
  949         strncpy(tmp,_("Scan finished.\n"), MAXLINE);
  950         append_to_text_view_bold(txt, tmp);
  951         wait_and_process_events();  
  952     }
  953 
  954     if (debug) print_writerreaderdevs();
  955 }
  956 
  957 
  958 /*
  959  * interpret output of driver=help and sort into memory structure
  960  */
  961 static void parse_driver(gchar *line) {
  962 gchar tmp[MAXLINE];
  963 gchar tmp2[MAXLINE];
  964 gchar drv[MAXLINE];
  965 gchar *p1;
  966 gint n;
  967     if (strncmp(line,"Driver types:",13) != 0 ) {
  968 
  969         strcpy(tmp,line);
  970         p1=strtok(tmp," ");
  971         strcpy(drv,p1); 
  972         /* now drv contains the driver name */
  973 
  974         p1=strtok(NULL,"");
  975         strcpy(tmp2,p1);
  976         strip_string(tmp2);
  977         /* now tmp2 contains the description */
  978 
  979         /* cut "driver for" away */ 
  980         if (strncmp(tmp2,"driver for ",11) == 0 ){
  981             strcpy(tmp,tmp2+11);
  982             strcpy(tmp2,tmp);
  983         }
  984 
  985         /* allocate structure */
  986         drivers[drvcount]=g_new(writer_driver_t,1);
  987 
  988         n = strlen(drv)+1;
  989         drivers[drvcount]->driver=g_new(gchar,n);
  990         strcpy(drivers[drvcount]->driver,drv);
  991 
  992         n = strlen(tmp2)+1;
  993         drivers[drvcount]->desc=g_new(gchar,n);
  994         strcpy(drivers[drvcount]->desc,tmp2);
  995 
  996         drvcount++;
  997         if (drvcount >= MAXDRIVERS) {
  998             g_error("Error: More than %d writer devices found\n",MAXDRIVERS);
  999         }
 1000     }
 1001 }
 1002 
 1003 
 1004 /*
 1005  * print memory-structure with drivers (debug purposes)
 1006  */
 1007 static void print_drivers() {
 1008 gint count;
 1009 
 1010     dodebug(2,"------ cdrecord drivers-structure -----\n");
 1011     count = 0;
 1012     while(drivers[count] != NULL) {
 1013         dodebug(2, "%s:%s\n",
 1014             drivers[count]->driver,
 1015             drivers[count]->desc);
 1016             
 1017         count++;
 1018     }
 1019 }
 1020 
 1021 
 1022 /*
 1023  * call cdrecord driver=help
 1024  */
 1025 void scandrivers() {
 1026 gchar line[MAXLINE];
 1027 FILE *fpin;
 1028 
 1029     /* allocate memory */
 1030     drivers = g_new0(writer_driver_t *,MAXDRIVERS);
 1031     drvcount = 0;
 1032 
 1033     get_wrap_path("CDRECORD", line);
 1034     strcat(line," driver=help 2>&1");
 1035 
 1036     dodebug(1, "calling: %s\n", line);
 1037         if ((fpin = popen(line,"r")) == NULL) {
 1038                 g_error("popen error\n");
 1039         }
 1040 
 1041         for (;;) {
 1042                 if (fgets(line,MAXLINE,fpin) == NULL) 
 1043                         break;
 1044         dodebug(10, "driverlist: %s",line);
 1045                 parse_driver(line);
 1046         }
 1047 
 1048         if (pclose(fpin) == -1) {
 1049                 g_error("pclose error\n");
 1050         }
 1051 
 1052     if (debug) print_drivers();
 1053 }
 1054 
 1055 
 1056 /*
 1057  * print memory-structure with charsets (debug purposes)
 1058  */
 1059 static void print_charsets() {
 1060 gint count;
 1061 gchar tmp[MAXLINE];
 1062 
 1063     dodebug(2,"------ mkisofs-charsets-structure -----\n");
 1064     count = 0;
 1065     strcpy(tmp,""); 
 1066     while(charset_types[count] != NULL) {
 1067 
 1068         strcat(tmp,charset_types[count]);
 1069 
 1070         if ((count+1) % 6) {
 1071             strcat(tmp, ", ");
 1072         } else {
 1073             dodebug(2, "%s\n", tmp);
 1074             strcpy(tmp,""); 
 1075         }
 1076         count++;
 1077     }
 1078     if (strcmp(tmp,"") != 0) 
 1079         dodebug(2, "%s\n", tmp);
 1080 }
 1081 
 1082 
 1083 /*
 1084  * compare charset names (for qsort)
 1085  */
 1086 static int sort_charsets (const void *a, const void *b)
 1087 {
 1088     return strverscmp (*(char * const *)a, *(char *const *)b);
 1089 }
 1090 
 1091 
 1092 /*
 1093  * call mkisofs -input-charset help
 1094  */
 1095 void scancharsets() {
 1096 gchar line[MAXLINE];
 1097 FILE *fpin;
 1098 gint start,count,tcount,i;
 1099 gchar **tmp_types;
 1100 
 1101     /* allocate memory */
 1102     charset_types = g_new0(gchar *,MAXCHARSETS+1);
 1103     tmp_types = g_new0(gchar *,MAXCHARSETS+1);
 1104 
 1105     start = 0;
 1106     count = 0;
 1107 
 1108     get_wrap_path("MKISOFS", line);
 1109     strcat(line," -input-charset help 2>&1");
 1110 
 1111     dodebug(1, "calling: %s\n", line);
 1112         if ((fpin = popen(line,"r")) == NULL) {
 1113                 g_error("popen error\n");
 1114         }
 1115 
 1116         for (;;) {
 1117                 if (fgets(line,MAXLINE,fpin) == NULL) 
 1118                         break;
 1119         /* wait for Known charsets.... line */
 1120         if (strncmp("Known",line,5) == 0) {
 1121             start = 1;
 1122             continue;
 1123         }
 1124         if (strcmp("mkisofs: 'iconv -l' lists more available names.\n",line) == 0) 
 1125             continue;
 1126 
 1127         if (start) {
 1128             dodebug(10, "mkisofs charsets: %s",line);
 1129 
 1130             tmp_types[count] = g_strdup(strip_string(line));
 1131             count++;        
 1132             if (count >= MAXCHARSETS) {
 1133                 g_error("Error: More than %d input charsets found\n",MAXCHARSETS);
 1134             }
 1135         }
 1136         }
 1137 
 1138         if (pclose(fpin) == -1) {
 1139                 g_error("pclose error\n");
 1140         }
 1141 
 1142     /* now sort charsets, adding a few special types into right places */
 1143     qsort(tmp_types,count,sizeof(*tmp_types),sort_charsets);
 1144 
 1145     tcount = count;
 1146     count = 0;
 1147     charset_types[count] = g_strdup("default");
 1148     count++;
 1149     charset_types[count] = g_strdup("utf-8");
 1150     count++;
 1151     for (i=0;i<tcount;i++) {
 1152         charset_types[count] = tmp_types[i];
 1153         count++;
 1154     }
 1155     charset_types[count] = g_strdup("custom");
 1156     count++;
 1157 
 1158     g_free(tmp_types);
 1159 
 1160     if (debug) print_charsets();
 1161 }
 1162 
 1163 
 1164 /*
 1165  * call cdrecord -prcap to get some device information
 1166  * also checks for mmap errors and return 1 if one occured
 1167  */
 1168 static gint getdevicecap(gchar *dev, gint *readmax, gint *cdrmax, gint *dvdmax, gint *iscdr, gint *isdvdrom, gint *isdvdr, gint *drvbuffer) {
 1169 gchar tmp[MAXLINE];
 1170 gchar line[MAXLINE];
 1171 gint tmpnr, errcount;
 1172 FILE *fpin;
 1173 gchar *p;
 1174 
 1175     /* set reasonable defaults */
 1176     *readmax = 0;
 1177     *cdrmax = 0;
 1178     *dvdmax = 0;
 1179     *iscdr = 0;
 1180     *isdvdrom = 0;
 1181     *isdvdr = 0;
 1182     *drvbuffer = 1;
 1183 
 1184         if (!dev) return 0;
 1185 
 1186         get_wrap_path("CDRECORD", tmp);
 1187         g_snprintf(line, MAXLINE, "%s dev= \"%s\" -prcap 2>&1", tmp, dev);
 1188 
 1189         dodebug(1, "calling: %s\n", line);
 1190         if ((fpin = popen(line,"r")) == NULL) {
 1191                 g_error("popen error\n");
 1192         }
 1193 
 1194     errcount = 0;
 1195         for (;;) {
 1196                 if (fgets(line,MAXLINE,fpin) == NULL) 
 1197                         break;
 1198                 dodebug(10, "prcap: %s",line);
 1199 
 1200                 /* line with mmap error? */
 1201                 if (strstr(line,"annot get mmap for")) {
 1202                         errcount++;
 1203                 }
 1204 
 1205         if (strstr(line, "Does write CD-R media")) {
 1206             *iscdr = 1;
 1207         }
 1208         if (strstr(line, "Does read DVD-ROM media")) {
 1209             *isdvdrom = 1;
 1210         }
 1211         if (strstr(line, "Does write DVD-R media")) {
 1212             *isdvdr = 1;
 1213         }
 1214         if (strstr(line, "Maximum read  speed:")) {
 1215             p = strtok(line,"(");
 1216             if (p) {
 1217                 p = strtok(NULL,")");
 1218                 if (p) {
 1219                     strcpy(tmp,p);
 1220                     sscanf(tmp,"CD %3dx, DVD %3d",
 1221                         readmax, &tmpnr);
 1222                 }
 1223             }
 1224         } else 
 1225         if (strstr(line, "Maximum write speed:")) {
 1226             p = strtok(line,"(");
 1227             if (p) {
 1228                 p = strtok(NULL,")");
 1229                 if (p) {
 1230                     strcpy(tmp,p);
 1231                     sscanf(tmp,"CD %3dx, DVD %3d",
 1232                         cdrmax, dvdmax);
 1233                 }
 1234             }
 1235         }
 1236         if (strstr(line, "Buffer size in KB:")) {
 1237             p = strstr(line, "KB: ");
 1238             if (p) {
 1239                 strcpy(tmp,p+4);
 1240             }
 1241             *drvbuffer = (gint) atoi(tmp) * 1024;
 1242         }
 1243     }
 1244 
 1245         if (pclose(fpin) == -1) {
 1246                 g_error("pclose error\n");
 1247         }
 1248 
 1249         if (errcount > 0) {
 1250                 return 1;
 1251         } else {
 1252                 return 0;
 1253         }
 1254 }
 1255 
 1256 
 1257 /*
 1258  * get driverflags and modes from drive
 1259  */
 1260 void getmodesflags(gchar *dev, gchar *drvflags, gchar *drvmodes) {
 1261 gchar tmp[MAXLINE];
 1262 gchar line[MAXLINE];
 1263 FILE *fpin;
 1264 gchar *p;
 1265 
 1266     strcpy(drvflags,"");
 1267     strcpy(drvmodes,"");
 1268 
 1269         if (!dev) return;
 1270 
 1271         get_wrap_path("CDRECORD", tmp);
 1272         g_snprintf(line, MAXLINE, "%s dev= \"%s\" -v -checkdrive 2>&1", tmp, dev);
 1273 
 1274         dodebug(1, "calling: %s\n", line);
 1275         if ((fpin = popen(line,"r")) == NULL) {
 1276                 g_error("popen error\n");
 1277         }
 1278         for (;;) {
 1279                 if (fgets(line,MAXLINE,fpin) == NULL) 
 1280                         break;
 1281                 dodebug(10, "checkdrive: %s",line);
 1282 
 1283         if (strstr(line, "Driver flags   :")) {
 1284             p = strtok(line,":");
 1285             if (p) {
 1286                 p = strtok(NULL,"");
 1287                 if (p) {
 1288                     strncpy(tmp,p,MAXLINE);
 1289                     strip_string(tmp);
 1290                     strncpy(drvflags,tmp,MAXLINE);
 1291                 }
 1292             }
 1293         } else 
 1294         if (strstr(line, "Supported modes:")) {
 1295             p = strtok(line,":");
 1296             if (p) {
 1297                 p = strtok(NULL,"");
 1298                 if (p) {
 1299                     strncpy(tmp,p,MAXLINE);
 1300                     strip_string(tmp);
 1301                     strncpy(drvmodes,tmp,MAXLINE);
 1302                 }
 1303             }
 1304         }
 1305     }
 1306 
 1307         if (pclose(fpin) == -1) {
 1308                 g_error("pclose error\n");
 1309         }
 1310 }
 1311 
 1312 
 1313 static gint parse_freespace(gchar *line, gchar *fs) {
 1314 gchar tmp[MAXLINE];
 1315 gchar *p1;
 1316 
 1317     /* skip first line(s) */
 1318     if (index(line,'/')) {
 1319             strcpy(tmp,line);
 1320 #if defined (aix)
 1321         /* filesystem label */
 1322         p1=strtok(tmp," ");
 1323         if (fs != NULL) {
 1324              /* get the filesystem */
 1325              strcpy(fs,p1);
 1326         }
 1327         /* size of filesystem */
 1328         p1=strtok(NULL," ");
 1329         if (p1 == NULL) { 
 1330             g_error("df -k output syntax error\n");
 1331         }
 1332         /* available blocks */
 1333         p1=strtok(NULL," ");
 1334         if (p1 == NULL) { 
 1335             g_error("df -k output syntax error\n");
 1336         }
 1337         return (atoi(p1));
 1338 #elif defined (hpux)
 1339         /* mountpoint */
 1340         p1=strtok(tmp,"(");
 1341         if (p1 == NULL) { 
 1342             g_error("df -b output syntax error\n");
 1343         }
 1344         /* filesystem label */
 1345         p1=strtok(NULL,")");
 1346         if (fs != NULL) {
 1347              /* get the filesystem - avoid "(" at the beginning */
 1348              strcpy(fs,p1);
 1349         }
 1350         /* size in kb */
 1351         p1=strtok(NULL,": ");
 1352         if (p1 == NULL) { 
 1353             g_error("df -b output syntax error\n");
 1354         }       
 1355         return (atoi(p1));
 1356 #else
 1357 
 1358         /* skip the first 4 fields in output to come to "available" */
 1359 
 1360         /* are we handling the first line of two?*/
 1361         p1=strtok(tmp," ");
 1362 
 1363         if (dfrun == 0) {
 1364             if (fs != NULL) {
 1365                 /* get the filesystem */
 1366                 strcpy(fs,p1);
 1367             }
 1368 
 1369             p1=strtok(NULL," ");
 1370             if (p1 == NULL) {
 1371                 /* ok..output splitted on two lines */
 1372                 dfrun = 1;
 1373                 return -1;
 1374             }
 1375         }
 1376         p1=strtok(NULL," ");
 1377         if (p1 == NULL) {
 1378             g_error("df -k output syntax error\n");
 1379         } 
 1380         p1=strtok(NULL," ");
 1381         if (p1 == NULL) { 
 1382             g_error("df -k output syntax error\n");
 1383         }
 1384         return (atoi(p1));
 1385 #endif
 1386     }
 1387     return -1;
 1388 }
 1389 
 1390 
 1391 /*
 1392  * get free disk space. return in 1024byte blocks or -1 if not valid
 1393  * return filesystem if not set to NULL
 1394  * will handle if output is in two lines...like when the filesystem
 1395  * output is longer that 20 chars - e.g. on nfs-links
 1396  * will handle df-output like:
 1397  *
 1398  * (Solaris)
 1399  * Filesystem         kbytes     used   avail   capacity  Mounted on
 1400  * fileserv:/export/home
 1401  *                  17502608 11609120 5718464        67%  /export/home
 1402  * 
 1403  * - OR -
 1404  * 
 1405  * (Linux)
 1406  * Filesystem    1024-blocks     Used Available Capacity Mounted on
 1407  * /dev/sda3         2494898  1606489    759428      68% /
 1408  * 
 1409  * Système de
 1410  * fichiers         1K-blocs   Utilisé  Disponible  U.%  Monté sur
 1411  * /dev/hda6        10080488   8043456     1524964  85%  /
 1412  * 
 1413  * - OR -
 1414  * 
 1415  * (AIX)
 1416  * Filesystem    1024-blocks    Free %Used    Iused %Iused Mounted on
 1417  * /dev/hd4             8192    2968   64%     1319    33% /
 1418  * /dev/hd2           573440   31644   95%    22280    16% /usr
 1419  * 
 1420  * - OR -
 1421  * 
 1422  * (HP-UXs df -b)
 1423  * /tmp             (/dev/vg00/lvol4       ) :   188158 Kbytes free
 1424  * /usr             (/dev/vg00/lvol5       ) :   286696 Kbytes free
 1425  * 
 1426  */
 1427 gint get_free_space(gchar *path, gchar *filesystem) {
 1428 gchar line[MAXLINE];
 1429 FILE *fpin;
 1430 gint space;
 1431 
 1432     space = -1;
 1433     dfrun = 0;
 1434 
 1435     if (is_directory(path) != 1) {
 1436         return -1;
 1437     }
 1438 
 1439     if (stat_file(DF)) {
 1440         strcpy(line,DF);
 1441         strcat(line," \"");
 1442         strcat(line,path);
 1443         strcat(line,"\"");
 1444     } else {
 1445         strcpy(line,DF2);
 1446         strcat(line," \"");
 1447         strcat(line,path);
 1448         strcat(line,"\"");
 1449     }
 1450 
 1451     dodebug(1, "calling: %s\n", line);
 1452         if ((fpin = popen(line,"r")) == NULL) {
 1453                 g_error("popen error\n");
 1454         }
 1455 
 1456         for (;;) {
 1457                 if (fgets(line,MAXLINE,fpin) == NULL) 
 1458                         break;
 1459         dodebug(10,"df: %s",line);
 1460                 space = parse_freespace(line,filesystem);
 1461         }
 1462 
 1463         if (pclose(fpin) == -1) {
 1464                 g_error("pclose error\n");
 1465         }
 1466 
 1467     if (filesystem != NULL) {
 1468         dodebug(2, "filesystem lookup for %s = %d blocks, fs = %s\n", 
 1469             path, space, filesystem);
 1470     } else {
 1471         dodebug(2, "filesystem lookup for %s = %d blocks, fs = %s\n", 
 1472             path, space, "(NULL)");
 1473     }
 1474  
 1475     return space;
 1476 }
 1477 
 1478 
 1479 /*
 1480  * get a list of all audio-devices found on a system. This has to be
 1481  * done platform dependent
 1482  */
 1483 GList *get_dsp_devices() {
 1484 GList *dsp;
 1485 GList *loop;
 1486 #if defined(__FreeBSD__)
 1487 struct stat buf;
 1488 #endif
 1489 #if defined(linux) 
 1490 void **hints, **n;
 1491 gchar *name;
 1492 #endif
 1493 #if defined(sun) || defined(aix) || defined(__OpenBSD__)
 1494 gchar *audiodev;
 1495 #endif
 1496     dsp = NULL;
 1497 
 1498 #if defined(linux) 
 1499     if (snd_device_name_hint(-1, "pcm", &hints) >= 0)
 1500     {
 1501         n = hints;
 1502         while (*n != NULL) {
 1503             name = snd_device_name_get_hint(*n, "NAME");
 1504             /* skip some devices */
 1505             if (strcmp(name, "null") != 0 && strncmp(name, "front", 5) != 0 
 1506                     && strncmp(name, "surround", 8) != 0)
 1507                 dsp = g_list_append(dsp, g_strdup(name));
 1508             free(name);
 1509             n++;
 1510         }
 1511     } 
 1512 #endif
 1513 
 1514 #if defined(__FreeBSD__)
 1515     /*
 1516      * for linux check if /dev/dsp or /dev/dsp1 exist
 1517      */
 1518     if (stat("/dev/dsp",&buf) == 0) {
 1519         dsp = g_list_append(dsp,"/dev/dsp");
 1520     }
 1521     if (stat("/dev/dsp1",&buf) == 0) {
 1522         dsp = g_list_append(dsp,"/dev/dsp1");
 1523     }
 1524 #endif
 1525 #if defined(sun) || defined(__OpenBSD__)
 1526     /*
 1527      * check if the user has any special audio-hardware running,
 1528      * which set the AUDIODEV-environment-variable
 1529      */
 1530     audiodev = getenv("AUDIODEV");
 1531     if (audiodev != NULL) {
 1532 
 1533         if (stat(audiodev,&buf) == 0) {
 1534             dsp = g_list_append(dsp,g_strdup(audiodev));
 1535         }
 1536     } else {
 1537         audiodev = "";
 1538     }
 1539     if (strcmp(audiodev,"/dev/audio") != 0) {
 1540 
 1541         if (stat("/dev/audio",&buf) == 0) {
 1542             dsp = g_list_append(dsp,"/dev/audio");
 1543         }
 1544     }
 1545 #endif
 1546 #ifdef aix
 1547        audiodev = getenv ("AUDIODEV");
 1548        if (audiodev != NULL) {
 1549 
 1550                if (stat (audiodev, &buf) == 0) {
 1551                        dsp = g_list_append (dsp, g_strdup(audiodev));
 1552                }
 1553        }
 1554        /* Try to use the device of a machine with PCI bus */
 1555         if (stat ("/dev/paud0/1", &buf) == 0) {
 1556                dsp = g_list_append (dsp, "/dev/paud0/1");
 1557        }
 1558         /* Try to use the device of a machine with MCA bus */
 1559         if (stat ("/dev/baud0/1", &buf) == 0) {
 1560                dsp = g_list_append (dsp, "/dev/baud0/1");
 1561        }
 1562 #endif
 1563 #ifdef hpux
 1564 # ifndef hpux_alib
 1565        /*
 1566     * for HP-UX check if /dev/audio exists
 1567     * I've never seen other audio devices under HP-UX
 1568     */
 1569        if (stat("/dev/audio",&buf) == 0) {
 1570                dsp = g_list_append(dsp,"/dev/audio");
 1571        }
 1572 # else
 1573        /*
 1574     * for HP-UX with the Alib we don't need to check if the
 1575         * device exists - we actually do not know even the device
 1576     */
 1577        dsp = g_list_append(dsp,"AUDIO ENVIRONMENT");
 1578 # endif
 1579 #endif
 1580 
 1581 #if defined(__sgi)
 1582 {
 1583     int     i, rv;
 1584     ALvalue devs [16];
 1585     ALpv    q [1];
 1586     char    devLabel [32];
 1587 
 1588     /*
 1589      * Fetch the list of available output audio devices.
 1590      */
 1591     q[0].param = AL_TYPE;
 1592     q[0].value.i = AL_OUTPUT_DEVICE_TYPE;
 1593     if ((rv = alQueryValues(AL_SYSTEM, AL_DEVICES, devs, 16, q, 1)) >= 0) {
 1594 
 1595         for (i = 0; i < rv; i++) {
 1596             q[0].param = AL_LABEL;
 1597             q[0].value.ptr = devLabel;
 1598             q[0].sizeIn = 32;
 1599             alGetParams(devs[i].i, q, 1);
 1600             if (alIsSubtype(AL_DEVICE_TYPE, devs[i].i)) {
 1601                 dsp = g_list_append(dsp, g_strdup(devLabel));
 1602             }
 1603         }
 1604     }
 1605 }
 1606 #endif
 1607 
 1608     /* do some debug output */
 1609     if (debug) {
 1610         loop = g_list_first(dsp);
 1611         while(loop) {
 1612             if (loop->data != NULL) 
 1613                 dodebug(10, "dspscan: %s\n", 
 1614                     (gchar *) loop->data);
 1615             loop = loop->next;
 1616         }
 1617     }
 1618 
 1619     return g_list_first(dsp);
 1620 }
 1621 
 1622 
 1623 /*
 1624  * take a dsp-device and find the fitting mixer-device
 1625  */
 1626 gchar *gen_mix_from_dspdev(gchar *dsp, gchar *ret) {
 1627 gchar tmp[MAXLINE];
 1628 #if !defined(aix) && !defined(linux)
 1629 struct stat buf;
 1630 # endif
 1631 #if defined(__FreeBSD__)
 1632 gchar tmp2[MAXLINE];
 1633 #endif
 1634 
 1635     strcpy(ret,"");
 1636 
 1637 #if defined(linux) 
 1638        g_snprintf(tmp,MAXLINE,"%s",dsp);
 1639        strcpy(ret,tmp);
 1640 #endif
 1641 
 1642 #if defined(__FreeBSD__)
 1643 
 1644     if (strncmp(dsp,"/dev/dsp",8) == 0) {
 1645         strcpy(tmp,dsp+8);
 1646         g_snprintf(tmp2,MAXLINE,"/dev/mixer%s",tmp);
 1647 
 1648         /* does device exist? */
 1649         if (stat(tmp2,&buf) == 0) {
 1650             strcpy(ret,tmp2);
 1651         }   
 1652     }   
 1653 #endif
 1654 #if defined(sun) || defined(__OpenBSD__)
 1655 
 1656     g_snprintf(tmp,MAXLINE,"%s%s",dsp,"ctl");
 1657 
 1658         /* does device exist? */
 1659         if (stat(tmp,&buf) == 0) {
 1660             strcpy(ret,tmp);
 1661         }
 1662 #endif
 1663 #ifdef aix
 1664        /*
 1665     * The gain will be set via ioctl
 1666     * and the usual output device
 1667     */
 1668        g_snprintf(tmp,MAXLINE,"%s",dsp);
 1669        strcpy(ret,tmp);
 1670 #endif
 1671 #ifdef hpux
 1672 # ifndef hpux_alib
 1673     g_snprintf(tmp,MAXLINE,"%s%s",dsp,"Ctl");
 1674 
 1675     /* does device exist? */
 1676     if (stat(tmp,&buf) == 0) {
 1677             strcpy(ret,tmp);
 1678     }
 1679 # else
 1680     /*
 1681      * We have no control or mixer device
 1682      * -> all is done via the Aserver-daemon and its API
 1683      */
 1684     strcpy(ret, "ASERVER"); 
 1685 # endif
 1686 #endif
 1687 
 1688     dodebug(10, "mixer: %s\n", ret);
 1689     return ret;
 1690 }
 1691 
 1692 
 1693 /*
 1694  * call uname -a to get a nice system-id-string
 1695  */
 1696 gchar *get_uname_info(gchar *str) {
 1697 FILE *fpin;
 1698 
 1699     if (stat_file(UNAME)) {
 1700         dodebug(1, "calling: %s\n", UNAME);
 1701             if ((fpin = popen(UNAME,"r")) == NULL) {
 1702                     g_error("popen error\n");
 1703         }
 1704         } else {
 1705         dodebug(1, "calling: %s\n", UNAME2);
 1706             if ((fpin = popen(UNAME2,"r")) == NULL) {
 1707                     g_error("popen error\n");
 1708         }
 1709     }
 1710 
 1711     strcpy(str,"");
 1712     if (fgets(str,MAXLINE,fpin) == NULL)
 1713                 g_error("fgets error\n");
 1714 
 1715         if (pclose(fpin) == -1) {
 1716                 g_error("pclose error\n");
 1717         }
 1718 
 1719     dodebug(10, "uname: %s\n", str);
 1720 
 1721     return str;
 1722 }
 1723 
 1724 
 1725 /*
 1726  * Save the setup-configuration to a file - all strings are converted
 1727  * in a printable form first:  return 0 if ok, or 1 on error
 1728  */
 1729 gint save_setup_config(gchar *confdir, gchar *fname) {
 1730 FILE *fd;
 1731 gchar tmp[MAXLINE];
 1732 gchar tmp2[MAXLINE];
 1733 GList *loop;
 1734 gint count;
 1735 
 1736     /* no confdir? treat path absolute */
 1737     if (strcmp(confdir,"") == 0) {
 1738         strncpy(tmp,fname,MAXLINE);
 1739     } else {
 1740 
 1741         /* now check if the confdir exists */
 1742         if (!is_directory(confdir)) {
 1743             /* try to create directory */
 1744             mkdir(confdir, 0700);
 1745             dodebug(2, "trying to mkdir %s\n", confdir);
 1746         }
 1747 
 1748         g_snprintf(tmp,MAXLINE,"%s/%s", confdir, fname);
 1749     }
 1750 
 1751     dodebug(1, "Opening %s for writing\n", tmp);
 1752     dolog(3, "Saving config file %s\n", tmp);
 1753 
 1754     fd = fopen(tmp,"w"); 
 1755 
 1756     if (fd == NULL) { 
 1757         /* error opening file */
 1758         return 1;
 1759     }
 1760 
 1761     /* write the config-file header */
 1762     fputs("#\n",fd);
 1763     g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s Configuration-File\n",XCDROAST_VERSION);
 1764     fputs(tmp,fd);
 1765     fputs("#\n",fd);
 1766     fputs("# Automatically created by the X-CD-Roast-Setup\n",fd);
 1767     fputs("# Don't edit! (Unless you REALLY know what you are doing)\n",fd);
 1768     fputs("#\n\n",fd);
 1769 
 1770     /* write data */
 1771     g_snprintf(tmp,MAXLINE,"VERSION = \"%s\"\n",XCDROAST_VERSION); 
 1772     fputs(tmp,fd);
 1773     g_snprintf(tmp,MAXLINE,"PLATFORM = \"%s\"\n",system_platform); 
 1774     fputs(tmp,fd);
 1775     g_snprintf(tmp,MAXLINE,"WRITER_DEVNR = %d\n",setupdata.writer_devnr);
 1776     fputs(tmp,fd);
 1777     g_snprintf(tmp,MAXLINE,"READER_DEVNR = %d\n",setupdata.reader_devnr);
 1778     fputs(tmp,fd);
 1779 
 1780     fputs("#\n",fd);
 1781 
 1782     /* write hardware structure */
 1783     count = 0;
 1784     while(writerreaderdevs[count] != NULL) {
 1785 
 1786         g_snprintf(tmp,MAXLINE,"WRITERREADER_DEVNR = %d\n",writerreaderdevs[count]->devnr);
 1787         fputs(tmp,fd);
 1788 
 1789         strcpy(tmp2,writerreaderdevs[count]->devicestr);
 1790         g_snprintf(tmp,MAXLINE,"WRITERREADER_DEVICESTR = \"%s\"\n",convert_escape(tmp2));
 1791         fputs(tmp,fd);
 1792 
 1793         strcpy(tmp2,writerreaderdevs[count]->vendor);
 1794         g_snprintf(tmp,MAXLINE,"WRITERREADER_VENDOR = \"%s\"\n",convert_escape(tmp2));
 1795         fputs(tmp,fd);
 1796         strcpy(tmp2,writerreaderdevs[count]->model);
 1797         g_snprintf(tmp,MAXLINE,"WRITERREADER_MODEL = \"%s\"\n",convert_escape(tmp2));
 1798         fputs(tmp,fd);
 1799         strcpy(tmp2,writerreaderdevs[count]->rev);
 1800         g_snprintf(tmp,MAXLINE,"WRITERREADER_REV = \"%s\"\n",convert_escape(tmp2));
 1801         fputs(tmp,fd);
 1802         
 1803         g_snprintf(tmp,MAXLINE,"WRITERREADER_READMAXSPEED = %d\n",writerreaderdevs[count]->writer_readmaxspeed);
 1804         fputs(tmp,fd);
 1805         g_snprintf(tmp,MAXLINE,"WRITERREADER_CDRMAXSPEED = %d\n",writerreaderdevs[count]->writer_cdrmaxspeed);
 1806         fputs(tmp,fd);
 1807         g_snprintf(tmp,MAXLINE,"WRITERREADER_DVDMAXSPEED = %d\n",writerreaderdevs[count]->writer_dvdmaxspeed);
 1808         fputs(tmp,fd);
 1809 
 1810         strcpy(tmp2,writerreaderdevs[count]->writer_flags);
 1811         g_snprintf(tmp,MAXLINE,"WRITERREADER_WRITER_FLAGS = \"%s\"\n",convert_escape(tmp2));
 1812         fputs(tmp,fd);
 1813         strcpy(tmp2,writerreaderdevs[count]->writer_modes);
 1814         g_snprintf(tmp,MAXLINE,"WRITERREADER_WRITER_MODES = \"%s\"\n",convert_escape(tmp2));
 1815         fputs(tmp,fd);
 1816 
 1817         g_snprintf(tmp,MAXLINE,"WRITERREADER_IS_CDRWRITER = %d\n",writerreaderdevs[count]->is_cdrwriter);
 1818         fputs(tmp,fd);
 1819         g_snprintf(tmp,MAXLINE,"WRITERREADER_IS_DVDWRITER = %d\n",writerreaderdevs[count]->is_dvdwriter);
 1820         fputs(tmp,fd);
 1821         g_snprintf(tmp,MAXLINE,"WRITERREADER_IS_DVDREADER = %d\n",writerreaderdevs[count]->is_dvdreader);
 1822         fputs(tmp,fd);
 1823         g_snprintf(tmp,MAXLINE,"WRITERREADER_SECTOR_SIZE = %d\n",writerreaderdevs[count]->sector_size);
 1824         fputs(tmp,fd);
 1825 
 1826         g_snprintf(tmp,MAXLINE,"WRITERREADER_DRVMODE = %d\n",writerreaderdevs[count]->writer_drvmode);
 1827         fputs(tmp,fd);
 1828         g_snprintf(tmp,MAXLINE,"WRITERREADER_MODE = %d\n",writerreaderdevs[count]->writer_mode);
 1829         fputs(tmp,fd);
 1830         g_snprintf(tmp,MAXLINE,"WRITERREADER_SPEED = %d\n",writerreaderdevs[count]->writer_speed);
 1831         fputs(tmp,fd);
 1832         g_snprintf(tmp,MAXLINE,"WRITERREADER_FIFO = %d\n",writerreaderdevs[count]->writer_fifo);
 1833         fputs(tmp,fd);
 1834         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_SPEED = %d\n",writerreaderdevs[count]->audioread_speed);
 1835         fputs(tmp,fd);
 1836         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_OVERLAP = %d\n",writerreaderdevs[count]->audioread_overlap);
 1837         fputs(tmp,fd);
 1838         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_HIDDENAUDIOTRACK = %d\n",writerreaderdevs[count]->audioread_showhiddentrack);
 1839         fputs(tmp,fd);
 1840         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_USEPARANOIA = %d\n",writerreaderdevs[count]->audioread_useparanoia);
 1841         fputs(tmp,fd);
 1842         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_PARANOIARETRIES = %d\n",writerreaderdevs[count]->audioread_paranoiaretries);
 1843         fputs(tmp,fd);
 1844         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_PARANOIAREADAHEAD = %d\n",writerreaderdevs[count]->audioread_paranoiareadahead);
 1845         fputs(tmp,fd);
 1846         g_snprintf(tmp,MAXLINE,"WRITERREADER_AUDIOREAD_PARANOIAMINOVERLAP = %d\n",writerreaderdevs[count]->audioread_paranoiaminoverlap);
 1847         fputs(tmp,fd);
 1848 
 1849 
 1850         fputs("#\n",fd);
 1851         count++;
 1852     }
 1853 
 1854     loop = g_list_first(setupdata.image_dirs);
 1855     while(loop) {
 1856         strcpy(tmp2,(gchar *)loop->data);
 1857         g_snprintf(tmp,MAXLINE,"IMAGE_DIRS = \"%s\"\n",convert_escape(tmp2));
 1858         fputs(tmp,fd);
 1859         loop = loop->next;
 1860     }
 1861 
 1862     strcpy(tmp2,setupdata.dsp_device);
 1863     g_snprintf(tmp,MAXLINE,"DSP_DEVICE = \"%s\"\n",convert_escape(tmp2));
 1864     fputs(tmp,fd);
 1865     strcpy(tmp2,setupdata.mix_device);
 1866     g_snprintf(tmp,MAXLINE,"MIX_DEVICE = \"%s\"\n",convert_escape(tmp2));
 1867     fputs(tmp,fd);
 1868     g_snprintf(tmp,MAXLINE,"NOTIFY_VIA = %d\n",setupdata.notify_via);
 1869     fputs(tmp,fd);
 1870     g_snprintf(tmp,MAXLINE,"NOTIFY_AT = %d\n",setupdata.notify_at);
 1871     fputs(tmp,fd);
 1872 
 1873     strcpy(tmp2,setupdata.cddb_host);
 1874     g_snprintf(tmp,MAXLINE,"CDDB_HOST = \"%s\"\n",convert_escape(tmp2));
 1875     fputs(tmp,fd);
 1876     g_snprintf(tmp,MAXLINE,"CDDB_PORT = %d\n",setupdata.cddb_port);
 1877     fputs(tmp,fd);
 1878     strcpy(tmp2,setupdata.cddb_proxy_host);
 1879     g_snprintf(tmp,MAXLINE,"CDDB_PROXY_HOST = \"%s\"\n",convert_escape(tmp2));
 1880     fputs(tmp,fd);
 1881     g_snprintf(tmp,MAXLINE,"CDDB_PROXY_PORT = %d\n",setupdata.cddb_proxy_port);
 1882     fputs(tmp,fd);
 1883     g_snprintf(tmp,MAXLINE,"CDDB_USE_HTTP = %d\n",setupdata.cddb_use_http);
 1884     fputs(tmp,fd);
 1885     g_snprintf(tmp,MAXLINE,"CDDB_USE_PROXY = %d\n",setupdata.cddb_use_proxy);
 1886     fputs(tmp,fd);
 1887 
 1888     strcpy(tmp2,setupdata.logfile);
 1889     g_snprintf(tmp,MAXLINE,"LOGFILE = \"%s\"\n",convert_escape(tmp2));
 1890     fputs(tmp,fd);
 1891     g_snprintf(tmp,MAXLINE,"LOGLEVEL = %d\n",setupdata.loglevel);
 1892     fputs(tmp,fd);
 1893 
 1894     strcpy(tmp2,setupdata.language);
 1895     g_snprintf(tmp,MAXLINE,"LANGUAGE = \"%s\"\n",convert_escape(tmp2));
 1896     fputs(tmp,fd);
 1897 
 1898     g_snprintf(tmp,MAXLINE,"OPTION_TOOLTIPS = %d\n",setupdata.option_tooltips);
 1899     fputs(tmp,fd);
 1900     g_snprintf(tmp,MAXLINE,"OPTION_AUTORAISE = %d\n",setupdata.option_autoraise);
 1901     fputs(tmp,fd);
 1902     g_snprintf(tmp,MAXLINE,"OPTION_SAVEPOS = %d\n",setupdata.option_savepos);
 1903     fputs(tmp,fd);
 1904     g_snprintf(tmp,MAXLINE,"OPTION_PERSONIMAGE = %d\n",setupdata.option_personimage);
 1905     fputs(tmp,fd);
 1906     g_snprintf(tmp,MAXLINE,"OPTION_OVERWRITEWARN = %d\n",setupdata.option_overwritewarn);
 1907     fputs(tmp,fd);
 1908     g_snprintf(tmp,MAXLINE,"OPTION_AUTODELETE = %d\n",setupdata.option_autodelete);
 1909     fputs(tmp,fd);
 1910     g_snprintf(tmp,MAXLINE,"OPTION_TITLEPROGRESS = %d\n",setupdata.option_titleprogress);
 1911     fputs(tmp,fd);
 1912     g_snprintf(tmp,MAXLINE,"OPTION_DISPLAYCDTEXT = %d\n",setupdata.option_displaycdtext);
 1913     fputs(tmp,fd);
 1914     /* save geometry data? */
 1915     if (setupdata.option_savepos) {
 1916         g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_X = %d\n", setupdata.mainwindow.x);
 1917         fputs(tmp,fd);
 1918         g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_Y = %d\n", setupdata.mainwindow.y);
 1919         fputs(tmp,fd);
 1920         g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_WIDTH = %d\n", setupdata.mainwindow.width);
 1921         fputs(tmp,fd);
 1922         g_snprintf(tmp,MAXLINE,"GEOMETRY_MAINWINDOW_HEIGHT = %d\n", setupdata.mainwindow.height);
 1923         fputs(tmp,fd);
 1924 
 1925         g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_X = %d\n", setupdata.burnwindow.x);
 1926         fputs(tmp,fd);
 1927         g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_Y = %d\n", setupdata.burnwindow.y);
 1928         fputs(tmp,fd);
 1929         g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_WIDTH = %d\n", setupdata.burnwindow.width);
 1930         fputs(tmp,fd);
 1931         g_snprintf(tmp,MAXLINE,"GEOMETRY_BURNWINDOW_HEIGHT = %d\n", setupdata.burnwindow.height);
 1932         fputs(tmp,fd);
 1933     }
 1934 
 1935     /* do save the following information only when root */
 1936     if (isroot()) {
 1937 
 1938         g_snprintf(tmp,MAXLINE,"ROOT_USERS_ACCESS = %d\n",setupdata.root_users_access);
 1939         fputs(tmp,fd);
 1940 
 1941         loop = g_list_first(setupdata.root_users_lists);
 1942         while(loop) {
 1943             strcpy(tmp2,(gchar *)loop->data);
 1944             g_snprintf(tmp,MAXLINE,"ROOT_USERS_LISTS = \"%s\"\n",convert_escape(tmp2));
 1945             fputs(tmp,fd);
 1946             loop = loop->next;
 1947         }
 1948 
 1949         g_snprintf(tmp,MAXLINE,"ROOT_HOSTS_ACCESS = %d\n",setupdata.root_hosts_access);
 1950         fputs(tmp,fd);
 1951 
 1952         loop = g_list_first(setupdata.root_hosts_lists);
 1953         while(loop) {
 1954             strcpy(tmp2,(gchar *)loop->data);
 1955             g_snprintf(tmp,MAXLINE,"ROOT_HOSTS_LISTS = \"%s\"\n",convert_escape(tmp2));
 1956             fputs(tmp,fd);
 1957             loop = loop->next;
 1958         }
 1959 
 1960         g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_WRITER = %d\n",setupdata.root_option_change_writer);
 1961         fputs(tmp,fd);
 1962         g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_WRITEPARAM = %d\n",setupdata.root_option_change_writeparam);
 1963         fputs(tmp,fd);
 1964         g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_READER = %d\n",setupdata.root_option_change_reader);
 1965         fputs(tmp,fd);
 1966         g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_READPARAM = %d\n",setupdata.root_option_change_readparam);
 1967         fputs(tmp,fd);
 1968         g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_IMAGEDIRS = %d\n",setupdata.root_option_change_imagedirs);
 1969         fputs(tmp,fd);
 1970         g_snprintf(tmp,MAXLINE,"ROOT_OPTION_CHANGE_LOGOPTIONS = %d\n",setupdata.root_option_change_logoptions);
 1971         fputs(tmp,fd);
 1972     }
 1973 
 1974     if (fclose(fd) != 0) {
 1975         /* error closing file */
 1976         return 1;
 1977     }
 1978 
 1979     return 0;
 1980 }
 1981 
 1982 
 1983 /*
 1984  * Load the setup-configuration, return 0 if ok or 1 on error
 1985  * when rootconf is set, load all from file, else only what we are allow
 1986  */
 1987 gint load_setup_config(gchar *fname, gint rootconf) {
 1988 FILE *fd;
 1989 gchar line[MAXLINE];
 1990 gchar id[MAXLINE];
 1991 gchar value[MAXLINE];
 1992 GList *tmp_image_dirs;
 1993 gint count, i, newadded;
 1994 
 1995     /* allocate memory if required */
 1996     if (!writerreaderdevs) {
 1997         writerreaderdevs = g_new0(writerreader_devices_t *, MAXDEVICES);
 1998     }
 1999 
 2000     count = -1; 
 2001     newadded = 0;
 2002     tmp_image_dirs = NULL;
 2003 
 2004     /* prepare some data */
 2005     if (rootconf) {
 2006         free_glist(&setupdata.image_dirs);
 2007     }
 2008     if (rootconf) {
 2009         free_glist(&setupdata.root_users_lists);
 2010         free_glist(&setupdata.root_hosts_lists);
 2011     }
 2012 
 2013     dodebug(1, "Opening config file %s for reading\n", fname);
 2014     dolog(3, "Loading config file %s\n", fname);
 2015 
 2016     if ((fd = fopen(fname,"r")) == NULL) { 
 2017         /* error opening file */
 2018         return 1;
 2019     }
 2020 
 2021     for (;;) {
 2022         if (fgets(line,MAXLINE,fd) == NULL)
 2023             break;
 2024         dodebug(10,"config: %s", line);
 2025 
 2026         /* skip empty or hashed lines */
 2027         strip_string(line);
 2028         if (*line == '#' || *line == '\0') 
 2029             continue;
 2030 
 2031                 /* parse lines */
 2032         if (parse_config_line(line,id,value)) {
 2033                     g_error("syntax error in config-file\n");
 2034         }   
 2035 
 2036         if (strcmp("VERSION",id) == 0) {
 2037             strcpy(xcdroast_version_loaded,value); 
 2038         }
 2039         if (strcmp("PLATFORM",id) == 0) {
 2040             ;
 2041         }
 2042 
 2043         if (rootconf || setupdata.root_option_change_writer) {
 2044             if (strcmp("WRITER_DEVNR",id) == 0) {
 2045                 setupdata.writer_devnr = atoi(value);
 2046             }
 2047         }
 2048         if (rootconf || setupdata.root_option_change_reader) {
 2049             if (strcmp("READER_DEVNR",id) == 0) {
 2050                 setupdata.reader_devnr = atoi(value);
 2051             }
 2052         }
 2053 
 2054         /* marker for a new device - must be the first entry! */
 2055         if (strcmp("WRITERREADER_DEVNR",id) == 0) {
 2056             i = get_writerreaderdevs_index(atoi(value));
 2057 
 2058             if (i == -1) {
 2059                 /* new device */
 2060                 if (rootconf || (setupdata.root_option_change_writer &&
 2061                             setupdata.root_option_change_reader)) {
 2062                 
 2063                         count = get_last_writerreaderdevs_index() +1;
 2064                         writerreaderdevs[count]=g_new0(writerreader_devices_t,1);
 2065                         writerreaderdevs[count]->devnr = atoi(value);
 2066                         newadded = 1;
 2067                 } else {
 2068                     /*
 2069                      * no permission to add
 2070                      * a new device -> ignore
 2071                      */
 2072                     count = -1;
 2073                     newadded = 0;
 2074                 }
 2075             } else {
 2076                 /* we seen such a device already */
 2077                 count = i;
 2078                 newadded = 0;
 2079             }
 2080         }   
 2081             
 2082         /* only load such data for newly allocated devices */
 2083         if (newadded) {
 2084 
 2085             if (strcmp("WRITERREADER_DEVICESTR",id) == 0) {
 2086                 if (count >= 0 && writerreaderdevs[count]) {
 2087                     writerreaderdevs[count]->devicestr = g_strdup(value);
 2088                 }   
 2089             }
 2090             if (strcmp("WRITERREADER_VENDOR",id) == 0) {
 2091                 if (count >= 0 && writerreaderdevs[count]) {
 2092                     strncpy(writerreaderdevs[count]->vendor, value, 9);
 2093                 }   
 2094             }
 2095             if (strcmp("WRITERREADER_MODEL",id) == 0) {
 2096                 if (count >= 0 && writerreaderdevs[count]) {
 2097                     strncpy(writerreaderdevs[count]->model, value, 17);
 2098                 }   
 2099             }
 2100             if (strcmp("WRITERREADER_REV",id) == 0) {
 2101                 if (count >= 0 && writerreaderdevs[count]) {
 2102                     strncpy(writerreaderdevs[count]->rev, value, 5);
 2103                 }   
 2104             }
 2105             if (strcmp("WRITERREADER_READMAXSPEED",id) == 0) {
 2106                 if (count >= 0 && writerreaderdevs[count]) {
 2107                     writerreaderdevs[count]->writer_readmaxspeed = atoi(value);
 2108                 }
 2109             }
 2110             if (strcmp("WRITERREADER_CDRMAXSPEED",id) == 0) {
 2111                 if (count >= 0 && writerreaderdevs[count]) {
 2112                     writerreaderdevs[count]->writer_cdrmaxspeed = atoi(value);
 2113                 }
 2114             }
 2115             if (strcmp("WRITERREADER_DVDMAXSPEED",id) == 0) {
 2116                 if (count >= 0 && writerreaderdevs[count]) {
 2117                     writerreaderdevs[count]->writer_dvdmaxspeed = atoi(value);
 2118                 }
 2119             }
 2120             if (strcmp("WRITERREADER_WRITER_FLAGS",id) == 0) {
 2121                 if (count >= 0 && writerreaderdevs[count]) {
 2122                     writerreaderdevs[count]->writer_flags = g_strdup(value);
 2123                 }   
 2124             }
 2125             if (strcmp("WRITERREADER_WRITER_MODES",id) == 0) {
 2126                 if (count >= 0 && writerreaderdevs[count]) {
 2127                     writerreaderdevs[count]->writer_modes = g_strdup(value);
 2128                 }   
 2129             }
 2130             if (strcmp("WRITERREADER_IS_CDRWRITER",id) == 0) {
 2131                 if (count >= 0 && writerreaderdevs[count]) {
 2132                     writerreaderdevs[count]->is_cdrwriter = atoi(value);
 2133                 }
 2134             }
 2135             if (strcmp("WRITERREADER_IS_DVDREADER",id) == 0) {
 2136                 if (count >= 0 && writerreaderdevs[count]) {
 2137                     writerreaderdevs[count]->is_dvdreader = atoi(value);
 2138                 }
 2139             }
 2140             if (strcmp("WRITERREADER_IS_DVDWRITER",id) == 0) {
 2141                 if (count >= 0 && writerreaderdevs[count]) {
 2142                     writerreaderdevs[count]->is_dvdwriter = atoi(value);
 2143                 }
 2144             }
 2145             if (strcmp("WRITERREADER_SECTOR_SIZE",id) == 0) {
 2146                 if (count >= 0 && writerreaderdevs[count]) {
 2147                     writerreaderdevs[count]->sector_size = atoi(value);
 2148                 }
 2149             }
 2150         }
 2151 
 2152         if (rootconf || newadded || setupdata.root_option_change_writeparam) {
 2153 
 2154             if (strcmp("WRITERREADER_DRVMODE",id) == 0) {
 2155                 if (count >= 0 && writerreaderdevs[count]) {
 2156                     writerreaderdevs[count]->writer_drvmode = atoi(value);
 2157                 }
 2158             }
 2159             if (strcmp("WRITERREADER_MODE",id) == 0) {
 2160                 if (count >= 0 && writerreaderdevs[count]) {
 2161                     writerreaderdevs[count]->writer_mode = atoi(value);
 2162                 }
 2163             }
 2164             if (strcmp("WRITERREADER_SPEED",id) == 0) {
 2165                 if (count >= 0 && writerreaderdevs[count]) {
 2166                     writerreaderdevs[count]->writer_speed = atoi(value);
 2167                 }
 2168             }
 2169             if (strcmp("WRITERREADER_FIFO",id) == 0) {
 2170                 if (count >= 0 && writerreaderdevs[count]) {
 2171                     writerreaderdevs[count]->writer_fifo = atoi(value);
 2172                 }
 2173             }
 2174         }
 2175 
 2176         if (rootconf || newadded || setupdata.root_option_change_readparam) {
 2177 
 2178             if (strcmp("WRITERREADER_AUDIOREAD_SPEED",id) == 0) {
 2179                 if (count >= 0 && writerreaderdevs[count]) {
 2180                     writerreaderdevs[count]->audioread_speed = atoi(value);
 2181                 }
 2182             }
 2183             if (strcmp("WRITERREADER_AUDIOREAD_OVERLAP",id) == 0) {
 2184                 if (count >= 0 && writerreaderdevs[count]) {
 2185                     writerreaderdevs[count]->audioread_overlap = atoi(value);
 2186                 }
 2187             }
 2188             if (strcmp("WRITERREADER_AUDIOREAD_HIDDENAUDIOTRACK",id) == 0) {
 2189                 if (count >= 0 && writerreaderdevs[count]) {
 2190                     writerreaderdevs[count]->audioread_showhiddentrack = atoi(value);
 2191                 }
 2192             }
 2193             if (strcmp("WRITERREADER_AUDIOREAD_USEPARANOIA",id) == 0) {
 2194                 if (count >= 0 && writerreaderdevs[count]) {
 2195                     writerreaderdevs[count]->audioread_useparanoia = atoi(value);
 2196                 }
 2197             }
 2198             if (strcmp("WRITERREADER_AUDIOREAD_PARANOIARETRIES",id) == 0) {
 2199                 if (count >= 0 && writerreaderdevs[count]) {
 2200                     writerreaderdevs[count]->audioread_paranoiaretries = atoi(value);
 2201                 }
 2202             }
 2203             if (strcmp("WRITERREADER_AUDIOREAD_PARANOIAREADAHEAD",id) == 0) {
 2204                 if (count >= 0 && writerreaderdevs[count]) {
 2205                     writerreaderdevs[count]->audioread_paranoiareadahead = atoi(value);
 2206                 }
 2207             }
 2208             if (strcmp("WRITERREADER_AUDIOREAD_PARANOIAMINOVERLAP",id) == 0) {
 2209                 if (count >= 0 && writerreaderdevs[count]) {
 2210                     writerreaderdevs[count]->audioread_paranoiaminoverlap = atoi(value);
 2211                 }
 2212             }
 2213         }
 2214 
 2215         if (rootconf) {
 2216             if (strcmp("IMAGE_DIRS",id) == 0) {
 2217                 setupdata.image_dirs = g_list_append(setupdata.image_dirs, g_strdup(value));    
 2218             }
 2219         } else {
 2220             /* user config - load to tmp list */
 2221             if (strcmp("IMAGE_DIRS",id) == 0) {
 2222                 tmp_image_dirs = g_list_append(tmp_image_dirs, g_strdup(value));    
 2223             }
 2224         }
 2225         if (strcmp("DSP_DEVICE",id) == 0) {
 2226             g_free(setupdata.dsp_device);
 2227             setupdata.dsp_device = g_strdup(value);
 2228         }
 2229         if (strcmp("MIX_DEVICE",id) == 0) {
 2230             g_free(setupdata.mix_device);
 2231             setupdata.mix_device = g_strdup(value);
 2232         }
 2233         if (strcmp("NOTIFY_VIA",id) == 0) {
 2234             setupdata.notify_via = atoi(value);
 2235         }
 2236         if (strcmp("NOTIFY_AT",id) == 0) {
 2237             setupdata.notify_at = atoi(value);
 2238         }
 2239 
 2240         if (strcmp("CDDB_HOST",id) == 0) {
 2241             g_free(setupdata.cddb_host);
 2242             setupdata.cddb_host = g_strdup(value);
 2243         }
 2244         if (strcmp("CDDB_PORT",id) == 0) {
 2245             setupdata.cddb_port = atoi(value);
 2246         }
 2247         if (strcmp("CDDB_PROXY_HOST",id) == 0) {
 2248             g_free(setupdata.cddb_proxy_host);
 2249             setupdata.cddb_proxy_host = g_strdup(value);
 2250         }
 2251         if (strcmp("CDDB_PROXY_PORT",id) == 0) {
 2252             setupdata.cddb_proxy_port = atoi(value);
 2253         }
 2254         if (strcmp("CDDB_USE_HTTP",id) == 0) {
 2255             setupdata.cddb_use_http = atoi(value);
 2256         }
 2257         if (strcmp("CDDB_USE_PROXY",id) == 0) {
 2258             setupdata.cddb_use_proxy = atoi(value);
 2259         }
 2260 
 2261         if (rootconf || setupdata.root_option_change_logoptions) {
 2262             if (strcmp("LOGFILE",id) == 0) {
 2263                 g_free(setupdata.logfile);
 2264                 setupdata.logfile = g_strdup(value);
 2265             }
 2266             if (strcmp("LOGLEVEL",id) == 0) {
 2267                 setupdata.loglevel = atoi(value);
 2268             }
 2269         }
 2270 
 2271         if (strcmp("LANGUAGE",id) == 0) {
 2272             g_free(setupdata.language);
 2273             setupdata.language = g_strdup(value);
 2274 
 2275             /* check if that value is an integer */
 2276             if (atoi(value) != 0 || strcmp(value,"0") == 0) {
 2277                 /*
 2278                  * it is, so set empty language
 2279                  * to be backward compatible
 2280                  */
 2281                 g_free(setupdata.language);
 2282                 setupdata.language = g_strdup("");
 2283             }
 2284         }
 2285 
 2286         if (strcmp("OPTION_TOOLTIPS",id) == 0) {
 2287             setupdata.option_tooltips = atoi(value);
 2288         }
 2289         if (strcmp("OPTION_AUTORAISE",id) == 0) {
 2290             setupdata.option_autoraise = atoi(value);
 2291         }
 2292         if (strcmp("OPTION_SAVEPOS",id) == 0) {
 2293             setupdata.option_savepos = atoi(value);
 2294         }
 2295         if (strcmp("OPTION_PERSONIMAGE",id) == 0) {
 2296             setupdata.option_personimage = atoi(value);
 2297         }
 2298         if (strcmp("OPTION_OVERWRITEWARN",id) == 0) {
 2299             setupdata.option_overwritewarn = atoi(value);
 2300         }
 2301         if (strcmp("OPTION_AUTODELETE",id) == 0) {
 2302             setupdata.option_autodelete = atoi(value);
 2303         }
 2304         if (strcmp("OPTION_TITLEPROGRESS",id) == 0) {
 2305             setupdata.option_titleprogress = atoi(value);
 2306         }
 2307         if (strcmp("OPTION_DISPLAYCDTEXT",id) == 0) {
 2308             setupdata.option_displaycdtext = atoi(value);
 2309         }
 2310         if (setupdata.option_savepos) {
 2311             if (strcmp("GEOMETRY_MAINWINDOW_X",id) == 0) {
 2312                 setupdata.mainwindow.x = atoi(value);
 2313             }
 2314             if (strcmp("GEOMETRY_MAINWINDOW_Y",id) == 0) {
 2315                 setupdata.mainwindow.y = atoi(value);
 2316             }
 2317             if (strcmp("GEOMETRY_MAINWINDOW_WIDTH",id) == 0) {
 2318                 setupdata.mainwindow.width = atoi(value);
 2319             }
 2320             if (strcmp("GEOMETRY_MAINWINDOW_HEIGHT",id) == 0) {
 2321                 setupdata.mainwindow.height = atoi(value);
 2322             }
 2323 
 2324             if (strcmp("GEOMETRY_BURNWINDOW_X",id) == 0) {
 2325                 setupdata.burnwindow.x = atoi(value);
 2326             }
 2327             if (strcmp("GEOMETRY_BURNWINDOW_Y",id) == 0) {
 2328                 setupdata.burnwindow.y = atoi(value);
 2329             }
 2330             if (strcmp("GEOMETRY_BURNWINDOW_WIDTH",id) == 0) {
 2331                 setupdata.burnwindow.width = atoi(value);
 2332             }
 2333             if (strcmp("GEOMETRY_BURNWINDOW_HEIGHT",id) == 0) {
 2334                 setupdata.burnwindow.height = atoi(value);
 2335             }
 2336         }
 2337 
 2338         /* do load the following information only when root */
 2339         if (rootconf) {
 2340             if (strcmp("ROOT_USERS_ACCESS",id) == 0) {
 2341                 setupdata.root_users_access = atoi(value);
 2342             }
 2343             if (strcmp("ROOT_USERS_LISTS",id) == 0) {
 2344                 setupdata.root_users_lists = g_list_append(setupdata.root_users_lists, g_strdup(value));    
 2345             }
 2346             if (strcmp("ROOT_HOSTS_ACCESS",id) == 0) {
 2347                 setupdata.root_hosts_access = atoi(value);
 2348             }
 2349             if (strcmp("ROOT_HOSTS_LISTS",id) == 0) {
 2350                 setupdata.root_hosts_lists = g_list_append(setupdata.root_hosts_lists, g_strdup(value));    
 2351             }
 2352 
 2353             if (strcmp("ROOT_OPTION_CHANGE_WRITER",id) == 0) {
 2354                 setupdata.root_option_change_writer = atoi(value);
 2355             }
 2356             if (strcmp("ROOT_OPTION_CHANGE_WRITEPARAM",id) == 0) {
 2357                 setupdata.root_option_change_writeparam = atoi(value);
 2358             }
 2359             if (strcmp("ROOT_OPTION_CHANGE_READER",id) == 0) {
 2360                 setupdata.root_option_change_reader = atoi(value);
 2361             }
 2362             if (strcmp("ROOT_OPTION_CHANGE_READPARAM",id) == 0) {
 2363                 setupdata.root_option_change_readparam = atoi(value);
 2364             }
 2365             if (strcmp("ROOT_OPTION_CHANGE_IMAGEDIRS",id) == 0) {
 2366                 setupdata.root_option_change_imagedirs = atoi(value);
 2367             }
 2368             if (strcmp("ROOT_OPTION_CHANGE_LOGOPTIONS",id) == 0) {
 2369                 setupdata.root_option_change_logoptions = atoi(value);
 2370             }
 2371         }
 2372     }
 2373     /* now handle image dirs */
 2374     if (!rootconf) {
 2375         /* are we allowed to change image dirs? */
 2376         if (setupdata.root_option_change_imagedirs) {
 2377             /* had we configured some yet? */
 2378             if (g_list_length(tmp_image_dirs) > 0) {
 2379                 /* use user one */
 2380                 copy_glist(&setupdata.image_dirs,
 2381                     tmp_image_dirs);
 2382             }
 2383         }
 2384     }
 2385 
 2386     /* free temporary list */
 2387     free_glist(&tmp_image_dirs);
 2388 
 2389     if (fclose(fd) != 0) {
 2390         /* error closing file */
 2391         return 1;
 2392     }
 2393 
 2394     return 0;
 2395 }
 2396 
 2397 
 2398 /*
 2399  * parse a detailed toc line
 2400  */
 2401 static void parse_toc_line(gchar *line) {
 2402 gchar tmp[MAXLINE];
 2403 gchar tmp2[MAXLINE];
 2404 gchar tmp3[MAXLINE];
 2405 gchar old_cddb_title[MAXLINE];
 2406 gchar old_cdtext_title[MAXLINE];
 2407 gchar old_cdtext_artist[MAXLINE];
 2408 gchar *p1;
 2409 gint min,sec,frm;
 2410 gint ret;
 2411 
 2412     /* too many tracks? */
 2413     if (tocnr >= MAXTRACKS) {
 2414         g_error("over %d tracks in toc\n",MAXTRACKS);
 2415     }
 2416 
 2417     strcpy(old_cddb_title,"");
 2418     strcpy(old_cdtext_title,"");
 2419     strcpy(old_cdtext_artist,"");
 2420 
 2421     /* allocate memory for new line (free first old memory)*/
 2422     if (trackinfo[tocnr] != NULL) {
 2423         g_free(trackinfo[tocnr]->volname);
 2424 
 2425         /* backup old cdtext */
 2426         if (trackinfo[tocnr]->title) {
 2427             strncpy(old_cdtext_title, trackinfo[tocnr]->title, MAXLINE);
 2428         }
 2429         g_free(trackinfo[tocnr]->title);
 2430         /* backup old cdtext */
 2431         if (trackinfo[tocnr]->artist) {
 2432             strncpy(old_cdtext_artist, trackinfo[tocnr]->artist, MAXLINE);
 2433         }
 2434         g_free(trackinfo[tocnr]->artist);
 2435 
 2436         /* backup old cddb-title  */
 2437         if (trackinfo[tocnr]->cddb_ttitle != NULL) {
 2438             strncpy(old_cddb_title, trackinfo[tocnr]->cddb_ttitle, MAXLINE);
 2439         }
 2440         g_free(trackinfo[tocnr]->cddb_ttitle);
 2441         g_free(trackinfo[tocnr]);
 2442     }
 2443     trackinfo[tocnr] = g_new0(track_info_t,1);
 2444 
 2445     /* when the cd is still the same as last time, restore cddb-title */
 2446     if (cd_is_still_the_same == 1) {
 2447         /* got a backuped title? */
 2448         if (strcmp(old_cddb_title,"") != 0) {
 2449             trackinfo[tocnr]->cddb_ttitle = g_strdup(old_cddb_title); 
 2450         }
 2451     }
 2452 
 2453     /* now we are prepared to fill structure */
 2454     strcpy(tmp,line+1);
 2455     p1 = strtok(tmp,":");
 2456     if (p1 == NULL) {
 2457         g_error("Unexpected output in cdda2wav toc-output\n");
 2458     }
 2459     trackinfo[tocnr]->track_nr = atoi(p1);
 2460     if (trackinfo[tocnr]->track_nr == 0)
 2461         cdinfo.nr_tracks++;
 2462     trackinfo[tocnr]->isosize = -1;
 2463 
 2464     /* put rest of string into tmp2 and strip off leading spaces */
 2465     p1 = strtok(NULL,"");
 2466     strcpy(tmp2,p1);
 2467     strip_string(tmp2);
 2468 
 2469     p1 = strtok(tmp2," ");
 2470     trackinfo[tocnr]->start_sec = atoi(p1);
 2471 
 2472     p1 = strtok(NULL,"");
 2473     if (p1 == NULL) {
 2474         g_error("Unexpected output in cdda2wav toc-output\n");
 2475     }
 2476     strcpy(tmp,p1);
 2477     strip_string(tmp);
 2478 
 2479     /* now get tracklength - convert to frames */
 2480     p1 = strtok(tmp," ");
 2481     sscanf(p1,"%d:%d.%d",&min,&sec,&frm);
 2482     trackinfo[tocnr]->size = (min*60+sec)*75 + frm;
 2483 
 2484     /* tracktype */
 2485     p1 = strtok(NULL," ");
 2486     if (strncmp(p1,"data",4) == 0) {
 2487         /* data-track */
 2488         trackinfo[tocnr]->type = 0;
 2489 
 2490         p1 = strtok(NULL," ");
 2491         if (strncmp(p1,"uninterrupted",13) == 0) {
 2492             trackinfo[tocnr]->rec_type = 1;
 2493         } else {
 2494             trackinfo[tocnr]->rec_type = 0;
 2495         }
 2496 
 2497         p1 = strtok(NULL," ");
 2498         if (strncmp(p1,"copydenied",10) == 0) {
 2499             trackinfo[tocnr]->copyperm = 0;
 2500         } else {
 2501             trackinfo[tocnr]->copyperm = 1;
 2502         }   
 2503         if (cd_is_still_the_same == 1) {
 2504             /* use cached cd-text */
 2505             trackinfo[tocnr]->title = g_strdup(old_cdtext_title);
 2506             trackinfo[tocnr]->artist = g_strdup(old_cdtext_artist);
 2507         }
 2508     } else {
 2509         /* audio-track */
 2510         trackinfo[tocnr]->type = 1;
 2511         
 2512         p1 = strtok(NULL," ");
 2513         if (strncmp(p1,"linear",6) == 0) {
 2514             trackinfo[tocnr]->preemp = 0;
 2515         } else {
 2516             trackinfo[tocnr]->preemp = 1;
 2517         }
 2518 
 2519         p1 = strtok(NULL," ");
 2520         if (strncmp(p1,"copydenied",10) == 0) {
 2521             trackinfo[tocnr]->copyperm = 0;
 2522         } else {
 2523             trackinfo[tocnr]->copyperm = 1;
 2524         }   
 2525 
 2526         p1 = strtok(NULL," ");
 2527         if (strncmp(p1,"stereo",6) == 0) {
 2528             trackinfo[tocnr]->stereo = 1;
 2529         } else {
 2530             trackinfo[tocnr]->stereo = 0;
 2531         }   
 2532 
 2533         p1 = strtok(NULL," ");
 2534         p1 = strtok(NULL,"");
 2535         if (p1) {
 2536             strcpy(tmp2,p1);
 2537             strip_string(tmp2);
 2538             ret = decode_title_artist(tmp2,tmp,tmp3);
 2539             if (ret != 0) {
 2540                 g_error("got unexpected artist/title\n");
 2541             }
 2542 
 2543             if (cd_is_still_the_same == 1) {
 2544                 if (tmp[0] == '\0') {
 2545                     /* no new data, use cached */
 2546                     trackinfo[tocnr]->title = g_strdup(old_cdtext_title);
 2547                 }  else {
 2548                     trackinfo[tocnr]->title = g_strdup(tmp);
 2549                 }
 2550                 if (tmp3[0] == '\0') {
 2551                     /* no new data, use cached */
 2552                     trackinfo[tocnr]->artist = g_strdup(old_cdtext_artist);
 2553                 } else {
 2554                     trackinfo[tocnr]->artist = g_strdup(tmp3);
 2555                 }   
 2556             } else {
 2557                 trackinfo[tocnr]->title = g_strdup(tmp);
 2558                 trackinfo[tocnr]->artist = g_strdup(tmp3);
 2559             }
 2560         } else {
 2561             trackinfo[tocnr]->title = g_strdup("");
 2562             trackinfo[tocnr]->artist = g_strdup("");
 2563         }
 2564     }   
 2565 
 2566     
 2567     tocnr++;
 2568 }
 2569 
 2570 
 2571 /*
 2572  * print memory-structure with toc-data (debug purposes)
 2573  */
 2574 static void print_cdinfo() {
 2575 gint i;
 2576 gchar *p1, *p2, *p3, *p4;
 2577 gchar tmp[] = "(NULL)";
 2578 
 2579     dodebug(2,"------ cdinfo-structure -----\n");
 2580     dodebug(2,"nr_tracks: %d\n",cdinfo.nr_tracks);
 2581     dodebug(2,"total_size: %d\n",cdinfo.total_size);
 2582     dodebug(2,"cddb_discid: %s\n",cdinfo.cddb_discid);
 2583     dodebug(2,"have_cdtext: %d, have_cdextra: %d\n",cdinfo.have_cdtext,
 2584          cdinfo.have_cdextra);
 2585     if (cdinfo.title != NULL && cdinfo.artist != NULL) {
 2586         dodebug(2,"title/artist: %s/%s\n",cdinfo.title,cdinfo.artist);
 2587     } else {
 2588         dodebug(2,"title/artist: (NULL)/(NULL)\n");
 2589     }
 2590     if (cdinfo.cddb_dtitle != NULL) {
 2591         dodebug(2,"cddb_dtitle: %s\n",cdinfo.cddb_dtitle);
 2592     } else {
 2593         dodebug(2,"cddb_dtitle: (NULL)\n");
 2594     }
 2595     dodebug(2,"leadout: %d\n", cdinfo.leadout);
 2596 
 2597     for (i = 0; i < cdinfo.nr_tracks; i++) {
 2598 
 2599         dodebug(2,"track: %d start: %d size: %d\n",trackinfo[i]->track_nr,
 2600             trackinfo[i]->start_sec, trackinfo[i]->size);
 2601         dodebug(2,"       type: %d, rec_type: %d, preemp: %d, copyperm: %d, stereo: %d\n", 
 2602             trackinfo[i]->type, trackinfo[i]->rec_type,
 2603             trackinfo[i]->preemp, trackinfo[i]->copyperm,
 2604             trackinfo[i]->stereo);
 2605         /* check if we have any null-pointers lying around */
 2606         p1 = trackinfo[i]->title;
 2607         p2 = trackinfo[i]->artist;
 2608         p3 = trackinfo[i]->cddb_ttitle;
 2609         p4 = trackinfo[i]->volname;
 2610         if (p1 == NULL) p1 = tmp;
 2611         if (p2 == NULL) p2 = tmp;
 2612         if (p3 == NULL) p3 = tmp;
 2613         if (p4 == NULL) p4 = tmp;
 2614 
 2615         dodebug(2,"       title/artist: %s/%s cddb_title: %s volname: %s\n", 
 2616             p1, p2, p3, p4);
 2617     }
 2618 }
 2619 
 2620 
 2621 /*
 2622  * interpret line for line the output of cdda2wav
 2623  */
 2624 static gint parse_toc(gchar *line) {
 2625 gchar tmp[MAXLINE];
 2626 gchar tmp2[MAXLINE];
 2627 gchar tmp3[MAXLINE];
 2628 gchar *p,*p1;
 2629 gint min,sec,frm;
 2630 gint ret;
 2631 gint mmaperror;
 2632 
 2633     mmaperror = 0;
 2634 
 2635     /* initial state */
 2636     if (tocstate == 0) {
 2637         /* mmap error? */
 2638         if (strstr(line,"annot get mmap for")) {
 2639             mmaperror = 1;
 2640         }
 2641 
 2642         /* first look for "Tracks" line */
 2643         if (strncmp(line,"Tracks:",7) == 0) {
 2644             strcpy(tmp,line+7);
 2645             p1 = strtok(tmp," ");
 2646             strcpy(tmp2,p1);
 2647             cdinfo.nr_tracks = atoi(tmp2);
 2648             p1 = strtok(NULL,"");
 2649             strcpy(tmp2,p1);
 2650             sscanf(tmp2,"%d:%d.%d",&min,&sec,&frm);         
 2651             cdinfo.total_size = (min*60+sec)*75 + frm;
 2652         }
 2653         if (strncmp(line,"CDINDEX",7) == 0) {
 2654             /* we don't support cdindex right now */
 2655             ;
 2656         }
 2657         if (strncmp(line,"CDDB",4) == 0) {
 2658             strcpy(tmp,line+15);
 2659             strip_string(tmp);
 2660             strcpy(cdinfo.cddb_discid,tmp);
 2661             /*
 2662              * check if the CD we have in the drive
 2663              * is the same as the last one we got
 2664              */
 2665             if (strcmp(cdinfo_cddb_title_bak, cdinfo.cddb_discid) == 0) {
 2666                 cd_is_still_the_same = 1;
 2667             }
 2668     
 2669             /* finished with state 0 */
 2670             tocstate = 1;
 2671         }
 2672 
 2673         /* get next line from output */
 2674         return mmaperror;
 2675     }
 2676 
 2677     /* cd-text state */
 2678     if (tocstate == 1) {
 2679         if (strncmp(line,"CD-Text: detected",17) == 0) {
 2680             cdinfo.have_cdtext = 1;
 2681         }
 2682         if (strncmp(line,"CD-Text: not detected",21) == 0) {
 2683             cdinfo.have_cdtext = 0;
 2684         }
 2685 
 2686         /* ignore any cd-text-output for now */
 2687         ;
 2688 
 2689         if (strncmp(line,"CD-Extra: ",10) == 0) {
 2690             /* see this as endmarker of cd-text section */
 2691             tocstate = 2;
 2692         }
 2693         /*
 2694          * don't return here because
 2695          * we may need the current line
 2696          */
 2697     }
 2698 
 2699     /* cd-extra state */
 2700     if (tocstate == 2) {
 2701         if (strncmp(line,"CD-Extra: detected",18) == 0) {
 2702             cdinfo.have_cdextra = 1;
 2703         }
 2704         if (strncmp(line,"CD-Extra: not detected",22) == 0) {
 2705             cdinfo.have_cdextra = 0;
 2706         }
 2707 
 2708         /* ignore any cd-extra-output for now */
 2709         ;
 2710         
 2711         if (strstr(line,"Album title:") != NULL) {
 2712             /* see this as endmarker of cd-extra section */
 2713             tocstate = 3;
 2714         }
 2715         /*
 2716          * don't return here because
 2717          * we may need the current line
 2718          */
 2719     }
 2720     
 2721     /* toc-listing mode */
 2722     if (tocstate == 3) {
 2723         if ((p = strstr(line,"Album title:")) != NULL) {
 2724             strcpy(tmp,p+13);
 2725             strip_string(tmp);
 2726             ret = decode_title_artist(tmp,tmp2,tmp3);
 2727             if (ret != 0) {
 2728                 g_error("got unexpected artist/title\n");
 2729             }   
 2730             g_free(cdinfo.title);
 2731 
 2732             cdinfo.title = g_strdup(tmp2);
 2733             g_free(cdinfo.artist);
 2734             cdinfo.artist = g_strdup(tmp3);
 2735         }
 2736 
 2737         /* now the most complex part: the toc-list itself */
 2738         if (line[0] == 'T' && line[3] == ':') {
 2739             parse_toc_line(line);
 2740         }   
 2741 
 2742         if (strncmp(line,"Leadout:",8) == 0) {
 2743             strcpy(tmp,line+8);
 2744             strip_string(tmp);
 2745             cdinfo.leadout = atoi(tmp);
 2746         }
 2747     }
 2748 
 2749     return 0;
 2750 }
 2751 
 2752 
 2753 /*
 2754  * called when reading the TOC of ATAPI cdroms takes too long
 2755  */
 2756 static gint getcdtoc_atapi_timeout_func(gpointer data) {
 2757 
 2758     getcdtoc_atapi_timeout_dialog = show_dialog_wait(ICO_INFO,
 2759         _("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."));
 2760 
 2761     return (FALSE);
 2762 }
 2763 
 2764 
 2765 static gboolean getcdtoc_out(GIOChannel *source, GIOCondition cond, gpointer data) {
 2766 gchar line[MAXLINE];
 2767 
 2768     if (cond & G_IO_IN) {
 2769         /* read output of getcdtoc */
 2770         read_io_channel(source, line, MAXLINE);
 2771 
 2772         dodebug(10,"readtoc: %s\n", line);
 2773 
 2774         count_mmaperror += parse_toc(line);
 2775         }
 2776 
 2777         /* getcdtoc finished */
 2778     if (cond == G_IO_HUP) {
 2779 
 2780                 /* tell our caller that we are done here */
 2781                 read_done = get_wait_ret(-1);
 2782                 return (FALSE);
 2783         }
 2784     return (TRUE);
 2785 }
 2786 
 2787 
 2788 /*
 2789  * call cdda2wav -J to get the cd-toc
 2790  * add ATAPI long-delay warning window
 2791  */
 2792 void get_cd_toc(gint devnr) {
 2793 gchar line[MAXLINE];
 2794 gchar tmp[MAXLINE];
 2795 gchar tmp2[MAXLINE];
 2796 gchar tmp8[MAXLINE];
 2797 gint ret, dvdsize, read_out;
 2798 gchar old_cdtext_title[MAXLINE];
 2799 gchar old_cdtext_artist[MAXLINE];
 2800 gint getcdtoc_timeout;
 2801 GIOChannel *gio;
 2802 
 2803     /* get bus,id,lun string */
 2804     if (convert_devnr2busid(devnr,tmp) != 0) {
 2805         g_error("non existing cdrom?");
 2806     }
 2807 
 2808     getcdtoc_atapi_timeout_dialog = NULL;
 2809     getcdtoc_timeout = 0;
 2810 
 2811     /* ATAPI device? (only on linux) */
 2812     if (strstr(tmp, "ATAPI")) {
 2813         /* if it does take longer than 5 seconds, display warning */
 2814         getcdtoc_timeout = g_timeout_add(5000,
 2815             getcdtoc_atapi_timeout_func, NULL);
 2816     }
 2817     
 2818     /* check if disc is loaded */
 2819     if (!check_medium_loaded(devnr)) {
 2820         /* not loaded */
 2821         cdinfo.nr_tracks = -1;
 2822 
 2823         if (getcdtoc_timeout) {
 2824             /* remove timeout, if it did not kick in yet */
 2825             g_source_remove(getcdtoc_timeout);
 2826         }   
 2827         if (getcdtoc_atapi_timeout_dialog) {
 2828             /* and remove the dialog wait window */
 2829             show_dialog_wait_remove(getcdtoc_atapi_timeout_dialog);
 2830         }   
 2831 
 2832         return;
 2833     }
 2834 
 2835     cdinfo.have_cdtext = -1;
 2836     cdinfo.have_cdextra = -1;
 2837     cdinfo.nr_tracks = -1;
 2838     
 2839     read_done = 999;
 2840     tocstate = 0;
 2841     tocnr = 0;
 2842     cd_is_still_the_same = 0;
 2843     count_mmaperror = 0;
 2844 
 2845 
 2846     /*
 2847      * backup cddb-value to check if the new CD
 2848      * is the same as the last one we read
 2849      */
 2850     strncpy(cdinfo_cddb_title_bak, cdinfo.cddb_discid, MAXLINE);
 2851 
 2852     /* backup current cd-text album info */
 2853     if (cdinfo.title) {
 2854         strncpy(old_cdtext_title, cdinfo.title, MAXLINE);
 2855     } else {
 2856         strcpy(old_cdtext_title, "");
 2857     }
 2858     if (cdinfo.artist) {
 2859         strncpy(old_cdtext_artist, cdinfo.artist, MAXLINE);
 2860     } else {
 2861         strcpy(old_cdtext_artist, "");
 2862     }
 2863 
 2864     /* have to enable -no-hidden-track? */
 2865     if (get_cur_audioread_showhiddentrack()) {
 2866         strcpy(tmp8,"");
 2867     } else {
 2868         strcpy(tmp8,"-no-hidden-track");
 2869     }
 2870 
 2871     /* build command line */
 2872     get_wrap_path("CDDA2WAV", tmp2);
 2873     g_snprintf(line,MAXLINE,
 2874            "%s -D \"%s\" %s -Q -g -H -J -v toc,summary,sectors,titles",
 2875            tmp2,tmp,tmp8);
 2876 
 2877     dodebug(1,"spawning: %s\n", line);
 2878 
 2879         readcdda_pid = full_dpl_pipe3(NULL,NULL,&read_out,line,0);
 2880         readcdda_pid2 = -1;
 2881 
 2882     gio = g_io_channel_unix_new(read_out);
 2883     g_io_channel_set_encoding(gio, NULL, NULL); 
 2884         readcdda_callback = g_io_add_watch(gio, G_IO_IN | G_IO_HUP,
 2885                 getcdtoc_out, NULL);
 2886 
 2887         /* now wait until toc is read */
 2888         while (read_done == 999) {
 2889                 wait_and_process_events();
 2890         }
 2891 
 2892     g_io_channel_unref(gio);
 2893         close(read_out);
 2894 
 2895     ret = read_done;
 2896 
 2897     /* error while reading tracks? */
 2898     if (ret != 0 && cdinfo.nr_tracks != tocnr) {
 2899         cdinfo.nr_tracks = -2;
 2900     }
 2901 
 2902     /* cd loaded but not readable = empty recordable? */
 2903     if (ret != 0 && cdinfo.nr_tracks < 1 ) {
 2904         cdinfo.nr_tracks = -2;
 2905     }
 2906 
 2907     /* if cd changed, clear out cddb_dtitle */
 2908     if (cd_is_still_the_same == 0) {
 2909         g_free(cdinfo.cddb_dtitle);
 2910         cdinfo.cddb_dtitle = NULL;
 2911     } else {
 2912         /* cd stayed the same, restore album cd-text */
 2913         if (cdinfo.title[0] == '\0' && old_cdtext_title[0] != '\0') {
 2914             g_free(cdinfo.title);
 2915             cdinfo.title = g_strdup(old_cdtext_title);
 2916         }
 2917         if (cdinfo.artist[0] == '\0' && old_cdtext_artist[0] != '\0') {
 2918             g_free(cdinfo.artist);
 2919             cdinfo.artist = g_strdup(old_cdtext_artist);
 2920         }
 2921     }
 2922 
 2923     /*
 2924      * now a workaround for a broken cdda2wav
 2925      * when it comes to read the toc of a DVD
 2926      * -> use cdrecord -toc instead
 2927      */
 2928     if (cdinfo.nr_tracks == 1 && (cdinfo.leadout == 1151850 || cdinfo.leadout == 1151849 || cdinfo.leadout == 449849)) {
 2929         /* this is slow, so only use it in that rare case */    
 2930         dvdsize = get_cdrecord_toc(devnr);
 2931         if (dvdsize > 0) {
 2932             /*
 2933              * overwrite faulty values by the real ones
 2934              * 1152000 is 256:00.00 which is not right
 2935              * 449999 is  100:00.00 -1 frame
 2936              */
 2937             cdinfo.leadout = dvdsize;
 2938             trackinfo[0]->size = dvdsize;
 2939             cdinfo.total_size = dvdsize + 150;
 2940         }
 2941     }
 2942 
 2943     /* have we hit the mmap error? */
 2944     if (count_mmaperror > 0) {
 2945                 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);
 2946                 if (ret == 1) 
 2947                         gtk_exit(1);
 2948     }
 2949 
 2950     if (getcdtoc_timeout) {
 2951         /* remove timeout, if it did not kick in yet */
 2952         g_source_remove(getcdtoc_timeout);
 2953     }   
 2954     if (getcdtoc_atapi_timeout_dialog) {
 2955         /* and remove the dialog wait window */
 2956         show_dialog_wait_remove(getcdtoc_atapi_timeout_dialog);
 2957     }   
 2958 
 2959     if (debug) print_cdinfo();
 2960 
 2961 }
 2962 
 2963 
 2964 /*
 2965  * start subprocess and reroute stdin and stdout
 2966  * use /bin/sh to spawn subprocess
 2967  */
 2968 pid_t full_dpl_pipe_shell(gint *out, gint *in, gchar *cmd) {
 2969 gint fd1[2], fd2[2];
 2970 pid_t pid;
 2971 
 2972     if (pipe(fd1) <0 || pipe(fd2) <0) {
 2973         g_error("pipe error\n");
 2974     }
 2975 
 2976     if (( pid = fork()) < 0) {
 2977         g_error("fork error\n");
 2978     } else 
 2979     if (pid > 0) {
 2980         /* parent */
 2981         close(fd1[0]);
 2982         close(fd2[1]);
 2983 
 2984         /* return new stdout/stdin of child */
 2985         if (in != NULL) 
 2986             *in = fd1[1];
 2987         else
 2988             close(fd1[1]);
 2989 
 2990         if (out != NULL)
 2991             *out = fd2[0];
 2992         else
 2993             close(fd2[0]);
 2994 
 2995         dodebug(11, "Created child pid: %d\n", pid); 
 2996     } else {
 2997 
 2998         /* child */
 2999         close(fd1[1]);
 3000         close(fd2[0]);
 3001 
 3002         /* reroute stdin from child */
 3003         if (fd1[0] != STDIN_FILENO) {
 3004             if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
 3005                 g_error("dup2 error on stdin\n");
 3006             }
 3007             close(fd1[0]);
 3008         }
 3009         /* reroute stdout from child */
 3010         if (fd2[1] != STDOUT_FILENO) {
 3011             if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
 3012                 g_error("dup2 error on stdout\n");
 3013             }
 3014             close(fd2[1]);
 3015         }
 3016 
 3017         g_setenv("LC_ALL", "C", TRUE);
 3018 
 3019         /* startup child */
 3020         if (execl("/bin/sh", "sh", "-c", cmd ,(void *)NULL) < 0) {
 3021             g_error("execl error\n");
 3022         }
 3023  
 3024     }
 3025 
 3026     return(pid);
 3027 }
 3028 
 3029 
 3030 /*
 3031  * rebuild a cmdline-string into a list of arguments..handle quotes and
 3032  * escaped chars nicely
 3033  */
 3034 static void rebuild_cmdline(char **arglist, gchar *cmd, gchar *callpath) {
 3035 gchar tmp[MAXLINE*10];
 3036 gchar *p;
 3037 gint n, count, start, in_quotes;
 3038 gchar oldc, c;
 3039 
 3040     n = 0;
 3041     count = 0;
 3042     start = 0;
 3043     in_quotes = 0;
 3044     oldc = '\0';
 3045     for (n = 0; n <= strlen(cmd); n++) {
 3046         c = cmd[n];
 3047         /*
 3048          * quotes found?
 3049          * search for closing quote
 3050          * ignore escaped quotes
 3051          */
 3052         if (c == '\"' && oldc != '\\') {
 3053             if (in_quotes == 0) {
 3054                 in_quotes = 1;
 3055             } else {
 3056                 /* end-quote found */
 3057                 in_quotes = 0;
 3058             }
 3059         }
 3060         oldc = c;
 3061 
 3062         /* space is delimitor between args */
 3063         if (in_quotes == 0 && (c == ' ' || c == '\0')) {
 3064             strncpy(tmp,cmd+start,n-start);
 3065             tmp[n-start] = '\0';
 3066 
 3067             /* skip empty args */
 3068             if (n-start == 0) {
 3069                 continue;
 3070             }
 3071             strip_string(tmp);
 3072             /*
 3073              * tmp does contain now our substr
 3074              * remove surrounding quotes if any
 3075              * and remove any escaped chars
 3076              */
 3077             if (tmp[0] == '\"') {
 3078                 p = tmp + 1;
 3079             } else {
 3080                 p = tmp;
 3081             }
 3082  
 3083             if (tmp[strlen(tmp)-1] == '\"') {
 3084                 tmp[strlen(tmp)-1] = '\0';
 3085             }
 3086             escape_parse(p); 
 3087 
 3088             /* empty unquoted string? skip */
 3089             if (p == tmp && strcmp(p,"") == 0) {
 3090                 continue;
 3091             }
 3092     
 3093             arglist[count] = g_strdup(p);
 3094             count++;
 3095             start = n+1;
 3096         }   
 3097 
 3098         if (count >= MAXPIPEARGS) {
 3099             g_error("Error: More than %d cmd arguments given\n",MAXPIPEARGS);
 3100         }
 3101     }
 3102 
 3103     /* now remove path from first argument */
 3104     strncpy(callpath,arglist[0], MAXLINE);
 3105     strncpy(tmp,arglist[0], MAXLINE*10);
 3106     p = rindex(tmp,'/');
 3107     if (p != NULL) {
 3108         g_free(arglist[0]);
 3109         arglist[0] = g_strdup(p+1);
 3110     }   
 3111 
 3112     /* now arglist is finished */
 3113 
 3114     /* output generated argument-list */
 3115     if (debug) {
 3116         dodebug(11,"----- created argument array for execv -----\n");
 3117         count = 0;
 3118         dodebug(11,":%s:\n",callpath);
 3119         while(arglist[count]) {
 3120             dodebug(11,":%s:\n",arglist[count]);
 3121             count++;
 3122         }
 3123     }
 3124 }
 3125 
 3126 
 3127 
 3128 /*
 3129  * create a bidirectional pipe
 3130  */
 3131 static gint my_s_pipe(gint fd[2], gint use_socketpair) {
 3132 
 3133     if (use_socketpair == 1) {
 3134 #if defined(HAVE_SOCKETPAIR) && HAVE_SOCKETPAIR == 1
 3135         return (socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
 3136 #else
 3137         /* socketpair not available - fallback */
 3138         return (pipe(fd));
 3139 #endif
 3140     } else {
 3141         return (pipe(fd));
 3142     }
 3143 }
 3144 
 3145 
 3146 /*
 3147  * start subprocess and reroute stdin, stderr and stdout
 3148  * does NOT use the shell as spawner
 3149  */
 3150 static pid_t full_dpl_pipe3(gint *out, gint *in, gint *err, gchar *cmd, 
 3151     gint use_socketpair) { 
 3152 gint fd1[2], fd2[2], fd3[2];
 3153 gchar **arglist;
 3154 gchar callpath[MAXLINE];
 3155 pid_t pid;
 3156 gint count;
 3157 
 3158     /* rebuild cmdline to array of args for execv */
 3159     arglist = g_new0(gchar *, MAXPIPEARGS);
 3160     rebuild_cmdline(arglist, cmd, callpath);
 3161 
 3162     /* do the pipe-stuff */
 3163     if (my_s_pipe(fd1, use_socketpair) < 0 || 
 3164         my_s_pipe(fd2, use_socketpair) < 0 || 
 3165         my_s_pipe(fd3, use_socketpair) < 0) {
 3166         g_error("pipe error\n");
 3167     }
 3168 
 3169     if (( pid = fork()) < 0) {
 3170         g_error("fork error\n");
 3171     } else 
 3172     if (pid > 0) {
 3173         /* parent */
 3174         close(fd1[0]);
 3175         close(fd2[1]);
 3176         close(fd3[1]);
 3177 
 3178         /* return new stdout/stdin/stderr of child */
 3179         if (in != NULL) 
 3180             *in = fd1[1];
 3181         else
 3182             close(fd1[1]);
 3183 
 3184         if (out != NULL)
 3185             *out = fd2[0];
 3186         else
 3187             close(fd2[0]);
 3188 
 3189         if (err != NULL)
 3190             *err = fd3[0];
 3191         else 
 3192             close(fd3[0]);
 3193 
 3194         dodebug(11, "Created child pid: %d\n", pid); 
 3195     } else {
 3196 
 3197         /* child */
 3198         close(fd1[1]);
 3199         close(fd2[0]);
 3200         close(fd3[0]);
 3201 
 3202         /* reroute stdin from child */
 3203         if (fd1[0] != STDIN_FILENO) {
 3204             if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
 3205                 g_error("dup2 error on stdin\n");
 3206             }
 3207             close(fd1[0]);
 3208         }
 3209         /* reroute stdout from child */
 3210         if (fd2[1] != STDOUT_FILENO) {
 3211             if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
 3212                 g_error("dup2 error on stdout\n");
 3213             }
 3214             close(fd2[1]);
 3215         }
 3216         /* reroute stderr from child */
 3217         if (fd3[1] != STDERR_FILENO) {
 3218             if (dup2(fd3[1], STDERR_FILENO) != STDERR_FILENO) {
 3219                 g_error("dup2 error on stderr\n");
 3220             }
 3221             close(fd3[1]);
 3222         }
 3223 
 3224         g_setenv("LC_ALL", "C", TRUE);
 3225 
 3226         /* startup child */
 3227         if (execv(callpath,arglist) < 0) {
 3228             g_error("execv error\n");
 3229         }
 3230  
 3231     }
 3232 
 3233     /* free arglist */
 3234     count = 0;
 3235     while(arglist[count]) {
 3236         g_free(arglist[count]);
 3237         count++;
 3238     }
 3239     g_free(arglist);
 3240 
 3241     return(pid);
 3242 }
 3243 
 3244 
 3245 /*
 3246  * start two subprocesses and connect stdout of the first with stdin
 3247  * of the second (proc1 | proc2) and reroute stdin and stderr of the
 3248  * first and stdout and stderr of the second
 3249  * returns pidnr1 and pidnr2
 3250  */
 3251 static void full_dpl_pipe4(pid_t *pidnr1, pid_t *pidnr2, gint *in1, gint *err1, 
 3252             gchar *cmd, gint *out2, gint *err2, gchar *cmd2,
 3253             gint use_socketpair) {
 3254 gint fd1[2], fd2[2], fd3[2], fd4[2], pipefd[2];
 3255 gchar **arglist;
 3256 gchar **arglist2;
 3257 gchar callpath[MAXLINE];
 3258 gchar callpath2[MAXLINE];
 3259 pid_t pid, pid2;
 3260 gint count;
 3261 
 3262     /* rebuild cmdline to array of args for execv */
 3263     arglist = g_new0(gchar *, MAXPIPEARGS);
 3264     arglist2 = g_new0(gchar *, MAXPIPEARGS);
 3265     rebuild_cmdline(arglist, cmd, callpath);
 3266     rebuild_cmdline(arglist2, cmd2, callpath2);
 3267 
 3268     /* do the pipe-stuff */
 3269     if (my_s_pipe(fd1, use_socketpair) < 0 || 
 3270         my_s_pipe(fd2, use_socketpair) < 0 || 
 3271         my_s_pipe(fd3, use_socketpair) < 0 ||
 3272         my_s_pipe(fd4, use_socketpair) < 0 || 
 3273         my_s_pipe(pipefd, use_socketpair) < 0) {
 3274         g_error("pipe error\n");
 3275     }
 3276 
 3277     /* fork for first process */
 3278     if (( pid = fork()) < 0) {
 3279         g_error("fork error\n");
 3280     } else 
 3281     if (pid > 0) {
 3282         /* parent */
 3283         close(fd1[0]);
 3284         close(fd2[1]);
 3285         close(pipefd[1]);
 3286 
 3287         /* return new fds of child */
 3288         if (in1 != NULL) 
 3289             *in1 = fd1[1];
 3290         else
 3291             close(fd1[1]);
 3292 
 3293         if (err1 != NULL)
 3294             *err1 = fd2[0];
 3295         else
 3296             close(fd2[0]);
 3297 
 3298         dodebug(11, "Created child pid: %d\n", pid); 
 3299     } else {
 3300 
 3301         /* child */
 3302         close(fd1[1]); 
 3303         close(fd2[0]);
 3304         close(pipefd[0]);
 3305 
 3306         /* reroute stdin from child */
 3307         if (fd1[0] != STDIN_FILENO) {
 3308             if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
 3309                 g_error("dup2 error on stdin\n");
 3310             }
 3311             close(fd1[0]);
 3312         }
 3313 
 3314         /* reroute stderr from child */
 3315         if (fd2[1] != STDERR_FILENO) {
 3316             if (dup2(fd2[1], STDERR_FILENO) != STDERR_FILENO) {
 3317                 g_error("dup2 error on stderr\n");
 3318             }
 3319             close(fd2[1]);
 3320         }
 3321 
 3322         /* reroute stdout from child to second child */
 3323         if (pipefd[1] != STDOUT_FILENO) {
 3324             if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
 3325                 g_error("dup2 error on stdout\n");
 3326             }
 3327             close(pipefd[1]); 
 3328         } 
 3329 
 3330         g_setenv("LC_ALL", "C", TRUE);
 3331 
 3332         /* startup first child */
 3333         if (execv(callpath,arglist) < 0) {
 3334             g_error("execv error\n");
 3335         }
 3336     }
 3337 
 3338 
 3339     /* fork for second process */
 3340     if (( pid2 = fork()) < 0) {
 3341         g_error("fork error\n");
 3342     } else 
 3343     if (pid2 > 0) {
 3344         /* parent */
 3345         close(fd3[1]);
 3346         close(fd4[1]);
 3347         close(pipefd[0]);
 3348 
 3349         /* return new fds of child */
 3350         if (out2 != NULL)
 3351             *out2 = fd3[0];
 3352         else
 3353             close(fd3[0]);
 3354 
 3355         if (err2 != NULL)
 3356             *err2 = fd4[0];
 3357         else 
 3358             close(fd4[0]);
 3359 
 3360         dodebug(11, "Created second child pid: %d\n", pid2); 
 3361     } else {
 3362 
 3363         /* child */
 3364         close(fd3[0]);
 3365         close(fd4[0]);
 3366         close(pipefd[1]);
 3367 
 3368         /* reroute stdin from first child */
 3369         if (pipefd[0] != STDIN_FILENO) {
 3370             if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
 3371                 g_error("dup2 error on stdin\n");
 3372             }
 3373             close(pipefd[0]); 
 3374         }
 3375 
 3376         /* reroute stderr from child */
 3377         if (fd4[1] != STDERR_FILENO) {
 3378             if (dup2(fd4[1], STDERR_FILENO) != STDERR_FILENO) {
 3379                 g_error("dup2 error on stdout\n");
 3380             }
 3381             close(fd4[1]);
 3382         }
 3383 
 3384         /* reroute stdout from child to second child */
 3385         if (fd3[1] != STDOUT_FILENO) {
 3386             if (dup2(fd3[1], STDOUT_FILENO) != STDOUT_FILENO) {
 3387                 g_error("dup2 error on stdout\n");
 3388             }
 3389             close(fd3[1]);
 3390         }
 3391 
 3392         g_setenv("LC_ALL", "C", TRUE);
 3393 
 3394         /* startup second child */
 3395         if (execv(callpath2,arglist2) < 0) {
 3396             g_error("execv error\n");
 3397         }
 3398     }
 3399 
 3400     /* free arglists */
 3401     count = 0;
 3402     while(arglist[count]) {
 3403         g_free(arglist[count]);
 3404         count++;
 3405     }
 3406     g_free(arglist);
 3407     count = 0;
 3408     while(arglist2[count]) {
 3409         g_free(arglist2[count]);
 3410         count++;
 3411     }
 3412     g_free(arglist2);
 3413 
 3414     /* return pids by call by reference */
 3415     *pidnr1 = pid;
 3416     *pidnr2 = pid2;
 3417 }
 3418 
 3419 
 3420 /*
 3421  * get the master-volume
 3422  * return val 0..100 or -1 or error
 3423  */
 3424 gint query_mixer() {
 3425 #if !(defined(linux))
 3426 gint mix;
 3427 #endif
 3428 #if defined(linux)
 3429 gint err = 0;
 3430 snd_mixer_t *handle = NULL;
 3431 snd_mixer_elem_t *elem;
 3432 snd_mixer_selem_id_t *sid;
 3433 long val, pmin, pmax;
 3434 #endif
 3435 #if defined(__FreeBSD__)
 3436 gint val;
 3437 #endif
 3438 #if defined(sun) || defined(__OpenBSD__)
 3439 audio_info_t ainfo;
 3440 #endif
 3441 #ifdef hpux
 3442 # ifndef hpux_alib
 3443 struct audio_gain again;
 3444 # endif
 3445 #endif
 3446 
 3447     if (strcmp(setupdata.mix_device,"") == 0) {
 3448         /* no mixer found - ignore */
 3449         return -1;
 3450     }
 3451 
 3452 #if defined(linux)
 3453     dodebug(10,"querying mixer '%s'\n", setupdata.mix_device);
 3454     snd_mixer_selem_id_alloca(&sid);
 3455 
 3456     if ((err = snd_mixer_open(&handle, 0)) < 0) {
 3457         g_warning("Mixer %s open error: %s\n", setupdata.mix_device, snd_strerror(err));
 3458         return -1;
 3459     }
 3460 
 3461     if ((err = snd_mixer_attach(handle, setupdata.mix_device)) < 0) {
 3462         g_warning("Mixer attach %s error: %s", setupdata.mix_device, snd_strerror(err));    
 3463         snd_mixer_close(handle);
 3464         return -1;
 3465     }
 3466 
 3467     if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
 3468         g_warning("Mixer register error: %s", snd_strerror(err));
 3469         snd_mixer_close(handle);
 3470         return -1;
 3471     }
 3472 
 3473     if ((err = snd_mixer_load(handle)) < 0) {
 3474         g_warning("Mixer %s load error: %s", setupdata.mix_device, snd_strerror(err));
 3475         snd_mixer_close(handle);
 3476         return -1;
 3477     }
 3478 
 3479     /* use first found mixer control */
 3480     elem = snd_mixer_first_elem(handle);
 3481     if (!elem) {
 3482         g_warning("Unable to find a simple control for this device");
 3483         snd_mixer_close(handle);
 3484         handle = NULL;
 3485         return -1;
 3486     } else {
 3487         snd_mixer_selem_get_id(elem, sid);
 3488         dodebug(10, "Using simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
 3489     }   
 3490 
 3491     if ((err = snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax)) < 0) {
 3492         g_warning("Failed to get playback volume range: %s", snd_strerror(err));
 3493         snd_mixer_close(handle);
 3494         return -1;
 3495     }
 3496 
 3497     if ((err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &val)) < 0) {
 3498         g_warning("Failed to get playback volume: %s", snd_strerror(err));
 3499         snd_mixer_close(handle);
 3500         return -1;
 3501     }
 3502 
 3503     snd_mixer_close(handle);
 3504 
 3505     return (gint)(100*val/(pmax-pmin)); 
 3506 
 3507 #endif
 3508 
 3509 #if defined(__FreeBSD__)
 3510 
 3511     dodebug(10,"querying mixer %s\n", setupdata.mix_device);
 3512     mix = open(setupdata.mix_device, O_RDWR);
 3513     if (mix < 0) {
 3514         g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3515         return -1;
 3516     }
 3517 
 3518     if (ioctl(mix,MIXER_READ(0),&val) == -1) {
 3519         g_warning("Error reading mixer\n");
 3520         return -1;
 3521     }   
 3522 
 3523     close(mix);
 3524 
 3525     /* average val of both channels */
 3526     return ((val & 0x7f) + ((val >> 8) & 0x7f))/2;
 3527 
 3528 #endif
 3529 #if defined(sun) || defined(__OpenBSD__)
 3530 
 3531     dodebug(10,"querying mixer %s\n", setupdata.mix_device);
 3532     mix = open(setupdata.mix_device, O_RDONLY);
 3533     if (mix < 0) {
 3534         g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3535         return -1;
 3536     }
 3537 
 3538     if (ioctl(mix, AUDIO_GETINFO, &ainfo) == -1) {
 3539         g_warning("Error reading mixer\n");
 3540         return -1;
 3541     }
 3542 
 3543     close(mix);
 3544 
 3545     return ((gint) ((gfloat) ainfo.play.gain / 2.55));
 3546 
 3547 #endif
 3548 #ifdef aix
 3549     /*
 3550      * Due to we are using the raw aix audio api,
 3551      * we are not able to query the gain settings :-(
 3552      * set the gain to the max. value and return 100
 3553      */
 3554     memset ( & achange, '\0', sizeof (achange));
 3555     memset ( & acontrol, '\0', sizeof (acontrol));
 3556 
 3557     /* Initialise with the max gain =2147418112      */
 3558     achange.balance        = 0x3fff0000;
 3559     achange.balance_delay  = 0;
 3560     achange.volume         = 2147418112;
 3561     achange.volume_delay   = 0;
 3562     achange.input          = AUDIO_IGNORE;
 3563     achange.output         = AUDIO_IGNORE;
 3564     achange.output         = AUDIO_IGNORE;
 3565     achange.treble         = AUDIO_IGNORE;
 3566     achange.bass           = AUDIO_IGNORE;
 3567     achange.pitch          = AUDIO_IGNORE;
 3568     achange.monitor        = AUDIO_IGNORE;
 3569     achange.dev_info       = (char *) NULL;
 3570     acontrol.ioctl_request = AUDIO_CHANGE;
 3571     acontrol.position      = 0;
 3572     acontrol.request_info  = (char *) & achange;
 3573 
 3574     if ((mix = open(setupdata.mix_device, O_RDONLY)) == -1) {
 3575         g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3576         return -1;
 3577         }
 3578     if (ioctl (mix, AUDIO_CONTROL, & acontrol) == -1) {
 3579         g_warning("Error reading mixer\n");
 3580         return -1;
 3581     }
 3582     close(mix);
 3583 
 3584     return (100);
 3585 #endif
 3586 #ifdef hpux
 3587 # ifndef hpux_alib
 3588     dodebug(10,"querying mixer %s\n", setupdata.mix_device);
 3589     if ((mix = open(setupdata.mix_device, O_RDONLY)) == -1) {
 3590         g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3591         return -1;
 3592     }
 3593     if (ioctl(mix, AUDIO_GET_GAINS, &again) == -1) {
 3594         g_warning("Error reading mixer\n");
 3595         return -1;
 3596     }
 3597     close(mix);
 3598     return ((gint) ((gfloat) (again.transmit_gain - AUDIO_OFF_GAIN)
 3599             / (gfloat) (AUDIO_MAX_GAIN - AUDIO_OFF_GAIN) * 100.0));
 3600 # else
 3601     /*
 3602      * The audio transmission gains are set by some
 3603      * environment variables or a fancy program
 3604      * like the AudioCP
 3605      */
 3606     return (0);
 3607 # endif
 3608 #endif
 3609 
 3610     return 0;
 3611 }
 3612 
 3613 
 3614 /*
 3615  * set the master-volume
 3616  * returns 0 on ok, -1 on error
 3617  */
 3618 gint set_mixer(gint val) {
 3619 #if !(defined(linux))
 3620 gint mix;
 3621 #endif
 3622 #if defined(linux)
 3623 gint err = 0;
 3624 snd_mixer_t *handle = NULL;
 3625 snd_mixer_elem_t *elem;
 3626 snd_mixer_selem_id_t *sid;
 3627 long sval, pmin, pmax;
 3628 #endif
 3629 #if defined(sun) || defined(__OpenBSD__)
 3630 audio_info_t ainfo;
 3631 #endif
 3632 #ifdef aix
 3633 audio_change   achange;
 3634 audio_control  acontrol;
 3635 #endif
 3636 #ifdef hpux
 3637 # ifndef hpux_alib
 3638 struct audio_gain again;
 3639 # endif
 3640 #endif
 3641 
 3642     if (strcmp(setupdata.mix_device,"") == 0) {
 3643         /* no mixer found - ignore */
 3644         return -1;
 3645     }
 3646 
 3647 #if defined(linux)
 3648     dodebug(10,"setting mixer '%s' to %d\n", setupdata.mix_device, val);
 3649     snd_mixer_selem_id_alloca(&sid);
 3650 
 3651     if ((err = snd_mixer_open(&handle, 0)) < 0) {
 3652         g_warning("Mixer %s open error: %s\n", setupdata.mix_device, snd_strerror(err));
 3653         return -1;
 3654     }
 3655 
 3656     if ((err = snd_mixer_attach(handle, setupdata.mix_device)) < 0) {
 3657         g_warning("Mixer attach %s error: %s", setupdata.mix_device, snd_strerror(err));    
 3658         snd_mixer_close(handle);
 3659         return -1;
 3660     }
 3661 
 3662     if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
 3663         g_warning("Mixer register error: %s", snd_strerror(err));
 3664         snd_mixer_close(handle);
 3665         return -1;
 3666     }
 3667 
 3668     if ((err = snd_mixer_load(handle)) < 0) {
 3669         g_warning("Mixer %s load error: %s", setupdata.mix_device, snd_strerror(err));
 3670         snd_mixer_close(handle);
 3671         return -1;
 3672     }
 3673 
 3674     /* use first found mixer control */
 3675     elem = snd_mixer_first_elem(handle);
 3676     if (!elem) {
 3677         g_warning("Unable to find a simple control for this device");
 3678         snd_mixer_close(handle);
 3679         handle = NULL;
 3680         return -1;
 3681     } else {
 3682         snd_mixer_selem_get_id(elem, sid);
 3683     }   
 3684 
 3685     if ((err = snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax)) < 0) {
 3686         g_warning("Failed to get playback volume range: %s", snd_strerror(err));
 3687         snd_mixer_close(handle);
 3688         return -1;
 3689     }
 3690 
 3691     sval = val*(pmax-pmin)/100;
 3692     if ((err = snd_mixer_selem_set_playback_volume_all(elem, sval)) < 0) {
 3693         g_warning("Failed to set playback volume: %s", snd_strerror(err));
 3694         snd_mixer_close(handle);
 3695         return -1;
 3696     }
 3697 
 3698     snd_mixer_close(handle);
 3699 
 3700     return 0;
 3701 #endif
 3702 
 3703 #if defined(__FreeBSD__)
 3704 
 3705     dodebug(10,"setting mixer %s to %d\n", setupdata.mix_device, val);
 3706     mix = open(setupdata.mix_device, O_RDWR);
 3707     if (mix < 0) {
 3708         g_warning("Can't open mixer-device\n");
 3709         return -1;
 3710     }
 3711 
 3712     val |= val << 8;
 3713     if (ioctl(mix, MIXER_WRITE(0), &val) == -1) {
 3714         g_warning("Error writing mixer\n");
 3715         return -1;
 3716     }
 3717 
 3718     close(mix);
 3719 
 3720 #endif 
 3721 #if defined(sun) || defined(__OpenBSD__)
 3722 
 3723     dodebug(10,"setting mixer %s to %d\n", setupdata.mix_device, val);
 3724     mix = open(setupdata.mix_device, O_WRONLY);
 3725     if (mix < 0) {
 3726         g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3727         return -1;
 3728     }
 3729 
 3730     AUDIO_INITINFO(&ainfo);
 3731     ainfo.play.gain = (gint) (2.55 * (gfloat) val);
 3732 
 3733     if (ioctl(mix, AUDIO_SETINFO, &ainfo) == -1) {
 3734         g_warning("Error writing mixer\n");
 3735         return -1;
 3736     }
 3737 
 3738     close(mix);
 3739 #endif
 3740 #ifdef aix
 3741        memset ( & achange, '\0', sizeof (achange));
 3742        memset ( & acontrol, '\0', sizeof (acontrol));
 3743 
 3744        /* Initialise with the max gain =2147418112      */
 3745        achange.balance        = AUDIO_IGNORE;
 3746        achange.balance_delay  = AUDIO_IGNORE;
 3747        achange.volume         = (long) (21474181.12 * (gfloat) val);
 3748        achange.volume_delay   = 0;
 3749        achange.input          = AUDIO_IGNORE;
 3750        achange.output         = AUDIO_IGNORE;
 3751        achange.output         = AUDIO_IGNORE;
 3752        achange.treble         = AUDIO_IGNORE;
 3753        achange.bass           = AUDIO_IGNORE;
 3754        achange.pitch          = AUDIO_IGNORE;
 3755        achange.monitor        = AUDIO_IGNORE;
 3756        achange.dev_info       = (char *) NULL;
 3757        acontrol.ioctl_request = AUDIO_CHANGE;
 3758        acontrol.position      = 0;
 3759        acontrol.request_info  = (char *) & achange;
 3760 
 3761        if ((mix = open(setupdata.mix_device, O_RDONLY)) == -1) {
 3762                 g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3763                 return -1;
 3764         }
 3765        if (ioctl (mix, AUDIO_CONTROL, & acontrol) == -1) {
 3766                g_warning("Error reading mixer\n");
 3767                return -1;
 3768        }
 3769        close (mix);
 3770 #endif
 3771 #ifdef hpux
 3772 # ifndef hpux_alib
 3773         dodebug(10,"setting mixer %s to %d\n", setupdata.mix_device, val);
 3774     if ((mix = open(setupdata.mix_device, O_RDWR)) == -1) {
 3775                 g_warning("Can't open mixer-device %s\n", setupdata.mix_device);
 3776                 return -1;
 3777         }
 3778     /* Query the receive/transmit/monitor gains */
 3779     again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
 3780     ioctl(mix,AUDIO_GET_GAINS,&again);
 3781 
 3782     /* Calculate the new transmit gain */
 3783     again.cgain[0].transmit_gain = AUDIO_OFF_GAIN 
 3784             + (gfloat) ((AUDIO_MAX_GAIN - AUDIO_OFF_GAIN) * val) * 0.01;
 3785     again.cgain[1].transmit_gain = again.cgain[0].transmit_gain;
 3786     again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
 3787 
 3788     /* Set the new gains (only transmit gain actually changed) */
 3789     if (ioctl(mix, AUDIO_SET_GAINS, &again) == -1) {
 3790             g_warning("Error setting audio gain\n");
 3791                 return -1;
 3792     }
 3793     close(mix);
 3794 # else
 3795     /*
 3796      * The audio transmission gains are set by some
 3797      * environment variables or a fancy program
 3798      * like the AudioCP
 3799      */
 3800     return 0;
 3801 # endif
 3802 #endif
 3803 
 3804     return 0;   
 3805 }
 3806 
 3807 
 3808 /*
 3809  * send SIGINT to a cdda2wav/readcd/cdrecord process (resp. to its child) 
 3810  * and hope that it terminates at it own
 3811  */
 3812 void kill_readcdda() {
 3813 
 3814     /* stop any timers watching for cdrecord output */
 3815     if (cdrtimer) {
 3816         g_source_remove(cdrtimer);
 3817         cdrtimer = 0;
 3818     }
 3819 
 3820     if (readcdda_pid != -1) {
 3821 
 3822         dodebug(2,"sending SIGINT to %d\n", (gint) readcdda_pid);
 3823         kill(readcdda_pid, SIGINT);
 3824     }
 3825     if (readcdda_pid2 != -1) {
 3826 
 3827         dodebug(2,"sending SIGINT to %d\n", (gint) readcdda_pid2);
 3828         kill(readcdda_pid2, SIGINT);
 3829     }
 3830 }
 3831 
 3832 
 3833 /*
 3834  * in bulk mode update the info-label of read tracks
 3835  */
 3836 static void update_bulk_readlabel() {
 3837 gchar tmp[MAXLINE];
 3838 gchar tmp2[MAXLINE];
 3839 gint frms;
 3840 
 3841     frms = writeparams.frames[read_tracknr];
 3842     convert_frames2mbminstring(frms, tmp);
 3843     g_snprintf(tmp2,MAXLINE,_("Reading audio track %d/%d [%s]"), read_tracknr,
 3844             writeparams.nrtracks, tmp);
 3845     gtk_label_set_text(GTK_LABEL(readtrack_info_label), tmp2);
 3846 }
 3847 
 3848 
 3849 /*
 3850  * parse output of cdda2wav and update sliders
 3851  */
 3852 static gboolean read_cdda2wav_out_io_in(GIOChannel *source, GIOCondition cond, gpointer data) {
 3853 gchar line[MAXLINE];
 3854 gchar tmp[MAXLINE];
 3855 gchar tmp2[MAXLINE];
 3856 gchar convtmp[MAXLINE];
 3857 gchar *p;
 3858 gint val, tnr, bulk;
 3859 gfloat pval, pval2;
 3860 
 3861     /* called for bulk or not? */
 3862     bulk = GPOINTER_TO_INT(data);
 3863 
 3864     /* read output of cdda */
 3865     read_io_channel(source, line, MAXLINE);
 3866 
 3867     /* nothing read - nonblock */
 3868     if (strcmp(line, "") == 0) {
 3869         wait_and_process_events();
 3870         return (TRUE);
 3871     }
 3872 
 3873     strip_string(line);
 3874     dodebug(10,"cdda2wav: %s\n", line);
 3875 
 3876     /* scanning for indexes? */
 3877     if (strncmp(line,"index scan:", 11) == 0) {
 3878         strcpy(tmp,line+11);
 3879         p = strtok(tmp,".");
 3880         if (p != NULL) {
 3881             tnr = atoi(p);
 3882         } else {
 3883             tnr = 0;
 3884         }
 3885         g_snprintf(tmp,MAXLINE,_("Scanning track %d for indices..."),tnr);
 3886         gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
 3887     }
 3888 
 3889     /* found indices? */
 3890     if (strncmp(line,"track", 5) == 0) {
 3891         strcpy(tmp,line);
 3892         /* just output until first comma - looks nicer */
 3893         p = strtok(tmp,",");
 3894         if (p != NULL) {
 3895             strcpy(tmp2,p);
 3896         } else {
 3897             strcpy(tmp2,tmp);
 3898         }   
 3899         strcat(tmp2,"\n");
 3900         append_to_text_view(readtrack_textview, tmp2);
 3901     }
 3902 
 3903     /* scanning for MCN? */
 3904     if (strncmp(line,"scanning for MCN", 16) == 0) {
 3905         gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Scanning for MCN (Media Catalog Number)..."));    
 3906     }   
 3907 
 3908     /* scanning for ISRC? */
 3909     if (strncmp(line,"scanning for ISRCs:", 19) == 0) {
 3910         strcpy(tmp,line+20);
 3911         p = strtok(tmp,".");
 3912         if (p != NULL) {
 3913             tnr = atoi(p);
 3914         } else {
 3915             tnr = 0;
 3916         }
 3917         g_snprintf(tmp,MAXLINE,_("Scanning track %d for ISRC..."),tnr);
 3918         gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
 3919     }
 3920     
 3921     /* done with scanning? */
 3922     if (strncmp(line,"recording", 9) == 0) {
 3923         if (bulk == 0) {
 3924             /* restore original info text */
 3925             gtk_label_set_text(GTK_LABEL(readtrack_info_label),
 3926                 readtrack_info_string); 
 3927         } else {
 3928             update_bulk_readlabel();
 3929         }
 3930     }
 3931 
 3932     /* look for a percent value */
 3933     if (line[strlen(line)-1] == '%') {
 3934         /* skip leading linefeed if any */
 3935         if (line[0] == '\r') 
 3936             line[0] = ' ';
 3937     
 3938         /* look for last space */
 3939         p = rindex(line,' ');
 3940         if (p != NULL) 
 3941             strcpy(tmp,p);
 3942         else 
 3943             strcpy(tmp,line);
 3944 
 3945         tmp[strlen(tmp)-1] = '\0';  
 3946         strip_string(tmp);
 3947         val = atoi(tmp);
 3948         pval = (gfloat)val/100;
 3949         if (pval > 1.0) pval = 1.0;
 3950         gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1),
 3951             pval);
 3952 
 3953         /* now calculate how much percent he have at all */
 3954         if (bulk == 0) {
 3955             pval2 = (pct_so_far + (pval * pct_this_track)) /100;
 3956             if (pval2 > 1.0) pval2 = 1.0;
 3957         } else {
 3958             pval2 = (writeparams.pct_so_far_arr[read_tracknr] +
 3959                 (pval * writeparams.pct_this_track_arr[read_tracknr]))/100;
 3960         }
 3961     
 3962         gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar2),
 3963             pval2);
 3964         set_xcdr_title(toplevel, viewmode_dialog, (gint)(pval2*100+0.5));
 3965 
 3966         /* now update info for small view */
 3967         g_snprintf(tmp,MAXLINE,"%d%% / %d%%",(gint)(pval*100+0.5),
 3968                (gint)(pval2*100+0.5));
 3969         gtk_label_set_text(GTK_LABEL(readtrack_small_info2),tmp);   
 3970         
 3971         return (TRUE);
 3972     }
 3973 
 3974     /* track recorded successfully or maybe with problems? */
 3975     if (strstr(line,"recorded ")) {
 3976         p = strstr(line,"100%  track ");
 3977         if (p != NULL) {
 3978             gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1), 1.0);
 3979             strcpy(tmp,p+6);    /* +6 = offset for '100%  ' */
 3980             strcpy(line,tmp);   
 3981 
 3982             if (bulk == 1) {
 3983                 /* in bulkmode this means we have to switch to next track */
 3984                 read_tracknr++;
 3985                 update_bulk_readlabel();
 3986             }   
 3987         }
 3988     }
 3989         
 3990     /* get subprocess pid */
 3991     if (strncmp(line,"child pid", 9) == 0) {
 3992         strcpy(tmp, line+12);
 3993         readcdda_pid= (pid_t) atoi(tmp);
 3994         return (TRUE);
 3995     }   
 3996     
 3997     /* error-text? do display these in the next block */
 3998     if (strncmp(line,"Error",5) == 0 || strstr(line,"open audio sample file") != NULL) {
 3999         read_output_ctrl = 1;
 4000     }   
 4001 
 4002     /* forward most other output to textview-window */
 4003     if (strncmp(line,"record",6) == 0 || read_output_ctrl == 1) {
 4004         read_output_ctrl = 1;
 4005         /* skip lines that do not interest us */
 4006         if (strncmp(line,"percent_done",12) == 0) {
 4007             return (TRUE);
 4008         }
 4009         if (strncmp(line,"overlap:min",11) == 0) {
 4010             return (TRUE);
 4011         }
 4012         p = strstr(line,"100%  ");
 4013         if (p != NULL) {
 4014             strcpy(tmp, p+6);   /* +6 = offset for '100%  ' */
 4015             strcpy(line, tmp);  
 4016         }
 4017         strcat(line,"\n");
 4018 
 4019         if (charset_convert_to_utf8(line, convtmp))
 4020             strncpy(line, convtmp, MAXLINE);
 4021 
 4022         append_to_text_view(readtrack_textview, line);
 4023     }   
 4024 
 4025     return (TRUE);
 4026 }
 4027 
 4028 static gboolean read_cdda2wav_out(GIOChannel *source, GIOCondition cond, gpointer data) {
 4029 gchar line[MAXLINE];
 4030 
 4031     if (cond & G_IO_IN) {
 4032             
 4033             read_cdda2wav_out_io_in(source, cond, data);
 4034         }
 4035 
 4036     if ((cond & G_IO_IN) && (cond & G_IO_HUP)) {
 4037                 read_io_channel_all(source, line, MAXLINE);
 4038         if (strcmp(line, "") == 0) {
 4039             cond = G_IO_HUP;
 4040         } else {
 4041             append_multiline_to_textview(line, "100%  ", readtrack_textview, "cdda2wav-hup");
 4042         }
 4043         }
 4044 
 4045     /* cdda-finished? */
 4046     if (cond == G_IO_HUP) {
 4047 
 4048         /* tell our caller that we are done here */
 4049         read_done = get_wait_ret(-1);
 4050         return (FALSE);
 4051     }
 4052     return (TRUE);
 4053 }
 4054 
 4055 /*
 4056  * parse dummy output of cdda2wav
 4057  * output stdout of cdda2wav where never should any data be delivered
 4058  */
 4059 static gboolean read_cdda2wav_dummyout(GIOChannel *source, GIOCondition cond, gpointer data) {
 4060 gchar line[MAXLINE];
 4061 
 4062     /* read output of cdda */
 4063     read_io_channel_all(source, line, MAXLINE);
 4064 
 4065     strcat(line,"\n");
 4066     append_to_text_view(readtrack_textview, line);
 4067 
 4068     return (TRUE);
 4069 }
 4070 
 4071 
 4072 /*
 4073  * call cdda2wav to read an audio-track 
 4074  * return 0 on success, 1 on error
 4075  */
 4076 gint read_audio_track(gint devnr, gint starttrack, gint endtrack, gint kbyte, 
 4077               gchar *fname, gint startoffset, gint endoffset,
 4078               gint nrtracks, gfloat percent, gfloat percent_done,
 4079               gint viewtrack) {
 4080 gchar cmd[MAXLINE];
 4081 gchar tmp[MAXLINE];
 4082 gchar tmp2[MAXLINE];
 4083 gchar tmp3[MAXLINE];
 4084 gchar tmp4[MAXLINE];
 4085 gchar tmp5[MAXLINE];
 4086 gchar tmp6[MAXLINE];
 4087 gchar tmp8[MAXLINE];
 4088 gchar tmp9[MAXLINE];
 4089 gchar tmpfname[MAXLINE];
 4090 gint read_in, read_out, read_dummy;
 4091 GIOChannel *gio, *gio2;
 4092 
 4093     /* if another read running, ignore */
 4094     if (read_done == 999) {
 4095         return -1;
 4096     }
 4097 
 4098     /* no filename given? */
 4099     if (fname == NULL) {
 4100         return 1;
 4101     }
 4102     strncpy(tmpfname, fname, MAXLINE);
 4103 
 4104     /* mark our read-process as running */
 4105     read_done = 999;
 4106     read_output_ctrl = 0;
 4107     readcdda_pid = -1;
 4108     readcdda_pid2 = -1;
 4109     read_abort_mark = 0;
 4110 
 4111     /* set info-label */
 4112     convert_kbytes2mbminstring(kbyte, tmp);
 4113     g_snprintf(tmp2,MAXLINE,_("Reading audio track %d/%d [%s]"), viewtrack, nrtracks, tmp);
 4114     gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   
 4115     strcpy(readtrack_info_string, tmp2);
 4116 
 4117     g_snprintf(tmp2,MAXLINE,_("Reading %d/%d:"), viewtrack, nrtracks);
 4118     gtk_label_set_text(GTK_LABEL(readtrack_small_info),tmp2);   
 4119     
 4120     /* get bus,id,lun string */
 4121     if (convert_devnr2busid(devnr,tmp) != 0) {
 4122         g_error("non existing cdrom?");
 4123     }
 4124 
 4125     /* some stuff to have our slider moving smoothly no matter how
 4126        big the tracks are */
 4127     pct_so_far = percent_done;
 4128     pct_this_track = percent;
 4129 
 4130     /* build command line */
 4131     if (endtrack != 0) {
 4132         g_snprintf(tmp2,MAXLINE,"%d+%d",starttrack,endtrack);
 4133     } else {
 4134         g_snprintf(tmp2,MAXLINE,"%d",starttrack);
 4135     }
 4136 
 4137     /* set speed only when not zero */
 4138     if (get_cur_audioread_speed() > 0) {
 4139         g_snprintf(tmp3,MAXLINE,"-S %d", get_cur_audioread_speed()); 
 4140     } else {
 4141         strcpy(tmp3,"");
 4142     }
 4143 
 4144     /* have to scan for indexes? */
 4145     if (curset.indexscan) {
 4146         strcpy(tmp4,"-i 1 -v all");
 4147     } else {
 4148         strcpy(tmp4,"-v toc,summary,sectors,titles");
 4149     }
 4150 
 4151     /* have to deemphasize? */
 4152     if (curset.deemphasize) {
 4153         strcpy(tmp9,"-deemphasize");
 4154     } else {
 4155         strcpy(tmp9,"");
 4156     }
 4157 
 4158     /* set paranoia options */
 4159     if (get_cur_audioread_useparanoia() && (get_cur_audioread_paranoiaminoverlap() < 1)) {
 4160         g_snprintf(tmp6, MAXLINE, "paraopts=retries=%d,readahead=%d",
 4161                get_cur_audioread_paranoiaretries(),get_cur_audioread_paranoiareadahead());
 4162     } else if (get_cur_audioread_useparanoia()) {
 4163         g_snprintf(tmp6, MAXLINE, "paraopts=retries=%d,readahead=%d,minoverlap=%d",
 4164                get_cur_audioread_paranoiaretries(),get_cur_audioread_paranoiareadahead(),get_cur_audioread_paranoiaminoverlap());
 4165     } else {
 4166         g_snprintf(tmp6, MAXLINE, "-P %d", get_cur_audioread_overlap());
 4167     }
 4168 
 4169     /* have to enable -no-hidden-track? */
 4170     if (get_cur_audioread_showhiddentrack()) {
 4171         strcpy(tmp8,"");
 4172     } else {
 4173         strcpy(tmp8,"-no-hidden-track");
 4174     }
 4175 
 4176     get_wrap_path("CDDA2WAV", tmp5);
 4177     g_snprintf(cmd,MAXLINE,
 4178            "%s -D \"%s\" -g -no-textfile -O wav -t %s %s %s %s %s %s \"%s\"",
 4179            tmp5,tmp,tmp2,tmp3,tmp4,tmp6,tmp8,tmp9,
 4180            convert_escape(tmpfname));
 4181 
 4182     dodebug(1, "spawning: %s\n",cmd);
 4183     dolog(2,"Read audio track %s\n", fname);
 4184     dolog(3,"Executing: %s\n",cmd);
 4185 
 4186     /* start child and get new fds */
 4187     readcdda_pid = full_dpl_pipe3(&read_dummy,&read_in,&read_out,cmd,0);
 4188     readcdda_pid2 = -1;
 4189 
 4190     /* catch output of child */
 4191     gio = g_io_channel_unix_new(read_out);
 4192     g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
 4193     g_io_channel_set_encoding(gio, NULL, NULL); 
 4194         readcdda_callback = g_io_add_watch(gio, G_IO_IN | G_IO_HUP,
 4195                 read_cdda2wav_out, GINT_TO_POINTER(0));
 4196 
 4197     gio2 = g_io_channel_unix_new(read_dummy);
 4198     g_io_channel_set_encoding(gio2, NULL, NULL); 
 4199         readcdda_callback2 = g_io_add_watch(gio2, G_IO_IN,
 4200                 read_cdda2wav_dummyout, NULL);
 4201 
 4202     /* now wait until track is read */
 4203     while (read_done == 999) {
 4204         wait_and_process_events();
 4205     }
 4206 
 4207     g_source_remove(readcdda_callback2);
 4208     g_io_channel_unref(gio);
 4209     g_io_channel_unref(gio2);
 4210 
 4211     close(read_out);
 4212     close(read_in);
 4213     close(read_dummy);
 4214 
 4215     append_to_text_view(readtrack_textview, "\n");
 4216 
 4217     /* error while reading? */
 4218     if (read_done != 0 && read_abort_mark == 0) {
 4219         g_snprintf(tmp,MAXLINE,_("Error reading audio track %d/%d"), starttrack, nrtracks);
 4220         gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
 4221         gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Read-Error:"));   
 4222         return 1;
 4223     }
 4224     /* aborted? */
 4225     if (read_abort_mark == 1) {
 4226         gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Read aborted..."));   
 4227         return 1;
 4228     }
 4229 
 4230     return 0;
 4231 }
 4232 
 4233 
 4234 /*
 4235  * call cdda2wav to read all audio tracks from a cd
 4236  */
 4237 gint start_bulk_read_action(gint devnr, gfloat percent_done, gint startnr) {
 4238 GList *loop;
 4239 track_read_param_t *trackparam;
 4240 char tmp[MAXLINE];
 4241 char tmptmp[MAXLINE];
 4242 char tmp3[MAXLINE];
 4243 char tmp4[MAXLINE];
 4244 char tmp5[MAXLINE];
 4245 char tmp6[MAXLINE];
 4246 char tmp8[MAXLINE];
 4247 char tmp9[MAXLINE];
 4248 char cmd[MAXLINE*10];  /* extra big buffer for very long cdrecord options */
 4249 gint read_in, read_out, read_dummy;
 4250 gint tracknr;
 4251 GIOChannel *gio, *gio2;
 4252 
 4253         /* if another read running, ignore */
 4254         if (read_done == 999) {
 4255                 return -1;
 4256         }
 4257 
 4258         /* mark our read-process as running */
 4259         read_done = 999;
 4260         read_output_ctrl = 0;
 4261     pct_so_far = percent_done;
 4262     read_tracknr = startnr;
 4263         readcdda_pid = -1;
 4264     readcdda_pid2 = -1;
 4265         read_abort_mark = 0;
 4266 
 4267     /* init track-label */
 4268     gtk_label_set_text(GTK_LABEL(readtrack_info_label), _("Initializing Disc Reader..."));
 4269     strcpy(readtrack_info_string, "");
 4270 
 4271         /* reset writeparams-arrays */
 4272     /* let's reuse this structure - even when we just read now */
 4273         g_free(writeparams.tracktype);
 4274         g_free(writeparams.frames);
 4275         g_free(writeparams.pct_so_far_arr);
 4276         g_free(writeparams.pct_this_track_arr);
 4277         writeparams.tracktype = g_new0(gint,MAXTRACKS);
 4278         writeparams.frames = g_new0(gint,MAXTRACKS);
 4279         writeparams.pct_so_far_arr = g_new0(gfloat,MAXTRACKS);
 4280         writeparams.pct_this_track_arr = g_new0(gfloat,MAXTRACKS);
 4281         writeparams.nrtracks = 0;
 4282         writeparams.simulation = curset.writesimul;
 4283 
 4284         /* get bus,id,lun string */
 4285         if (convert_devnr2busid(devnr,tmp) != 0) {
 4286                 g_error("non existing cdrom?");
 4287         }
 4288 
 4289         /* set speed only when not zero */
 4290         if (get_cur_audioread_speed() > 0) {
 4291                 g_snprintf(tmp3,MAXLINE,"-S %d", get_cur_audioread_speed()); 
 4292         } else {
 4293                 strcpy(tmp3,"");
 4294         }
 4295 
 4296         /* have to scan for indexes? */
 4297         if (curset.indexscan) {
 4298                 strcpy(tmp4,"-v all");
 4299         } else {
 4300                 strcpy(tmp4,"-v toc,summary,sectors,titles");
 4301         }
 4302 
 4303         /* have to deemphasize? */
 4304         if (curset.deemphasize) {
 4305                 strcpy(tmp9,"-deemphasize");
 4306         } else {
 4307                 strcpy(tmp9,"");
 4308         }
 4309 
 4310     /* set paranoia options */
 4311     if (get_cur_audioread_useparanoia() && (get_cur_audioread_paranoiaminoverlap() < 1)) {
 4312         g_snprintf(tmp6, MAXLINE, "paraopts=retries=%d,readahead=%d",
 4313                get_cur_audioread_paranoiaretries(),get_cur_audioread_paranoiareadahead());
 4314     } else if (get_cur_audioread_useparanoia()) {
 4315         g_snprintf(tmp6, MAXLINE, "paraopts=retries=%d,readahead=%d,minoverlap=%d",
 4316                get_cur_audioread_paranoiaretries(),get_cur_audioread_paranoiareadahead(),get_cur_audioread_paranoiaminoverlap());
 4317     } else {
 4318         g_snprintf(tmp6, MAXLINE, "-P %d", get_cur_audioread_overlap());
 4319     }
 4320 
 4321     /* have to enable -no-hidden-track? */
 4322     if (get_cur_audioread_showhiddentrack()) {
 4323         strcpy(tmp8,"");
 4324     } else {
 4325         strcpy(tmp8,"-no-hidden-track");
 4326     }
 4327 
 4328     get_wrap_path("CDDA2WAV", tmp5);
 4329     g_snprintf(cmd,MAXLINE,
 4330            "%s -D \"%s\" -g -no-textfile -O wav %s %s %s %s %s -B",
 4331            tmp5,tmp,tmp3,tmp4,tmp6,tmp8,tmp9);
 4332 
 4333     tracknr = startnr;
 4334     /* now add all track-filenames (only audio) */
 4335         loop = g_list_first(trackreadset.trackparams);
 4336         while(loop) {
 4337                 trackparam = loop->data;
 4338                 if (trackparam->trackfile != NULL && 
 4339                 trackparam->tracktype == 1) {
 4340             strcpy(tmptmp, trackparam->trackfile);
 4341                         g_snprintf(tmp, MAXLINE, " \"%s\"",
 4342                                 convert_escape(tmptmp));
 4343                         strcat(cmd, tmp);
 4344 
 4345             /* fill up percent values for percentbar */
 4346             writeparams.tracktype[tracknr] = trackparam->tracktype;
 4347             writeparams.frames[tracknr] = trackparam->frames;
 4348             writeparams.pct_this_track_arr[tracknr] = trackparam->percent;
 4349             writeparams.pct_so_far_arr[tracknr] = pct_so_far;
 4350             pct_so_far += trackparam->percent;
 4351             writeparams.nrtracks++;
 4352             tracknr++;
 4353 
 4354                 }
 4355                 loop = loop->next;
 4356         }
 4357     /* correct full nr of tracks (so we have the full count of tracks) */
 4358     writeparams.nrtracks+=startnr-1;
 4359 
 4360         dodebug(1, "spawning: %s\n",cmd);
 4361         dolog(2,"Read all audio tracks\n");
 4362         dolog(3,"Executing: %s\n",cmd);
 4363 
 4364         /* start child and get new fds */
 4365         readcdda_pid = full_dpl_pipe3(&read_dummy,&read_in,&read_out,cmd,0);
 4366     readcdda_pid2 = -1;
 4367 
 4368         /* catch output of child */
 4369     gio = g_io_channel_unix_new(read_out);
 4370     g_io_channel_set_encoding(gio, NULL, NULL); 
 4371     g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
 4372         readcdda_callback = g_io_add_watch(gio, G_IO_IN | G_IO_HUP,
 4373                 read_cdda2wav_out, GINT_TO_POINTER(1));
 4374 
 4375     gio2 = g_io_channel_unix_new(read_dummy);
 4376     g_io_channel_set_encoding(gio2, NULL, NULL); 
 4377         readcdda_callback2 = g_io_add_watch(gio2, G_IO_IN,
 4378                 read_cdda2wav_dummyout, NULL);
 4379 
 4380         /* now wait until track is read */
 4381         while (read_done == 999) {
 4382                 wait_and_process_events();
 4383         }
 4384 
 4385     g_source_remove(readcdda_callback2);
 4386     g_io_channel_unref(gio);
 4387     g_io_channel_unref(gio2);
 4388 
 4389         close(read_out);
 4390         close(read_in);
 4391     close(read_dummy);
 4392 
 4393     append_to_text_view(readtrack_textview, "\n");
 4394 
 4395         /* error while reading? */
 4396         if (read_done != 0 && read_abort_mark == 0) {
 4397                 g_snprintf(tmp,MAXLINE,_("Error reading audio track %d/%d"), read_tracknr, 
 4398             writeparams.nrtracks);
 4399                 gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);        
 4400                 gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Read-Error:"));  
 4401                 return 1;
 4402         }
 4403         /* aborted? */
 4404         if (read_abort_mark == 1) {
 4405                 gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Read aborted..."));  
 4406                 return 1;
 4407         }
 4408 
 4409     return 0;
 4410 }
 4411 
 4412 
 4413 /*
 4414  * parse output of readcd and update sliders
 4415  */
 4416 static gboolean read_readcd_out_io_in(GIOChannel *source, GIOCondition cond, gpointer data) {
 4417 gchar line[MAXLINE];
 4418 gchar tmp[MAXLINE];
 4419 gchar tmp2[MAXLINE];
 4420 gint val;
 4421 gfloat pval, pval2;
 4422 
 4423     /* read output of readcd */
 4424     read_io_channel(source, line, MAXLINE);
 4425 
 4426     /* nothing read - nonblock */
 4427     if (strcmp(line, "") == 0) {
 4428         wait_and_process_events();
 4429         return (TRUE);
 4430     }
 4431 
 4432     dodebug(10,"readcd: %s\n", line);
 4433 
 4434     /* look for end value */
 4435     if (strncmp(line,"end:",4) == 0) {
 4436         strcpy(tmp,line+4);
 4437         strip_string(tmp);
 4438         readcd_endsector = atoi(tmp);
 4439         return (TRUE);
 4440     }
 4441 
 4442     /* look for a percent value */
 4443     if (strncmp(line,"addr:",5) == 0) {
 4444         /* skip leading linefeed if any */
 4445         if (line[0] == '\r') 
 4446             strcpy(tmp,line+6);
 4447         else 
 4448             strcpy(tmp,line+5);
 4449 
 4450         strip_string(tmp);
 4451         strcpy(tmp2,strtok(tmp," "));
 4452         val = atoi(tmp2) - readcd_startsector;
 4453 
 4454         /* if not set yet, do nothing */
 4455         if (readcd_endsector == 0) 
 4456             return (TRUE);
 4457 
 4458         pval = (gfloat)val/(gfloat)(readcd_endsector - readcd_startsector);
 4459         if (pval > 1.0) pval = 1.0;
 4460 
 4461         gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar1),
 4462             pval);
 4463 
 4464         /* now calculate how much percent he has at all */
 4465         pval2 = (pct_so_far + (pval * pct_this_track)) /100;
 4466         if (pval2 > 1.0) pval2 = 1.0;
 4467         gtk_progress_set_percentage(GTK_PROGRESS(readtrack_pbar2),
 4468             pval2);
 4469         set_xcdr_title(toplevel,viewmode_dialog,(gint)(pval2*100+0.5));
 4470 
 4471         /* now update info for small view */
 4472         g_snprintf(tmp,MAXLINE,"%d%% / %d%%",(gint)(pval*100+0.5),
 4473                (gint)(pval2*100+0.5));
 4474         gtk_label_set_text(GTK_LABEL(readtrack_small_info2),tmp);   
 4475         
 4476         return (TRUE);
 4477     }
 4478 
 4479     /* look if last expected line from readcd came */
 4480     if (strncmp(line,"Read",4) == 0) {
 4481         /* ok...now we can expect that we were not aborted */
 4482         if (read_output_ctrl != 2) {
 4483             read_output_ctrl = 1;
 4484         }
 4485     }
 4486 
 4487     /* look if we got an read error */
 4488     if (line[0] == '.') {
 4489         gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Failed to read sector - retrying"));  
 4490         gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Retrying..."));   
 4491     }
 4492 
 4493     /* now look if the got an error which could not corrected */
 4494     if (strstr(line,"not corrected")) {
 4495         read_output_ctrl = 2;
 4496     }
 4497 
 4498     /* write error on hard disk? */
 4499     if (strstr(line,"annot write")) {
 4500         read_output_ctrl = 2;
 4501     }
 4502 
 4503         /* some blocked output of tracks came through */
 4504         if (strstr(line, " cnt: ")) {
 4505                 /* kick it */
 4506                 return (TRUE);
 4507         }
 4508 
 4509     /* forward most other output to textview window */
 4510     strcat(line,"\n");
 4511     append_to_text_view(readtrack_textview, line);
 4512 
 4513     return (TRUE);
 4514 }
 4515 
 4516 static gboolean read_readcd_out(GIOChannel *source, GIOCondition cond, gpointer data) {
 4517 gchar line[MAXLINE];
 4518 gint ret;
 4519 
 4520         if (cond & G_IO_IN) {
 4521         
 4522             read_readcd_out_io_in(source, cond, data);
 4523         }
 4524 
 4525     if ((cond & G_IO_IN) && (cond & G_IO_HUP)) {
 4526                 read_io_channel_all(source, line, MAXLINE);
 4527         if (strcmp(line, "") == 0) {
 4528             cond = G_IO_HUP;
 4529         } else {
 4530             append_multiline_to_textview(line, "", readtrack_textview, "readcd-hup");
 4531         }
 4532         }
 4533 
 4534     /* readcd-finished? */
 4535     if (cond == G_IO_HUP) {
 4536 
 4537         /* tell our caller that we are done here */
 4538         ret = get_wait_ret(-1);
 4539         if (ret == 0 && read_output_ctrl == 0) {
 4540             /* readcd does return status 0 when killed - override */
 4541             read_done = 1;
 4542         } else {
 4543             read_done = ret;
 4544         }
 4545         return (FALSE);
 4546     }
 4547 
 4548     return(TRUE);
 4549 }
 4550 
 4551 /*
 4552  * call readcd to read a data-track 
 4553  * return 0 on success, 1 on error
 4554  */
 4555 gint read_data_track(gint devnr, gint starttrack, gint kbyte, 
 4556               gchar *fname, gint startoffset, gint endoffset,
 4557               gint nrtracks, gfloat percent, gfloat percent_done,
 4558               gint viewtrack) {
 4559 gchar cmd[MAXLINE];
 4560 gchar tmp[MAXLINE];
 4561 gchar tmptmp[MAXLINE];
 4562 gchar tmp2[MAXLINE];
 4563 gchar tmp3[MAXLINE];
 4564 gint read_in, read_out, sectsize;
 4565 GIOChannel *gio;
 4566 
 4567     /* if another read running, ignore */
 4568     if (read_done == 999) {
 4569         return -1;
 4570     }
 4571 
 4572     /* no filename given? */
 4573     if (fname == NULL) {
 4574         return 1;
 4575     }
 4576 
 4577     /* mark our read-process as running */
 4578     read_done = 999;
 4579     readcdda_pid = -1;
 4580     readcdda_pid2 = -1;
 4581     read_output_ctrl = 0;
 4582     readcd_startsector = startoffset;
 4583     readcd_endsector = 0;
 4584     read_abort_mark = 0;
 4585 
 4586     /* set info-label */
 4587     convert_kbytes2mbminstring(kbyte, tmp);
 4588     g_snprintf(tmp2,MAXLINE,_("Reading data track %d/%d [%s]"), viewtrack, nrtracks, tmp);
 4589     gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp2);   
 4590 
 4591     g_snprintf(tmp2,MAXLINE,_("Reading %d/%d:"), viewtrack, nrtracks);
 4592     gtk_label_set_text(GTK_LABEL(readtrack_small_info),tmp2);   
 4593     
 4594     /* get bus,id,lun string */
 4595     if (convert_devnr2busid_dev(devnr,tmp) != 0) {
 4596         g_error("non existing cdrom?");
 4597     }
 4598 
 4599     /* some stuff to have our slider moving smoothly no matter how
 4600        big the tracks are */
 4601     pct_so_far = percent_done;
 4602     pct_this_track = percent;
 4603 
 4604         /* now check which sectorsize we got */
 4605         sectsize = get_sectorsize(devnr);
 4606     if (sectsize == 2352) {
 4607         /* workaround for buggy drives */
 4608             endoffset = ((endoffset * DATASECTORSIZE) / sectsize) + 1;
 4609     }
 4610 
 4611     get_wrap_path("READCD", tmp3);
 4612     strcpy(tmptmp,fname);
 4613     g_snprintf(cmd,MAXLINE,
 4614            "%s %s sectors=%d-%d -s retries=32 f= \"%s\"",
 4615            tmp3, tmp, startoffset, endoffset, 
 4616            convert_escape(tmptmp));
 4617     dodebug(1, "spawning: %s\n",cmd);
 4618     dolog(2,"Read data track %s\n", fname);
 4619     dolog(3,"Executing: %s\n",cmd);
 4620 
 4621     /* start child and get new fds */
 4622     readcdda_pid = full_dpl_pipe3(NULL,&read_in,&read_out,cmd,0); 
 4623     readcdda_pid2 = -1;
 4624 
 4625     /* catch output of child */
 4626     gio = g_io_channel_unix_new(read_out);
 4627     g_io_channel_set_encoding(gio, NULL, NULL); 
 4628     g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
 4629     readcdda_callback = g_io_add_watch(gio, G_IO_IN | G_IO_HUP,
 4630         read_readcd_out, NULL);
 4631 
 4632     /* now wait until track is read */
 4633     while (read_done == 999) {
 4634         wait_and_process_events();
 4635     }
 4636 
 4637     g_io_channel_unref(gio);
 4638     close(read_out);
 4639     close(read_in);
 4640 
 4641     append_to_text_view(readtrack_textview, "\n");
 4642 
 4643     /* error while reading? */
 4644     if ((read_done != 0 && read_abort_mark == 0) || read_output_ctrl == 2) {
 4645         g_snprintf(tmp,MAXLINE,_("Error reading data track %d/%d"), starttrack, nrtracks);
 4646         gtk_label_set_text(GTK_LABEL(readtrack_info_label),tmp);    
 4647         gtk_label_set_text(GTK_LABEL(readtrack_small_info),_("Read-Error:"));   
 4648         return 1;
 4649     }
 4650     /* aborted? */
 4651     if (read_abort_mark == 1) {
 4652         gtk_label_set_text(GTK_LABEL(readtrack_info_label),_("Read aborted..."));   
 4653         return 1;
 4654     }
 4655 
 4656     return 0;
 4657 }
 4658 
 4659 
 4660 static gboolean checkmedium_out_io_in(GIOChannel *source, GIOCondition cond, gpointer data) {
 4661 gint devnr, sectsize;
 4662 gchar tmp[MAXLINE];
 4663 gchar line[MAXLINE];
 4664 gchar *p;
 4665 
 4666         /* read output of readcd */
 4667     read_io_channel(source, line, MAXLINE);
 4668 
 4669     dodebug(10,"check_medium_loaded: %s\n", line);
 4670     /*
 4671      * got the message that no medium is present?
 4672      * in this case, ignore return code
 4673      */
 4674     if (strstr(line,"medium not present")) {
 4675         checkmedium_found = 1;
 4676     }
 4677     if (strstr(line,"Device not ready")) {
 4678                 checkmedium_found = 1;
 4679         }
 4680 
 4681         /* get a line about sectorsize? */
 4682         if (strstr(line,"Sectorsize:")) {
 4683                 /* extract the bytes given there */
 4684                 strcpy(tmp,line+12);
 4685                 p = strtok(tmp," ");
 4686                 if (p) {
 4687                         sectsize = atoi(p);
 4688                         dodebug(10,"-> Detected sectorsize of %d bytes\n", sectsize);
 4689             devnr = GPOINTER_TO_INT(data);
 4690                         set_sectorsize(devnr,sectsize);
 4691                 }
 4692         }
 4693     return (TRUE);
 4694 }
 4695 
 4696 static gboolean checkmedium_out(GIOChannel *source, GIOCondition cond, gpointer data) {
 4697 
 4698     if (cond & G_IO_IN) {
 4699 
 4700             checkmedium_out_io_in(source, cond, data);
 4701         }
 4702 
 4703         /* readcd finished */
 4704     if (cond == G_IO_HUP) {
 4705 
 4706                 /* tell our caller that we are done here */
 4707                 read_done = get_wait_ret(-1);
 4708                 return (FALSE);
 4709         }
 4710     return (TRUE);
 4711 }
 4712 
 4713 /*
 4714  * checks if a disc is loaded in drive 
 4715  * return 0 if not, 1 if loaded and ready
 4716  */
 4717 static gint check_medium_loaded(gint devnr) {
 4718 gchar tmp[MAXLINE];
 4719 gchar tmp2[MAXLINE];
 4720 gchar line[MAXLINE];
 4721 gint read_out;
 4722 GIOChannel *gio;
 4723 
 4724     checkmedium_found = 0;
 4725     read_done = 999;
 4726 
 4727     /* get bus,id,lun string */
 4728     if (convert_devnr2busid_dev(devnr,tmp) != 0) {
 4729         g_error("non existing cdrom?");
 4730     }
 4731 
 4732     /* build command line */
 4733     get_wrap_path("READCD", tmp2);
 4734     g_snprintf(line,MAXLINE,"%s %s f=- sectors=0-0",
 4735         tmp2,tmp);
 4736 
 4737     dodebug(1, "spawning: %s\n", line);
 4738 
 4739         readcdda_pid = full_dpl_pipe3(NULL,NULL,&read_out,line,0);
 4740         readcdda_pid2 = -1;
 4741 
 4742     gio = g_io_channel_unix_new(read_out);
 4743     g_io_channel_set_encoding(gio, NULL, NULL); 
 4744     readcdda_callback = g_io_add_watch(gio, G_IO_IN | G_IO_HUP,
 4745         checkmedium_out, GINT_TO_POINTER(devnr));
 4746 
 4747         /* now wait until toc is read */
 4748         while (read_done == 999) {
 4749                 wait_and_process_events();
 4750         }
 4751 
 4752     g_io_channel_unref(gio);
 4753         close(read_out);
 4754 
 4755     dodebug(10, "medium loaded return code: %d\n", read_done);
 4756 
 4757     if ((read_done == 0 || read_done == 255) && checkmedium_found == 0) 
 4758         return 1;
 4759     else
 4760         return 0;
 4761 }
 4762 
 4763 
 4764 /*
 4765  * save the contents of a text-widget to a file 
 4766  * return 0 on success, 1 on error
 4767  */
 4768 gint save_text2file(char *fname, GtkWidget *txt) {
 4769 gchar *buf;
 4770 GtkTextBuffer *buffer;
 4771 GtkTextIter start, end;
 4772 gint fd;
 4773 
 4774     /* get text from textwidget */
 4775     buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt));
 4776     gtk_text_buffer_get_bounds(buffer, &start, &end);
 4777     buf = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
 4778 
 4779     dodebug(2, "saving extended output to %s\n", fname);
 4780     dolog(3, "Saving extended output to %s\n", fname);
 4781 
 4782     /* write to file */
 4783     fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
 4784     if (fd < 0) {
 4785         g_warning("Can't open file %s for writing\n",fname);
 4786         return 1;
 4787     }
 4788 
 4789     if (write(fd,buf,strlen(buf)) != strlen(buf)) {
 4790         g_warning("Can't write file %s\n",fname);
 4791         return 1;
 4792     }
 4793 
 4794     g_free(buf);
 4795     close(fd);
 4796     chmod(fname,0644);
 4797 
 4798     return 0;
 4799 }
 4800 
 4801 
 4802 /*
 4803  * write the toc-file when copying full discs
 4804  */
 4805 gint write_copy_cd_toc_file(gchar *tocfile) {
 4806 GList *loop;
 4807 track_read_param_t *trackparam;
 4808 FILE *fd;
 4809 time_t acttime;
 4810 gchar timestr[MAXLINE];
 4811 gint tracknr;
 4812 gchar tmp[MAXLINE];
 4813 gchar tmp2[MAXLINE];
 4814 
 4815     if (tocfile == NULL) return 1;
 4816 
 4817     dodebug(2, "writing Disc toc file %s\n", tocfile);
 4818 
 4819         /* is a link? */
 4820         if (check_islink(tocfile, NULL)) {
 4821             g_warning("Warning, won't overwrite a link at %s\n", tocfile);
 4822         return 1;
 4823         }
 4824 
 4825     /* write to file */
 4826     fd = fopen(tocfile,"w"); 
 4827 
 4828     if (fd == NULL) {
 4829         g_warning("Can't open file %s for writing\n",tocfile);
 4830         return 1;
 4831     }
 4832 
 4833     /* get current time */
 4834     acttime = time((time_t *) 0);
 4835     strcpy(timestr,ctime(&acttime));
 4836     timestr[strlen(timestr)-1] = '\0';
 4837 
 4838     /* write header */
 4839     fputs("#\n",fd);
 4840     g_snprintf(tmp,MAXLINE,"# X-CD-Roast %s - TOC-File\n",XCDROAST_VERSION);
 4841     fputs(tmp,fd);
 4842     g_snprintf(tmp,MAXLINE,"# created: %s\n", timestr);
 4843     fputs(tmp,fd);
 4844     g_snprintf(tmp,MAXLINE,"# by: %s@%s\n", username, hostname);
 4845     fputs(tmp,fd);
 4846     fputs("#\n",fd);
 4847 
 4848     /* write disc info */
 4849     convert_frames2minstring(cdinfo.total_size, tmp2);
 4850     g_snprintf(tmp,MAXLINE,"# Tracks: %d [%s]\n", 
 4851         cdinfo.nr_tracks, tmp2);
 4852     fputs(tmp,fd);
 4853     if (cdinfo.title && cdinfo.artist) {
 4854         g_snprintf(tmp,MAXLINE,"# title/artist: %s / %s\n",
 4855             cdinfo.title, cdinfo.artist);
 4856         fputs(tmp,fd);
 4857     }
 4858     if (cdinfo.cddb_dtitle != NULL) {
 4859         g_snprintf(tmp,MAXLINE,"# cddb: %s\n", cdinfo.cddb_dtitle);
 4860         fputs(tmp,fd);
 4861     }
 4862     fputs("#\n",fd);
 4863 
 4864     /* generate disc title */
 4865     if (cdinfo.cddb_dtitle != NULL) {
 4866         strcpy(tmp2,cdinfo.cddb_dtitle);
 4867         g_snprintf(tmp,MAXLINE,"cdtitle = \"%s\"\n", convert_escape(tmp2));
 4868     } else 
 4869     if (cdinfo.title && cdinfo.artist && cdinfo.title[0] != '\0') {
 4870         g_snprintf(tmp2,MAXLINE,"%s / %s", 
 4871             cdinfo.title, cdinfo.artist);
 4872         g_snprintf(tmp,MAXLINE,"cdtitle = \"%s\"\n", convert_escape(tmp2));
 4873     } else {
 4874         /*
 4875          * no title available?
 4876          * if data-track get track-label (better than nothing)
 4877          * get first track
 4878          */
 4879         loop = g_list_first(trackreadset.trackparams);
 4880         if (loop) {
 4881             trackparam = loop->data;
 4882             tracknr = trackparam->trackinfo_index;
 4883             if (trackinfo[tracknr]->title != NULL) {
 4884                 strcpy(tmp2,trackinfo[tracknr]->title);
 4885             } else {
 4886                 strcpy(tmp2,"");
 4887             }
 4888             g_snprintf(tmp,MAXLINE,"cdtitle = \"%s\"\n", 
 4889                 convert_escape(tmp2));
 4890         } else {    
 4891             g_snprintf(tmp,MAXLINE,"cdtitle = \"\"\n");
 4892         }
 4893     }   
 4894     fputs(tmp,fd);
 4895     g_snprintf(tmp,MAXLINE,"cdsize = %d\n",cdinfo.total_size);
 4896     fputs(tmp,fd);
 4897     g_snprintf(tmp,MAXLINE,"discid = \"%s\"\n",cdinfo.cddb_discid);
 4898     fputs(tmp,fd);
 4899 
 4900 
 4901     /* write a section for each track */
 4902     loop = g_list_first(trackreadset.trackparams);
 4903     while (loop) {
 4904         trackparam = loop->data;
 4905 
 4906         tracknr = trackparam->trackinfo_index;
 4907 
 4908         /* make sure to get some NULLs wasted */
 4909         if (trackinfo[tracknr]->title == NULL) {
 4910             trackinfo[tracknr]->title = g_strdup("");
 4911         }
 4912         if (trackinfo[tracknr]->artist == NULL) {
 4913             trackinfo[tracknr]->artist = g_strdup("");
 4914         }
 4915 
 4916         fputs("\n",fd);
 4917         if (trackinfo[tracknr]->type == 0) {
 4918             convert_frames2mbstring(trackinfo[tracknr]->size, tmp2);
 4919             g_snprintf(tmp,MAXLINE,"# data: %s [%"LL_FORMAT" bytes / %s]\n",
 4920                 trackinfo[tracknr]->title,
 4921                 (gint64) trackinfo[tracknr]->size * DATASECTORSIZE,
 4922                 tmp2);
 4923             fputs(tmp,fd);
 4924         } else {
 4925             convert_frames2minstring(trackinfo[tracknr]->size, tmp2);
 4926             g_snprintf(tmp,MAXLINE,"# audio: %s / %s [%"LL_FORMAT" bytes / %s]\n",
 4927                 trackinfo[tracknr]->title,
 4928                 trackinfo[tracknr]->artist,
 4929                 (gint64) trackinfo[tracknr]->size * CDDAFRAME, tmp2);
 4930             fputs(tmp,fd);
 4931             if (trackinfo[tracknr]->cddb_ttitle != NULL) {
 4932                 g_snprintf(tmp,MAXLINE,"# cddb: %s\n",
 4933                     trackinfo[tracknr]->cddb_ttitle);
 4934                 fputs(tmp,fd);
 4935             }
 4936         }
 4937 
 4938         g_snprintf(tmp,MAXLINE,"track = %02d\n", trackparam->starttrack);
 4939         fputs(tmp,fd);
 4940         g_snprintf(tmp,MAXLINE,"type = %d\n", trackinfo[tracknr]->type);
 4941         fputs(tmp,fd);
 4942         g_snprintf(tmp,MAXLINE,"size = %d\n", trackinfo[tracknr]->size);
 4943         fputs(tmp,fd);
 4944         g_snprintf(tmp,MAXLINE,"startsec = %d\n", trackinfo[tracknr]->start_sec);
 4945         fputs(tmp,fd);
 4946 
 4947         if (trackparam->trackfile != NULL) {
 4948             strcpy(tmp2, trackparam->trackfile);
 4949         } else {
 4950             strcpy(tmp2,"");
 4951         }
 4952         g_snprintf(tmp,MAXLINE,"file = \"%s\"\n", 
 4953             convert_escape(tmp2));
 4954         fputs(tmp,fd);
 4955 
 4956         loop = loop->next;
 4957     }
 4958 
 4959     if (fclose(fd) != 0) {
 4960         /* error closing file */
 4961         return 1;
 4962     }
 4963 
 4964     return 0;
 4965 }
 4966 
 4967 
 4968 /*
 4969  * print trackparams-structure for debug reasons
 4970  */
 4971 void print_trackreadset() {
 4972 GList *loop;
 4973 track_read_param_t *trackparam;
 4974 
 4975     dodebug(2,"------ trackreadset-structure -----\n");
 4976     dodebug(2,"nrtracks: %d\n",trackreadset.nrtracks);
 4977     dodebug(2,"cdsize: %d\n",trackreadset.cdsize);
 4978     dodebug(2,"tocfile: %s\n",trackreadset.tocfile);
 4979     dodebug(2,"cdtitle: %s\n",trackreadset.cdtitle);
 4980 
 4981     loop = g_list_first(trackreadset.trackparams);
 4982     while(loop) {
 4983         trackparam = loop->data;
 4984         dodebug(2,"\ntrackinfo_index: %d\n", trackparam->trackinfo_index);
 4985         dodebug(2,"starttrack: %d\n", trackparam->starttrack);
 4986         dodebug(2,"endtrack: %d\n", trackparam->endtrack);
 4987         dodebug(2,"tracktype: %d\n", trackparam->tracktype);
 4988         dodebug(2,"start_sec: %d\n", trackparam->start_sec);
 4989         dodebug(2,"startoffset: %d\n", trackparam->startoffset);
 4990         dodebug(2,"endoffset: %d\n", trackparam->endoffset);
 4991         dodebug(2,"percent: %f\n", trackparam->percent);
 4992         dodebug(2,"kbyte: %d\n", trackparam->kbyte);
 4993         dodebug(2,"frames: %d\n", trackparam->frames);
 4994         if (trackparam->trackfile != NULL) {
 4995             dodebug(2,"trackfile: %s\n", trackparam->trackfile);
 4996         } else {
 4997             dodebug(2,"trackfile: (NULL)\n");
 4998         }   
 4999         loop = loop->next;
 5000     }
 5001 }
 5002 
 5003 
 5004 /*
 5005  * read the toc-file when copying full discs
 5006  */
 5007 gint read_copy_cd_toc_file(gchar *tocfile) {
 5008 FILE *fd;
 5009 GList *loop;
 5010 track_read_param_t *trackparam;
 5011 gchar line[MAXLINE];
 5012 gchar id[MAXLINE];
 5013 gchar value[MAXLINE];
 5014 gint cdsize;
 5015 gfloat per;
 5016 
 5017     /* keep compiler shut about uninitialized warning */
 5018     trackparam = NULL;
 5019 
 5020     /* prepare trackreadset for refilling */
 5021     loop = g_list_first(trackreadset.trackparams);
 5022     while (loop) {
 5023         trackparam = loop->data;
 5024         g_free(trackparam->trackfile);
 5025         g_free(trackparam);
 5026         loop = loop->next;
 5027     }
 5028     g_list_free(trackreadset.trackparams);
 5029     trackreadset.trackparams = NULL;
 5030 
 5031     trackreadset.nrtracks = 0;
 5032     trackreadset.cdsize = 0;
 5033     cdsize = 0;
 5034     g_free(trackreadset.tocfile);
 5035     trackreadset.tocfile=g_strdup(tocfile);
 5036     g_free(trackreadset.cdtitle);
 5037     trackreadset.cdtitle = g_strdup("");
 5038 
 5039     dodebug(2, "reading Disc toc file %s\n", tocfile);
 5040     /* open file */
 5041     fd = fopen(tocfile,"r");
 5042 
 5043     if (fd == NULL) {
 5044         g_warning("Can't open file %s for reading\n",tocfile);
 5045         return 1;
 5046     }
 5047 
 5048     for (;;) {
 5049         if (fgets(line,MAXLINE,fd) == NULL)
 5050             break;
 5051 
 5052         dodebug(10,"read tocfile: %s", line);
 5053         /* skip empty or hashed lines */
 5054         strip_string(line);
 5055         if (*line == '#' || *line == '\0')
 5056             continue;
 5057 
 5058                 /* parse lines */
 5059         if (parse_config_line(line,id,value)) {
 5060             dodebug(10,"invalid line in tocfile");
 5061             fclose(fd);
 5062             return 1;
 5063         }   
 5064 
 5065         if (strcmp("cdtitle",id) == 0) {
 5066             g_free(trackreadset.cdtitle);
 5067             trackreadset.cdtitle = g_strdup(value);
 5068         }
 5069         if (strcmp("discid",id) == 0) {
 5070             g_free(trackreadset.cd_discid);
 5071             trackreadset.cd_discid = g_strdup(value);
 5072         }
 5073         if (strcmp("cdsize"