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

xtools.c

/*
      xtools.c
      27.3.99 tn
*/

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

#include "largefile.h"

#if HAVE_LOCALE_H
#include <locale.h>
#else
# define setlocale(Category, Locale) 
#endif
#include "gettext.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <errno.h>
#include <ctype.h>
#include <grp.h>
#include <pwd.h>

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

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

extern gint debug;
extern writerreader_devices_t **writerreaderdevs;
extern gchar **alt_scsidevices;
extern setup_data_t setupdata;
extern cd_info_t cdinfo;
extern track_info_t **trackinfo;
extern GList *imagelist;
extern current_set_t curset;
extern track_read_set_t trackreadset;
extern GList *tocfiles;
extern GList *writelist;
extern gint bigfonts;
extern gint oldfontcode;
extern gchar sharedir[MAXLINE];
extern gchar prefixdir[MAXLINE];
extern gint c_locale_is_utf8;

void define_tooltip(GtkWidget *widget, gchar *ttext) {
GtkTooltips *tip;

#ifdef YELLOW_TIPS
GdkColor bg;
GtkStyle *style;
#endif
      /* tooltips wanted? */
      if (setupdata.option_tooltips == 0) {
            return;
      }

      tip = gtk_tooltips_new();
      gtk_tooltips_set_tip(tip,widget,ttext,NULL);

      /* set tip color (yellow) */

      /*
      *** Commented by C.W.Huang :
      *** Why set tip color by hand? It should be set by the theme.
      *** Due to an unknown feature or bug of gtk_widget_set_style(),
      *** GdkFont of the tip will be changed so multibyte characters
      *** cannot be displayed correctly!
      */
#ifdef YELLOW_TIPS

      gtk_tooltips_force_window(tip);
      if (!gdk_color_parse(TOOLTIPCOL,&bg)) {
            g_warning("Can't parse color %s\n",TOOLTIPCOL);
            return;
      }
        if (!gdk_color_alloc(gtk_widget_get_colormap(tip->tip_window),&bg)) {
            g_warning("Cant allocate color %s\n",TOOLTIPCOL);
            return;
      }
      style = gtk_style_copy(gtk_widget_get_style(tip->tip_window));
      style->bg[GTK_STATE_NORMAL] = bg;
      gtk_widget_set_style(tip->tip_window, style);
#endif
}


/* sets the font and color for a label widget.
   if color/font is NULL then don't set color/font  */

void set_font_and_color(GtkWidget *widget, gchar *font, gchar *color) {

#if GTK_MAJOR_VERSION < 2
GtkStyle *style;
GdkColor c;
gchar tmp[MAXLINE];
gchar *p;

      style=gtk_style_copy(gtk_widget_get_style(widget));

      if (font != NULL) {
            gdk_font_unref(style->font);

            /* make copy of string, because we use strtok later */
            strncpy(tmp,font,MAXLINE);

            /* for unknown reasons in some locales the fonts do
               not work correcly bold or italic when using fontset */
            if (oldfontcode) {

                  /* now use only the definition up to the first comma */
                  p = strtok(tmp,",");
                  if (p) {                
                        style->font = gdk_font_load(p);
                  } else {
                        style->font = gdk_font_load(font);
                  }
            } else {
                  style->font = gdk_fontset_load(tmp);
            }

            /* check if valid font */
            if (style->font == NULL) {
                  g_warning("Font %s not found\n",tmp);
                  return;
            }
      }

      if (color != NULL) {
            if (!gdk_color_parse(color,&c)) {
                  g_warning("Can't parse color %s\n",color);
                  return;
            }

            if (!gdk_color_alloc(gtk_widget_get_colormap(widget),&c)) {
                  g_warning("Cant allocate color %s\n",color);
                  return;
            }

            style->fg[GTK_STATE_NORMAL] = c;
      }
      
      gtk_widget_set_style(GTK_WIDGET(widget),style);

#else
      /* version for GTK 2 */

gchar *orglabel;
gchar *newlabel;
gint length;

      newlabel = NULL;
      orglabel = (gchar *)gtk_label_get_text(GTK_LABEL(widget));
      
      if (font && strcmp(font, BOLDFONT) == 0 && !color) {
            length = strlen(orglabel) + strlen("<b></b>") + 1;
            newlabel = (gchar *) g_new0(gchar *, length); 
            g_snprintf(newlabel, length, "<b>%s</b>", orglabel);
      }
      if (font && strcmp(font, BIGFONT) == 0 && !color) {
            length = strlen(orglabel) + strlen("<span size=\"xx-large\"></span>") + 1;
            newlabel = (gchar *) g_new0(gchar *, length); 
            g_snprintf(newlabel, length, "<span size=\"xx-large\">%s</span>", orglabel);
      }
      if (color && !font) {
            length = strlen(orglabel) + strlen("<span color=\"\"></span>") + strlen(color) + 1;
            newlabel = (gchar *) g_new0(gchar *, length); 
            g_snprintf(newlabel, length, "<span color=\"%s\">%s</span>", color, orglabel);
      }
      if (font && strcmp(font, BOLDFONT) == 0 && color) {
            length = strlen(orglabel) + strlen("<b><span color=\"\"></span></b>") + strlen(color) + 1;
            newlabel = (gchar *) g_new0(gchar *, length); 
            g_snprintf(newlabel, length, "<b><span color=\"%s\">%s</span></b>", color, orglabel);
      }
      if (font && strcmp(font, BIGFONT) == 0 && color) {
            length = strlen(orglabel) + strlen("<span color=\"\" size=\"xx-large\"></span>") + strlen(color) + 1;
            newlabel = (gchar *) g_new0(gchar *, length); 
            g_snprintf(newlabel, length, "<span color=\"%s\" size=\"xx-large\">%s</span>", color, orglabel);
      }

      if (newlabel) {
            gtk_label_set_text(GTK_LABEL(widget),newlabel); 
            gtk_label_set_use_markup (GTK_LABEL(widget), TRUE);
            g_free(newlabel);
      }
#endif
}


/* set font and color for a frame */

void set_font_and_color_frame(GtkWidget *widget, gchar *font, gchar *color) {

#if GTK_MAJOR_VERSION < 2
      /* gtk1 version is identical to label version */
      set_font_and_color(widget, font, color);
#else

      set_font_and_color(gtk_frame_get_label_widget(GTK_FRAME(widget)), font, color);

#endif
}

/* sets the color for a label widget.
   if color is NULL then don't set color/font  */

void set_labelcolor(GtkWidget *widget, gchar *color) {
GtkStyle *style;
GdkColor c;

      style=gtk_style_copy(gtk_widget_get_style(widget));

      if (color != NULL) {
            if (!gdk_color_parse(color,&c)) {
                  g_warning("Can't parse color %s\n",color);
                  return;
            }

            if (!gdk_color_alloc(gtk_widget_get_colormap(widget),&c)) {
                  g_warning("Cant allocate color %s\n",color);
                  return;
            }

            style->fg[GTK_STATE_NORMAL] = c;
      }
      
      gtk_widget_set_style(GTK_WIDGET(widget),style);
}


/* sets a certain row in a clist to a font */

void set_clist_row_font(GtkCList *clist, gint row, gchar *ffont) {

#if GTK_MAJOR_VERSION < 2
GtkStyle *style;
gchar tmp[MAXLINE];
gchar *p;

      style=gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(clist)));

      /* make copy of string, because we use strtok later */
      strncpy(tmp,ffont,MAXLINE);

      gdk_font_unref(style->font);
      /* for unknown reasons in some locales the fonts do
         not work correcly bold or italic when using fontset */
      if (oldfontcode) {
            /* now use only the definition up to the first comma */
            p = strtok(tmp,",");
            if (p) {                
                  style->font = gdk_font_load(p);
            } else {
                  style->font = gdk_font_load(ffont);
            }
      } else {
            style->font = gdk_fontset_load(tmp);
      }

            /* check if valid font */
            if (style->font == NULL) {
                  g_warning("Font %s not found\n",tmp);
                  return;
            }

      gtk_clist_set_row_style(clist,row,style);
#else
      /* version for GTK 2 */

GtkStyle *style;

      style=gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(clist)));

      if (ffont && strcmp(ffont, SLANTFONT) == 0) {
            pango_font_description_set_style(style->font_desc,
                  PANGO_STYLE_ITALIC);
      }
      if (ffont && strcmp(ffont, BOLDFONT) == 0) {
            pango_font_description_set_weight(style->font_desc, 
                  PANGO_WEIGHT_BOLD);
      }
      
      gtk_clist_set_row_style(clist,row,style);

#endif

}


/* colors a certain row in a clist */

void set_clist_row_color(GtkCList *clist, gint row, gchar *color) {
GtkStyle *style;
GdkColor c;

      style=gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(clist)));

      if (!gdk_color_parse(color,&c)) {
            g_warning("Can't parse color %s\n",color);
            return;
      }

            if (!gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(clist)),&c)) {
            g_warning("Cant allocate color %s\n",color);
            return;
      }
      style->fg[GTK_STATE_NORMAL] = c;

      gtk_clist_set_row_style(clist,row,style);
}


/* return the given font (you have to unref it later) */

GdkFont *get_some_font(gchar *fontstr) {
gchar tmp[MAXLINE];
gchar *p;
GdkFont *font;

      strncpy(tmp,fontstr,MAXLINE);

      if (oldfontcode) {
            /* now use only the definition up to the first comma */
            p = strtok(tmp,",");
            if (p) {                
                  font = gdk_font_load(p); 
                  /* for some reason the defaul fixed font seems not to work - hard core here another font for ancient systems */
      /*          font = gdk_font_load("-*-*-medium-r-normal-*-*-120-*-*-*-*-*-*"); */
            } else {
                  font = gdk_font_load(fontstr);
            }
      } else {
            font = gdk_fontset_load(tmp); 
      }

      return font;
}


/* free a simple glist structure */

void free_glist(GList **list) {
GList *loop;
gchar *dir;

      loop = g_list_first(*list);
      while(loop) {
            dir = loop->data;
            g_free(dir); 
            loop = loop->next;
      }
      g_list_free(*list);
      *list = NULL;     
}


/* copy a simple glist (which has only strings as elements) */

void copy_glist(GList **dst, GList *src) {
GList *loop;
gchar *dir;

      /* clear target list */
      free_glist(dst); 

      loop = g_list_first(src);
      while(loop) {
            dir = loop->data;
            *dst = g_list_append(*dst,g_strdup(dir)); 
            loop = loop->next;
      }
}


/* remove a string-element from a glist */

void del_glist_link(GList **list, gchar *str) {
GList *loop;
gchar *dir;

      if (str == NULL) 
            return;

      loop = g_list_first(*list);
      while(loop) {
            dir = loop->data;
            if (dir && strcmp(str,dir) == 0) {
                  g_free(dir); 
                  *list = g_list_remove_link(*list, loop);
                  return;
            }
            loop = loop->next;
      }
}


/* check if a string-element is in a glist */
/* return 1 if found, 0 if not */

gint check_in_glist(GList **list, gchar *str) {
GList *loop;
gchar *dir;

      if (str == NULL) 
            return 0;

      loop = g_list_first(*list);
      while(loop) {
            dir = loop->data;
            if (dir && strcmp(str,dir) == 0) {
                  return 1;
            }
            loop = loop->next;
      }
      return 0;
}


/* check if a path is in a master-path-glist */
/* return 1 if found, 0 if not */

gint check_in_mstr_glist(GList **list, gchar *str) {
GList *loop;
mstr_redirect_t *mstr;
gchar *dir;

      if (str == NULL) 
            return 0;

      loop = g_list_first(*list);
      while(loop) {
            mstr = (mstr_redirect_t *) loop->data;
            if (mstr) {
                  dir = mstr->mstr_path;
            } else {
                  dir = NULL;
            }
            if (dir && strcmp(str,dir) == 0) {
                  return 1;
            }
            loop = loop->next;
      }
      return 0;
}


