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