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