/* remove a string-element from a master-glist */
/* if there is a redir-path, remove only this and return */
/* (unless del_both is set, where the whole entry is removed) */
/* del_both == -1, only remove link if possible */

void del_mstr_glist_link(GList **list, gchar *str, gint del_both) {
GList *loop;
mstr_redirect_t *mstr;
gchar *dir;

      if (str == NULL) 
            return;

      loop = g_list_first(*list);
      while(loop) {
            mstr = (mstr_redirect_t *) loop->data;
            if (mstr) {
                  dir = mstr->mstr_path;
            } else {
                  dir = NULL;
            }

            if (dir && strcmp(str,dir) == 0) {
                  /* found link */
                  if (mstr->redir_path) {
                        /* remove redir-path only */
                        g_free(mstr->redir_path);
                        mstr->redir_path = NULL;

                        if (del_both == 0)
                              return;
                  }
                  if (del_both == -1) return;

                  g_free(dir); 
                  g_free(mstr);
                  *list = g_list_remove_link(*list, loop);
                  return;
            }
            loop = loop->next;
      }
}


/* clear a mstr_glist */

void clear_mstr_glist(GList **list) {
GList *loop;
mstr_redirect_t *mstr;

      loop = g_list_first(*list);
      while(loop) {
            mstr = (mstr_redirect_t *) loop->data;
            if (mstr) {
                  if (mstr->mstr_path) 
                        g_free(mstr->mstr_path);
                  if (mstr->redir_path) 
                        g_free(mstr->redir_path);
                  g_free(mstr);
            }
            loop = loop->next;
      }
      g_list_free(*list);
      *list = NULL;     
}


/* add a redir path to the master-glist */

void add_redir_mstr_glist(GList **list, gchar *str, gchar *new) {
GList *loop;
mstr_redirect_t *mstr;
gchar *dir;

      if (str == NULL) 
            return;

      loop = g_list_first(*list);
      while(loop) {
            mstr = (mstr_redirect_t *) loop->data;
            if (mstr) {
                  dir = mstr->mstr_path;
            } else {
                  dir = NULL;
            }
            if (dir && strcmp(str,dir) == 0) {
                  /* found link */
                  if (mstr->redir_path) {
                        /* remove redir-path first */
                        g_free(mstr->redir_path);
                  }
                  /* now set new value */
                  mstr->redir_path = g_strdup(new);
                  return;
            }
            loop = loop->next;
      }
}


/* get a string in the form bla => foo and return only bla */

void extract_mstr_path_from_clist(gchar *in, gchar *out) {
gint found;
guint i;

      if (in == NULL || out == NULL) 
            return;

        if (strlen(in) == 0) {
                strcpy(out,"");
                return;
        }

      found = -1;

      for (i = 0; i < strlen(in)-1; i++) {
            if ((in[i] == '=') && (in[i+1] == '>')) {
                  found = i;
                  break;
            }
      } 

      if (found == -1) {
            /* nothing found - return original string */
            strcpy(out,in);
      } else {
            strncpy(out,in,found);
            out[found] = '\0';
      }
      strip_string(out);

      /* internally we use not utf8, convert back from widget */
      convert_for_gtk2_filename(out);
}


/* get the redir path from the master-glist */

void get_redir_path_from_mstr_glist(GList **list, gchar *str, gchar *ret) {
GList *loop;
mstr_redirect_t *mstr;
gchar *dir;

      if (str == NULL) 
            return;

      loop = g_list_first(*list);
      while(loop) {
            mstr = (mstr_redirect_t *) loop->data;
            if (mstr) {
                  dir = mstr->mstr_path;
            } else {
                  dir = NULL;
            }
            if (dir && strcmp(str,dir) == 0) {
                  /* found link */
                  if (mstr->redir_path) {
                        strcpy(ret, mstr->redir_path);
                  } else {
                        strcpy(ret, "");
                  }
                  return;
            }
            loop = loop->next;
      }
      strcpy(ret, "");
}


/* set scsi-sector-size for a given device */

void set_sectorsize(gint devnr, gint size) {
gint i;

        i = 0;
        while(writerreaderdevs[i] != NULL) {
                if (devnr == writerreaderdevs[i]->devnr) {
                        writerreaderdevs[i]->sector_size = size;
                        return;
                }
                i++;
        }
}


/* get scsi-sector-size for a given device */

gint get_sectorsize(gint devnr) {
gint i;

        i = 0;
        while(writerreaderdevs[i] != NULL) {
                if (devnr == writerreaderdevs[i]->devnr) {
                        return(writerreaderdevs[i]->sector_size);
                }
                i++;
        }
 
        return DATASECTORSIZE;
}


/* convert the devnr to a device-string. return 1 if devnr not found */

gint convert_devnr2devstring(gint devnr, gchar *str) {
gint i;
gchar tmp[MAXLINE];

      i = 0;
      while(writerreaderdevs[i] != NULL) {
            if (devnr == writerreaderdevs[i]->devnr) {
                  if (!writerreaderdevs[i]->devicestr) {
                        g_error("empty device string?");
                  }
                  g_snprintf(tmp,MAXLINE,"%s %s [%s]",
                        writerreaderdevs[i]->vendor, 
                        writerreaderdevs[i]->model,
                        writerreaderdevs[i]->devicestr);
                  strcpy(str,tmp);
                  return 0;
            }
            i++;
      }

      strcpy(str,"");
      return 1;
}


/* convert the devnr to a vendor-string. return 1 if devnr not found */

gint convert_devnr2vendor(gint devnr, gchar *str) {
gint i;

      i = 0;
      while(writerreaderdevs[i] != NULL) {
            if (devnr == writerreaderdevs[i]->devnr) {
                  strcpy(str,writerreaderdevs[i]->vendor);
                  return 0;
            }
            i++;
      }
      strcpy(str,"");
      return 1;
}


/* convert the devnr to a model-string. return 1 if devnr not found */

gint convert_devnr2model(gint devnr, gchar *str) {
gint i;

      i = 0;
      while(writerreaderdevs[i] != NULL) {
            if (devnr == writerreaderdevs[i]->devnr) {
                  strcpy(str,writerreaderdevs[i]->model);
                  return 0;
            }
            i++;
      }
      strcpy(str,"");
      return 1;
}


/* convert the devnr to a bus/id/lun-string. return 1 if devnr not found */

gint convert_devnr2busid(gint devnr, gchar *str) {
gint i;

      i = 0;
      while(writerreaderdevs[i] != NULL) {
            if (devnr == writerreaderdevs[i]->devnr) {
                  if (!writerreaderdevs[i]->devicestr) {
                        g_error("empty device string?");
                  }
                  strncpy(str,
                      writerreaderdevs[i]->devicestr,
                      MAXLINE);
                  convert_escape(str);
                  return 0;
            }
            i++;
      }
      strcpy(str,"");
      return 1;
}


/* save as convert_devnr2busid(), but return with dev= component */

gint convert_devnr2busid_dev(gint devnr, gchar *str) {
gint i;
gchar tmp[MAXLINE];

      i = 0;
      while(writerreaderdevs[i] != NULL) {
            if (devnr == writerreaderdevs[i]->devnr) {
                  if (!writerreaderdevs[i]->devicestr) {
                        g_error("empty device string?");
                  }
                  strncpy(tmp,
                      writerreaderdevs[i]->devicestr,
                      MAXLINE);
                  convert_escape(tmp);
                  g_snprintf(str,MAXLINE,"dev= \"%s\"",tmp);
                  return 0;
            }
            i++;
      }
      strcpy(str,"");
      return 1;
}


/* convert kilobytes to MB/min string */
/* displays MB when using 2048b sectors. min like stored audiotracks on the
   hard drive - this is not correct when displaying the minutesize of DATA
   tracks. */ 

void convert_kbytes2mbminstring(gint kbytes, gchar *str) {
gint mb;
gint min;
gint sec;
gint frames;
gint frms;
gint64 tmpsize;

      mb = kbytes/1024;
      
#if 0
      /* we have a problem here, that we hit gint overflow on
         large values - in this case round a little inexact */
      if (mb < 2000) {
            /* correct value */
            frames = (kbytes*1024)/CDDAFRAME;
      } else {
            /* rounded value */
            frames = (kbytes/CDDAFRAME)*1024;
      }     
#endif
      /* new code using 64 bit values */
      tmpsize = (gint64)kbytes * 1024;
      frames = (gint) ((gint64)tmpsize/CDDAFRAME);
      
      min = frames/(60*75);
      sec = (frames%(60*75))/75;
      frms = (frames%75);
      /* csec = (4*(frames%75)+1)/3; */

      g_snprintf(str,MAXLINE,"%dMB / %d:%02d.%02d",mb,min,sec,frms);
}


/* convert kilobytes to MB/min string */
/* displays MB when using 2048b sectors. min like the size of track after
   burned. The only correct min size display when burning data tracks */ 

void convert_kbytes2mbcorrectminstring(gint kbytes, gchar *str) {
gint mb;
gint min;
gint sec;
gint frames;
gint frms;

      mb = kbytes/1024;
      frames = kbytes/2;      
      min = frames/(60*75);
      sec = (frames%(60*75))/75;
      frms = (frames%75);
      /* csec = (4*(frames%75)+1)/3; */

      g_snprintf(str,MAXLINE,"%dMB / %d:%02d.%02d",mb,min,sec,frms);
}


/* convert frames to MB/min string */
/* should only be used for audio or full disk info */

void convert_frames2mbminstring(gint frames, gchar *str) {
gint mb;
gint min;
gint sec;
gint frms;
gint64 tmpsize;

#if 0
      mb = ((frames/1024)*CDDAFRAME)/1024; 
      /* mb = ((frames/1024)*DATASECTORSIZE)/1024; */
#endif
      /* use 64 bit values */
      tmpsize = (gint64)frames * CDDAFRAME;
      mb = (gint) ((gint64)tmpsize >> 20);

      min = frames/(60*75);
      sec = (frames%(60*75))/75;
      frms = (frames%75);
      /* csec = (4*(frames%75)+1)/3; */

      g_snprintf(str,MAXLINE,"%dMB / %d:%02d.%02d",mb,min,sec,frms);
}


/* convert frames/sectors to MB string */
/* note - this is only true for DATA-tracks */

void convert_frames2mbstring(gint frames, gchar *str) {
gint mb;

      mb = frames*(DATASECTORSIZE/1024)/1024;
      g_snprintf(str,MAXLINE,"%dMB",mb);
}


/* convert kbytes to MB string */

void convert_kbytes2mbstring(gint kbytes, gchar *str) {
gint mb;

      mb = kbytes/1024;
      g_snprintf(str,MAXLINE,"%dMB",mb);
}


/* convert frames to min string */

void convert_frames2minstring(gint frames, gchar *str) {
gint min;
gint sec;
gint frms;

      min = frames/(60*75);
      sec = (frames%(60*75))/75;
      frms = (frames%75);
      /* csec = (4*(frames%75)+1)/3; */

      g_snprintf(str,MAXLINE,"%d:%02d.%02d",min,sec,frms);
}


/* creates a label that is right justified. Useful when
   packing into a table */

GtkWidget *rightjust_gtk_label_new(gchar *txt) {
GtkWidget *align;
GtkWidget *label;

      /* create right justify alignment */
      align = gtk_alignment_new(1.0,0.5,0,0);
      label = gtk_label_new(txt);
      gtk_container_add(GTK_CONTAINER(align),label);
      gtk_widget_show(label);

      return align;
}


/* creates a label that is left justified. Useful when
   packing into a table */

