1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Libbrasero-burn
4  * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5  *
6  * Libbrasero-burn is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
12  * GStreamer plugins to be used and distributed together with GStreamer
13  * and Libbrasero-burn. This permission is above and beyond the permissions granted
14  * by the GPL license by which Libbrasero-burn is covered. If you modify this code
15  * you may extend this exception to your version of the code, but you are not
16  * obligated to do so. If you do not wish to do so, delete this exception
17  * statement from your version.
18  *
19  * Libbrasero-burn is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to:
26  * 	The Free Software Foundation, Inc.,
27  * 	51 Franklin Street, Fifth Floor
28  * 	Boston, MA  02110-1301, USA.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34 
35 #include <string.h>
36 #include <sys/resource.h>
37 
38 #include <glib.h>
39 #include <glib-object.h>
40 #include <glib/gi18n-lib.h>
41 
42 #include "brasero-volume.h"
43 
44 #include "burn-basics.h"
45 #include "burn-debug.h"
46 #include "burn-plugin-manager.h"
47 #include "brasero-session.h"
48 #include "burn-plugin-manager.h"
49 #include "burn-image-format.h"
50 #include "libbrasero-marshal.h"
51 
52 #include "brasero-tags.h"
53 #include "brasero-track-image.h"
54 #include "brasero-track-data-cfg.h"
55 #include "brasero-session-cfg.h"
56 #include "brasero-burn-lib.h"
57 #include "brasero-session-helper.h"
58 
59 
60 /**
61  * SECTION:brasero-session-cfg
62  * @short_description: Configure automatically a #BraseroBurnSession object
63  * @see_also: #BraseroBurn, #BraseroBurnSession
64  * @include: brasero-session-cfg.h
65  *
66  * This object configures automatically a session reacting to any change
67  * made to the various parameters.
68  **/
69 
70 typedef struct _BraseroSessionCfgPrivate BraseroSessionCfgPrivate;
71 struct _BraseroSessionCfgPrivate
72 {
73 	BraseroBurnFlag supported;
74 	BraseroBurnFlag compulsory;
75 
76 	/* Do some caching to improve performances */
77 	BraseroImageFormat output_format;
78 	gchar *output;
79 
80 	BraseroTrackType *source;
81 	goffset disc_size;
82 	goffset session_blocks;
83 	goffset session_size;
84 
85 	BraseroSessionError is_valid;
86 
87 	guint CD_TEXT_modified:1;
88 	guint configuring:1;
89 	guint disabled:1;
90 
91 	guint output_msdos:1;
92 };
93 
94 #define BRASERO_SESSION_CFG_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_SESSION_CFG, BraseroSessionCfgPrivate))
95 
96 enum
97 {
98 	IS_VALID_SIGNAL,
99 	WRONG_EXTENSION_SIGNAL,
100 	LAST_SIGNAL
101 };
102 
103 
104 static guint session_cfg_signals [LAST_SIGNAL] = { 0 };
105 
106 G_DEFINE_TYPE (BraseroSessionCfg, brasero_session_cfg, BRASERO_TYPE_SESSION_SPAN);
107 
108 /**
109  * This is to handle tags (and more particularly video ones)
110  */
111 
112 static void
brasero_session_cfg_tag_changed(BraseroBurnSession * session,const gchar * tag)113 brasero_session_cfg_tag_changed (BraseroBurnSession *session,
114                                  const gchar *tag)
115 {
116 	if (!strcmp (tag, BRASERO_VCD_TYPE)) {
117 		int svcd_type;
118 
119 		svcd_type = brasero_burn_session_tag_lookup_int (session, BRASERO_VCD_TYPE);
120 		if (svcd_type != BRASERO_SVCD)
121 			brasero_burn_session_tag_add_int (session,
122 			                                  BRASERO_VIDEO_OUTPUT_ASPECT,
123 			                                  BRASERO_VIDEO_ASPECT_4_3);
124 	}
125 }
126 
127 /**
128  * brasero_session_cfg_has_default_output_path:
129  * @session: a #BraseroSessionCfg
130  *
131  * This function returns whether the path returned
132  * by brasero_burn_session_get_output () is an
133  * automatically created one.
134  *
135  * Return value: a #gboolean. TRUE if the path(s)
136  * creation is handled by @session, FALSE if it was
137  * set.
138  **/
139 
140 gboolean
brasero_session_cfg_has_default_output_path(BraseroSessionCfg * session)141 brasero_session_cfg_has_default_output_path (BraseroSessionCfg *session)
142 {
143 	BraseroBurnSessionClass *klass;
144 	BraseroBurnResult result;
145 
146 	klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
147 	result = klass->get_output_path (BRASERO_BURN_SESSION (session), NULL, NULL);
148 	return (result == BRASERO_BURN_OK);
149 }
150 
151 static gboolean
brasero_session_cfg_wrong_extension_signal(BraseroSessionCfg * session)152 brasero_session_cfg_wrong_extension_signal (BraseroSessionCfg *session)
153 {
154 	GValue instance_and_params [1];
155 	GValue return_value;
156 
157 	instance_and_params [0].g_type = 0;
158 	g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (session));
159 	g_value_set_instance (instance_and_params, session);
160 
161 	return_value.g_type = 0;
162 	g_value_init (&return_value, G_TYPE_BOOLEAN);
163 	g_value_set_boolean (&return_value, FALSE);
164 
165 	g_signal_emitv (instance_and_params,
166 			session_cfg_signals [WRONG_EXTENSION_SIGNAL],
167 			0,
168 			&return_value);
169 
170 	g_value_unset (instance_and_params);
171 
172 	return g_value_get_boolean (&return_value);
173 }
174 
175 static BraseroBurnResult
brasero_session_cfg_set_output_image(BraseroBurnSession * session,BraseroImageFormat format,const gchar * image,const gchar * toc)176 brasero_session_cfg_set_output_image (BraseroBurnSession *session,
177 				      BraseroImageFormat format,
178 				      const gchar *image,
179 				      const gchar *toc)
180 {
181 	gchar *dot;
182 	gchar *set_toc = NULL;
183 	gchar * set_image = NULL;
184 	BraseroBurnResult result;
185 	BraseroBurnSessionClass *klass;
186 	const gchar *suffixes [] = {".iso",
187 				    ".toc",
188 				    ".cue",
189 				    ".toc",
190 				    NULL };
191 
192 	/* Make sure something actually changed */
193 	klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
194 	klass->get_output_path (BRASERO_BURN_SESSION (session),
195 	                        &set_image,
196 	                        &set_toc);
197 
198 	if (!set_image && !set_toc) {
199 		/* see if image and toc set paths differ */
200 		brasero_burn_session_get_output (BRASERO_BURN_SESSION (session),
201 		                                 &set_image,
202 		                                 &set_toc);
203 		if (set_image && image && !strcmp (set_image, image)) {
204 			/* It's the same default path so no
205 			 * need to carry on and actually set
206 			 * the path of image. */
207 			image = NULL;
208 		}
209 
210 		if (set_toc && toc && !strcmp (set_toc, toc)) {
211 			/* It's the same default path so no
212 			 * need to carry on and actually set
213 			 * the path of image. */
214 			toc = NULL;
215 		}
216 	}
217 
218 	if (set_image)
219 		g_free (set_image);
220 
221 	if (set_toc)
222 		g_free (set_toc);
223 
224 	/* First set all information */
225 	result = klass->set_output_image (session,
226 					  format,
227 					  image,
228 					  toc);
229 
230 	if (!image && !toc)
231 		return result;
232 
233 	if (format == BRASERO_IMAGE_FORMAT_NONE)
234 		format = brasero_burn_session_get_output_format (session);
235 
236 	if (format == BRASERO_IMAGE_FORMAT_NONE)
237 		return result;
238 
239 	if (format & BRASERO_IMAGE_FORMAT_BIN) {
240 		dot = g_utf8_strrchr (image, -1, '.');
241 		if (!dot || strcmp (suffixes [0], dot)) {
242 			gboolean res;
243 
244 			res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
245 			if (res) {
246 				gchar *fixed_path;
247 
248 				fixed_path = brasero_image_format_fix_path_extension (format, FALSE, image);
249 				/* NOTE: call ourselves with the fixed path as this way,
250 				 * in case the path is the same as the default one after
251 				 * fixing the extension we'll keep on using default path */
252 				result = brasero_burn_session_set_image_output_full (session,
253 				                                                     format,
254 				                                                     fixed_path,
255 				                                                     toc);
256 				g_free (fixed_path);
257 			}
258 		}
259 	}
260 	else {
261 		dot = g_utf8_strrchr (toc, -1, '.');
262 
263 		if (format & BRASERO_IMAGE_FORMAT_CLONE
264 		&& (!dot || strcmp (suffixes [1], dot))) {
265 			gboolean res;
266 
267 			res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
268 			if (res) {
269 				gchar *fixed_path;
270 
271 				fixed_path = brasero_image_format_fix_path_extension (format, FALSE, toc);
272 				result = brasero_burn_session_set_image_output_full (session,
273 				                                                     format,
274 				                                                     image,
275 				                                                     fixed_path);
276 				g_free (fixed_path);
277 			}
278 		}
279 		else if (format & BRASERO_IMAGE_FORMAT_CUE
280 		     && (!dot || strcmp (suffixes [2], dot))) {
281 			gboolean res;
282 
283 			res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
284 			if (res) {
285 				gchar *fixed_path;
286 
287 				fixed_path = brasero_image_format_fix_path_extension (format, FALSE, toc);
288 				result = brasero_burn_session_set_image_output_full (session,
289 				                                                     format,
290 				                                                     image,
291 				                                                     fixed_path);
292 				g_free (fixed_path);
293 			}
294 		}
295 		else if (format & BRASERO_IMAGE_FORMAT_CDRDAO
296 		     && (!dot || strcmp (suffixes [3], dot))) {
297 			gboolean res;
298 
299 			res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
300 			if (res) {
301 				gchar *fixed_path;
302 
303 				fixed_path = brasero_image_format_fix_path_extension (format, FALSE, toc);
304 				result = brasero_burn_session_set_image_output_full (session,
305 				                                                     format,
306 				                                                     image,
307 				                                                     fixed_path);
308 				g_free (fixed_path);
309 			}
310 		}
311 	}
312 
313 	return result;
314 }
315 
316 static BraseroBurnResult
brasero_session_cfg_get_output_path(BraseroBurnSession * session,gchar ** image,gchar ** toc)317 brasero_session_cfg_get_output_path (BraseroBurnSession *session,
318 				     gchar **image,
319 				     gchar **toc)
320 {
321 	gchar *path = NULL;
322 	BraseroBurnResult result;
323 	BraseroImageFormat format;
324 	BraseroBurnSessionClass *klass;
325 	BraseroSessionCfgPrivate *priv;
326 
327 	klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
328 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
329 
330 	result = klass->get_output_path (session,
331 					 image,
332 					 toc);
333 	if (result == BRASERO_BURN_OK)
334 		return result;
335 
336 	if (priv->output_format == BRASERO_IMAGE_FORMAT_NONE)
337 		return BRASERO_BURN_ERR;
338 
339 	/* Note: path and format are determined earlier in fact, in the function
340 	 * that check the free space on the hard drive. */
341 	path = g_strdup (priv->output);
342 	format = priv->output_format;
343 
344 	switch (format) {
345 	case BRASERO_IMAGE_FORMAT_BIN:
346 		if (image)
347 			*image = path;
348 		break;
349 
350 	case BRASERO_IMAGE_FORMAT_CDRDAO:
351 	case BRASERO_IMAGE_FORMAT_CLONE:
352 	case BRASERO_IMAGE_FORMAT_CUE:
353 		if (toc)
354 			*toc = path;
355 
356 		if (image)
357 			*image = brasero_image_format_get_complement (format, path);
358 		break;
359 
360 	default:
361 		g_free (path);
362 		g_free (priv->output);
363 		priv->output = NULL;
364 		return BRASERO_BURN_ERR;
365 	}
366 
367 	return BRASERO_BURN_OK;
368 }
369 
370 static BraseroImageFormat
brasero_session_cfg_get_output_format(BraseroBurnSession * session)371 brasero_session_cfg_get_output_format (BraseroBurnSession *session)
372 {
373 	BraseroBurnSessionClass *klass;
374 	BraseroSessionCfgPrivate *priv;
375 	BraseroImageFormat format;
376 
377 	klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
378 	format = klass->get_output_format (session);
379 
380 	if (format != BRASERO_IMAGE_FORMAT_NONE)
381 		return format;
382 
383 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
384 
385 	if (priv->output_format)
386 		return priv->output_format;
387 
388 	/* Cache the path for later use */
389 	priv->output_format = brasero_burn_session_get_default_output_format (session);
390 	return priv->output_format;
391 }
392 
393 /**
394  * brasero_session_cfg_get_error:
395  * @session: a #BraseroSessionCfg
396  *
397  * This function returns the current status and if
398  * autoconfiguration is/was successful.
399  *
400  * Return value: a #BraseroSessionError.
401  **/
402 
403 BraseroSessionError
brasero_session_cfg_get_error(BraseroSessionCfg * session)404 brasero_session_cfg_get_error (BraseroSessionCfg *session)
405 {
406 	BraseroSessionCfgPrivate *priv;
407 
408 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
409 
410 	if (priv->is_valid == BRASERO_SESSION_VALID
411 	&&  priv->CD_TEXT_modified)
412 		return BRASERO_SESSION_NO_CD_TEXT;
413 
414 	return priv->is_valid;
415 }
416 
417 /**
418  * brasero_session_cfg_disable:
419  * @session: a #BraseroSessionCfg
420  *
421  * This function disables autoconfiguration
422  *
423  **/
424 
425 void
brasero_session_cfg_disable(BraseroSessionCfg * session)426 brasero_session_cfg_disable (BraseroSessionCfg *session)
427 {
428 	BraseroSessionCfgPrivate *priv;
429 
430 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
431 	priv->disabled = TRUE;
432 }
433 
434 /**
435  * brasero_session_cfg_enable:
436  * @session: a #BraseroSessionCfg
437  *
438  * This function (re)-enables autoconfiguration
439  *
440  **/
441 
442 void
brasero_session_cfg_enable(BraseroSessionCfg * session)443 brasero_session_cfg_enable (BraseroSessionCfg *session)
444 {
445 	BraseroSessionCfgPrivate *priv;
446 
447 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
448 	priv->disabled = FALSE;
449 }
450 
451 static void
brasero_session_cfg_set_drive_properties_default_flags(BraseroSessionCfg * self)452 brasero_session_cfg_set_drive_properties_default_flags (BraseroSessionCfg *self)
453 {
454 	BraseroMedia media;
455 	BraseroSessionCfgPrivate *priv;
456 
457 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
458 
459 	media = brasero_burn_session_get_dest_media (BRASERO_BURN_SESSION (self));
460 
461 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)
462 	||  BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED)
463 	||  BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS_DL)) {
464 		/* This is a special case to favour libburn/growisofs
465 		 * wodim/cdrecord for these types of media. */
466 		if (priv->supported & BRASERO_BURN_FLAG_MULTI) {
467 			brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
468 						       BRASERO_BURN_FLAG_MULTI);
469 
470 			priv->supported = BRASERO_BURN_FLAG_NONE;
471 			priv->compulsory = BRASERO_BURN_FLAG_NONE;
472 			brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
473 							     &priv->supported,
474 							     &priv->compulsory);
475 		}
476 	}
477 
478 	/* Always set this flag whenever possible */
479 	if (priv->supported & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE) {
480 		brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
481 					       BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE);
482 
483 		if (priv->supported & BRASERO_BURN_FLAG_FAST_BLANK
484 		&& (media & BRASERO_MEDIUM_UNFORMATTED) == 0)
485 			brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
486 						       BRASERO_BURN_FLAG_FAST_BLANK);
487 
488 		priv->supported = BRASERO_BURN_FLAG_NONE;
489 		priv->compulsory = BRASERO_BURN_FLAG_NONE;
490 		brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
491 						     &priv->supported,
492 						     &priv->compulsory);
493 	}
494 
495 #if 0
496 
497 	/* NOTE: Stop setting DAO here except if it
498 	 * is declared compulsory (but that's handled
499 	 * somewhere else) or if it was explicity set.
500 	 * If we set it just  by  default when it's
501 	 * supported but not compulsory, MULTI
502 	 * becomes not supported anymore.
503 	 * For data the only way it'd be really useful
504 	 * is if we wanted to fit a selection on the disc.
505 	 * The problem here is that we don't know
506 	 * what the size of the final image is going
507 	 * to be.
508 	 * For images there are cases when after
509 	 * writing an image the user may want to
510 	 * add some more data to it later. As in the
511 	 * case of data the only way this flag would
512 	 * be useful would be to help fit the image
513 	 * on the disc. But I doubt it would really
514 	 * help a lot.
515 	 * For audio we need it to write things like
516 	 * CD-TEXT but in this case the backend
517 	 * will return it as compulsory. */
518 
519 	/* Another case when this flag is needed is
520 	 * for DVD-RW quick blanked as they only
521 	 * support DAO. But there again this should
522 	 * be covered by the backend that should
523 	 * return DAO as compulsory. */
524 
525 	/* Leave the code as a reminder. */
526 	/* When copying with same drive don't set write mode, it'll be set later */
527 	if (!brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))
528 	&&  !(media & BRASERO_MEDIUM_DVD)) {
529 		/* use DAO whenever it's possible except for DVDs otherwise
530 		 * wodime which claims to support it will be used by default
531 		 * instead of say growisofs. */
532 		if (priv->supported & BRASERO_BURN_FLAG_DAO) {
533 			brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), BRASERO_BURN_FLAG_DAO);
534 
535 			priv->supported = BRASERO_BURN_FLAG_NONE;
536 			priv->compulsory = BRASERO_BURN_FLAG_NONE;
537 			brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
538 							     &priv->supported,
539 							     &priv->compulsory);
540 
541 			/* NOTE: after setting DAO, some flags may become
542 			 * compulsory like MULTI. */
543 		}
544 	}
545 #endif
546 }
547 
548 static void
brasero_session_cfg_set_drive_properties_flags(BraseroSessionCfg * self,BraseroBurnFlag flags)549 brasero_session_cfg_set_drive_properties_flags (BraseroSessionCfg *self,
550 						BraseroBurnFlag flags)
551 {
552 	BraseroDrive *drive;
553 	BraseroBurnFlag flag;
554 	BraseroMedium *medium;
555 	BraseroBurnResult result;
556 	BraseroBurnFlag original_flags;
557 	BraseroSessionCfgPrivate *priv;
558 
559 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
560 
561 	original_flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
562 
563 	/* If the session is invalid no need to check the flags: just add them.
564 	 * The correct flags will be re-computed anyway when the session becomes
565 	 * valid again. */
566 	if (priv->is_valid != BRASERO_SESSION_VALID) {
567 		BRASERO_BURN_LOG ("Session currently not ready for flag computation: adding flags (will update later)");
568 		brasero_burn_session_set_flags (BRASERO_BURN_SESSION (self), flags);
569 		return;
570 	}
571 
572 	BRASERO_BURN_LOG ("Resetting all flags");
573 	BRASERO_BURN_LOG_FLAGS (original_flags, "Current are");
574 	BRASERO_BURN_LOG_FLAGS (flags, "New should be");
575 
576 	drive = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (self));
577 	if (!drive) {
578 		BRASERO_BURN_LOG ("No drive");
579 		return;
580 	}
581 
582 	medium = brasero_drive_get_medium (drive);
583 	if (!medium) {
584 		BRASERO_BURN_LOG ("No medium");
585 		return;
586 	}
587 
588 	/* This prevents signals to be emitted while (re-) adding them one by one */
589 	g_object_freeze_notify (G_OBJECT (self));
590 
591 	brasero_burn_session_set_flags (BRASERO_BURN_SESSION (self), BRASERO_BURN_FLAG_NONE);
592 
593 	priv->supported = BRASERO_BURN_FLAG_NONE;
594 	priv->compulsory = BRASERO_BURN_FLAG_NONE;
595 	result = brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
596 						      &priv->supported,
597 						      &priv->compulsory);
598 
599 	if (result != BRASERO_BURN_OK) {
600 		brasero_burn_session_set_flags (BRASERO_BURN_SESSION (self), original_flags | flags);
601 		g_object_thaw_notify (G_OBJECT (self));
602 		return;
603 	}
604 
605 	for (flag = BRASERO_BURN_FLAG_EJECT; flag < BRASERO_BURN_FLAG_LAST; flag <<= 1) {
606 		/* see if this flag was originally set */
607 		if ((flags & flag) == 0)
608 			continue;
609 
610 		/* Don't set write modes now in this case */
611 		if (brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))
612 		&& (flag & (BRASERO_BURN_FLAG_DAO|BRASERO_BURN_FLAG_RAW)))
613 			continue;
614 
615 		if (priv->compulsory
616 		&& (priv->compulsory & brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self))) != priv->compulsory) {
617 			brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), priv->compulsory);
618 
619 			priv->supported = BRASERO_BURN_FLAG_NONE;
620 			priv->compulsory = BRASERO_BURN_FLAG_NONE;
621 			brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
622 							     &priv->supported,
623 							     &priv->compulsory);
624 		}
625 
626 		if (priv->supported & flag) {
627 			brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), flag);
628 
629 			priv->supported = BRASERO_BURN_FLAG_NONE;
630 			priv->compulsory = BRASERO_BURN_FLAG_NONE;
631 			brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
632 							     &priv->supported,
633 							     &priv->compulsory);
634 		}
635 	}
636 
637 	if (original_flags & BRASERO_BURN_FLAG_DAO
638 	&&  priv->supported & BRASERO_BURN_FLAG_DAO) {
639 		/* Only set DAO if it was explicitely requested */
640 		brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), BRASERO_BURN_FLAG_DAO);
641 
642 		priv->supported = BRASERO_BURN_FLAG_NONE;
643 		priv->compulsory = BRASERO_BURN_FLAG_NONE;
644 		brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
645 						     &priv->supported,
646 						     &priv->compulsory);
647 
648 		/* NOTE: after setting DAO, some flags may become
649 		 * compulsory like MULTI. */
650 	}
651 
652 	brasero_session_cfg_set_drive_properties_default_flags (self);
653 
654 	/* These are always supported and better be set. */
655 	brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
656 	                               BRASERO_BURN_FLAG_CHECK_SIZE|
657 	                               BRASERO_BURN_FLAG_NOGRACE);
658 
659 	/* This one is only supported when we are
660 	 * burning to a disc or copying a disc but it
661 	 * would better be set. */
662 	if (priv->supported & BRASERO_BURN_FLAG_EJECT)
663 		brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
664 		                               BRASERO_BURN_FLAG_EJECT);
665 
666 	/* allow notify::flags signal again */
667 	g_object_thaw_notify (G_OBJECT (self));
668 }
669 
670 static void
brasero_session_cfg_add_drive_properties_flags(BraseroSessionCfg * self,BraseroBurnFlag flags)671 brasero_session_cfg_add_drive_properties_flags (BraseroSessionCfg *self,
672 						BraseroBurnFlag flags)
673 {
674 	/* add flags then wipe out flags from session to check them one by one */
675 	flags |= brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
676 	brasero_session_cfg_set_drive_properties_flags (self, flags);
677 }
678 
679 static void
brasero_session_cfg_rm_drive_properties_flags(BraseroSessionCfg * self,BraseroBurnFlag flags)680 brasero_session_cfg_rm_drive_properties_flags (BraseroSessionCfg *self,
681 					       BraseroBurnFlag flags)
682 {
683 	/* add flags then wipe out flags from session to check them one by one */
684 	flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self)) & (~flags);
685 	brasero_session_cfg_set_drive_properties_flags (self, flags);
686 }
687 
688 static void
brasero_session_cfg_check_drive_settings(BraseroSessionCfg * self)689 brasero_session_cfg_check_drive_settings (BraseroSessionCfg *self)
690 {
691 	BraseroBurnFlag flags;
692 
693 	/* Try to properly update the flags for the current drive */
694 	flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
695 	if (brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))) {
696 		flags |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE|
697 			 BRASERO_BURN_FLAG_FAST_BLANK;
698 	}
699 
700 	/* check each flag before re-adding it */
701 	brasero_session_cfg_add_drive_properties_flags (self, flags);
702 }
703 
704 static BraseroSessionError
brasero_session_cfg_check_volume_size(BraseroSessionCfg * self)705 brasero_session_cfg_check_volume_size (BraseroSessionCfg *self)
706 {
707 	struct rlimit limit;
708 	BraseroSessionCfgPrivate *priv;
709 
710 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
711 	if (!priv->disc_size) {
712 		GFileInfo *info;
713 		gchar *directory;
714 		GFile *file = NULL;
715 		const gchar *filesystem;
716 
717 		/* Cache the path for later use */
718 		if (priv->output_format == BRASERO_IMAGE_FORMAT_NONE)
719 			priv->output_format = brasero_burn_session_get_output_format (BRASERO_BURN_SESSION (self));
720 
721 		if (!priv->output) {
722 			gchar *name = NULL;
723 
724 			/* If we try to copy a volume get (and use) its name */
725 			if (brasero_track_type_get_has_medium (priv->source)) {
726 				BraseroMedium *medium;
727 
728 				medium = brasero_burn_session_get_src_medium (BRASERO_BURN_SESSION (self));
729 				if (medium)
730 					name = brasero_volume_get_name (BRASERO_VOLUME (medium));
731 			}
732 
733 			priv->output = brasero_image_format_get_default_path (priv->output_format, name);
734 			g_free (name);
735 		}
736 
737 		directory = g_path_get_dirname (priv->output);
738 		file = g_file_new_for_path (directory);
739 		g_free (directory);
740 
741 		if (file == NULL)
742 			goto error;
743 
744 		/* Check permissions first */
745 		info = g_file_query_info (file,
746 					  G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
747 					  G_FILE_QUERY_INFO_NONE,
748 					  NULL,
749 					  NULL);
750 		if (!info) {
751 			g_object_unref (file);
752 			goto error;
753 		}
754 
755 		if (!g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) {
756 			g_object_unref (info);
757 			g_object_unref (file);
758 			goto error;
759 		}
760 		g_object_unref (info);
761 
762 		/* Now size left */
763 		info = g_file_query_filesystem_info (file,
764 						     G_FILE_ATTRIBUTE_FILESYSTEM_FREE ","
765 						     G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
766 						     NULL,
767 						     NULL);
768 		g_object_unref (file);
769 
770 		if (!info)
771 			goto error;
772 
773 		/* Now check the filesystem type: the problem here is that some
774 		 * filesystems have a maximum file size limit of 4 GiB and more than
775 		 * often we need a temporary file size of 4 GiB or more. */
776 		filesystem = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE);
777 		if (!g_strcmp0 (filesystem, "msdos"))
778 			priv->output_msdos = TRUE;
779 		else
780 			priv->output_msdos = FALSE;
781 
782 		priv->disc_size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
783 		g_object_unref (info);
784 	}
785 
786 	BRASERO_BURN_LOG ("Session size %lli/Hard drive size %lli",
787 			  priv->session_size,
788 			  priv->disc_size);
789 
790 	if (priv->output_msdos && priv->session_size >= 2147483648ULL)
791 		goto error;
792 
793 	if (priv->session_size > priv->disc_size)
794 		goto error;
795 
796 	/* Last but not least, use getrlimit () to check that we are allowed to
797 	 * write a file of such length and that quotas won't get in our way */
798 	if (getrlimit (RLIMIT_FSIZE, &limit))
799 		goto error;
800 
801 	if (limit.rlim_cur < priv->session_size)
802 		goto error;
803 
804 	priv->is_valid = BRASERO_SESSION_VALID;
805 	return BRASERO_SESSION_VALID;
806 
807 error:
808 
809 	priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
810 	return BRASERO_SESSION_INSUFFICIENT_SPACE;
811 }
812 
813 static BraseroSessionError
brasero_session_cfg_check_size(BraseroSessionCfg * self)814 brasero_session_cfg_check_size (BraseroSessionCfg *self)
815 {
816 	BraseroSessionCfgPrivate *priv;
817 	BraseroBurnFlag flags;
818 	BraseroMedium *medium;
819 	BraseroDrive *burner;
820 	GValue *value = NULL;
821 	/* in sectors */
822 	goffset max_sectors;
823 
824 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
825 
826 	/* Get the session size if need be */
827 	if (!priv->session_blocks) {
828 		if (brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (self),
829 						     BRASERO_DATA_TRACK_SIZE_TAG,
830 						     &value) == BRASERO_BURN_OK) {
831 			priv->session_blocks = g_value_get_int64 (value);
832 			priv->session_size = priv->session_blocks * 2048;
833 		}
834 		else if (brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (self),
835 							  BRASERO_STREAM_TRACK_SIZE_TAG,
836 							  &value) == BRASERO_BURN_OK) {
837 			priv->session_blocks = g_value_get_int64 (value);
838 			priv->session_size = priv->session_blocks * 2352;
839 		}
840 		else
841 			brasero_burn_session_get_size (BRASERO_BURN_SESSION (self),
842 						       &priv->session_blocks,
843 						       &priv->session_size);
844 	}
845 
846 	/* Get the disc and its size if need be */
847 	burner = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (self));
848 	if (!burner) {
849 		priv->is_valid = BRASERO_SESSION_NO_OUTPUT;
850 		return BRASERO_SESSION_NO_OUTPUT;
851 	}
852 
853 	if (brasero_drive_is_fake (burner))
854 		return brasero_session_cfg_check_volume_size (self);
855 
856 	medium = brasero_drive_get_medium (burner);
857 	if (!medium) {
858 		priv->is_valid = BRASERO_SESSION_NO_OUTPUT;
859 		return BRASERO_SESSION_NO_OUTPUT;
860 	}
861 
862 	/* Get both sizes if need be */
863 	if (!priv->disc_size) {
864 		priv->disc_size = brasero_burn_session_get_available_medium_space (BRASERO_BURN_SESSION (self));
865 		if (priv->disc_size < 0)
866 			priv->disc_size = 0;
867 	}
868 
869 	BRASERO_BURN_LOG ("Session size %lli/Disc size %lli",
870 			  priv->session_blocks,
871 			  priv->disc_size);
872 
873 	if (priv->session_blocks < priv->disc_size) {
874 		priv->is_valid = BRASERO_SESSION_VALID;
875 		return BRASERO_SESSION_VALID;
876 	}
877 
878 	/* Overburn is only for CDs */
879 	if ((brasero_medium_get_status (medium) & BRASERO_MEDIUM_CD) == 0) {
880 		priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
881 		return BRASERO_SESSION_INSUFFICIENT_SPACE;
882 	}
883 
884 	/* The idea would be to test write the disc with cdrecord from /dev/null
885 	 * until there is an error and see how much we were able to write. So,
886 	 * when we propose overburning to the user, we could ask if he wants
887 	 * us to determine how much data can be written to a particular disc
888 	 * provided he has chosen a real disc. */
889 	max_sectors = priv->disc_size * 103 / 100;
890 	if (max_sectors < priv->session_blocks) {
891 		priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
892 		return BRASERO_SESSION_INSUFFICIENT_SPACE;
893 	}
894 
895 	flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
896 	if (!(flags & BRASERO_BURN_FLAG_OVERBURN)) {
897 		BraseroSessionCfgPrivate *priv;
898 
899 		priv = BRASERO_SESSION_CFG_PRIVATE (self);
900 
901 		if (!(priv->supported & BRASERO_BURN_FLAG_OVERBURN)) {
902 			priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
903 			return BRASERO_SESSION_INSUFFICIENT_SPACE;
904 		}
905 
906 		priv->is_valid = BRASERO_SESSION_OVERBURN_NECESSARY;
907 		return BRASERO_SESSION_OVERBURN_NECESSARY;
908 	}
909 
910 	priv->is_valid = BRASERO_SESSION_VALID;
911 	return BRASERO_SESSION_VALID;
912 }
913 
914 static void
brasero_session_cfg_set_tracks_audio_format(BraseroBurnSession * session,BraseroStreamFormat format)915 brasero_session_cfg_set_tracks_audio_format (BraseroBurnSession *session,
916 					     BraseroStreamFormat format)
917 {
918 	GSList *tracks;
919 	GSList *iter;
920 
921 	tracks = brasero_burn_session_get_tracks (session);
922 	for (iter = tracks; iter; iter = iter->next) {
923 		BraseroTrack *track;
924 
925 		track = iter->data;
926 		if (!BRASERO_IS_TRACK_STREAM (track))
927 			continue;
928 
929 		brasero_track_stream_set_format (BRASERO_TRACK_STREAM (track), format);
930 	}
931 }
932 
933 static gboolean
brasero_session_cfg_can_update(BraseroSessionCfg * self)934 brasero_session_cfg_can_update (BraseroSessionCfg *self)
935 {
936 	BraseroSessionCfgPrivate *priv;
937 	BraseroBurnResult result;
938 	BraseroStatus *status;
939 
940 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
941 
942 	if (priv->disabled)
943 		return FALSE;
944 
945 	if (priv->configuring)
946 		return FALSE;
947 
948 	/* Make sure the session is ready */
949 	status = brasero_status_new ();
950 	result = brasero_burn_session_get_status (BRASERO_BURN_SESSION (self), status);
951 	if (result == BRASERO_BURN_NOT_READY || result == BRASERO_BURN_RUNNING) {
952 		g_object_unref (status);
953 
954 		priv->is_valid = BRASERO_SESSION_NOT_READY;
955 		g_signal_emit (self,
956 			       session_cfg_signals [IS_VALID_SIGNAL],
957 			       0);
958 		return FALSE;
959 	}
960 
961 	if (result == BRASERO_BURN_ERR) {
962 		GError *error;
963 
964 		error = brasero_status_get_error (status);
965 		if (error) {
966 			if (error->code == BRASERO_BURN_ERROR_EMPTY) {
967 				g_object_unref (status);
968 				g_error_free (error);
969 
970 				priv->is_valid = BRASERO_SESSION_EMPTY;
971 				g_signal_emit (self,
972 					       session_cfg_signals [IS_VALID_SIGNAL],
973 					       0);
974 				return FALSE;
975 			}
976 
977 			g_error_free (error);
978 		}
979 	}
980 	g_object_unref (status);
981 	return TRUE;
982 }
983 
984 static void
brasero_session_cfg_update(BraseroSessionCfg * self)985 brasero_session_cfg_update (BraseroSessionCfg *self)
986 {
987 	BraseroSessionCfgPrivate *priv;
988 	BraseroBurnResult result;
989 	BraseroDrive *burner;
990 
991 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
992 
993 	/* Make sure there is a source */
994 	if (priv->source) {
995 		brasero_track_type_free (priv->source);
996 		priv->source = NULL;
997 	}
998 
999 	priv->source = brasero_track_type_new ();
1000 	brasero_burn_session_get_input_type (BRASERO_BURN_SESSION (self), priv->source);
1001 
1002 	if (brasero_track_type_is_empty (priv->source)) {
1003 		priv->is_valid = BRASERO_SESSION_EMPTY;
1004 		g_signal_emit (self,
1005 			       session_cfg_signals [IS_VALID_SIGNAL],
1006 			       0);
1007 		return;
1008 	}
1009 
1010 	/* it can be empty with just an empty track */
1011 	if (brasero_track_type_get_has_medium (priv->source)
1012 	&&  brasero_track_type_get_medium_type (priv->source) == BRASERO_MEDIUM_NONE) {
1013 		priv->is_valid = BRASERO_SESSION_NO_INPUT_MEDIUM;
1014 		g_signal_emit (self,
1015 			       session_cfg_signals [IS_VALID_SIGNAL],
1016 			       0);
1017 		return;
1018 	}
1019 
1020 	if (brasero_track_type_get_has_image (priv->source)
1021 	&&  brasero_track_type_get_image_format (priv->source) == BRASERO_IMAGE_FORMAT_NONE) {
1022 		gchar *uri;
1023 		GSList *tracks;
1024 
1025 		tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (self));
1026 
1027 		/* It can be two cases:
1028 		 * - no image set
1029 		 * - image format cannot be detected */
1030 		if (tracks) {
1031 			BraseroTrack *track;
1032 
1033 			track = tracks->data;
1034 			uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
1035 			if (uri) {
1036 				priv->is_valid = BRASERO_SESSION_UNKNOWN_IMAGE;
1037 				g_free (uri);
1038 			}
1039 			else
1040 				priv->is_valid = BRASERO_SESSION_NO_INPUT_IMAGE;
1041 		}
1042 		else
1043 			priv->is_valid = BRASERO_SESSION_NO_INPUT_IMAGE;
1044 
1045 		g_signal_emit (self,
1046 			       session_cfg_signals [IS_VALID_SIGNAL],
1047 			       0);
1048 		return;
1049 	}
1050 
1051 	/* make sure there is an output set */
1052 	burner = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (self));
1053 	if (!burner) {
1054 		priv->is_valid = BRASERO_SESSION_NO_OUTPUT;
1055 		g_signal_emit (self,
1056 			       session_cfg_signals [IS_VALID_SIGNAL],
1057 			       0);
1058 		return;
1059 	}
1060 
1061 	/* In case the output was an image remove the path cache. It will be
1062 	 * re-computed on demand. */
1063 	if (priv->output) {
1064 		g_free (priv->output);
1065 		priv->output = NULL;
1066 	}
1067 
1068 	if (priv->output_format)
1069 		priv->output_format = BRASERO_IMAGE_FORMAT_NONE;
1070 
1071 	/* Check that current input and output work */
1072 	if (brasero_track_type_get_has_stream (priv->source)) {
1073 		if (priv->CD_TEXT_modified) {
1074 			/* Try to redo what we undid (after all a new plugin
1075 			 * could have been activated in the mean time ...) and
1076 			 * see what happens */
1077 			brasero_track_type_set_stream_format (priv->source,
1078 							      BRASERO_METADATA_INFO|
1079 							      brasero_track_type_get_stream_format (priv->source));
1080 			result = brasero_burn_session_input_supported (BRASERO_BURN_SESSION (self), priv->source, FALSE);
1081 			if (result == BRASERO_BURN_OK) {
1082 				priv->CD_TEXT_modified = FALSE;
1083 
1084 				priv->configuring = TRUE;
1085 				brasero_session_cfg_set_tracks_audio_format (BRASERO_BURN_SESSION (self),
1086 									     brasero_track_type_get_stream_format (priv->source));
1087 				priv->configuring = FALSE;
1088 			}
1089 			else {
1090 				/* No, nothing's changed */
1091 				brasero_track_type_set_stream_format (priv->source,
1092 								      (~BRASERO_METADATA_INFO) &
1093 								      brasero_track_type_get_stream_format (priv->source));
1094 				result = brasero_burn_session_input_supported (BRASERO_BURN_SESSION (self), priv->source, FALSE);
1095 			}
1096 		}
1097 		else {
1098 			result = brasero_burn_session_can_burn (BRASERO_BURN_SESSION (self), FALSE);
1099 
1100 			if (result != BRASERO_BURN_OK
1101 			&& (brasero_track_type_get_stream_format (priv->source) & BRASERO_METADATA_INFO)) {
1102 				/* Another special case in case some burning backends
1103 				 * don't support CD-TEXT for audio (libburn). If no
1104 				 * other backend is available remove CD-TEXT option but
1105 				 * tell user... */
1106 				brasero_track_type_set_stream_format (priv->source,
1107 								      (~BRASERO_METADATA_INFO) &
1108 								      brasero_track_type_get_stream_format (priv->source));
1109 
1110 				result = brasero_burn_session_input_supported (BRASERO_BURN_SESSION (self), priv->source, FALSE);
1111 
1112 				BRASERO_BURN_LOG ("Tested support without Metadata information (result %d)", result);
1113 				if (result == BRASERO_BURN_OK) {
1114 					priv->CD_TEXT_modified = TRUE;
1115 
1116 					priv->configuring = TRUE;
1117 					brasero_session_cfg_set_tracks_audio_format (BRASERO_BURN_SESSION (self),
1118 										     brasero_track_type_get_has_stream (priv->source));
1119 					priv->configuring = FALSE;
1120 				}
1121 			}
1122 		}
1123 	}
1124 	else if (brasero_track_type_get_has_medium (priv->source)
1125 	&&  (brasero_track_type_get_medium_type (priv->source) & BRASERO_MEDIUM_HAS_AUDIO)) {
1126 		BraseroImageFormat format = BRASERO_IMAGE_FORMAT_NONE;
1127 
1128 		/* If we copy an audio disc check the image
1129 		 * type we're writing to as it may mean that
1130 		 * CD-TEXT cannot be copied.
1131 		 * Make sure that the writing backend
1132 		 * supports writing CD-TEXT?
1133 		 * no, if a backend reports it supports an
1134 		 * image type it should be able to burn all
1135 		 * its data. */
1136 		if (!brasero_burn_session_is_dest_file (BRASERO_BURN_SESSION (self))) {
1137 			BraseroTrackType *tmp_type;
1138 
1139 			tmp_type = brasero_track_type_new ();
1140 
1141 			/* NOTE: this is the same as brasero_burn_session_supported () */
1142 			result = brasero_burn_session_get_tmp_image_type_same_src_dest (BRASERO_BURN_SESSION (self), tmp_type);
1143 			if (result == BRASERO_BURN_OK) {
1144 				if (brasero_track_type_get_has_image (tmp_type)) {
1145 					format = brasero_track_type_get_image_format (tmp_type);
1146 					priv->CD_TEXT_modified = (format & (BRASERO_IMAGE_FORMAT_CDRDAO|BRASERO_IMAGE_FORMAT_CUE)) == 0;
1147 				}
1148 				else if (brasero_track_type_get_has_stream (tmp_type)) {
1149 					/* FIXME: for the moment
1150 					 * we consider that this
1151 					 * type will always allow
1152 					 * to copy CD-TEXT */
1153 					priv->CD_TEXT_modified = FALSE;
1154 				}
1155 				else
1156 					priv->CD_TEXT_modified = TRUE;
1157 			}
1158 			else
1159 				priv->CD_TEXT_modified = TRUE;
1160 
1161 			brasero_track_type_free (tmp_type);
1162 
1163 			BRASERO_BURN_LOG ("Temporary image type %i", format);
1164 		}
1165 		else {
1166 			result = brasero_burn_session_can_burn (BRASERO_BURN_SESSION (self), FALSE);
1167 			format = brasero_burn_session_get_output_format (BRASERO_BURN_SESSION (self));
1168 			priv->CD_TEXT_modified = (format & (BRASERO_IMAGE_FORMAT_CDRDAO|BRASERO_IMAGE_FORMAT_CUE)) == 0;
1169 		}
1170 	}
1171 	else {
1172 		/* Don't use flags as they'll be adapted later. */
1173 		priv->CD_TEXT_modified = FALSE;
1174 		result = brasero_burn_session_can_burn (BRASERO_BURN_SESSION (self), FALSE);
1175 	}
1176 
1177 	if (result != BRASERO_BURN_OK) {
1178 		if (brasero_track_type_get_has_medium (priv->source)
1179 		&& (brasero_track_type_get_medium_type (priv->source) & BRASERO_MEDIUM_PROTECTED)
1180 		&&  brasero_burn_library_input_supported (priv->source) != BRASERO_BURN_OK) {
1181 			/* This is a special case to display a helpful message */
1182 			priv->is_valid = BRASERO_SESSION_DISC_PROTECTED;
1183 			g_signal_emit (self,
1184 				       session_cfg_signals [IS_VALID_SIGNAL],
1185 				       0);
1186 		}
1187 		else {
1188 			priv->is_valid = BRASERO_SESSION_NOT_SUPPORTED;
1189 			g_signal_emit (self,
1190 				       session_cfg_signals [IS_VALID_SIGNAL],
1191 				       0);
1192 		}
1193 
1194 		return;
1195 	}
1196 
1197 	/* Special case for video projects */
1198 	if (brasero_track_type_get_has_stream (priv->source)
1199 	&&  BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (priv->source))) {
1200 		/* Only set if it was not already set */
1201 		if (brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (self), BRASERO_VCD_TYPE, NULL) != BRASERO_BURN_OK)
1202 			brasero_burn_session_tag_add_int (BRASERO_BURN_SESSION (self),
1203 							  BRASERO_VCD_TYPE,
1204 							  BRASERO_SVCD);
1205 	}
1206 
1207 	/* Configure flags */
1208 	priv->configuring = TRUE;
1209 
1210 	if (brasero_drive_is_fake (burner))
1211 		/* Remove some impossible flags */
1212 		brasero_burn_session_remove_flag (BRASERO_BURN_SESSION (self),
1213 						  BRASERO_BURN_FLAG_DUMMY|
1214 						  BRASERO_BURN_FLAG_NO_TMP_FILES);
1215 
1216 	priv->configuring = FALSE;
1217 
1218 	/* Finally check size */
1219 	if (brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))) {
1220 		priv->is_valid = BRASERO_SESSION_VALID;
1221 		g_signal_emit (self,
1222 			       session_cfg_signals [IS_VALID_SIGNAL],
1223 			       0);
1224 	}
1225 	else {
1226 		brasero_session_cfg_check_size (self);
1227 		g_signal_emit (self,
1228 			       session_cfg_signals [IS_VALID_SIGNAL],
1229 			       0);
1230 	}
1231 }
1232 
1233 static void
brasero_session_cfg_session_loaded(BraseroTrackDataCfg * track,BraseroMedium * medium,gboolean is_loaded,BraseroSessionCfg * session)1234 brasero_session_cfg_session_loaded (BraseroTrackDataCfg *track,
1235 				    BraseroMedium *medium,
1236 				    gboolean is_loaded,
1237 				    BraseroSessionCfg *session)
1238 {
1239 	BraseroBurnFlag session_flags;
1240 	BraseroSessionCfgPrivate *priv;
1241 
1242 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1243 	if (priv->disabled)
1244 		return;
1245 
1246 	priv->session_blocks = 0;
1247 	priv->session_size = 0;
1248 
1249 	session_flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (session));
1250 	if (is_loaded) {
1251 		/* Set the correct medium and add the flag */
1252 		brasero_burn_session_set_burner (BRASERO_BURN_SESSION (session),
1253 						 brasero_medium_get_drive (medium));
1254 
1255 		if ((session_flags & BRASERO_BURN_FLAG_MERGE) == 0)
1256 			brasero_session_cfg_add_drive_properties_flags (session, BRASERO_BURN_FLAG_MERGE);
1257 	}
1258 	else if ((session_flags & BRASERO_BURN_FLAG_MERGE) != 0)
1259 		brasero_session_cfg_rm_drive_properties_flags (session, BRASERO_BURN_FLAG_MERGE);
1260 }
1261 
1262 static void
brasero_session_cfg_track_added(BraseroBurnSession * session,BraseroTrack * track)1263 brasero_session_cfg_track_added (BraseroBurnSession *session,
1264 				 BraseroTrack *track)
1265 {
1266 	BraseroSessionCfgPrivate *priv;
1267 
1268 	if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1269 		return;
1270 
1271 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1272 	priv->session_blocks = 0;
1273 	priv->session_size = 0;
1274 
1275 	if (BRASERO_IS_TRACK_DATA_CFG (track))
1276 		g_signal_connect (track,
1277 				  "session-loaded",
1278 				  G_CALLBACK (brasero_session_cfg_session_loaded),
1279 				  session);
1280 
1281 	/* A track was added:
1282 	 * - check if all flags are supported
1283 	 * - check available formats for path
1284 	 * - set one path */
1285 	brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1286 	brasero_session_cfg_check_drive_settings (BRASERO_SESSION_CFG (session));
1287 }
1288 
1289 static void
brasero_session_cfg_track_removed(BraseroBurnSession * session,BraseroTrack * track,guint former_position)1290 brasero_session_cfg_track_removed (BraseroBurnSession *session,
1291 				   BraseroTrack *track,
1292 				   guint former_position)
1293 {
1294 	BraseroSessionCfgPrivate *priv;
1295 
1296 	if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1297 		return;
1298 
1299 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1300 	priv->session_blocks = 0;
1301 	priv->session_size = 0;
1302 
1303 	/* Just in case */
1304 	g_signal_handlers_disconnect_by_func (track,
1305 					      brasero_session_cfg_session_loaded,
1306 					      session);
1307 
1308 	/* If there were several tracks and at least one remained there is no
1309 	 * use checking flags since the source type has not changed anyway.
1310 	 * If there is no more track, there is no use checking flags anyway. */
1311 	brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1312 }
1313 
1314 static void
brasero_session_cfg_track_changed(BraseroBurnSession * session,BraseroTrack * track)1315 brasero_session_cfg_track_changed (BraseroBurnSession *session,
1316 				   BraseroTrack *track)
1317 {
1318 	BraseroSessionCfgPrivate *priv;
1319 	BraseroTrackType *current;
1320 
1321 	if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1322 		return;
1323 
1324 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1325 	priv->session_blocks = 0;
1326 	priv->session_size = 0;
1327 
1328 	current = brasero_track_type_new ();
1329 	brasero_burn_session_get_input_type (session, current);
1330 	if (brasero_track_type_equal (current, priv->source)) {
1331 		/* This is a shortcut if the source type has not changed */
1332 		brasero_track_type_free (current);
1333 		brasero_session_cfg_check_size (BRASERO_SESSION_CFG (session));
1334 		g_signal_emit (session,
1335 			       session_cfg_signals [IS_VALID_SIGNAL],
1336 			       0);
1337  		return;
1338 	}
1339 	brasero_track_type_free (current);
1340 
1341 	/* when that happens it's mostly because a medium source changed, or
1342 	 * a new image was set.
1343 	 * - check if all flags are supported
1344 	 * - check available formats for path
1345 	 * - set one path if need be */
1346 	brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1347 	brasero_session_cfg_check_drive_settings (BRASERO_SESSION_CFG (session));
1348 }
1349 
1350 static void
brasero_session_cfg_output_changed(BraseroBurnSession * session,BraseroMedium * former)1351 brasero_session_cfg_output_changed (BraseroBurnSession *session,
1352 				    BraseroMedium *former)
1353 {
1354 	BraseroSessionCfgPrivate *priv;
1355 
1356 	if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1357 		return;
1358 
1359 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1360 	priv->disc_size = 0;
1361 
1362 	/* Case for video project */
1363 	if (priv->source
1364 	&&  brasero_track_type_get_has_stream (priv->source)
1365 	&&  BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (priv->source))) {
1366 		BraseroMedia media;
1367 
1368 		media = brasero_burn_session_get_dest_media (session);
1369 		if (media & BRASERO_MEDIUM_DVD)
1370 			brasero_burn_session_tag_add_int (session,
1371 			                                  BRASERO_DVD_STREAM_FORMAT,
1372 			                                  BRASERO_AUDIO_FORMAT_AC3);
1373 		else if (media & BRASERO_MEDIUM_CD)
1374 			brasero_burn_session_tag_add_int (session,
1375 							  BRASERO_DVD_STREAM_FORMAT,
1376 							  BRASERO_AUDIO_FORMAT_MP2);
1377 		else {
1378 			BraseroImageFormat format;
1379 
1380 			format = brasero_burn_session_get_output_format (session);
1381 			if (format == BRASERO_IMAGE_FORMAT_CUE)
1382 				brasero_burn_session_tag_add_int (session,
1383 								  BRASERO_DVD_STREAM_FORMAT,
1384 								  BRASERO_AUDIO_FORMAT_MP2);
1385 			else
1386 				brasero_burn_session_tag_add_int (session,
1387 								  BRASERO_DVD_STREAM_FORMAT,
1388 								  BRASERO_AUDIO_FORMAT_AC3);
1389 		}
1390 	}
1391 
1392 	/* In this case need to :
1393 	 * - check if all flags are supported
1394 	 * - for images, set a path if it wasn't already set */
1395 	brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1396 	brasero_session_cfg_check_drive_settings (BRASERO_SESSION_CFG (session));
1397 }
1398 
1399 static void
brasero_session_cfg_caps_changed(BraseroPluginManager * manager,BraseroSessionCfg * self)1400 brasero_session_cfg_caps_changed (BraseroPluginManager *manager,
1401 				  BraseroSessionCfg *self)
1402 {
1403 	BraseroSessionCfgPrivate *priv;
1404 
1405 	if (!brasero_session_cfg_can_update (self))
1406 		return;
1407 
1408 	priv = BRASERO_SESSION_CFG_PRIVATE (self);
1409 	priv->disc_size = 0;
1410 	priv->session_blocks = 0;
1411 	priv->session_size = 0;
1412 
1413 	/* In this case we need to check if:
1414 	 * - flags are supported or not supported anymore
1415 	 * - image types as input/output are supported
1416 	 * - if the current set of input/output still works */
1417 	brasero_session_cfg_update (self);
1418 	brasero_session_cfg_check_drive_settings (self);
1419 }
1420 
1421 /**
1422  * brasero_session_cfg_add_flags:
1423  * @session: a #BraseroSessionCfg
1424  * @flags: a #BraseroBurnFlag
1425  *
1426  * Adds all flags from @flags that are supported.
1427  *
1428  **/
1429 
1430 void
brasero_session_cfg_add_flags(BraseroSessionCfg * session,BraseroBurnFlag flags)1431 brasero_session_cfg_add_flags (BraseroSessionCfg *session,
1432 			       BraseroBurnFlag flags)
1433 {
1434 	BraseroSessionCfgPrivate *priv;
1435 
1436 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1437 
1438 	if ((priv->supported & flags) != flags)
1439 		return;
1440 
1441 	if ((brasero_burn_session_get_flags (BRASERO_BURN_SESSION (session)) & flags) == flags)
1442 		return;
1443 
1444 	brasero_session_cfg_add_drive_properties_flags (session, flags);
1445 
1446 	if (brasero_session_cfg_can_update (session))
1447 		brasero_session_cfg_update (session);
1448 }
1449 
1450 /**
1451  * brasero_session_cfg_remove_flags:
1452  * @session: a #BraseroSessionCfg
1453  * @flags: a #BraseroBurnFlag
1454  *
1455  * Removes all flags that are not compulsory.
1456  *
1457  **/
1458 
1459 void
brasero_session_cfg_remove_flags(BraseroSessionCfg * session,BraseroBurnFlag flags)1460 brasero_session_cfg_remove_flags (BraseroSessionCfg *session,
1461 				  BraseroBurnFlag flags)
1462 {
1463 	brasero_burn_session_remove_flag (BRASERO_BURN_SESSION (session), flags);
1464 
1465 	/* For this case reset all flags as some flags could
1466 	 * be made available after the removal of one flag
1467 	 * Example: After the removal of MULTI, FAST_BLANK
1468 	 * becomes available again for DVDRW sequential */
1469 	brasero_session_cfg_set_drive_properties_default_flags (session);
1470 
1471 	if (brasero_session_cfg_can_update (session))
1472 		brasero_session_cfg_update (session);
1473 }
1474 
1475 /**
1476  * brasero_session_cfg_is_supported:
1477  * @session: a #BraseroSessionCfg
1478  * @flag: a #BraseroBurnFlag
1479  *
1480  * Checks whether a particular flag is supported.
1481  *
1482  * Return value: a #gboolean. TRUE if it is supported;
1483  * FALSE otherwise.
1484  **/
1485 
1486 gboolean
brasero_session_cfg_is_supported(BraseroSessionCfg * session,BraseroBurnFlag flag)1487 brasero_session_cfg_is_supported (BraseroSessionCfg *session,
1488 				  BraseroBurnFlag flag)
1489 {
1490 	BraseroSessionCfgPrivate *priv;
1491 
1492 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1493 	return (priv->supported & flag) == flag;
1494 }
1495 
1496 /**
1497  * brasero_session_cfg_is_compulsory:
1498  * @session: a #BraseroSessionCfg
1499  * @flag: a #BraseroBurnFlag
1500  *
1501  * Checks whether a particular flag is compulsory.
1502  *
1503  * Return value: a #gboolean. TRUE if it is compulsory;
1504  * FALSE otherwise.
1505  **/
1506 
1507 gboolean
brasero_session_cfg_is_compulsory(BraseroSessionCfg * session,BraseroBurnFlag flag)1508 brasero_session_cfg_is_compulsory (BraseroSessionCfg *session,
1509 				   BraseroBurnFlag flag)
1510 {
1511 	BraseroSessionCfgPrivate *priv;
1512 
1513 	priv = BRASERO_SESSION_CFG_PRIVATE (session);
1514 	return (priv->compulsory & flag) == flag;
1515 }
1516 
1517 static void
brasero_session_cfg_init(BraseroSessionCfg * object)1518 brasero_session_cfg_init (BraseroSessionCfg *object)
1519 {
1520 	BraseroSessionCfgPrivate *priv;
1521 	BraseroPluginManager *manager;
1522 
1523 	priv = BRASERO_SESSION_CFG_PRIVATE (object);
1524 
1525 	priv->is_valid = BRASERO_SESSION_EMPTY;
1526 	manager = brasero_plugin_manager_get_default ();
1527 	g_signal_connect (manager,
1528 	                  "caps-changed",
1529 	                  G_CALLBACK (brasero_session_cfg_caps_changed),
1530 	                  object);
1531 }
1532 
1533 static void
brasero_session_cfg_finalize(GObject * object)1534 brasero_session_cfg_finalize (GObject *object)
1535 {
1536 	BraseroPluginManager *manager;
1537 	BraseroSessionCfgPrivate *priv;
1538 	GSList *tracks;
1539 
1540 	priv = BRASERO_SESSION_CFG_PRIVATE (object);
1541 
1542 	tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (object));
1543 	for (; tracks; tracks = tracks->next) {
1544 		BraseroTrack *track;
1545 
1546 		track = tracks->data;
1547 		g_signal_handlers_disconnect_by_func (track,
1548 						      brasero_session_cfg_session_loaded,
1549 						      object);
1550 	}
1551 
1552 	manager = brasero_plugin_manager_get_default ();
1553 	g_signal_handlers_disconnect_by_func (manager,
1554 	                                      brasero_session_cfg_caps_changed,
1555 	                                      object);
1556 
1557 	if (priv->source) {
1558 		brasero_track_type_free (priv->source);
1559 		priv->source = NULL;
1560 	}
1561 
1562 	if (priv->output) {
1563 		g_free (priv->output);
1564 		priv->output = NULL;
1565 	}
1566 
1567 	G_OBJECT_CLASS (brasero_session_cfg_parent_class)->finalize (object);
1568 }
1569 
1570 static void
brasero_session_cfg_class_init(BraseroSessionCfgClass * klass)1571 brasero_session_cfg_class_init (BraseroSessionCfgClass *klass)
1572 {
1573 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
1574 	BraseroBurnSessionClass *session_class = BRASERO_BURN_SESSION_CLASS (klass);
1575 
1576 	g_type_class_add_private (klass, sizeof (BraseroSessionCfgPrivate));
1577 
1578 	object_class->finalize = brasero_session_cfg_finalize;
1579 
1580 	session_class->get_output_path = brasero_session_cfg_get_output_path;
1581 	session_class->get_output_format = brasero_session_cfg_get_output_format;
1582 	session_class->set_output_image = brasero_session_cfg_set_output_image;
1583 
1584 	session_class->track_added = brasero_session_cfg_track_added;
1585 	session_class->track_removed = brasero_session_cfg_track_removed;
1586 	session_class->track_changed = brasero_session_cfg_track_changed;
1587 	session_class->output_changed = brasero_session_cfg_output_changed;
1588 	session_class->tag_changed = brasero_session_cfg_tag_changed;
1589 
1590 	session_cfg_signals [WRONG_EXTENSION_SIGNAL] =
1591 		g_signal_new ("wrong_extension",
1592 		              G_OBJECT_CLASS_TYPE (klass),
1593 		              G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP | G_SIGNAL_ACTION,
1594 		              0,
1595 		              NULL, NULL,
1596 		              brasero_marshal_BOOLEAN__VOID,
1597 		              G_TYPE_BOOLEAN,
1598 			      0,
1599 		              G_TYPE_NONE);
1600 	session_cfg_signals [IS_VALID_SIGNAL] =
1601 		g_signal_new ("is_valid",
1602 		              G_OBJECT_CLASS_TYPE (klass),
1603 		              G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP | G_SIGNAL_ACTION,
1604 		              0,
1605 		              NULL, NULL,
1606 		              g_cclosure_marshal_VOID__VOID,
1607 		              G_TYPE_NONE,
1608 			      0,
1609 		              G_TYPE_NONE);
1610 }
1611 
1612 /**
1613  * brasero_session_cfg_new:
1614  *
1615  *  Creates a new #BraseroSessionCfg object.
1616  *
1617  * Return value: a #BraseroSessionCfg object.
1618  **/
1619 
1620 BraseroSessionCfg *
brasero_session_cfg_new(void)1621 brasero_session_cfg_new (void)
1622 {
1623 	return g_object_new (BRASERO_TYPE_SESSION_CFG, NULL);
1624 }
1625