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 
37 #include <glib.h>
38 #include <glib/gi18n.h>
39 
40 #include "burn-caps.h"
41 #include "burn-debug.h"
42 #include "brasero-plugin.h"
43 #include "brasero-plugin-private.h"
44 #include "brasero-plugin-information.h"
45 #include "brasero-session-helper.h"
46 
47 #define BRASERO_BURN_CAPS_SHOULD_BLANK(media_MACRO, flags_MACRO)		\
48 	((media_MACRO & BRASERO_MEDIUM_UNFORMATTED) ||				\
49 	((media_MACRO & (BRASERO_MEDIUM_HAS_AUDIO|BRASERO_MEDIUM_HAS_DATA)) &&	\
50 	 (flags_MACRO & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND)) == FALSE))
51 
52 #define BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES(session)			\
53 {										\
54 	brasero_burn_session_log (session, "Unsupported type of task operation"); \
55 	BRASERO_BURN_LOG ("Unsupported type of task operation");		\
56 	return BRASERO_BURN_NOT_SUPPORTED;					\
57 }
58 
59 static BraseroBurnResult
brasero_burn_caps_get_blanking_flags_real(BraseroBurnCaps * caps,gboolean ignore_errors,BraseroMedia media,BraseroBurnFlag session_flags,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)60 brasero_burn_caps_get_blanking_flags_real (BraseroBurnCaps *caps,
61                                            gboolean ignore_errors,
62 					   BraseroMedia media,
63 					   BraseroBurnFlag session_flags,
64 					   BraseroBurnFlag *supported,
65 					   BraseroBurnFlag *compulsory)
66 {
67 	GSList *iter;
68 	gboolean supported_media;
69 	BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_NONE;
70 	BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_ALL;
71 
72 	BRASERO_BURN_LOG_DISC_TYPE (media, "Getting blanking flags for");
73 	if (media == BRASERO_MEDIUM_NONE) {
74 		BRASERO_BURN_LOG ("Blanking not possible: no media");
75 		if (supported)
76 			*supported = BRASERO_BURN_FLAG_NONE;
77 		if (compulsory)
78 			*compulsory = BRASERO_BURN_FLAG_NONE;
79 		return BRASERO_BURN_NOT_SUPPORTED;
80 	}
81 
82 	supported_media = FALSE;
83 	for (iter = caps->priv->caps_list; iter; iter = iter->next) {
84 		BraseroMedia caps_media;
85 		BraseroCaps *caps;
86 		GSList *links;
87 
88 		caps = iter->data;
89 		if (!brasero_track_type_get_has_medium (&caps->type))
90 			continue;
91 
92 		caps_media = brasero_track_type_get_medium_type (&caps->type);
93 		if ((media & caps_media) != media)
94 			continue;
95 
96 		for (links = caps->links; links; links = links->next) {
97 			GSList *plugins;
98 			BraseroCapsLink *link;
99 
100 			link = links->data;
101 
102 			if (link->caps != NULL)
103 				continue;
104 
105 			supported_media = TRUE;
106 			/* don't need the plugins to be sorted since we go
107 			 * through all the plugin list to get all blanking flags
108 			 * available. */
109 			for (plugins = link->plugins; plugins; plugins = plugins->next) {
110 				BraseroPlugin *plugin;
111 				BraseroBurnFlag supported_plugin;
112 				BraseroBurnFlag compulsory_plugin;
113 
114 				plugin = plugins->data;
115 				if (!brasero_plugin_get_active (plugin, ignore_errors))
116 					continue;
117 
118 				if (!brasero_plugin_get_blank_flags (plugin,
119 								     media,
120 								     session_flags,
121 								     &supported_plugin,
122 								     &compulsory_plugin))
123 					continue;
124 
125 				supported_flags |= supported_plugin;
126 				compulsory_flags &= compulsory_plugin;
127 			}
128 		}
129 	}
130 
131 	if (!supported_media) {
132 		BRASERO_BURN_LOG ("media blanking not supported");
133 		return BRASERO_BURN_NOT_SUPPORTED;
134 	}
135 
136 	/* This is a special case that is in MMC specs:
137 	 * DVD-RW sequential must be fully blanked
138 	 * if we really want multisession support. */
139 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW)
140 	&& (session_flags & BRASERO_BURN_FLAG_MULTI)) {
141 		if (compulsory_flags & BRASERO_BURN_FLAG_FAST_BLANK) {
142 			BRASERO_BURN_LOG ("fast media blanking only supported but multisession required for DVDRW");
143 			return BRASERO_BURN_NOT_SUPPORTED;
144 		}
145 
146 		supported_flags &= ~BRASERO_BURN_FLAG_FAST_BLANK;
147 
148 		BRASERO_BURN_LOG ("removed fast blank for a DVDRW with multisession");
149 	}
150 
151 	if (supported)
152 		*supported = supported_flags;
153 	if (compulsory)
154 		*compulsory = compulsory_flags;
155 
156 	return BRASERO_BURN_OK;
157 }
158 
159 /**
160  * brasero_burn_session_get_blank_flags:
161  * @session: a #BraseroBurnSession
162  * @supported: a #BraseroBurnFlag
163  * @compulsory: a #BraseroBurnFlag
164  *
165  * Given the various parameters stored in @session,
166  * stores in @supported and @compulsory, the flags
167  * that can be used (@supported) and must be used
168  * (@compulsory) when blanking the medium in the
169  * #BraseroDrive (set with brasero_burn_session_set_burner ()).
170  *
171  * Return value: a #BraseroBurnResult.
172  * BRASERO_BURN_OK if the retrieval was successful.
173  * BRASERO_BURN_ERR otherwise.
174  **/
175 
176 BraseroBurnResult
brasero_burn_session_get_blank_flags(BraseroBurnSession * session,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)177 brasero_burn_session_get_blank_flags (BraseroBurnSession *session,
178 				      BraseroBurnFlag *supported,
179 				      BraseroBurnFlag *compulsory)
180 {
181 	BraseroMedia media;
182 	BraseroBurnCaps *self;
183 	BraseroBurnResult result;
184 	BraseroBurnFlag session_flags;
185 
186 	media = brasero_burn_session_get_dest_media (session);
187 	BRASERO_BURN_LOG_DISC_TYPE (media, "Getting blanking flags for");
188 
189 	if (media == BRASERO_MEDIUM_NONE) {
190 		BRASERO_BURN_LOG ("Blanking not possible: no media");
191 		if (supported)
192 			*supported = BRASERO_BURN_FLAG_NONE;
193 		if (compulsory)
194 			*compulsory = BRASERO_BURN_FLAG_NONE;
195 		return BRASERO_BURN_NOT_SUPPORTED;
196 	}
197 
198 	session_flags = brasero_burn_session_get_flags (session);
199 
200 	self = brasero_burn_caps_get_default ();
201 	result = brasero_burn_caps_get_blanking_flags_real (self,
202 	                                                    brasero_burn_session_get_strict_support (session) == FALSE,
203 							    media,
204 							    session_flags,
205 							    supported,
206 							    compulsory);
207 	g_object_unref (self);
208 
209 	return result;
210 }
211 
212 static BraseroBurnResult
brasero_burn_caps_can_blank_real(BraseroBurnCaps * self,gboolean ignore_plugin_errors,BraseroMedia media,BraseroBurnFlag flags)213 brasero_burn_caps_can_blank_real (BraseroBurnCaps *self,
214                                   gboolean ignore_plugin_errors,
215                                   BraseroMedia media,
216 				  BraseroBurnFlag flags)
217 {
218 	GSList *iter;
219 
220 	BRASERO_BURN_LOG_DISC_TYPE (media, "Testing blanking caps for");
221 	if (media == BRASERO_MEDIUM_NONE) {
222 		BRASERO_BURN_LOG ("no media => no blanking possible");
223 		return BRASERO_BURN_NOT_SUPPORTED;
224 	}
225 
226 	/* This is a special case from MMC: DVD-RW sequential
227 	 * can only be multisession is they were fully blanked
228 	 * so if there are the two flags, abort. */
229 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW)
230 	&&  (flags & BRASERO_BURN_FLAG_MULTI)
231 	&&  (flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
232 		BRASERO_BURN_LOG ("fast media blanking only supported but multisession required for DVD-RW");
233 		return BRASERO_BURN_NOT_SUPPORTED;
234 	}
235 
236 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
237 		BraseroCaps *caps;
238 		GSList *links;
239 
240 		caps = iter->data;
241 		if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
242 			continue;
243 
244 		if ((media & brasero_track_type_get_medium_type (&caps->type)) != media)
245 			continue;
246 
247 		BRASERO_BURN_LOG_TYPE (&caps->type, "Searching links for caps");
248 
249 		for (links = caps->links; links; links = links->next) {
250 			GSList *plugins;
251 			BraseroCapsLink *link;
252 
253 			link = links->data;
254 
255 			if (link->caps != NULL)
256 				continue;
257 
258 			BRASERO_BURN_LOG ("Searching plugins");
259 
260 			/* Go through all plugins for the link and stop if we
261 			 * find at least one active plugin that accepts the
262 			 * flags. No need for plugins to be sorted */
263 			for (plugins = link->plugins; plugins; plugins = plugins->next) {
264 				BraseroPlugin *plugin;
265 
266 				plugin = plugins->data;
267 				if (!brasero_plugin_get_active (plugin, ignore_plugin_errors))
268 					continue;
269 
270 				if (brasero_plugin_check_blank_flags (plugin, media, flags)) {
271 					BRASERO_BURN_LOG_DISC_TYPE (media, "Can blank");
272 					return BRASERO_BURN_OK;
273 				}
274 			}
275 		}
276 	}
277 
278 	BRASERO_BURN_LOG_DISC_TYPE (media, "No blanking capabilities for");
279 
280 	return BRASERO_BURN_NOT_SUPPORTED;
281 }
282 
283 /**
284  * brasero_burn_session_can_blank:
285  * @session: a #BraseroBurnSession
286  *
287  * Given the various parameters stored in @session, this
288  * function checks whether the medium in the
289  * #BraseroDrive (set with brasero_burn_session_set_burner ())
290  * can be blanked.
291  *
292  * Return value: a #BraseroBurnResult.
293  * BRASERO_BURN_OK if it is possible.
294  * BRASERO_BURN_ERR otherwise.
295  **/
296 
297 BraseroBurnResult
brasero_burn_session_can_blank(BraseroBurnSession * session)298 brasero_burn_session_can_blank (BraseroBurnSession *session)
299 {
300 	BraseroMedia media;
301 	BraseroBurnFlag flags;
302 	BraseroBurnCaps *self;
303 	BraseroBurnResult result;
304 
305 	self = brasero_burn_caps_get_default ();
306 
307 	media = brasero_burn_session_get_dest_media (session);
308 	BRASERO_BURN_LOG_DISC_TYPE (media, "Testing blanking caps for");
309 
310 	if (media == BRASERO_MEDIUM_NONE) {
311 		BRASERO_BURN_LOG ("no media => no blanking possible");
312 		g_object_unref (self);
313 		return BRASERO_BURN_NOT_SUPPORTED;
314 	}
315 
316 	flags = brasero_burn_session_get_flags (session);
317 	result = brasero_burn_caps_can_blank_real (self,
318 	                                           brasero_burn_session_get_strict_support (session) == FALSE,
319 	                                           media,
320 	                                           flags);
321 	g_object_unref (self);
322 
323 	return result;
324 }
325 
326 static void
brasero_caps_link_get_record_flags(BraseroCapsLink * link,gboolean ignore_plugin_errors,BraseroMedia media,BraseroBurnFlag session_flags,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory_retval)327 brasero_caps_link_get_record_flags (BraseroCapsLink *link,
328                                     gboolean ignore_plugin_errors,
329 				    BraseroMedia media,
330 				    BraseroBurnFlag session_flags,
331 				    BraseroBurnFlag *supported,
332 				    BraseroBurnFlag *compulsory_retval)
333 {
334 	GSList *iter;
335 	BraseroBurnFlag compulsory;
336 
337 	compulsory = BRASERO_BURN_FLAG_ALL;
338 
339 	/* Go through all plugins to get the supported/... record flags for link */
340 	for (iter = link->plugins; iter; iter = iter->next) {
341 		gboolean result;
342 		BraseroPlugin *plugin;
343 		BraseroBurnFlag plugin_supported;
344 		BraseroBurnFlag plugin_compulsory;
345 
346 		plugin = iter->data;
347 		if (!brasero_plugin_get_active (plugin, ignore_plugin_errors))
348 			continue;
349 
350 		result = brasero_plugin_get_record_flags (plugin,
351 							  media,
352 							  session_flags,
353 							  &plugin_supported,
354 							  &plugin_compulsory);
355 		if (!result)
356 			continue;
357 
358 		*supported |= plugin_supported;
359 		compulsory &= plugin_compulsory;
360 	}
361 
362 	*compulsory_retval = compulsory;
363 }
364 
365 static void
brasero_caps_link_get_data_flags(BraseroCapsLink * link,gboolean ignore_plugin_errors,BraseroMedia media,BraseroBurnFlag session_flags,BraseroBurnFlag * supported)366 brasero_caps_link_get_data_flags (BraseroCapsLink *link,
367                                   gboolean ignore_plugin_errors,
368 				  BraseroMedia media,
369 				  BraseroBurnFlag session_flags,
370 				  BraseroBurnFlag *supported)
371 {
372 	GSList *iter;
373 
374 	/* Go through all plugins the get the supported/... data flags for link */
375 	for (iter = link->plugins; iter; iter = iter->next) {
376 		BraseroPlugin *plugin;
377 		BraseroBurnFlag plugin_supported;
378 		BraseroBurnFlag plugin_compulsory;
379 
380 		plugin = iter->data;
381 		if (!brasero_plugin_get_active (plugin, ignore_plugin_errors))
382 			continue;
383 
384 		brasero_plugin_get_image_flags (plugin,
385 		                                media,
386 		                                session_flags,
387 		                                &plugin_supported,
388 		                                &plugin_compulsory);
389 		*supported |= plugin_supported;
390 	}
391 }
392 
393 static gboolean
brasero_caps_link_check_data_flags(BraseroCapsLink * link,gboolean ignore_plugin_errors,BraseroBurnFlag session_flags,BraseroMedia media)394 brasero_caps_link_check_data_flags (BraseroCapsLink *link,
395                                     gboolean ignore_plugin_errors,
396 				    BraseroBurnFlag session_flags,
397 				    BraseroMedia media)
398 {
399 	GSList *iter;
400 	BraseroBurnFlag flags;
401 
402 	/* here we just make sure that at least one of the plugins in the link
403 	 * can comply with the flags (APPEND/MERGE) */
404 	flags = session_flags & (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE);
405 
406 	/* If there are no image flags forget it */
407 	if (flags == BRASERO_BURN_FLAG_NONE)
408 		return TRUE;
409 
410 	/* Go through all plugins; at least one must support image flags */
411 	for (iter = link->plugins; iter; iter = iter->next) {
412 		gboolean result;
413 		BraseroPlugin *plugin;
414 
415 		plugin = iter->data;
416 		if (!brasero_plugin_get_active (plugin, ignore_plugin_errors))
417 			continue;
418 
419 		result = brasero_plugin_check_image_flags (plugin,
420 							   media,
421 							   session_flags);
422 		if (result)
423 			return TRUE;
424 	}
425 
426 	return FALSE;
427 }
428 
429 static gboolean
brasero_caps_link_check_record_flags(BraseroCapsLink * link,gboolean ignore_plugin_errors,BraseroBurnFlag session_flags,BraseroMedia media)430 brasero_caps_link_check_record_flags (BraseroCapsLink *link,
431                                       gboolean ignore_plugin_errors,
432 				      BraseroBurnFlag session_flags,
433 				      BraseroMedia media)
434 {
435 	GSList *iter;
436 	BraseroBurnFlag flags;
437 
438 	flags = session_flags & BRASERO_PLUGIN_BURN_FLAG_MASK;
439 
440 	/* If there are no record flags forget it */
441 	if (flags == BRASERO_BURN_FLAG_NONE)
442 		return TRUE;
443 
444 	/* Go through all plugins: at least one must support record flags */
445 	for (iter = link->plugins; iter; iter = iter->next) {
446 		gboolean result;
447 		BraseroPlugin *plugin;
448 
449 		plugin = iter->data;
450 		if (!brasero_plugin_get_active (plugin, ignore_plugin_errors))
451 			continue;
452 
453 		result = brasero_plugin_check_record_flags (plugin,
454 							    media,
455 							    session_flags);
456 		if (result)
457 			return TRUE;
458 	}
459 
460 	return FALSE;
461 }
462 
463 static gboolean
brasero_caps_link_check_media_restrictions(BraseroCapsLink * link,gboolean ignore_plugin_errors,BraseroMedia media)464 brasero_caps_link_check_media_restrictions (BraseroCapsLink *link,
465                                             gboolean ignore_plugin_errors,
466 					    BraseroMedia media)
467 {
468 	GSList *iter;
469 
470 	/* Go through all plugins: at least one must support media */
471 	for (iter = link->plugins; iter; iter = iter->next) {
472 		gboolean result;
473 		BraseroPlugin *plugin;
474 
475 		plugin = iter->data;
476 		if (!brasero_plugin_get_active (plugin, ignore_plugin_errors))
477 			continue;
478 
479 		result = brasero_plugin_check_media_restrictions (plugin, media);
480 		if (result)
481 			return TRUE;
482 	}
483 
484 	return FALSE;
485 }
486 
487 static BraseroBurnResult
brasero_caps_report_plugin_error(BraseroPlugin * plugin,BraseroForeachPluginErrorCb callback,gpointer user_data)488 brasero_caps_report_plugin_error (BraseroPlugin *plugin,
489                                   BraseroForeachPluginErrorCb callback,
490                                   gpointer user_data)
491 {
492 	GSList *errors;
493 
494 	errors = brasero_plugin_get_errors (plugin);
495 	if (!errors)
496 		return BRASERO_BURN_ERR;
497 
498 	do {
499 		BraseroPluginError *error;
500 		BraseroBurnResult result;
501 
502 		error = errors->data;
503 		result = callback (error->type, error->detail, user_data);
504 		if (result == BRASERO_BURN_RETRY) {
505 			/* Something has been done
506 			 * to fix the error like an install
507 			 * so reload the errors */
508 			brasero_plugin_check_plugin_ready (plugin);
509 			errors = brasero_plugin_get_errors (plugin);
510 			continue;
511 		}
512 
513 		if (result != BRASERO_BURN_OK)
514 			return result;
515 
516 		errors = errors->next;
517 	} while (errors);
518 
519 	return BRASERO_BURN_OK;
520 }
521 
522 struct _BraseroFindLinkCtx {
523 	BraseroMedia media;
524 	BraseroTrackType *input;
525 	BraseroPluginIOFlag io_flags;
526 	BraseroBurnFlag session_flags;
527 
528 	BraseroForeachPluginErrorCb callback;
529 	gpointer user_data;
530 
531 	guint ignore_plugin_errors:1;
532 	guint check_session_flags:1;
533 };
534 typedef struct _BraseroFindLinkCtx BraseroFindLinkCtx;
535 
536 static void
brasero_caps_find_link_set_ctx(BraseroBurnSession * session,BraseroFindLinkCtx * ctx,BraseroTrackType * input)537 brasero_caps_find_link_set_ctx (BraseroBurnSession *session,
538                                 BraseroFindLinkCtx *ctx,
539                                 BraseroTrackType *input)
540 {
541 	ctx->input = input;
542 
543 	if (ctx->check_session_flags) {
544 		ctx->session_flags = brasero_burn_session_get_flags (session);
545 
546 		if (BRASERO_BURN_SESSION_NO_TMP_FILE (session))
547 			ctx->io_flags = BRASERO_PLUGIN_IO_ACCEPT_PIPE;
548 		else
549 			ctx->io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
550 	}
551 	else
552 		ctx->io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE|
553 					BRASERO_PLUGIN_IO_ACCEPT_PIPE;
554 
555 	if (!ctx->callback)
556 		ctx->ignore_plugin_errors = (brasero_burn_session_get_strict_support (session) == FALSE);
557 	else
558 		ctx->ignore_plugin_errors = TRUE;
559 }
560 
561 static BraseroBurnResult
brasero_caps_find_link(BraseroCaps * caps,BraseroFindLinkCtx * ctx)562 brasero_caps_find_link (BraseroCaps *caps,
563                         BraseroFindLinkCtx *ctx)
564 {
565 	GSList *iter;
566 
567 	BRASERO_BURN_LOG_WITH_TYPE (&caps->type, BRASERO_PLUGIN_IO_NONE, "Found link (with %i links):", g_slist_length (caps->links));
568 
569 	/* Here we only make sure we have at least one link working. For a link
570 	 * to be followed it must first:
571 	 * - link to a caps with correct io flags
572 	 * - have at least a plugin accepting the record flags if caps type is
573 	 *   a disc (that means that the link is the recording part)
574 	 *
575 	 * and either:
576 	 * - link to a caps equal to the input
577 	 * - link to a caps (linking itself to another caps, ...) accepting the
578 	 *   input
579 	 */
580 
581 	for (iter = caps->links; iter; iter = iter->next) {
582 		BraseroCapsLink *link;
583 		BraseroBurnResult result;
584 
585 		link = iter->data;
586 
587 		if (!link->caps)
588 			continue;
589 
590 		/* check that the link has some active plugin */
591 		if (!brasero_caps_link_active (link, ctx->ignore_plugin_errors))
592 			continue;
593 
594 		/* since this link contains recorders, check that at least one
595 		 * of them can handle the record flags */
596 		if (ctx->check_session_flags && brasero_track_type_get_has_medium (&caps->type)) {
597 			if (!brasero_caps_link_check_record_flags (link, ctx->ignore_plugin_errors, ctx->session_flags, ctx->media))
598 				continue;
599 
600 			if (brasero_caps_link_check_recorder_flags_for_input (link, ctx->session_flags) != BRASERO_BURN_OK)
601 				continue;
602 		}
603 
604 		/* first see if that's the perfect fit:
605 		 * - it must have the same caps (type + subtype)
606 		 * - it must have the proper IO */
607 		if (brasero_track_type_get_has_data (&link->caps->type)) {
608 			if (ctx->check_session_flags
609 			&& !brasero_caps_link_check_data_flags (link, ctx->ignore_plugin_errors, ctx->session_flags, ctx->media))
610 				continue;
611 		}
612 		else if (!brasero_caps_link_check_media_restrictions (link, ctx->ignore_plugin_errors, ctx->media))
613 			continue;
614 
615 		if ((link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
616 		&&   brasero_caps_is_compatible_type (link->caps, ctx->input)) {
617 			if (ctx->callback) {
618 				BraseroPlugin *plugin;
619 
620 				/* If we are supposed to report/signal that the plugin
621 				 * could be used but only if some more elements are
622 				 * installed */
623 				plugin = brasero_caps_link_need_download (link);
624 				if (plugin)
625 					return brasero_caps_report_plugin_error (plugin, ctx->callback, ctx->user_data);
626 			}
627 			return BRASERO_BURN_OK;
628 		}
629 
630 		/* we can't go further than a DISC type */
631 		if (brasero_track_type_get_has_medium (&link->caps->type))
632 			continue;
633 
634 		if ((link->caps->flags & ctx->io_flags) == BRASERO_PLUGIN_IO_NONE)
635 			continue;
636 
637 		/* try to see where the inputs of this caps leads to */
638 		result = brasero_caps_find_link (link->caps, ctx);
639 		if (result == BRASERO_BURN_CANCEL)
640 			return result;
641 
642 		if (result == BRASERO_BURN_OK) {
643 			if (ctx->callback) {
644 				BraseroPlugin *plugin;
645 
646 				/* If we are supposed to report/signal that the plugin
647 				 * could be used but only if some more elements are
648 				 * installed */
649 				plugin = brasero_caps_link_need_download (link);
650 				if (plugin)
651 					return brasero_caps_report_plugin_error (plugin, ctx->callback, ctx->user_data);
652 			}
653 			return BRASERO_BURN_OK;
654 		}
655 	}
656 
657 	return BRASERO_BURN_NOT_SUPPORTED;
658 }
659 
660 static BraseroBurnResult
brasero_caps_try_output(BraseroBurnCaps * self,BraseroFindLinkCtx * ctx,BraseroTrackType * output)661 brasero_caps_try_output (BraseroBurnCaps *self,
662                          BraseroFindLinkCtx *ctx,
663                          BraseroTrackType *output)
664 {
665 	BraseroCaps *caps;
666 
667 	/* here we search the start caps */
668 	caps = brasero_burn_caps_find_start_caps (self, output);
669 	if (!caps) {
670 		BRASERO_BURN_LOG ("No caps available");
671 		return BRASERO_BURN_NOT_SUPPORTED;
672 	}
673 
674 	/* Here flags don't matter as we don't record anything.
675 	 * Even the IOFlags since that can be checked later with
676 	 * brasero_burn_caps_get_flags. */
677 	if (brasero_track_type_get_has_medium (output))
678 		ctx->media = brasero_track_type_get_medium_type (output);
679 	else
680 		ctx->media = BRASERO_MEDIUM_FILE;
681 
682 	return brasero_caps_find_link (caps, ctx);
683 }
684 
685 static BraseroBurnResult
brasero_caps_try_output_with_blanking(BraseroBurnCaps * self,BraseroBurnSession * session,BraseroFindLinkCtx * ctx,BraseroTrackType * output)686 brasero_caps_try_output_with_blanking (BraseroBurnCaps *self,
687                                        BraseroBurnSession *session,
688                                        BraseroFindLinkCtx *ctx,
689                                        BraseroTrackType *output)
690 {
691 	gboolean result;
692 	BraseroCaps *last_caps;
693 
694 	result = brasero_caps_try_output (self, ctx, output);
695 	if (result == BRASERO_BURN_OK
696 	||  result == BRASERO_BURN_CANCEL)
697 		return result;
698 
699 	/* we reached this point in two cases:
700 	 * - if the disc cannot be handled
701 	 * - if some flags are not handled
702 	 * It is helpful only if:
703 	 * - the disc was closed and no plugin can handle this type of
704 	 * disc once closed (CD-R(W))
705 	 * - there was the flag BLANK_BEFORE_WRITE set and no plugin can
706 	 * handle this flag (means that the plugin should erase and
707 	 * then write on its own. Basically that works only with
708 	 * overwrite formatted discs, DVD+RW, ...) */
709 	if (!brasero_track_type_get_has_medium (output))
710 		return BRASERO_BURN_NOT_SUPPORTED;
711 
712 	/* output is a disc try with initial blanking */
713 	BRASERO_BURN_LOG ("Support for input/output failed.");
714 
715 	/* apparently nothing can be done to reach our goal. Maybe that
716 	 * is because we first have to blank the disc. If so add a blank
717 	 * task to the others as a first step */
718 	if ((ctx->check_session_flags
719 	&& !(ctx->session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE))
720 	||   brasero_burn_session_can_blank (session) != BRASERO_BURN_OK)
721 		return BRASERO_BURN_NOT_SUPPORTED;
722 
723 	BRASERO_BURN_LOG ("Trying with initial blanking");
724 
725 	/* retry with the same disc type but blank this time */
726 	ctx->media = brasero_track_type_get_medium_type (output);
727 	ctx->media &= ~(BRASERO_MEDIUM_CLOSED|
728 	                BRASERO_MEDIUM_APPENDABLE|
729 	                BRASERO_MEDIUM_UNFORMATTED|
730 	                BRASERO_MEDIUM_HAS_DATA|
731 	                BRASERO_MEDIUM_HAS_AUDIO);
732 	ctx->media |= BRASERO_MEDIUM_BLANK;
733 	brasero_track_type_set_medium_type (output, ctx->media);
734 
735 	last_caps = brasero_burn_caps_find_start_caps (self, output);
736 	if (!last_caps)
737 		return BRASERO_BURN_NOT_SUPPORTED;
738 
739 	return brasero_caps_find_link (last_caps, ctx);
740 }
741 
742 /**
743  * brasero_burn_session_input_supported:
744  * @session: a #BraseroBurnSession
745  * @input: a #BraseroTrackType
746  * @check_flags: a #gboolean
747  *
748  * Given the various parameters stored in @session, this
749  * function checks whether a session with the data type
750  * @type could be burnt to the medium in the #BraseroDrive (set
751  * through brasero_burn_session_set_burner ()).
752  * If @check_flags is %TRUE, then flags are taken into account
753  * and are not if it is %FALSE.
754  *
755  * Return value: a #BraseroBurnResult.
756  * BRASERO_BURN_OK if it is possible.
757  * BRASERO_BURN_ERR otherwise.
758  **/
759 
760 BraseroBurnResult
brasero_burn_session_input_supported(BraseroBurnSession * session,BraseroTrackType * input,gboolean check_flags)761 brasero_burn_session_input_supported (BraseroBurnSession *session,
762 				      BraseroTrackType *input,
763                                       gboolean check_flags)
764 {
765 	BraseroBurnCaps *self;
766 	BraseroBurnResult result;
767 	BraseroTrackType output;
768 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
769 
770 	result = brasero_burn_session_get_output_type (session, &output);
771 	if (result != BRASERO_BURN_OK)
772 		return result;
773 
774 	BRASERO_BURN_LOG_TYPE (input, "Checking support for input");
775 	BRASERO_BURN_LOG_TYPE (&output, "and output");
776 
777 	ctx.check_session_flags = check_flags;
778 	brasero_caps_find_link_set_ctx (session, &ctx, input);
779 
780 	if (check_flags) {
781 		result = brasero_check_flags_for_drive (brasero_burn_session_get_burner (session),
782 							ctx.session_flags);
783 
784 		if (!result)
785 			BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
786 
787 		BRASERO_BURN_LOG_FLAGS (ctx.session_flags, "with flags");
788 	}
789 
790 	self = brasero_burn_caps_get_default ();
791 	result = brasero_caps_try_output_with_blanking (self,
792 							session,
793 	                                                &ctx,
794 							&output);
795 	g_object_unref (self);
796 
797 	if (result != BRASERO_BURN_OK) {
798 		BRASERO_BURN_LOG_TYPE (input, "Input not supported");
799 		return result;
800 	}
801 
802 	return BRASERO_BURN_OK;
803 }
804 
805 /**
806  * brasero_burn_session_output_supported:
807  * @session: a #BraseroBurnSession *
808  * @output: a #BraseroTrackType *
809  *
810  * Make sure that the image type or medium type defined in @output can be
811  * created/burnt given the parameters and the current data set in @session.
812  *
813  * Return value: BRASERO_BURN_OK if the medium type or the image type can be used as an output.
814  **/
815 BraseroBurnResult
brasero_burn_session_output_supported(BraseroBurnSession * session,BraseroTrackType * output)816 brasero_burn_session_output_supported (BraseroBurnSession *session,
817 				       BraseroTrackType *output)
818 {
819 	BraseroBurnCaps *self;
820 	BraseroTrackType input;
821 	BraseroBurnResult result;
822 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
823 
824 	/* Here, we can't check if the drive supports the flags since the output
825 	 * is hypothetical. There is no real medium. So forget the following :
826 	 * if (!brasero_burn_caps_flags_check_for_drive (session))
827 	 *	BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
828 	 * The only thing we could do would be to check some known forbidden
829 	 * flags for some media provided the output type is DISC. */
830 
831 	brasero_burn_session_get_input_type (session, &input);
832 	brasero_caps_find_link_set_ctx (session, &ctx, &input);
833 
834 	BRASERO_BURN_LOG_TYPE (output, "Checking support for output");
835 	BRASERO_BURN_LOG_TYPE (&input, "and input");
836 	BRASERO_BURN_LOG_FLAGS (brasero_burn_session_get_flags (session), "with flags");
837 
838 	self = brasero_burn_caps_get_default ();
839 	result = brasero_caps_try_output_with_blanking (self,
840 							session,
841 	                                                &ctx,
842 							output);
843 	g_object_unref (self);
844 
845 	if (result != BRASERO_BURN_OK) {
846 		BRASERO_BURN_LOG_TYPE (output, "Output not supported");
847 		return result;
848 	}
849 
850 	return BRASERO_BURN_OK;
851 }
852 
853 /**
854  * This is only to be used in case one wants to copy using the same drive.
855  * It determines the possible middle image type.
856  */
857 
858 static BraseroBurnResult
brasero_burn_caps_is_session_supported_same_src_dest(BraseroBurnCaps * self,BraseroBurnSession * session,BraseroFindLinkCtx * ctx,BraseroTrackType * tmp_type)859 brasero_burn_caps_is_session_supported_same_src_dest (BraseroBurnCaps *self,
860 						      BraseroBurnSession *session,
861                                                       BraseroFindLinkCtx *ctx,
862                                                       BraseroTrackType *tmp_type)
863 {
864 	GSList *iter;
865 	BraseroDrive *burner;
866 	BraseroTrackType input;
867 	BraseroBurnResult result;
868 	BraseroTrackType output;
869 	BraseroImageFormat format;
870 
871 	BRASERO_BURN_LOG ("Checking disc copy support with same source and destination");
872 
873 	/* To determine if a CD/DVD can be copied using the same source/dest,
874 	 * we first determine if can be imaged and then if this image can be
875 	 * burnt to whatever medium type. */
876 	brasero_caps_find_link_set_ctx (session, ctx, &input);
877 	ctx->io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
878 
879 	memset (&input, 0, sizeof (BraseroTrackType));
880 	brasero_burn_session_get_input_type (session, &input);
881 	BRASERO_BURN_LOG_TYPE (&input, "input");
882 
883 	if (ctx->check_session_flags) {
884 		/* NOTE: DAO can be a problem. So just in case remove it. It is
885 		 * not really useful in this context. What we want here is to
886 		 * know whether a medium can be used given the input; only 1
887 		 * flag is important here (MERGE) and can have consequences. */
888 		ctx->session_flags &= ~BRASERO_BURN_FLAG_DAO;
889 		BRASERO_BURN_LOG_FLAGS (ctx->session_flags, "flags");
890 	}
891 
892 	burner = brasero_burn_session_get_burner (session);
893 
894 	/* First see if it works with a stream type */
895 	brasero_track_type_set_has_stream (&output);
896 
897 	/* FIXME! */
898 	brasero_track_type_set_stream_format (&output,
899 	                                      BRASERO_AUDIO_FORMAT_RAW|
900 	                                      BRASERO_METADATA_INFO);
901 
902 	BRASERO_BURN_LOG_TYPE (&output, "Testing stream type");
903 	result = brasero_caps_try_output (self, ctx, &output);
904 	if (result == BRASERO_BURN_CANCEL)
905 		return result;
906 
907 	if (result == BRASERO_BURN_OK) {
908 		BRASERO_BURN_LOG ("Stream type seems to be supported as output");
909 
910 		/* This format can be used to create an image. Check if can be
911 		 * burnt now. Just find at least one medium. */
912 		for (iter = self->priv->caps_list; iter; iter = iter->next) {
913 			BraseroBurnResult result;
914 			BraseroMedia media;
915 			BraseroCaps *caps;
916 
917 			caps = iter->data;
918 
919 			if (!brasero_track_type_get_has_medium (&caps->type))
920 				continue;
921 
922 			media = brasero_track_type_get_medium_type (&caps->type);
923 			/* Audio is only supported by CDs */
924 			if ((media & BRASERO_MEDIUM_CD) == 0)
925 				continue;
926 
927 			/* This type of disc cannot be burnt; skip them */
928 			if (media & BRASERO_MEDIUM_ROM)
929 				continue;
930 
931 			/* Make sure this is supported by the drive */
932 			if (!brasero_drive_can_write_media (burner, media))
933 				continue;
934 
935 			ctx->media = media;
936 			result = brasero_caps_find_link (caps, ctx);
937 			BRASERO_BURN_LOG_DISC_TYPE (media,
938 						    "Tested medium (%s)",
939 						    result == BRASERO_BURN_OK ? "working":"not working");
940 
941 			if (result == BRASERO_BURN_OK) {
942 				if (tmp_type) {
943 					brasero_track_type_set_has_stream (tmp_type);
944 					brasero_track_type_set_stream_format (tmp_type, brasero_track_type_get_stream_format (&output));
945 				}
946 
947 				return BRASERO_BURN_OK;
948 			}
949 
950 			if (result == BRASERO_BURN_CANCEL)
951 				return result;
952 		}
953 	}
954 	else
955 		BRASERO_BURN_LOG ("Stream format not supported as output");
956 
957 	/* Find one available output format */
958 	format = BRASERO_IMAGE_FORMAT_CDRDAO;
959 	brasero_track_type_set_has_image (&output);
960 
961 	for (; format > BRASERO_IMAGE_FORMAT_NONE; format >>= 1) {
962 		brasero_track_type_set_image_format (&output, format);
963 
964 		BRASERO_BURN_LOG_TYPE (&output, "Testing temporary image format");
965 
966 		/* Don't need to try blanking here (saves
967 		 * a few lines of debug) since that is an
968 		 * image */
969 		result = brasero_caps_try_output (self, ctx, &output);
970 		if (result == BRASERO_BURN_CANCEL)
971 			return result;
972 
973 		if (result != BRASERO_BURN_OK)
974 			continue;
975 
976 		/* This format can be used to create an image. Check if can be
977 		 * burnt now. Just find at least one medium. */
978 		for (iter = self->priv->caps_list; iter; iter = iter->next) {
979 			BraseroBurnResult result;
980 			BraseroMedia media;
981 			BraseroCaps *caps;
982 
983 			caps = iter->data;
984 
985 			if (!brasero_track_type_get_has_medium (&caps->type))
986 				continue;
987 
988 			media = brasero_track_type_get_medium_type (&caps->type);
989 
990 			/* This type of disc cannot be burnt; skip them */
991 			if (media & BRASERO_MEDIUM_ROM)
992 				continue;
993 
994 			/* These three types only work with CDs. Skip the rest. */
995 			if ((format == BRASERO_IMAGE_FORMAT_CDRDAO
996 			||   format == BRASERO_IMAGE_FORMAT_CLONE
997 			||   format == BRASERO_IMAGE_FORMAT_CUE)
998 			&& (media & BRASERO_MEDIUM_CD) == 0)
999 				continue;
1000 
1001 			/* Make sure this is supported by the drive */
1002 			if (!brasero_drive_can_write_media (burner, media))
1003 				continue;
1004 
1005 			ctx->media = media;
1006 			result = brasero_caps_find_link (caps, ctx);
1007 			BRASERO_BURN_LOG_DISC_TYPE (media,
1008 						    "Tested medium (%s)",
1009 						    result == BRASERO_BURN_OK ? "working":"not working");
1010 
1011 			if (result == BRASERO_BURN_OK) {
1012 				if (tmp_type) {
1013 					brasero_track_type_set_has_image (tmp_type);
1014 					brasero_track_type_set_image_format (tmp_type, brasero_track_type_get_image_format (&output));
1015 				}
1016 
1017 				return BRASERO_BURN_OK;
1018 			}
1019 
1020 			if (result == BRASERO_BURN_CANCEL)
1021 				return result;
1022 		}
1023 	}
1024 
1025 	return BRASERO_BURN_NOT_SUPPORTED;
1026 }
1027 
1028 BraseroBurnResult
brasero_burn_session_get_tmp_image_type_same_src_dest(BraseroBurnSession * session,BraseroTrackType * image_type)1029 brasero_burn_session_get_tmp_image_type_same_src_dest (BraseroBurnSession *session,
1030                                                        BraseroTrackType *image_type)
1031 {
1032 	BraseroBurnCaps *self;
1033 	BraseroBurnResult result;
1034 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
1035 
1036 	g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
1037 
1038 	self = brasero_burn_caps_get_default ();
1039 	result = brasero_burn_caps_is_session_supported_same_src_dest (self,
1040 	                                                               session,
1041 	                                                               &ctx,
1042 	                                                               image_type);
1043 	g_object_unref (self);
1044 	return result;
1045 }
1046 
1047 static BraseroBurnResult
brasero_burn_session_supported(BraseroBurnSession * session,BraseroFindLinkCtx * ctx)1048 brasero_burn_session_supported (BraseroBurnSession *session,
1049                                 BraseroFindLinkCtx *ctx)
1050 {
1051 	gboolean result;
1052 	BraseroBurnCaps *self;
1053 	BraseroTrackType input;
1054 	BraseroTrackType output;
1055 
1056 	/* Special case */
1057 	if (brasero_burn_session_same_src_dest_drive (session)) {
1058 		BraseroBurnResult res;
1059 
1060 		self = brasero_burn_caps_get_default ();
1061 		res = brasero_burn_caps_is_session_supported_same_src_dest (self, session, ctx, NULL);
1062 		g_object_unref (self);
1063 
1064 		return res;
1065 	}
1066 
1067 	result = brasero_burn_session_get_output_type (session, &output);
1068 	if (result != BRASERO_BURN_OK)
1069 		BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
1070 
1071 	brasero_burn_session_get_input_type (session, &input);
1072 	brasero_caps_find_link_set_ctx (session, ctx, &input);
1073 
1074 	BRASERO_BURN_LOG_TYPE (&output, "Checking support for session. Ouput is ");
1075 	BRASERO_BURN_LOG_TYPE (&input, "and input is");
1076 
1077 	if (ctx->check_session_flags) {
1078 		result = brasero_check_flags_for_drive (brasero_burn_session_get_burner (session), ctx->session_flags);
1079 		if (!result)
1080 			BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
1081 
1082 		BRASERO_BURN_LOG_FLAGS (ctx->session_flags, "with flags");
1083 	}
1084 
1085 	self = brasero_burn_caps_get_default ();
1086 	result = brasero_caps_try_output_with_blanking (self,
1087 							session,
1088 	                                                ctx,
1089 							&output);
1090 	g_object_unref (self);
1091 
1092 	if (result != BRASERO_BURN_OK) {
1093 		BRASERO_BURN_LOG_TYPE (&output, "Session not supported");
1094 		return result;
1095 	}
1096 
1097 	BRASERO_BURN_LOG_TYPE (&output, "Session supported");
1098 	return BRASERO_BURN_OK;
1099 }
1100 
1101 /**
1102  * brasero_burn_session_can_burn:
1103  * @session: a #BraseroBurnSession
1104  * @check_flags: a #gboolean
1105  *
1106  * Given the various parameters stored in @session, this
1107  * function checks whether the data contained in @session
1108  * can be burnt to the medium in the #BraseroDrive (set
1109  * through brasero_burn_session_set_burner ()).
1110  * If @check_flags determine the behavior of this function.
1111  *
1112  * Return value: a #BraseroBurnResult.
1113  * BRASERO_BURN_OK if it is possible.
1114  * BRASERO_BURN_ERR otherwise.
1115  **/
1116 
1117 BraseroBurnResult
brasero_burn_session_can_burn(BraseroBurnSession * session,gboolean check_flags)1118 brasero_burn_session_can_burn (BraseroBurnSession *session,
1119 			       gboolean check_flags)
1120 {
1121 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
1122 
1123 	g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
1124 
1125 	ctx.check_session_flags = check_flags;
1126 
1127 	return brasero_burn_session_supported (session, &ctx);
1128 }
1129 
1130 /**
1131  * brasero_session_foreach_plugin_error:
1132  * @session: a #BraseroBurnSession.
1133  * @callback: a #BraseroSessionPluginErrorCb.
1134  * @user_data: a #gpointer. The data passed to @callback.
1135  *
1136  * Call @callback for each error in plugins.
1137  *
1138  * Return value: a #BraseroBurnResult.
1139  * BRASERO_BURN_OK if it is possible.
1140  * BRASERO_BURN_ERR otherwise.
1141  **/
1142 
1143 BraseroBurnResult
brasero_session_foreach_plugin_error(BraseroBurnSession * session,BraseroForeachPluginErrorCb callback,gpointer user_data)1144 brasero_session_foreach_plugin_error (BraseroBurnSession *session,
1145                                       BraseroForeachPluginErrorCb callback,
1146                                       gpointer user_data)
1147 {
1148 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
1149 
1150 	g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
1151 
1152 	ctx.callback = callback;
1153 	ctx.user_data = user_data;
1154 
1155 	return brasero_burn_session_supported (session, &ctx);
1156 }
1157 
1158 /**
1159  * brasero_burn_session_get_required_media_type:
1160  * @session: a #BraseroBurnSession
1161  *
1162  * Return the medium types that could be used to burn
1163  * @session.
1164  *
1165  * Return value: a #BraseroMedia
1166  **/
1167 
1168 BraseroMedia
brasero_burn_session_get_required_media_type(BraseroBurnSession * session)1169 brasero_burn_session_get_required_media_type (BraseroBurnSession *session)
1170 {
1171 	BraseroMedia required_media = BRASERO_MEDIUM_NONE;
1172 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
1173 	BraseroTrackType input;
1174 	BraseroBurnCaps *self;
1175 	GSList *iter;
1176 
1177 	if (brasero_burn_session_is_dest_file (session))
1178 		return BRASERO_MEDIUM_FILE;
1179 
1180 	/* we try to determine here what type of medium is allowed to be burnt
1181 	 * to whether a CD or a DVD. Appendable, blank are not properties being
1182 	 * determined here. We just want it to be writable in a broad sense. */
1183 	ctx.check_session_flags = TRUE;
1184 	brasero_burn_session_get_input_type (session, &input);
1185 	brasero_caps_find_link_set_ctx (session, &ctx, &input);
1186 	BRASERO_BURN_LOG_TYPE (&input, "Determining required media type for input");
1187 
1188 	/* NOTE: BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE is a problem here since it
1189 	 * is only used if needed. Likewise DAO can be a problem. So just in
1190 	 * case remove them. They are not really useful in this context. What we
1191 	 * want here is to know which media can be used given the input; only 1
1192 	 * flag is important here (MERGE) and can have consequences. */
1193 	ctx.session_flags &= ~BRASERO_BURN_FLAG_DAO;
1194 	BRASERO_BURN_LOG_FLAGS (ctx.session_flags, "and flags");
1195 
1196 	self = brasero_burn_caps_get_default ();
1197 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
1198 		BraseroCaps *caps;
1199 		gboolean result;
1200 
1201 		caps = iter->data;
1202 
1203 		if (!brasero_track_type_get_has_medium (&caps->type))
1204 			continue;
1205 
1206 		/* Put BRASERO_MEDIUM_NONE so we can always succeed */
1207 		result = brasero_caps_find_link (caps, &ctx);
1208 		BRASERO_BURN_LOG_DISC_TYPE (caps->type.subtype.media,
1209 					    "Tested (%s)",
1210 					    result == BRASERO_BURN_OK ? "working":"not working");
1211 
1212 		if (result == BRASERO_BURN_CANCEL) {
1213 			g_object_unref (self);
1214 			return result;
1215 		}
1216 
1217 		if (result != BRASERO_BURN_OK)
1218 			continue;
1219 
1220 		/* This caps work, add its subtype */
1221 		required_media |= brasero_track_type_get_medium_type (&caps->type);
1222 	}
1223 
1224 	/* filter as we are only interested in these */
1225 	required_media &= BRASERO_MEDIUM_WRITABLE|
1226 			  BRASERO_MEDIUM_CD|
1227 			  BRASERO_MEDIUM_DVD;
1228 
1229 	g_object_unref (self);
1230 	return required_media;
1231 }
1232 
1233 /**
1234  * brasero_burn_session_get_possible_output_formats:
1235  * @session: a #BraseroBurnSession
1236  * @formats: a #BraseroImageFormat
1237  *
1238  * Returns the disc image types that could be set to create
1239  * an image given the current state of @session.
1240  *
1241  * Return value: a #guint. The number of formats available.
1242  **/
1243 
1244 guint
brasero_burn_session_get_possible_output_formats(BraseroBurnSession * session,BraseroImageFormat * formats)1245 brasero_burn_session_get_possible_output_formats (BraseroBurnSession *session,
1246 						  BraseroImageFormat *formats)
1247 {
1248 	guint num = 0;
1249 	BraseroImageFormat format;
1250 	BraseroTrackType *output = NULL;
1251 
1252 	g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), 0);
1253 
1254 	/* see how many output format are available */
1255 	format = BRASERO_IMAGE_FORMAT_CDRDAO;
1256 	(*formats) = BRASERO_IMAGE_FORMAT_NONE;
1257 
1258 	output = brasero_track_type_new ();
1259 	brasero_track_type_set_has_image (output);
1260 
1261 	for (; format > BRASERO_IMAGE_FORMAT_NONE; format >>= 1) {
1262 		BraseroBurnResult result;
1263 
1264 		brasero_track_type_set_image_format (output, format);
1265 		result = brasero_burn_session_output_supported (session, output);
1266 		if (result == BRASERO_BURN_OK) {
1267 			(*formats) |= format;
1268 			num ++;
1269 		}
1270 	}
1271 
1272 	brasero_track_type_free (output);
1273 
1274 	return num;
1275 }
1276 
1277 /**
1278  * brasero_burn_session_get_default_output_format:
1279  * @session: a #BraseroBurnSession
1280  *
1281  * Returns the default disc image type that should be set to create
1282  * an image given the current state of @session.
1283  *
1284  * Return value: a #BraseroImageFormat
1285  **/
1286 
1287 BraseroImageFormat
brasero_burn_session_get_default_output_format(BraseroBurnSession * session)1288 brasero_burn_session_get_default_output_format (BraseroBurnSession *session)
1289 {
1290 	BraseroBurnCaps *self;
1291 	BraseroBurnResult result;
1292 	BraseroTrackType source = { BRASERO_TRACK_TYPE_NONE, { 0, }};
1293 	BraseroTrackType output = { BRASERO_TRACK_TYPE_NONE, { 0, }};
1294 
1295 	self = brasero_burn_caps_get_default ();
1296 
1297 	if (!brasero_burn_session_is_dest_file (session)) {
1298 		g_object_unref (self);
1299 		return BRASERO_IMAGE_FORMAT_NONE;
1300 	}
1301 
1302 	brasero_burn_session_get_input_type (session, &source);
1303 	if (brasero_track_type_is_empty (&source)) {
1304 		g_object_unref (self);
1305 		return BRASERO_IMAGE_FORMAT_NONE;
1306 	}
1307 
1308 	if (brasero_track_type_get_has_image (&source)) {
1309 		g_object_unref (self);
1310 		return brasero_track_type_get_image_format (&source);
1311 	}
1312 
1313 	brasero_track_type_set_has_image (&output);
1314 	brasero_track_type_set_image_format (&output, BRASERO_IMAGE_FORMAT_NONE);
1315 
1316 	if (brasero_track_type_get_has_stream (&source)) {
1317 		/* Otherwise try all possible image types */
1318 		output.subtype.img_format = BRASERO_IMAGE_FORMAT_CDRDAO;
1319 		for (; output.subtype.img_format != BRASERO_IMAGE_FORMAT_NONE;
1320 		       output.subtype.img_format >>= 1) {
1321 
1322 			result = brasero_burn_session_output_supported (session,
1323 									&output);
1324 			if (result == BRASERO_BURN_OK) {
1325 				g_object_unref (self);
1326 				return brasero_track_type_get_image_format (&output);
1327 			}
1328 		}
1329 
1330 		g_object_unref (self);
1331 		return BRASERO_IMAGE_FORMAT_NONE;
1332 	}
1333 
1334 	if (brasero_track_type_get_has_data (&source)
1335 	|| (brasero_track_type_get_has_medium (&source)
1336 	&& (brasero_track_type_get_medium_type (&source) & BRASERO_MEDIUM_DVD))) {
1337 		brasero_track_type_set_image_format (&output, BRASERO_IMAGE_FORMAT_BIN);
1338 		result = brasero_burn_session_output_supported (session, &output);
1339 		g_object_unref (self);
1340 
1341 		if (result != BRASERO_BURN_OK)
1342 			return BRASERO_IMAGE_FORMAT_NONE;
1343 
1344 		return BRASERO_IMAGE_FORMAT_BIN;
1345 	}
1346 
1347 	/* for the input which are CDs there are lots of possible formats */
1348 	output.subtype.img_format = BRASERO_IMAGE_FORMAT_CDRDAO;
1349 	for (; output.subtype.img_format != BRASERO_IMAGE_FORMAT_NONE;
1350 	       output.subtype.img_format >>= 1) {
1351 
1352 		result = brasero_burn_session_output_supported (session, &output);
1353 		if (result == BRASERO_BURN_OK) {
1354 			g_object_unref (self);
1355 			return brasero_track_type_get_image_format (&output);
1356 		}
1357 	}
1358 
1359 	g_object_unref (self);
1360 	return BRASERO_IMAGE_FORMAT_NONE;
1361 }
1362 
1363 static BraseroBurnResult
brasero_caps_set_flags_from_recorder_input(BraseroTrackType * input,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)1364 brasero_caps_set_flags_from_recorder_input (BraseroTrackType *input,
1365                                             BraseroBurnFlag *supported,
1366                                             BraseroBurnFlag *compulsory)
1367 {
1368 	if (brasero_track_type_get_has_image (input)) {
1369 		BraseroImageFormat format;
1370 
1371 		format = brasero_track_type_get_image_format (input);
1372 		if (format == BRASERO_IMAGE_FORMAT_CUE
1373 		||  format == BRASERO_IMAGE_FORMAT_CDRDAO) {
1374 			if ((*supported) & BRASERO_BURN_FLAG_DAO)
1375 				(*compulsory) |= BRASERO_BURN_FLAG_DAO;
1376 			else
1377 				return BRASERO_BURN_NOT_SUPPORTED;
1378 		}
1379 		else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
1380 			/* RAW write mode should (must) only be used in this case */
1381 			if ((*supported) & BRASERO_BURN_FLAG_RAW) {
1382 				(*supported) &= ~BRASERO_BURN_FLAG_DAO;
1383 				(*compulsory) &= ~BRASERO_BURN_FLAG_DAO;
1384 				(*compulsory) |= BRASERO_BURN_FLAG_RAW;
1385 			}
1386 			else
1387 				return BRASERO_BURN_NOT_SUPPORTED;
1388 		}
1389 		else
1390 			(*supported) &= ~BRASERO_BURN_FLAG_RAW;
1391 	}
1392 
1393 	return BRASERO_BURN_OK;
1394 }
1395 
1396 static BraseroPluginIOFlag
brasero_caps_get_flags(BraseroCaps * caps,gboolean ignore_plugin_errors,BraseroBurnFlag session_flags,BraseroMedia media,BraseroTrackType * input,BraseroPluginIOFlag flags,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)1397 brasero_caps_get_flags (BraseroCaps *caps,
1398                         gboolean ignore_plugin_errors,
1399 			BraseroBurnFlag session_flags,
1400 			BraseroMedia media,
1401 			BraseroTrackType *input,
1402 			BraseroPluginIOFlag flags,
1403 			BraseroBurnFlag *supported,
1404 			BraseroBurnFlag *compulsory)
1405 {
1406 	GSList *iter;
1407 	BraseroPluginIOFlag retval = BRASERO_PLUGIN_IO_NONE;
1408 
1409 	/* First we must know if this link leads somewhere. It must
1410 	 * accept the already existing flags. If it does, see if it
1411 	 * accepts the input and if not, if one of its ancestors does */
1412 	for (iter = caps->links; iter; iter = iter->next) {
1413 		BraseroBurnFlag data_supported = BRASERO_BURN_FLAG_NONE;
1414 		BraseroBurnFlag rec_compulsory = BRASERO_BURN_FLAG_ALL;
1415 		BraseroBurnFlag rec_supported = BRASERO_BURN_FLAG_NONE;
1416 		BraseroPluginIOFlag io_flags;
1417 		BraseroCapsLink *link;
1418 
1419 		link = iter->data;
1420 
1421 		if (!link->caps)
1422 			continue;
1423 
1424 		/* check that the link has some active plugin */
1425 		if (!brasero_caps_link_active (link, ignore_plugin_errors))
1426 			continue;
1427 
1428 		if (brasero_track_type_get_has_medium (&caps->type)) {
1429 			BraseroBurnFlag tmp;
1430 			BraseroBurnResult result;
1431 
1432 			brasero_caps_link_get_record_flags (link,
1433 			                                    ignore_plugin_errors,
1434 							    media,
1435 							    session_flags,
1436 							    &rec_supported,
1437 							    &rec_compulsory);
1438 
1439 			/* see if that link can handle the record flags.
1440 			 * NOTE: compulsory are not a failure in this case. */
1441 			tmp = session_flags & BRASERO_PLUGIN_BURN_FLAG_MASK;
1442 			if ((tmp & rec_supported) != tmp)
1443 				continue;
1444 
1445 			/* This is the recording plugin, check its input as
1446 			 * some flags depend on it. */
1447 			result = brasero_caps_set_flags_from_recorder_input (&link->caps->type,
1448 			                                                     &rec_supported,
1449 			                                                     &rec_compulsory);
1450 			if (result != BRASERO_BURN_OK)
1451 				continue;
1452 		}
1453 
1454 		if (brasero_track_type_get_has_data (&link->caps->type)) {
1455 			BraseroBurnFlag tmp;
1456 
1457 			brasero_caps_link_get_data_flags (link,
1458 			                                  ignore_plugin_errors,
1459 							  media,
1460 							  session_flags,
1461 						    	  &data_supported);
1462 
1463 			/* see if that link can handle the data flags.
1464 			 * NOTE: compulsory are not a failure in this case. */
1465 			tmp = session_flags & (BRASERO_BURN_FLAG_APPEND|
1466 					       BRASERO_BURN_FLAG_MERGE);
1467 
1468 			if ((tmp & data_supported) != tmp)
1469 				continue;
1470 		}
1471 		else if (!brasero_caps_link_check_media_restrictions (link, ignore_plugin_errors, media))
1472 			continue;
1473 
1474 		/* see if that's the perfect fit */
1475 		if ((link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
1476 		&&   brasero_caps_is_compatible_type (link->caps, input)) {
1477 			/* special case for input that handle output/input */
1478 			if (caps->type.type == BRASERO_TRACK_TYPE_DISC)
1479 				retval |= BRASERO_PLUGIN_IO_ACCEPT_PIPE;
1480 			else
1481 				retval |= caps->flags;
1482 
1483 			(*compulsory) &= rec_compulsory;
1484 			(*supported) |= data_supported|rec_supported;
1485 			continue;
1486 		}
1487 
1488 		if ((link->caps->flags & flags) == BRASERO_PLUGIN_IO_NONE)
1489 			continue;
1490 
1491 		/* we can't go further than a DISC type */
1492 		if (link->caps->type.type == BRASERO_TRACK_TYPE_DISC)
1493 			continue;
1494 
1495 		/* try to see where the inputs of this caps leads to */
1496 		io_flags = brasero_caps_get_flags (link->caps,
1497 		                                   ignore_plugin_errors,
1498 						   session_flags,
1499 						   media,
1500 						   input,
1501 						   flags,
1502 						   supported,
1503 						   compulsory);
1504 		if (io_flags == BRASERO_PLUGIN_IO_NONE)
1505 			continue;
1506 
1507 		(*compulsory) &= rec_compulsory;
1508 		retval |= (io_flags & flags);
1509 		(*supported) |= data_supported|rec_supported;
1510 	}
1511 
1512 	return retval;
1513 }
1514 
1515 static void
brasero_medium_supported_flags(BraseroMedium * medium,BraseroBurnFlag * supported_flags,BraseroBurnFlag * compulsory_flags)1516 brasero_medium_supported_flags (BraseroMedium *medium,
1517 				BraseroBurnFlag *supported_flags,
1518                                 BraseroBurnFlag *compulsory_flags)
1519 {
1520 	BraseroMedia media;
1521 
1522 	media = brasero_medium_get_status (medium);
1523 
1524 	/* This is always FALSE */
1525 	if (media & BRASERO_MEDIUM_PLUS)
1526 		(*supported_flags) &= ~BRASERO_BURN_FLAG_DUMMY;
1527 
1528 	/* Simulation is only possible according to write modes. This mode is
1529 	 * mostly used by cdrecord/wodim for CLONE images. */
1530 	else if (media & BRASERO_MEDIUM_DVD) {
1531 		if (!brasero_medium_can_use_dummy_for_sao (medium))
1532 			(*supported_flags) &= ~BRASERO_BURN_FLAG_DUMMY;
1533 	}
1534 	else if ((*supported_flags) & BRASERO_BURN_FLAG_DAO) {
1535 		if (!brasero_medium_can_use_dummy_for_sao (medium))
1536 			(*supported_flags) &= ~BRASERO_BURN_FLAG_DUMMY;
1537 	}
1538 	else if (!brasero_medium_can_use_dummy_for_tao (medium))
1539 		(*supported_flags) &= ~BRASERO_BURN_FLAG_DUMMY;
1540 
1541 	/* The following is only true if we won't _have_ to blank
1542 	 * the disc since a CLOSED disc is not able for tao/sao.
1543 	 * so if BLANK_BEFORE_RIGHT is TRUE then we leave
1544 	 * the benefit of the doubt, but flags should be rechecked
1545 	 * after the drive was blanked. */
1546 	if (((*compulsory_flags) & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE) == 0
1547 	&&  !BRASERO_MEDIUM_RANDOM_WRITABLE (media)
1548 	&&  !brasero_medium_can_use_tao (medium)) {
1549 		(*supported_flags) &= ~BRASERO_BURN_FLAG_MULTI;
1550 
1551 		if (brasero_medium_can_use_sao (medium))
1552 			(*compulsory_flags) |= BRASERO_BURN_FLAG_DAO;
1553 		else
1554 			(*supported_flags) &= ~BRASERO_BURN_FLAG_DAO;
1555 	}
1556 
1557 	if (!brasero_medium_can_use_burnfree (medium))
1558 		(*supported_flags) &= ~BRASERO_BURN_FLAG_BURNPROOF;
1559 }
1560 
1561 static void
brasero_burn_caps_flags_update_for_drive(BraseroBurnSession * session,BraseroBurnFlag * supported_flags,BraseroBurnFlag * compulsory_flags)1562 brasero_burn_caps_flags_update_for_drive (BraseroBurnSession *session,
1563                                           BraseroBurnFlag *supported_flags,
1564                                           BraseroBurnFlag *compulsory_flags)
1565 {
1566 	BraseroDrive *drive;
1567 	BraseroMedium *medium;
1568 
1569 	drive = brasero_burn_session_get_burner (session);
1570 	if (!drive)
1571 		return;
1572 
1573 	medium = brasero_drive_get_medium (drive);
1574 	if (!medium)
1575 		return;
1576 
1577 	brasero_medium_supported_flags (medium,
1578 	                                supported_flags,
1579 	                                compulsory_flags);
1580 }
1581 
1582 static BraseroBurnResult
brasero_caps_get_flags_for_disc(BraseroBurnCaps * self,gboolean ignore_plugin_errors,BraseroBurnFlag session_flags,BraseroMedia media,BraseroTrackType * input,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)1583 brasero_caps_get_flags_for_disc (BraseroBurnCaps *self,
1584                                  gboolean ignore_plugin_errors,
1585 				 BraseroBurnFlag session_flags,
1586 				 BraseroMedia media,
1587 				 BraseroTrackType *input,
1588 				 BraseroBurnFlag *supported,
1589 				 BraseroBurnFlag *compulsory)
1590 {
1591 	BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_NONE;
1592 	BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_ALL;
1593 	BraseroPluginIOFlag io_flags;
1594 	BraseroTrackType output;
1595 	BraseroCaps *caps;
1596 
1597 	/* create the output to find first caps */
1598 	brasero_track_type_set_has_medium (&output);
1599 	brasero_track_type_set_medium_type (&output, media);
1600 
1601 	caps = brasero_burn_caps_find_start_caps (self, &output);
1602 	if (!caps) {
1603 		BRASERO_BURN_LOG_DISC_TYPE (media, "FLAGS: no caps could be found for");
1604 		return BRASERO_BURN_NOT_SUPPORTED;
1605 	}
1606 
1607 	BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
1608 				    caps->flags,
1609 				    "FLAGS: trying caps");
1610 
1611 	io_flags = brasero_caps_get_flags (caps,
1612 	                                   ignore_plugin_errors,
1613 					   session_flags,
1614 					   media,
1615 					   input,
1616 					   BRASERO_PLUGIN_IO_ACCEPT_FILE|
1617 					   BRASERO_PLUGIN_IO_ACCEPT_PIPE,
1618 					   &supported_flags,
1619 					   &compulsory_flags);
1620 
1621 	if (io_flags == BRASERO_PLUGIN_IO_NONE) {
1622 		BRASERO_BURN_LOG ("FLAGS: not supported");
1623 		return BRASERO_BURN_NOT_SUPPORTED;
1624 	}
1625 
1626 	/* NOTE: DO NOT TEST the input image here. What should be tested is the
1627 	 * type of the input right before the burner plugin. See:
1628 	 * brasero_burn_caps_set_flags_from_recorder_input())
1629 	 * For example in the following situation: AUDIO => CUE => BURNER the
1630 	 * DAO flag would not be set otherwise. */
1631 
1632 	if (brasero_track_type_get_has_stream (input)) {
1633 		BraseroStreamFormat format;
1634 
1635 		format = brasero_track_type_get_stream_format (input);
1636 		if (format & BRASERO_METADATA_INFO) {
1637 			/* In this case, DAO is compulsory if we want to write CD-TEXT */
1638 			if (supported_flags & BRASERO_BURN_FLAG_DAO)
1639 				compulsory_flags |= BRASERO_BURN_FLAG_DAO;
1640 			else
1641 				return BRASERO_BURN_NOT_SUPPORTED;
1642 		}
1643 	}
1644 
1645 	if (compulsory_flags & BRASERO_BURN_FLAG_DAO) {
1646 		/* unlikely */
1647 		compulsory_flags &= ~BRASERO_BURN_FLAG_RAW;
1648 		supported_flags &= ~BRASERO_BURN_FLAG_RAW;
1649 	}
1650 
1651 	if (io_flags & BRASERO_PLUGIN_IO_ACCEPT_PIPE) {
1652 		supported_flags |= BRASERO_BURN_FLAG_NO_TMP_FILES;
1653 
1654 		if ((io_flags & BRASERO_PLUGIN_IO_ACCEPT_FILE) == 0)
1655 			compulsory_flags |= BRASERO_BURN_FLAG_NO_TMP_FILES;
1656 	}
1657 
1658 	*supported |= supported_flags;
1659 	*compulsory |= compulsory_flags;
1660 
1661 	return BRASERO_BURN_OK;
1662 }
1663 
1664 static BraseroBurnResult
brasero_burn_caps_get_flags_for_medium(BraseroBurnCaps * self,BraseroBurnSession * session,BraseroMedia media,BraseroBurnFlag session_flags,BraseroTrackType * input,BraseroBurnFlag * supported_flags,BraseroBurnFlag * compulsory_flags)1665 brasero_burn_caps_get_flags_for_medium (BraseroBurnCaps *self,
1666                                         BraseroBurnSession *session,
1667 					BraseroMedia media,
1668 					BraseroBurnFlag session_flags,
1669 					BraseroTrackType *input,
1670 					BraseroBurnFlag *supported_flags,
1671 					BraseroBurnFlag *compulsory_flags)
1672 {
1673 	BraseroBurnResult result;
1674 	gboolean can_blank = FALSE;
1675 
1676 	/* See if medium is supported out of the box */
1677 	result = brasero_caps_get_flags_for_disc (self,
1678 	                                          brasero_burn_session_get_strict_support (session) == FALSE,
1679 						  session_flags,
1680 						  media,
1681 						  input,
1682 						  supported_flags,
1683 						  compulsory_flags);
1684 
1685 	/* see if we can add BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE. Add it when:
1686 	 * - media can be blanked, it has audio or data and we're not merging
1687 	 * - media is not formatted and it can be blanked/formatted */
1688 	if (brasero_burn_caps_can_blank_real (self, brasero_burn_session_get_strict_support (session) == FALSE, media, session_flags) == BRASERO_BURN_OK)
1689 		can_blank = TRUE;
1690 	else if (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)
1691 		return BRASERO_BURN_NOT_SUPPORTED;
1692 
1693 	if (can_blank) {
1694 		gboolean first_success;
1695 		BraseroBurnFlag blank_compulsory = BRASERO_BURN_FLAG_NONE;
1696 		BraseroBurnFlag blank_supported = BRASERO_BURN_FLAG_NONE;
1697 
1698 		/* we reached this point in two cases:
1699 		 * - if the disc cannot be handled
1700 		 * - if some flags are not handled
1701 		 * It is helpful only if:
1702 		 * - the disc was closed and no plugin can handle this type of
1703 		 * disc once closed (CD-R(W))
1704 		 * - there was the flag BLANK_BEFORE_WRITE set and no plugin can
1705 		 * handle this flag (means that the plugin should erase and
1706 		 * then write on its own. Basically that works only with
1707 		 * overwrite formatted discs, DVD+RW, ...) */
1708 
1709 		/* What's above is not entirely true. In fact we always need to
1710 		 * check even if we first succeeded. There are some cases like
1711 		 * CDRW where it's useful.
1712 		 * Ex: a CDRW with data appendable can be either appended (then
1713 		 * no DAO possible) or blanked and written (DAO possible). */
1714 
1715 		/* result here is the result of the first operation, so if it
1716 		 * failed, BLANK before becomes compulsory. */
1717 		first_success = (result == BRASERO_BURN_OK);
1718 
1719 		/* pretends it is blank and formatted to see if it would work.
1720 		 * If it works then that means that the BLANK_BEFORE_WRITE flag
1721 		 * is compulsory. */
1722 		media &= ~(BRASERO_MEDIUM_CLOSED|
1723 			   BRASERO_MEDIUM_APPENDABLE|
1724 			   BRASERO_MEDIUM_UNFORMATTED|
1725 			   BRASERO_MEDIUM_HAS_DATA|
1726 			   BRASERO_MEDIUM_HAS_AUDIO);
1727 		media |= BRASERO_MEDIUM_BLANK;
1728 		result = brasero_caps_get_flags_for_disc (self,
1729 		                                          brasero_burn_session_get_strict_support (session) == FALSE,
1730 							  session_flags,
1731 							  media,
1732 							  input,
1733 							  supported_flags,
1734 							  compulsory_flags);
1735 
1736 		/* if both attempts failed, drop it */
1737 		if (result != BRASERO_BURN_OK) {
1738 			/* See if we entirely failed */
1739 			if (!first_success)
1740 				return result;
1741 
1742 			/* we tried with a blank medium but did not
1743 			 * succeed. So that means the flags BLANK.
1744 			 * is not supported */
1745 		}
1746 		else {
1747 			(*supported_flags) |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE;
1748 
1749 			if (!first_success)
1750 				(*compulsory_flags) |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE;
1751 
1752 			/* If BLANK flag is supported then MERGE/APPEND can't be compulsory */
1753 			(*compulsory_flags) &= ~(BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND);
1754 
1755 			/* need to add blanking flags */
1756 			brasero_burn_caps_get_blanking_flags_real (self,
1757 			                                           brasero_burn_session_get_strict_support (session) == FALSE,
1758 								   media,
1759 								   session_flags,
1760 								   &blank_supported,
1761 								   &blank_compulsory);
1762 			(*supported_flags) |= blank_supported;
1763 			(*compulsory_flags) |= blank_compulsory;
1764 		}
1765 
1766 	}
1767 	else if (result != BRASERO_BURN_OK)
1768 		return result;
1769 
1770 	/* These are a special case for DVDRW sequential */
1771 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW)) {
1772 		/* That's a way to give priority to MULTI over FAST
1773 		 * and leave the possibility to always use MULTI. */
1774 		if (session_flags & BRASERO_BURN_FLAG_MULTI)
1775 			(*supported_flags) &= ~BRASERO_BURN_FLAG_FAST_BLANK;
1776 		else if ((session_flags & BRASERO_BURN_FLAG_FAST_BLANK)
1777 		         &&  (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)) {
1778 			/* We should be able to handle this case differently but unfortunately
1779 			 * there are buggy firmwares that won't report properly the supported
1780 			 * mode writes */
1781 			if (!((*supported_flags) & BRASERO_BURN_FLAG_DAO))
1782 					 return BRASERO_BURN_NOT_SUPPORTED;
1783 
1784 			(*compulsory_flags) |= BRASERO_BURN_FLAG_DAO;
1785 		}
1786 	}
1787 
1788 	if (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE) {
1789 		/* make sure we remove MERGE/APPEND from supported and
1790 		 * compulsory since that's not possible anymore */
1791 		(*supported_flags) &= ~(BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND);
1792 		(*compulsory_flags) &= ~(BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND);
1793 	}
1794 
1795 	/* FIXME! we should restart the whole process if
1796 	 * ((session_flags & compulsory_flags) != compulsory_flags) since that
1797 	 * means that some supported files could be excluded but were not */
1798 
1799 	return BRASERO_BURN_OK;
1800 }
1801 
1802 static BraseroBurnResult
brasero_burn_caps_get_flags_same_src_dest_for_types(BraseroBurnCaps * self,BraseroBurnSession * session,BraseroTrackType * input,BraseroTrackType * output,BraseroBurnFlag * supported_ret,BraseroBurnFlag * compulsory_ret)1803 brasero_burn_caps_get_flags_same_src_dest_for_types (BraseroBurnCaps *self,
1804                                                      BraseroBurnSession *session,
1805                                                      BraseroTrackType *input,
1806                                                      BraseroTrackType *output,
1807                                                      BraseroBurnFlag *supported_ret,
1808                                                      BraseroBurnFlag *compulsory_ret)
1809 {
1810 	GSList *iter;
1811 	gboolean type_supported;
1812 	BraseroBurnResult result;
1813 	BraseroBurnFlag session_flags;
1814 	BraseroFindLinkCtx ctx = { 0, NULL, 0, };
1815 	BraseroBurnFlag supported_final = BRASERO_BURN_FLAG_NONE;
1816 	BraseroBurnFlag compulsory_final = BRASERO_BURN_FLAG_ALL;
1817 
1818 	/* NOTE: there is no need to get the flags here since there are
1819 	 * no specific DISC => IMAGE flags. We just want to know if that
1820 	 * is possible. */
1821 	BRASERO_BURN_LOG_TYPE (output, "Testing temporary image format");
1822 
1823 	brasero_caps_find_link_set_ctx (session, &ctx, input);
1824 	ctx.io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
1825 
1826 	/* Here there is no need to try blanking as there
1827 	 * is no disc (saves a few debug lines) */
1828 	result = brasero_caps_try_output (self, &ctx, output);
1829 	if (result != BRASERO_BURN_OK) {
1830 		BRASERO_BURN_LOG_TYPE (output, "Format not supported");
1831 		return result;
1832 	}
1833 
1834 	session_flags = brasero_burn_session_get_flags (session);
1835 
1836 	/* This format can be used to create an image. Check if can be
1837 	 * burnt now. Just find at least one medium. */
1838 	type_supported = FALSE;
1839 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
1840 		BraseroBurnFlag compulsory;
1841 		BraseroBurnFlag supported;
1842 		BraseroBurnResult result;
1843 		BraseroMedia media;
1844 		BraseroCaps *caps;
1845 
1846 		caps = iter->data;
1847 		if (!brasero_track_type_get_has_medium (&caps->type))
1848 			continue;
1849 
1850 		media = brasero_track_type_get_medium_type (&caps->type);
1851 
1852 		/* This type of disc cannot be burnt; skip them */
1853 		if (media & BRASERO_MEDIUM_ROM)
1854 			continue;
1855 
1856 		if ((media & BRASERO_MEDIUM_CD) == 0) {
1857 			if (brasero_track_type_get_has_image (output)) {
1858 				BraseroImageFormat format;
1859 
1860 				format = brasero_track_type_get_image_format (output);
1861 				/* These three types only work with CDs. */
1862 				if (format == BRASERO_IMAGE_FORMAT_CDRDAO
1863 				||   format == BRASERO_IMAGE_FORMAT_CLONE
1864 				||   format == BRASERO_IMAGE_FORMAT_CUE)
1865 					continue;
1866 			}
1867 			else if (brasero_track_type_get_has_stream (output))
1868 				continue;
1869 		}
1870 
1871 		/* Merge all available flags for each possible medium type */
1872 		supported = BRASERO_BURN_FLAG_NONE;
1873 		compulsory = BRASERO_BURN_FLAG_NONE;
1874 
1875 		result = brasero_caps_get_flags_for_disc (self,
1876 		                                          brasero_burn_session_get_strict_support (session) == FALSE,
1877 		                                          session_flags,
1878 		                                          media,
1879 							  output,
1880 							  &supported,
1881 							  &compulsory);
1882 
1883 		if (result != BRASERO_BURN_OK)
1884 			continue;
1885 
1886 		type_supported = TRUE;
1887 		supported_final |= supported;
1888 		compulsory_final &= compulsory;
1889 	}
1890 
1891 	BRASERO_BURN_LOG_TYPE (output, "Format supported %i", type_supported);
1892 	if (!type_supported)
1893 		return BRASERO_BURN_NOT_SUPPORTED;
1894 
1895 	*supported_ret = supported_final;
1896 	*compulsory_ret = compulsory_final;
1897 	return BRASERO_BURN_OK;
1898 }
1899 
1900 static BraseroBurnResult
brasero_burn_caps_get_flags_same_src_dest(BraseroBurnCaps * self,BraseroBurnSession * session,BraseroBurnFlag * supported_ret,BraseroBurnFlag * compulsory_ret)1901 brasero_burn_caps_get_flags_same_src_dest (BraseroBurnCaps *self,
1902 					   BraseroBurnSession *session,
1903 					   BraseroBurnFlag *supported_ret,
1904 					   BraseroBurnFlag *compulsory_ret)
1905 {
1906 	BraseroTrackType input;
1907 	BraseroBurnResult result;
1908 	gboolean copy_supported;
1909 	BraseroTrackType output;
1910 	BraseroImageFormat format;
1911 	BraseroBurnFlag session_flags;
1912 	BraseroBurnFlag supported_final = BRASERO_BURN_FLAG_NONE;
1913 	BraseroBurnFlag compulsory_final = BRASERO_BURN_FLAG_ALL;
1914 
1915 	BRASERO_BURN_LOG ("Retrieving disc copy flags with same source and destination");
1916 
1917 	/* To determine if a CD/DVD can be copied using the same source/dest,
1918 	 * we first determine if can be imaged and then what are the flags when
1919 	 * we can burn it to a particular medium type. */
1920 	memset (&input, 0, sizeof (BraseroTrackType));
1921 	brasero_burn_session_get_input_type (session, &input);
1922 	BRASERO_BURN_LOG_TYPE (&input, "input");
1923 
1924 	session_flags = brasero_burn_session_get_flags (session);
1925 	BRASERO_BURN_LOG_FLAGS (session_flags, "(FLAGS) Session flags");
1926 
1927 	/* Check the current flags are possible */
1928 	if (session_flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_NO_TMP_FILES))
1929 		return BRASERO_BURN_NOT_SUPPORTED;
1930 
1931 	/* Check for stream type */
1932 	brasero_track_type_set_has_stream (&output);
1933 	/* FIXME! */
1934 	brasero_track_type_set_stream_format (&output,
1935 	                                      BRASERO_AUDIO_FORMAT_RAW|
1936 	                                      BRASERO_METADATA_INFO);
1937 
1938 	result = brasero_burn_caps_get_flags_same_src_dest_for_types (self,
1939 	                                                              session,
1940 	                                                              &input,
1941 	                                                              &output,
1942 	                                                              &supported_final,
1943 	                                                              &compulsory_final);
1944 	if (result == BRASERO_BURN_CANCEL)
1945 		return result;
1946 
1947 	copy_supported = (result == BRASERO_BURN_OK);
1948 
1949 	/* Check flags for all available format */
1950 	format = BRASERO_IMAGE_FORMAT_CDRDAO;
1951 	brasero_track_type_set_has_image (&output);
1952 	for (; format > BRASERO_IMAGE_FORMAT_NONE; format >>= 1) {
1953 		BraseroBurnFlag supported;
1954 		BraseroBurnFlag compulsory;
1955 
1956 		/* check if this image type is possible given the current flags */
1957 		if (format != BRASERO_IMAGE_FORMAT_CLONE
1958 		&& (session_flags & BRASERO_BURN_FLAG_RAW))
1959 			continue;
1960 
1961 		brasero_track_type_set_image_format (&output, format);
1962 
1963 		supported = BRASERO_BURN_FLAG_NONE;
1964 		compulsory = BRASERO_BURN_FLAG_NONE;
1965 		result = brasero_burn_caps_get_flags_same_src_dest_for_types (self,
1966 		                                                              session,
1967 		                                                              &input,
1968 		                                                              &output,
1969 		                                                              &supported,
1970 		                                                              &compulsory);
1971 		if (result == BRASERO_BURN_CANCEL)
1972 			return result;
1973 
1974 		if (result != BRASERO_BURN_OK)
1975 			continue;
1976 
1977 		copy_supported = TRUE;
1978 		supported_final |= supported;
1979 		compulsory_final &= compulsory;
1980 	}
1981 
1982 	if (!copy_supported)
1983 		return BRASERO_BURN_NOT_SUPPORTED;
1984 
1985 	*supported_ret |= supported_final;
1986 	*compulsory_ret |= compulsory_final;
1987 
1988 	/* we also add these two flags as being supported
1989 	 * since they could be useful and can't be tested
1990 	 * until the disc is inserted which it is not at the
1991 	 * moment */
1992 	(*supported_ret) |= (BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE|
1993 			     BRASERO_BURN_FLAG_FAST_BLANK);
1994 
1995 	if (brasero_track_type_get_medium_type (&input) & BRASERO_MEDIUM_HAS_AUDIO) {
1996 		/* This is a special case for audio discs.
1997 		 * Since they may contain CD-TEXT and
1998 		 * since CD-TEXT can only be written with
1999 		 * DAO then we must make sure the user
2000 		 * can't use MULTI since then DAO is
2001 		 * impossible. */
2002 		(*compulsory_ret) |= BRASERO_BURN_FLAG_DAO;
2003 
2004 		/* This is just to make sure */
2005 		(*supported_ret) &= (~BRASERO_BURN_FLAG_MULTI);
2006 		(*compulsory_ret) &= (~BRASERO_BURN_FLAG_MULTI);
2007 	}
2008 
2009 	return BRASERO_BURN_OK;
2010 }
2011 
2012 /**
2013  * This is meant to use as internal API
2014  */
2015 BraseroBurnResult
brasero_caps_session_get_image_flags(BraseroTrackType * input,BraseroTrackType * output,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)2016 brasero_caps_session_get_image_flags (BraseroTrackType *input,
2017                                      BraseroTrackType *output,
2018                                      BraseroBurnFlag *supported,
2019                                      BraseroBurnFlag *compulsory)
2020 {
2021 	BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_NONE;
2022 	BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_CHECK_SIZE|BRASERO_BURN_FLAG_NOGRACE;
2023 
2024 	BRASERO_BURN_LOG ("FLAGS: image required");
2025 
2026 	/* In this case no APPEND/MERGE is possible */
2027 	if (brasero_track_type_get_has_medium (input))
2028 		supported_flags |= BRASERO_BURN_FLAG_EJECT;
2029 
2030 	*supported = supported_flags;
2031 	*compulsory = compulsory_flags;
2032 
2033 	BRASERO_BURN_LOG_FLAGS (supported_flags, "FLAGS: supported");
2034 	BRASERO_BURN_LOG_FLAGS (compulsory_flags, "FLAGS: compulsory");
2035 
2036 	return BRASERO_BURN_OK;
2037 }
2038 
2039 /**
2040  * brasero_burn_session_get_burn_flags:
2041  * @session: a #BraseroBurnSession
2042  * @supported: a #BraseroBurnFlag or NULL
2043  * @compulsory: a #BraseroBurnFlag or NULL
2044  *
2045  * Given the various parameters stored in @session, this function
2046  * stores:
2047  * - the flags that can be used (@supported)
2048  * - the flags that must be used (@compulsory)
2049  * when writing @session to a disc.
2050  *
2051  * Return value: a #BraseroBurnResult.
2052  * BRASERO_BURN_OK if the retrieval was successful.
2053  * BRASERO_BURN_ERR otherwise.
2054  **/
2055 
2056 BraseroBurnResult
brasero_burn_session_get_burn_flags(BraseroBurnSession * session,BraseroBurnFlag * supported,BraseroBurnFlag * compulsory)2057 brasero_burn_session_get_burn_flags (BraseroBurnSession *session,
2058 				     BraseroBurnFlag *supported,
2059 				     BraseroBurnFlag *compulsory)
2060 {
2061 	gboolean res;
2062 	BraseroMedia media;
2063 	BraseroBurnCaps *self;
2064 	BraseroTrackType *input;
2065 	BraseroBurnResult result;
2066 
2067 	BraseroBurnFlag session_flags;
2068 	/* FIXME: what's the meaning of NOGRACE when outputting ? */
2069 	BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_NONE;
2070 	BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_CHECK_SIZE|
2071 					  BRASERO_BURN_FLAG_NOGRACE;
2072 
2073 	self = brasero_burn_caps_get_default ();
2074 
2075 	input = brasero_track_type_new ();
2076 	brasero_burn_session_get_input_type (session, input);
2077 	BRASERO_BURN_LOG_WITH_TYPE (input,
2078 				    BRASERO_PLUGIN_IO_NONE,
2079 				    "FLAGS: searching available flags for input");
2080 
2081 	if (brasero_burn_session_is_dest_file (session)) {
2082 		BraseroTrackType *output;
2083 
2084 		BRASERO_BURN_LOG ("FLAGS: image required");
2085 
2086 		output = brasero_track_type_new ();
2087 		brasero_burn_session_get_output_type (session, output);
2088 		brasero_caps_session_get_image_flags (input, output, supported, compulsory);
2089 		brasero_track_type_free (output);
2090 
2091 		brasero_track_type_free (input);
2092 		g_object_unref (self);
2093 		return BRASERO_BURN_OK;
2094 	}
2095 
2096 	supported_flags |= BRASERO_BURN_FLAG_EJECT;
2097 
2098 	/* special case */
2099 	if (brasero_burn_session_same_src_dest_drive (session)) {
2100 		BRASERO_BURN_LOG ("Same source and destination");
2101 		result = brasero_burn_caps_get_flags_same_src_dest (self,
2102 								    session,
2103 								    &supported_flags,
2104 								    &compulsory_flags);
2105 
2106 		/* These flags are of course never possible */
2107 		supported_flags &= ~(BRASERO_BURN_FLAG_NO_TMP_FILES|
2108 				     BRASERO_BURN_FLAG_MERGE);
2109 		compulsory_flags &= ~(BRASERO_BURN_FLAG_NO_TMP_FILES|
2110 				      BRASERO_BURN_FLAG_MERGE);
2111 
2112 		if (result == BRASERO_BURN_OK) {
2113 			BRASERO_BURN_LOG_FLAGS (supported_flags, "FLAGS: supported");
2114 			BRASERO_BURN_LOG_FLAGS (compulsory_flags, "FLAGS: compulsory");
2115 
2116 			*supported = supported_flags;
2117 			*compulsory = compulsory_flags;
2118 		}
2119 		else
2120 			BRASERO_BURN_LOG ("No available flags for copy");
2121 
2122 		brasero_track_type_free (input);
2123 		g_object_unref (self);
2124 		return result;
2125 	}
2126 
2127 	session_flags = brasero_burn_session_get_flags (session);
2128 	BRASERO_BURN_LOG_FLAGS (session_flags, "FLAGS (session):");
2129 
2130 	/* sanity check:
2131 	 * - drive must support flags
2132 	 * - MERGE and BLANK are not possible together.
2133 	 * - APPEND and MERGE are compatible. MERGE wins
2134 	 * - APPEND and BLANK are incompatible */
2135 	res = brasero_check_flags_for_drive (brasero_burn_session_get_burner (session), session_flags);
2136 	if (!res) {
2137 		BRASERO_BURN_LOG ("Session flags not supported by drive");
2138 		brasero_track_type_free (input);
2139 		g_object_unref (self);
2140 		return BRASERO_BURN_ERR;
2141 	}
2142 
2143 	if ((session_flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND))
2144 	&&  (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)) {
2145 		brasero_track_type_free (input);
2146 		g_object_unref (self);
2147 		return BRASERO_BURN_NOT_SUPPORTED;
2148 	}
2149 
2150 	/* Let's get flags for recording */
2151 	media = brasero_burn_session_get_dest_media (session);
2152 	result = brasero_burn_caps_get_flags_for_medium (self,
2153 	                                                 session,
2154 							 media,
2155 							 session_flags,
2156 							 input,
2157 							 &supported_flags,
2158 							 &compulsory_flags);
2159 
2160 	brasero_track_type_free (input);
2161 	g_object_unref (self);
2162 
2163 	if (result != BRASERO_BURN_OK)
2164 		return result;
2165 
2166 	brasero_burn_caps_flags_update_for_drive (session,
2167 	                                          &supported_flags,
2168 	                                          &compulsory_flags);
2169 
2170 	if (supported)
2171 		*supported = supported_flags;
2172 
2173 	if (compulsory)
2174 		*compulsory = compulsory_flags;
2175 
2176 	BRASERO_BURN_LOG_FLAGS (supported_flags, "FLAGS: supported");
2177 	BRASERO_BURN_LOG_FLAGS (compulsory_flags, "FLAGS: compulsory");
2178 	return BRASERO_BURN_OK;
2179 }
2180