GtkWidget *leftjust_gtk_label_new(gchar *txt) {
GtkWidget *align;
GtkWidget *label;

      /* create left justify alignment */
      align = gtk_alignment_new(0.0,0.5,0,0);
      label = gtk_label_new(txt);
      gtk_container_add(GTK_CONTAINER(align),label);
      gtk_widget_show(label);

      return align;
}


/* get some info about our image-file */

static void analyze_imgfile(gchar *path, gchar *file, GList **retlist) {
struct stat buf;
image_files_t *entry;
gchar tmp[MAXLINE];
gchar volid[MAXLINE];
off_t size;
gint type,readable,isosize;
gint fd;

      strncpy(tmp,path,MAXLINE-strlen(file)-2);
      strcat(tmp,"/");
      strcat(tmp,file);

      stat(tmp,&buf);

      /* check if regular file or link */
      if (S_ISLNK(buf.st_mode) != 1 && S_ISREG(buf.st_mode) != 1) {
            /* its not..so ignore */
            return;
      } 

      /* readable for us? */
      fd = open(tmp, O_RDONLY,0);
      if (fd == -1) {
            readable = 0;
      } else {
            readable = 1;
            close(fd);
      }     
      
      size = (off_t) buf.st_size;

      isosize = 0;

      /* now do some tests about file-contents */
      if (strncmp(file+strlen(file)-4,".toc",4) == 0) {
            type = 4;
      } else if (strncmp(file+strlen(file)-4,".wav",4) == 0) {
            /* wav-file */
            if (check_wav_file(tmp) == 0) {
                  /* invalid wav */
                  type = 2;
            } else {
                  /* valid wav */
                  type = 1;
            }
      } else {
            /* data-file */
            isosize = check_iso_file(-1,tmp,volid,0);
            if (isosize == 0) {
                  /* unknown data */
                  type = 3;
            } else {
                  /* iso9660 */
                  type = 0;
            }
      }

      /* allocate memory and fill structure */
      entry = g_new(image_files_t,1);
      entry->path = g_strdup(tmp);
      entry->mtime = buf.st_mtime;
      entry->size = (off_t) size;
      entry->type = type;
      entry->readable = readable;
      entry->from_track = 0;
      if (type == 0) {
            entry->volname = g_strdup(volid);
      } else {
            entry->volname = NULL;
      }
      entry->title = NULL;
      entry->artist = NULL;
      entry->cddb_ttitle = NULL;
      entry->cd_discid = NULL;
      
      entry->isosize = isosize;
      entry->last_session_start = -1;
      entry->next_session_start = -1;

      /* find if there is some information in the inf-file */
      get_inf_tracktitle(tmp, entry);

      /* add to list */
      *retlist = g_list_append(*retlist, entry);
}


/* scans a directory for files matching the known extensions */
/* return 0 if ok, 1 on problem */

gint get_img_files(gchar *path, GList **retlist) {
gchar *img_ext[] = IMG_EXTENSIONS;
struct dirent *ent;
DIR *dir;         
gint i,len,len2;

      dir = opendir(path);

      /* invalid directory */
      if (dir == NULL) 
            return 1;

      /* scan a directory */
      while ( (ent = readdir(dir)) ) {
            /* does the extension match? */
            for(i = 0; img_ext[i] != NULL; i++) {
                  len = strlen(img_ext[i]);
                  len2 = strlen(ent->d_name);

                  /* skip to short filenames */
                  if (len2 < len) continue;

                  if (strncmp((ent->d_name)+len2-len,img_ext[i],len) == 0) {
                        /* we found a match */
                        analyze_imgfile(path,ent->d_name,retlist);                  
                  }
            }           
      }

      closedir(dir);
      return 0;
}


/* print imagelist-memory-structure (debug purpose) */

void print_imagelist() {
GList *loop;
image_files_t *entry;

      dodebug(2,"--------- imagelist glist ---------\n");
      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;
            dodebug(2,"path: %s, %"LL_FORMAT", %d, %d, %d (%d,%d)\n",entry->path,
                  (gint64)entry->size, entry->type, entry->readable,
                  entry->isosize, entry->last_session_start, 
                  entry->next_session_start);
            if (entry->volname != NULL) {
                  dodebug(2, "\tvolname: %s\n", entry->volname);
            }

            loop = loop->next;
      }     
}


/* sort the imagelist according to file names */

void sort_imagelist() {
GList *first, *last, *list1, *list2;
image_files_t *ent1, *ent2, *ent3;

       first = g_list_first(imagelist);
       last = g_list_last(imagelist);
       for (list1 = first; list1 != last; list1 = list1->next) {
               for (list2 = last; list2 != list1; list2 = list2->prev) {
                       ent1 = (image_files_t *) list1->data;
                       ent2 = (image_files_t *) list2->data;

                       if(strcmp(ent1->path,ent2->path) > 0) {
                               ent3 = ent1;
                               list1->data = list2->data;
                               list2->data = ent3;
                       }
               }
       }
}


/* search all image-directories and create a list of matching files */
/* return number of matching files */

gint scan_imagedirs() {
GList *loop;
gchar tmp[MAXLINE];
image_files_t *entry;

      /* free the old image-list first */
      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;
            g_free(entry->path);
            g_free(entry->volname);
            g_free(entry->title);
            g_free(entry->artist);
            g_free(entry->cddb_ttitle);
            g_free(entry->cd_discid);
            g_free(entry);

            loop = loop->next;
      }
      g_list_free(imagelist);
      imagelist = NULL;

      loop = g_list_first(setupdata.image_dirs);
      while (loop) {
            /* image-dir extracted */
            strncpy(tmp,(gchar *)loop->data, MAXLINE);
            get_img_files(tmp,&imagelist);

            loop = loop->next;
      }

      /* sort the image-list */
      sort_imagelist();

      /* now we have a complete image-list */
      if (debug) print_imagelist(); 

      return (g_list_length(imagelist));
}


/* return a string saying which type of CD we are currently handling */
/* mode = 0: used check cd in drive, mode = 1: check trackreadset for
   writing */

gint determine_cd_type(gchar *ret, gint mode) {
gint i;
gint audio,data;
gint type;
gchar tmp[MAXLINE];
GList *loop;
track_read_param_t *trackparam;
      
      /* unknown type */
      type = -1;

      /* count tracks */
      audio = 0;
      data = 0;
      trackparam = NULL;
      
      
      if (mode == 0) {
            /* check cdinfo-structure */
            for (i = 0; i < cdinfo.nr_tracks; i++) {
                  if (trackinfo[i]->type == 0) {
                        data++;
                  } else {
                        audio++;
                  }
            }
      } else {
            /* check trackreadset-structure */
            loop = g_list_first(trackreadset.trackparams);
            while(loop) {
                  trackparam = loop->data;
                  if (trackparam->tracktype == 0) {
                        data++;
                  } else {
                        audio++;
                  }

                  loop = loop->next;
            }
            /* now point trackparam back to first track for later use */
            loop = g_list_first(trackreadset.trackparams);
            if (loop) trackparam = loop->data;
            else trackparam = NULL;
      }     

      /* pure data-cd */
      if (data == 1 && audio == 0) {
            type = 0;
      } else
      /* pure audio-cd */
      if (data == 0 && audio > 0) {
            type = 1;
      } else
      /* mixed-mode */
      if (mode == 0 && data == 1 && audio > 0 && trackinfo[0]->type == 0) {
            type = 2;
      } else
      if (mode == 1 && data == 1 && audio > 0 && trackparam->tracktype == 0) {
            type = 2;
      } else
      /* cd-extra */
      if (mode == 0 && data == 1 && audio > 0 && cdinfo.have_cdextra) {
            type = 3;
      } else
      if (mode == 1 && data == 1 && audio > 0 && trackparam->tracktype == 1) {
            /* one data, at least one audio and first track audio */
            type = 3;
      } else 
      /* multisession */
      if (data > 1 && audio == 0) {
            type = 4;
      } 

      /* enough for now */
      switch (type) {
      case 0:
            if ((mode == 0 && cdinfo.total_size < 450000) ||
                (mode == 1 && trackreadset.cdsize < 450000)) {
                  strncpy(tmp,_("Data-CD"),MAXLINE);
            } else {
                  strncpy(tmp,_("Data-DVD"),MAXLINE);
            }
            break;
      case 1:
            strncpy(tmp,_("Audio-CD"),MAXLINE);
            break;
      case 2:
            strncpy(tmp,_("Mixed-Mode-CD"),MAXLINE);
            break;
      case 3:
            strncpy(tmp,_("CD-Extra"),MAXLINE);
            break;
      case 4:
            strncpy(tmp,_("Multisession-CD"),MAXLINE);
            break;
      default:
            strncpy(tmp,_("Unknown"),MAXLINE);
            break;
      }

      /* return value */
      strncpy(ret,tmp,MAXLINE);
      return (type);
}


/* calculate free space dependent of current image-dir setting */
/* return free kbytes and kbytes free in biggest imagedir */

gint determine_free_space(gint *biggestfree) {
gchar tmp[MAXLINE];
gchar path[MAXLINE];
GList *loop;
gint free, getfree;
gint maxfree;

      /* get image-path */
      if (curset.image_index == -1) {
            strncpy(path,"",MAXLINE);
      } else {
            strncpy(path,(gchar *)g_list_nth_data(setupdata.image_dirs,
                  curset.image_index), MAXLINE);

            /* this dir writeable? */
            if (is_dir_writeable(path) == 1) {
                  /* its not */
                  *biggestfree = 0;
                  return 0;
            }
      }

      free = 0;
      maxfree = 0;
      if (strcmp(path,"") != 0) {
            free = get_free_space(path,NULL);
            maxfree = free;
      } else {
            /* automatic setting - add all available space */
            loop = g_list_first(setupdata.image_dirs);
            while(loop) {
                  strncpy(tmp,(gchar *)loop->data,MAXLINE);

                  /* this dir writeable? */
                  if (is_dir_writeable(tmp) == 1) {
                        /* no? skip */
                        loop = loop->next;
                        continue;
                  }

                  getfree = get_free_space(tmp,NULL);
                  free += getfree;
                  /* get biggest block */
                  if (getfree > maxfree) 
                        maxfree = getfree;
                  loop = loop->next;
            }
      }

      if (free < 0) {
            g_warning("Invalid image-path setting?\n");
            free = 0;
            maxfree = 0;
      }

      *biggestfree = maxfree;
      return free;
}


/* does look where to save the tracks before reading them. 
   Checks available diskspace and the image-directory-settings.
   return 0 if ok, 1 on error/disk full, 2 if no writeable dir found */
/* return 3 if we are about to overwrite a link */
/* return via call by reference the size (in kbytes) that will be
   free due overwriting old files. Also return the freed size on
   the directory with the most space available */

