"Fossies" - the Fresh Open Source Software Archive

Member "xcdroast-1.19/src/xtools.c" (2 Nov 2018, 75097 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 "xtools.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  *  xtools.c
    3  *  27.3.99 tn
    4  *
    5  *
    6  *  Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
    7  *
    8  *  This file is part of xcdroast.
    9  *
   10  *  This program is free software; you can redistribute it and/or modify
   11  *  it under the terms of the GNU General Public License as published by
   12  *  the Free Software Foundation; either version 2 of the License, or
   13  *  (at your option) any later version.
   14  *
   15  *  This program is distributed in the hope that it will be useful,
   16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  *  GNU General Public License for more details.
   19  *
   20  *  You should have received a copy of the GNU General Public License
   21  *  along with this program; if not, write to the Free Software
   22  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   23  */
   24 
   25 #ifdef HAVE_CONFIG_H
   26 # include <config.h>
   27 #endif
   28 
   29 #include "largefile.h"
   30 
   31 #include <locale.h>
   32 #include "gettext.h"
   33 
   34 #include <stdio.h>
   35 #include <stdlib.h>
   36 #include <sys/stat.h>
   37 #include <unistd.h>
   38 #include <string.h>
   39 #include <strings.h>
   40 #include <dirent.h>
   41 #include <fcntl.h>
   42 #include <sys/types.h>
   43 #include <errno.h>
   44 #include <ctype.h>
   45 #include <grp.h>
   46 #include <pwd.h>
   47 
   48 #if ENABLE_NLS
   49 # define _(String) gettext (String)
   50 # define N_(String) gettext_noop (String)
   51 #else
   52 # define _(String) (String)
   53 # define N_(String) (String)
   54 #endif
   55 
   56 #include <gtk/gtk.h>
   57 #include <gdk/gdk.h>
   58 #include "xcdrdata.h"
   59 #include "xcdroast.h"
   60 #include "main.h"
   61 
   62 extern gint debug;
   63 extern writerreader_devices_t **writerreaderdevs;
   64 extern gchar **alt_scsidevices;
   65 extern setup_data_t setupdata;
   66 extern cd_info_t cdinfo;
   67 extern track_info_t **trackinfo;
   68 extern GList *imagelist;
   69 extern current_set_t curset;
   70 extern track_read_set_t trackreadset;
   71 extern GList *tocfiles;
   72 extern GList *writelist;
   73 extern gint bigfonts;
   74 extern gchar sharedir[MAXLINE];
   75 extern gchar prefixdir[MAXLINE];
   76 extern gint c_locale_is_utf8;
   77 
   78 void define_tooltip(GtkWidget *widget, gchar *ttext) {
   79 GtkTooltips *tip;
   80 
   81     /* tooltips wanted? */
   82     if (setupdata.option_tooltips == 0) {
   83         return;
   84     }
   85 
   86     tip = gtk_tooltips_new();
   87     gtk_tooltips_set_tip(tip,widget,ttext,NULL);
   88 }
   89 
   90 
   91 /*
   92  * sets the font and color for a label widget.
   93  * if color/font is NULL then don't set color/font
   94  */
   95 void set_font_and_color(GtkWidget *widget, gchar *font, gchar *color) {
   96 GdkColor coldef;
   97 PangoFontDescription *fontdef;
   98 
   99     if (color) {
  100         gdk_color_parse (color, &coldef);
  101         gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &coldef);
  102     }   
  103     if (font) {
  104         fontdef = pango_font_description_from_string(font);
  105             gtk_widget_modify_font(widget, fontdef);
  106     }
  107 }
  108 
  109 
  110 /*
  111  * set font and color for a frame
  112  */
  113 void set_font_and_color_frame(GtkWidget *widget, gchar *font, gchar *color) {
  114 
  115     set_font_and_color(gtk_frame_get_label_widget(GTK_FRAME(widget)), font, color);
  116 }
  117 
  118 
  119 /*
  120  * sets the enable status for a label widget
  121  */
  122 void set_labelcolor(GtkWidget *widget, gchar *color) {
  123 
  124     if (strcmp(color, DISABLEDCOLOR) == 0)
  125         gtk_widget_set_sensitive(widget, FALSE);
  126     else
  127         gtk_widget_set_sensitive(widget, TRUE);
  128 }
  129 
  130 
  131 /*
  132  * sets a certain row in a clist to a font
  133  */
  134 void set_clist_row_font(GtkCList *clist, gint row, gchar *ffont) {
  135 GtkStyle *style;
  136 
  137     style=gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(clist)));
  138 
  139     if (ffont && strcmp(ffont, PANGO_ITALIC) == 0) {
  140         pango_font_description_set_style(style->font_desc,
  141             PANGO_STYLE_ITALIC);
  142     }
  143     if (ffont && strcmp(ffont, PANGO_BOLD) == 0) {
  144         pango_font_description_set_weight(style->font_desc, 
  145             PANGO_WEIGHT_BOLD);
  146     }
  147     
  148     gtk_clist_set_row_style(clist,row,style);
  149 
  150 }
  151 
  152 
  153 /*
  154  * colors a certain row in a clist
  155  */
  156 void set_clist_row_color(GtkCList *clist, gint row, gchar *color) {
  157 GtkStyle *style;
  158 GdkColor c;
  159 
  160     style=gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(clist)));
  161 
  162     if (!gdk_color_parse(color,&c)) {
  163         g_warning("Can't parse color %s\n",color);
  164         return;
  165     }
  166 
  167         if (!gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(clist)),&c)) {
  168         g_warning("Can't allocate color %s\n",color);
  169         return;
  170     }
  171     style->fg[GTK_STATE_NORMAL] = c;
  172 
  173     gtk_clist_set_row_style(clist,row,style);
  174 }
  175 
  176 
  177 /*
  178  * free a simple glist structure
  179  */
  180 void free_glist(GList **list) {
  181 GList *loop;
  182 gchar *dir;
  183 
  184     loop = g_list_first(*list);
  185     while(loop) {
  186         dir = loop->data;
  187         g_free(dir); 
  188         loop = loop->next;
  189     }
  190     g_list_free(*list);
  191     *list = NULL;   
  192 }
  193 
  194 
  195 /*
  196  * copy a simple glist (which has only strings as elements)
  197  */
  198 void copy_glist(GList **dst, GList *src) {
  199 GList *loop;
  200 gchar *dir;
  201 
  202     /* clear target list */
  203     free_glist(dst); 
  204 
  205     loop = g_list_first(src);
  206     while(loop) {
  207         dir = loop->data;
  208         *dst = g_list_append(*dst,g_strdup(dir)); 
  209         loop = loop->next;
  210     }
  211 }
  212 
  213 
  214 /*
  215  * remove a string-element from a glist
  216  */
  217 void del_glist_link(GList **list, gchar *str) {
  218 GList *loop;
  219 gchar *dir;
  220 
  221     if (str == NULL) 
  222         return;
  223 
  224     loop = g_list_first(*list);
  225     while(loop) {
  226         dir = loop->data;
  227         if (dir && strcmp(str,dir) == 0) {
  228             g_free(dir); 
  229             *list = g_list_remove_link(*list, loop);
  230             return;
  231         }
  232         loop = loop->next;
  233     }
  234 }
  235 
  236 
  237 /*
  238  * check if a string-element is in a glist
  239  * return 1 if found, 0 if not
  240  */
  241 gint check_in_glist(GList **list, gchar *str) {
  242 GList *loop;
  243 gchar *dir;
  244 
  245     if (str == NULL) 
  246         return 0;
  247 
  248     loop = g_list_first(*list);
  249     while(loop) {
  250         dir = loop->data;
  251         if (dir && strcmp(str,dir) == 0) {
  252             return 1;
  253         }
  254         loop = loop->next;
  255     }
  256     return 0;
  257 }
  258 
  259 
  260 /*
  261  * check if a path is in a master-path-glist
  262  * return 1 if found, 0 if not
  263  */
  264 gint check_in_mstr_glist(GList **list, gchar *str) {
  265 GList *loop;
  266 mstr_redirect_t *mstr;
  267 gchar *dir;
  268 
  269     if (str == NULL) 
  270         return 0;
  271 
  272     loop = g_list_first(*list);
  273     while(loop) {
  274         mstr = (mstr_redirect_t *) loop->data;
  275         if (mstr) {
  276             dir = mstr->mstr_path;
  277         } else {
  278             dir = NULL;
  279         }
  280         if (dir && strcmp(str,dir) == 0) {
  281             return 1;
  282         }
  283         loop = loop->next;
  284     }
  285     return 0;
  286 }
  287 
  288 /*
  289  * remove a string-element from a master-glist
  290  * if there is a redir-path, remove only this and return
  291  * (unless del_both is set, where the whole entry is removed)
  292  * del_both == -1, only remove link if possible
  293  */
  294 void del_mstr_glist_link(GList **list, gchar *str, gint del_both) {
  295 GList *loop;
  296 mstr_redirect_t *mstr;
  297 gchar *dir;
  298 
  299     if (str == NULL) 
  300         return;
  301 
  302     loop = g_list_first(*list);
  303     while(loop) {
  304         mstr = (mstr_redirect_t *) loop->data;
  305         if (mstr) {
  306             dir = mstr->mstr_path;
  307         } else {
  308             dir = NULL;
  309         }
  310 
  311         if (dir && strcmp(str,dir) == 0) {
  312             /* found link */
  313             if (mstr->redir_path) {
  314                 /* remove redir-path only */
  315                 g_free(mstr->redir_path);
  316                 mstr->redir_path = NULL;
  317 
  318                 if (del_both == 0)
  319                     return;
  320             }
  321             if (del_both == -1) return;
  322 
  323             g_free(dir); 
  324             g_free(mstr);
  325             *list = g_list_remove_link(*list, loop);
  326             return;
  327         }
  328         loop = loop->next;
  329     }
  330 }
  331 
  332 
  333 /*
  334  * clear a mstr_glist
  335  */
  336 void clear_mstr_glist(GList **list) {
  337 GList *loop;
  338 mstr_redirect_t *mstr;
  339 
  340     loop = g_list_first(*list);
  341     while(loop) {
  342         mstr = (mstr_redirect_t *) loop->data;
  343         if (mstr) {
  344             if (mstr->mstr_path) 
  345                 g_free(mstr->mstr_path);
  346             if (mstr->redir_path) 
  347                 g_free(mstr->redir_path);
  348             g_free(mstr);
  349         }
  350         loop = loop->next;
  351     }
  352     g_list_free(*list);
  353     *list = NULL;   
  354 }
  355 
  356 
  357 /*
  358  * add a redir path to the master-glist
  359  */
  360 void add_redir_mstr_glist(GList **list, gchar *str, gchar *new) {
  361 GList *loop;
  362 mstr_redirect_t *mstr;
  363 gchar *dir;
  364 
  365     if (str == NULL) 
  366         return;
  367 
  368     loop = g_list_first(*list);
  369     while(loop) {
  370         mstr = (mstr_redirect_t *) loop->data;
  371         if (mstr) {
  372             dir = mstr->mstr_path;
  373         } else {
  374             dir = NULL;
  375         }
  376         if (dir && strcmp(str,dir) == 0) {
  377             /* found link */
  378             if (mstr->redir_path) {
  379                 /* remove redir-path first */
  380                 g_free(mstr->redir_path);
  381             }
  382             /* now set new value */
  383             mstr->redir_path = g_strdup(new);
  384             return;
  385         }
  386         loop = loop->next;
  387     }
  388 }
  389 
  390 
  391 /*
  392  * get a string in the form bla => foo and return only bla
  393  */
  394 void extract_mstr_path_from_clist(gchar *in, gchar *out) {
  395 gint found;
  396 guint i;
  397 
  398     if (in == NULL || out == NULL) 
  399         return;
  400 
  401         if (strlen(in) == 0) {
  402                 strcpy(out,"");
  403                 return;
  404         }
  405 
  406     found = -1;
  407 
  408     for (i = 0; i < strlen(in)-1; i++) {
  409         if ((in[i] == '=') && (in[i+1] == '>')) {
  410             found = i;
  411             break;
  412         }
  413     } 
  414 
  415     if (found == -1) {
  416         /* nothing found - return original string */
  417         strcpy(out,in);
  418     } else {
  419         strncpy(out,in,found);
  420         out[found] = '\0';
  421     }
  422     strip_string(out);
  423 
  424     /* internally we use not utf8, convert back from widget */
  425     convert_for_gtk2_filename(out);
  426 }
  427 
  428 
  429 /*
  430  * get the redir path from the master-glist
  431  */
  432 void get_redir_path_from_mstr_glist(GList **list, gchar *str, gchar *ret) {
  433 GList *loop;
  434 mstr_redirect_t *mstr;
  435 gchar *dir;
  436 
  437     if (str == NULL) 
  438         return;
  439 
  440     loop = g_list_first(*list);
  441     while(loop) {
  442         mstr = (mstr_redirect_t *) loop->data;
  443         if (mstr) {
  444             dir = mstr->mstr_path;
  445         } else {
  446             dir = NULL;
  447         }
  448         if (dir && strcmp(str,dir) == 0) {
  449             /* found link */
  450             if (mstr->redir_path) {
  451                 strcpy(ret, mstr->redir_path);
  452             } else {
  453                 strcpy(ret, "");
  454             }
  455             return;
  456         }
  457         loop = loop->next;
  458     }
  459     strcpy(ret, "");
  460 }
  461 
  462 
  463 /*
  464  * set scsi-sector-size for a given device
  465  */
  466 void set_sectorsize(gint devnr, gint size) {
  467 gint i;
  468 
  469         i = 0;
  470         while(writerreaderdevs[i] != NULL) {
  471                 if (devnr == writerreaderdevs[i]->devnr) {
  472                         writerreaderdevs[i]->sector_size = size;
  473                         return;
  474                 }
  475                 i++;
  476         }
  477 }
  478 
  479 
  480 /*
  481  * get scsi-sector-size for a given device
  482  */
  483 gint get_sectorsize(gint devnr) {
  484 gint i;
  485 
  486         i = 0;
  487         while(writerreaderdevs[i] != NULL) {
  488                 if (devnr == writerreaderdevs[i]->devnr) {
  489                         return(writerreaderdevs[i]->sector_size);
  490                 }
  491                 i++;
  492         }
  493  
  494         return DATASECTORSIZE;
  495 }
  496 
  497 
  498 /*
  499  * convert the devnr to a device-string. return 1 if devnr not found
  500  */
  501 gint convert_devnr2devstring(gint devnr, gchar *str) {
  502 gint i;
  503 gchar tmp[MAXLINE];
  504 
  505     i = 0;
  506     while(writerreaderdevs[i] != NULL) {
  507         if (devnr == writerreaderdevs[i]->devnr) {
  508             if (!writerreaderdevs[i]->devicestr) {
  509                 g_error("empty device string?");
  510             }
  511             g_snprintf(tmp,MAXLINE,"%s %s [%s]",
  512                 writerreaderdevs[i]->vendor, 
  513                 writerreaderdevs[i]->model,
  514                 writerreaderdevs[i]->devicestr);
  515             strcpy(str,tmp);
  516             return 0;
  517         }
  518         i++;
  519     }
  520 
  521     strcpy(str,"");
  522     return 1;
  523 }
  524 
  525 
  526 /*
  527  * convert the devnr to a vendor-string. return 1 if devnr not found
  528  */
  529 gint convert_devnr2vendor(gint devnr, gchar *str) {
  530 gint i;
  531 
  532     i = 0;
  533     while(writerreaderdevs[i] != NULL) {
  534         if (devnr == writerreaderdevs[i]->devnr) {
  535             strcpy(str,writerreaderdevs[i]->vendor);
  536             return 0;
  537         }
  538         i++;
  539     }
  540     strcpy(str,"");
  541     return 1;
  542 }
  543 
  544 
  545 /*
  546  * convert the devnr to a model-string. return 1 if devnr not found
  547  */
  548 gint convert_devnr2model(gint devnr, gchar *str) {
  549 gint i;
  550 
  551     i = 0;
  552     while(writerreaderdevs[i] != NULL) {
  553         if (devnr == writerreaderdevs[i]->devnr) {
  554             strcpy(str,writerreaderdevs[i]->model);
  555             return 0;
  556         }
  557         i++;
  558     }
  559     strcpy(str,"");
  560     return 1;
  561 }
  562 
  563 
  564 /*
  565  * convert the devnr to a bus/id/lun-string. return 1 if devnr not found
  566  */
  567 gint convert_devnr2busid(gint devnr, gchar *str) {
  568 gint i;
  569 
  570     i = 0;
  571     while(writerreaderdevs[i] != NULL) {
  572         if (devnr == writerreaderdevs[i]->devnr) {
  573             if (!writerreaderdevs[i]->devicestr) {
  574                 g_error("empty device string?");
  575             }
  576             strncpy(str,
  577                 writerreaderdevs[i]->devicestr,
  578                 MAXLINE);
  579             convert_escape(str);
  580             return 0;
  581         }
  582         i++;
  583     }
  584     strcpy(str,"");
  585     return 1;
  586 }
  587 
  588 
  589 /*
  590  * save as convert_devnr2busid(), but return with dev= component
  591  */
  592 gint convert_devnr2busid_dev(gint devnr, gchar *str) {
  593 gint i;
  594 gchar tmp[MAXLINE];
  595 
  596     i = 0;
  597     while(writerreaderdevs[i] != NULL) {
  598         if (devnr == writerreaderdevs[i]->devnr) {
  599             if (!writerreaderdevs[i]->devicestr) {
  600                 g_error("empty device string?");
  601             }
  602             strncpy(tmp,
  603                 writerreaderdevs[i]->devicestr,
  604                 MAXLINE);
  605             convert_escape(tmp);
  606             g_snprintf(str,MAXLINE,"dev= \"%s\"",tmp);
  607             return 0;
  608         }
  609         i++;
  610     }
  611     strcpy(str,"");
  612     return 1;
  613 }
  614 
  615 
  616 /*
  617  * Convert kbytes to MiB/min or MiB/h or GiB/h string.
  618  * Displays MiB or GiB when using 2048b sectors.
  619  * Displays minutes or hours suitable to audio tracks on the hard drive.
  620  * This is not correct when displaying the minute-size of DATA tracks!
  621  */ 
  622 void convert_kbytes2mbminstring(gint kbytes, gchar *str) {
  623 gint MiB, GiB;
  624 gint min, sec, frms;
  625 gint hrs, min1;
  626 gint frames;
  627 gint64 tmpsize;
  628 
  629     MiB = kbytes/1024;
  630     GiB = kbytes/1048576;
  631     tmpsize = (gint64)kbytes * 1024;
  632     frames = (gint) ((gint64)tmpsize/CDDAFRAME);
  633     
  634     hrs = frames/(3600*75);
  635     min1 = (frames%(3600*75))/60/75;
  636     min = frames/(60*75);
  637     sec = (frames%(60*75))/75;
  638     frms = (frames%75);
  639 
  640     if (min < 600) {
  641         g_snprintf(str,MAXLINE,"%d MiB / %d:%02d.%02d min",MiB,min,sec,frms);
  642     } else if (MiB < 10240) {
  643         g_snprintf(str,MAXLINE,"%d MiB / %d:%02d h",MiB,hrs,min1);
  644     } else {
  645         g_snprintf(str,MAXLINE,"%d GiB / %d:%02d h",GiB,hrs,min1);
  646     }
  647 }
  648 
  649 
  650 /*
  651  * convert kbytes to MiB/min string
  652  * displays MiB when using 2048b sectors. min like the size of track after
  653  * burned. The only correct min size display when burning data tracks
  654  */ 
  655 void convert_kbytes2mbcorrectminstring(gint kbytes, gchar *str) {
  656 gint MiB;
  657 gint min;
  658 gint sec;
  659 gint frames;
  660 gint frms;
  661 
  662     MiB = kbytes/1024;
  663     frames = kbytes/2;  
  664     min = frames/(60*75);
  665     sec = (frames%(60*75))/75;
  666     frms = (frames%75);
  667 
  668     g_snprintf(str,MAXLINE,"%d MiB / %d:%02d.%02d",MiB,min,sec,frms);
  669 }
  670 
  671 
  672 /*
  673  * convert frames to MiB/min string
  674  * should only be used for audio or full disk info
  675  */
  676 void convert_frames2mbminstring(gint frames, gchar *str) {
  677 gint MiB;
  678 gint min;
  679 gint sec;
  680 gint frms;
  681 gint64 tmpsize;
  682 
  683     tmpsize = (gint64)frames * CDDAFRAME;
  684     MiB = (gint) ((gint64)tmpsize >> 20);
  685 
  686     min = frames/(60*75);
  687     sec = (frames%(60*75))/75;
  688     frms = (frames%75);
  689 
  690     g_snprintf(str,MAXLINE,"%d MiB / %d:%02d.%02d min",MiB,min,sec,frms);
  691 }
  692 
  693 
  694 /*
  695  * convert sectors to MiB/min string
  696  * should only be used for data or full disk info
  697  */
  698 void convert_sectors2mbminstring(gint sectors, gchar *str) {
  699 gint MiB;
  700 gint min;
  701 gint sec;
  702 gint frms, frames;
  703 gint64 tmpsize;
  704 
  705     tmpsize = (gint64)sectors * DATASECTORSIZE;
  706     MiB = (gint) ((gint64)tmpsize >> 20);
  707 
  708     frames = (gint) (tmpsize / CDDAFRAME);
  709     min = frames/(60*75);
  710     sec = (frames%(60*75))/75;
  711     frms = (frames%75);
  712 
  713     g_snprintf(str,MAXLINE,"%d MiB / %d:%02d.%02d",MiB,min,sec,frms);
  714 }
  715 
  716 
  717 /*
  718  * convert frames/sectors to MiB string
  719  * note - this is only true for DATA-tracks
  720  */
  721 void convert_frames2mbstring(gint frames, gchar *str) {
  722 gint MiB;
  723 
  724     MiB = frames*(DATASECTORSIZE/1024)/1024;
  725     g_snprintf(str,MAXLINE,"%d MiB",MiB);
  726 }
  727 
  728 
  729 /*
  730  * convert kbytes to MiB string
  731  */
  732 void convert_kbytes2mbstring(gint kbytes, gchar *str) {
  733 gint MiB;
  734 
  735     MiB = kbytes/1024;
  736     g_snprintf(str,MAXLINE,"%d MiB",MiB);
  737 }
  738 
  739 
  740 /*
  741  * convert frames to min string
  742  */
  743 void convert_frames2minstring(gint frames, gchar *str) {
  744 gint min;
  745 gint sec;
  746 gint frms;
  747 
  748     min = frames/(60*75);
  749     sec = (frames%(60*75))/75;
  750     frms = (frames%75);
  751 
  752     g_snprintf(str,MAXLINE,"%d:%02d.%02d",min,sec,frms);
  753 }
  754 
  755 
  756 /*
  757  * Creates a label that is right justified.
  758  * Useful when packing into a table.
  759  */
  760 GtkWidget *rightjust_gtk_label_new(gchar *txt) {
  761 GtkWidget *align;
  762 GtkWidget *label;
  763 
  764     /* create right justify alignment */
  765     align = gtk_alignment_new(1.0,0.5,0,0);
  766     label = gtk_label_new(txt);
  767     gtk_container_add(GTK_CONTAINER(align),label);
  768     gtk_widget_show(label);
  769 
  770     return align;
  771 }
  772 
  773 
  774 /*
  775  * Creates a label that is left justified.
  776  * Useful when packing into a table.
  777  */
  778 GtkWidget *leftjust_gtk_label_new(gchar *txt) {
  779 GtkWidget *align;
  780 GtkWidget *label;
  781 
  782     /* create left justify alignment */
  783     align = gtk_alignment_new(0.0,0.5,0,0);
  784     label = gtk_label_new(txt);
  785     gtk_container_add(GTK_CONTAINER(align),label);
  786     gtk_widget_show(label);
  787 
  788     return align;
  789 }
  790 
  791 
  792 /*
  793  * get some info about our image-file
  794  */
  795 static void analyze_imgfile(gchar *path, gchar *file, GList **retlist) {
  796 struct stat buf;
  797 image_files_t *entry;
  798 gchar tmp[MAXLINE];
  799 gchar volid[MAXLINE];
  800 off_t size;
  801 gint type,readable,isosize;
  802 gint fd;
  803 
  804     strncpy(tmp,path,MAXLINE-strlen(file)-2);
  805     strcat(tmp,"/");
  806     strcat(tmp,file);
  807 
  808     stat(tmp,&buf);
  809 
  810     /* check if regular file or link */
  811     if (S_ISLNK(buf.st_mode) != 1 && S_ISREG(buf.st_mode) != 1) {
  812         /* its not..so ignore */
  813         return;
  814     } 
  815 
  816     /* readable for us? */
  817     fd = open(tmp, O_RDONLY,0);
  818     if (fd == -1) {
  819         readable = 0;
  820     } else {
  821         readable = 1;
  822         close(fd);
  823     }   
  824     
  825     size = (off_t) buf.st_size;
  826 
  827     isosize = 0;
  828 
  829     /* now do some tests about file-contents */
  830     if (strncmp(file+strlen(file)-4,".toc",4) == 0) {
  831         type = 4;
  832     } else if (strncmp(file+strlen(file)-4,".wav",4) == 0) {
  833         /* wav-file */
  834         if (check_wav_file(tmp) == 0) {
  835             /* invalid wav */
  836             type = 2;
  837         } else {
  838             /* valid wav */
  839             type = 1;
  840         }
  841     } else {
  842         /* data-file */
  843         isosize = check_iso_file(-1,tmp,volid,0);
  844         if (isosize == 0) {
  845             /* unknown data */
  846             type = 3;
  847         } else {
  848             /* iso9660 */
  849             type = 0;
  850         }
  851     }
  852 
  853     /* allocate memory and fill structure */
  854     entry = g_new(image_files_t,1);
  855     entry->path = g_strdup(tmp);
  856     entry->mtime = buf.st_mtime;
  857     entry->size = (off_t) size;
  858     entry->type = type;
  859     entry->readable = readable;
  860     entry->from_track = 0;
  861     if (type == 0) {
  862         entry->volname = g_strdup(volid);
  863     } else {
  864         entry->volname = NULL;
  865     }
  866     entry->title = NULL;
  867     entry->artist = NULL;
  868     entry->cddb_ttitle = NULL;
  869     entry->cd_discid = NULL;
  870     
  871     entry->isosize = isosize;
  872     entry->last_session_start = -1;
  873     entry->next_session_start = -1;
  874 
  875     /* find if there is some information in the inf-file */
  876     get_inf_tracktitle(tmp, entry);
  877 
  878     /* add to list */
  879     *retlist = g_list_append(*retlist, entry);
  880 }
  881 
  882 
  883 /*
  884  * scans a directory for files matching the known extensions
  885  * return 0 if ok, 1 on problem
  886  */
  887 gint get_img_files(gchar *path, GList **retlist) {
  888 gchar *img_ext[] = IMG_EXTENSIONS;
  889 struct dirent *ent;
  890 DIR *dir;         
  891 gint i,len,len2;
  892 
  893     dir = opendir(path);
  894 
  895     /* invalid directory */
  896     if (dir == NULL) 
  897         return 1;
  898 
  899     /* scan a directory */
  900     while ( (ent = readdir(dir)) ) {
  901         /* does the extension match? */
  902         for(i = 0; img_ext[i] != NULL; i++) {
  903             len = strlen(img_ext[i]);
  904             len2 = strlen(ent->d_name);
  905 
  906             /* skip too short filenames */
  907             if (len2 < len) continue;
  908 
  909             if (strncasecmp((ent->d_name)+len2-len,img_ext[i],len) == 0) {
  910                 /* we found a match */
  911                 analyze_imgfile(path,ent->d_name,retlist);          
  912             }
  913         }       
  914     }
  915 
  916     closedir(dir);
  917     return 0;
  918 }
  919 
  920 
  921 /*
  922  * print imagelist-memory-structure (debug purpose)
  923  */
  924 void print_imagelist() {
  925 GList *loop;
  926 image_files_t *entry;
  927 
  928     dodebug(2,"--------- imagelist glist ---------\n");
  929     loop = g_list_first(imagelist);
  930     while (loop) {
  931         entry = loop->data;
  932         dodebug(2,"path: %s, %"LL_FORMAT", %d, %d, %d (%d,%d)\n",entry->path,
  933             (gint64)entry->size, entry->type, entry->readable,
  934             entry->isosize, entry->last_session_start, 
  935             entry->next_session_start);
  936         if (entry->volname != NULL) {
  937             dodebug(2, "\tvolname: %s\n", entry->volname);
  938         }
  939 
  940         loop = loop->next;
  941     }   
  942 }
  943 
  944 
  945 /*
  946  * sort the imagelist according to file names
  947  */
  948 void sort_imagelist() {
  949 GList *first, *last, *list1, *list2;
  950 image_files_t *ent1, *ent2, *ent3;
  951 
  952        first = g_list_first(imagelist);
  953        last = g_list_last(imagelist);
  954        for (list1 = first; list1 != last; list1 = list1->next) {
  955                for (list2 = last; list2 != list1; list2 = list2->prev) {
  956                        ent1 = (image_files_t *) list1->data;
  957                        ent2 = (image_files_t *) list2->data;
  958 
  959                        if(strcmp(ent1->path,ent2->path) > 0) {
  960                                ent3 = ent1;
  961                                list1->data = list2->data;
  962                                list2->data = ent3;
  963                        }
  964                }
  965        }
  966 }
  967 
  968 
  969 /*
  970  * search all image-directories and create a list of matching files
  971  * return number of matching files
  972  */
  973 gint scan_imagedirs() {
  974 GList *loop;
  975 gchar tmp[MAXLINE];
  976 image_files_t *entry;
  977 
  978     /* free the old image-list first */
  979     loop = g_list_first(imagelist);
  980     while (loop) {
  981         entry = loop->data;
  982         g_free(entry->path);
  983         g_free(entry->volname);
  984         g_free(entry->title);
  985         g_free(entry->artist);
  986         g_free(entry->cddb_ttitle);
  987             g_free(entry->cd_discid);
  988         g_free(entry);
  989 
  990         loop = loop->next;
  991     }
  992     g_list_free(imagelist);
  993     imagelist = NULL;
  994 
  995     loop = g_list_first(setupdata.image_dirs);
  996     while (loop) {
  997         /* image-dir extracted */
  998         strncpy(tmp,(gchar *)loop->data, MAXLINE);
  999         get_img_files(tmp,&imagelist);
 1000 
 1001         loop = loop->next;
 1002     }
 1003 
 1004     /* sort the image-list */
 1005     sort_imagelist();
 1006 
 1007     /* now we have a complete image-list */
 1008     if (debug) print_imagelist(); 
 1009 
 1010     return (g_list_length(imagelist));
 1011 }
 1012 
 1013 
 1014 /*
 1015  * Fills a string saying what type of disc we are currently handling
 1016  * and also returns a corresponding number for each type of disc.
 1017  * mode = 0: checks the disc in the drive
 1018  * mode = 1: checks trackreadset for writing
 1019  */
 1020 gint determine_disc_type(gchar *type_name, gint mode) {
 1021 gint i;
 1022 gint audio,data;
 1023 gint type_num;
 1024 gchar tmp[MAXLINE];
 1025 GList *loop;
 1026 track_read_param_t *trackparam;
 1027     
 1028     /* unknown type */
 1029     type_num = -1;
 1030 
 1031     /* count tracks */
 1032     audio = 0;
 1033     data = 0;
 1034     trackparam = NULL;
 1035     
 1036     
 1037     if (mode == 0) {
 1038         /* check cdinfo-structure */
 1039         for (i = 0; i < cdinfo.nr_tracks; i++) {
 1040             if (trackinfo[i]->type == 0) {
 1041                 data++;
 1042             } else {
 1043                 audio++;
 1044             }
 1045         }
 1046     } else {
 1047         /* check trackreadset-structure */
 1048         loop = g_list_first(trackreadset.trackparams);
 1049         while(loop) {
 1050             trackparam = loop->data;
 1051             if (trackparam->tracktype == 0) {
 1052                 data++;
 1053             } else {
 1054                 audio++;
 1055             }
 1056 
 1057             loop = loop->next;
 1058         }
 1059         /* now point trackparam back to first track for later use */
 1060         loop = g_list_first(trackreadset.trackparams);
 1061         if (loop) trackparam = loop->data;
 1062         else trackparam = NULL;
 1063     }   
 1064 
 1065     /* pure data-cd */
 1066     if (data == 1 && audio == 0) {
 1067         type_num = 0;
 1068     } else
 1069     /* pure audio-cd */
 1070     if (data == 0 && audio > 0) {
 1071         type_num = 1;
 1072     } else
 1073     /* mixed-mode */
 1074     if (mode == 0 && data == 1 && audio > 0 && trackinfo[0]->type == 0) {
 1075         type_num = 2;
 1076     } else
 1077     if (mode == 1 && data == 1 && audio > 0 && trackparam->tracktype == 0) {
 1078         type_num = 2;
 1079     } else
 1080     /* cd-extra */
 1081     if (mode == 0 && data == 1 && audio > 0 && cdinfo.have_cdextra) {
 1082         type_num = 3;
 1083     } else
 1084     if (mode == 1 && data == 1 && audio > 0 && trackparam->tracktype == 1) {
 1085         /* one data, at least one audio and first track audio */
 1086         type_num = 3;
 1087     } else 
 1088     /* multisession */
 1089     if (data > 1 && audio == 0) {
 1090         type_num = 4;
 1091     } 
 1092 
 1093     /* enough for now */
 1094     switch (type_num) {
 1095     case 0:
 1096         if ((mode == 0 && cdinfo.total_size < 450000) ||
 1097             (mode == 1 && trackreadset.cdsize < 450000)) {
 1098             /* 450000 equals 100:00.00 min */
 1099             strncpy(tmp,_("Data-CD"),MAXLINE);
 1100         } else {
 1101             strncpy(tmp,_("Data-DVD"),MAXLINE);
 1102         }
 1103         break;
 1104     case 1:
 1105         strncpy(tmp,_("Audio-CD"),MAXLINE);
 1106         break;
 1107     case 2:
 1108         strncpy(tmp,_("Mixed-Mode-CD"),MAXLINE);
 1109         break;
 1110     case 3:
 1111         strncpy(tmp,_("CD-Extra"),MAXLINE);
 1112         break;
 1113     case 4:
 1114         strncpy(tmp,_("Multisession-CD"),MAXLINE);
 1115         break;
 1116     default:
 1117         strncpy(tmp,_("Unknown"),MAXLINE);
 1118         break;
 1119     }
 1120 
 1121     /* return value(s) */
 1122     strncpy(type_name,tmp,MAXLINE);
 1123     return (type_num);
 1124 }
 1125 
 1126 
 1127 /*
 1128  * calculate free space dependent of current image-dir setting
 1129  * return free kbytes and kbytes free in biggest imagedir
 1130  */
 1131 gint determine_free_space(gint *biggestfree) {
 1132 gchar tmp[MAXLINE];
 1133 gchar path[MAXLINE];
 1134 GList *loop;
 1135 gint free, getfree;
 1136 gint maxfree;
 1137 
 1138     /* get image-path */
 1139     if (curset.image_index == -1) {
 1140         strncpy(path,"",MAXLINE);
 1141     } else {
 1142         strncpy(path,(gchar *)g_list_nth_data(setupdata.image_dirs,
 1143             curset.image_index), MAXLINE);
 1144 
 1145         /* this dir writeable? */
 1146         if (is_dir_writeable(path) == 1) {
 1147             /* its not */
 1148             *biggestfree = 0;
 1149             return 0;
 1150         }
 1151     }
 1152 
 1153     free = 0;
 1154     maxfree = 0;
 1155     if (strcmp(path,"") != 0) {
 1156         free = get_free_space(path,NULL);
 1157         maxfree = free;
 1158     } else {
 1159         /* automatic setting - add all available space */
 1160         loop = g_list_first(setupdata.image_dirs);
 1161         while(loop) {
 1162             strncpy(tmp,(gchar *)loop->data,MAXLINE);
 1163 
 1164             /* this dir writeable? */
 1165             if (is_dir_writeable(tmp) == 1) {
 1166                 /* no? skip */
 1167                 loop = loop->next;
 1168                 continue;
 1169             }
 1170 
 1171             getfree = get_free_space(tmp,NULL);
 1172             free += getfree;
 1173             /* get biggest block */
 1174             if (getfree > maxfree) 
 1175                 maxfree = getfree;
 1176             loop = loop->next;
 1177         }
 1178     }
 1179 
 1180     if (free < 0) {
 1181         g_warning("Invalid image-path setting?\n");
 1182         free = 0;
 1183         maxfree = 0;
 1184     }
 1185 
 1186     *biggestfree = maxfree;
 1187     return free;
 1188 }
 1189 
 1190 
 1191 /*
 1192  * does look where to save the tracks before reading them. 
 1193  * Checks available disk space and the image-directory-settings.
 1194  * return 0 if ok, 1 on error/disk full, 2 if no writeable dir found
 1195  * and 3 if we are about to overwrite a link,
 1196  * return via call by reference the size (in kbytes) that will be
 1197  * free due overwriting old files. Also return the freed size on
 1198  * the directory with the most space available
 1199  */
 1200 gint allocate_track_filenames(gint *overwrite, gint *overwritebiggest) {
 1201 gchar tmp[MAXLINE];
 1202 gchar biggestpath[MAXLINE];
 1203 gchar path[MAXLINE];
 1204 gchar ext[MAXLINE];
 1205 track_read_param_t *trackparam;
 1206 GList *loop, *loop2;
 1207 gint free;
 1208 gint size, tmpkbyte;
 1209 gint ret;
 1210 image_dir_free_t *freedir;
 1211 GList *freedirs;
 1212 struct stat buf;
 1213 gint overwritefree, overwritefreebiggest;
 1214 gint maxfree;
 1215 
 1216     dodebug(10,"calling allocate_track_filenames\n");
 1217 
 1218     overwritefree = 0;
 1219     overwritefreebiggest = 0;
 1220     ret = 0;
 1221     freedirs = NULL;
 1222     maxfree = 0;
 1223     strcpy(biggestpath,"");
 1224 
 1225     /* build image-path/free structure */
 1226     if (curset.image_index == -1) {
 1227         /* automatic setting */
 1228         loop = g_list_first(setupdata.image_dirs);
 1229         while(loop) {
 1230             strncpy(path,(gchar *)loop->data,MAXLINE);
 1231 
 1232             /* this dir writeable? */
 1233             if (is_dir_writeable(path) == 1) {
 1234                 /* no? skip */
 1235                 loop = loop->next;
 1236                 continue;
 1237             }
 1238             free = get_free_space(path,NULL);
 1239             freedir = g_new(image_dir_free_t,1);
 1240             freedir->path = g_strdup(path);
 1241             freedir->free = free;
 1242             freedirs = g_list_append(freedirs,freedir);
 1243 
 1244             /* path with biggest available block? */
 1245             if (free > maxfree) {
 1246                 maxfree = free;
 1247                 strncpy(biggestpath,path,MAXLINE);
 1248             }   
 1249             loop = loop->next;
 1250         }
 1251         /* no dirs writeable */
 1252         if (freedirs == NULL) {
 1253             *overwrite = 0;
 1254             *overwritebiggest = 0;
 1255             return 2;
 1256         }
 1257     } else {
 1258         /* single path */
 1259         strncpy(path,(gchar *)g_list_nth_data(setupdata.image_dirs,
 1260             curset.image_index), MAXLINE);
 1261         /* this dir writeable? */
 1262         if (is_dir_writeable(path) == 1) {
 1263             *overwrite = 0;
 1264             *overwritebiggest = 0;
 1265             return 2;
 1266         }
 1267         free = get_free_space(path,NULL);
 1268         freedir = g_new(image_dir_free_t,1);
 1269         freedir->path = g_strdup(path);
 1270         freedir->free = free;
 1271         freedirs = g_list_append(freedirs,freedir);
 1272         maxfree = free;
 1273         strncpy(biggestpath,path,MAXLINE);
 1274     }
 1275     /* now we have a structure with all paths we are allowed
 1276        to save data in and how much space is available there */
 1277 
 1278     /* loop through all available tracks */
 1279     loop = g_list_first(trackreadset.trackparams);
 1280     while (loop) {
 1281         trackparam = loop->data;
 1282 
 1283         if (trackparam->tracktype == 0) 
 1284             strcpy(ext,"iso");
 1285         else
 1286             strcpy(ext,"wav");
 1287         
 1288         /* how much space needs this track? */
 1289         size = trackparam->kbyte;
 1290 
 1291         strcpy(path,"");
 1292 
 1293         /* where is enough space for it? */
 1294         loop2 = g_list_first(freedirs);
 1295         while (loop2) {
 1296             freedir = loop2->data;
 1297         
 1298             /* build temporary filename */
 1299             g_snprintf(tmp,MAXLINE, "%s/%s-%02d.%s", freedir->path, 
 1300                 curset.file_prefix,
 1301                 trackparam->starttrack, ext);
 1302 
 1303             /* already a file with this name on hd? */
 1304             if (stat(tmp,&buf) == 0) {
 1305 
 1306                 /* is a link? */
 1307                 if (check_islink(tmp, NULL)) {
 1308                     g_warning("Possibly overwriting a link at %s - not allowed.\n", tmp);
 1309                     return 3;
 1310                 }
 1311 
 1312                 /* file exists */
 1313                 tmpkbyte = (gint) ((off_t)buf.st_size >> 10);
 1314                 if (tmpkbyte == 0) {
 1315                     /* file smaller than one kb? */
 1316                     /* assume 1 kb then */
 1317                     tmpkbyte = 1;
 1318                 }
 1319                 overwritefree += tmpkbyte;
 1320 
 1321                 /* file in directory with most space? */
 1322                 if (strcmp(freedir->path,biggestpath) == 0) {
 1323                     overwritefreebiggest += tmpkbyte;
 1324                 } 
 1325             } else {
 1326                 tmpkbyte = 0;
 1327             }
 1328 
 1329             /* enough free? consider space that is freed
 1330                when we overwrite a file (tmpkbyte) */
 1331             if (size < (freedir->free + tmpkbyte)) {
 1332                 /* found freespace */
 1333                 strncpy(path,freedir->path,MAXLINE);
 1334                 freedir->free-=size - tmpkbyte;
 1335                 break;
 1336             }
 1337  
 1338             loop2 = loop2->next;
 1339         }
 1340     
 1341         /* no free space found? */
 1342         if (strcmp(path,"") == 0) {
 1343             /* mark we found an error */
 1344             ret = 1;
 1345         }
 1346 
 1347         /* tmp does contain now our valid filename */
 1348         g_free(trackparam->trackfile);
 1349         trackparam->trackfile = g_strdup(tmp);
 1350 
 1351         loop = loop->next;
 1352     }
 1353 
 1354     /* free image-path/free structure */
 1355     loop2 = g_list_first(freedirs);
 1356     while (loop2) {
 1357         freedir = loop2->data;
 1358         g_free(freedir->path);
 1359         g_free(freedir);
 1360         loop2 = loop2->next;
 1361     }
 1362     g_list_free(freedirs);
 1363 
 1364     *overwrite = overwritefree;
 1365     *overwritebiggest = overwritefreebiggest;
 1366 
 1367     if (debug > 1) {
 1368         print_trackreadset();
 1369     }
 1370 
 1371     return ret;
 1372 }
 1373 
 1374 
 1375 /*
 1376  * does scan the image-structure for toc-files.
 1377  * Takes current image-dir-setting into account. Return number 
 1378  * of found toc files or 0. Newest file is on top
 1379  */ 
 1380 gint scan_for_toc_files() {
 1381 GList *loop;
 1382 image_files_t *entry;
 1383 gchar basename[MAXLINE];
 1384 gchar ipath[MAXLINE];
 1385 gchar *p;
 1386 time_t fdate;
 1387 
 1388     /* clear old list */
 1389     g_list_free(tocfiles);
 1390     tocfiles = NULL;
 1391     fdate = 0;
 1392 
 1393     loop = g_list_first(imagelist);
 1394     while (loop) {
 1395         entry = loop->data;
 1396 
 1397         /* toc-file */
 1398         if (entry->type == 4) {
 1399         
 1400             /* get the basedir */
 1401             strncpy(basename,entry->path,MAXLINE);
 1402             p = rindex(basename,'/');
 1403             *p = '\0';
 1404             if (strcmp(basename,"") == 0) {
 1405                 strcpy(basename,"/");
 1406             }
 1407         
 1408             /* now check if the basedir fits in the currently
 1409                set image-path */
 1410             if (curset.image_index != -1) {
 1411                 strncpy(ipath, (gchar *)g_list_nth_data(
 1412                     setupdata.image_dirs,
 1413                     curset.image_index), MAXLINE);
 1414 
 1415                 /* does not fit - skip */
 1416                 if (strcmp(ipath, basename) != 0) {
 1417                     loop = loop->next;
 1418                     continue;
 1419                 }
 1420             }
 1421             
 1422             /* if new file newer than the old one */
 1423             if (entry->mtime < fdate) {
 1424                 /* append at back */
 1425                 tocfiles = g_list_append(tocfiles,entry->path);
 1426             } else {
 1427                 /* prepend at front */
 1428                 tocfiles = g_list_prepend(tocfiles,entry->path);
 1429                 fdate = entry->mtime;
 1430             }
 1431         }
 1432 
 1433         loop = loop->next;
 1434     }
 1435 
 1436     return g_list_length(tocfiles);
 1437 }
 1438 
 1439 
 1440 /*
 1441  * this function is called whenever a dialog window idles on the screen
 1442  * and we want that events are processed and if there are no events
 1443  * no CPU-time is wasted
 1444  */
 1445 void wait_and_process_events() {
 1446 
 1447     while (gtk_events_pending())
 1448         gtk_main_iteration();
 1449     usleep(1000);
 1450 }
 1451 
 1452 
 1453 /*
 1454  * check if all files scheduled for writing does exist and have
 1455  * the right size. Return 0 if all ok, 1 if all files there but with
 1456  * wrong size, 2 if files missing and 3 if no permission to read/invalid,
 1457  * 4 when audio files with wrong isrc or mcn found
 1458  */ 
 1459 gint check_write_files(gint nosizecheck) {
 1460 GList *loop;
 1461 track_read_param_t *trackparam;
 1462 struct stat buf;
 1463 off_t size;
 1464 gint sumframes;
 1465 gint fd;
 1466 gint errsize, diff, invalidisrcmcn;
 1467 
 1468     sumframes = 0;
 1469     errsize = 0;
 1470     invalidisrcmcn = 0;
 1471     loop = g_list_first(trackreadset.trackparams);
 1472     while(loop) {
 1473         trackparam = loop->data;
 1474 
 1475         if (stat(trackparam->trackfile, &buf) != 0) {
 1476             /* no such file */
 1477             return 2;
 1478         }
 1479         
 1480         /* check if regular file or link */
 1481         if (S_ISLNK(buf.st_mode) != 1 && S_ISREG(buf.st_mode) != 1) {
 1482             /* its not */
 1483             return 3;
 1484         }
 1485 
 1486         /* readable for us? */
 1487         fd = open(trackparam->trackfile, O_RDONLY,0);
 1488         if (fd == -1) {
 1489             return 3;
 1490         } else {
 1491             close(fd);
 1492         }
 1493 
 1494         if (trackparam->tracktype == 0) {
 1495             /* datatrack */
 1496             size = (off_t) ((off_t)trackparam->frames * DATASECTORSIZE);
 1497             sumframes += trackparam->frames;
 1498         } else {
 1499             /* audiotrack */
 1500 
 1501             /* check if ISRC/MCN info is valid */
 1502             invalidisrcmcn += check_valid_isrc_mcn(trackparam->trackfile);
 1503 
 1504             size = (off_t) ((off_t)trackparam->frames * CDDAFRAME);
 1505             sumframes += trackparam->frames;
 1506         }
 1507 
 1508         /*
 1509          * check size of file - allow an offset of 4096 bytes
 1510          * and an offset of 152*2048 (leadout+runout sectors)
 1511          * (and allow an offset of 44 bytes (wavheader))
 1512          */
 1513         diff = (gint) abs((off_t) size - (off_t) buf.st_size);
 1514         if (diff != 0 && diff != 4096 && diff != 152*2048 && diff != 44) {
 1515             /* a file with wrong size found? */
 1516             errsize++;
 1517         } 
 1518         loop = loop->next;
 1519     }   
 1520     /* g_print("sumframes: %d\n", sumframes); */
 1521 
 1522     if (invalidisrcmcn > 0) {
 1523         return 4;
 1524     }
 1525 
 1526     if (errsize == 0 || nosizecheck) {
 1527         /* all ok */
 1528         return 0;
 1529     } else {
 1530         /* files with wrong sizes */
 1531         return 1;
 1532     }
 1533 }
 1534 
 1535 
 1536 /*
 1537  * correct any problem in an .inf file with an invalid ISRC or MCN number.
 1538  * Return 1 if there was a problem. (like permission denied)
 1539  */
 1540 gint clear_isrc_mcn_from_tracks() {
 1541 GList *loop;
 1542 track_read_param_t *trackparam;
 1543 gint stat;
 1544 
 1545     stat = 0;
 1546     loop = g_list_first(trackreadset.trackparams);
 1547     while(loop) {
 1548         trackparam = loop->data;
 1549 
 1550         if (check_valid_isrc_mcn(trackparam->trackfile)) {
 1551             /* ok, thats one of the bad files */
 1552             stat += clear_isrc_mcn_from_inffile(trackparam->trackfile);
 1553         }
 1554 
 1555         loop = loop->next;
 1556     }
 1557 
 1558     if (stat > 0) {
 1559         return 1;
 1560     } else {
 1561         return 0;
 1562     }
 1563 }
 1564 
 1565 
 1566 /*
 1567  * get the size of a track given by filename from imagelist (in bytes)
 1568  * or -1 when not found
 1569  */
 1570 off_t get_size_from_imagelist(gchar *tname) {
 1571 GList *loop;
 1572 image_files_t *entry;
 1573 
 1574     loop = g_list_first(imagelist);
 1575     while (loop) {
 1576         entry = loop->data;
 1577 
 1578         if (strcmp(tname,entry->path) == 0) {
 1579             return ((off_t) entry->size);
 1580         }
 1581         loop = loop->next;
 1582     }
 1583 
 1584     return (off_t)-1;
 1585 }
 1586 
 1587 
 1588 /*
 1589  * get the type of a track given by filename from imagelist
 1590  * or -1 when not found
 1591  */
 1592 gint get_type_from_imagelist(gchar *tname) {
 1593 GList *loop;
 1594 image_files_t *entry;
 1595 
 1596     loop = g_list_first(imagelist);
 1597     while (loop) {
 1598         entry = loop->data;
 1599 
 1600         if (strcmp(tname,entry->path) == 0) {
 1601             return (entry->type);
 1602         }
 1603         loop = loop->next;
 1604     }
 1605 
 1606     return -1;
 1607 }
 1608 
 1609 
 1610 /*
 1611  * get the number of a track given by filename from imagelist
 1612  * or -1 when not found
 1613  */
 1614 gint get_tracknr_from_imagelist(gchar *tname) {
 1615 GList *loop;
 1616 image_files_t *entry;
 1617 
 1618     loop = g_list_first(imagelist);
 1619     while (loop) {
 1620         entry = loop->data;
 1621 
 1622         if (strcmp(tname,entry->path) == 0) {
 1623             return (entry->from_track);
 1624         }
 1625         loop = loop->next;
 1626     }
 1627 
 1628     return -1;
 1629 }
 1630 
 1631 
 1632 /*
 1633  * get the msinfo values from imagelist
 1634  */
 1635 void get_msinfo_from_imagelist(gchar *tname, gint *nr1, gint *nr2) {
 1636 GList *loop;
 1637 image_files_t *entry;
 1638 
 1639     loop = g_list_first(imagelist);
 1640     while (loop) {
 1641         entry = loop->data;
 1642 
 1643         if (strcmp(tname,entry->path) == 0) {
 1644 
 1645             *nr1 = entry->last_session_start;
 1646             *nr2 = entry->next_session_start;
 1647         }
 1648         loop = loop->next;
 1649     }
 1650 }
 1651 
 1652 
 1653 image_files_t *get_entry_from_imagelist(gchar *tname) {
 1654 GList *loop;
 1655 image_files_t *entry;
 1656 
 1657     loop = g_list_first(imagelist);
 1658     while (loop) {
 1659         entry = loop->data;
 1660 
 1661         if (tname && strcmp(tname,entry->path) == 0) {
 1662             return entry;
 1663         }
 1664         loop = loop->next;
 1665     }
 1666     return NULL;
 1667 }
 1668 
 1669 
 1670 /*
 1671  * get the discid of a track given by filename from imagelist
 1672  * or 1 when not found
 1673  */
 1674 gint get_discid_from_imagelist(gchar *tname, gchar *ret) {
 1675 GList *loop;
 1676 image_files_t *entry;
 1677 
 1678     loop = g_list_first(imagelist);
 1679     while (loop) {
 1680         entry = loop->data;
 1681 
 1682         if (strcmp(tname,entry->path) == 0) {
 1683 
 1684             if (entry->cd_discid == NULL) 
 1685                 return 1;
 1686 
 1687             strcpy(ret, entry->cd_discid);
 1688             return 0;
 1689         }
 1690         loop = loop->next;
 1691     }
 1692 
 1693     return 1;
 1694 }
 1695 
 1696 
 1697 /*
 1698  * get the volname of a track given by filename from imagelist
 1699  * or 1 when not found
 1700  */
 1701 gint get_volname_from_imagelist(gchar *tname, gchar *ret) {
 1702 GList *loop;
 1703 image_files_t *entry;
 1704 
 1705     loop = g_list_first(imagelist);
 1706     while (loop) {
 1707         entry = loop->data;
 1708 
 1709         if (strcmp(tname,entry->path) == 0) {
 1710 
 1711             if (entry->volname == NULL) 
 1712                 return 1;
 1713 
 1714             strcpy(ret, entry->volname);
 1715             return 0;
 1716         }
 1717         loop = loop->next;
 1718     }
 1719 
 1720     return 1;
 1721 }
 1722 
 1723 
 1724 /*
 1725  * is valid wav-file and in cd-quality?
 1726  * return 1 if, 0 if not
 1727  */
 1728 gint check_wav_file(gchar *wavname) {
 1729 gint fd;
 1730 
 1731     fd = open (wavname, O_RDONLY, 0);
 1732     if (fd == -1) {
 1733         return 0;
 1734     }
 1735 
 1736     if (!is_std_wav_file(fd, NULL)) {
 1737         /* no wav at all or not cd-quality */
 1738         close(fd);
 1739         return 0;
 1740     }
 1741 
 1742     /* passed all tests */
 1743     close(fd);
 1744     return 1;
 1745 }
 1746 
 1747 
 1748 /*
 1749  * small thing for iso-check
 1750  */
 1751 static gint empty(gchar c) {
 1752     return (c == 0 || c == ' ');
 1753 }
 1754 
 1755 
 1756 /*
 1757  * check if valid iso9660-image
 1758  * return number of sectors if, 0 if not
 1759  * if isoname set to NULL then query drive directly
 1760  */
 1761 gint check_iso_file(gint devnr, gchar *isoname, gchar *volid, gint startsec) {
 1762 gchar buf[DATASECTORSIZE];
 1763 gchar tmp[MAXLINE];
 1764 gchar c;
 1765 gint i,j,k,count;
 1766 gint volsize;
 1767  
 1768     if (isoname != NULL) {
 1769         /* read from file */
 1770         if (read_info_sector_from_file(isoname,buf,sizeof(buf)) == 0) {
 1771             return 0;
 1772         }
 1773     } else {
 1774         /* read from device */
 1775         if (read_info_sector_from_dev(devnr,buf,sizeof(buf), startsec) == 0) {
 1776             return 0;
 1777         }
 1778     }
 1779 
 1780     /* search iso9660-signature */
 1781     if (strncmp(buf, "\001CD001\001", 8) != 0) {
 1782         return 0;
 1783     }
 1784 
 1785     /* ok, we got an iso9660-image. 
 1786        As a bonus extract volumne-name if requested */
 1787     if (volid != NULL) {
 1788         count = 0;
 1789         for(i = 40; i < 72; i++) {
 1790             if (empty(buf[i]))
 1791                 continue;
 1792             for (j = i+1; j < 72; j++) {
 1793                 if (!buf[j] || (j < 72-1
 1794                 && empty(buf[j]) && empty(buf[j+1])))
 1795                     break;
 1796             }
 1797             for (k = i; k < j; k++) {
 1798                 c = buf[k];
 1799                 if (isprint((gint)c) || isspace((gint)c)) {
 1800                     tmp[count++] = c;           
 1801                 }
 1802             }
 1803             i = j;
 1804         }
 1805         tmp[count] = '\0';
 1806         strcpy(volid,tmp);
 1807     }
 1808 
 1809     /* now also extract the size of the image */
 1810     volsize = ((buf[80] & 0xff) |
 1811           ((buf[81] & 0xff) << 8) |
 1812           ((buf[82] & 0xff) << 16) |
 1813           ((buf[83] & 0xff) << 24)); 
 1814            
 1815     return volsize;
 1816 }
 1817 
 1818 
 1819 /*
 1820  * get cd toc and do read the iso9660-volid if possible
 1821  */
 1822 void get_cd_toc_and_volid(gint devnr) {
 1823 gint i, volsize;
 1824 gchar tmp[MAXLINE];
 1825 GtkWidget *tmpdialog;
 1826 
 1827     /*
 1828      * create dialog, just to grab the focus on it
 1829      * and make xcdroast no longer "clickable"
 1830      */
 1831     tmpdialog = my_gtk_dialog_new();
 1832         gtk_grab_add(tmpdialog);
 1833 
 1834     get_cd_toc(devnr);
 1835 
 1836     gtk_grab_remove(GTK_WIDGET(tmpdialog));
 1837     gtk_widget_destroy(tmpdialog);
 1838     
 1839     /* no disc loaded? */
 1840     if (cdinfo.nr_tracks <= 0) {
 1841         return;
 1842     }
 1843     strcpy(tmp,"");
 1844 
 1845     /* scan every data track */
 1846 #ifdef SCANEVERYTRACK 
 1847     for (i = 0; i < cdinfo.nr_tracks; i++) {
 1848 #else
 1849     for (i = 0; i < 1; i++) {
 1850 #endif
 1851     
 1852         if (trackinfo[i]->type == 0) {
 1853             /* get iso-header for current track */
 1854             strcpy(tmp,"");
 1855             volsize = check_iso_file(devnr, NULL, tmp, 
 1856                 trackinfo[i]->start_sec);   
 1857             if (strcmp(tmp,"") != 0) {
 1858                 g_free(trackinfo[i]->volname);
 1859                 trackinfo[i]->volname = g_strdup(tmp);
 1860             }
 1861             trackinfo[i]->isosize = volsize;
 1862         }
 1863     }
 1864 
 1865     /* now set disc title to iso9660-volname because
 1866        that's all we got at the moment */
 1867 
 1868     /* last label still in buffer? */
 1869     if (strcmp(tmp,"") != 0) {
 1870         /* now check we have currently another title */
 1871         if (cdinfo.cddb_dtitle == NULL || strcmp(cdinfo.cddb_dtitle, tmp) != 0) { 
 1872             /* no? then use iso-header as title */
 1873             cdinfo.title = NULL;
 1874             cdinfo.cddb_dtitle = g_strdup(tmp);
 1875         }
 1876     }   
 1877 }
 1878 
 1879 
 1880 /*
 1881  * do output debug messages
 1882  */
 1883 void dodebug(gint debuglevel, gchar *fmt, ...) {
 1884 va_list ap;
 1885 gchar tmp[MAXLINE*21];
 1886 gchar *p;
 1887 guint i;
 1888 
 1889     /* output message when debuglevel is high enough */
 1890     if (debuglevel <= debug) {
 1891 
 1892         /* put together the variable argument list */
 1893         va_start(ap,fmt);
 1894         vsprintf(tmp, fmt, ap);
 1895         va_end(ap);
 1896     
 1897                 /* remove first linefeed if any */
 1898         p = index(tmp,'\r');
 1899         if (p != NULL) 
 1900                         *p = ' ';
 1901 
 1902         /* remove \b if any */
 1903         for (i = 0; i < strlen(tmp); i++) {
 1904             if (tmp[i] == '\b') {
 1905                 tmp[i] = ' ';
 1906             }
 1907         }
 1908 
 1909         fprintf(stderr,"DBG%d: %s",debuglevel,tmp);
 1910     }
 1911 }
 1912 
 1913 
 1914 /*
 1915  * do write to logfile
 1916  */
 1917 void dolog(gint loglevel, gchar *fmt, ...) {
 1918 va_list ap;
 1919 gchar tmp[MAXLINE*21];  /* two buffers up to 10k plus saveguard */
 1920 gchar tmp2[MAXLINE];
 1921 char timestr[MAXLINE];
 1922 time_t acttime;
 1923 FILE *lfile;
 1924 
 1925     /* output message when loglevel is high enough */
 1926     if (loglevel <= setupdata.loglevel && strcmp(setupdata.logfile,"")) {
 1927 
 1928         /* put together the variable argument list */
 1929         va_start(ap,fmt);
 1930         vsprintf(tmp, fmt, ap);
 1931         va_end(ap);
 1932         
 1933         acttime = time((time_t *) 0);
 1934         strncpy(timestr,ctime(&acttime),MAXLINE);
 1935 
 1936         /* remove last \n from timestr */
 1937         timestr[strlen(timestr)-1] = 0;
 1938 
 1939         strncpy(tmp2, setupdata.logfile,MAXLINE);
 1940         check_tilde(tmp2);
 1941 
 1942         lfile = fopen(tmp2,"a");
 1943 
 1944         if (lfile == NULL) {
 1945             g_warning("Can't open logfile %s for writing\n", 
 1946                 tmp2);
 1947             return;
 1948         }
 1949 
 1950         if (!fprintf(lfile,"%s XCDR %s: %s", timestr,
 1951             XCDROAST_VERSION, tmp)) {
 1952             g_warning("Error appending to logfile\n");
 1953         }
 1954         fclose(lfile);
 1955     }
 1956 }
 1957 
 1958 
 1959 /*
 1960  * notify-beep function:
 1961  * no beep, always, on completion, warnings only
 1962  */
 1963 void dobeep(gint type) {
 1964 gint doit;
 1965 
 1966     doit = 0;
 1967 
 1968     switch (setupdata.notify_at) {
 1969     case 0: 
 1970         /* we want no beep */
 1971         return;
 1972 
 1973     case 1:
 1974         /* always */
 1975         doit = 1;
 1976         break;
 1977     case 2:
 1978         /* on completion */
 1979         if (type == 1) 
 1980             doit = 1;
 1981         break;
 1982     case 3:
 1983         /* warnings only */
 1984         if (type == 2)
 1985             doit = 1;
 1986         break;
 1987     default:
 1988         return;
 1989     }
 1990 
 1991     /* ok..we have to play a sound */
 1992     if (doit == 1) {
 1993         if (setupdata.notify_via == 0) {
 1994             /* dspdevice */
 1995             if (strcmp(setupdata.dsp_device,"") != 0) {
 1996                 test_dspdevice_play();  
 1997             }
 1998         } else {
 1999             /* internal speaker */
 2000             gdk_beep();
 2001         }
 2002     }
 2003 }
 2004 
 2005 
 2006 /*
 2007  * check if the image-dirs fit to our partitions
 2008  * return 0 if ok, 1 when there were errors (and we edited the list)
 2009  */
 2010 gint verify_loaded_config () {
 2011 GList *loop, *loop2;
 2012 GList *fslist;
 2013 gchar dir[MAXLINE];
 2014 gchar fs[MAXLINE];
 2015 gint free;
 2016 gint fsuse;
 2017 gint dirsok;
 2018 
 2019     /*
 2020      * now check if all the loaded image-dirs exist
 2021      * and are each on an own partition
 2022      */
 2023     fslist = NULL;
 2024     dirsok = 0;
 2025     loop = g_list_first(setupdata.image_dirs);
 2026     while (loop) {
 2027         strncpy(dir,(gchar *)loop->data,MAXLINE);
 2028         /* get filesystem for this dir */
 2029         free = get_free_space(dir,fs);
 2030         if (free == -1) {
 2031             /* no such directory */
 2032             /* mark to remove this entry from the list...*/
 2033             g_free(loop->data); 
 2034             loop->data = NULL;
 2035             dirsok = 1;
 2036         } else {
 2037             /* check if this dir is already in use */
 2038             /* if not, add to fs-list */
 2039             fsuse = 0;
 2040             loop2 = g_list_first(fslist);
 2041             while (loop2) {
 2042                 if (strcmp(fs, (gchar *)loop2->data) == 0) {
 2043                     fsuse = 1;
 2044                 }
 2045                 loop2 = loop2->next;
 2046             }   
 2047             if (fsuse == 0) {
 2048                 /* not already used */
 2049                 fslist = g_list_append(fslist, g_strdup(fs));
 2050             } else {
 2051                 /* remove this entry from list */
 2052                 g_free(loop->data); 
 2053                 loop->data = NULL;
 2054                 dirsok = 1;
 2055             }
 2056         }
 2057 
 2058         loop = loop->next;
 2059     }
 2060 
 2061     /* free our temporary list */
 2062     free_glist(&fslist);
 2063 
 2064     /* now really remove the marked dirs from list */
 2065     loop = g_list_first(setupdata.image_dirs);
 2066     while (loop) {
 2067         loop2 = loop->next;
 2068         if (loop->data == NULL) {
 2069             setupdata.image_dirs = 
 2070                 g_list_remove_link(setupdata.image_dirs, loop);
 2071         }
 2072         loop = loop2;
 2073     }
 2074 
 2075     return dirsok;
 2076 }
 2077 
 2078 
 2079 /*
 2080  * check if this track matches the inserted disc (verify tracks)
 2081  * return 0 if all ok, 1 on some error, 2 if file does not match to disc
 2082  * and 3 if we don't want verify audio (checking for readable not necessary 
 2083  * because unreadable tracks are not displayed in verify menu
 2084  */
 2085 gint check_vrfy_track(gchar *fname) {
 2086 gchar tmp[MAXLINE];
 2087 
 2088         /* get the discid */
 2089         if (get_discid_from_imagelist(fname,tmp) != 0) {
 2090                 /* no discid found in info-file? */
 2091                 return 1;
 2092         }
 2093 
 2094         /* compare with current disc */
 2095         if (strcmp(tmp, cdinfo.cddb_discid) != 0) {
 2096                 return 2;
 2097         }
 2098 
 2099     /* check if it's an audio track and we want to verify them */
 2100     if (curset.noaudioverify == 1 && 
 2101         get_type_from_imagelist(fname) == 1) {
 2102         return 3;
 2103     }
 2104         /* all ok */
 2105         return 0;
 2106 }
 2107 
 2108 
 2109 /*
 2110  * build a trackname for image-lists
 2111  */
 2112 void assign_trackname(gchar *titlestr, image_files_t *entry) {
 2113 
 2114                 /* see if there is cd text for this track */
 2115                 if (entry->title && entry->artist &&
 2116                     strcmp(entry->title,"") && strcmp(entry->artist,"")) {
 2117                         g_snprintf(titlestr,MAXLINE,"%s / %s",
 2118                                 entry->title, entry->artist);
 2119                 } else
 2120                 if (entry->title && strcmp(entry->title,"")) {
 2121                         strcpy(titlestr, entry->title);
 2122                 } else
 2123                 if (entry->cddb_ttitle && strcmp(entry->cddb_ttitle,"")) {
 2124                         strcpy(titlestr, entry->cddb_ttitle);
 2125                 } else
 2126                 if (entry->volname && strcmp(entry->volname,"")) {
 2127                         g_snprintf(titlestr,MAXLINE,"%s / ISO9660",
 2128                                 entry->volname);
 2129                 }
 2130 }
 2131 
 2132 
 2133 /*
 2134  * check if a filename is on the writelist
 2135  */
 2136 gint is_on_writelist(gchar *file) {
 2137 GList *loop;
 2138 gchar *track;
 2139 
 2140         loop = g_list_first(writelist);
 2141         while (loop) {
 2142                 track = loop->data;
 2143         if (track && strcmp(track, file) == 0) {
 2144             return 1;
 2145         }
 2146         loop = loop->next;
 2147     }
 2148     return 0;
 2149 }
 2150 
 2151 
 2152 /*
 2153  * free trackreadset
 2154  */
 2155 void clear_trackreadset() {
 2156 GList *loop;
 2157 track_read_param_t *trackparam;
 2158 
 2159         loop = g_list_first(trackreadset.trackparams);
 2160         while (loop) {
 2161                 trackparam = loop->data;
 2162                 g_free(trackparam->trackfile);
 2163                 g_free(trackparam);
 2164                 loop = loop->next;
 2165         }
 2166     if (trackreadset.trackparams)
 2167             g_list_free(trackreadset.trackparams);
 2168         trackreadset.trackparams = NULL;
 2169     g_free(trackreadset.tocfile);
 2170     trackreadset.tocfile = g_strdup("");
 2171     g_free(trackreadset.cdtitle);
 2172     trackreadset.cdtitle = g_strdup("");
 2173     g_free(trackreadset.cd_discid);
 2174     trackreadset.cd_discid = g_strdup("");
 2175         trackreadset.nrtracks = 0;
 2176         trackreadset.cdsize = 0;
 2177 }
 2178 
 2179 
 2180 /*
 2181  * transform coordinates when bigfonts are used
 2182  */
 2183 gint tbf(gint koord) {
 2184 
 2185         if (bigfonts == 1) {
 2186                 return (koord * XCDR_TOPLEVEL_X1)/XCDR_TOPLEVEL_X0;
 2187         } else {
 2188                 return koord;
 2189         }
 2190 }
 2191 
 2192 
 2193 /*
 2194  * sort a glist of strings
 2195  */
 2196 void sort_glist(GList *filelist) {
 2197 GList *first, *last, *list1, *list2;
 2198 gchar *str1, *str2, *str3;
 2199 
 2200         first = g_list_first(filelist);
 2201         last = g_list_last(filelist);
 2202         for (list1 = first; list1 != last; list1 = list1->next) {
 2203                 for (list2 = last; list2 != list1; list2 = list2->prev) {
 2204                         str1 = (gchar *) list1->data;
 2205                         str2 = (gchar *) list2->data;
 2206 
 2207                         if (strcmp (str1, str2) > 0) {
 2208                                 str3 = str1;
 2209                                 list1->data = list2->data;
 2210                                 list2->data = str3;
 2211                         }
 2212                 }
 2213         }
 2214 }
 2215 
 2216 
 2217 /*
 2218  * sort a glist of integers
 2219  */
 2220 void sort_int_glist(GList *intlist) {
 2221 GList *first, *last, *list1, *list2;
 2222 gint int1, int2, int3;
 2223 
 2224         first = g_list_first(intlist);
 2225         last = g_list_last(intlist);
 2226         for (list1 = first; list1 != last; list1 = list1->next) {
 2227                 for (list2 = last; list2 != list1; list2 = list2->prev) {
 2228                         int1 = GPOINTER_TO_INT(list1->data);
 2229                         int2 = GPOINTER_TO_INT(list2->data);
 2230 
 2231                         if (int1 > int2) {
 2232                                 int3 = int1;
 2233                 list1->data = list2->data;
 2234                 list2->data = GINT_TO_POINTER(int3);
 2235                         }
 2236                 }
 2237         }
 2238 }
 2239 
 2240 
 2241 /*
 2242  * determine path for helper apps
 2243  */
 2244 void get_spawn_path(gchar *app, gchar *ret) {
 2245 struct stat buf;
 2246 
 2247     /* when path is with a leading slash (absolute), do nothing */
 2248     if (app[0] == '/') {
 2249         strcpy(ret,app);
 2250         return;
 2251     }
 2252 
 2253     /* otherwise it's relative - add sharedir first */
 2254     g_snprintf(ret,MAXLINE,"%s/%s", sharedir, app);
 2255 
 2256     /* now check if this file does exist */
 2257     if (stat(ret,&buf) != 0) {
 2258         /* it does not, so try the fallback */
 2259         g_snprintf(ret,MAXLINE,"%s/%s", prefixdir, app);
 2260     }
 2261     return;
 2262 }
 2263 
 2264 
 2265 /*
 2266  * reroute a command through the wrapper;
 2267  * cmd is one of "CDRECORD", "MKISOFS", "CDDA2WAV", "READCD";
 2268  * if the cdrtools use localization then the prefix LANG=en is needed
 2269  */
 2270 gchar *get_wrap_path(gchar *cmd, gchar *ret) {
 2271 gchar tmp[MAXLINE];
 2272 
 2273     g_snprintf(tmp,MAXLINE,"%s/%s %s", sharedir, WRAPPER, cmd);
 2274     strncpy(ret, tmp, MAXLINE);
 2275 
 2276     return ret;
 2277 }
 2278 
 2279 
 2280 /*
 2281  * returns the gracetime to use:
 2282  * set to 3 seconds in order to prevent the volume management
 2283  * from interrupting the write process
 2284  */
 2285 gint get_gracetime() {
 2286     return 3;
 2287 }
 2288 
 2289 
 2290 /*
 2291  * find a path with enough space to save a mkisofs-image
 2292  * return 0 if found, 1 on error/disk-full, return 2 if no writeable dir
 2293  * return 3 if we would overwrite a link -> possible exploitable
 2294  * size is given in kbyte
 2295  * return via call by reference the size (in kbytes) that will be
 2296  * free due overwriting old files. Also return the freed size on
 2297  * the directory with the most space available
 2298  */
 2299 gint allocate_master_filename(gint size, gint nr, gchar **return_fname, 
 2300     gint *overwrite, gint *overwritebiggest) {
 2301 gchar tmp[MAXLINE];
 2302 gchar biggestpath[MAXLINE];
 2303 gchar path[MAXLINE];
 2304 GList *freedirs;
 2305 struct stat buf;
 2306 GList *loop, *loop2;
 2307 image_dir_free_t *freedir;
 2308 gint free,maxfree,tmpkbyte;
 2309 gint overwritefree, overwritefreebiggest;
 2310 gint ret;
 2311 
 2312         overwritefree = 0;
 2313         overwritefreebiggest = 0;
 2314         ret = 0;
 2315     freedirs = NULL;
 2316     maxfree = 0;
 2317     strcpy(biggestpath,"");
 2318 
 2319         /* build image-path/free structure */
 2320         if (curset.image_index == -1) {
 2321                 /* automatic setting */
 2322                 loop = g_list_first(setupdata.image_dirs);
 2323                 while(loop) {
 2324                         strncpy(path,(gchar *)loop->data, MAXLINE);
 2325 
 2326             /* this dir writeable? */
 2327             if (is_dir_writeable(path) == 1) {
 2328                 /* no? skip */
 2329                 loop = loop->next;
 2330                 continue;
 2331             }
 2332                         free = get_free_space(path,NULL);
 2333                         freedir = g_new(image_dir_free_t,1);
 2334                         freedir->path = g_strdup(path);
 2335                         freedir->free = free;
 2336                         freedirs = g_list_append(freedirs,freedir);
 2337 
 2338                         /* path with biggest available block? */
 2339                         if (free > maxfree) {
 2340                                 maxfree = free;
 2341                                 strncpy(biggestpath,path,MAXLINE);
 2342                         }       
 2343                         loop = loop->next;
 2344                 }
 2345         /* no dirs writeable */
 2346         if (freedirs == NULL) {
 2347             *overwrite = 0;
 2348             *overwritebiggest = 0;
 2349             return 2;
 2350         }
 2351         } else {
 2352                 /* single path */
 2353                 strncpy(path,(gchar *)g_list_nth_data(setupdata.image_dirs,
 2354                         curset.image_index), MAXLINE);
 2355 
 2356         /* this dir writeable? */
 2357         if (is_dir_writeable(path) == 1) {
 2358             *overwrite = 0;
 2359             *overwritebiggest = 0;
 2360             return 2;
 2361         }
 2362                 free = get_free_space(path,NULL);
 2363                 freedir = g_new(image_dir_free_t,1);
 2364                 freedir->path = g_strdup(path);
 2365                 freedir->free = free;
 2366                 freedirs = g_list_append(freedirs,freedir);
 2367                 maxfree = free;
 2368                 strncpy(biggestpath,path,MAXLINE);
 2369         }
 2370         /* now we have a structure with all paths we are allowed
 2371        to save data in and how much space is available there */
 2372 
 2373     strcpy(path,"");
 2374 
 2375     /* look in which path we have space */
 2376     loop2 = g_list_first(freedirs);
 2377     while (loop2) {
 2378         freedir = loop2->data;
 2379 
 2380         /* build temporary filename */
 2381         g_snprintf(tmp,MAXLINE, "%s/%s-%02d.%s", freedir->path,
 2382             curset.file_prefix, nr, "iso");
 2383 
 2384         /* already a file with this name on hd? */
 2385         if (stat(tmp,&buf) == 0) {
 2386 
 2387             /* is a link? */
 2388             if (check_islink(tmp, NULL)) {
 2389                 g_warning("Possibly overwriting a link at %s - not allowed.\n", tmp);
 2390                 return 3;
 2391             }
 2392 
 2393             /* file exists */
 2394             tmpkbyte = (gint) ((off_t)buf.st_size >> 10);
 2395             if (tmpkbyte == 0) {
 2396                 /* file smaller than one kb? */
 2397                 /* assume 1 kb then */
 2398                 tmpkbyte = 1;
 2399             }
 2400             overwritefree += tmpkbyte;
 2401 
 2402             /* file in directory with most space? */
 2403             if (strcmp(freedir->path,biggestpath) == 0) {
 2404                 overwritefreebiggest += tmpkbyte;
 2405             }
 2406         } else {
 2407             tmpkbyte = 0;
 2408         }
 2409 
 2410         /* enough free? consider space that is freed
 2411            when we overwrite a file (tmpkbyte) */
 2412         if (size < (freedir->free + tmpkbyte)) {
 2413             /* found freespace */
 2414             strncpy(path,freedir->path,MAXLINE);
 2415             freedir->free-=size - tmpkbyte;
 2416             break;
 2417         }
 2418         loop2 = loop2->next;
 2419     }
 2420 
 2421     /* no free space found? */
 2422     if (strcmp(path,"") == 0) {
 2423         ret = 1;
 2424         dodebug(1,"allocate_master_filename: no free space\n");
 2425     } else {
 2426         /* found a file */
 2427         if (return_fname != NULL) {
 2428             g_free(*return_fname);
 2429             *return_fname = g_strdup(tmp);
 2430         }
 2431         dodebug(1,"allocate_master_filename: got %s\n", tmp);
 2432     }
 2433 
 2434         /* free image-path/free structure */
 2435         loop2 = g_list_first(freedirs);
 2436         while (loop2) {
 2437                 freedir = loop2->data;
 2438                 g_free(freedir->path);
 2439                 g_free(freedir);
 2440                 loop2 = loop2->next;
 2441         }
 2442         g_list_free(freedirs);
 2443 
 2444         *overwrite = overwritefree;
 2445         *overwritebiggest = overwritefreebiggest;
 2446 
 2447     return ret;
 2448 }
 2449 
 2450 
 2451 /*
 2452  * checks if the current writer supports
 2453  * SANYO burnproof or something like that
 2454  */
 2455 gint does_support_burnproof(gint devnr) {
 2456 gint i;
 2457 gchar *flags;
 2458 
 2459         i = get_writerreaderdevs_index(devnr);
 2460         if (i == -1)
 2461                 return 0;
 2462 
 2463         flags = writerreaderdevs[i]->writer_flags;
 2464         if (!flags)     
 2465                 return 0;
 2466 
 2467     if (strstr(flags,"BURNFREE"))
 2468         return 1;
 2469 
 2470     return 0;
 2471 }
 2472 
 2473 /*
 2474  * checks if the current writer supports
 2475  * Plextor VariRec
 2476  */
 2477 gint does_support_varirec(gint devnr) {
 2478 gint i;
 2479 gchar *flags;
 2480 
 2481         i = get_writerreaderdevs_index(devnr);
 2482         if (i == -1)
 2483                 return 0;
 2484 
 2485         flags = writerreaderdevs[i]->writer_flags;
 2486         if (!flags)     
 2487                 return 0;
 2488 
 2489     if (strstr(flags,"VARIREC")) 
 2490         return 1;
 2491 
 2492     return 0;
 2493 }
 2494 
 2495 /*
 2496  * checks if the current writer supports
 2497  * Yamaha audiomaster
 2498  */
 2499 gint does_support_audiomaster(gint devnr) {
 2500 gint i;
 2501 gchar *flags;
 2502 
 2503         i = get_writerreaderdevs_index(devnr);
 2504         if (i == -1)
 2505                 return 0;
 2506 
 2507         flags = writerreaderdevs[i]->writer_flags;
 2508         if (!flags)     
 2509                 return 0;
 2510 
 2511     if (strstr(flags,"AUDIOMASTER"))
 2512         return 1;
 2513 
 2514     return 0;
 2515 }
 2516 
 2517 /*
 2518  * checks if the current writer supports
 2519  * forcespeed
 2520  */
 2521 gint does_support_forcespeed(gint devnr) {
 2522 gint i;
 2523 gchar *flags;
 2524 
 2525         i = get_writerreaderdevs_index(devnr);
 2526         if (i == -1)
 2527                 return 0;
 2528 
 2529         flags = writerreaderdevs[i]->writer_flags;
 2530         if (!flags)     
 2531                 return 0;
 2532 
 2533     if (strstr(flags,"FORCESPEED"))
 2534         return 1;
 2535 
 2536     return 0;
 2537 }
 2538 
 2539 
 2540 /*
 2541  * check if a given group-id matches a groupname
 2542  */
 2543 gint match_group_name(gid_t gid, gchar *group) {
 2544 struct group *grp;
 2545     
 2546         /* get structure containing name of group */
 2547         grp = getgrgid(gid);
 2548 
 2549         if (grp && grp->gr_name) {
 2550         dodebug(3,"Matching gid = %d (%s)\n", gid, grp->gr_name);
 2551                 if (strncmp(grp->gr_name,group,strlen(group)) == 0) {
 2552                         /* does match */
 2553                         return 1;
 2554                 }
 2555         }
 2556         return 0;
 2557 }
 2558 
 2559 
 2560 /*
 2561  * return string with group name
 2562  */
 2563 void return_group_name(gid_t gid, gchar *ret) {
 2564 struct group *grp;
 2565     
 2566         /* get structure containing name of group */
 2567         grp = getgrgid(gid);
 2568     
 2569     if (grp && grp->gr_name) {
 2570         strncpy(ret,grp->gr_name,MAXLINE);
 2571         return;
 2572     }
 2573     
 2574     /* unable to get grp name? return id as text */
 2575     g_snprintf(ret,MAXLINE,"%d", (gint) gid);   
 2576     return; 
 2577 }
 2578 
 2579 
 2580 /*
 2581  * return string with username name
 2582  */
 2583 void return_user_name(uid_t uid, gchar *ret) {
 2584 struct passwd *pw;
 2585     
 2586     pw = getpwuid(uid);
 2587     
 2588     if (pw && pw->pw_name) {
 2589         strncpy(ret,pw->pw_name,MAXLINE);
 2590         return;
 2591     }
 2592     
 2593     /* unable to get grp name? return id as text */
 2594     g_snprintf(ret,MAXLINE,"%d", (gint) uid);   
 2595     return; 
 2596 }
 2597 
 2598 
 2599 /*
 2600  * return 1 if a group exists (by group name)
 2601  */
 2602 gint check_group_exists(gchar *name) {
 2603 struct group *grp;
 2604  
 2605     grp = getgrnam(name);
 2606 
 2607     if (grp) 
 2608         return 1;
 2609     else
 2610         return 0;
 2611 }
 2612 
 2613 
 2614 /*
 2615  * parse the alternate device string (if any)
 2616  */
 2617 void parse_alt_devs(gchar *str) {
 2618 gint i;
 2619 gchar *p;
 2620 gchar tmp[MAXLINE];
 2621 
 2622     /* allocate memory */
 2623     alt_scsidevices = g_new0(gchar *,MAXDEVICES);
 2624     i = 0;
 2625 
 2626     if (str == NULL) {
 2627         /* no devices, return */
 2628         return;
 2629     }
 2630 
 2631     dodebug(2,"----- list of manually chosen device names -----\n");
 2632 
 2633     /* get list of devices */
 2634     p = strtok(str,";");
 2635     while (p) {
 2636         strncpy(tmp,p,MAXLINE);
 2637         strip_string(tmp);
 2638 
 2639         alt_scsidevices[i] = g_strdup(tmp);
 2640         dodebug(2,"alt_device: %d - \"%s\"\n",i, tmp);
 2641     
 2642         p = strtok(NULL,";");
 2643         i++;
 2644         if (i >= MAXDEVICES) {
 2645             g_error("Error: More than %d devices given\n",MAXDEVICES);
 2646         }
 2647     }       
 2648 
 2649     return; 
 2650 }
 2651 
 2652 
 2653 /*
 2654  * return the path to the chmod command
 2655  */
 2656 void get_chmod_cmd(gchar *cmd) {
 2657 struct stat buf;
 2658 gchar tmp[MAXLINE], tmp2[MAXLINE];
 2659 gchar *p1;
 2660 
 2661     /* if path is set absolute don't search for it */
 2662     strncpy(tmp, CHMOD, MAXLINE);
 2663     if (tmp[0] == '/') {
 2664         if (stat(CHMOD,&buf) == 0) {
 2665             strncpy(cmd, CHMOD, MAXLINE);
 2666         } else {
 2667             strcpy(cmd,"");
 2668         }
 2669         return;
 2670     }
 2671 
 2672     strncpy(tmp,CHOWNGRPMOD_PATH,MAXLINE);
 2673 
 2674     /* loop through path and try each one */
 2675     p1 = strtok(tmp,":");
 2676     while (p1) {
 2677         g_snprintf(tmp2,MAXLINE,"%s/%s", p1, CHMOD);
 2678         if (stat(tmp2,&buf) == 0) {
 2679             strncpy(cmd, tmp2, MAXLINE);
 2680             return;
 2681         }
 2682         p1 = strtok(NULL,":");
 2683     }
 2684 
 2685     /* not found */
 2686     strcpy(cmd,"");
 2687     return;
 2688 }
 2689 
 2690 
 2691 /*
 2692  * return the path to the chgrp command
 2693  */
 2694 void get_chgrp_cmd(gchar *cmd) {
 2695 struct stat buf;
 2696 gchar tmp[MAXLINE], tmp2[MAXLINE];
 2697 gchar *p1;
 2698 
 2699     /* if path is set absolute don't search for it */
 2700     strncpy(tmp, CHGRP, MAXLINE);
 2701     if (tmp[0] == '/') {
 2702         if (stat(CHGRP,&buf) == 0) {
 2703             strncpy(cmd, CHGRP, MAXLINE);
 2704         } else {
 2705             strcpy(cmd,"");
 2706         }
 2707         return;
 2708     }
 2709 
 2710     strncpy(tmp,CHOWNGRPMOD_PATH,MAXLINE);
 2711 
 2712     /* loop through path and try each one */
 2713     p1 = strtok(tmp,":");
 2714     while (p1) {
 2715         g_snprintf(tmp2,MAXLINE,"%s/%s", p1, CHGRP);
 2716         if (stat(tmp2,&buf) == 0) {
 2717             strncpy(cmd, tmp2, MAXLINE);
 2718             return;
 2719         }
 2720         p1 = strtok(NULL,":");
 2721     }
 2722 
 2723     /* not found */
 2724     strcpy(cmd,"");
 2725     return;
 2726 }
 2727 
 2728 
 2729 /*
 2730  * return the path to the chown command
 2731  */
 2732 void get_chown_cmd(gchar *cmd) {
 2733 struct stat buf;
 2734 gchar tmp[MAXLINE], tmp2[MAXLINE];
 2735 gchar *p1;
 2736 
 2737     /* if path is set absolute don't search for it */
 2738     strncpy(tmp, CHOWN, MAXLINE);
 2739     if (tmp[0] == '/') {
 2740         if (stat(CHOWN,&buf) == 0) {
 2741             strncpy(cmd, CHOWN, MAXLINE);
 2742         } else {
 2743             strcpy(cmd,"");
 2744         }
 2745         return;
 2746     }
 2747 
 2748     strncpy(tmp,CHOWNGRPMOD_PATH,MAXLINE);
 2749 
 2750     /* loop through path and try each one */
 2751     p1 = strtok(tmp,":");
 2752     while (p1) {
 2753         g_snprintf(tmp2,MAXLINE,"%s/%s", p1, CHOWN);
 2754         if (stat(tmp2,&buf) == 0) {
 2755             strncpy(cmd, tmp2, MAXLINE);
 2756             return;
 2757         }
 2758         p1 = strtok(NULL,":");
 2759     }
 2760 
 2761     /* not found */
 2762     strcpy(cmd,"");
 2763     return;
 2764 }
 2765 
 2766 
 2767 /*
 2768  * allocate an entry in the nonrootval-list
 2769  */
 2770 void add_to_nonrootvalues(GList **list, gchar *path, gint uid, gint gid, gint mode) {
 2771 nonroot_flags_t *entry;
 2772 
 2773         entry = g_new0(nonroot_flags_t, 1);
 2774         if (entry) {
 2775                 entry->path = g_strdup(path);
 2776                 entry->uid = (uid_t)uid;
 2777                 entry->gid = (gid_t)gid;
 2778                 entry->mode = (mode_t)mode;
 2779 
 2780                 *list = g_list_append(*list, entry);
 2781         }
 2782 }
 2783 
 2784 
 2785 /*
 2786  * free the nonrootvalues glist
 2787  */
 2788 void free_nonrootvalues(GList **list) {
 2789 GList *loop;
 2790 nonroot_flags_t *entry;
 2791 
 2792     loop = g_list_first(*list);
 2793     while(loop) {
 2794         entry = (nonroot_flags_t *)loop->data;
 2795         g_free(entry->path);
 2796         g_free(entry);
 2797 
 2798         loop = loop->next;      
 2799     }   
 2800     g_list_free(*list);
 2801     *list = NULL;   
 2802 }
 2803 
 2804 
 2805 /*
 2806  * split the DTITLE line from cddb to artist and title
 2807  */
 2808 void get_artist_and_title_from_cddb(gchar *dtitle, gchar *artist, gchar *title) {
 2809 gchar *p;
 2810 gint len;
 2811 
 2812     p = index(dtitle, '/');
 2813     if (p) {
 2814         len = p - dtitle;
 2815         if (len > MAXLINE) 
 2816             len = MAXLINE;
 2817         strncpy(title, dtitle,len);
 2818         title[len] = '\0';  
 2819         strip_string(title);
 2820 
 2821         strncpy(artist, p+1, MAXLINE);
 2822         strip_string(artist);
 2823     } else {
 2824         strncpy(title, dtitle, MAXLINE);
 2825         strip_string(title);
 2826         strcpy(artist,"");
 2827     }
 2828 }
 2829 
 2830 
 2831 /*
 2832  * switch artist <-> title in a cddb string
 2833  */
 2834 void switch_artist_title(gchar *dtitle) {
 2835 gchar title[MAXLINE];
 2836 gchar artist[MAXLINE];
 2837 
 2838     get_artist_and_title_from_cddb(dtitle, title, artist);
 2839     g_snprintf(dtitle, MAXLINE, "%s / %s", title, artist);
 2840 }
 2841 
 2842 
 2843 /*
 2844  * open the xinf-file for the given track and extract artist and title
 2845  * fallback to cddb if no title given
 2846  */
 2847 void get_title_artist_from_xinf(gchar *file, gchar *artist, gchar *title) {
 2848 image_files_t *entry;
 2849 
 2850     entry = g_new(image_files_t,1);
 2851     entry->path = NULL;
 2852     entry->volname = NULL;
 2853     entry->title = NULL;
 2854     entry->artist = NULL;
 2855     entry->cddb_ttitle = NULL;
 2856     entry->cd_discid = NULL;
 2857 
 2858     /* open file and extract data */
 2859     get_inf_tracktitle(file, entry);
 2860 
 2861     if (entry->title && *entry->title) {
 2862         strncpy(title, entry->title, MAXLINE);
 2863     } else {
 2864         /* try cddb title */
 2865         if (entry->cddb_ttitle) {
 2866             strncpy(title, entry->cddb_ttitle, MAXLINE);
 2867         }
 2868     }
 2869     if (entry->artist) {
 2870         strncpy(artist, entry->artist, MAXLINE);
 2871     }
 2872 
 2873     /* free entry again */
 2874         g_free(entry->path);
 2875         g_free(entry->volname);
 2876         g_free(entry->title);
 2877         g_free(entry->artist);
 2878         g_free(entry->cddb_ttitle);
 2879         g_free(entry->cd_discid);
 2880         g_free(entry);
 2881 }
 2882 
 2883 
 2884 /*
 2885  * returns a file name for the tocfile used in the write-tracks dialog
 2886  */
 2887 void generate_tmp_tocfile_name(gchar *tocfile) {
 2888 
 2889     g_snprintf(tocfile, MAXLINE, "%s/xcdr-wrtrk-%d.ttoc",
 2890         TMP_XCDR_DIR, (gint) getpid());
 2891 }
 2892  
 2893 
 2894 /*
 2895  * returns a prefix used in the copy audio on-the-fly dialog
 2896  */
 2897 void generate_tmp_prefix_name(gchar *tmpprefix) {
 2898 
 2899     g_snprintf(tmpprefix, MAXLINE, "%s/xcdr-tmp-%d",
 2900         TMP_XCDR_DIR, (gint) getpid());
 2901 }
 2902  
 2903 
 2904 /*
 2905  * returns a unique filename that is not in use yet
 2906  * or an empty string on error
 2907  */
 2908 void generate_tmp_file_name(gchar *ext, gchar *file1) {
 2909 gchar randchars[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 2910 gint i, done, length, count, ind;
 2911 gchar tmp[MAXLINE];
 2912 gchar fname[MAXLINE];
 2913 struct stat buf;
 2914 
 2915     done = 0;
 2916     count = 0;
 2917     length = strlen(randchars);
 2918 
 2919     /* try 10 times to get a unique filename..then give up */
 2920     while (count < 10) {
 2921         /* gen random string */
 2922         for (i = 0; i < 4; i++) {
 2923                         ind = (gint)((gfloat)length*rand()/(RAND_MAX+1.0)); 
 2924                         tmp[i] = randchars[ind];
 2925                 }
 2926         tmp[4] = '\0';
 2927 
 2928         g_snprintf(fname, MAXLINE, "%s/xcdr%s.%s", TMP_XCDR_DIR,
 2929             tmp,ext);
 2930 
 2931         /* already such a file on the hard disk? */
 2932         if (stat(fname,&buf)) {
 2933             /* no, there isn't - good for us! */
 2934             done = 1;
 2935             break;
 2936         }
 2937         count++;
 2938     }
 2939 
 2940     if (done == 0) {
 2941         strcpy(file1,"");
 2942     } else {
 2943         strncpy(file1,fname,MAXLINE);
 2944     }
 2945 }
 2946 
 2947 
 2948 /*
 2949  * create a 0 byte file
 2950  */
 2951 gint write_empty_file(gchar *fname) {
 2952 FILE *fd;
 2953 
 2954     fd = fopen(fname,"w"); 
 2955     if (!fd) return 1;
 2956 
 2957     dodebug(2,"creating temporary file %s\n", fname);
 2958 
 2959     fclose(fd);
 2960     return 0;
 2961 }
 2962 
 2963 
 2964 /*
 2965  * check if our writer is from sony..needed for some multisession checks
 2966  */
 2967 gint is_a_sony(gint devnr) {
 2968 gchar tmp[MAXLINE];
 2969 
 2970     strcpy(tmp,"");
 2971     convert_devnr2vendor(devnr, tmp);
 2972 
 2973     if (strncasecmp(tmp,"SONY",4) == 0) {
 2974         return 1;
 2975     }
 2976 
 2977     return 0;   
 2978 }
 2979 
 2980 
 2981 /*
 2982  * parse a version id like 1.11a23 into the structure (1.11 is also ok)
 2983  * returns 1 on failure
 2984  */
 2985 gint parse_version_str(gchar *str, version_id_t *ver) {
 2986 gchar tmp[MAXLINE];
 2987 gchar *p,*q,*r;
 2988 
 2989         ver->major = ver->minor = ver->patch = ver->branch = 0;
 2990     ver->devel='h';
 2991 
 2992     strncpy(tmp, str, MAXLINE);
 2993     p = tmp;
 2994     for(p=tmp; (*p != 0) && (!isdigit((int) *p ) );p++); /* scan for first digit */
 2995     if(*p)
 2996         {   
 2997           q = strstr(p,".");
 2998           if(q) /* then there's a minor version number */
 2999           {
 3000             *q++ = 0;
 3001             r = strstr(q,".");
 3002             if(r) /* then there's a second dot - call it branch number */
 3003             {
 3004               *r++ = 0;
 3005               ver->branch = atoi(r);
 3006             }
 3007             ver->minor = atoi(q);
 3008             if(r)q=r; /* skip to after branch number if there was one */
 3009           }
 3010       ver->major = atoi(p);
 3011       if(q)p=q; /* skip to after minor (and maybe branch) */
 3012       for( q=p; (*q != 0) && (isdigit((int) *q ));q++);
 3013       if(*q) 
 3014         ver->devel = tolower(*q++);
 3015       else 
 3016         q=p;
 3017       if(*q)
 3018       {
 3019             if(isdigit((int) *q)) ver->patch = atoi(q);
 3020       }
 3021       return 0;
 3022     }
 3023     return 1;
 3024 }
 3025 
 3026 
 3027 /*
 3028  * compares two version strings. Return -1 when older, 0 when equal 
 3029  * and 1 when newer
 3030  */
 3031 gint compare_versions(gchar *gotversion, gchar *minimal_version) {
 3032 version_id_t ver0, ver1;
 3033 unsigned long bigver0, bigver1;
 3034  
 3035     /* convert version strings into compareable values */
 3036     if (parse_version_str(gotversion, &ver0)) 
 3037         return -1;
 3038     if (parse_version_str(minimal_version, &ver1)) 
 3039         return -1;
 3040 
 3041     /* calculate a big pure numeric version str */
 3042     bigver0 = ver0.major * 10000000 + ver0.minor * 100000 + 
 3043               ver0.branch * 1000 +
 3044           (ver0.devel - 'a') * 100 + ver0.patch;
 3045     bigver1 = ver1.major * 10000000 + ver1.minor * 100000 + 
 3046               ver1.branch * 1000 +
 3047           (ver1.devel - 'a') * 100 + ver1.patch;
 3048 
 3049     if (bigver1 == bigver0) return 0;
 3050     if (bigver1 < bigver0) return 1;
 3051 
 3052     return -1;
 3053 }
 3054 
 3055 
 3056 /*
 3057  * searches a list of directories for the biggest common path
 3058  * compontent  e.g. /home/tn/bla and /home/tn/src  would result in
 3059  * -> /home/tn
 3060  */
 3061 void get_common_path_component(GList *dirs, gchar *common) {
 3062 GList *loop;
 3063 gchar tmp[MAXLINE];
 3064 gchar match[MAXLINE];
 3065 gint i,len;
 3066 gchar *p;
 3067 
 3068     loop = g_list_first(dirs);
 3069     /* init match str */
 3070     strncpy(match, loop->data, MAXLINE);
 3071     while (loop) {
 3072         strncpy(tmp, loop->data, MAXLINE);
 3073 
 3074         /* which str is shorter? */
 3075         if (strlen(tmp) > strlen(match)) {
 3076             len = strlen(match);
 3077         } else {
 3078             len = strlen(tmp);
 3079         }
 3080         for (i = 0; i < len; i++) {
 3081             /* search until mismatch */
 3082             if (tmp[i] != match[i]) {
 3083                 break;
 3084             }
 3085         }
 3086         /* found shortest common path */
 3087         match[i] = '\0';
 3088 
 3089         /* now match again */
 3090         loop = loop->next;
 3091     }
 3092 
 3093     /* match contains now the longest common paths..remove now
 3094        any non directory parts at the end */
 3095     p = rindex(match,'/');
 3096     if (p) {
 3097         *p = '\0';  
 3098     }
 3099     strncpy(common, match, MAXLINE);
 3100 }
 3101 
 3102 
 3103 /*
 3104  * return driveropts string for cdrecord
 3105  * return 1 if varirec is enabled
 3106  */
 3107 gint do_driveropts(gchar *out, gint devnr) {
 3108 gchar tmp[MAXLINE];
 3109 gchar tmp2[MAXLINE];
 3110 gint varirecon;
 3111 
 3112     varirecon = 0;
 3113     strcpy(tmp,"");
 3114     if (does_support_burnproof(devnr)) {
 3115         if (curset.writeburnfree) {
 3116             strcat(tmp,"burnfree");
 3117         } else {
 3118             strcat(tmp,"noburnfree");
 3119         }
 3120     }
 3121     if (does_support_audiomaster(devnr)) {
 3122         if (curset.writeaudiomaster) {
 3123             if (tmp[0] != '\0') 
 3124                 strcat(tmp,",");
 3125             strcat(tmp,"audiomaster");
 3126         }
 3127     }
 3128     if (does_support_forcespeed(devnr)) {
 3129         if (tmp[0] != '\0') 
 3130             strcat(tmp,",");
 3131         if (curset.writeforcespeed) {
 3132             strcat(tmp,"forcespeed");
 3133         } else {
 3134             strcat(tmp,"noforcespeed");
 3135         }
 3136     }
 3137     if (does_support_varirec(devnr)) {
 3138         if (curset.writevarirec < 50) {
 3139             if (tmp[0] != '\0') 
 3140                 strcat(tmp,",");
 3141             g_snprintf(tmp2,MAXLINE,"varirec=%d", curset.writevarirec);
 3142             strcat(tmp,tmp2);
 3143             varirecon = 1;
 3144         }
 3145     }
 3146     
 3147     if (tmp[0] != '\0') {
 3148         /* added some options? */
 3149         strcpy(tmp2, "driveropts=");
 3150         strcat(tmp2, tmp);
 3151     } else {
 3152         strcpy(tmp2,"");
 3153     }
 3154     strncpy(out, tmp2, MAXLINE);
 3155 
 3156     return varirecon;
 3157 }
 3158 
 3159 
 3160 /*
 3161  * return index in writerreaderdevs structure for given devnr
 3162  * -1 when not found
 3163  */
 3164 gint get_writerreaderdevs_index(gint devnr) {
 3165 gint i, found;
 3166 
 3167         i = 0;
 3168     found = 0;
 3169         while(writerreaderdevs[i] != NULL) {
 3170                 if (writerreaderdevs[i]->devnr == devnr) {
 3171             found = 1;
 3172                         break;
 3173                 }
 3174                 i++;
 3175         }
 3176 
 3177     if (found) {
 3178         return i;
 3179     } else {
 3180         return -1;
 3181     }
 3182 }
 3183 
 3184 
 3185 /*
 3186  * return 1 if the device devnr supports the given write mode
 3187  */
 3188 gint writemode_supported(gint mode, gint devnr) {
 3189 gint i;
 3190 gchar *modes;
 3191 
 3192     i = get_writerreaderdevs_index(devnr);
 3193     if (i == -1)
 3194         return 1;
 3195 
 3196     modes = writerreaderdevs[i]->writer_modes;
 3197     if (!modes)     
 3198         return 1;
 3199 
 3200     /* no modes? allow all in this case */
 3201     if (strlen(modes) == 0) 
 3202         return 1;
 3203 
 3204     switch(mode) {
 3205         
 3206         case 0: 
 3207             if (strstr(modes, "DAO"))
 3208                 return 1;
 3209             /* SAO in the middle of the mode string? */
 3210             if (strstr(modes, "SAO "))
 3211                 return 1;
 3212             /* SAO at the end of the string? */
 3213             if (strlen(modes) >= 3 && 
 3214                 strcmp((modes + strlen(modes) - 3), "SAO") == 0) 
 3215                 return 1;
 3216             break;
 3217         case 1:
 3218         case 2:
 3219             if (strstr(modes, "TAO"))
 3220                 return 1;
 3221             break;  
 3222         case 3:
 3223             if (strstr(modes,"RAW/R96R"))
 3224                 return 1;
 3225             break;
 3226         case 4:
 3227             if (strstr(modes,"RAW/R96P"))
 3228                 return 1;
 3229             break;
 3230         case 5:
 3231             if (strstr(modes,"RAW/R16"))
 3232                 return 1;
 3233             break;
 3234         default:
 3235             return 0;
 3236     }
 3237     return 0;
 3238 }
 3239 
 3240 
 3241 /*
 3242  * free all of the current writerreader structure and reset all
 3243  */
 3244 void free_writerreader_data() {
 3245 gint i;
 3246 
 3247         i = 0;
 3248         while(writerreaderdevs[i] != NULL) {
 3249         /* free first string data */
 3250         g_free(writerreaderdevs[i]->devicestr);
 3251         g_free(writerreaderdevs[i]->writer_flags);
 3252         g_free(writerreaderdevs[i]->writer_modes);
 3253 
 3254         g_free(writerreaderdevs[i]);
 3255 
 3256         i++;
 3257         }
 3258 
 3259     g_free(writerreaderdevs);
 3260     writerreaderdevs = NULL;
 3261 
 3262     /* set devicenumbers back to default -1 */
 3263     setupdata.writer_devnr = -1;
 3264     setupdata.reader_devnr = -1;
 3265     curset.writer_devnr = -1;
 3266     curset.reader_devnr = -1;
 3267 
 3268     return;
 3269 }
 3270 
 3271 
 3272 /*
 3273  * remove a device from the structure
 3274  */
 3275 void remove_from_writerreader_data(gint devnr) {
 3276 gint startindex, endindex;
 3277 gint i;
 3278 
 3279     startindex = -1;
 3280     i = 0; 
 3281     while(writerreaderdevs[i] != NULL) {
 3282         if (writerreaderdevs[i]->devnr == devnr) {
 3283             startindex = i;
 3284         }
 3285         i++;
 3286     }
 3287     endindex = i - 1;
 3288 
 3289     if (startindex == -1 || endindex == -1) {
 3290         /* nothing to do */
 3291         return;
 3292     } 
 3293 
 3294     /* erase entry from memory */
 3295     g_free(writerreaderdevs[startindex]->devicestr);
 3296     g_free(writerreaderdevs[startindex]->writer_flags);
 3297     g_free(writerreaderdevs[startindex]->writer_modes);
 3298     g_free(writerreaderdevs[startindex]);
 3299 
 3300     /* shift data to fill empty place */
 3301     for (i = startindex; i < endindex; i++) {
 3302         writerreaderdevs[i] = writerreaderdevs[i+1];
 3303     }
 3304 
 3305     /* last entry is now zero */
 3306     writerreaderdevs[endindex] = NULL;
 3307 
 3308     /* set devicenumbers back to default -1 if required */
 3309     if (setupdata.writer_devnr == devnr) 
 3310         setupdata.writer_devnr = -1;
 3311     if (setupdata.reader_devnr == devnr) 
 3312         setupdata.reader_devnr = -1;
 3313     if (curset.writer_devnr == devnr) 
 3314         curset.writer_devnr = -1;
 3315     if (curset.reader_devnr == devnr) 
 3316         curset.reader_devnr = -1;
 3317 }
 3318 
 3319 
 3320 /*
 3321  * returns the last used index - or -1 if no entries at all
 3322  */
 3323 gint get_last_writerreaderdevs_index() {
 3324 gint count;
 3325 
 3326     count = 0;
 3327         while(writerreaderdevs[count] != NULL) {
 3328                 if (count == MAXDEVICES-1) {
 3329             g_error("To many devices");
 3330                 }
 3331                 count++;
 3332         }
 3333         count--;
 3334 
 3335     return count;
 3336 }
 3337 
 3338 
 3339 /*
 3340  * saves the size of the given window in the burnwindow-geometry
 3341  */
 3342 void store_win_geometry(GtkWidget *win) {
 3343 
 3344         if (setupdata.option_savepos) {
 3345                 gdk_window_get_root_origin(win->window,
 3346                         &setupdata.burnwindow.x, 
 3347                         &setupdata.burnwindow.y);
 3348                 setupdata.burnwindow.width = gdk_window_get_width(win->window);
 3349                 setupdata.burnwindow.height = gdk_window_get_height(win->window);
 3350         } 
 3351 }
 3352 
 3353 
 3354 /*
 3355  * set the size of a given window from burnwindow-geometry
 3356  */
 3357 gint set_win_geometry(GtkWidget *win) {
 3358 gint result;
 3359 
 3360     result = 0;
 3361         if (setupdata.option_savepos && 
 3362              setupdata.burnwindow.width != -1 && 
 3363              setupdata.burnwindow.height != -1 &&
 3364              setupdata.burnwindow.x != -1 &&
 3365              setupdata.burnwindow.y != -1) {
 3366 
 3367         gtk_widget_realize(win);
 3368                 gdk_window_move_resize(win->window,
 3369                         setupdata.burnwindow.x,
 3370                         setupdata.burnwindow.y,
 3371                         setupdata.burnwindow.width,
 3372                         setupdata.burnwindow.height);
 3373         gtk_window_move(GTK_WINDOW(win), 
 3374             setupdata.burnwindow.x,
 3375             setupdata.burnwindow.y);
 3376         result = 1;
 3377         }
 3378 
 3379     return result;
 3380 }
 3381 
 3382 
 3383 /*
 3384  * set or reset the xcdroast title bar for both toplevel and one dialog
 3385  * window - adds a percent counter if requested
 3386  */
 3387 void set_xcdr_title(GtkWidget *dialog, GtkWidget *dialog2, gint val) {
 3388 char tmp[MAXLINE];
 3389 
 3390     if (val >= 0 && val <= 100 && setupdata.option_titleprogress) {
 3391         g_snprintf(tmp, MAXLINE, "%d%% %s %s", val, 
 3392             T_XCDROAST, XCDROAST_VERSION);
 3393     } else {
 3394         g_snprintf(tmp, MAXLINE, "%s %s", 
 3395             T_XCDROAST, XCDROAST_VERSION);
 3396     }   
 3397 
 3398     if (dialog) 
 3399         gtk_window_set_title(GTK_WINDOW(dialog), tmp);
 3400     if (dialog2) 
 3401         gtk_window_set_title(GTK_WINDOW(dialog2), tmp);
 3402 }
 3403 
 3404 
 3405 /*
 3406  * returns the devnr of a given devicestr or -1 when not found
 3407  */
 3408 gint get_writerreaderdevs_index_from_devstr(gchar *devstr) {
 3409 gint count;
 3410 
 3411     count = 0;
 3412         while(writerreaderdevs[count] != NULL) {
 3413         if (strncmp(writerreaderdevs[count]->devicestr, devstr, MAXLINE)== 0) {
 3414             return count;
 3415         }
 3416                 count++;
 3417         }
 3418 
 3419     return -1;
 3420 }
 3421 
 3422 
 3423 /*
 3424  * return whether we have an empty CD-R or DVD-R in the drive
 3425  * we are sure that there IS a medium there - but we don't know which type
 3426  * check only if device is dvdwriter and we have prodvd installed
 3427  */
 3428 gchar *return_media_type(gint devnr) {
 3429 gchar drvflags[MAXLINE], drvmodes[MAXLINE];
 3430 gchar tmp[MAXLINE];
 3431 gint isdvd,i;
 3432 
 3433     isdvd = 0;
 3434     i = get_writerreaderdevs_index(devnr);
 3435 
 3436     if (i >= 0 && curset.isProDVD && writerreaderdevs[i]->is_dvdwriter) {
 3437             if (convert_devnr2busid(devnr,tmp) != 0) {
 3438                     g_error("non existing cdrom?");
 3439             }
 3440         getmodesflags(tmp, drvflags, drvmodes);
 3441 
 3442         /* if drvflags contains the flag DVD we have a DVD loaded */
 3443         if (strstr(drvflags,"DVD ")) {
 3444             isdvd = 1;
 3445         }
 3446     }
 3447     if (isdvd) {
 3448         return _("Empty DVD+-R/RW");
 3449     } else {
 3450         return _("Empty CD-R/RW");
 3451     }
 3452 }
 3453 
 3454 
 3455 /*
 3456  * return please-insert-media text - CD or DVD version
 3457  */
 3458 gchar *pleaseinsertmedia() {
 3459 
 3460         if (curset.cdrtype < 1000) {
 3461         return _("Please insert a CD-R/RW in the CD-Writer.");
 3462     } else {
 3463         return _("Please insert a DVD+-R/RW in the DVD-Writer.");
 3464     }
 3465 }
 3466 
 3467 
 3468 /*
 3469  * return if we can write dvds with the given device
 3470  */
 3471 gint is_dvdwriter(gint devnr) {
 3472 gint i;
 3473 
 3474     i = get_writerreaderdevs_index(devnr);
 3475 
 3476     if (i >= 0 && writerreaderdevs[i]->is_dvdwriter) {
 3477         return 1;
 3478     }
 3479     return 0;
 3480 }
 3481 
 3482 
 3483 /*
 3484  * return a new dialog widget
 3485  */
 3486 GtkWidget *my_gtk_dialog_new() {
 3487 GtkWidget *win;
 3488 
 3489     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 3490     gtk_widget_realize(win);
 3491 
 3492     return(win);
 3493 }
 3494 
 3495 
 3496 /*
 3497  * convert a given string to utf8, when it is not already
 3498  * used for strings we got from the system or from cddb
 3499  */
 3500 gchar *convert_for_gtk2(gchar *str) {
 3501 gchar *utfstr;
 3502 gsize in, out; 
 3503     
 3504     if (g_utf8_validate(str, strlen(str), NULL)) {
 3505         /* we are already uft8? */
 3506         return str;
 3507     }
 3508 
 3509     utfstr = NULL;
 3510     utfstr = g_locale_to_utf8(str, strlen(str), &in, &out, NULL);
 3511 
 3512     if (utfstr) {
 3513         /* overwrite old string with new */
 3514         strncpy(str,utfstr,MAXLINE);
 3515     }
 3516     return str;
 3517 }
 3518 
 3519 
 3520 /*
 3521  * get a filename from an GTK2 widget
 3522  */
 3523 gchar *convert_for_gtk2_filename(gchar *str) {
 3524 
 3525     /* no longer needed? */
 3526     return str;
 3527 }
 3528 
 3529 
 3530 /*
 3531  * return the gtk2 stock icon fitting to our requested self made icon
 3532  */
 3533 gchar *lookup_stock_icon(gchar *icon) {
 3534 
 3535     if (strncmp(icon, ICO_ERROR, MAXLINE) == 0) 
 3536         return GTK_STOCK_DIALOG_ERROR; 
 3537     if (strncmp(icon, ICO_INFO, MAXLINE) == 0) 
 3538         return GTK_STOCK_DIALOG_INFO; 
 3539     if (strncmp(icon, ICO_WARN, MAXLINE) == 0) 
 3540         return GTK_STOCK_DIALOG_WARNING; 
 3541     if (strncmp(icon, ICO_QUEST, MAXLINE) == 0) 
 3542         return GTK_STOCK_DIALOG_QUESTION; 
 3543 
 3544     /* not found? */
 3545     return NULL;
 3546 }
 3547