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 #include <string.h>
31 
32 #ifdef HAVE_CONFIG_H
33 #  include <config.h>
34 #endif
35 
36 #include <glib.h>
37 #include <glib/gi18n-lib.h>
38 #include <glib/gstdio.h>
39 
40 #include <gst/gst.h>
41 #include <gst/pbutils/pbutils.h>
42 
43 #include "brasero-io.h"
44 
45 #include "burn-basics.h"
46 #include "burn-debug.h"
47 #include "burn-caps.h"
48 #include "burn-plugin-manager.h"
49 #include "brasero-plugin-information.h"
50 
51 #include "brasero-drive.h"
52 #include "brasero-medium-monitor.h"
53 
54 #include "brasero-burn-lib.h"
55 #include "burn-caps.h"
56 
57 static BraseroPluginManager *plugin_manager = NULL;
58 static BraseroMediumMonitor *medium_manager = NULL;
59 static BraseroBurnCaps *default_caps = NULL;
60 
61 
62 GQuark
brasero_burn_quark(void)63 brasero_burn_quark (void)
64 {
65 	static GQuark quark = 0;
66 
67 	if (!quark)
68 		quark = g_quark_from_static_string ("BraseroBurnError");
69 
70 	return quark;
71 }
72 
73 const gchar *
brasero_burn_action_to_string(BraseroBurnAction action)74 brasero_burn_action_to_string (BraseroBurnAction action)
75 {
76 	gchar *strings [BRASERO_BURN_ACTION_LAST] = { 	"",
77 							N_("Getting size"),
78 							N_("Creating image"),
79 							N_("Writing"),
80 							N_("Blanking"),
81 							N_("Creating checksum"),
82 							N_("Copying disc"),
83 							N_("Copying file"),
84 							N_("Analysing audio files"),
85 							N_("Transcoding song"),
86 							N_("Preparing to write"),
87 							N_("Writing leadin"),
88 							N_("Writing CD-Text information"),
89 							N_("Finalizing"),
90 							N_("Writing leadout"),
91 						        N_("Starting to record"),
92 							N_("Success"),
93 							N_("Ejecting medium")};
94 	return _(strings [action]);
95 }
96 
97 /**
98  * utility functions
99  */
100 
101 gboolean
brasero_check_flags_for_drive(BraseroDrive * drive,BraseroBurnFlag flags)102 brasero_check_flags_for_drive (BraseroDrive *drive,
103 			       BraseroBurnFlag flags)
104 {
105 	BraseroMedia media;
106 	BraseroMedium *medium;
107 
108 	if (!drive)
109 		return TRUE;
110 
111 	if (brasero_drive_is_fake (drive))
112 		return TRUE;
113 
114 	medium = brasero_drive_get_medium (drive);
115 	if (!medium)
116 		return TRUE;
117 
118 	media = brasero_medium_get_status (medium);
119 	if (flags & BRASERO_BURN_FLAG_DUMMY) {
120 		/* This is always FALSE */
121 		if (media & BRASERO_MEDIUM_PLUS) {
122 			BRASERO_BURN_LOG ("Drive does not support BRASERO_MEDIUM_PLUS flag");
123 			return FALSE;
124 		}
125 
126 		if (media & BRASERO_MEDIUM_DVD) {
127 			if (!brasero_medium_can_use_dummy_for_sao (medium)) {
128 				BRASERO_BURN_LOG ("Drive does not support using dummy for SAO");
129 				return FALSE;
130 			}
131 		}
132 		else if (flags & BRASERO_BURN_FLAG_DAO) {
133 			if (!brasero_medium_can_use_dummy_for_sao (medium)) {
134 				BRASERO_BURN_LOG ("Drive does not support using dummy for DAO");
135 				return FALSE;
136 			}
137 		}
138 		else if (!brasero_medium_can_use_dummy_for_tao (medium)) {
139 			BRASERO_BURN_LOG ("Drive does not support using dummy for TAO");
140 			return FALSE;
141 		}
142 	}
143 
144 	if (flags & BRASERO_BURN_FLAG_BURNPROOF) {
145 		if (!brasero_medium_can_use_burnfree (medium)) {
146 			BRASERO_BURN_LOG ("Drive does not support burnproof/burnfree");
147 			return FALSE;
148 		}
149 	}
150 
151 	return TRUE;
152 }
153 
154 gchar *
brasero_string_get_localpath(const gchar * uri)155 brasero_string_get_localpath (const gchar *uri)
156 {
157 	gchar *localpath;
158 	gchar *realuri;
159 	GFile *file;
160 
161 	if (!uri)
162 		return NULL;
163 
164 	if (uri [0] == '/')
165 		return g_strdup (uri);
166 
167 	if (strncmp (uri, "file://", 7))
168 		return NULL;
169 
170 	file = g_file_new_for_commandline_arg (uri);
171 	realuri = g_file_get_uri (file);
172 	g_object_unref (file);
173 
174 	localpath = g_filename_from_uri (realuri, NULL, NULL);
175 	g_free (realuri);
176 
177 	return localpath;
178 }
179 
180 gchar *
brasero_string_get_uri(const gchar * uri)181 brasero_string_get_uri (const gchar *uri)
182 {
183 	gchar *uri_return;
184 	GFile *file;
185 
186 	if (!uri)
187 		return NULL;
188 
189 	if (uri [0] != '/')
190 		return g_strdup (uri);
191 
192 	file = g_file_new_for_commandline_arg (uri);
193 	uri_return = g_file_get_uri (file);
194 	g_object_unref (file);
195 
196 	return uri_return;
197 }
198 
199 static void
brasero_caps_list_dump(void)200 brasero_caps_list_dump (void)
201 {
202 	GSList *iter;
203 	BraseroBurnCaps *self;
204 
205 	self = brasero_burn_caps_get_default ();
206 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
207 		BraseroCaps *caps;
208 
209 		caps = iter->data;
210 		BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
211 					    caps->flags,
212 					    "Created %i links pointing to",
213 					    g_slist_length (caps->links));
214 	}
215 
216 	g_object_unref (self);
217 }
218 
219 /**
220  * brasero_burn_library_start:
221  * @argc: an #int.
222  * @argv: a #char **.
223  *
224  * Starts the library. This function must be called
225  * before using any of the functions.
226  *
227  * Rename to: init
228  *
229  * Returns: a #gboolean
230  **/
231 
232 gboolean
brasero_burn_library_start(int * argc,char ** argv[])233 brasero_burn_library_start (int *argc,
234                             char **argv [])
235 {
236 	BRASERO_BURN_LOG ("Initializing Brasero-burn %i.%i.%i",
237 			  BRASERO_MAJOR_VERSION,
238 			  BRASERO_MINOR_VERSION,
239 			  BRASERO_SUB);
240 
241 #if defined(HAVE_STRUCT_USCSI_CMD)
242 	/* Work around: because on OpenSolaris brasero possibly be run
243 	 * as root for a user with 'Primary Administrator' profile,
244 	 * a root dbus session will be autospawned at that time.
245 	 * This fix is to work around
246 	 * http://bugzilla.gnome.org/show_bug.cgi?id=526454
247 	 */
248 	g_setenv ("DBUS_SESSION_BUS_ADDRESS", "autolaunch:", TRUE);
249 #endif
250 
251 	/* Initialize external libraries (threads...) */
252 	if (!g_thread_supported ())
253 		g_thread_init (NULL);
254 
255 	/* ... and GStreamer) */
256 	if (!gst_init_check (argc, argv, NULL))
257 		return FALSE;
258 
259 	/* This is for missing codec automatic install */
260 	gst_pb_utils_init ();
261 
262 	/* initialize the media library */
263 	brasero_media_library_start ();
264 
265 	/* initialize all device list */
266 	if (!medium_manager)
267 		medium_manager = brasero_medium_monitor_get_default ();
268 
269 	/* initialize plugins */
270 	if (!default_caps)
271 		default_caps = BRASERO_BURNCAPS (g_object_new (BRASERO_TYPE_BURNCAPS, NULL));
272 
273 	if (!plugin_manager)
274 		plugin_manager = brasero_plugin_manager_get_default ();
275 
276 	brasero_caps_list_dump ();
277 	return TRUE;
278 }
279 
280 BraseroBurnCaps *
brasero_burn_caps_get_default()281 brasero_burn_caps_get_default ()
282 {
283 	if (!default_caps)
284 		g_error ("You must call brasero_burn_library_start () before using API from libbrasero-burn");
285 
286 	g_object_ref (default_caps);
287 	return default_caps;
288 }
289 
290 /**
291  * brasero_burn_library_get_plugins_list:
292  *
293  * This function returns the list of plugins that
294  * are available to libbrasero-burn.
295  *
296  * Returns: (element-type GObject.Object) (transfer full):a #GSList that must be destroyed when not needed and each object unreffed.
297  **/
298 
299 GSList *
brasero_burn_library_get_plugins_list(void)300 brasero_burn_library_get_plugins_list (void)
301 {
302 	plugin_manager = brasero_plugin_manager_get_default ();
303 	return brasero_plugin_manager_get_plugins_list (plugin_manager);
304 }
305 
306 /**
307  * brasero_burn_library_stop:
308  *
309  * Stop the library. Don't use any of the functions or
310  * objects afterwards
311  *
312  * Rename to: deinit
313  *
314  **/
315 void
brasero_burn_library_stop(void)316 brasero_burn_library_stop (void)
317 {
318 	if (plugin_manager) {
319 		g_object_unref (plugin_manager);
320 		plugin_manager = NULL;
321 	}
322 
323 	if (medium_manager) {
324 		g_object_unref (medium_manager);
325 		medium_manager = NULL;
326 	}
327 
328 	if (default_caps) {
329 		g_object_unref (default_caps);
330 		default_caps = NULL;
331 	}
332 
333 	/* Cleanup the io thing */
334 	brasero_io_shutdown ();
335 }
336 
337 /**
338  * brasero_burn_library_can_checksum:
339  *
340  * Checks whether the library can do any kind of
341  * checksum at all.
342  *
343  * Returns: a #gboolean
344  */
345 
346 gboolean
brasero_burn_library_can_checksum(void)347 brasero_burn_library_can_checksum (void)
348 {
349 	GSList *iter;
350 	BraseroBurnCaps *self;
351 
352 	self = brasero_burn_caps_get_default ();
353 
354 	if (self->priv->tests == NULL) {
355 		g_object_unref (self);
356 		return FALSE;
357 	}
358 
359 	for (iter = self->priv->tests; iter; iter = iter->next) {
360 		BraseroCapsTest *tmp;
361 		GSList *links;
362 
363 		tmp = iter->data;
364 		for (links = tmp->links; links; links = links->next) {
365 			BraseroCapsLink *link;
366 
367 			link = links->data;
368 			if (brasero_caps_link_active (link, 0)) {
369 				g_object_unref (self);
370 				return TRUE;
371 			}
372 		}
373 	}
374 
375 	g_object_unref (self);
376 	return FALSE;
377 }
378 
379 /**
380  * brasero_burn_library_input_supported:
381  * @type: a #BraseroTrackType
382  *
383  * Checks whether @type can be used as input.
384  *
385  * Returns: a #BraseroBurnResult
386  */
387 
388 BraseroBurnResult
brasero_burn_library_input_supported(BraseroTrackType * type)389 brasero_burn_library_input_supported (BraseroTrackType *type)
390 {
391 	GSList *iter;
392 	BraseroBurnCaps *self;
393 
394 	g_return_val_if_fail (type != NULL, BRASERO_BURN_ERR);
395 
396 	self = brasero_burn_caps_get_default ();
397 
398 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
399 		BraseroCaps *caps;
400 
401 		caps = iter->data;
402 
403 		if (brasero_caps_is_compatible_type (caps, type)
404 		&&  brasero_burn_caps_is_input (self, caps)) {
405 			g_object_unref (self);
406 			return BRASERO_BURN_OK;
407 		}
408 	}
409 
410 	g_object_unref (self);
411 	return BRASERO_BURN_ERR;
412 }
413 
414 /**
415  * brasero_burn_library_get_media_capabilities:
416  * @media: a #BraseroMedia
417  *
418  * Used to test what the library can do based on the medium type.
419  * Returns BRASERO_MEDIUM_WRITABLE if the disc can be written
420  * and / or BRASERO_MEDIUM_REWRITABLE if the disc can be erased.
421  *
422  * Returns: a #BraseroMedia
423  */
424 
425 BraseroMedia
brasero_burn_library_get_media_capabilities(BraseroMedia media)426 brasero_burn_library_get_media_capabilities (BraseroMedia media)
427 {
428 	GSList *iter;
429 	GSList *links;
430 	BraseroMedia retval;
431 	BraseroBurnCaps *self;
432 	BraseroCaps *caps = NULL;
433 
434 	self = brasero_burn_caps_get_default ();
435 
436 	retval = BRASERO_MEDIUM_NONE;
437 	BRASERO_BURN_LOG_DISC_TYPE (media, "checking media caps for");
438 
439 	/* we're only interested in DISC caps. There should be only one caps fitting */
440 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
441 		caps = iter->data;
442 		if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
443 			continue;
444 
445 		if ((media & caps->type.subtype.media) == media)
446 			break;
447 
448 		caps = NULL;
449 	}
450 
451 	if (!caps) {
452 		g_object_unref (self);
453 		return BRASERO_MEDIUM_NONE;
454 	}
455 
456 	/* check the links */
457 	for (links = caps->links; links; links = links->next) {
458 		GSList *plugins;
459 		gboolean active;
460 		BraseroCapsLink *link;
461 
462 		link = links->data;
463 
464 		/* this link must have at least one active plugin to be valid
465 		 * plugins are not sorted but in this case we don't need them
466 		 * to be. we just need one active if another is with a better
467 		 * priority all the better. */
468 		active = FALSE;
469 		for (plugins = link->plugins; plugins; plugins = plugins->next) {
470 			BraseroPlugin *plugin;
471 
472 			plugin = plugins->data;
473 			/* Ignore plugin errors */
474 			if (brasero_plugin_get_active (plugin, TRUE)) {
475 				/* this link is valid */
476 				active = TRUE;
477 				break;
478 			}
479 		}
480 
481 		if (!active)
482 			continue;
483 
484 		if (!link->caps) {
485 			/* means that it can be blanked */
486 			retval |= BRASERO_MEDIUM_REWRITABLE;
487 			continue;
488 		}
489 
490 		/* means it can be written. NOTE: if this disc has already some
491 		 * data on it, it even means it can be appended */
492 		retval |= BRASERO_MEDIUM_WRITABLE;
493 	}
494 
495 	g_object_unref (self);
496 	return retval;
497 }
498 
499