gint allocate_track_filenames(gint *overwrite, gint *overwritebiggest) {
gchar tmp[MAXLINE];
gchar biggestpath[MAXLINE];
gchar path[MAXLINE];
gchar ext[MAXLINE];
track_read_param_t *trackparam;
GList *loop, *loop2;
gint free;
gint size, tmpkbyte;
gint ret;
image_dir_free_t *freedir;
GList *freedirs;
struct stat buf;
gint overwritefree, overwritefreebiggest;
gint maxfree;

      dodebug(10,"calling allocate_track_filenames\n");

      overwritefree = 0;
      overwritefreebiggest = 0;
      ret = 0;
      freedirs = NULL;
      maxfree = 0;
      strcpy(biggestpath,"");

      /* build image-path/free structure */
      if (curset.image_index == -1) {
            /* automatic setting */
            loop = g_list_first(setupdata.image_dirs);
            while(loop) {
                  strncpy(path,(gchar *)loop->data,MAXLINE);

                  /* this dir writeable? */
                  if (is_dir_writeable(path) == 1) {
                        /* no? skip */
                        loop = loop->next;
                        continue;
                  }
                  free = get_free_space(path,NULL);
                  freedir = g_new(image_dir_free_t,1);
                  freedir->path = g_strdup(path);
                  freedir->free = free;
                  freedirs = g_list_append(freedirs,freedir);

                  /* path with biggest available block? */
                  if (free > maxfree) {
                        maxfree = free;
                        strncpy(biggestpath,path,MAXLINE);
                  }     
                  loop = loop->next;
            }
            /* no dirs writeable */
            if (freedirs == NULL) {
                  *overwrite = 0;
                  *overwritebiggest = 0;
                  return 2;
            }
      } else {
            /* single path */
            strncpy(path,(gchar *)g_list_nth_data(setupdata.image_dirs,
                  curset.image_index), MAXLINE);
            /* this dir writeable? */
            if (is_dir_writeable(path) == 1) {
                  *overwrite = 0;
                  *overwritebiggest = 0;
                  return 2;
            }
            free = get_free_space(path,NULL);
            freedir = g_new(image_dir_free_t,1);
            freedir->path = g_strdup(path);
            freedir->free = free;
            freedirs = g_list_append(freedirs,freedir);
            maxfree = free;
            strncpy(biggestpath,path,MAXLINE);
      }
      /* now we have a structure with all path we are allowed to 
         save data in and how much space is available there */

      /* loop through all available tracks */
      loop = g_list_first(trackreadset.trackparams);
      while (loop) {
            trackparam = loop->data;

            if (trackparam->tracktype == 0) 
                  strcpy(ext,"iso");
            else
                  strcpy(ext,"wav");
            
            /* how much space needs this track? */
            size = trackparam->kbyte;

            strcpy(path,"");

            /* where is enough space for it? */
            loop2 = g_list_first(freedirs);
            while (loop2) {
                  freedir = loop2->data;
            
                  /* build temporary filename */
                  g_snprintf(tmp,MAXLINE, "%s/%s-%02d.%s", freedir->path, 
                        curset.file_prefix,
                        trackparam->starttrack, ext);

                  /* already a file with this name on hd? */
                  if (stat(tmp,&buf) == 0) {

                        /* is a link? */
                        if (check_islink(tmp, NULL)) {
                              g_warning("Possibly overwriting a link at %s - not allowed.\n", tmp);
                              return 3;
                        }

                        /* file exists */
                        tmpkbyte = (gint) ((off_t)buf.st_size >> 10);
                        if (tmpkbyte == 0) {
                              /* file smaller than one kb? */
                              /* assume 1 kb then */
                              tmpkbyte = 1;
                        }
                        overwritefree += tmpkbyte;

                        /* file in directory with most space? */
                        if (strcmp(freedir->path,biggestpath) == 0) {
                              overwritefreebiggest += tmpkbyte;
                        } 
                  } else {
                        tmpkbyte = 0;
                  }

                  /* enough free? consider space that is freed
                     when we overwrite a file (tmpkbyte) */
                  if (size < (freedir->free + tmpkbyte)) {
                        /* found freespace */
                        strncpy(path,freedir->path,MAXLINE);
                        freedir->free-=size - tmpkbyte;
                        break;
                  }
 
                  loop2 = loop2->next;
            }
      
            /* no free space found? */
            if (strcmp(path,"") == 0) {
                  /* mark we found an error */
                  ret = 1;
            }

            /* tmp does contain now our valid filename */
            g_free(trackparam->trackfile);
            trackparam->trackfile = g_strdup(tmp);

            loop = loop->next;
      }

      /* free image-path/free structure */
      loop2 = g_list_first(freedirs);
      while (loop2) {
            freedir = loop2->data;
            g_free(freedir->path);
            g_free(freedir);
            loop2 = loop2->next;
      }
      g_list_free(freedirs);

      *overwrite = overwritefree;
      *overwritebiggest = overwritefreebiggest;

      if (debug > 1) {
            print_trackreadset();
      }

      return ret;
}


/* does scan the image-structure for toc-files.
   Takes current image-dir-setting into account. Return number 
   of found toc files or 0. Newest file is on top */ 

gint scan_for_toc_files() {
GList *loop;
image_files_t *entry;
gchar basename[MAXLINE];
gchar ipath[MAXLINE];
gchar *p;
time_t fdate;

      /* clear old list */
      g_list_free(tocfiles);
      tocfiles = NULL;
      fdate = 0;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            /* toc-file */
            if (entry->type == 4) {
            
                  /* get the basedir */
                  strncpy(basename,entry->path,MAXLINE);
                  p = rindex(basename,'/');
                  *p = '\0';
                  if (strcmp(basename,"") == 0) {
                        strcpy(basename,"/");
                  }
            
                  /* now check if the basedir fits in the currently
                     set image-path */
                  if (curset.image_index != -1) {
                        strncpy(ipath, (gchar *)g_list_nth_data(
                              setupdata.image_dirs,
                              curset.image_index), MAXLINE);

                        /* does not fit - skip */
                        if (strcmp(ipath, basename) != 0) {
                              loop = loop->next;
                              continue;
                        }
                  }
                  
                  /* if new file newer than the old one */
                  if (entry->mtime < fdate) {
                        /* append at back */
                        tocfiles = g_list_append(tocfiles,entry->path);
                  } else {
                        /* prepend at front */
                        tocfiles = g_list_prepend(tocfiles,entry->path);
                        fdate = entry->mtime;
                  }
            }

            loop = loop->next;
      }

      return g_list_length(tocfiles);
}


/* this function is called whenever a dialog window idles on the screen
   and we want that events are processed and if there are no events
   no CPU-time is wasted */

void wait_and_process_events() {

      while (gtk_events_pending())
            gtk_main_iteration();
      usleep(100);
}


/* check if all files scheduled for writing does exist and have
   the right size. Return 0 if all ok, 1 if all files there but with
   wrong size, 2 if files missing and 3 if no permission to read/invalid,
   4 when audio files with wrong isrc or mcn found */ 

gint check_write_files(gint nosizecheck) {
GList *loop;
track_read_param_t *trackparam;
struct stat buf;
off_t size;
gint sumframes;
gint fd;
gint errsize, diff, invalidisrcmcn;

      sumframes = 0;
      errsize = 0;
      invalidisrcmcn = 0;
      loop = g_list_first(trackreadset.trackparams);
      while(loop) {
            trackparam = loop->data;

            if (stat(trackparam->trackfile, &buf) != 0) {
                  /* no such file */
                  return 2;
            }
            
            /* check if regular file or link */
            if (S_ISLNK(buf.st_mode) != 1 && S_ISREG(buf.st_mode) != 1) {
                  /* its not */
                  return 3;
            }

            /* readable for us? */
            fd = open(trackparam->trackfile, O_RDONLY,0);
            if (fd == -1) {
                  return 3;
            } else {
                  close(fd);
            }

            if (trackparam->tracktype == 0) {
                  /* datatrack */
                  size = (off_t) ((off_t)trackparam->frames * DATASECTORSIZE);
                  sumframes += trackparam->frames;
            } else {
                  /* audiotrack */

                  /* check if ISRC/MCN info is valid */
                  invalidisrcmcn += check_valid_isrc_mcn(trackparam->trackfile);

                  size = (off_t) ((off_t)trackparam->frames * CDDAFRAME);
                  sumframes += trackparam->frames;
            }

            /* check size of file - allow a offset of 4096 bytes */
            /* and offset of 152*2048 (leadout+runout sectors) */
            /* (and allow offset of 44 bytes (wavheader)) */
            diff = (gint) abs((off_t) size - (off_t) buf.st_size);
            if (diff != 0 && diff != 4096 && diff != 152*2048 && diff != 44) {
                  /* a file with wrong size found? */
                  errsize++;
            } 
            loop = loop->next;
      }     
      /* g_print("sumframes: %d\n", sumframes); */

      if (invalidisrcmcn > 0) {
            return 4;
      }

      if (errsize == 0 || nosizecheck) {
            /* all ok */
            return 0;
      } else {
            /* files with wrong sizes */
            return 1;
      }
}


/* correct any problem in an .inf file with an invalid ISRC or MCN number.
   Return 1 if there was a problem. (like permission denied) */

gint clear_isrc_mcn_from_tracks() {
GList *loop;
track_read_param_t *trackparam;
gint stat;

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

            if (check_valid_isrc_mcn(trackparam->trackfile)) {
                  /* ok, thats one of the bad files */
                  stat += clear_isrc_mcn_from_inffile(trackparam->trackfile);
            }

            loop = loop->next;
      }

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


/* get the size of a track given by filename from imagelist (in bytes) */ 
/* or -1 when not found */

off_t get_size_from_imagelist(gchar *tname) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (strcmp(tname,entry->path) == 0) {
                  return ((off_t) entry->size);
            }
            loop = loop->next;
      }

      return (off_t)-1;
}


/* get the type of a track given by filename from imagelist */ 
/* or -1 when not found */

gint get_type_from_imagelist(gchar *tname) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (strcmp(tname,entry->path) == 0) {
                  return (entry->type);
            }
            loop = loop->next;
      }

      return -1;
}


/* get the number of a track given by filename from imagelist */ 
/* or -1 when not found */

gint get_tracknr_from_imagelist(gchar *tname) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (strcmp(tname,entry->path) == 0) {
                  return (entry->from_track);
            }
            loop = loop->next;
      }

      return -1;
}


/* get the msinfo values from imagelist */

void get_msinfo_from_imagelist(gchar *tname, gint *nr1, gint *nr2) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (strcmp(tname,entry->path) == 0) {

                  *nr1 = entry->last_session_start;
                  *nr2 = entry->next_session_start;
            }
            loop = loop->next;
      }
}


image_files_t *get_entry_from_imagelist(gchar *tname) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (tname && strcmp(tname,entry->path) == 0) {
                  return entry;
            }
            loop = loop->next;
      }
      return NULL;
}


/* get the discid of a track given by filename from imagelist */ 
/* or 1 when not found */

gint get_discid_from_imagelist(gchar *tname, gchar *ret) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (strcmp(tname,entry->path) == 0) {

                  if (entry->cd_discid == NULL) 
                        return 1;

                  strcpy(ret, entry->cd_discid);
                  return 0;
            }
            loop = loop->next;
      }

      return 1;
}


/* get the volname of a track given by filename from imagelist */ 
/* or 1 when not found */

gint get_volname_from_imagelist(gchar *tname, gchar *ret) {
GList *loop;
image_files_t *entry;

      loop = g_list_first(imagelist);
      while (loop) {
            entry = loop->data;

            if (strcmp(tname,entry->path) == 0) {

                  if (entry->volname == NULL) 
                        return 1;

                  strcpy(ret, entry->volname);
                  return 0;
            }
            loop = loop->next;
      }

      return 1;
}


/* is valid wav-file and in cd-quality? */
/* return 1 if, 0 if not */

gint check_wav_file(gchar *wavname) {
guchar waveHdr[44];
gint fd;

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

      read(fd, &waveHdr, sizeof(waveHdr));

      if (!is_std_wav_file(waveHdr)) {
            /* no wav at all */
            close(fd);
            return 0;
      }

      /* is it in cd-quality? */
      if (!is_in_cd_quality(waveHdr)) {
            close(fd);
            return 0;
      }

      /* passed all tests */
      close(fd);
      return 1;
}


/* small thing for iso-check */

static gint empty(gchar c) {
      return (c == 0 || c == ' ');
}


/* check if valid iso9660-image */
/* return number of sectors if, 0 if not */
/* if isoname set to NULL then query drive directly */

