/* xtools.c 27.3.99 tn */ #ifdef HAVE_CONFIG_H # include #endif #include "largefile.h" #if HAVE_LOCALE_H #include #else # define setlocale(Category, Locale) #endif #include "gettext.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if ENABLE_NLS # define _(String) gettext (String) # define N_(String) gettext_noop (String) #else # define _(String) (String) # define N_(String) (String) #endif #include #include #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("") + 1; newlabel = (gchar *) g_new0(gchar *, length); g_snprintf(newlabel, length, "%s", orglabel); } if (font && strcmp(font, BIGFONT) == 0 && !color) { length = strlen(orglabel) + strlen("") + 1; newlabel = (gchar *) g_new0(gchar *, length); g_snprintf(newlabel, length, "%s", orglabel); } if (color && !font) { length = strlen(orglabel) + strlen("") + strlen(color) + 1; newlabel = (gchar *) g_new0(gchar *, length); g_snprintf(newlabel, length, "%s", color, orglabel); } if (font && strcmp(font, BOLDFONT) == 0 && color) { length = strlen(orglabel) + strlen("") + strlen(color) + 1; newlabel = (gchar *) g_new0(gchar *, length); g_snprintf(newlabel, length, "%s", color, orglabel); } if (font && strcmp(font, BIGFONT) == 0 && color) { length = strlen(orglabel) + strlen("") + strlen(color) + 1; newlabel = (gchar *) g_new0(gchar *, length); g_snprintf(newlabel, length, "%s", 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) { gint fd; fd = open (wavname, O_RDONLY, 0); if (fd == -1) { return 0; } if (!is_std_wav_file(fd, NULL)) { /* no wav at all or not cd-quality */ 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 */ gchar *get_wrap_path_cdrecord(gchar *ret) { gchar tmp[MAXLINE]; 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 *p,*q,*r; ver->major = ver->minor = ver->patch = ver->branch = 0; ver->devel='h'; strncpy(tmp, str, MAXLINE); p = tmp; for(p=tmp; (*p != 0) && (!isdigit((int) *p ) );p++); // scan for first digit if(*p) { q = strstr(p,"."); if(q) // then there's a minor version number { *q++ = 0; r = strstr(q,"."); if(r) // then there's a second dot - call it branch number { *r++ = 0; ver->branch = atoi(r); } ver->minor = atoi(q); if(r)q=r; // skip to after branch number if there was one } ver->major = atoi(p); if(q)p=q; // skip to after minor (and maybe branch) for( q=p; (*q != 0) && (isdigit((int) *q ));q++); if(*q) ver->devel = tolower(*q++); else q=p; if(*q) { if(isdigit((int) *q)) ver->patch = atoi(q); } return 0; } return 1; } /* 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; unsigned long 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 * 10000000 + ver0.minor * 100000 + ver0.branch * 1000 + (ver0.devel - 'a') * 100 + ver0.patch; bigver1 = ver1.major * 10000000 + ver1.minor * 100000 + ver1.branch * 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; gsize 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; gsize 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; gsize 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; #ifdef BROKEN_GTK2_LOCALE /* on my redhat 7.3 system it does only work that way, but on other systems the correct way is in the #else branch */ locstr = g_locale_from_utf8(str, strlen(str), &in, &out, NULL); #else locstr = g_filename_from_utf8(str, strlen(str), &in, &out, NULL); #endif 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 }