gint check_iso_file(gint devnr, gchar *isoname, gchar *volid, gint startsec) {
gchar buf[DATASECTORSIZE];
gchar tmp[MAXLINE];
gchar c;
gint i,j,k,count;
gint volsize;
 
      if (isoname != NULL) {
            /* read from file */
            if (read_info_sector_from_file(isoname,buf,sizeof(buf)) == 0) {
                  return 0;
            }
      } else {
            /* read from device */
            if (read_info_sector_from_dev(devnr,buf,sizeof(buf), startsec) == 0) {
                  return 0;
            }
      }

      /* search iso9660-signature */
      if (strncmp(buf, "\001CD001\001", 8) != 0) {
            return 0;
      }

      /* ok, we got an iso9660-image. 
         As a bonus extract volumne-name if requested */
      if (volid != NULL) {
            count = 0;
            for(i = 40; i < 72; i++) {
                  if (empty(buf[i]))
                        continue;
                  for (j = i+1; j < 72; j++) {
                        if (!buf[j] || (j < 72-1
                        && empty(buf[j]) && empty(buf[j+1])))
                              break;
                  }
                  for (k = i; k < j; k++) {
                        c = buf[k];
                        if (isprint((gint)c) || isspace((gint)c)) {
                              tmp[count++] = c;             
                        }
                  }
                  i = j;
            }
            tmp[count] = '\0';
            strcpy(volid,tmp);
      }

      /* now also extract the size of the image */
      volsize = ((buf[80] & 0xff) |
              ((buf[81] & 0xff) << 8) |
              ((buf[82] & 0xff) << 16) |
              ((buf[83] & 0xff) << 24)); 
               
      return volsize;
}


/* get cd toc and do read the iso9660-volid if possible */

void get_cd_toc_and_volid(gint devnr) {
gint i, volsize;
gchar tmp[MAXLINE];
GtkWidget *tmpdialog;

      /* create dialog, just to grab the focus on it and make
         xcdroast not longer "clickable" */
      tmpdialog = my_gtk_dialog_new();
        gtk_grab_add(tmpdialog);

      get_cd_toc(devnr);

      gtk_grab_remove(GTK_WIDGET(tmpdialog));
      gtk_widget_destroy(tmpdialog);
      
      /* no cd loaded? */
      if (cdinfo.nr_tracks <= 0) {
            return;
      }
      strcpy(tmp,"");

      /* scan every data track */
#ifdef SCANEVERYTRACK 
      for (i = 0; i < cdinfo.nr_tracks; i++) {
#else
      for (i = 0; i < 1; i++) {
#endif
      
            if (trackinfo[i]->type == 0) {
                  /* get iso-header for current track */
                  strcpy(tmp,"");
                  volsize = check_iso_file(devnr, NULL, tmp, 
                        trackinfo[i]->start_sec);     
                  if (strcmp(tmp,"") != 0) {
                        g_free(trackinfo[i]->volname);
                        trackinfo[i]->volname = g_strdup(tmp);
                  }
                  trackinfo[i]->isosize = volsize;
            }
      }

      /* now set disk-title to iso9660-volname because thats all we
         got at the moment */

      /* last label still in buffer? */
      if (strcmp(tmp,"") != 0) {
            /* now check we have currently another title */
            if (cdinfo.cddb_dtitle == NULL) { 
                  /* no? then use iso-header as title */
                  cdinfo.cddb_dtitle = g_strdup(tmp);
            }
      }     
}


/* do output debug messages */

void dodebug(gint debuglevel, gchar *fmt, ...) {
va_list ap;
gchar tmp[MAXLINE*21];
gchar *p;
guint i;

      /* output message when debuglevel is high enough */
      if (debuglevel <= debug) {

            /* put together the variable argument list */
            va_start(ap,fmt);
            vsprintf(tmp, fmt, ap);
            va_end(ap);
      
                /* remove first linefeed if any */
            p = index(tmp,'\r');
            if (p != NULL) 
                        *p = ' ';

            /* remove \b if any */
            for (i = 0; i < strlen(tmp); i++) {
                  if (tmp[i] == '\b') {
                        tmp[i] = ' ';
                  }
            }

            fprintf(stderr,"DGB%d: %s",debuglevel,tmp);
      }
}


/* do write to logfile */

void dolog(gint loglevel, gchar *fmt, ...) {
va_list ap;
gchar tmp[MAXLINE*21];  /* two buffers up to 10k plus saveguard */
gchar tmp2[MAXLINE];
char timestr[MAXLINE];
time_t acttime;
FILE *lfile;

      /* output message when loglevel is high enough */
      if (loglevel <= setupdata.loglevel && strcmp(setupdata.logfile,"")) {

            /* put together the variable argument list */
            va_start(ap,fmt);
            vsprintf(tmp, fmt, ap);
            va_end(ap);
            
            acttime = time((time_t *) 0);
            strncpy(timestr,ctime(&acttime),MAXLINE);

            /* remove last \n from timestr */
            timestr[strlen(timestr)-1] = 0;

            strncpy(tmp2, setupdata.logfile,MAXLINE);
            check_tilde(tmp2);

            lfile = fopen(tmp2,"a");

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

            if (!fprintf(lfile,"%s XCDR %s: %s", timestr,
                  XCDROAST_VERSION, tmp)) {
                  g_warning("Error appending to logfile\n");
            }
            fclose(lfile);
      }
}


/* notify-beep function */
/* type: 1 = completed task, 2 = warnings */

void dobeep(gint type) {
gint doit;

      doit = 0;

      switch (setupdata.notify_at) {
      case 0: 
            /* we want no beep */
            return;

      case 1:
            /* always */
            doit = 1;
            break;
      case 2:
            /* on completion */
            if (type == 1) 
                  doit = 1;
            break;
      case 3:
            /* warnings only */
            if (type == 2)
                  doit = 1;
            break;
      default:
            return;
      }

      /* ok..we have to play a sound */
      if (doit == 1) {
            if (setupdata.notify_via == 0) {
                  /* dspdevice */
                  if (strcmp(setupdata.dsp_device,"") != 0) {
                        test_dspdevice_play();  
                  }
            } else {
                  /* internal speaker */
                  gdk_beep();
            }
      }
}


/* check if the image-dirs fit to our partitions */
/* return 0 if ok, 1 when there were errors (and we edited the list) */

gint verify_loaded_config2 () {
GList *loop, *loop2;
GList *fslist;
gchar dir[MAXLINE];
gchar fs[MAXLINE];
gint free;
gint fsuse;
gint dirsok;

      /* now check if all the loaded image-dir exists and are each on
         a own partition */

      fslist = NULL;
      dirsok = 0;
      loop = g_list_first(setupdata.image_dirs);
      while (loop) {
            strncpy(dir,(gchar *)loop->data,MAXLINE);
            /* get filesystem for this dir */
            free = get_free_space(dir,fs);
            if (free == -1) {
                  /* no such directory */
                  /* mark to remove this entry from the list...*/
                  g_free(loop->data); 
                  loop->data = NULL;
                  dirsok = 1;
            } else {
                  /* check if this dir is already in use */
                  /* if not, add to fs-list */
                  fsuse = 0;
                  loop2 = g_list_first(fslist);
                  while (loop2) {
                        if (strcmp(fs, (gchar *)loop2->data) == 0) {
                              fsuse = 1;
                        }
                        loop2 = loop2->next;
                  }     
                  if (fsuse == 0) {
                        /* not already used */
                        fslist = g_list_append(fslist, g_strdup(fs));
                  } else {
                        /* remove this entry from list */
                        g_free(loop->data); 
                        loop->data = NULL;
                        dirsok = 1;
                  }
            }

            loop = loop->next;
      }

      /* free our temporary list */
      free_glist(&fslist);

      /* now really remove the marked dirs from list */
      loop = g_list_first(setupdata.image_dirs);
      while (loop) {
            loop2 = loop->next;
            if (loop->data == NULL) {
                  setupdata.image_dirs = 
                        g_list_remove_link(setupdata.image_dirs, loop);
            }
            loop = loop2;
      }

      return dirsok;
}


/* check if this track match the inserted cd (verify tracks) */
/* return 0 if all ok, 1 on some error, 2 if file does not match to cd
   and 3 if we dont want verify audio (checking for readable not necessary 
   because unreadable tracks are not displayed in verify menu */

gint check_vrfy_track(gchar *fname) {
gchar tmp[MAXLINE];

        /* get the discid */
        if (get_discid_from_imagelist(fname,tmp) != 0) {
                /* no discid found in info-file? */
                return 1;
        }

        /* compare with current cd */
        if (strcmp(tmp, cdinfo.cddb_discid) != 0) {
                return 2;
        }

      /* check if its an audio track and we want to verify them */
      if (curset.noaudioverify == 1 && 
            get_type_from_imagelist(fname) == 1) {
            return 3;
      }
        /* all ok */
        return 0;
}


/* build a trackname for image-lists */

void assign_trackname(gchar *titlestr, image_files_t *entry) {

                /* see if there is cd text for this track */
                if (entry->title && entry->artist &&
                    strcmp(entry->title,"") && strcmp(entry->artist,"")) {
                        g_snprintf(titlestr,MAXLINE,"%s / %s",
                                entry->title, entry->artist);
                } else
                if (entry->title && strcmp(entry->title,"")) {
                        strcpy(titlestr, entry->title);
                } else
                if (entry->cddb_ttitle && strcmp(entry->cddb_ttitle,"")) {
                        strcpy(titlestr, entry->cddb_ttitle);
                } else
                if (entry->volname && strcmp(entry->volname,"")) {
                        g_snprintf(titlestr,MAXLINE,"%s / ISO9660",
                                entry->volname);
                }
}


/* check if a filename is on the writelist */

gint is_on_writelist(gchar *file) {
GList *loop;
gchar *track;

        loop = g_list_first(writelist);
        while (loop) {
                track = loop->data;
            if (track && strcmp(track, file) == 0) {
                  return 1;
            }
            loop = loop->next;
      }
      return 0;
}


/* free trackreadset */

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

        loop = g_list_first(trackreadset.trackparams);
        while (loop) {
                trackparam = loop->data;
                g_free(trackparam->trackfile);
                g_free(trackparam);
                loop = loop->next;
        }
      if (trackreadset.trackparams)
            g_list_free(trackreadset.trackparams);
        trackreadset.trackparams = NULL;
      g_free(trackreadset.tocfile);
      trackreadset.tocfile = g_strdup("");
      g_free(trackreadset.cdtitle);
      trackreadset.cdtitle = g_strdup("");
      g_free(trackreadset.cd_discid);
      trackreadset.cd_discid = g_strdup("");
        trackreadset.nrtracks = 0;
        trackreadset.cdsize = 0;
}


/* transform coordinates when bigfonts are used */

gint tbf(gint koord) {

        if (bigfonts == 1) {
                return (koord * XCDR_TOPLEVEL_X1)/XCDR_TOPLEVEL_X0;
        } else {
                return koord;
        }
}


/* sort a glist of strings */

void sort_glist(GList *filelist) {
GList *first, *last, *list1, *list2;
gchar *str1, *str2, *str3;

        first = g_list_first(filelist);
        last = g_list_last(filelist);
        for (list1 = first; list1 != last; list1 = list1->next) {
                for (list2 = last; list2 != list1; list2 = list2->prev) {
                        str1 = (gchar *) list1->data;
                        str2 = (gchar *) list2->data;

                        if (strcmp (str1, str2) > 0) {
                                str3 = str1;
                                list1->data = list2->data;
                                list2->data = str3;
                        }
                }
        }
}


/* sort a glist of integers */

void sort_int_glist(GList *intlist) {
GList *first, *last, *list1, *list2;
gint int1, int2, int3;

        first = g_list_first(intlist);
        last = g_list_last(intlist);
        for (list1 = first; list1 != last; list1 = list1->next) {
                for (list2 = last; list2 != list1; list2 = list2->prev) {
                        int1 = GPOINTER_TO_INT(list1->data);
                        int2 = GPOINTER_TO_INT(list2->data);

                        if (int1 > int2) {
                                int3 = int1;
/*
                                GPOINTER_TO_INT(list1->data) = 
                              GPOINTER_TO_INT(list2->data);
                                GPOINTER_TO_INT(list2->data) = int3;
*/
                        list1->data = list2->data;
                        list2->data = GINT_TO_POINTER(int3);
                        }
                }
        }
}


/* determine path for helper apps */

void get_spawn_path(gchar *app, gchar *ret) {
struct stat buf;

      /* when path is with a leading slash (absolute), do nothing */
      if (app[0] == '/') {
            strcpy(ret,app);
            return;
      }

      /* otherwise its relative - add sharedir first */
      g_snprintf(ret,MAXLINE,"%s/%s", sharedir, app);

      /* now check if this file does exist */
      if (stat(ret,&buf) != 0) {
            /* it does not, so try the fallback */
            g_snprintf(ret,MAXLINE,"%s/%s", prefixdir, app);
      }
      return;
}


/* reroute a command through the wrapper */
/* cmd is one of "CDRECORD", "MKISOFS", "CDDA2WAV", "READCD" 
   or "CDRECORDPRODVD" */

gchar *get_wrap_path(gchar *cmd, gchar *ret) {
gchar tmp[MAXLINE];

      g_snprintf(tmp,MAXLINE,"%s/%s %s", sharedir, WRAPPER, cmd);
      strncpy(ret, tmp, MAXLINE);

      return ret;
}

/* reroute the cdrecord command through the wrapper */
/* determine automatically if proDVD version is needed or not */

gchar *get_wrap_path_cdrecord(gchar *ret) {
gchar tmp[MAXLINE];

      /* use DVD version if installed and media type > 1GB */
      if (curset.isProDVD && curset.cdrtype > 1000) {
            g_snprintf(tmp,MAXLINE,"%s/%s %s", sharedir, WRAPPER, 
                  "CDRECORDPRODVD");
      } else {
            g_snprintf(tmp,MAXLINE,"%s/%s %s", sharedir, WRAPPER, 
                  "CDRECORD");
      }
      strncpy(ret, tmp, MAXLINE);

      return ret;
}


/* returns the gracetime to use */

gint get_gracetime() {

      if (curset.isProDVD && curset.cdrtype > 1000) {
            /* use 10 seconds for prodvd, because the keycheck
               can take a while... */
            return 10;
      } else {
            /* for normal version 2 seconds is enough */
            return 2;
      }
}


/* find a path with enough space to save a mkisofs-image */
/* return 0 if found, 1 on error/disk-full, return 2 if no writeable dir */
/* return 3 if we would overwrite a link -> possible exploitable */
/* size is given in kbyte */
/* return via call by reference the size (in kbytes) that will be
   free due overwriting old files. Also return the freed size on
   the directory with the most space available */

gint allocate_master_filename(gint size, gint nr, gchar **return_fname, 
      gint *overwrite, gint *overwritebiggest) {
gchar tmp[MAXLINE];
gchar biggestpath[MAXLINE];
gchar path[MAXLINE];
GList *freedirs;
struct stat buf;
GList *loop, *loop2;
image_dir_free_t *freedir;
gint free,maxfree,tmpkbyte;
gint overwritefree, overwritefreebiggest;
gint ret;

        overwritefree = 0;
        overwritefreebiggest = 0;
        ret = 0;
      freedirs = NULL;
      maxfree = 0;
      strcpy(biggestpath,"");

        /* build image-path/free structure */
        if (curset.image_index == -1) {
                /* automatic setting */
                loop = g_list_first(setupdata.image_dirs);
                while(loop) {
                        strncpy(path,(gchar *)loop->data, MAXLINE);

                  /* this dir writeable? */
                  if (is_dir_writeable(path) == 1) {
                        /* no? skip */
                        loop = loop->next;
                        continue;
                  }
                        free = get_free_space(path,NULL);
                        freedir = g_new(image_dir_free_t,1);
                        freedir->path = g_strdup(path);
                        freedir->free = free;
                        freedirs = g_list_append(freedirs,freedir);

                        /* path with biggest available block? */
                        if (free > maxfree) {
                                maxfree = free;
                                strncpy(biggestpath,path,MAXLINE);
                        }       
                        loop = loop->next;
                }
            /* no dirs writeable */
            if (freedirs == NULL) {
                  *overwrite = 0;
                  *overwritebiggest = 0;
                  return 2;
            }
        } else {
                /* single path */
                strncpy(path,(gchar *)g_list_nth_data(setupdata.image_dirs,
                        curset.image_index), MAXLINE);

            /* this dir writeable? */
            if (is_dir_writeable(path) == 1) {
                  *overwrite = 0;
                  *overwritebiggest = 0;
                  return 2;
            }
                free = get_free_space(path,NULL);
                freedir = g_new(image_dir_free_t,1);
                freedir->path = g_strdup(path);
                freedir->free = free;
                freedirs = g_list_append(freedirs,freedir);
                maxfree = free;
                strncpy(biggestpath,path,MAXLINE);
        }
        /* now we have a structure with all path we are allowed to 
           save data in and how much space is available there */

      strcpy(path,"");

      /* look in which path we have space */
      loop2 = g_list_first(freedirs);
      while (loop2) {
            freedir = loop2->data;

            /* build temporary filename */
            g_snprintf(tmp,MAXLINE, "%s/%s-%02d.%s", freedir->path,
                  curset.file_prefix, nr, "iso");

            /* already a file with this name on hd? */
            if (stat(tmp,&buf) == 0) {

                  /* is a link? */
                  if (check_islink(tmp, NULL)) {
                        g_warning("Possibly overwriting a link at %s - not allowed.\n", tmp);
                        return 3;
                  }

                  /* file exists */
                  tmpkbyte = (gint) ((off_t)buf.st_size >> 10);
                  if (tmpkbyte == 0) {
                        /* file smaller than one kb? */
                        /* assume 1 kb then */
                        tmpkbyte = 1;
                  }
                  overwritefree += tmpkbyte;

                  /* file in directory with most space? */
                  if (strcmp(freedir->path,biggestpath) == 0) {
                        overwritefreebiggest += tmpkbyte;
                  }
            } else {
                  tmpkbyte = 0;
            }

            /* enough free? consider space that is freed
               when we overwrite a file (tmpkbyte) */
            if (size < (freedir->free + tmpkbyte)) {
                  /* found freespace */
                  strncpy(path,freedir->path,MAXLINE);
                  freedir->free-=size - tmpkbyte;
                  break;
            }
            loop2 = loop2->next;
      }

      /* no free space found? */
      if (strcmp(path,"") == 0) {
            ret = 1;
            dodebug(1,"allocate_master_filename: no free space\n");
      } else {
            /* found a file */
            if (return_fname != NULL) {
                  g_free(*return_fname);
                  *return_fname = g_strdup(tmp);
            }
            dodebug(1,"allocate_master_filename: got %s\n", tmp);
      }

        /* free image-path/free structure */
        loop2 = g_list_first(freedirs);
        while (loop2) {
                freedir = loop2->data;
                g_free(freedir->path);
                g_free(freedir);
                loop2 = loop2->next;
        }
        g_list_free(freedirs);

        *overwrite = overwritefree;
        *overwritebiggest = overwritefreebiggest;

      return ret;
}


/* checks if the current writer does support SANYO burnproof or something
   like that */

gint does_support_burnproof(gint devnr) {
gint i;
gchar *flags;

        i = get_writerreaderdevs_index(devnr);
        if (i == -1)
                return 0;

        flags = writerreaderdevs[i]->writer_flags;
        if (!flags)     
                return 0;

      if (strstr(flags,"BURNFREE"))
            return 1;

      return 0;
}

/* checks if the current writer does support Plextor VariRec */

gint does_support_varirec(gint devnr) {
gint i;
gchar *flags;

        i = get_writerreaderdevs_index(devnr);
        if (i == -1)
                return 0;

        flags = writerreaderdevs[i]->writer_flags;
        if (!flags)     
                return 0;

      if (strstr(flags,"VARIREC")) 
            return 1;

      return 0;
}

/* checks if the current writer does support Yamaha audiomaster */

gint does_support_audiomaster(gint devnr) {
gint i;
gchar *flags;

        i = get_writerreaderdevs_index(devnr);
        if (i == -1)
                return 0;

        flags = writerreaderdevs[i]->writer_flags;
        if (!flags)     
                return 0;

      if (strstr(flags,"AUDIOMASTER"))
            return 1;

      return 0;
}

/* checks if the current writer does support forcespeed */

gint does_support_forcespeed(gint devnr) {
gint i;
gchar *flags;

        i = get_writerreaderdevs_index(devnr);
        if (i == -1)
                return 0;

        flags = writerreaderdevs[i]->writer_flags;
        if (!flags)     
                return 0;

      if (strstr(flags,"FORCESPEED"))
            return 1;

      return 0;
}


/* check if a given group-id matches a groupname */

gint match_group_name(gid_t gid, gchar *group) {
struct group *grp;
      
        /* get structure containing name of group */
        grp = getgrgid(gid);

        if (grp && grp->gr_name) {
            dodebug(3,"Matching gid = %d (%s)\n", gid, grp->gr_name);
                if (strncmp(grp->gr_name,group,strlen(group)) == 0) {
                        /* does match */
                        return 1;
                }
        }
        return 0;
}


/* return string with group name */

void return_group_name(gid_t gid, gchar *ret) {
struct group *grp;
      
        /* get structure containing name of group */
        grp = getgrgid(gid);
      
      if (grp && grp->gr_name) {
            strncpy(ret,grp->gr_name,MAXLINE);
            return;
      }
      
      /* unable to get grp name? return id as text */
      g_snprintf(ret,MAXLINE,"%d", (gint) gid); 
      return;     
}


/* return string with username name */

void return_user_name(uid_t uid, gchar *ret) {
struct passwd *pw;
      
      pw = getpwuid(uid);
      
      if (pw && pw->pw_name) {
            strncpy(ret,pw->pw_name,MAXLINE);
            return;
      }
      
      /* unable to get grp name? return id as text */
      g_snprintf(ret,MAXLINE,"%d", (gint) uid); 
      return;     
}


/* return 1 if a group exists (by group name) */

gint check_group_exists(gchar *name) {
struct group *grp;
 
      grp = getgrnam(name);

      if (grp) 
            return 1;
      else
            return 0;
}


/* parse the alternate device string (if any) */

void parse_alt_devs(gchar *str) {
gint i;
gchar *p;
gchar tmp[MAXLINE];

      /* allocate memory */
      alt_scsidevices = g_new0(gchar *,MAXDEVICES);
      i = 0;

      if (str == NULL) {
            /* no devices, return */
            return;
      }

      dodebug(2,"----- list of manually choosen device names -----\n");

      /* get list of devices */
      p = strtok(str,";");
      while (p) {
            strncpy(tmp,p,MAXLINE);
            strip_string(tmp);

            alt_scsidevices[i] = g_strdup(tmp);
            dodebug(2,"alt_device: %d - \"%s\"\n",i, tmp);
      
            p = strtok(NULL,";");
            i++;
            if (i >= MAXDEVICES) {
                  g_error("Error: More than %d devices given\n",MAXDEVICES);
            }
      }           

      return;     
}


/* return the path to the chmod command */

void get_chmod_cmd(gchar *cmd) {
struct stat buf;
gchar tmp[MAXLINE], tmp2[MAXLINE];
gchar *p1;

      /* if path is set absolute dont search for it */
      strncpy(tmp, CHMOD, MAXLINE);
      if (tmp[0] == '/') {
            if (stat(CHMOD,&buf) == 0) {
                  strncpy(cmd, CHMOD, MAXLINE);
            } else {
                  strcpy(cmd,"");
            }
            return;
      }

      strncpy(tmp,CHOWNGRPMOD_PATH,MAXLINE);

      /* loop through path and try each one */
      p1 = strtok(tmp,":");
      while (p1) {
            g_snprintf(tmp2,MAXLINE,"%s/%s", p1, CHMOD);
            if (stat(tmp2,&buf) == 0) {
                  strncpy(cmd, tmp2, MAXLINE);
                  return;
            }
            p1 = strtok(NULL,":");
      }

      /* not found */
      strcpy(cmd,"");
      return;
}


/* return the path to the chgrp command */

void get_chgrp_cmd(gchar *cmd) {
struct stat buf;
gchar tmp[MAXLINE], tmp2[MAXLINE];
gchar *p1;

      /* if path is set absolute dont search for it */
      strncpy(tmp, CHGRP, MAXLINE);
      if (tmp[0] == '/') {
            if (stat(CHGRP,&buf) == 0) {
                  strncpy(cmd, CHGRP, MAXLINE);
            } else {
                  strcpy(cmd,"");
            }
            return;
      }

      strncpy(tmp,CHOWNGRPMOD_PATH,MAXLINE);

      /* loop through path and try each one */
      p1 = strtok(tmp,":");
      while (p1) {
            g_snprintf(tmp2,MAXLINE,"%s/%s", p1, CHGRP);
            if (stat(tmp2,&buf) == 0) {
                  strncpy(cmd, tmp2, MAXLINE);
                  return;
            }
            p1 = strtok(NULL,":");
      }

      /* not found */
      strcpy(cmd,"");
      return;
}


/* return the path to the chown command */

void get_chown_cmd(gchar *cmd) {
struct stat buf;
gchar tmp[MAXLINE], tmp2[MAXLINE];
gchar *p1;

      /* if path is set absolute dont search for it */
      strncpy(tmp, CHOWN, MAXLINE);
      if (tmp[0] == '/') {
            if (stat(CHOWN,&buf) == 0) {
                  strncpy(cmd, CHOWN, MAXLINE);
            } else {
                  strcpy(cmd,"");
            }
            return;
      }

      strncpy(tmp,CHOWNGRPMOD_PATH,MAXLINE);

      /* loop through path and try each one */
      p1 = strtok(tmp,":");
      while (p1) {
            g_snprintf(tmp2,MAXLINE,"%s/%s", p1, CHOWN);
            if (stat(tmp2,&buf) == 0) {
                  strncpy(cmd, tmp2, MAXLINE);
                  return;
            }
            p1 = strtok(NULL,":");
      }

      /* not found */
      strcpy(cmd,"");
      return;
}


/* allocate an entry in the nonrootval-list */

void add_to_nonrootvalues(GList **list, gchar *path, gint uid, gint gid, gint mode) {
nonroot_flags_t *entry;

        entry = g_new0(nonroot_flags_t, 1);
        if (entry) {
                entry->path = g_strdup(path);
                entry->uid = (uid_t)uid;
                entry->gid = (gid_t)gid;
                entry->mode = (mode_t)mode;

                *list = g_list_append(*list, entry);
        }
}


/* free the nonrootvalues glist */

void free_nonrootvalues(GList **list) {
GList *loop;
nonroot_flags_t *entry;

      loop = g_list_first(*list);
      while(loop) {
            entry = (nonroot_flags_t *)loop->data;
            g_free(entry->path);
            g_free(entry);

            loop = loop->next;            
      }     
      g_list_free(*list);
      *list = NULL;     
}


/* split the DTITLE line from cddb to artist and title */

void get_artist_and_title_from_cddb(gchar *dtitle, gchar *artist, gchar *title) {
gchar *p;
gint len;

      p = index(dtitle, '/');
      if (p) {
            len = p - dtitle;
            if (len > MAXLINE) 
                  len = MAXLINE;
            strncpy(title, dtitle,len);
            title[len] = '\0';      
            strip_string(title);

            strncpy(artist, p+1, MAXLINE);
            strip_string(artist);
      } else {
            strncpy(title, dtitle, MAXLINE);
            strip_string(title);
            strcpy(artist,"");
      }
}


/* switch artist <-> title in a cddb string */

void switch_artist_title(gchar *dtitle) {
gchar title[MAXLINE];
gchar artist[MAXLINE];

      get_artist_and_title_from_cddb(dtitle, title, artist);
      g_snprintf(dtitle, MAXLINE, "%s / %s", title, artist);
}


/* open the xinf-file for the given track and extract artist and title */
/* fallback to cddb if no title given */

void get_title_artist_from_xinf(gchar *file, gchar *artist, gchar *title) {
image_files_t *entry;

      entry = g_new(image_files_t,1);
      entry->path = NULL;
      entry->volname = NULL;
      entry->title = NULL;
      entry->artist = NULL;
      entry->cddb_ttitle = NULL;
      entry->cd_discid = NULL;

      /* open file and extract data */
      get_inf_tracktitle(file, entry);

      if (entry->title && *entry->title) {
            strncpy(title, entry->title, MAXLINE);
      } else {
            /* try cddb title */
            if (entry->cddb_ttitle) {
                  strncpy(title, entry->cddb_ttitle, MAXLINE);
            }
      }
      if (entry->artist) {
            strncpy(artist, entry->artist, MAXLINE);
      }

      /* free entry again */
        g_free(entry->path);
        g_free(entry->volname);
        g_free(entry->title);
        g_free(entry->artist);
        g_free(entry->cddb_ttitle);
        g_free(entry->cd_discid);
        g_free(entry);
}


/* returns a file name for the tocfile used in the write-tracks dialog */

void generate_tmp_tocfile_name(gchar *tocfile) {

      g_snprintf(tocfile, MAXLINE, "%s/xcdr-wrtrk-%d.ttoc",
            TMP_XCDR_DIR, (gint) getpid());
}
 

/* returns a prefix used in the copy audio on-the-fly dialog */

void generate_tmp_prefix_name(gchar *tmpprefix) {

      g_snprintf(tmpprefix, MAXLINE, "%s/xcdr-tmp-%d",
            TMP_XCDR_DIR, (gint) getpid());
}
 

/* returns a unique filenames that is not in use yet */
/* or empty string on error */

void generate_tmp_file_name(gchar *ext, gchar *file1) {
gchar randchars[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
gint i, done, length, count, ind;
gchar tmp[MAXLINE];
gchar fname[MAXLINE];
struct stat buf;

      done = 0;
      count = 0;
      length = strlen(randchars);

      /* try 10 times to get a unique filename..then give up */
      while (count < 10) {
            /* gen random string */
            for (i = 0; i < 4; i++) {
                        ind = (gint)((gfloat)length*rand()/(RAND_MAX+1.0)); 
                        tmp[i] = randchars[ind];
                }
            tmp[4] = '\0';

            g_snprintf(fname, MAXLINE, "%s/xcdr%s.%s", TMP_XCDR_DIR,
                  tmp,ext);

            /* already such a file on disk? */
            if (stat(fname,&buf)) {
                  /* no its not - good for us! */
                  done = 1;
                  break;
            }
            count++;
      }

      if (done == 0) {
            strcpy(file1,"");
      } else {
            strncpy(file1,fname,MAXLINE);
      }
}


/* create a 0 byte file */

gint write_empty_file(gchar *fname) {
FILE *fd;

      fd = fopen(fname,"w"); 
      if (!fd) return 1;

      dodebug(2,"creating temporary file %s\n", fname);

      fclose(fd);
      return 0;
}


/* check if our writer is from sony..needed for some multisession checks */

gint is_a_sony(gint devnr) {
gchar tmp[MAXLINE];

      strcpy(tmp,"");
      convert_devnr2vendor(devnr, tmp);

      if (strncasecmp(tmp,"SONY",4) == 0) {
            return 1;
      }

      return 0;   
}


/* parse a version id like 1.11a23 into the structure (1.11 is also ok) */
/* returns 1 on failure */

gint parse_version_str(gchar *str, version_id_t *ver) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gchar *p;
gint found;
guint i;

      strncpy(tmp, str, MAXLINE);
      p = strtok(tmp,".");
      if (p) {
            ver->major = atoi(p);
      } else {
            return 1;
      }
      p = strtok(NULL,"");
      if (p) {
            /* look for letter */
            found = -1;
            strncpy(tmp2,p, MAXLINE);
            for (i = 0; i < strlen(tmp2); i++) {
                  if (!isdigit((gint)tmp2[i])) {
                        ver->devel = tolower(tmp2[i]);
                        found = i;
                        break;
                  }
            }
            if (found == -1) {
                  /* no letter? full version then? */
                  ver->minor = atoi(tmp2);
                  ver->patch = 0;
                  ver->devel = 'h'; /* highest devel char */
            } else {
                  strncpy(tmp,tmp2,found);
                  tmp[found] = '\0';
                  ver->minor = atoi(tmp);
                  
                  strncpy(tmp,tmp2+found+1, MAXLINE);
                  ver->patch = atoi(tmp);
            }
      } else {
            return 1;
      }

      return 0;
}


/* compares two version strings. Return -1 when older, 0 when equal 
   and 1 when newer */

gint compare_versions(gchar *gotversion, gchar *minimal_version) {
version_id_t ver0, ver1;
gint bigver0, bigver1;
 
      /* convert version strings into compareable values */
      if (parse_version_str(gotversion, &ver0)) 
            return -1;
      if (parse_version_str(minimal_version, &ver1)) 
            return -1;

      /* calculate a big pure numeric version str */
      bigver0 = ver0.major * 100000 + ver0.minor * 1000 + 
              (ver0.devel - 'a') * 100 + ver0.patch;
      bigver1 = ver1.major * 100000 + ver1.minor * 1000 + 
              (ver1.devel - 'a') * 100 + ver1.patch;

      if (bigver1 == bigver0) return 0;
      if (bigver1 < bigver0) return 1;

      return -1;
}


/* searches a list of directories for the biggest common path
   compontent  e.g. /home/tn/bla and /home/tn/src  would result in
   -> /home/tn */

void get_common_path_component(GList *dirs, gchar *common) {
GList *loop;
gchar tmp[MAXLINE];
gchar match[MAXLINE];
gint i,len;
gchar *p;

      loop = g_list_first(dirs);
      /* init match str */
      strncpy(match, loop->data, MAXLINE);
      while (loop) {
            strncpy(tmp, loop->data, MAXLINE);

            /* which str is shorter? */
            if (strlen(tmp) > strlen(match)) {
                  len = strlen(match);
            } else {
                  len = strlen(tmp);
            }
            for (i = 0; i < len; i++) {
                  /* search until mismatch */
                  if (tmp[i] != match[i]) {
                        break;
                  }
            }
            /* found shortest common path */
            match[i] = '\0';

            /* now match again */
            loop = loop->next;
      }

      /* match contains now the longest common paths..remove now
         any non directory parts at the end */
      p = rindex(match,'/');
      if (p) {
            *p = '\0';  
      }
      strncpy(common, match, MAXLINE);
}


/* return driveropts string for cdrecord */
/* return 1 if varirec is enabled */

gint do_driveropts(gchar *out, gint devnr) {
gchar tmp[MAXLINE];
gchar tmp2[MAXLINE];
gint varirecon;

      varirecon = 0;
      strcpy(tmp,"");
      if (does_support_burnproof(devnr)) {
            if (curset.writeburnfree) {
                  strcat(tmp,"burnfree");
            } else {
                  strcat(tmp,"noburnfree");
            }
      }
      if (does_support_audiomaster(devnr)) {
            if (curset.writeaudiomaster) {
                  if (tmp[0] != '\0') 
                        strcat(tmp,",");
                  strcat(tmp,"audiomaster");
            }
      }
      if (does_support_forcespeed(devnr)) {
            if (tmp[0] != '\0') 
                  strcat(tmp,",");
            if (curset.writeforcespeed) {
                  strcat(tmp,"forcespeed");
            } else {
                  strcat(tmp,"noforcespeed");
            }
      }
      if (does_support_varirec(devnr)) {
            if (curset.writevarirec < 50) {
                  if (tmp[0] != '\0') 
                        strcat(tmp,",");
                  g_snprintf(tmp2,MAXLINE,"varirec=%d", curset.writevarirec);
                  strcat(tmp,tmp2);
                  varirecon = 1;
            }
      }
      
      if (tmp[0] != '\0') {
            /* added some options? */
            strcpy(tmp2, "driveropts=");
            strcat(tmp2, tmp);
      } else {
            strcpy(tmp2,"");
      }
      strncpy(out, tmp2, MAXLINE);

      return varirecon;
}


/* return index in writerreaderdevs structure for given devnr */
/* -1 when not found */

gint get_writerreaderdevs_index(gint devnr) {
gint i, found;

        i = 0;
      found = 0;
        while(writerreaderdevs[i] != NULL) {
                if (writerreaderdevs[i]->devnr == devnr) {
                  found = 1;
                        break;
                }
                i++;
        }

      if (found) {
            return i;
      } else {
            return -1;
      }
}


/* return 1 if the device devnr supports the given write mode */

gint writemode_supported(gint mode, gint devnr) {
gint i;
gchar *modes;

      i = get_writerreaderdevs_index(devnr);
      if (i == -1)
            return 1;

      modes = writerreaderdevs[i]->writer_modes;
      if (!modes)       
            return 1;

      /* no modes? allow all in this case */
      if (strlen(modes) == 0) 
            return 1;

      switch(mode) {
            
            case 0: 
                  if (strstr(modes, "DAO"))
                        return 1;
                  /* SAO in the middle of the mode string? */
                  if (strstr(modes, "SAO "))
                        return 1;
                  /* SAO at the end of the string? */
                  if (strlen(modes) >= 3 && 
                      strcmp((modes + strlen(modes) - 3), "SAO") == 0) 
                        return 1;
                  break;
            case 1:
            case 2:
                  if (strstr(modes, "TAO"))
                        return 1;
                  break;      
            case 3:
                  if (strstr(modes,"RAW/R96R"))
                        return 1;
                  break;
            case 4:
                  if (strstr(modes,"RAW/R96P"))
                        return 1;
                  break;
            case 5:
                  if (strstr(modes,"RAW/R16"))
                        return 1;
                  break;
            default:
                  return 0;
      }
      return 0;
}


/* free all of the current writerreader structure and reset all */

void free_writerreader_data() {
gint i;

        i = 0;
        while(writerreaderdevs[i] != NULL) {
            /* free first string data */
            g_free(writerreaderdevs[i]->devicestr);
            g_free(writerreaderdevs[i]->writer_flags);
            g_free(writerreaderdevs[i]->writer_modes);

            g_free(writerreaderdevs[i]);

            i++;
        }

      g_free(writerreaderdevs);
      writerreaderdevs = NULL;

      /* set devicenumbers back to default -1 */
      setupdata.writer_devnr = -1;
      setupdata.reader_devnr = -1;
      curset.writer_devnr = -1;
      curset.reader_devnr = -1;

      return;
}


/* remove a device from the structure */

void remove_from_writerreader_data(gint devnr) {
gint startindex, endindex;
gint i;

      startindex = -1;
      i = 0; 
      while(writerreaderdevs[i] != NULL) {
            if (writerreaderdevs[i]->devnr == devnr) {
                  startindex = i;
            }
            i++;
      }
      endindex = i - 1;

      if (startindex == -1 || endindex == -1) {
            /* nothing to do */
            return;
      } 

      /* erase entry from memory */
      g_free(writerreaderdevs[startindex]->devicestr);
      g_free(writerreaderdevs[startindex]->writer_flags);
      g_free(writerreaderdevs[startindex]->writer_modes);
      g_free(writerreaderdevs[startindex]);

      /* shift data to fill empty place */
      for (i = startindex; i < endindex; i++) {
            writerreaderdevs[i] = writerreaderdevs[i+1];
      }

      /* last entry is now zero */
      writerreaderdevs[endindex] = NULL;

      /* set devicenumbers back to default -1 if required */
      if (setupdata.writer_devnr == devnr) 
            setupdata.writer_devnr = -1;
      if (setupdata.reader_devnr == devnr) 
            setupdata.reader_devnr = -1;
      if (curset.writer_devnr == devnr) 
            curset.writer_devnr = -1;
      if (curset.reader_devnr == devnr) 
            curset.reader_devnr = -1;
}


/* returns the last used index - or -1 if no entries at all */

gint get_last_writerreaderdevs_index() {
gint count;

      count = 0;
        while(writerreaderdevs[count] != NULL) {
                if (count == MAXDEVICES-1) {
                  g_error("To many devices");
                }
                count++;
        }
        count--;

      return count;
}


/* saves the size of the given window in the burnwindow-geometry */

void store_win_geometry(GtkWidget *win) {

        if (setupdata.option_savepos) {
                gdk_window_get_root_origin(win->window,
                        &setupdata.burnwindow.x, 
                        &setupdata.burnwindow.y);
                gdk_window_get_size(win->window,
                        &setupdata.burnwindow.width,
                        &setupdata.burnwindow.height);
        } 
}


/* set the size of a given window from burnwindow-geometry */

gint set_win_geometry(GtkWidget *win) {
gint result;

      result = 0;
        if (setupdata.option_savepos && 
             setupdata.burnwindow.width != -1 && 
             setupdata.burnwindow.height != -1 &&
             setupdata.burnwindow.x != -1 &&
             setupdata.burnwindow.y != -1) {

            gtk_widget_realize(win);
                gdk_window_move_resize(win->window,
                        setupdata.burnwindow.x,
                        setupdata.burnwindow.y,
                        setupdata.burnwindow.width,
                        setupdata.burnwindow.height);
            gtk_widget_set_uposition(win, 
                  setupdata.burnwindow.x,
                  setupdata.burnwindow.y);
            result = 1;
        }

      return result;
}


/* set or reset the xcdroast title bar for both toplevel and one dialog
   window - adds a percent counter if requsted */

void set_xcdr_title(GtkWidget *dialog, GtkWidget *dialog2, gint val) {
char tmp[MAXLINE];

      if (val >= 0 && val <= 100 && setupdata.option_titleprogress) {
            g_snprintf(tmp, MAXLINE, "%d%% %s %s", val, 
                  T_XCDROAST, XCDROAST_VERSION);
      } else {
            g_snprintf(tmp, MAXLINE, "%s %s", 
                  T_XCDROAST, XCDROAST_VERSION);
      }     

      if (dialog) 
            gtk_window_set_title(GTK_WINDOW(dialog), tmp);
      if (dialog2) 
            gtk_window_set_title(GTK_WINDOW(dialog2), tmp);
}


/* returns the devnr of a given devicestr or -1 when not found */

gint get_writerreaderdevs_index_from_devstr(gchar *devstr) {
gint count;

      count = 0;
        while(writerreaderdevs[count] != NULL) {
            if (strncmp(writerreaderdevs[count]->devicestr, devstr, MAXLINE)== 0) {
                  return count;
            }
                count++;
        }

      return -1;
}


/* return whether we have a empty CD-R or DVD-R in the drive */
/* we are sure that there IS a medium there - but we dont know which type */
/* check only if device is dvdwriter and we have prodvd installed */

gchar *return_media_type(gint devnr) {
gchar drvflags[MAXLINE], drvmodes[MAXLINE];
gchar tmp[MAXLINE];
gint isdvd,i;

      isdvd = 0;
      i = get_writerreaderdevs_index(devnr);

      if (i >= 0 && curset.isProDVD && writerreaderdevs[i]->is_dvdwriter) {
              if (convert_devnr2busid(devnr,tmp) != 0) {
                      g_error("non existing cdrom?");
              }
            getmodesflags(tmp, drvflags, drvmodes);

            /* if drvflags contains the flag DVD we have a DVD loaded */
            if (strstr(drvflags,"DVD ")) {
                  isdvd = 1;
            }
      }
      if (isdvd) {
            return _("Empty DVD+-R/RW");
      } else {
            return _("Empty CD-R/RW");
      }
}


/* return please-insert-media text  CD or DVD version */

gchar *pleaseinsertmedia() {

        if (curset.cdrtype < 1000) {
            return _("Please insert a CD-R/RW in the CD-Writer.");
      } else {
            return _("Please insert a DVD+-R/RW in the DVD-Writer.");
      }
}


/* return if we can write dvds with the given device */

gint is_dvdwriter(gint devnr) {
gint i;

      i = get_writerreaderdevs_index(devnr);

      if (i >= 0 && writerreaderdevs[i]->is_dvdwriter) {
            return 1;
      }
      return 0;
}


/* return a new dialog widget */
 
GtkWidget *my_gtk_dialog_new() {

#if GTK_MAJOR_VERSION < 2
      return gtk_window_new(GTK_WINDOW_DIALOG);
#else
      return gtk_window_new(GTK_WINDOW_TOPLEVEL);
#endif
}


/* convert a given string to utf8, when it is not already */
/* used for strings we got from the system or from cddb */

gchar *convert_for_gtk2(gchar *str) {

#if GTK_MAJOR_VERSION < 2
      /* do nothing when using gtk1 */
      return str;
#else
gchar *utfstr;
gint in, out; 
      
      if (g_utf8_validate(str, strlen(str), NULL)) {
            /* we are already uft8? */
            return str;
      }

      utfstr = NULL;
      utfstr = g_locale_to_utf8(str, strlen(str), &in, &out, NULL);

      if (utfstr) {
            /* overwrite old string with new */
            strncpy(str,utfstr,MAXLINE);
      }
      return str;
#endif
}


/* the classic text-widget is unable to handle utf text */

gchar *convert_for_gtk2_textwidget(gchar *str) {

#if GTK_MAJOR_VERSION < 2
      /* do nothing when using gtk1 */
      return str;
#else
gchar *locstr;
gint in, out;

      locstr = g_locale_from_utf8(str, strlen(str), &in, &out, NULL);
      if (locstr) {
            strncpy(str, locstr, MAXLINE);
      }
      return str;
#endif
}


/* get a filename from an GTK2 widget */

gchar *convert_for_gtk2_filename(gchar *str) {

#if GTK_MAJOR_VERSION < 2
      /* do nothing when using gtk1 */
      return str;
#else
gchar *locstr;
gint in, out;

      /* ok, if your filesystem is already UTF8 we are not 
         allowed to change the filenames here. */
      if (c_locale_is_utf8)
            return str;

      /* should be logical to use g_filename_from_utf8() here, but
         somehow this works not correctly on my testsystem */
      locstr = g_locale_from_utf8(str, strlen(str), &in, &out, NULL);
      if (locstr) {
            strncpy(str, locstr, MAXLINE);
      }
      return str;
#endif
}


/* return the gtk2 stock icon fitting to our requested self made icon */

gchar *lookup_stock_icon(gchar *icon) {

#if GTK_MAJOR_VERSION < 2
        /* do nothing when using gtk1 */
        return icon;
#else

      if (strncmp(icon, ICO_ERROR, MAXLINE) == 0) 
            return GTK_STOCK_DIALOG_ERROR; 
      if (strncmp(icon, ICO_INFO, MAXLINE) == 0) 
            return GTK_STOCK_DIALOG_INFO; 
      if (strncmp(icon, ICO_WARN, MAXLINE) == 0) 
            return GTK_STOCK_DIALOG_WARNING; 
      if (strncmp(icon, ICO_QUEST, MAXLINE) == 0) 
            return GTK_STOCK_DIALOG_QUESTION; 

      /* not found? */
      return NULL;
#endif
}


Generated by  Doxygen 1.6.0   Back to index