[brasero] Missing files that were not taken into account during last commit



commit 8b1a7218493615f02a2ce8ec8c73e898086a4441
Author: Philippe Rouquier <bonfire-app wanadoo fr>
Date:   Sun Apr 19 13:49:56 2009 +0200

    Missing files that were not taken into account during last commit
---
 plugins/Makefile.am                       |   13 +
 plugins/cdrdao/Makefile.am                |   31 +
 plugins/cdrdao/burn-cdrdao-common.h       |   39 +
 plugins/cdrdao/burn-cdrdao.c              |  698 ++++++++++++
 plugins/cdrdao/burn-cdrdao.h              |   44 +
 plugins/cdrdao/burn-toc2cue.c             |  339 ++++++
 plugins/cdrdao/burn-toc2cue.h             |   44 +
 plugins/cdrkit/Makefile.am                |   39 +
 plugins/cdrkit/burn-cdrkit.h              |   39 +
 plugins/cdrkit/burn-genisoimage.c         |  579 ++++++++++
 plugins/cdrkit/burn-genisoimage.h         |   46 +
 plugins/cdrkit/burn-readom.c              |  484 +++++++++
 plugins/cdrkit/burn-readom.h              |   46 +
 plugins/cdrkit/burn-wodim.c               | 1380 ++++++++++++++++++++++++
 plugins/cdrkit/burn-wodim.h               |   44 +
 plugins/cdrtools/Makefile.am              |   39 +
 plugins/cdrtools/burn-cdrecord.c          | 1371 ++++++++++++++++++++++++
 plugins/cdrtools/burn-cdrecord.h          |   44 +
 plugins/cdrtools/burn-cdrtools.h          |   39 +
 plugins/cdrtools/burn-mkisofs.c           |  586 ++++++++++
 plugins/cdrtools/burn-mkisofs.h           |   46 +
 plugins/cdrtools/burn-readcd.c            |  496 +++++++++
 plugins/cdrtools/burn-readcd.h            |   46 +
 plugins/checksum/Makefile.am              |   34 +
 plugins/checksum/burn-checksum-files.c    | 1506 ++++++++++++++++++++++++++
 plugins/checksum/burn-checksum-files.h    |   44 +
 plugins/checksum/burn-checksum-image.c    |  824 +++++++++++++++
 plugins/checksum/burn-checksum-image.h    |   44 +
 plugins/checksum/burn-volume-read.c       |  397 +++++++
 plugins/checksum/burn-volume-read.h       |   72 ++
 plugins/dvdauthor/Makefile.am             |   23 +
 plugins/dvdauthor/burn-dvdauthor.c        |  423 ++++++++
 plugins/dvdauthor/burn-dvdauthor.h        |   41 +
 plugins/dvdcss/Makefile.am                |   22 +
 plugins/dvdcss/burn-dvdcss-private.h      |   66 ++
 plugins/dvdcss/burn-dvdcss.c              |  698 ++++++++++++
 plugins/dvdcss/burn-dvdcss.h              |   48 +
 plugins/growisofs/Makefile.am             |   30 +
 plugins/growisofs/burn-dvd-rw-format.c    |  212 ++++
 plugins/growisofs/burn-dvd-rw-format.h    |   46 +
 plugins/growisofs/burn-growisofs-common.h |   39 +
 plugins/growisofs/burn-growisofs.c        |  924 ++++++++++++++++
 plugins/growisofs/burn-growisofs.h        |   44 +
 plugins/libburnia/Makefile.am             |   36 +
 plugins/libburnia/burn-libburn-common.c   |  377 +++++++
 plugins/libburnia/burn-libburn-common.h   |   71 ++
 plugins/libburnia/burn-libburn.c          | 1026 ++++++++++++++++++
 plugins/libburnia/burn-libburn.h          |   48 +
 plugins/libburnia/burn-libburnia.h        |   38 +
 plugins/libburnia/burn-libisofs.c         | 1074 +++++++++++++++++++
 plugins/libburnia/burn-libisofs.h         |   48 +
 plugins/libburnia/burn-libread-disc.h     |   68 ++
 plugins/local-track/Makefile.am           |   31 +
 plugins/local-track/burn-local-image.c    |  946 +++++++++++++++++
 plugins/local-track/burn-local-image.h    |   44 +
 plugins/local-track/burn-uri.c            |  746 +++++++++++++
 plugins/local-track/burn-uri.h            |   44 +
 plugins/transcode/Makefile.am             |   36 +
 plugins/transcode/burn-normalize.c        |  628 +++++++++++
 plugins/transcode/burn-normalize.h        |   48 +
 plugins/transcode/burn-transcode.c        | 1647 +++++++++++++++++++++++++++++
 plugins/transcode/burn-transcode.h        |   44 +
 plugins/transcode/burn-vob.c              | 1269 ++++++++++++++++++++++
 plugins/transcode/burn-vob.h              |   41 +
 plugins/vcdimager/Makefile.am             |   23 +
 plugins/vcdimager/burn-vcdimager.c        |  527 +++++++++
 plugins/vcdimager/burn-vcdimager.h        |   36 +
 67 files changed, 20965 insertions(+), 0 deletions(-)

diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644
index 0000000..723b75f
--- /dev/null
+++ b/plugins/Makefile.am
@@ -0,0 +1,13 @@
+SUBDIRS = cdrdao transcode dvdcss growisofs checksum local-track dvdauthor vcdimager
+
+if BUILD_LIBBURNIA
+SUBDIRS += libburnia
+endif
+
+if BUILD_CDRKIT
+SUBDIRS += cdrkit
+endif
+
+if BUILD_CDRTOOLS
+SUBDIRS += cdrtools
+endif
diff --git a/plugins/cdrdao/Makefile.am b/plugins/cdrdao/Makefile.am
new file mode 100644
index 0000000..67c0e7e
--- /dev/null
+++ b/plugins/cdrdao/Makefile.am
@@ -0,0 +1,31 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_GCONF_CFLAGS)
+
+#cdrdao
+cdrdaodir = $(libdir)/brasero/plugins
+cdrdao_LTLIBRARIES = libbrasero-cdrdao.la
+libbrasero_cdrdao_la_SOURCES = burn-cdrdao.c burn-cdrdao.h \
+	burn-cdrdao-common.h 
+libbrasero_cdrdao_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_cdrdao_la_LDFLAGS = -module -avoid-version
+
+#toc2cue
+toc2cuedir = $(libdir)/brasero/plugins
+toc2cue_LTLIBRARIES = libbrasero-toc2cue.la
+libbrasero_toc2cue_la_SOURCES = burn-toc2cue.c burn-toc2cue.h \
+	burn-cdrdao-common.h 
+libbrasero_toc2cue_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_toc2cue_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/cdrdao/burn-cdrdao-common.h b/plugins/cdrdao/burn-cdrdao-common.h
new file mode 100644
index 0000000..f26e3d6
--- /dev/null
+++ b/plugins/cdrdao/burn-cdrdao-common.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *            burn-cdrdao-common.h
+ *
+ *  Mon Oct 29 12:34:41 2007
+ *  Copyright  2007  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef _BURN_CDRDAO_COMMON_H
+#define _BURN_CDRDAO_COMMON_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CDRDAO_DESCRIPTION		N_("Cdrdao burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_CDRDAO_COMMON_H */
+
+ 
diff --git a/plugins/cdrdao/burn-cdrdao.c b/plugins/cdrdao/burn-cdrdao.c
new file mode 100644
index 0000000..080ed27
--- /dev/null
+++ b/plugins/cdrdao/burn-cdrdao.c
@@ -0,0 +1,698 @@
+/***************************************************************************
+ *            cdrdao.c
+ *
+ *  dim jan 22 15:38:18 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "burn-cdrdao-common.h"
+#include "burn-cdrdao.h"
+#include "brasero-error.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-track-disc.h"
+#include "brasero-track-image.h"
+#include "brasero-drive.h"
+#include "brasero-medium.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroCdrdao, brasero_cdrdao, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroCdrdaoPrivate {
+  	guint use_raw:1;
+};
+typedef struct _BraseroCdrdaoPrivate BraseroCdrdaoPrivate;
+#define BRASERO_CDRDAO_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CDRDAO, BraseroCdrdaoPrivate)) 
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_RAW_FLAG "/apps/brasero/config/raw_flag" 
+
+static gboolean
+brasero_cdrdao_read_stderr_image (BraseroCdrdao *cdrdao, const gchar *line)
+{
+	int min, sec, sub, s1;
+
+	if (sscanf (line, "%d:%d:%d", &min, &sec, &sub) == 3) {
+		guint64 secs = min * 60 + sec;
+
+		brasero_job_set_written_track (BRASERO_JOB (cdrdao), secs * 75 * 2352);
+		if (secs > 2)
+			brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+	}
+	else if (sscanf (line, "Leadout %*s %*d %d:%d:%*d(%i)", &min, &sec, &s1) == 3) {
+		BraseroJobAction action;
+
+		brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+		if (action == BRASERO_JOB_ACTION_SIZE) {
+			/* get the number of sectors. As we added -raw sector = 2352 bytes */
+			brasero_job_set_output_size_for_current_track (BRASERO_JOB (cdrdao), s1, (gint64) s1 * 2352ULL);
+			brasero_job_finished_session (BRASERO_JOB (cdrdao));
+		}
+	}
+	else if (strstr (line, "Copying audio tracks")) {
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_DRIVE_COPY,
+						_("Copying audio track"),
+						FALSE);
+	}
+	else if (strstr (line, "Copying data track")) {
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_DRIVE_COPY,
+						_("Copying data track"),
+						FALSE);
+	}
+	else
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_cdrdao_read_stderr_record (BraseroCdrdao *cdrdao, const gchar *line)
+{
+	int fifo, track, min, sec;
+	guint written, total;
+
+	if (sscanf (line, "Wrote %u of %u (Buffers %d%%  %*s", &written, &total, &fifo) >= 2) {
+		brasero_job_set_dangerous (BRASERO_JOB (cdrdao), TRUE);
+
+		brasero_job_set_written_session (BRASERO_JOB (cdrdao), written * 1048576);
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_RECORDING,
+						NULL,
+						FALSE);
+
+		brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+	}
+	else if (sscanf (line, "Wrote %*s blocks. Buffer fill min") == 1) {
+		/* this is for fixating phase */
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_FIXATING,
+						NULL,
+						FALSE);
+	}
+	else if (sscanf (line, "Analyzing track %d %*s start %d:%d:%*d, length %*d:%*d:%*d", &track, &min, &sec) == 3) {
+		gchar *string;
+
+		string = g_strdup_printf (_("Analysing track %02i"), track);
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_ANALYSING,
+						string,
+						TRUE);
+		g_free (string);
+	}
+	else if (sscanf (line, "%d:%d:%*d", &min, &sec) == 2) {
+		gint64 written;
+		guint64 secs = min * 60 + sec;
+
+		if (secs > 2)
+			brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+
+		written = secs * 75 * 2352;
+		brasero_job_set_written_session (BRASERO_JOB (cdrdao), written);
+	}
+	else if (strstr (line, "Writing track")) {
+		brasero_job_set_dangerous (BRASERO_JOB (cdrdao), TRUE);
+	}
+	else if (strstr (line, "Writing finished successfully")
+	     ||  strstr (line, "On-the-fly CD copying finished successfully")) {
+		brasero_job_set_dangerous (BRASERO_JOB (cdrdao), FALSE);
+	}
+	else if (strstr (line, "Blanking disk...")) {
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_BLANKING,
+						NULL,
+						FALSE);
+		brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+		brasero_job_set_dangerous (BRASERO_JOB (cdrdao), TRUE);
+	}
+	else {
+		gchar *name = NULL;
+		gchar *cuepath = NULL;
+		BraseroTrack *track = NULL;
+		BraseroJobAction action;
+
+		/* Try to catch error could not find cue file */
+
+		/* Track could be NULL here if we're simply blanking a medium */
+		brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+		if (action == BRASERO_JOB_ACTION_ERASE)
+			return TRUE;
+
+		brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+		if (!track)
+			return FALSE;
+
+		cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+
+		if (!cuepath)
+			return FALSE;
+
+		if (!strstr (line, cuepath)
+		&&  !strstr (line, "ERROR: Could not find input file")) {
+			g_free (cuepath);
+			return FALSE;
+		}
+
+		name = g_path_get_basename (cuepath);
+		g_free (cuepath);
+
+		brasero_job_error (BRASERO_JOB (cdrdao),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_FILE_NOT_FOUND,
+						/* Translators: %s is a filename */
+						_("\"%s\" could not be found"),
+						name));
+		g_free (name);
+	}
+
+	return TRUE;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	BraseroCdrdao *cdrdao;
+	gboolean result = FALSE;
+	BraseroJobAction action;
+
+	cdrdao = BRASERO_CDRDAO (process);
+
+	brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+	if (action == BRASERO_JOB_ACTION_RECORD
+	||  action == BRASERO_JOB_ACTION_ERASE)
+		result = brasero_cdrdao_read_stderr_record (cdrdao, line);
+	else if (action == BRASERO_JOB_ACTION_IMAGE
+	     ||  action == BRASERO_JOB_ACTION_SIZE)
+		result = brasero_cdrdao_read_stderr_image (cdrdao, line);
+
+	if (result)
+		return BRASERO_BURN_OK;
+
+	if (strstr (line, "Cannot setup device")) {
+		brasero_job_error (BRASERO_JOB (cdrdao),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_DRIVE_BUSY,
+						_("The drive is busy")));
+	}
+	else if (strstr (line, "Illegal command")) {
+		brasero_job_error (BRASERO_JOB (cdrdao),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("Your version of cdrdao does not seem to be supported by libbrasero")));
+	}
+	else if (strstr (line, "Operation not permitted. Cannot send SCSI")) {
+		brasero_job_error (BRASERO_JOB (cdrdao),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_cdrdao_set_argv_device (BraseroCdrdao *cdrdao,
+				GPtrArray *argv)
+{
+	gchar *device = NULL;
+
+	g_ptr_array_add (argv, g_strdup ("--device"));
+
+#ifdef HAVE_CAM_LIB_H
+	/* FreeBSD like that better */
+	brasero_job_get_bus_target_lun (BRASERO_JOB (cdrdao), &device);
+#else
+	brasero_job_get_device (BRASERO_JOB (cdrdao), &device);
+#endif
+
+	g_ptr_array_add (argv, device);
+}
+
+static void
+brasero_cdrdao_set_argv_common_rec (BraseroCdrdao *cdrdao,
+				    GPtrArray *argv)
+{
+	BraseroBurnFlag flags;
+	gchar *speed_str;
+	guint speed;
+
+	brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+	if (flags & BRASERO_BURN_FLAG_DUMMY)
+		g_ptr_array_add (argv, g_strdup ("--simulate"));
+
+	g_ptr_array_add (argv, g_strdup ("--speed"));
+
+	brasero_job_get_speed (BRASERO_JOB (cdrdao), &speed);
+	speed_str = g_strdup_printf ("%d", speed);
+	g_ptr_array_add (argv, speed_str);
+
+	if (flags & BRASERO_BURN_FLAG_OVERBURN)
+		g_ptr_array_add (argv, g_strdup ("--overburn"));
+	if (flags & BRASERO_BURN_FLAG_MULTI)
+		g_ptr_array_add (argv, g_strdup ("--multi"));
+}
+
+static void
+brasero_cdrdao_set_argv_common (BraseroCdrdao *cdrdao,
+				GPtrArray *argv)
+{
+	BraseroBurnFlag flags;
+
+	brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+
+	/* cdrdao manual says it is a similar option to gracetime */
+	if (flags & BRASERO_BURN_FLAG_NOGRACE)
+		g_ptr_array_add (argv, g_strdup ("-n"));
+
+	g_ptr_array_add (argv, g_strdup ("-v"));
+	g_ptr_array_add (argv, g_strdup ("2"));
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv_record (BraseroCdrdao *cdrdao,
+				GPtrArray *argv)
+{
+	BraseroTrackType *type = NULL;
+	BraseroCdrdaoPrivate *priv;
+
+	priv = BRASERO_CDRDAO_PRIVATE (cdrdao); 
+
+	g_ptr_array_add (argv, g_strdup ("cdrdao"));
+
+	type = brasero_track_type_new ();
+	brasero_job_get_input_type (BRASERO_JOB (cdrdao), type);
+
+        if (brasero_track_type_get_has_medium (type)) {
+		BraseroDrive *drive;
+		BraseroTrack *track;
+		BraseroBurnFlag flags;
+
+		g_ptr_array_add (argv, g_strdup ("copy"));
+		brasero_cdrdao_set_argv_device (cdrdao, argv);
+		brasero_cdrdao_set_argv_common (cdrdao, argv);
+		brasero_cdrdao_set_argv_common_rec (cdrdao, argv);
+
+		brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+		if (flags & BRASERO_BURN_FLAG_NO_TMP_FILES)
+			g_ptr_array_add (argv, g_strdup ("--on-the-fly"));
+
+		if (priv->use_raw)
+		  	g_ptr_array_add (argv, g_strdup ("--driver generic-mmc-raw")); 
+
+		g_ptr_array_add (argv, g_strdup ("--source-device"));
+
+		brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+#ifdef HAVE_CAM_LIB_H
+	/* FreeBSD like that better */
+		g_ptr_array_add (argv, brasero_drive_get_bus_target_lun_string (drive));
+#else
+		g_ptr_array_add (argv, g_strdup (brasero_drive_get_device (drive)));
+#endif
+
+	}
+	else if (brasero_track_type_get_has_image (type)) {
+		gchar *cuepath;
+		BraseroTrack *track;
+
+		brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+
+		if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_CUE) {
+			gchar *parent;
+
+			cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			parent = g_path_get_dirname (cuepath);
+			brasero_process_set_working_directory (BRASERO_PROCESS (cdrdao), parent);
+			g_free (parent);
+		}
+		else if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_CDRDAO)
+			cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+		else {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_SUPPORTED (cdrdao);
+		}
+
+		if (!cuepath) {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_READY (cdrdao);
+		}
+
+		g_ptr_array_add (argv, g_strdup ("write"));
+
+		brasero_cdrdao_set_argv_device (cdrdao, argv);
+		brasero_cdrdao_set_argv_common (cdrdao, argv);
+		brasero_cdrdao_set_argv_common_rec (cdrdao, argv);
+
+		g_ptr_array_add (argv, cuepath);
+	}
+	else {
+		brasero_track_type_free (type);
+		BRASERO_JOB_NOT_SUPPORTED (cdrdao);
+	}
+
+	brasero_track_type_free (type);
+	brasero_job_set_use_average_rate (BRASERO_JOB (cdrdao), TRUE);
+	brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+					BRASERO_BURN_ACTION_START_RECORDING,
+					NULL,
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv_blank (BraseroCdrdao *cdrdao,
+			       GPtrArray *argv)
+{
+	BraseroBurnFlag flags;
+
+	g_ptr_array_add (argv, g_strdup ("cdrdao"));
+	g_ptr_array_add (argv, g_strdup ("blank"));
+
+	brasero_cdrdao_set_argv_device (cdrdao, argv);
+	brasero_cdrdao_set_argv_common (cdrdao, argv);
+
+	g_ptr_array_add (argv, g_strdup ("--blank-mode"));
+	brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+	if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK))
+		g_ptr_array_add (argv, g_strdup ("full"));
+	else
+		g_ptr_array_add (argv, g_strdup ("minimal"));
+
+	brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+					BRASERO_BURN_ACTION_BLANKING,
+					NULL,
+					FALSE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv_image (BraseroCdrdao *cdrdao,
+			       GPtrArray *argv,
+			       GError **error)
+{
+	gchar *image = NULL, *toc = NULL;
+	BraseroTrackType *output = NULL;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroDrive *drive;
+	BraseroTrack *track;
+
+	g_ptr_array_add (argv, g_strdup ("cdrdao"));
+	g_ptr_array_add (argv, g_strdup ("read-cd"));
+	g_ptr_array_add (argv, g_strdup ("--device"));
+
+	brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+	drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+#ifdef HAVE_CAM_LIB_H
+	/* FreeBSD like that better */
+	g_ptr_array_add (argv, brasero_drive_get_bus_target_lun_string (drive));
+#else
+	g_ptr_array_add (argv, g_strdup (brasero_drive_get_device (drive)));
+#endif
+
+	g_ptr_array_add (argv, g_strdup ("--read-raw"));
+
+	/* This is done so that if a cue file is required we first generate
+	 * a temporary toc file that will be later converted to a cue file.
+	 * The datafile is written where it should be from the start. */
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (cdrdao), output);
+
+	if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_CDRDAO) {
+		result = brasero_job_get_image_output (BRASERO_JOB (cdrdao),
+						       &image,
+						       &toc);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (output);
+			return result;
+		}
+	}
+	else {
+		result = brasero_job_get_image_output (BRASERO_JOB (cdrdao),
+						       &image,
+						       NULL);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (output);
+			return result;
+		}
+	
+		result = brasero_job_get_tmp_file (BRASERO_JOB (cdrdao),
+						   NULL,
+						   &toc,
+						   error);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (output);
+			return result;
+		}
+	}
+
+	brasero_track_type_free (output);
+
+	/* it's safe to remove them: session/task make sure they don't exist 
+	 * when there is the proper flag whether it be tmp or real output. */ 
+	if (toc)
+		g_remove (toc);
+	if (image)
+		g_remove (image);
+
+	brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+						BRASERO_BURN_ACTION_GETTING_SIZE,
+						NULL,
+						FALSE);
+		brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+	}
+
+	g_ptr_array_add (argv, g_strdup ("--datafile"));
+	g_ptr_array_add (argv, image);
+
+	g_ptr_array_add (argv, g_strdup ("-v"));
+	g_ptr_array_add (argv, g_strdup ("2"));
+
+	g_ptr_array_add (argv, toc);
+
+	brasero_job_set_use_average_rate (BRASERO_JOB (cdrdao), TRUE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv (BraseroProcess *process,
+			 GPtrArray *argv,
+			 GError **error)
+{
+	BraseroCdrdao *cdrdao;
+	BraseroJobAction action;
+
+	cdrdao = BRASERO_CDRDAO (process);
+
+	/* sets the first argv */
+	brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+	if (action == BRASERO_JOB_ACTION_RECORD)
+		return brasero_cdrdao_set_argv_record (cdrdao, argv);
+	else if (action == BRASERO_JOB_ACTION_ERASE)
+		return brasero_cdrdao_set_argv_blank (cdrdao, argv);
+	else if (action == BRASERO_JOB_ACTION_IMAGE)
+		return brasero_cdrdao_set_argv_image (cdrdao, argv, error);
+	else if (action == BRASERO_JOB_ACTION_SIZE) {
+		BraseroTrack *track;
+
+		brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+		if (BRASERO_IS_TRACK_DISC (track)) {
+			guint64 sectors = 0;
+
+			brasero_track_get_size (track, &sectors, NULL);
+
+			/* cdrdao won't get a track size under 300 sectors */
+			if (sectors < 300)
+				sectors = 300;
+
+			brasero_job_set_output_size_for_current_track (BRASERO_JOB (cdrdao),
+								       sectors,
+								       sectors * 2352ULL);
+		}
+		else
+			return BRASERO_BURN_NOT_SUPPORTED;
+
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	BRASERO_JOB_NOT_SUPPORTED (cdrdao);
+}
+
+static void
+brasero_cdrdao_class_init (BraseroCdrdaoClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroCdrdaoPrivate));
+
+	parent_class = g_type_class_peek_parent(klass);
+	object_class->finalize = brasero_cdrdao_finalize;
+
+	process_class->stderr_func = brasero_cdrdao_read_stderr;
+	process_class->set_argv = brasero_cdrdao_set_argv;
+	process_class->post = brasero_job_finished_session;
+}
+
+static void
+brasero_cdrdao_init (BraseroCdrdao *obj)
+{  
+	GConfClient *client;
+ 	BraseroCdrdaoPrivate *priv;
+ 	
+	/* load our "configuration" */
+ 	priv = BRASERO_CDRDAO_PRIVATE (obj);
+ 	
+ 	client = gconf_client_get_default ();
+ 	priv->use_raw = gconf_client_get_bool (client,
+					       GCONF_KEY_RAW_FLAG,
+					       NULL);
+
+ 	g_object_unref (client); 
+}
+
+static void
+brasero_cdrdao_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_cdrdao_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	GSList *output;
+	BraseroBurnResult result;
+	BraseroPluginConfOption *use_raw; 
+	const BraseroMedia media_w = BRASERO_MEDIUM_CD|
+				     BRASERO_MEDIUM_WRITABLE|
+				     BRASERO_MEDIUM_REWRITABLE|
+				     BRASERO_MEDIUM_BLANK;
+	const BraseroMedia media_rw = BRASERO_MEDIUM_CD|
+				      BRASERO_MEDIUM_REWRITABLE|
+				      BRASERO_MEDIUM_APPENDABLE|
+				      BRASERO_MEDIUM_CLOSED|
+				      BRASERO_MEDIUM_HAS_DATA|
+				      BRASERO_MEDIUM_HAS_AUDIO|
+				      BRASERO_MEDIUM_BLANK;
+
+	brasero_plugin_define (plugin,
+			       "Cdrdao",
+			       _("Use cdrdao to copy and burn CDs"),
+			       "Philippe Rouquier",
+			       20);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("cdrdao", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* that's for cdrdao images: CDs only as input */
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+				       BRASERO_MEDIUM_ROM|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_HAS_AUDIO|
+				       BRASERO_MEDIUM_HAS_DATA);
+
+	/* an image can be created ... */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_IMAGE_FORMAT_CDRDAO);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	/* ... or a disc */
+	output = brasero_caps_disc_new (media_w);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	/* cdrdao can also record these types of images to a disc */
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_CDRDAO|
+					BRASERO_IMAGE_FORMAT_CUE);
+	
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* cdrdao is used to burn images so it can't APPEND and the disc must
+	 * have been blanked before (it can't overwrite)
+	 * NOTE: BRASERO_MEDIUM_FILE is needed here because of restriction API
+	 * when we output an image. */
+	brasero_plugin_set_flags (plugin,
+				  media_w|
+				  BRASERO_MEDIUM_FILE,
+				  BRASERO_BURN_FLAG_DAO|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* cdrdao can also blank */
+	output = brasero_caps_disc_new (media_rw);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+					media_rw,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	use_raw = brasero_plugin_conf_option_new (GCONF_KEY_RAW_FLAG,
+						  _("Enable \"--driver generic-mmc-raw\" flag (see cdrdao manual)"),
+						  BRASERO_PLUGIN_OPTION_BOOL);
+
+	brasero_plugin_add_conf_option (plugin, use_raw);
+
+	brasero_plugin_register_group (plugin, _(CDRDAO_DESCRIPTION));
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrdao/burn-cdrdao.h b/plugins/cdrdao/burn-cdrdao.h
new file mode 100644
index 0000000..3a50a2c
--- /dev/null
+++ b/plugins/cdrdao/burn-cdrdao.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            cdrdao.h
+ *
+ *  dim jan 22 15:38:18 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef CDRDAO_H
+#define CDRDAO_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CDRDAO         (brasero_cdrdao_get_type ())
+#define BRASERO_CDRDAO(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CDRDAO, BraseroCdrdao))
+#define BRASERO_CDRDAO_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CDRDAO, BraseroCdrdaoClass))
+#define BRASERO_IS_CDRDAO(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CDRDAO))
+#define BRASERO_IS_CDRDAO_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CDRDAO))
+#define BRASERO_CDRDAO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CDRDAO, BraseroCdrdaoClass))
+
+G_END_DECLS
+
+#endif /* CDRDAO_H */
diff --git a/plugins/cdrdao/burn-toc2cue.c b/plugins/cdrdao/burn-toc2cue.c
new file mode 100644
index 0000000..902aaf8
--- /dev/null
+++ b/plugins/cdrdao/burn-toc2cue.c
@@ -0,0 +1,339 @@
+/***************************************************************************
+ *            burn-toc2cue.c
+ *
+ *  mar oct  3 18:30:51 2006
+ *  Copyright  2006  Philippe Rouquier
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-cdrdao-common.h"
+#include "burn-toc2cue.h"
+#include "brasero-track-image.h"
+ 
+BRASERO_PLUGIN_BOILERPLATE (BraseroToc2Cue, brasero_toc2cue, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroToc2CuePrivate {
+	gchar *output;
+};
+typedef struct _BraseroToc2CuePrivate BraseroToc2CuePrivate;
+
+#define BRASERO_TOC2CUE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TOC2CUE, BraseroToc2CuePrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_toc2cue_read_stdout (BraseroProcess *process,
+			     const gchar *line)
+{
+	BraseroToc2Cue *self;
+
+	self = BRASERO_TOC2CUE (process);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_toc2cue_read_stderr (BraseroProcess *process,
+			     const gchar *line)
+{
+	BraseroTrack *current = NULL;
+	BraseroToc2CuePrivate *priv;
+	BraseroTrackImage *track;
+	BraseroToc2Cue *self;
+	GError *error = NULL;
+	gchar *tmp_img_path;
+	GIOChannel *source;
+	guint tmp_path_len;
+	GIOStatus status;
+	gchar *img_path;
+	gchar *toc_path;
+	gchar *buffer;
+	FILE *output;
+
+	self = BRASERO_TOC2CUE (process);
+	priv = BRASERO_TOC2CUE_PRIVATE (self);
+
+	if (!strstr (line, "Converted toc-file"))
+		return BRASERO_BURN_OK;
+
+	/* Now we also need to replace all the occurences of tmp file name by
+	 * the real output file name in the created cue */
+	source = g_io_channel_new_file (priv->output, "r", &error);
+	if (!source) {
+		brasero_job_error (BRASERO_JOB (process), error);
+		return BRASERO_BURN_OK;
+	}
+
+	brasero_job_get_image_output (BRASERO_JOB (self),
+				      &img_path,
+				      &toc_path);
+	
+	output = fopen (toc_path, "w");
+	if (!output) {
+                int errsv = errno;
+
+		g_io_channel_unref (source);
+
+		g_free (img_path);
+		g_free (toc_path);
+
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_GENERAL,
+							g_strerror (errsv)));
+		return BRASERO_BURN_OK;
+	}
+
+	/* get the path of the image that should remain unchanged */
+	brasero_job_get_current_track (BRASERO_JOB (self), &current);
+	tmp_img_path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), FALSE);
+	tmp_path_len = strlen (tmp_img_path);
+
+	status = g_io_channel_read_line (source, &buffer, NULL, NULL, &error);
+	while (status == G_IO_STATUS_NORMAL) {
+		gchar *location;
+
+		location = strstr (buffer, tmp_img_path);
+		if (location) {
+			gchar *tmp;
+
+			tmp = buffer;
+			buffer = g_strdup_printf ("%.*s%s%s",
+						  location - buffer,
+						  buffer,
+						  img_path,
+						  location + tmp_path_len);
+			g_free (tmp);
+		}
+
+		if (!fwrite (buffer, strlen (buffer), 1, output)) {
+                        int errsv = errno;
+
+			g_free (buffer);
+
+			fclose (output);
+			g_io_channel_unref (source);
+
+			g_free (tmp_img_path);
+			
+			g_free (img_path);
+			g_free (toc_path);
+
+			brasero_job_error (BRASERO_JOB (process),
+					   g_error_new_literal (BRASERO_BURN_ERROR,
+								BRASERO_BURN_ERROR_GENERAL,
+								g_strerror (errsv)));
+			return BRASERO_BURN_OK;
+		}
+
+		g_free (buffer);
+		status = g_io_channel_read_line (source, &buffer, NULL, NULL, &error);
+	}
+
+	fclose (output);
+	g_io_channel_unref (source);
+
+	if (status == G_IO_STATUS_ERROR) {
+		g_free (tmp_img_path);
+		g_free (img_path);
+		g_free (toc_path);
+		brasero_job_error (BRASERO_JOB (process), error);
+		return BRASERO_BURN_OK;
+	}
+
+	/* the previous track image path will now be a link pointing to the
+	 * image path of the new track just created */
+	if (g_rename (tmp_img_path, img_path)) {
+                int errsv = errno;
+
+		brasero_job_error (BRASERO_JOB (self),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_GENERAL,
+							g_strerror (errsv)));
+		return BRASERO_BURN_OK;
+	}
+
+	if (link (img_path, tmp_img_path)) {
+                int errsv = errno;
+
+		brasero_job_error (BRASERO_JOB (self),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_GENERAL,
+							g_strerror (errsv)));
+		return BRASERO_BURN_OK;
+	} /* symlink () could also be used */
+
+	track = brasero_track_image_new ();
+	brasero_track_image_set_source (track,
+					img_path,
+					toc_path,
+					BRASERO_IMAGE_FORMAT_CUE);
+
+	g_free (tmp_img_path);
+	g_free (img_path);
+	g_free (toc_path);
+
+	brasero_job_add_track (BRASERO_JOB (process), BRASERO_TRACK (track));
+
+	/* It's good practice to unref the track afterwards as we don't need it
+	 * anymore. BraseroTaskCtx refs it. */
+	g_object_unref (track);
+
+	brasero_job_finished_track (BRASERO_JOB (process));
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_toc2cue_set_argv (BraseroProcess *process,
+			  GPtrArray *argv,
+			  GError **error)
+{
+	BraseroToc2CuePrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroToc2Cue *self;
+	BraseroTrack *track;
+	gchar *tocpath;
+	gchar *output;
+
+	self = BRASERO_TOC2CUE (process);
+	priv = BRASERO_TOC2CUE_PRIVATE (self);
+
+	brasero_job_get_action (BRASERO_JOB (self), &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		BRASERO_JOB_NOT_SUPPORTED (process);
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+					   NULL,
+					   &output,
+					   error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	tocpath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+
+	priv->output = g_strdup (output);
+	g_remove (priv->output);
+
+	g_ptr_array_add (argv, g_strdup ("toc2cue"));
+	g_ptr_array_add (argv, tocpath);
+	g_ptr_array_add (argv, output);
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					_("Converting toc file"),
+					FALSE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_toc2cue_post (BraseroJob *job)
+{
+	BraseroToc2CuePrivate *priv;
+
+	priv = BRASERO_TOC2CUE_PRIVATE (job);
+	if (priv->output) {
+		g_free (priv->output);
+		priv->output = NULL;
+	}
+
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_toc2cue_class_init (BraseroToc2CueClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroToc2CuePrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_toc2cue_finalize;
+
+	process_class->stdout_func = brasero_toc2cue_read_stdout;
+	process_class->stderr_func = brasero_toc2cue_read_stderr;
+	process_class->set_argv = brasero_toc2cue_set_argv;
+	process_class->post = brasero_toc2cue_post;
+}
+
+static void
+brasero_toc2cue_init (BraseroToc2Cue *obj)
+{ }
+
+static void
+brasero_toc2cue_finalize (GObject *object)
+{
+	brasero_toc2cue_post (BRASERO_JOB (object));
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_toc2cue_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "toc2cue",
+			       _("Toc2cue converts .toc files into .cue files"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("toc2cue", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_CDRDAO);
+
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_IMAGE_FORMAT_CUE);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	brasero_plugin_register_group (plugin, _(CDRDAO_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrdao/burn-toc2cue.h b/plugins/cdrdao/burn-toc2cue.h
new file mode 100644
index 0000000..e3af7d2
--- /dev/null
+++ b/plugins/cdrdao/burn-toc2cue.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            burn-toc2cue.h
+ *
+ *  mar oct  3 18:30:51 2006
+ *  Copyright  2006  Philippe Rouquier
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef BURN_TOC2CUE_H
+#define BURN_TOC2CUE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_TOC2CUE         (brasero_toc2cue_get_type ())
+#define BRASERO_TOC2CUE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_TOC2CUE, BraseroToc2Cue))
+#define BRASERO_TOC2CUE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_TOC2CUE, BraseroToc2CueClass))
+#define BRASERO_IS_TOC2CUE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_TOC2CUE))
+#define BRASERO_IS_TOC2CUE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_TOC2CUE))
+#define BRASERO_TOC2CUE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_TOC2CUE, BraseroToc2CueClass))
+
+G_END_DECLS
+
+#endif /* BURN_TOC2CUE_H */
diff --git a/plugins/cdrkit/Makefile.am b/plugins/cdrkit/Makefile.am
new file mode 100644
index 0000000..8d56bfd
--- /dev/null
+++ b/plugins/cdrkit/Makefile.am
@@ -0,0 +1,39 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_GCONF_CFLAGS)
+
+#wodim
+wodimdir = $(libdir)/brasero/plugins
+wodim_LTLIBRARIES = libbrasero-wodim.la
+libbrasero_wodim_la_SOURCES = burn-wodim.c burn-wodim.h \
+	burn-cdrkit.h 
+libbrasero_wodim_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_wodim_la_LDFLAGS = -module -avoid-version
+
+#genisoimage
+genisoimagedir = $(libdir)/brasero/plugins
+genisoimage_LTLIBRARIES = libbrasero-genisoimage.la
+libbrasero_genisoimage_la_SOURCES = burn-genisoimage.c burn-genisoimage.h \
+	burn-cdrkit.h 
+libbrasero_genisoimage_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_genisoimage_la_LDFLAGS = -module -avoid-version
+
+#readom
+readomdir = $(libdir)/brasero/plugins
+readom_LTLIBRARIES = libbrasero-readom.la
+libbrasero_readom_la_SOURCES = burn-readom.c burn-readom.h \
+	burn-cdrkit.h 
+libbrasero_readom_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_readom_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/cdrkit/burn-cdrkit.h b/plugins/cdrkit/burn-cdrkit.h
new file mode 100644
index 0000000..ef3e33b
--- /dev/null
+++ b/plugins/cdrkit/burn-cdrkit.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *            cdrkit.h
+ *
+ *  Mon Oct 29 12:21:53 2007
+ *  Copyright  2007  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef _CDRKIT_H
+#define _CDRKIT_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CDRKIT_DESCRIPTION		N_("Cdrkit burning suite")
+
+G_END_DECLS
+
+#endif /* _CDRKIT_H */
+
+ 
diff --git a/plugins/cdrkit/burn-genisoimage.c b/plugins/cdrkit/burn-genisoimage.c
new file mode 100644
index 0000000..7bae00e
--- /dev/null
+++ b/plugins/cdrkit/burn-genisoimage.c
@@ -0,0 +1,579 @@
+/***************************************************************************
+ *            genisoimage.c
+ *
+ *  dim jan 22 15:20:57 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrkit.h"
+#include "burn-genisoimage.h"
+#include "brasero-track-data.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroGenisoimage, brasero_genisoimage, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroGenisoimagePrivate {
+	guint use_utf8:1;
+};
+typedef struct _BraseroGenisoimagePrivate BraseroGenisoimagePrivate;
+
+#define BRASERO_GENISOIMAGE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimagePrivate))
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_genisoimage_read_isosize (BraseroProcess *process, const gchar *line)
+{
+	gint64 sectors;
+
+	sectors = strtoll (line, NULL, 10);
+	if (!sectors)
+		return BRASERO_BURN_OK;
+
+	/* genisoimage reports blocks of 2048 bytes */
+	brasero_job_set_output_size_for_current_track (BRASERO_JOB (process),
+						       sectors,
+						       (gint64) sectors * 2048ULL);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_read_stdout (BraseroProcess *process, const gchar *line)
+{
+	BraseroJobAction action;
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		return brasero_genisoimage_read_isosize (process, line);
+
+	return TRUE;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	gchar fraction_str [7] = { 0, };
+	BraseroGenisoimage *genisoimage;
+	BraseroGenisoimagePrivate *priv;
+
+	genisoimage = BRASERO_GENISOIMAGE (process);
+	priv = BRASERO_GENISOIMAGE_PRIVATE (process);
+
+	if (strstr (line, "estimate finish")
+	&&  sscanf (line, "%6c%% done, estimate finish", fraction_str) == 1) {
+		gdouble fraction;
+	
+		fraction = g_strtod (fraction_str, NULL) / (gdouble) 100.0;
+		brasero_job_set_progress (BRASERO_JOB (genisoimage), fraction);
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+	}
+	else if (strstr (line, "Input/output error. Read error on old image")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+							_("Last session import failed")));
+	}
+	else if (strstr (line, "Unable to sort directory")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_WRITE_IMAGE,
+							_("An image could not be created")));
+	}
+	else if (strstr (line, "have the same joliet name")
+	     ||  strstr (line, "Joliet tree sort failed.")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_IMAGE_JOLIET,
+							_("An image could not be created")));
+	}
+	else if (strstr (line, "Use genisoimage -help")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_GENERAL,
+							_("This version of genisoimage is not supported")));
+	}
+/*	else if ((pos =  strstr (line,"genisoimage: Permission denied. "))) {
+		int res = FALSE;
+		gboolean isdir = FALSE;
+		char *path = NULL;
+
+		pos += strlen ("genisoimage: Permission denied. ");
+		if (!strncmp (pos, "Unable to open directory ", 24)) {
+			isdir = TRUE;
+
+			pos += strlen ("Unable to open directory ");
+			path = g_strdup (pos);
+			path[strlen (path) - 1] = 0;
+		}
+		else if (!strncmp (pos, "File ", 5)) {
+			char *end;
+
+			isdir = FALSE;
+			pos += strlen ("File ");
+			end = strstr (pos, " is not readable - ignoring");
+			if (end)
+				path = g_strndup (pos, end - pos);
+		}
+		else
+			return TRUE;
+
+		res = brasero_genisoimage_base_ask_unreadable_file (BRASERO_GENISOIMAGE_BASE (process),
+								path,
+								isdir);
+		if (!res) {
+			g_free (path);
+
+			brasero_job_progress_changed (BRASERO_JOB (process), 1.0, -1);
+			brasero_job_cancel (BRASERO_JOB (process), FALSE);
+			return FALSE;
+		}
+	}*/
+	else if (strstr (line, "Incorrectly encoded string")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT_INVALID,
+							_("Some files have invalid filenames")));
+	}
+	else if (strstr (line, "Unknown charset")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT_INVALID,
+							_("Unknown character encoding")));
+	}
+	else if (strstr (line, "No space left on device")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_DISK_SPACE,
+							_("There is no space left on the device")));
+
+	}
+	else if (strstr (line, "Unable to open disc image file")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_PERMISSION,
+							_("You do not have the required permission to write at this location")));
+
+	}
+	else if (strstr (line, "Value too large for defined data type")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_MEDIUM_SPACE,
+							_("Not enough space available on the disc")));
+	}
+
+	/** REMINDER: these should not be necessary
+
+	else if (strstr (line, "Resource temporarily unavailable")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT,
+							_("Data could not be written")));
+	}
+	else if (strstr (line, "Bad file descriptor.")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT,
+							_("Internal error: bad file descriptor")));
+	}
+
+	**/
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_set_argv_image (BraseroGenisoimage *genisoimage,
+				    GPtrArray *argv,
+				    GError **error)
+{
+	gchar *label = NULL;
+	BraseroTrack *track;
+	BraseroBurnFlag flags;
+	gchar *emptydir = NULL;
+	gchar *videodir = NULL;
+	BraseroImageFS image_fs;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	gchar *grafts_path = NULL;
+	gchar *excluded_path = NULL;
+
+	/* set argv */
+	g_ptr_array_add (argv, g_strdup ("-r"));
+
+	result = brasero_job_get_current_track (BRASERO_JOB (genisoimage), &track);
+	if (result != BRASERO_BURN_OK)
+		BRASERO_JOB_NOT_READY (genisoimage);
+
+	image_fs = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+	if (image_fs & BRASERO_IMAGE_FS_JOLIET)
+		g_ptr_array_add (argv, g_strdup ("-J"));
+
+	if ((image_fs & BRASERO_IMAGE_FS_ISO)
+	&&  (image_fs & BRASERO_IMAGE_ISO_FS_LEVEL_3)) {
+		g_ptr_array_add (argv, g_strdup ("-iso-level"));
+		g_ptr_array_add (argv, g_strdup ("3"));
+
+		/* NOTE: the following is specific to genisoimage
+		 * It allows to burn files over 4 GiB */
+		g_ptr_array_add (argv, g_strdup ("-allow-limited-size"));
+	}
+
+	if (image_fs & BRASERO_IMAGE_FS_UDF)
+		g_ptr_array_add (argv, g_strdup ("-udf"));
+
+	if (image_fs & BRASERO_IMAGE_FS_VIDEO) {
+		g_ptr_array_add (argv, g_strdup ("-dvd-video"));
+
+		result = brasero_job_get_tmp_dir (BRASERO_JOB (genisoimage),
+						  &videodir,
+						  error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-graft-points"));
+
+	if (image_fs & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY)
+		g_ptr_array_add (argv, g_strdup ("-D"));	// This is dangerous the manual says but apparently it works well
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (genisoimage),
+					   NULL,
+					   &grafts_path,
+					   error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		return result;
+	}
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (genisoimage),
+					   NULL,
+					   &excluded_path,
+					   error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		return result;
+	}
+
+	result = brasero_job_get_tmp_dir (BRASERO_JOB (genisoimage),
+					  &emptydir,
+					  error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		g_free (excluded_path);
+		return result;
+	}
+
+	result = brasero_track_data_get_paths (BRASERO_TRACK_DATA (track),
+					       (image_fs & BRASERO_IMAGE_FS_JOLIET) != 0,
+					       grafts_path,
+					       excluded_path,
+					       emptydir,
+					       videodir,
+					       error);
+	g_free (emptydir);
+
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		g_free (excluded_path);
+		return result;
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-path-list"));
+	g_ptr_array_add (argv, grafts_path);
+
+	g_ptr_array_add (argv, g_strdup ("-exclude-list"));
+	g_ptr_array_add (argv, excluded_path);
+
+	brasero_job_get_data_label (BRASERO_JOB (genisoimage), &label);
+	if (label) {
+		g_ptr_array_add (argv, g_strdup ("-V"));
+		g_ptr_array_add (argv, label);
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-A"));
+	g_ptr_array_add (argv, g_strdup_printf ("Brasero-%i.%i.%i",
+						BRASERO_MAJOR_VERSION,
+						BRASERO_MINOR_VERSION,
+						BRASERO_SUB));
+	
+	g_ptr_array_add (argv, g_strdup ("-sysid"));
+	g_ptr_array_add (argv, g_strdup ("LINUX"));
+	
+	/* FIXME! -sort is an interesting option allowing to decide where the 
+	* files are written on the disc and therefore to optimize later reading */
+	/* FIXME: -hidden --hidden-list -hide-jolie -hide-joliet-list will allow to hide
+	* some files when we will display the contents of a disc we will want to merge */
+	/* FIXME: support preparer publisher options */
+
+	brasero_job_get_flags (BRASERO_JOB (genisoimage), &flags);
+	if (flags & (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE)) {
+		guint64 last_session = 0, next_wr_add = 0;
+		gchar *startpoint = NULL;
+
+		brasero_job_get_last_session_address (BRASERO_JOB (genisoimage), &last_session);
+		brasero_job_get_next_writable_address (BRASERO_JOB (genisoimage), &next_wr_add);
+		if (last_session == -1 || next_wr_add == -1) {
+			g_free (videodir);
+			BRASERO_JOB_LOG (genisoimage, "Failed to get the start point of the track. Make sure the media allow to add files (it is not closed)");
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("An internal error occured"));
+			return BRASERO_BURN_ERR;
+		}
+
+		startpoint = g_strdup_printf ("%"G_GINT64_FORMAT",%"G_GINT64_FORMAT,
+					      last_session,
+					      next_wr_add);
+
+		g_ptr_array_add (argv, g_strdup ("-C"));
+		g_ptr_array_add (argv, startpoint);
+
+		if (flags & BRASERO_BURN_FLAG_MERGE) {
+		        gchar *device = NULL;
+
+			g_ptr_array_add (argv, g_strdup ("-M"));
+
+			brasero_job_get_device (BRASERO_JOB (genisoimage), &device);
+			g_ptr_array_add (argv, device);
+		}
+	}
+
+	brasero_job_get_action (BRASERO_JOB (genisoimage), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		g_ptr_array_add (argv, g_strdup ("-quiet"));
+		g_ptr_array_add (argv, g_strdup ("-print-size"));
+
+		brasero_job_set_current_action (BRASERO_JOB (genisoimage),
+						BRASERO_BURN_ACTION_GETTING_SIZE,
+						NULL,
+						FALSE);
+		brasero_job_start_progress (BRASERO_JOB (genisoimage), FALSE);
+
+		if (videodir) {
+			g_ptr_array_add (argv, g_strdup ("-f"));
+			g_ptr_array_add (argv, videodir);
+		}
+
+		return BRASERO_BURN_OK;
+	}
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (genisoimage), NULL) != BRASERO_BURN_OK) {
+		gchar *output = NULL;
+
+		result = brasero_job_get_image_output (BRASERO_JOB (genisoimage),
+						      &output,
+						       NULL);
+		if (result != BRASERO_BURN_OK) {
+			g_free (videodir);
+			return result;
+		}
+
+		g_ptr_array_add (argv, g_strdup ("-o"));
+		g_ptr_array_add (argv, output);
+	}
+
+	if (videodir) {
+		g_ptr_array_add (argv, g_strdup ("-f"));
+		g_ptr_array_add (argv, videodir);
+	}
+
+	brasero_job_set_current_action (BRASERO_JOB (genisoimage),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					NULL,
+					FALSE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_set_argv (BraseroProcess *process,
+			      GPtrArray *argv,
+			      GError **error)
+{
+	BraseroGenisoimagePrivate *priv;
+	BraseroGenisoimage *genisoimage;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	gchar *prog_name;
+
+	genisoimage = BRASERO_GENISOIMAGE (process);
+	priv = BRASERO_GENISOIMAGE_PRIVATE (process);
+
+	prog_name = g_find_program_in_path ("genisoimage");
+	if (prog_name && g_file_test (prog_name, G_FILE_TEST_IS_EXECUTABLE))
+		g_ptr_array_add (argv, prog_name);
+	else
+		g_ptr_array_add (argv, g_strdup ("genisoimage"));
+
+	if (priv->use_utf8) {
+		g_ptr_array_add (argv, g_strdup ("-input-charset"));
+		g_ptr_array_add (argv, g_strdup ("utf8"));
+	}
+
+	brasero_job_get_action (BRASERO_JOB (genisoimage), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		result = brasero_genisoimage_set_argv_image (genisoimage, argv, error);
+	else if (action == BRASERO_JOB_ACTION_IMAGE)
+		result = brasero_genisoimage_set_argv_image (genisoimage, argv, error);
+	else
+		BRASERO_JOB_NOT_SUPPORTED (genisoimage);
+
+	return result;
+}
+
+static void
+brasero_genisoimage_class_init (BraseroGenisoimageClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroGenisoimagePrivate));
+
+	parent_class = g_type_class_peek_parent(klass);
+	object_class->finalize = brasero_genisoimage_finalize;
+
+	process_class->stdout_func = brasero_genisoimage_read_stdout;
+	process_class->stderr_func = brasero_genisoimage_read_stderr;
+	process_class->set_argv = brasero_genisoimage_set_argv;
+}
+
+static void
+brasero_genisoimage_init (BraseroGenisoimage *obj)
+{
+	BraseroGenisoimagePrivate *priv;
+	gchar *standard_error;
+	gboolean res;
+
+	priv = BRASERO_GENISOIMAGE_PRIVATE (obj);
+
+	/* this code used to be ncb_genisoimage_supports_utf8 */
+	res = g_spawn_command_line_sync ("genisoimage -input-charset utf8",
+					 NULL,
+					 &standard_error,
+					 NULL,
+					 NULL);
+
+	if (res && !g_strrstr (standard_error, "Unknown charset"))
+		priv->use_utf8 = TRUE;
+	else
+		priv->use_utf8 = FALSE;
+
+	g_free (standard_error);
+}
+
+static void
+brasero_genisoimage_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_genisoimage_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "genisoimage",
+			       _("Use genisoimage to create images from a file selection"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("genisoimage", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CDR|
+				  BRASERO_MEDIUM_CDRW|
+				  BRASERO_MEDIUM_DVDR|
+				  BRASERO_MEDIUM_DVDRW|
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_DVDR_PLUS|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_AUDIO|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_RESTRICTED|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* Caps */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_IMAGE_FORMAT_BIN);
+
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+				       BRASERO_IMAGE_FS_UDF|
+				       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+				       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+				       BRASERO_IMAGE_FS_JOLIET|
+				       BRASERO_IMAGE_FS_VIDEO);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+				       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+				       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+				       BRASERO_IMAGE_FS_SYMLINK);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	g_slist_free (output);
+
+	brasero_plugin_register_group (plugin, _(CDRKIT_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrkit/burn-genisoimage.h b/plugins/cdrkit/burn-genisoimage.h
new file mode 100644
index 0000000..ed8c1b4
--- /dev/null
+++ b/plugins/cdrkit/burn-genisoimage.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *            genisoimage.h
+ *
+ *  dim jan 22 15:20:57 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef GENISOIMAGE_H
+#define GENISOIMAGE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_GENISOIMAGE         (brasero_genisoimage_get_type ())
+#define BRASERO_GENISOIMAGE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimage))
+#define BRASERO_GENISOIMAGE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimageClass))
+#define BRASERO_IS_GENISOIMAGE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_GENISOIMAGE))
+#define BRASERO_IS_GENISOIMAGE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_GENISOIMAGE))
+#define BRASERO_GENISOIMAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimageClass))
+
+G_END_DECLS
+
+#endif /* GENISOIMAGE_H */
diff --git a/plugins/cdrkit/burn-readom.c b/plugins/cdrkit/burn-readom.c
new file mode 100644
index 0000000..60677e8
--- /dev/null
+++ b/plugins/cdrkit/burn-readom.c
@@ -0,0 +1,484 @@
+/***************************************************************************
+ *            readom.c
+ *
+ *  dim jan 22 18:06:10 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-cdrkit.h"
+#include "burn-readom.h"
+#include "burn-process.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "brasero-tags.h"
+#include "brasero-track-disc.h"
+
+#include "burn-volume.h"
+#include "brasero-drive.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroReadom, brasero_readom, BRASERO_TYPE_PROCESS, BraseroProcess);
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_readom_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	BraseroReadom *readom;
+	gint dummy1;
+	gint dummy2;
+	gchar *pos;
+
+	readom = BRASERO_READOM (process);
+
+	if ((pos = strstr (line, "addr:"))) {
+		gint sector;
+		gint64 written;
+		BraseroTrackType *output = NULL;
+
+		pos += strlen ("addr:");
+		sector = strtoll (pos, NULL, 10);
+
+		output = brasero_track_type_new ();
+		brasero_job_get_output_type (BRASERO_JOB (readom), output);
+
+		if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN)
+			written = (gint64) ((gint64) sector * 2048ULL);
+		else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_CLONE)
+			written = (gint64) ((gint64) sector * 2448ULL);
+		else
+			written = (gint64) ((gint64) sector * 2048ULL);
+
+		brasero_job_set_written_track (BRASERO_JOB (readom), written);
+
+		if (sector > 10)
+			brasero_job_start_progress (BRASERO_JOB (readom), FALSE);
+
+		brasero_track_type_free (output);
+	}
+	else if ((pos = strstr (line, "Capacity:"))) {
+		brasero_job_set_current_action (BRASERO_JOB (readom),
+						BRASERO_BURN_ACTION_DRIVE_COPY,
+						NULL,
+						FALSE);
+	}
+	else if (strstr (line, "Device not ready.")) {
+		brasero_job_error (BRASERO_JOB (readom),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_DRIVE_BUSY,
+						_("The drive is busy")));
+	}
+	else if (strstr (line, "Cannot open SCSI driver.")) {
+		brasero_job_error (BRASERO_JOB (readom),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));		
+	}
+	else if (strstr (line, "Cannot send SCSI cmd via ioctl")) {
+		brasero_job_error (BRASERO_JOB (readom),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));
+	}
+	/* we scan for this error as in this case readcd returns success */
+	else if (sscanf (line, "Input/output error. Error on sector %d not corrected. Total of %d error", &dummy1, &dummy2) == 2) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("An internal error occured")));
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readom_argv_set_iso_boundary (BraseroReadom *readom,
+				      GPtrArray *argv,
+				      GError **error)
+{
+	guint64 nb_blocks;
+	BraseroTrack *track;
+	GValue *value = NULL;
+	BraseroTrackType *output = NULL;
+
+	brasero_job_get_current_track (BRASERO_JOB (readom), &track);
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (readom), output);
+
+	brasero_track_tag_lookup (track,
+				  BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+				  &value);
+	if (value) {
+		guint64 start, end;
+
+		/* we were given an address to start */
+		start = g_value_get_uint64 (value);
+
+		/* get the length now */
+		value = NULL;
+		brasero_track_tag_lookup (track,
+					  BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+					  &value);
+
+		end = g_value_get_uint64 (value);
+
+		BRASERO_JOB_LOG (readom,
+				 "reading from sector %lli to %lli",
+				 start,
+				 end);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+							start,
+							end));
+	}
+	/* 0 means all disc, -1 problem */
+	else if (brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)) > 0) {
+		guint64 start;
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_track_space (medium,
+						brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+						NULL,
+						&nb_blocks);
+		brasero_medium_get_track_address (medium,
+						  brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+						  NULL,
+						  &start);
+
+		BRASERO_JOB_LOG (readom,
+				 "reading %i from sector %lli to %lli",
+				 brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+				 start,
+				 start + nb_blocks);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+							start,
+							start + nb_blocks));
+	}
+	/* if it's BIN output just read the last track */
+	else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+		guint64 start;
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_last_data_track_space (medium,
+							  NULL,
+							  &nb_blocks);
+		brasero_medium_get_last_data_track_address (medium,
+							    NULL,
+							    &start);
+		BRASERO_JOB_LOG (readom,
+				 "reading last track from sector %lli to %lli",
+				 start,
+				 start + nb_blocks);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+							start,
+							start + nb_blocks));
+	}
+	else {
+		brasero_track_get_size (track, &nb_blocks, NULL);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=0-%lli", nb_blocks));
+	}
+
+	brasero_track_type_free (output);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readom_get_size (BraseroReadom *self,
+			 GError **error)
+{
+	guint64 blocks;
+	GValue *value = NULL;
+	BraseroTrack *track = NULL;
+	BraseroTrackType *output = NULL;
+
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (self), output);
+
+	if (!brasero_track_type_get_has_image (output)) {
+		brasero_track_type_free (output);
+		return BRASERO_BURN_ERR;
+	}
+
+	brasero_track_tag_lookup (track,
+				  BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+				  &value);
+	if (value) {
+		guint64 start, end;
+
+		/* we were given an address to start */
+		start = g_value_get_uint64 (value);
+
+		/* get the length now */
+		value = NULL;
+		brasero_track_tag_lookup (track,
+					  BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+					  &value);
+
+		end = g_value_get_uint64 (value);
+		blocks = end - start;
+	}
+	else if (brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)) > 0) {
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_track_space (medium,
+						brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+						NULL,
+						&blocks);
+	}
+	else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_last_data_track_space (medium,
+							  NULL,
+							  &blocks);
+	}
+	else
+		brasero_track_get_size (track, &blocks, NULL);
+
+	if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+		brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+							       blocks,
+							       blocks * 2048ULL);
+	}
+	else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_CLONE) {
+		brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+							       blocks,
+							       blocks * 2448ULL);
+	}
+	else {
+		brasero_track_type_free (output);
+		return BRASERO_BURN_NOT_SUPPORTED;
+	}
+
+	brasero_track_type_free (output);
+
+	/* no need to go any further */
+	return BRASERO_BURN_NOT_RUNNING;
+}
+
+static BraseroBurnResult
+brasero_readom_set_argv (BraseroProcess *process,
+			 GPtrArray *argv,
+			 GError **error)
+{
+	BraseroBurnResult result = FALSE;
+	BraseroTrackType *output = NULL;
+	BraseroImageFormat format;
+	BraseroJobAction action;
+	BraseroReadom *readom;
+	BraseroMedium *medium;
+	BraseroDrive *drive;
+	BraseroTrack *track;
+	BraseroMedia media;
+	gchar *outfile_arg;
+	gchar *dev_str;
+
+	readom = BRASERO_READOM (process);
+
+	/* This is a kind of shortcut */
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		return brasero_readom_get_size (readom, error);
+
+	g_ptr_array_add (argv, g_strdup ("readom"));
+
+	brasero_job_get_current_track (BRASERO_JOB (readom), &track);
+	drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+	if (!brasero_drive_get_device (drive))
+		return BRASERO_BURN_ERR;
+
+	dev_str = g_strdup_printf ("dev=%s", brasero_drive_get_device (drive));
+	g_ptr_array_add (argv, dev_str);
+
+	g_ptr_array_add (argv, g_strdup ("-nocorr"));
+
+	medium = brasero_drive_get_medium (drive);
+	media = brasero_medium_get_status (medium);
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (readom), output);
+	format = brasero_track_type_get_image_format (output);
+	brasero_track_type_free (output);
+
+	if ((media & BRASERO_MEDIUM_DVD)
+	&&   format != BRASERO_IMAGE_FORMAT_BIN) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("An internal error occured"));
+		return BRASERO_BURN_ERR;
+	}
+
+	if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+		/* NOTE: with this option the sector size is 2448 
+		 * because it is raw96 (2352+96) otherwise it is 2048  */
+		g_ptr_array_add (argv, g_strdup ("-clone"));
+	}
+	else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+		g_ptr_array_add (argv, g_strdup ("-noerror"));
+
+		/* don't do it for clone since we need the entire disc */
+		result = brasero_readom_argv_set_iso_boundary (readom, argv, error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (readom);
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (readom), NULL) != BRASERO_BURN_OK) {
+		gchar *image;
+
+		if (format != BRASERO_IMAGE_FORMAT_CLONE
+		&&  format != BRASERO_IMAGE_FORMAT_BIN)
+			BRASERO_JOB_NOT_SUPPORTED (readom);
+
+		result = brasero_job_get_image_output (BRASERO_JOB (readom),
+						       &image,
+						       NULL);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		outfile_arg = g_strdup_printf ("-f=%s", image);
+		g_ptr_array_add (argv, outfile_arg);
+		g_free (image);
+	}
+	else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+		outfile_arg = g_strdup ("-f=-");
+		g_ptr_array_add (argv, outfile_arg);
+	}
+	else 	/* unfortunately raw images can't be piped out */
+		BRASERO_JOB_NOT_SUPPORTED (readom);
+
+	brasero_job_set_use_average_rate (BRASERO_JOB (process), TRUE);
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_readom_class_init (BraseroReadomClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS(klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_readom_finalize;
+
+	process_class->stderr_func = brasero_readom_read_stderr;
+	process_class->set_argv = brasero_readom_set_argv;
+}
+
+static void
+brasero_readom_init (BraseroReadom *obj)
+{ }
+
+static void
+brasero_readom_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_readom_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "readom",
+			       _("Use readom to create disc images"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("readom", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* that's for clone mode only The only one to copy audio */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_IMAGE_FORMAT_CLONE);
+
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+				       BRASERO_MEDIUM_ROM|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_HAS_AUDIO|
+				       BRASERO_MEDIUM_HAS_DATA);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* that's for regular mode: it accepts the previous type of discs 
+	 * plus the DVDs types as well */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_IMAGE_FORMAT_BIN);
+
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+				       BRASERO_MEDIUM_DVD|
+				       BRASERO_MEDIUM_DUAL_L|
+				       BRASERO_MEDIUM_PLUS|
+				       BRASERO_MEDIUM_SEQUENTIAL|
+				       BRASERO_MEDIUM_RESTRICTED|
+				       BRASERO_MEDIUM_ROM|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_HAS_DATA);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	brasero_plugin_register_group (plugin, _(CDRKIT_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrkit/burn-readom.h b/plugins/cdrkit/burn-readom.h
new file mode 100644
index 0000000..6372ed8
--- /dev/null
+++ b/plugins/cdrkit/burn-readom.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *            readom.h
+ *
+ *  dim jan 22 18:06:10 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef READOM_H
+#define READOM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_READOM         (brasero_readom_get_type ())
+#define BRASERO_READOM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_READOM, BraseroReadom))
+#define BRASERO_READOM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_READOM, BraseroReadomClass))
+#define BRASERO_IS_READOM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_READOM))
+#define BRASERO_IS_READOM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_READOM))
+#define BRASERO_READOM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_READOM, BraseroReadomClass))
+
+G_END_DECLS
+
+#endif /* READOM_H */
diff --git a/plugins/cdrkit/burn-wodim.c b/plugins/cdrkit/burn-wodim.c
new file mode 100644
index 0000000..3f0086f
--- /dev/null
+++ b/plugins/cdrkit/burn-wodim.c
@@ -0,0 +1,1380 @@
+/***************************************************************************
+ *            wodim.c
+ *
+ *  dim jan 22 15:22:52 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-units.h"
+
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrkit.h"
+#include "burn-wodim.h"
+
+#include "brasero-tags.h"
+#include "brasero-track-image.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroWodim, brasero_wodim, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroWodimPrivate {
+	gint64 current_track_end_pos;
+	gint64 current_track_written;
+
+	gint current_track_num;
+	gint track_count;
+
+	gint minbuf;
+
+	GSList *infs;
+
+	guint immediate:1;
+};
+typedef struct _BraseroWodimPrivate BraseroWodimPrivate;
+#define BRASERO_WODIM_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_WODIM, BraseroWodimPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_IMMEDIATE_FLAG	"/apps/brasero/config/immed_flag"
+#define GCONF_KEY_MINBUF_VALUE		"/apps/brasero/config/minbuf_value"
+
+static BraseroBurnResult
+brasero_wodim_stderr_read (BraseroProcess *process, const gchar *line)
+{
+	BraseroBurnFlag flags;
+
+	brasero_job_get_flags (BRASERO_JOB (process), &flags);
+
+	if (strstr (line, "Cannot open SCSI driver.")
+	||  strstr (line, "Operation not permitted. Cannot send SCSI cmd via ioctl")
+	||  strstr (line, "Cannot open or use SCSI driver")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));
+	}
+	else if (!(flags & BRASERO_BURN_FLAG_OVERBURN)
+	     &&  strstr (line, "Data may not fit on current disk")) {
+		/* we don't error out if overburn was chosen */
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_SPACE,
+						_("Not enough space available on the disc")));
+	}
+	else if (strstr (line ,"cdrecord: A write error occured")
+	     ||  strstr (line, "Could not write Lead-in")
+	     ||  strstr (line, "Cannot fixate disk")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_WRITE_MEDIUM,
+						_("An error occured while writing to disc")));
+	}
+	else if (strstr (line, "DMA speed too slow") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_SLOW_DMA,
+						_("The system is too slow to write the disc at this speed. Try a lower speed")));
+	}
+	else if (strstr (line, "Device or resource busy")) {
+		if (!strstr (line, "retrying in")) {
+			brasero_job_error (BRASERO_JOB (process),
+					   g_error_new (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_DRIVE_BUSY,
+							_("The drive is busy")));
+		}
+	}
+	else if (strstr (line, "Illegal write mode for this drive")) {
+		/* NOTE : when it happened I had to unlock the
+		 * drive with cdrdao and eject it. Should we ? */
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_DRIVE_BUSY,
+						_("The drive is busy")));
+	}
+
+	/* REMINDER: these should not be necessary as we checked that already */
+	/**
+	else if (strstr (line, "cannot write medium - incompatible format") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_INPUT_INVALID,
+						_("The image does not seem to be a proper iso9660 file system")));
+	}
+	else if (strstr (line, "This means that we are checking recorded media.") != NULL) {
+	**/	/* NOTE: defer the consequence of this error as it is not always
+		 * fatal. So send a warning but don't stop the process. */
+	/**	brasero_process_deferred_error (process,
+						g_error_new (BRASERO_BURN_ERROR,
+							     BRASERO_BURN_ERROR_MEDIUM_INVALID,
+							     _("The disc is already burnt")));
+	}
+	else if (strstr (line, "Cannot blank disk, aborting.") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_INVALID,
+						_("The disc could not be blanked")));
+	}
+	else if (strstr (line, "Bad audio track size")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("The audio tracks are too short or not a multiple of 2352")));
+	}
+	else if (strstr (line, "cdrecord: No such file or directory. Cannot open")
+	     ||  strstr (line, "No tracks specified. Need at least one.")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_INPUT,
+						_("The image file cannot be found")));
+	}
+	else if (strstr (line, "Inappropriate audio coding")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_INPUT_INVALID,
+						_("All audio files must be stereo, 16-bit digital audio with 44100Hz samples")));
+	}
+	else if (strstr (line, "No disk / Wrong disk!") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIA_NONE,
+						_("There seems to be no disc in the drive")));
+	}
+
+	**/
+
+	/** For these we'd rather have a message saying "cdrecord failed"
+	 *  as an internal error occured says nothing/even less
+	else if (strstr (line, "Bad file descriptor. read error on input file")
+	     ||  strstr (line, "Input buffer error, aborting")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("An internal error occured")));
+	}
+
+	**/
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_wodim_compute (BraseroWodim *wodim,
+		       gint mb_written,
+		       gint mb_total,
+		       gint track_num)
+{
+	gboolean track_num_changed = FALSE;
+	BraseroWodimPrivate *priv;
+	BraseroJobAction action;
+	gint64 this_remain;
+	gint64 bytes;
+	gint64 total;
+
+	priv = BRASERO_WODIM_PRIVATE (wodim);
+	if (mb_total <= 0)
+		return;
+
+	total = mb_total * 1048576;
+
+	if (track_num > priv->current_track_num) {
+		track_num_changed = TRUE;
+		priv->current_track_num = track_num;
+		priv->current_track_end_pos += mb_total * 1048576;
+	}
+
+	this_remain = (mb_total - mb_written) * 1048576;
+	bytes = (total - priv->current_track_end_pos) + this_remain;
+	brasero_job_set_written_session (BRASERO_JOB (wodim), total - bytes);
+
+	brasero_job_get_action (BRASERO_JOB (wodim), &action);
+	if (action == BRASERO_JOB_ACTION_RECORD) {
+		gchar *action_string;
+
+		action_string = g_strdup_printf ("Writing track %02i", track_num);
+		brasero_job_set_current_action (BRASERO_JOB (wodim),
+						BRASERO_BURN_ACTION_RECORDING,
+						action_string,
+						track_num_changed);
+		g_free (action_string);
+	}
+	else if (action == BRASERO_JOB_ACTION_ERASE) {
+		brasero_job_set_progress (BRASERO_JOB (wodim), (gfloat) mb_written / (gfloat) mb_total);
+		brasero_job_set_current_action (BRASERO_JOB (wodim),
+						BRASERO_BURN_ACTION_BLANKING,
+						NULL,
+						FALSE);
+	}
+}
+
+static BraseroBurnResult
+brasero_wodim_stdout_read (BraseroProcess *process, const gchar *line)
+{
+	guint track;
+	guint speed_1, speed_2;
+	BraseroWodim *wodim;
+	BraseroWodimPrivate *priv;
+	int mb_written = 0, mb_total = 0, fifo = 0, buf = 0;
+
+	wodim = BRASERO_WODIM (process);
+	priv = BRASERO_WODIM_PRIVATE (wodim);
+
+	if (sscanf (line, "Track %2u: %d of %d MB written (fifo %d%%) [buf %d%%] %d.%dx.",
+		    &track, &mb_written, &mb_total, &fifo, &buf, &speed_1, &speed_2) == 7) {
+		gdouble current_rate;
+
+		current_rate = (gdouble) ((gdouble) speed_1 +
+			       (gdouble) speed_2 / 10.0) *
+			       (gdouble) CD_RATE;
+		brasero_job_set_rate (BRASERO_JOB (wodim), current_rate);
+
+		priv->current_track_written = mb_written * 1048576;
+		brasero_wodim_compute (wodim,
+				       mb_written,
+				       mb_total,
+				       track);
+
+		brasero_job_start_progress (BRASERO_JOB (wodim), FALSE);
+	} 
+	else if (sscanf (line, "Track %2u:    %d MB written (fifo %d%%) [buf  %d%%]  %d.%dx.",
+			 &track, &mb_written, &fifo, &buf, &speed_1, &speed_2) == 6) {
+		gdouble current_rate;
+
+		/* this line is printed when wodim writes on the fly */
+		current_rate = (gdouble) ((gdouble) speed_1 +
+			       (gdouble) speed_2 / 10.0) *
+			       (gdouble) CD_RATE;
+		brasero_job_set_rate (BRASERO_JOB (wodim), current_rate);
+
+		priv->current_track_written = mb_written * 1048576;
+		if (brasero_job_get_fd_in (BRASERO_JOB (wodim), NULL) == BRASERO_BURN_OK) {
+			guint64 bytes = 0;
+
+			/* we must ask the imager what is the total size */
+			brasero_job_get_session_output_size (BRASERO_JOB (wodim),
+							     NULL,
+							     &bytes);
+			mb_total = bytes / 1048576;
+			brasero_wodim_compute (wodim,
+					       mb_written,
+					       mb_total,
+					       track);
+		}
+
+		brasero_job_start_progress (BRASERO_JOB (wodim), FALSE);
+	}
+	else if (sscanf (line, "Formating in progress: %d.%d %% done", &mb_written, &mb_total) == 2) {
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_BLANKING,
+						_("Formatting disc"),
+						FALSE);
+
+		brasero_job_start_progress (BRASERO_JOB (wodim), FALSE);
+		brasero_job_set_progress (BRASERO_JOB (wodim),
+					  (gdouble) ((gdouble) mb_written + ((gdouble) mb_total) / 10.0) / 100.0);
+	}
+	else if (sscanf (line, "Track %*d: %*s %d MB ", &mb_total) == 1) {
+/*		if (mb_total > 0)
+			priv->tracks_total_bytes += mb_total * 1048576;
+*/	}
+	else if (strstr (line, "Sending CUE sheet")) {
+		BraseroTrackType *type = NULL;
+
+		/* See if we are in an audio case which would mean we're writing
+		 * CD-TEXT */
+		type = brasero_track_type_new ();
+		brasero_job_get_input_type (BRASERO_JOB (wodim), type);
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_RECORDING_CD_TEXT,
+						brasero_track_type_get_has_stream (type) ? NULL:_("Writing cue sheet"),
+						FALSE);
+		brasero_track_type_free (type);
+	}
+	else if (g_str_has_prefix (line, "Re-load disk and hit <CR>")
+	     ||  g_str_has_prefix (line, "send SIGUSR1 to continue")) {
+		BraseroBurnAction action = BRASERO_BURN_ACTION_NONE;
+
+		brasero_job_get_current_action (BRASERO_JOB (process), &action);
+
+		/* NOTE: There seems to be a BUG somewhere when writing raw images
+		 * with clone mode. After disc has been written and fixated wodim
+		 * asks the media to be reloaded. So we simply ignore this message
+		 * and returns that everything went well. Which is indeed the case */
+		if (action == BRASERO_BURN_ACTION_FIXATING) {
+			brasero_job_finished_session (BRASERO_JOB (process));
+			return BRASERO_BURN_OK;
+		}
+
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_NEED_RELOADING,
+						_("The disc needs to be reloaded before being recorded")));
+	}
+	else if (g_str_has_prefix (line, "Fixating...")
+	     ||  g_str_has_prefix (line, "Writing Leadout...")) {
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_FIXATING,
+						NULL,
+						FALSE);
+	}
+	else if (g_str_has_prefix (line, "Last chance to quit, ")) {
+		brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+	}
+	else if (g_str_has_prefix (line, "Blanking PMA, TOC, pregap")
+	     ||  strstr (line, "Blanking entire disk")) {
+
+	}
+	/* This should not happen */
+	/* else if (strstr (line, "Use tsize= option in SAO mode to specify track size")) */
+
+	return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_wodim_write_inf (BraseroWodim *wodim,
+			 GPtrArray *argv,
+			 BraseroTrack *track,
+			 const gchar *tmpdir,
+			 const gchar *album,
+			 gint index,
+			 gint start,
+			 gboolean last_track,
+			 GError **error)
+{
+	gint fd;
+	int isrc;
+	gint size;
+        int errsv;
+	gchar *path;
+	guint64 length;
+	gchar *string;
+	gint b_written;
+	gint64 sectors;
+	gchar buffer [128];
+	const gchar *info;
+	BraseroWodimPrivate *priv;
+
+	priv = BRASERO_WODIM_PRIVATE (wodim);
+
+	/* NOTE: about the .inf files: they should have the exact same path
+	 * but the ending suffix file is replaced by inf:
+	 * example : /path/to/file.mp3 => /path/to/file.inf */
+	if (brasero_job_get_fd_in (BRASERO_JOB (wodim), NULL) != BRASERO_BURN_OK) {
+		gchar *dot, *separator;
+
+		path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+
+		dot = strrchr (path, '.');
+		separator = strrchr (path, G_DIR_SEPARATOR);
+
+		if (dot && dot > separator)
+			path = g_strdup_printf ("%.*s.inf", dot - path, path);
+		else
+			path = g_strdup_printf ("%s.inf", path);
+
+		/* since this file was not returned by brasero_job_get_tmp_file
+		 * it won't be erased when session is unrefed so we have to do 
+		 * it ourselves */
+		priv->infs = g_slist_prepend (priv->infs, g_strdup (path));
+	}
+	else {
+		BraseroBurnResult result;
+
+		/* in this case don't care about the name since stdin is used */
+		result = brasero_job_get_tmp_file (BRASERO_JOB (wodim),
+						   ".inf",
+						   &path,
+						   error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+
+	fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+	if (fd < 0)
+		goto error;
+
+	BRASERO_JOB_LOG (wodim, "writing inf (%s)", path);
+
+	/* The problem here is that when writing CD-TEXT from .inf files, wodim
+	 * uses only one charset (and don't let us specify which one) which is
+	 * ISO-8859-1. (NOTE: don't believe the doc claiming it requires ASCII
+	 * and see cdrecord/cdtext.c line 309).
+	 * So we have to convert our UTF-8 input into such a charset.
+	 * NOTE: according to docs ASCII should be used for text packs other
+	 * than disc/track title.
+	 * It might be good in the end to write and pack CD-TEXT pack data 
+	 * ourselves so we can set a different charset from English like 
+	 * Chinese for example. */
+	strcpy (buffer, "# created by brasero\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "MCN=\t\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	/* ISRC */
+	isrc = brasero_track_tag_lookup_int (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ISRC_TAG);
+	if (isrc > 0)
+		string = g_strdup_printf ("ISRC=\t%i\n", isrc);
+	else
+		string = g_strdup ("ISRC=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Albumperformer=\t\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	if (album) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (album,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Albumtitle=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Albumtitle=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	/* ARTIST */
+	info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+						BRASERO_TRACK_STREAM_ARTIST_TAG);
+	if (info) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (info,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Performer=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Performer=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	/* COMPOSER */
+	info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+						BRASERO_TRACK_STREAM_COMPOSER_TAG);
+	if (info) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (info,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Composer=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Composer=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	/* TITLE */
+	info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+						BRASERO_TRACK_STREAM_TITLE_TAG);
+	if (info) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (info,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Tracktitle=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Tracktitle=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	string = g_strdup_printf ("Tracknumber=\t%i\n", index);
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	string = g_strdup_printf ("Trackstart=\t%i\n", start);
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	length = 0;
+	brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
+	sectors = BRASERO_DURATION_TO_SECTORS (length);
+
+	BRASERO_JOB_LOG (wodim, "got track length %lli %lli", length, sectors);
+	string = g_strdup_printf ("Tracklength=\t%"G_GINT64_FORMAT", 0\n", sectors);
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Pre-emphasis=\tno\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Channels=\t2\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Copy_permitted=\tyes\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Endianess=\tlittle\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Index=\t\t0\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	/* NOTE: -1 here means no pregap */
+	if (!last_track) {
+		/* K3b does this (possibly to remove silence) */
+		string = g_strdup_printf ("Index0=\t\t%"G_GINT64_FORMAT"\n",
+					  sectors - 150);
+	}
+	else
+		string = g_strdup_printf ("Index0=\t\t-1\n");
+
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+
+	if (b_written != size)
+		goto error;
+
+	close (fd);
+
+	if (argv)
+		g_ptr_array_add (argv, path);
+	else
+		g_free (path);
+
+	return BRASERO_BURN_OK;
+
+
+error:
+        errsv = errno;
+
+	g_remove (path);
+	g_free (path);
+
+	BRASERO_JOB_LOG (wodim,
+			 "The inf file can't be written : %s",
+			 g_strerror (errsv));
+
+	g_set_error (error,
+		     BRASERO_BURN_ERROR,
+		     BRASERO_BURN_ERROR_GENERAL,
+		     _("An internal error occured"));
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_wodim_write_infs (BraseroWodim *wodim,
+			   GPtrArray *argv,
+			   GError **error)
+{
+	BraseroWodimPrivate *priv;
+	BraseroBurnResult result;
+	gchar *tmpdir = NULL;
+	GSList *tracks;
+	GSList *iter;
+	gchar *album;
+	gint index;
+	gint start;
+
+	priv = BRASERO_WODIM_PRIVATE (wodim);
+
+	brasero_job_get_audio_title (BRASERO_JOB (wodim), &album);
+	brasero_job_get_tracks (BRASERO_JOB (wodim), &tracks);
+	index = 1;
+	start = 0;
+
+	for (iter = tracks; iter; iter = iter->next) {
+		guint64 sectors;
+		BraseroTrack *track;
+
+		track = iter->data;
+		result = brasero_wodim_write_inf (wodim,
+						  argv,
+						  track,
+						  tmpdir,
+						  album,
+						  index,
+						  start,
+						  (iter->next == NULL),
+						  error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		index ++;
+		sectors = 0;
+
+		brasero_track_get_size (track, &sectors, NULL);
+		start += sectors;
+	}
+
+	g_free (album);
+	g_free (tmpdir);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_wodim_set_argv_record (BraseroWodim *wodim,
+				GPtrArray *argv, 
+				GError **error)
+{
+	guint speed;
+	BraseroBurnFlag flags;
+	BraseroWodimPrivate *priv;
+	BraseroTrackType *type = NULL;
+
+	priv = BRASERO_WODIM_PRIVATE (wodim);
+
+	if (priv->immediate) {
+		g_ptr_array_add (argv, g_strdup ("-immed"));
+		g_ptr_array_add (argv, g_strdup_printf ("minbuf=%i", priv->minbuf));
+	}
+
+	if (brasero_job_get_speed (BRASERO_JOB (wodim), &speed) == BRASERO_BURN_OK) {
+		gchar *speed_str;
+
+		speed_str = g_strdup_printf ("speed=%d", speed);
+		g_ptr_array_add (argv, speed_str);
+	}
+
+	brasero_job_get_flags (BRASERO_JOB (wodim), &flags);
+	if (flags & BRASERO_BURN_FLAG_OVERBURN)
+		g_ptr_array_add (argv, g_strdup ("-overburn"));
+	if (flags & BRASERO_BURN_FLAG_BURNPROOF)
+		g_ptr_array_add (argv, g_strdup ("driveropts=burnfree"));
+	if (flags & BRASERO_BURN_FLAG_MULTI)
+		g_ptr_array_add (argv, g_strdup ("-multi"));
+
+	/* NOTE: This write mode is necessary for all CLONE images burning */
+	if (flags & BRASERO_BURN_FLAG_RAW)
+		g_ptr_array_add (argv, g_strdup ("-raw96r"));
+
+	/* NOTE1: DAO can't be used if we're appending to a disc */
+	/* NOTE2: CD-text cannot be written in tao mode (which is the default)
+	 * NOTE3: when we don't want wodim to use stdin then we give the audio
+	 * file on the command line. Otherwise we use the .inf */
+	if (flags & BRASERO_BURN_FLAG_DAO)
+		g_ptr_array_add (argv, g_strdup ("-dao"));
+
+	type = brasero_track_type_new ();
+	brasero_job_get_input_type (BRASERO_JOB (wodim), type);
+	if (brasero_job_get_fd_in (BRASERO_JOB (wodim), NULL) == BRASERO_BURN_OK) {
+		BraseroBurnResult result;
+		int buffer_size;
+		guint64 sectors;
+		
+		/* we need to know what is the type of the track (audio / data) */
+		result = brasero_job_get_input_type (BRASERO_JOB (wodim), type);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (type);
+
+			BRASERO_JOB_LOG (wodim, "Imager doesn't seem to be ready");
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("An internal error occured"));
+			return BRASERO_BURN_ERR;
+		}
+		
+		/* ask the size */
+		result = brasero_job_get_session_output_size (BRASERO_JOB (wodim),
+							      &sectors,
+							      NULL);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (type);
+
+			BRASERO_JOB_LOG (wodim, "The size of the session cannot be retrieved");
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("An internal error occured"));
+			return BRASERO_BURN_ERR;
+		}
+
+		/* we create a buffer depending on the size 
+		 * buffer 4m> < 64m and is 1/25th of size otherwise */
+		buffer_size = sectors * 2352 / 1024 / 1024 / 25;
+		if (buffer_size > 32)
+			buffer_size = 32;
+		else if (buffer_size < 4)
+			buffer_size = 4;
+
+		g_ptr_array_add (argv, g_strdup_printf ("fs=%im", buffer_size));
+		if (brasero_track_type_get_has_image (type)) {
+			if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_BIN) {
+				g_ptr_array_add (argv, g_strdup_printf ("tsize=%Lis", sectors));
+
+				g_ptr_array_add (argv, g_strdup ("-data"));
+				g_ptr_array_add (argv, g_strdup ("-nopad"));
+				g_ptr_array_add (argv, g_strdup ("-"));
+			}
+			else {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_SUPPORTED (wodim);
+			}
+		}
+		else if (brasero_track_type_get_has_stream (type)) {
+			/* NOTE: when we don't want wodim to use stdin then we
+			 * give the audio file on the command line. Otherwise we
+			 * use the .inf */
+			g_ptr_array_add (argv, g_strdup ("-swab"));
+			g_ptr_array_add (argv, g_strdup ("-audio"));
+			g_ptr_array_add (argv, g_strdup ("-useinfo"));
+			g_ptr_array_add (argv, g_strdup ("-text"));
+
+			result = brasero_wodim_write_infs (wodim,
+							   argv,
+							   error);
+			if (result != BRASERO_BURN_OK) {
+				brasero_track_type_free (type);
+				return result;
+			}
+		}
+		else {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_SUPPORTED (wodim);
+		}
+	}
+	else if (brasero_track_type_get_has_stream (type)) {
+		BraseroBurnResult result;
+		GSList *tracks;
+
+		g_ptr_array_add (argv, g_strdup ("fs=16m"));
+		g_ptr_array_add (argv, g_strdup ("-audio"));
+		g_ptr_array_add (argv, g_strdup ("-swab"));
+		g_ptr_array_add (argv, g_strdup ("-pad"));
+	
+		g_ptr_array_add (argv, g_strdup ("-useinfo"));
+		g_ptr_array_add (argv, g_strdup ("-text"));
+
+		result = brasero_wodim_write_infs (wodim,
+						   NULL,
+						   error);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (type);
+			return result;
+		}
+
+		tracks = NULL;
+		brasero_job_get_tracks (BRASERO_JOB (wodim), &tracks);
+		for (; tracks; tracks = tracks->next) {
+			BraseroTrack *track;
+			gchar *path;
+
+			track = tracks->data;
+			path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+			g_ptr_array_add (argv, path);
+		}
+	}
+	else if (brasero_track_type_get_has_image (type)) {
+		BraseroTrack *track = NULL;
+		BraseroImageFormat format;
+
+		brasero_job_get_current_track (BRASERO_JOB (wodim), &track);
+		if (!track) {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_READY (wodim);
+		}
+
+		format = brasero_track_type_get_image_format (type);
+		if (format == BRASERO_IMAGE_FORMAT_NONE) {
+			gchar *image_path;
+
+			image_path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!image_path) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (wodim);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+			g_ptr_array_add (argv, g_strdup ("-data"));
+			g_ptr_array_add (argv, g_strdup ("-nopad"));
+			g_ptr_array_add (argv, image_path);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+			gchar *isopath;
+
+			isopath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!isopath) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (wodim);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+			g_ptr_array_add (argv, g_strdup ("-data"));
+			g_ptr_array_add (argv, g_strdup ("-nopad"));
+			g_ptr_array_add (argv, isopath);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+			gchar *rawpath;
+
+			rawpath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!rawpath) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (wodim);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+			g_ptr_array_add (argv, g_strdup ("-clone"));
+			g_ptr_array_add (argv, rawpath);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_CUE) {
+			gchar *cue_str;
+			gchar *cuepath;
+
+			cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!cuepath) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (wodim);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+
+			cue_str = g_strdup_printf ("cuefile=%s", cuepath);
+			g_ptr_array_add (argv, cue_str);
+			g_free (cuepath);
+		}
+		else {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_SUPPORTED (wodim);
+		}
+	}
+	else {
+		brasero_track_type_free (type);
+		BRASERO_JOB_NOT_SUPPORTED (wodim);
+	}
+
+	brasero_track_type_free (type);
+	brasero_job_set_current_action (BRASERO_JOB (wodim),
+					BRASERO_BURN_ACTION_START_RECORDING,
+					NULL,
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_wodim_set_argv_blank (BraseroWodim *wodim, GPtrArray *argv)
+{
+	BraseroBurnResult result;
+	BraseroBurnFlag flags;
+	BraseroMedia media;
+
+	brasero_job_get_flags (BRASERO_JOB (wodim), &flags);
+
+	result = brasero_job_get_media (BRASERO_JOB (wodim), &media);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	if (!BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)) {
+		gchar *blank_str;
+
+		blank_str = g_strdup_printf ("blank=%s",
+					    (flags & BRASERO_BURN_FLAG_FAST_BLANK) ? "fast" : "all");
+		g_ptr_array_add (argv, blank_str);
+	}
+	else if (media & BRASERO_MEDIUM_UNFORMATTED) {
+		g_ptr_array_add (argv, g_strdup ("-format"));
+
+		/* There are many options for this given by an option that is
+		 * not documented: formattype=#type where type can be:
+		 * - force: to force reformatting => problem cannot/doesn't want to reformat a disc already formated
+		 * - full: to do a full formatting => problem only reformats what is not done yet
+		 * - background: formatting in the background => problem cannot/doesn't want to reformat a disc already formated
+		 * conclusion: we can only accept unformated media.
+		 * The following option allows to do it more quickly:
+		 * g_ptr_array_add (argv, g_strdup ("formattype=background");
+		 */
+				
+	}
+	else {
+		guint speed;
+		BraseroWodimPrivate *priv;
+
+		priv = BRASERO_WODIM_PRIVATE (wodim);
+
+		/* Since we can't reformat any already formatted DVD+RW, we 
+		 * write 0s to it to blank. */
+		if (priv->immediate) {
+			g_ptr_array_add (argv, g_strdup ("-immed"));
+			g_ptr_array_add (argv, g_strdup_printf ("minbuf=%i", priv->minbuf));
+		}
+
+		if (brasero_job_get_speed (BRASERO_JOB (wodim), &speed) == BRASERO_BURN_OK) {
+			gchar *speed_str;
+
+			speed_str = g_strdup_printf ("speed=%d", speed);
+			g_ptr_array_add (argv, speed_str);
+		}
+
+		if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
+			gint64 sectors = 0;
+			BraseroMedium *medium;
+
+			brasero_job_get_medium (BRASERO_JOB (wodim), &medium);
+			brasero_medium_get_data_size (medium, NULL, &sectors);
+			if (!sectors)
+				brasero_medium_get_capacity (medium, NULL, &sectors);
+
+			g_ptr_array_add (argv, g_strdup_printf ("tsize=%Lis", sectors));
+		}
+		else	/* we set 512s because wodim complains otherwise */
+			g_ptr_array_add (argv, g_strdup_printf ("tsize=512s"));
+
+		g_ptr_array_add (argv, g_strdup ("fs=16m"));
+		g_ptr_array_add (argv, g_strdup ("-data"));
+		g_ptr_array_add (argv, g_strdup ("-nopad"));
+		g_ptr_array_add (argv, g_strdup ("/dev/zero"));
+	}
+
+	brasero_job_set_current_action (BRASERO_JOB (wodim),
+					BRASERO_BURN_ACTION_BLANKING,
+					NULL,
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_wodim_set_argv (BraseroProcess *process,
+			 GPtrArray *argv,
+			 GError **error)
+{
+	BraseroWodimPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroWodim *wodim;
+	BraseroBurnFlag flags;
+	gchar *dev_str;
+	gchar *device;
+
+	wodim = BRASERO_WODIM (process);
+	priv = BRASERO_WODIM_PRIVATE (wodim);
+
+	brasero_job_get_action (BRASERO_JOB (wodim), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	g_ptr_array_add (argv, g_strdup ("wodim"));
+	g_ptr_array_add (argv, g_strdup ("-v"));
+
+	brasero_job_get_device (BRASERO_JOB (wodim), &device);
+	dev_str = g_strdup_printf ("dev=%s", device);
+	g_ptr_array_add (argv, dev_str);
+	g_free (device);
+
+	brasero_job_get_flags (BRASERO_JOB (wodim), &flags);
+        if (flags & BRASERO_BURN_FLAG_DUMMY)
+		g_ptr_array_add (argv, g_strdup ("-dummy"));
+
+	/* There is a bug in wodim where if we set that it takes 15 more so 
+	 * disable it as long as the bug remains. */
+
+	/* if (flags & BRASERO_BURN_FLAG_NOGRACE)
+	 *	g_ptr_array_add (argv, g_strdup ("gracetime=0"));
+	 */
+
+	if (action == BRASERO_JOB_ACTION_RECORD)
+		result = brasero_wodim_set_argv_record (wodim, argv, error);
+	else if (action == BRASERO_JOB_ACTION_ERASE)
+		result = brasero_wodim_set_argv_blank (wodim, argv);
+	else
+		BRASERO_JOB_NOT_SUPPORTED (wodim);
+
+	return result;	
+}
+
+static BraseroBurnResult
+brasero_wodim_post (BraseroJob *job)
+{
+	BraseroWodimPrivate *priv;
+	GSList *iter;
+
+	priv = BRASERO_WODIM_PRIVATE (job);
+	for (iter = priv->infs; iter; iter = iter->next) {
+		gchar *path;
+
+		path = iter->data;
+		g_remove (path);
+		g_free (path);
+	}
+
+	g_slist_free (priv->infs);
+	priv->infs = NULL;
+
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_wodim_class_init (BraseroWodimClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroWodimPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_wodim_finalize;
+
+	process_class->stderr_func = brasero_wodim_stderr_read;
+	process_class->stdout_func = brasero_wodim_stdout_read;
+	process_class->set_argv = brasero_wodim_set_argv;
+	process_class->post = brasero_wodim_post;
+}
+
+static void
+brasero_wodim_init (BraseroWodim *obj)
+{
+	GConfClient *client;
+	BraseroWodimPrivate *priv;
+
+	/* load our "configuration" */
+	priv = BRASERO_WODIM_PRIVATE (obj);
+
+	client = gconf_client_get_default ();
+	priv->immediate = gconf_client_get_bool (client,
+						 GCONF_KEY_IMMEDIATE_FLAG,
+						 NULL);
+	priv->minbuf = gconf_client_get_int (client,
+					     GCONF_KEY_MINBUF_VALUE,
+					     NULL);
+	if (priv->minbuf > 95 || priv->minbuf < 25)
+		priv->minbuf = 30;
+
+	g_object_unref (client);
+}
+
+static void
+brasero_wodim_finalize (GObject *object)
+{
+	BraseroWodimPrivate *priv;
+	GSList *iter;
+
+	priv = BRASERO_WODIM_PRIVATE (object);
+
+	for (iter = priv->infs; iter; iter = iter->next) {
+		gchar *path;
+
+		path = iter->data;
+		g_remove (path);
+		g_free (path);
+	}
+
+	g_slist_free (priv->infs);
+	priv->infs = NULL;
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_wodim_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroPluginConfOption *immed, *minbuf;
+	const BraseroMedia media = BRASERO_MEDIUM_CD|
+				   BRASERO_MEDIUM_WRITABLE|
+				   BRASERO_MEDIUM_REWRITABLE|
+				   BRASERO_MEDIUM_BLANK|
+				   BRASERO_MEDIUM_APPENDABLE|
+				   BRASERO_MEDIUM_HAS_AUDIO|
+				   BRASERO_MEDIUM_HAS_DATA;
+
+	/* tests failed with DVD-RW in restricted overwrite mode */
+	const BraseroMedia dvd_media = BRASERO_MEDIUM_DVD|
+				       BRASERO_MEDIUM_PLUS|
+				       BRASERO_MEDIUM_SEQUENTIAL|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_BLANK|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_HAS_DATA;
+	const BraseroMedia media_rw = BRASERO_MEDIUM_CD|
+				      BRASERO_MEDIUM_REWRITABLE|
+				      BRASERO_MEDIUM_APPENDABLE|
+				      BRASERO_MEDIUM_CLOSED|
+				      BRASERO_MEDIUM_HAS_AUDIO|
+				      BRASERO_MEDIUM_HAS_DATA|
+				      BRASERO_MEDIUM_BLANK;
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	/* NOTE: it seems that cdrecord can burn cue files on the fly */
+	brasero_plugin_define (plugin,
+			       "wodim",
+			       _("Use wodim to burn CDs and DVDs"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("wodim", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* for recording */
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_BIN);
+
+	/* wodim can burn all DVDs (except DVD-RW restricted) when it's ISOs */
+	output = brasero_caps_disc_new (dvd_media);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	/* All CD-R(W) */
+	output = brasero_caps_disc_new (media);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_METADATA_INFO);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* for CLONE and CUE type images, we only want blank CD-R(W) */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+					BRASERO_MEDIUM_WRITABLE|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_BLANK);
+
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_CUE|
+					BRASERO_IMAGE_FORMAT_CLONE);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* Flags for CD (RW)s */
+	BRASERO_PLUGIN_ADD_STANDARD_CDR_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+	BRASERO_PLUGIN_ADD_STANDARD_CDRW_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+	/* Apart from DAO it also supports RAW mode to burn CLONE images. This
+	 * is a special mode for which there isn't any DUMMY burn possible */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CD|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_RAW|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* For DVD-W and DVD-RW sequential
+	 * NOTE: given the performed tests it seems that wodim should not be 
+	 * used to start a multisession DVD-RW or even continue one. */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVD|
+				  BRASERO_MEDIUM_SEQUENTIAL|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_DAO|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* For DVD+R limited capabilites to blank media */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDR_PLUS|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_MULTI|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* For DVD+RW: limited capabilities there are no MULTI possible
+	 * NOTE: no UNFORMATTED here since wodim doesn't format them before*/
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* blanking/formatting caps and flags for +/sequential RW
+	 * NOTE: restricted overwrite DVD-RW can't be formatted.
+	 * moreover DVD+RW are formatted while DVD-RW sequential are blanked.
+	 * NOTE: blanking DVD-RW doesn't work */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_DVDRW_PLUS|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	/* again DVD+RW don't support dummy */
+	/* NOTE: wodim doesn't support formating already formated DVD+RWs. That
+	 * is an error for it (stupid!). So sets only unformated DVDs. */
+	brasero_plugin_set_blank_flags (plugin,
+					BRASERO_MEDIUM_DVDRW_PLUS|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	/* for blanking (CDRWs) */
+	output = brasero_caps_disc_new (media_rw);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+					media_rw,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	/* add some configure options */
+	immed = brasero_plugin_conf_option_new (GCONF_KEY_IMMEDIATE_FLAG,
+						_("Enable \"-immed\" flag (see wodim manual)"),
+						BRASERO_PLUGIN_OPTION_BOOL);
+	minbuf = brasero_plugin_conf_option_new (GCONF_KEY_MINBUF_VALUE,
+						 _("Minimum drive buffer fill ratio (in %) (see wodim manual):"),
+						 BRASERO_PLUGIN_OPTION_INT);
+	brasero_plugin_conf_option_int_set_range (minbuf, 25, 95);
+
+	brasero_plugin_conf_option_bool_add_suboption (immed, minbuf);
+	brasero_plugin_add_conf_option (plugin, immed);
+
+	brasero_plugin_register_group (plugin, _(CDRKIT_DESCRIPTION));
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrkit/burn-wodim.h b/plugins/cdrkit/burn-wodim.h
new file mode 100644
index 0000000..78c2c32
--- /dev/null
+++ b/plugins/cdrkit/burn-wodim.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            wodim.h
+ *
+ *  dim jan 22 15:22:52 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef WODIM_H
+#define WODIM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_WODIM         (brasero_wodim_get_type ())
+#define BRASERO_WODIM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_WODIM, BraseroWodim))
+#define BRASERO_WODIM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_WODIM, BraseroWodimClass))
+#define BRASERO_IS_WODIM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_WODIM))
+#define BRASERO_IS_WODIM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_WODIM))
+#define BRASERO_WODIM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_WODIM, BraseroWodimClass))
+
+G_END_DECLS
+
+#endif /* WODIM_H */
diff --git a/plugins/cdrtools/Makefile.am b/plugins/cdrtools/Makefile.am
new file mode 100644
index 0000000..a5e2ebb
--- /dev/null
+++ b/plugins/cdrtools/Makefile.am
@@ -0,0 +1,39 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_GCONF_CFLAGS)
+
+#cdrecord
+cdrecorddir = $(libdir)/brasero/plugins
+cdrecord_LTLIBRARIES = libbrasero-cdrecord.la
+libbrasero_cdrecord_la_SOURCES = burn-cdrecord.c burn-cdrecord.h \
+	burn-cdrtools.h 
+libbrasero_cdrecord_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_cdrecord_la_LDFLAGS = -module -avoid-version
+
+#mkisofs
+mkisofsdir = $(libdir)/brasero/plugins
+mkisofs_LTLIBRARIES = libbrasero-mkisofs.la
+libbrasero_mkisofs_la_SOURCES = burn-mkisofs.c burn-mkisofs.h \
+	burn-cdrtools.h 
+libbrasero_mkisofs_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_mkisofs_la_LDFLAGS = -module -avoid-version
+
+#readcd
+readcddir = $(libdir)/brasero/plugins
+readcd_LTLIBRARIES = libbrasero-readcd.la
+libbrasero_readcd_la_SOURCES = burn-readcd.c burn-readcd.h \
+	burn-cdrtools.h 
+libbrasero_readcd_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_readcd_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/cdrtools/burn-cdrecord.c b/plugins/cdrtools/burn-cdrecord.c
new file mode 100644
index 0000000..0af98d4
--- /dev/null
+++ b/plugins/cdrtools/burn-cdrecord.c
@@ -0,0 +1,1371 @@
+/***************************************************************************
+ *            cdrecord.c
+ *
+ *  dim jan 22 15:22:52 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-units.h"
+
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrtools.h"
+#include "burn-cdrecord.h"
+
+#include "brasero-tags.h"
+#include "brasero-track-image.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroCDRecord, brasero_cdrecord, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroCDRecordPrivate {
+	gint64 current_track_end_pos;
+	gint64 current_track_written;
+
+	gint current_track_num;
+	gint track_count;
+
+	gint minbuf;
+
+	GSList *infs;
+
+	guint immediate:1;
+};
+typedef struct _BraseroCDRecordPrivate BraseroCDRecordPrivate;
+#define BRASERO_CD_RECORD_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CD_RECORD, BraseroCDRecordPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_IMMEDIATE_FLAG	"/apps/brasero/config/immed_flag"
+#define GCONF_KEY_MINBUF_VALUE		"/apps/brasero/config/minbuf_value"
+
+static BraseroBurnResult
+brasero_cdrecord_stderr_read (BraseroProcess *process, const gchar *line)
+{
+	BraseroBurnFlag flags;
+
+	brasero_job_get_flags (BRASERO_JOB (process), &flags);
+
+	if (strstr (line, "Cannot open SCSI driver.")
+	||  strstr (line, "Operation not permitted. Cannot send SCSI cmd via ioctl")
+	||  strstr (line, "Cannot open or use SCSI driver")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));
+	}
+	else if (!(flags & BRASERO_BURN_FLAG_OVERBURN)
+	     &&  strstr (line, "Data may not fit on current disk")) {
+		/* we don't error out if overburn was chosen */
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_SPACE,
+						_("Not enough space available on the disc")));
+	}
+	else if (strstr (line ,"cdrecord: A write error occured")
+	     ||  strstr (line, "Could not write Lead-in")
+	     ||  strstr (line, "Cannot fixate disk")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_WRITE_MEDIUM,
+						_("An error occured while writing to disc")));
+	}
+	else if (strstr (line, "DMA speed too slow") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_SLOW_DMA,
+						_("The system is too slow to write the disc at this speed. Try a lower speed")));
+	}
+	else if (strstr (line, "Device or resource busy")) {
+		if (!strstr (line, "retrying in")) {
+			brasero_job_error (BRASERO_JOB (process),
+					   g_error_new (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_DRIVE_BUSY,
+							_("The drive is busy")));
+		}
+	}
+	else if (strstr (line, "Illegal write mode for this drive")) {
+		/* NOTE : when it happened I had to unlock the
+		 * drive with cdrdao and eject it. Should we ? */
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_DRIVE_BUSY,
+						_("The drive is busy")));
+	}
+
+	/* REMINDER: these should not be necessary as we checked that already */
+	/**
+	else if (strstr (line, "cannot write medium - incompatible format") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_INPUT_INVALID,
+						_("The image does not seem to be a proper iso9660 file system")));
+	}
+	else if (strstr (line, "This means that we are checking recorded media.") != NULL) {
+	**/	/* NOTE: defer the consequence of this error as it is not always
+		 * fatal. So send a warning but don't stop the process. */
+	/**	brasero_process_deferred_error (process,
+						g_error_new (BRASERO_BURN_ERROR,
+							     BRASERO_BURN_ERROR_MEDIUM_INVALID,
+							     _("The disc is already burnt")));
+	}
+	else if (strstr (line, "Cannot blank disk, aborting.") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_INVALID,
+						_("The disc could not be blanked")));
+	}
+	else if (strstr (line, "Bad audio track size")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("The audio tracks are too short or not a multiple of 2352")));
+	}
+	else if (strstr (line, "cdrecord: No such file or directory. Cannot open")
+	     ||  strstr (line, "No tracks specified. Need at least one.")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_INPUT,
+						_("The image file cannot be found")));
+	}
+	else if (strstr (line, "Inappropriate audio coding")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_INPUT_INVALID,
+						_("All audio files must be stereo, 16-bit digital audio with 44100Hz samples")));
+	}
+	else if (strstr (line, "No disk / Wrong disk!") != NULL) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIA_NONE,
+						_("There seems to be no disc in the drive")));
+	}
+
+	**/
+
+	/** For these we'd rather have a message saying "cdrecord failed"
+	 *  as an internal error occured says nothing/even less
+	else if (strstr (line, "Bad file descriptor. read error on input file")
+	     ||  strstr (line, "Input buffer error, aborting")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("An internal error occured")));
+	}
+
+	**/
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_cdrecord_compute (BraseroCDRecord *cdrecord,
+			  gint mb_written,
+			  gint mb_total,
+			  gint track_num)
+{
+	gboolean track_num_changed = FALSE;
+	BraseroCDRecordPrivate *priv;
+	gchar *action_string;
+	gint64 this_remain;
+	gint64 bytes;
+	gint64 total;
+
+	priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+	if (mb_total <= 0)
+		return;
+
+	total = mb_total * 1048576;
+
+	if (track_num > priv->current_track_num) {
+		track_num_changed = TRUE;
+		priv->current_track_num = track_num;
+		priv->current_track_end_pos += mb_total * 1048576;
+	}
+
+	this_remain = (mb_total - mb_written) * 1048576;
+	bytes = (total - priv->current_track_end_pos) + this_remain;
+	brasero_job_set_written_session (BRASERO_JOB (cdrecord), total - bytes);
+
+	action_string = g_strdup_printf ("Writing track %02i", track_num);
+	brasero_job_set_current_action (BRASERO_JOB (cdrecord),
+					BRASERO_BURN_ACTION_RECORDING,
+					action_string,
+					track_num_changed);
+	g_free (action_string);
+}
+
+static BraseroBurnResult
+brasero_cdrecord_stdout_read (BraseroProcess *process, const gchar *line)
+{
+	guint track;
+	guint speed_1, speed_2;
+	BraseroCDRecord *cdrecord;
+	BraseroCDRecordPrivate *priv;
+	int mb_written = 0, mb_total = 0, fifo = 0, buf = 0;
+
+	cdrecord = BRASERO_CD_RECORD (process);
+	priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+	if (sscanf (line, "Track %2u: %d of %d MB written (fifo %d%%) [buf %d%%] %d.%dx.",
+		    &track, &mb_written, &mb_total, &fifo, &buf, &speed_1, &speed_2) == 7) {
+		gdouble current_rate;
+
+		current_rate = (gdouble) ((gdouble) speed_1 +
+			       (gdouble) speed_2 / 10.0) *
+			       (gdouble) CD_RATE;
+		brasero_job_set_rate (BRASERO_JOB (cdrecord), current_rate);
+
+		priv->current_track_written = mb_written * 1048576;
+		brasero_cdrecord_compute (cdrecord,
+					  mb_written,
+					  mb_total,
+					  track);
+
+		brasero_job_start_progress (BRASERO_JOB (cdrecord), FALSE);
+	} 
+	else if (sscanf (line, "Track %2u:    %d MB written (fifo %d%%) [buf  %d%%]  %d.%dx.",
+			 &track, &mb_written, &fifo, &buf, &speed_1, &speed_2) == 6) {
+		gdouble current_rate;
+
+		/* this line is printed when cdrecord writes on the fly */
+		current_rate = (gdouble) ((gdouble) speed_1 +
+			       (gdouble) speed_2 / 10.0) *
+			       (gdouble) CD_RATE;
+		brasero_job_set_rate (BRASERO_JOB (cdrecord), current_rate);
+
+		priv->current_track_written = mb_written * 1048576;
+		if (brasero_job_get_fd_in (BRASERO_JOB (cdrecord), NULL) == BRASERO_BURN_OK) {
+			guint64 bytes = 0;
+
+			/* we must ask the imager what is the total size */
+			brasero_job_get_session_output_size (BRASERO_JOB (cdrecord),
+							     NULL,
+							     &bytes);
+			mb_total = bytes / 1048576;
+			brasero_cdrecord_compute (cdrecord,
+						  mb_written,
+						  mb_total,
+						  track);
+		}
+
+		brasero_job_start_progress (BRASERO_JOB (cdrecord), FALSE);
+	}
+	else if (sscanf (line, "Track %*d: %*s %d MB ", &mb_total) == 1) {
+/*		if (mb_total > 0)
+			priv->tracks_total_bytes += mb_total * 1048576;
+*/	}
+	else if (strstr (line, "Formatting media")) {
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_BLANKING,
+						_("Formatting disc"),
+						FALSE);
+	}
+	else if (strstr (line, "Sending CUE sheet")) {
+		BraseroTrackType *type = NULL;
+
+		/* See if we are in an audio case which would mean we're writing
+		 * CD-TEXT */
+		type = brasero_track_type_new ();
+		brasero_job_get_input_type (BRASERO_JOB (cdrecord), type);
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_RECORDING_CD_TEXT,
+						brasero_track_type_get_has_stream (type) ? NULL:_("Writing cue sheet"),
+						FALSE);
+		brasero_track_type_free (type);
+	}
+	else if (g_str_has_prefix (line, "Re-load disk and hit <CR>")
+	     ||  g_str_has_prefix (line, "send SIGUSR1 to continue")) {
+		BraseroBurnAction action = BRASERO_BURN_ACTION_NONE;
+
+		brasero_job_get_current_action (BRASERO_JOB (process), &action);
+
+		/* NOTE: There seems to be a BUG somewhere when writing raw images
+		 * with clone mode. After disc has been written and fixated cdrecord
+		 * asks the media to be reloaded. So we simply ignore this message
+		 * and returns that everything went well. Which is indeed the case */
+		if (action == BRASERO_BURN_ACTION_FIXATING) {
+			brasero_job_finished_session (BRASERO_JOB (process));
+			return BRASERO_BURN_OK;
+		}
+
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_NEED_RELOADING,
+						_("The disc needs to be reloaded before being recorded")));
+	}
+	else if (g_str_has_prefix (line, "Fixating...")
+	     ||  g_str_has_prefix (line, "Writing Leadout...")) {
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_FIXATING,
+						NULL,
+						FALSE);
+	}
+	else if (g_str_has_prefix (line, "Last chance to quit, ")) {
+		brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+	}
+	else if (g_str_has_prefix (line, "Blanking PMA, TOC, pregap")
+	     ||  strstr (line, "Blanking entire disk")) {
+
+	}
+	/* This should not happen */
+	/* else if (strstr (line, "Use tsize= option in SAO mode to specify track size")) */
+
+	return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_cdrecord_write_inf (BraseroCDRecord *cdrecord,
+			    GPtrArray *argv,
+			    BraseroTrack *track,
+			    const gchar *tmpdir,
+			    const gchar *album,
+			    gint index,
+			    gint start,
+			    gboolean last_track,
+			    GError **error)
+{
+	gint fd;
+	int isrc;
+        int errsv;
+	gint size;
+	gchar *path;
+	guint64 length;
+	gchar *string;
+	gint b_written;
+	gint64 sectors;
+	const gchar *info;
+	gchar buffer [128];
+	BraseroCDRecordPrivate *priv;
+
+	priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+	/* NOTE: about the .inf files: they should have the exact same path
+	 * but the ending suffix file is replaced by inf:
+	 * example : /path/to/file.mp3 => /path/to/file.inf */
+	if (brasero_job_get_fd_in (BRASERO_JOB (cdrecord), NULL) != BRASERO_BURN_OK) {
+		gchar *dot, *separator;
+
+		path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+
+		dot = strrchr (path, '.');
+		separator = strrchr (path, G_DIR_SEPARATOR);
+
+		if (dot && dot > separator)
+			path = g_strdup_printf ("%.*s.inf",
+						dot - path,
+						path);
+		else
+			path = g_strdup_printf ("%s.inf",
+						path);
+
+		/* since this file was not returned by brasero_job_get_tmp_file
+		 * it won't be erased when session is unrefed so we have to do 
+		 * it ourselves */
+		priv->infs = g_slist_prepend (priv->infs, g_strdup (path));
+	}
+	else {
+		BraseroBurnResult result;
+
+		/* in this case don't care about the name since stdin is used */
+		result = brasero_job_get_tmp_file (BRASERO_JOB (cdrecord),
+						   ".inf",
+						   &path,
+						   error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+
+	fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+	if (fd < 0)
+		goto error;
+
+	BRASERO_JOB_LOG (cdrecord, "writing inf (%s)", path);
+
+	/* The problem here is that when writing CD-TEXT from .inf files, wodim
+	 * uses only one charset (and don't let us specify which one) which is
+	 * ISO-8859-1. (NOTE: don't believe the doc claiming it requires ASCII
+	 * and see cdrecord/cdtext.c line 309).
+	 * So we have to convert our UTF-8 input into such a charset.
+	 * NOTE: according to docs ASCII should be used for text packs other
+	 * than disc/track title.
+	 * It might be good in the end to write and pack CD-TEXT pack data 
+	 * ourselves so we can set a different charset from English like 
+	 * Chinese for example. */
+	strcpy (buffer, "# created by brasero\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "MCN=\t\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	/* ISRC */
+	isrc = brasero_track_tag_lookup_int (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ISRC_TAG);
+	if (isrc > 0)
+		string = g_strdup_printf ("ISRC=\t%i\n", isrc);
+	else
+		string = g_strdup ("ISRC=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Albumperformer=\t\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	if (album) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (album,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Albumtitle=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Albumtitle=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	/* ARTIST */
+	info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+						BRASERO_TRACK_STREAM_ARTIST_TAG);
+	if (info) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (info,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Performer=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Performer=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	/* COMPOSER */
+	info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+						BRASERO_TRACK_STREAM_COMPOSER_TAG);
+	if (info) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (info,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Composer=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Composer=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	/* TITLE */
+	info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+						BRASERO_TRACK_STREAM_TITLE_TAG);
+	if (info) {
+		gchar *encoded;
+
+		encoded = g_convert_with_fallback (info,
+						   -1,
+						   "ISO-8859-1",
+						   "UTF-8",
+						   "_",	/* Fallback for non convertible characters */
+						   NULL,
+						   NULL,
+						   NULL);
+		string = g_strdup_printf ("Tracktitle=\t%s\n", encoded);
+		g_free (encoded);
+	}
+	else
+		string = strdup ("Tracktitle=\t\n");
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	string = g_strdup_printf ("Tracknumber=\t%i\n", index);
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	string = g_strdup_printf ("Trackstart=\t%i\n", start);
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	length = 0;
+	brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
+	sectors = BRASERO_DURATION_TO_SECTORS (length);
+
+	BRASERO_JOB_LOG (cdrecord, "got track length %lli", length);
+	string = g_strdup_printf ("Tracklength=\t%"G_GINT64_FORMAT", 0\n", sectors);
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Pre-emphasis=\tno\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Channels=\t2\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Copy_permitted=\tyes\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Endianess=\tlittle\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	strcpy (buffer, "Index=\t\t0\n");
+	size = strlen (buffer);
+	b_written = write (fd, buffer, size);
+	if (b_written != size)
+		goto error;
+
+	/* NOTE: -1 here means no pregap */
+	if (!last_track) {
+		/* K3b does this (possibly to remove silence) */
+		string = g_strdup_printf ("Index0=\t\t%"G_GINT64_FORMAT"\n",
+					  sectors - 150);
+	}
+	else
+		string = g_strdup_printf ("Index0=\t\t-1\n");
+
+	size = strlen (string);
+	b_written = write (fd, string, size);
+	g_free (string);
+	if (b_written != size)
+		goto error;
+
+	close (fd);
+
+	if (argv)
+		g_ptr_array_add (argv, path);
+	else
+		g_free (path);
+
+	return BRASERO_BURN_OK;
+
+
+error:
+        errsv = errno;
+
+	g_remove (path);
+	g_free (path);
+
+	g_set_error (error,
+		     BRASERO_BURN_ERROR,
+		     BRASERO_BURN_ERROR_GENERAL,
+		     _("An internal error occured (%s)"), 
+		     g_strerror (errsv));
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_write_infs (BraseroCDRecord *cdrecord,
+			     GPtrArray *argv,
+			     GError **error)
+{
+	BraseroCDRecordPrivate *priv;
+	BraseroBurnResult result;
+	gchar *tmpdir = NULL;
+	GSList *tracks;
+	GSList *iter;
+	gchar *album;
+	gint index;
+	gint start;
+
+	priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+	brasero_job_get_audio_title (BRASERO_JOB (cdrecord), &album);
+	brasero_job_get_tracks (BRASERO_JOB (cdrecord), &tracks);
+	index = 1;
+	start = 0;
+
+	for (iter = tracks; iter; iter = iter->next) {
+		guint64 sectors;
+		BraseroTrack *track;
+
+		track = iter->data;
+		result = brasero_cdrecord_write_inf (cdrecord,
+						     argv,
+						     track,
+						     tmpdir,
+						     album,
+						     index,
+						     start,
+						     (iter->next == NULL),
+						     error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		index ++;
+		sectors = 0;
+
+		brasero_track_get_size (track, &sectors, NULL);
+		start += sectors;
+	}
+
+	g_free (album);
+	g_free (tmpdir);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_set_argv_record (BraseroCDRecord *cdrecord,
+				  GPtrArray *argv, 
+				  GError **error)
+{
+	guint speed;
+	BraseroBurnFlag flags;
+	BraseroCDRecordPrivate *priv;
+	BraseroTrackType *type = NULL;
+
+	priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+	if (priv->immediate) {
+		g_ptr_array_add (argv, g_strdup ("-immed"));
+		g_ptr_array_add (argv, g_strdup_printf ("minbuf=%i", priv->minbuf));
+	}
+
+	if (brasero_job_get_speed (BRASERO_JOB (cdrecord), &speed) == BRASERO_BURN_OK) {
+		gchar *speed_str;
+
+		speed_str = g_strdup_printf ("speed=%d", speed);
+		g_ptr_array_add (argv, speed_str);
+	}
+
+	brasero_job_get_flags (BRASERO_JOB (cdrecord), &flags);
+	if (flags & BRASERO_BURN_FLAG_OVERBURN)
+		g_ptr_array_add (argv, g_strdup ("-overburn"));
+	if (flags & BRASERO_BURN_FLAG_BURNPROOF)
+		g_ptr_array_add (argv, g_strdup ("driveropts=burnfree"));
+	if (flags & BRASERO_BURN_FLAG_MULTI)
+		g_ptr_array_add (argv, g_strdup ("-multi"));
+
+	/* NOTE: This write mode is necessary for all CLONE images burning */
+	if (flags & BRASERO_BURN_FLAG_RAW)
+		g_ptr_array_add (argv, g_strdup ("-raw96r"));
+
+	/* NOTE1: DAO can't be used if we're appending to a disc */
+	/* NOTE2: CD-text cannot be written in tao mode (which is the default)
+	 * NOTE3: when we don't want wodim to use stdin then we give the audio
+	 * file on the command line. Otherwise we use the .inf */
+	if (flags & BRASERO_BURN_FLAG_DAO)
+		g_ptr_array_add (argv, g_strdup ("-dao"));
+
+	type = brasero_track_type_new ();
+	brasero_job_get_input_type (BRASERO_JOB (cdrecord), type);
+
+	if (brasero_job_get_fd_in (BRASERO_JOB (cdrecord), NULL) == BRASERO_BURN_OK) {
+		BraseroBurnResult result;
+		int buffer_size;
+		guint64 sectors;
+		
+		/* we need to know what is the type of the track (audio / data) */
+		result = brasero_job_get_input_type (BRASERO_JOB (cdrecord), type);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (type);
+
+			BRASERO_JOB_LOG (cdrecord, "Imager doesn't seem to be ready")
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("An internal error occured"));
+			return BRASERO_BURN_ERR;
+		}
+		
+		/* ask the size */
+		result = brasero_job_get_session_output_size (BRASERO_JOB (cdrecord),
+							      &sectors,
+							      NULL);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (type);
+
+			BRASERO_JOB_LOG (cdrecord, "The size of the session cannot be retrieved")
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("An internal error occured"));
+			return BRASERO_BURN_ERR;
+		}
+
+		/* we create a buffer depending on the size 
+		 * buffer 4m> < 64m and is 1/25th of size otherwise */
+		buffer_size = sectors * 2352 / 1024 / 1024 / 25;
+		if (buffer_size > 32)
+			buffer_size = 32;
+		else if (buffer_size < 4)
+			buffer_size = 4;
+
+		g_ptr_array_add (argv, g_strdup_printf ("fs=%im", buffer_size));
+		if (brasero_track_type_get_has_image (type)) {
+			BraseroImageFormat format;
+
+			format = brasero_track_type_get_image_format (type);
+			if (format == BRASERO_IMAGE_FORMAT_BIN) {
+				g_ptr_array_add (argv, g_strdup_printf ("tsize=%Lis", sectors));
+				g_ptr_array_add (argv, g_strdup ("-data"));
+				g_ptr_array_add (argv, g_strdup ("-nopad"));
+				g_ptr_array_add (argv, g_strdup ("-"));
+			}
+			else {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+			}
+		}
+		else if (brasero_track_type_get_has_stream (type)) {
+			g_ptr_array_add (argv, g_strdup ("-swab"));
+			g_ptr_array_add (argv, g_strdup ("-audio"));
+			g_ptr_array_add (argv, g_strdup ("-useinfo"));
+			g_ptr_array_add (argv, g_strdup ("-text"));
+
+			result = brasero_cdrecord_write_infs (cdrecord,
+							      argv,
+							      error);
+			if (result != BRASERO_BURN_OK) {
+				brasero_track_type_free (type);
+				return result;
+			}
+		}
+		else {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+		}
+	}
+	else if (brasero_track_type_get_has_stream (type)) {
+		BraseroBurnResult result;
+		GSList *tracks;
+
+		g_ptr_array_add (argv, g_strdup ("fs=16m"));
+		g_ptr_array_add (argv, g_strdup ("-audio"));
+		g_ptr_array_add (argv, g_strdup ("-swab"));
+		g_ptr_array_add (argv, g_strdup ("-pad"));
+	
+		g_ptr_array_add (argv, g_strdup ("-useinfo"));
+		g_ptr_array_add (argv, g_strdup ("-text"));
+
+		result = brasero_cdrecord_write_infs (cdrecord,
+						      NULL,
+						      error);
+		if (result != BRASERO_BURN_OK) {
+			brasero_track_type_free (type);
+			return result;
+		}
+
+		tracks = NULL;
+		brasero_job_get_tracks (BRASERO_JOB (cdrecord), &tracks);
+		for (; tracks; tracks = tracks->next) {
+			BraseroTrack *track;
+			gchar *path;
+
+			track = tracks->data;
+			path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+			g_ptr_array_add (argv, path);
+		}
+	}
+	else if (brasero_track_type_get_has_image (type)) {
+		BraseroTrack *track = NULL;
+		BraseroImageFormat format;
+
+		brasero_job_get_current_track (BRASERO_JOB (cdrecord), &track);
+		if (!track) {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_READY (cdrecord);
+		}
+
+		format = brasero_track_type_get_image_format (type);
+		if (format == BRASERO_IMAGE_FORMAT_NONE) {
+			gchar *image_path;
+
+			image_path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!image_path) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (cdrecord);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+			g_ptr_array_add (argv, g_strdup ("-data"));
+			g_ptr_array_add (argv, g_strdup ("-nopad"));
+			g_ptr_array_add (argv, image_path);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+			gchar *isopath;
+
+			isopath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!isopath) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (cdrecord);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+			g_ptr_array_add (argv, g_strdup ("-data"));
+			g_ptr_array_add (argv, g_strdup ("-nopad"));
+			g_ptr_array_add (argv, isopath);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+			gchar *rawpath;
+
+			rawpath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!rawpath) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (cdrecord);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+			g_ptr_array_add (argv, g_strdup ("-clone"));
+			g_ptr_array_add (argv, rawpath);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_CUE) {
+			gchar *cue_str;
+			gchar *cuepath;
+
+			cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			if (!cuepath) {
+				brasero_track_type_free (type);
+				BRASERO_JOB_NOT_READY (cdrecord);
+			}
+
+			g_ptr_array_add (argv, g_strdup ("fs=16m"));
+
+			cue_str = g_strdup_printf ("cuefile=%s", cuepath);
+			g_ptr_array_add (argv, cue_str);
+			g_free (cuepath);
+		}
+		else {
+			brasero_track_type_free (type);
+			BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+		}
+	}
+	else {
+		brasero_track_type_free (type);
+		BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+	}
+
+	brasero_track_type_free (type);
+
+	brasero_job_set_current_action (BRASERO_JOB (cdrecord),
+					BRASERO_BURN_ACTION_START_RECORDING,
+					NULL,
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_set_argv_blank (BraseroCDRecord *cdrecord, GPtrArray *argv)
+{
+	gchar *blank_str;
+	BraseroBurnFlag flags;
+
+	brasero_job_get_flags (BRASERO_JOB (cdrecord), &flags);
+	blank_str = g_strdup_printf ("blank=%s",
+				    (flags & BRASERO_BURN_FLAG_FAST_BLANK) ? "fast" : "all");
+	g_ptr_array_add (argv, blank_str);
+
+	brasero_job_set_current_action (BRASERO_JOB (cdrecord),
+					BRASERO_BURN_ACTION_BLANKING,
+					NULL,
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_set_argv (BraseroProcess *process,
+			   GPtrArray *argv,
+			   GError **error)
+{
+	BraseroCDRecordPrivate *priv;
+	BraseroCDRecord *cdrecord;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroBurnFlag flags;
+	gchar *dev_str;
+	gchar *device;
+
+	cdrecord = BRASERO_CD_RECORD (process);
+	priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+	brasero_job_get_action (BRASERO_JOB (cdrecord), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	g_ptr_array_add (argv, g_strdup ("cdrecord"));
+	g_ptr_array_add (argv, g_strdup ("-v"));
+
+#ifdef HAVE_CAM_LIB_H
+	/* FreeBSD like that better */
+	brasero_job_get_bus_target_lun (BRASERO_JOB (cdrecord), &device);
+#else
+	brasero_job_get_device (BRASERO_JOB (cdrecord), &device);
+#endif
+
+	dev_str = g_strdup_printf ("dev=%s", device);
+	g_ptr_array_add (argv, dev_str);
+	g_free (device);
+
+	brasero_job_get_flags (BRASERO_JOB (cdrecord), &flags);
+        if (flags & BRASERO_BURN_FLAG_DUMMY)
+		g_ptr_array_add (argv, g_strdup ("-dummy"));
+
+	if (flags & BRASERO_BURN_FLAG_NOGRACE)
+		g_ptr_array_add (argv, g_strdup ("gracetime=0"));
+
+	if (action == BRASERO_JOB_ACTION_RECORD)
+		result = brasero_cdrecord_set_argv_record (cdrecord, argv, error);
+	else if (action == BRASERO_JOB_ACTION_ERASE)
+		result = brasero_cdrecord_set_argv_blank (cdrecord, argv);
+	else
+		BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+
+	return result;	
+}
+
+static BraseroBurnResult
+brasero_cdrecord_post (BraseroJob *job)
+{
+	BraseroCDRecordPrivate *priv;
+	GSList *iter;
+
+	priv = BRASERO_CD_RECORD_PRIVATE (job);
+	for (iter = priv->infs; iter; iter = iter->next) {
+		gchar *path;
+
+		path = iter->data;
+		g_remove (path);
+		g_free (path);
+	}
+
+	g_slist_free (priv->infs);
+	priv->infs = NULL;
+
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_cdrecord_class_init (BraseroCDRecordClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroCDRecordPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_cdrecord_finalize;
+
+	process_class->stderr_func = brasero_cdrecord_stderr_read;
+	process_class->stdout_func = brasero_cdrecord_stdout_read;
+	process_class->set_argv = brasero_cdrecord_set_argv;
+	process_class->post = brasero_cdrecord_post;
+}
+
+static void
+brasero_cdrecord_init (BraseroCDRecord *obj)
+{
+	GConfClient *client;
+	BraseroCDRecordPrivate *priv;
+
+	/* load our "configuration" */
+	priv = BRASERO_CD_RECORD_PRIVATE (obj);
+
+	client = gconf_client_get_default ();
+	priv->immediate = gconf_client_get_bool (client,
+						 GCONF_KEY_IMMEDIATE_FLAG,
+						 NULL);
+	priv->minbuf = gconf_client_get_int (client,
+					     GCONF_KEY_MINBUF_VALUE,
+					     NULL);
+	if (priv->minbuf > 95 || priv->minbuf < 25)
+		priv->minbuf = 30;
+
+	g_object_unref (client);
+}
+
+static void
+brasero_cdrecord_finalize (GObject *object)
+{
+	BraseroCDRecordPrivate *priv;
+	GSList *iter;
+
+	priv = BRASERO_CD_RECORD_PRIVATE (object);
+
+	for (iter = priv->infs; iter; iter = iter->next) {
+		gchar *path;
+
+		path = iter->data;
+		g_remove (path);
+		g_free (path);
+	}
+
+	g_slist_free (priv->infs);
+	priv->infs = NULL;
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_cdrecord_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroPluginConfOption *immed, *minbuf;
+	const BraseroMedia media = BRASERO_MEDIUM_CD|
+				   BRASERO_MEDIUM_WRITABLE|
+				   BRASERO_MEDIUM_REWRITABLE|
+				   BRASERO_MEDIUM_BLANK|
+				   BRASERO_MEDIUM_APPENDABLE|
+				   BRASERO_MEDIUM_HAS_AUDIO|
+				   BRASERO_MEDIUM_HAS_DATA;
+	const BraseroMedia dvd_media = BRASERO_MEDIUM_DVD|
+				       BRASERO_MEDIUM_PLUS|
+				       BRASERO_MEDIUM_SEQUENTIAL|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_BLANK|
+				       BRASERO_MEDIUM_UNFORMATTED|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_HAS_DATA;
+	const BraseroMedia media_rw = BRASERO_MEDIUM_CD|
+				      BRASERO_MEDIUM_REWRITABLE|
+				      BRASERO_MEDIUM_APPENDABLE|
+				      BRASERO_MEDIUM_CLOSED|
+				      BRASERO_MEDIUM_HAS_AUDIO|
+				      BRASERO_MEDIUM_HAS_DATA|
+				      BRASERO_MEDIUM_BLANK;
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	/* NOTE: it seems that cdrecord can burn cue files on the fly */
+	brasero_plugin_define (plugin,
+			       "cdrecord",
+			       _("Use cdrecord to burn CDs and DVDs"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("cdrecord", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* for recording */
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_BIN);
+
+	/* cdrecord can burn all DVDs (except restricted) when it's ISOs */
+	output = brasero_caps_disc_new (dvd_media);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	/* All CD-R(W) */
+	output = brasero_caps_disc_new (media);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_METADATA_INFO);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* for CLONE and CUE type images, we only want blank CD-R(W) */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+					BRASERO_MEDIUM_WRITABLE|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_BLANK);
+
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_CUE|
+					BRASERO_IMAGE_FORMAT_CLONE);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* Blank CD(R)W : don't use standard flags cdrecord fails consistently
+	 * to write a first track of a multisession disc with DAO mode. */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CD|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_DAO|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CD|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_MULTI|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* Apart from DAO it also supports RAW mode to burn CLONE images. This
+	 * is a special mode for which there isn't any DUMMY burn possible */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CD|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_RAW|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* This is a CDR with data data can be merged or at least appended */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CD|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_AUDIO|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_MULTI|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_APPEND);
+
+	/* It is a CDRW we want the CD to be either blanked before or appended
+	 * that's why we set MERGE as compulsory. That way if the CD is not
+	 * MERGED we force the blank before writing to avoid appending sessions
+	 * endlessly until there is no free space. */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CD|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_AUDIO|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_MULTI|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_MERGE);
+
+	/* DVD-RW cdrecord capabilites are limited to blank media.
+	 * It should not start a multisession disc. */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVD|
+				  BRASERO_MEDIUM_SEQUENTIAL|
+				  BRASERO_MEDIUM_WRITABLE|
+				  BRASERO_MEDIUM_REWRITABLE|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_DAO|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_DUMMY|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* DVD+W cdrecord capabilities are limited to blank media */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDR_PLUS|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_DAO|
+				  BRASERO_BURN_FLAG_BURNPROOF|
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* for DVD+RW cdrecord capabilities are limited no MERGE */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_UNFORMATTED|
+				  BRASERO_MEDIUM_BLANK,
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_OVERBURN|
+				  BRASERO_BURN_FLAG_NOGRACE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* blanking/formatting caps and flags for +/sequential RW
+	 * NOTE: restricted overwrite DVD-RW can't be formatted.
+	 * moreover DVD+RW are formatted while DVD-RW sequential are blanked.
+	 */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_APPENDABLE|
+	    				BRASERO_MEDIUM_SEQUENTIAL|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+	    				BRASERO_MEDIUM_DVDRW |
+	    				BRASERO_MEDIUM_BLANK|
+	    				BRASERO_MEDIUM_CLOSED |
+	    				BRASERO_MEDIUM_APPENDABLE|
+	    				BRASERO_MEDIUM_HAS_DATA|
+	    				BRASERO_MEDIUM_UNFORMATTED,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+	/* again DVD+RW don't support dummy */
+	brasero_plugin_set_blank_flags (plugin,
+					BRASERO_MEDIUM_DVDRW_PLUS|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK|
+					BRASERO_MEDIUM_CLOSED,
+					BRASERO_BURN_FLAG_NOGRACE,
+					BRASERO_BURN_FLAG_NONE);
+
+	/* for blanking (CDRWs) */
+	output = brasero_caps_disc_new (media_rw);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+					media_rw,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	/* add some configure options */
+	immed = brasero_plugin_conf_option_new (GCONF_KEY_IMMEDIATE_FLAG,
+						_("Enable \"-immed\" flag (see cdrecord manual)"),
+						BRASERO_PLUGIN_OPTION_BOOL);
+	minbuf = brasero_plugin_conf_option_new (GCONF_KEY_MINBUF_VALUE,
+						 _("Minimum drive buffer fill ratio (in %%)(see cdrecord manual):"),
+						 BRASERO_PLUGIN_OPTION_INT);
+	brasero_plugin_conf_option_int_set_range (minbuf, 25, 95);
+
+	brasero_plugin_conf_option_bool_add_suboption (immed, minbuf);
+	brasero_plugin_add_conf_option (plugin, immed);
+
+	brasero_plugin_register_group (plugin, _(CDRTOOLS_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrtools/burn-cdrecord.h b/plugins/cdrtools/burn-cdrecord.h
new file mode 100644
index 0000000..3c9719e
--- /dev/null
+++ b/plugins/cdrtools/burn-cdrecord.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            cdrecord.h
+ *
+ *  dim jan 22 15:22:52 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef CDRECORD_H
+#define CDRECORD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CD_RECORD         (brasero_cdrecord_get_type ())
+#define BRASERO_CD_RECORD(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CD_RECORD, BraseroCDRecord))
+#define BRASERO_CD_RECORD_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CD_RECORD, BraseroCDRecordClass))
+#define BRASERO_IS_CD_RECORD(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CD_RECORD))
+#define BRASERO_IS_CD_RECORD_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CD_RECORD))
+#define BRASERO_CD_RECORD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CD_RECORD, BraseroCDRecordClass))
+
+G_END_DECLS
+
+#endif /* CDRECORD_H */
diff --git a/plugins/cdrtools/burn-cdrtools.h b/plugins/cdrtools/burn-cdrtools.h
new file mode 100644
index 0000000..a21abb4
--- /dev/null
+++ b/plugins/cdrtools/burn-cdrtools.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *            burn-cdrtools.h
+ *
+ *  Mon Oct 29 12:27:57 2007
+ *  Copyright  2007  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef _BURN_CDRTOOLS_H
+#define _BURN_CDRTOOLS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CDRTOOLS_DESCRIPTION		N_("Cdrtools burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_CDRTOOLS_H */
+
+ 
diff --git a/plugins/cdrtools/burn-mkisofs.c b/plugins/cdrtools/burn-mkisofs.c
new file mode 100644
index 0000000..2d2b146
--- /dev/null
+++ b/plugins/cdrtools/burn-mkisofs.c
@@ -0,0 +1,586 @@
+/***************************************************************************
+ *            mkisofs.c
+ *
+ *  dim jan 22 15:20:57 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-debug.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrtools.h"
+#include "burn-mkisofs.h"
+#include "brasero-track-data.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroMkisofs, brasero_mkisofs, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroMkisofsPrivate {
+	guint use_utf8:1;
+};
+typedef struct _BraseroMkisofsPrivate BraseroMkisofsPrivate;
+
+#define BRASERO_MKISOFS_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_MKISOFS, BraseroMkisofsPrivate))
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_mkisofs_read_isosize (BraseroProcess *process, const gchar *line)
+{
+	gint64 sectors;
+
+	sectors = strtoll (line, NULL, 10);
+	if (!sectors)
+		return BRASERO_BURN_OK;
+
+	/* mkisofs reports blocks of 2048 bytes */
+	brasero_job_set_output_size_for_current_track (BRASERO_JOB (process),
+						       sectors,
+						       sectors * 2048ULL);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_read_stdout (BraseroProcess *process, const gchar *line)
+{
+	BraseroJobAction action;
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		return brasero_mkisofs_read_isosize (process, line);
+
+	return TRUE;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	gchar fraction_str [7] = { 0, };
+	BraseroMkisofs *mkisofs;
+	BraseroMkisofsPrivate *priv;
+
+	mkisofs = BRASERO_MKISOFS (process);
+	priv = BRASERO_MKISOFS_PRIVATE (process);
+
+	if (strstr (line, "estimate finish")
+	&&  sscanf (line, "%6c%% done, estimate finish", fraction_str) == 1) {
+		gdouble fraction;
+	
+		fraction = g_strtod (fraction_str, NULL) / (gdouble) 100.0;
+		brasero_job_set_progress (BRASERO_JOB (mkisofs), fraction);
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+	}
+	else if (strstr (line, "Input/output error. Read error on old image")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+							_("Last session import failed")));
+	}
+	else if (strstr (line, "Unable to sort directory")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_WRITE_IMAGE,
+							_("An image could not be created")));
+	}
+	else if (strstr (line, "have the same joliet name")
+	     ||  strstr (line, "Joliet tree sort failed.")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_IMAGE_JOLIET,
+							_("An image could not be created")));
+	}
+	else if (strstr (line, "Use mkisofs -help")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_GENERAL,
+							_("This version of mkisofs is not supported")));
+	}
+/*	else if ((pos =  strstr (line,"mkisofs: Permission denied. "))) {
+		int res = FALSE;
+		gboolean isdir = FALSE;
+		char *path = NULL;
+
+		pos += strlen ("mkisofs: Permission denied. ");
+		if (!strncmp (pos, "Unable to open directory ", 24)) {
+			isdir = TRUE;
+
+			pos += strlen ("Unable to open directory ");
+			path = g_strdup (pos);
+			path[strlen (path) - 1] = 0;
+		}
+		else if (!strncmp (pos, "File ", 5)) {
+			char *end;
+
+			isdir = FALSE;
+			pos += strlen ("File ");
+			end = strstr (pos, " is not readable - ignoring");
+			if (end)
+				path = g_strndup (pos, end - pos);
+		}
+		else
+			return TRUE;
+
+		res = brasero_mkisofs_base_ask_unreadable_file (BRASERO_GENISOIMAGE_BASE (process),
+								path,
+								isdir);
+		if (!res) {
+			g_free (path);
+
+			brasero_job_progress_changed (BRASERO_JOB (process), 1.0, -1);
+			brasero_job_cancel (BRASERO_JOB (process), FALSE);
+			return FALSE;
+		}
+	}*/
+	else if (strstr (line, "Incorrectly encoded string")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT_INVALID,
+							_("Some files have invalid filenames")));
+	}
+	else if (strstr (line, "Unknown charset")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT_INVALID,
+							_("Unknown character encoding")));
+	}
+	else if (strstr (line, "No space left on device")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_DISK_SPACE,
+							_("There is no space left on the device")));
+
+	}
+	else if (strstr (line, "Unable to open disc image file")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_PERMISSION,
+							_("You do not have the required permission to write at this location")));
+
+	}
+	else if (strstr (line, "Value too large for defined data type")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_MEDIUM_SPACE,
+							_("Not enough space available on the disc")));
+	}
+
+	/** REMINDER: these should not be necessary
+
+	else if (strstr (line, "Resource temporarily unavailable")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT,
+							_("Data could not be written")));
+	}
+	else if (strstr (line, "Bad file descriptor.")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT,
+							_("Internal error: bad file descriptor")));
+	}
+
+	**/
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_set_argv_image (BraseroMkisofs *mkisofs,
+				GPtrArray *argv,
+				GError **error)
+{
+	gchar *label = NULL;
+	BraseroTrack *track;
+	BraseroBurnFlag flags;
+	gchar *videodir = NULL;
+	gchar *emptydir = NULL;
+	BraseroJobAction action;
+	BraseroImageFS image_fs;
+	BraseroBurnResult result;
+	gchar *grafts_path = NULL;
+	gchar *excluded_path = NULL;
+
+	/* set argv */
+	g_ptr_array_add (argv, g_strdup ("-r"));
+
+	result = brasero_job_get_current_track (BRASERO_JOB (mkisofs), &track);
+	if (result != BRASERO_BURN_OK)
+		BRASERO_JOB_NOT_READY (mkisofs);
+
+	image_fs = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+	if (image_fs & BRASERO_IMAGE_FS_JOLIET)
+		g_ptr_array_add (argv, g_strdup ("-J"));
+
+	if ((image_fs & BRASERO_IMAGE_FS_ISO)
+	&&  (image_fs & BRASERO_IMAGE_ISO_FS_LEVEL_3)) {
+		g_ptr_array_add (argv, g_strdup ("-iso-level"));
+		g_ptr_array_add (argv, g_strdup ("3"));
+	}
+
+	if (image_fs & BRASERO_IMAGE_FS_UDF)
+		g_ptr_array_add (argv, g_strdup ("-udf"));
+
+	if (image_fs & BRASERO_IMAGE_FS_VIDEO) {
+		g_ptr_array_add (argv, g_strdup ("-dvd-video"));
+
+		result = brasero_job_get_tmp_dir (BRASERO_JOB (mkisofs),
+						  &videodir,
+						  error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-graft-points"));
+
+	if (image_fs & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY)
+		g_ptr_array_add (argv, g_strdup ("-D"));	// This is dangerous the manual says but apparently it works well
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (mkisofs),
+					   NULL,
+					   &grafts_path,
+					   error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		return result;
+	}
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (mkisofs),
+					   NULL,
+					   &excluded_path,
+					   error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (grafts_path);
+		g_free (videodir);
+		return result;
+	}
+
+	result = brasero_job_get_tmp_dir (BRASERO_JOB (mkisofs),
+					  &emptydir,
+					  error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		g_free (excluded_path);
+		return result;
+	}
+
+	result = brasero_track_data_get_paths (BRASERO_TRACK_DATA (track),
+					       (image_fs & BRASERO_IMAGE_FS_JOLIET) != 0,
+					       grafts_path,
+					       excluded_path,
+					       emptydir,
+					       videodir,
+					       error);
+	g_free (emptydir);
+
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		g_free (excluded_path);
+		return result;
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-path-list"));
+	g_ptr_array_add (argv, grafts_path);
+
+	g_ptr_array_add (argv, g_strdup ("-exclude-list"));
+	g_ptr_array_add (argv, excluded_path);
+
+	brasero_job_get_data_label (BRASERO_JOB (mkisofs), &label);
+	if (label) {
+		g_ptr_array_add (argv, g_strdup ("-V"));
+		g_ptr_array_add (argv, label);
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-A"));
+	g_ptr_array_add (argv, g_strdup_printf ("Brasero-%i.%i.%i",
+						BRASERO_MAJOR_VERSION,
+						BRASERO_MINOR_VERSION,
+						BRASERO_SUB));
+	
+	g_ptr_array_add (argv, g_strdup ("-sysid"));
+#if defined(HAVE_STRUCT_USCSI_CMD)
+	g_ptr_array_add (argv, g_strdup ("SOLARIS"));
+#else
+	g_ptr_array_add (argv, g_strdup ("LINUX"));
+#endif
+	
+	/* FIXME! -sort is an interesting option allowing to decide where the 
+	* files are written on the disc and therefore to optimize later reading */
+	/* FIXME: -hidden --hidden-list -hide-jolie -hide-joliet-list will allow to hide
+	* some files when we will display the contents of a disc we will want to merge */
+	/* FIXME: support preparer publisher options */
+
+	brasero_job_get_flags (BRASERO_JOB (mkisofs), &flags);
+	if (flags & (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE)) {
+		guint64 last_session = 0, next_wr_add = 0;
+		gchar *startpoint = NULL;
+
+		brasero_job_get_last_session_address (BRASERO_JOB (mkisofs), &last_session);
+		brasero_job_get_next_writable_address (BRASERO_JOB (mkisofs), &next_wr_add);
+		if (last_session == -1 || next_wr_add == -1) {
+			g_free (videodir);
+			BRASERO_JOB_LOG (mkisofs, "Failed to get the start point of the track. Make sure the media allow to add files (it is not closed)"); 
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("An internal error occured"));
+			return BRASERO_BURN_ERR;
+		}
+
+		startpoint = g_strdup_printf ("%"G_GINT64_FORMAT",%"G_GINT64_FORMAT,
+					      last_session,
+					      next_wr_add);
+
+		g_ptr_array_add (argv, g_strdup ("-C"));
+		g_ptr_array_add (argv, startpoint);
+
+		if (flags & BRASERO_BURN_FLAG_MERGE) {
+		        gchar *device = NULL;
+
+			g_ptr_array_add (argv, g_strdup ("-M"));
+
+#ifdef HAVE_CAM_LIB_H
+	/* FreeBSD like that better */
+			brasero_job_get_bus_target_lun (BRASERO_JOB (mkisofs), &device);
+#else
+			brasero_job_get_device (BRASERO_JOB (mkisofs), &device);
+#endif
+
+			g_ptr_array_add (argv, device);
+		}
+	}
+
+	brasero_job_get_action (BRASERO_JOB (mkisofs), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		g_ptr_array_add (argv, g_strdup ("-quiet"));
+		g_ptr_array_add (argv, g_strdup ("-print-size"));
+
+		brasero_job_set_current_action (BRASERO_JOB (mkisofs),
+						BRASERO_BURN_ACTION_GETTING_SIZE,
+						NULL,
+						FALSE);
+		brasero_job_start_progress (BRASERO_JOB (mkisofs), FALSE);
+
+		if (videodir) {
+			g_ptr_array_add (argv, g_strdup ("-f"));
+			g_ptr_array_add (argv, videodir);
+		}
+
+		return BRASERO_BURN_OK;
+	}
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (mkisofs), NULL) != BRASERO_BURN_OK) {
+		gchar *output = NULL;
+
+		result = brasero_job_get_image_output (BRASERO_JOB (mkisofs),
+						      &output,
+						       NULL);
+		if (result != BRASERO_BURN_OK) {
+			g_free (videodir);
+			return result;
+		}
+
+		g_ptr_array_add (argv, g_strdup ("-o"));
+		g_ptr_array_add (argv, output);
+	}
+
+	if (videodir) {
+		g_ptr_array_add (argv, g_strdup ("-f"));
+		g_ptr_array_add (argv, videodir);
+	}
+
+	brasero_job_set_current_action (BRASERO_JOB (mkisofs),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					NULL,
+					FALSE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_set_argv (BraseroProcess *process,
+			  GPtrArray *argv,
+			  GError **error)
+{
+	gchar *prog_name;
+	BraseroJobAction action;
+	BraseroMkisofs *mkisofs;
+	BraseroBurnResult result;
+	BraseroMkisofsPrivate *priv;
+
+	mkisofs = BRASERO_MKISOFS (process);
+	priv = BRASERO_MKISOFS_PRIVATE (process);
+
+	prog_name = g_find_program_in_path ("mkisofs");
+	if (prog_name && g_file_test (prog_name, G_FILE_TEST_IS_EXECUTABLE))
+		g_ptr_array_add (argv, prog_name);
+	else
+		g_ptr_array_add (argv, g_strdup ("mkisofs"));
+
+	if (priv->use_utf8) {
+		g_ptr_array_add (argv, g_strdup ("-input-charset"));
+		g_ptr_array_add (argv, g_strdup ("utf8"));
+	}
+
+	brasero_job_get_action (BRASERO_JOB (mkisofs), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		result = brasero_mkisofs_set_argv_image (mkisofs, argv, error);
+	else if (action == BRASERO_JOB_ACTION_IMAGE)
+		result = brasero_mkisofs_set_argv_image (mkisofs, argv, error);
+	else
+		BRASERO_JOB_NOT_SUPPORTED (mkisofs);
+
+	return result;
+}
+
+static void
+brasero_mkisofs_class_init (BraseroMkisofsClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroMkisofsPrivate));
+
+	parent_class = g_type_class_peek_parent(klass);
+	object_class->finalize = brasero_mkisofs_finalize;
+
+	process_class->stdout_func = brasero_mkisofs_read_stdout;
+	process_class->stderr_func = brasero_mkisofs_read_stderr;
+	process_class->set_argv = brasero_mkisofs_set_argv;
+}
+
+static void
+brasero_mkisofs_init (BraseroMkisofs *obj)
+{
+	BraseroMkisofsPrivate *priv;
+	gchar *standard_error;
+	gboolean res;
+
+	priv = BRASERO_MKISOFS_PRIVATE (obj);
+
+	/* this code used to be ncb_mkisofs_supports_utf8 */
+	res = g_spawn_command_line_sync ("mkisofs -input-charset utf8",
+					 NULL,
+					 &standard_error,
+					 NULL,
+					 NULL);
+
+	if (res && !g_strrstr (standard_error, "Unknown charset"))
+		priv->use_utf8 = TRUE;
+	else
+		priv->use_utf8 = FALSE;
+
+	g_free (standard_error);
+}
+
+static void
+brasero_mkisofs_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_mkisofs_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "mkisofs",
+			       _("Use mkisofs to create image from a file selection"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("mkisofs", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CDR|
+				  BRASERO_MEDIUM_CDRW|
+				  BRASERO_MEDIUM_DVDR|
+				  BRASERO_MEDIUM_DVDRW|
+				  BRASERO_MEDIUM_DVDR_PLUS|
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_AUDIO|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_RESTRICTED|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	/* Caps */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_IMAGE_FORMAT_BIN);
+
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+				       BRASERO_IMAGE_FS_UDF|
+				       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+				       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+				       BRASERO_IMAGE_FS_JOLIET|
+				       BRASERO_IMAGE_FS_VIDEO);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+				       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+				       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+				       BRASERO_IMAGE_FS_SYMLINK);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	g_slist_free (output);
+
+	brasero_plugin_register_group (plugin, _(CDRTOOLS_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrtools/burn-mkisofs.h b/plugins/cdrtools/burn-mkisofs.h
new file mode 100644
index 0000000..c853f00
--- /dev/null
+++ b/plugins/cdrtools/burn-mkisofs.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *            mkisofs.h
+ *
+ *  dim jan 22 15:20:57 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef MKISOFS_H
+#define MKISOFS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_MKISOFS         (brasero_mkisofs_get_type ())
+#define BRASERO_MKISOFS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_MKISOFS, BraseroMkisofs))
+#define BRASERO_MKISOFS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_MKISOFS, BraseroMkisofsClass))
+#define BRASERO_IS_MKISOFS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_MKISOFS))
+#define BRASERO_IS_MKISOFS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_MKISOFS))
+#define BRASERO_MKISOFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_MKISOFS, BraseroMkisofsClass))
+
+G_END_DECLS
+
+#endif /* MKISOFS_H */
diff --git a/plugins/cdrtools/burn-readcd.c b/plugins/cdrtools/burn-readcd.c
new file mode 100644
index 0000000..072d60c
--- /dev/null
+++ b/plugins/cdrtools/burn-readcd.c
@@ -0,0 +1,496 @@
+/***************************************************************************
+ *            readcd.c
+ *
+ *  dim jan 22 18:06:10 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-cdrtools.h"
+#include "burn-readcd.h"
+#include "burn-process.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "brasero-tags.h"
+#include "brasero-track-disc.h"
+
+#include "burn-volume.h"
+#include "brasero-drive.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroReadcd, brasero_readcd, BRASERO_TYPE_PROCESS, BraseroProcess);
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_readcd_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	BraseroReadcd *readcd;
+	gint dummy1;
+	gint dummy2;
+	gchar *pos;
+
+	readcd = BRASERO_READCD (process);
+
+	if ((pos = strstr (line, "addr:"))) {
+		gint sector;
+		gint64 written;
+		BraseroImageFormat format;
+		BraseroTrackType *output = NULL;
+
+		pos += strlen ("addr:");
+		sector = strtoll (pos, NULL, 10);
+
+		output = brasero_track_type_new ();
+		brasero_job_get_output_type (BRASERO_JOB (readcd), output);
+
+		format = brasero_track_type_get_image_format (output);
+		if (format == BRASERO_IMAGE_FORMAT_BIN)
+			written = (gint64) ((gint64) sector * 2048ULL);
+		else if (format == BRASERO_IMAGE_FORMAT_CLONE)
+			written = (gint64) ((gint64) sector * 2448ULL);
+		else
+			written = (gint64) ((gint64) sector * 2048ULL);
+
+		brasero_track_type_free (output);
+
+		brasero_job_set_written_track (BRASERO_JOB (readcd), written);
+
+		if (sector > 10)
+			brasero_job_start_progress (BRASERO_JOB (readcd), FALSE);
+	}
+	else if ((pos = strstr (line, "Capacity:"))) {
+		brasero_job_set_current_action (BRASERO_JOB (readcd),
+							BRASERO_BURN_ACTION_DRIVE_COPY,
+							NULL,
+							FALSE);
+	}
+	else if (strstr (line, "Device not ready.")) {
+		brasero_job_error (BRASERO_JOB (readcd),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_DRIVE_BUSY,
+						_("The drive is busy")));
+	}
+	else if (strstr (line, "Cannot open SCSI driver.")) {
+		brasero_job_error (BRASERO_JOB (readcd),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));		
+	}
+	else if (strstr (line, "Cannot send SCSI cmd via ioctl")) {
+		brasero_job_error (BRASERO_JOB (readcd),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_PERMISSION,
+						_("You do not have the required permissions to use this drive")));
+	}
+	/* we scan for this error as in this case readcd returns success */
+	else if (sscanf (line, "Input/output error. Error on sector %d not corrected. Total of %d error", &dummy1, &dummy2) == 2) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_GENERAL,
+						_("An internal error occured")));
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readcd_argv_set_iso_boundary (BraseroReadcd *readcd,
+				      GPtrArray *argv,
+				      GError **error)
+{
+	guint64 nb_blocks;
+	BraseroTrack *track;
+	GValue *value = NULL;
+	BraseroTrackType *output = NULL;
+
+	brasero_job_get_current_track (BRASERO_JOB (readcd), &track);
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (readcd), output);
+
+	brasero_track_tag_lookup (track,
+				  BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+				  &value);
+	if (value) {
+		guint64 start, end;
+
+		/* we were given an address to start */
+		start = g_value_get_uint64 (value);
+
+		/* get the length now */
+		value = NULL;
+		brasero_track_tag_lookup (track,
+					  BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+					  &value);
+
+		end = g_value_get_uint64 (value);
+
+		BRASERO_JOB_LOG (readcd,
+				 "reading from sector %lli to %lli",
+				 start,
+				 end);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+							start,
+							end));
+	}
+	/* 0 means all disc, -1 problem */
+	else if (brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track)) > 0) {
+		guint64 start;
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_track_space (medium,
+						brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+						NULL,
+						&nb_blocks);
+		brasero_medium_get_track_address (medium,
+						  brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+						  NULL,
+						  &start);
+
+		BRASERO_JOB_LOG (readcd,
+				 "reading %i from sector %lli to %lli",
+				 brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+				 start,
+				 start + nb_blocks);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+							start,
+							start + nb_blocks));
+	}
+	/* if it's BIN output just read the last track */
+	else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+		guint64 start;
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_last_data_track_space (medium,
+							  NULL,
+							  &nb_blocks);
+		brasero_medium_get_last_data_track_address (medium,
+							    NULL,
+							    &start);
+		BRASERO_JOB_LOG (readcd,
+				 "reading last track from sector %lli to %lli",
+				 start,
+				 start + nb_blocks);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+							start,
+							start + nb_blocks));
+	}
+	else {
+		brasero_track_get_size (track, &nb_blocks, NULL);
+		g_ptr_array_add (argv, g_strdup_printf ("-sectors=0-%lli", nb_blocks));
+	}
+
+	brasero_track_type_free (output);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readcd_get_size (BraseroReadcd *self,
+			 GError **error)
+{
+	guint64 blocks;
+	GValue *value = NULL;
+	BraseroImageFormat format;
+	BraseroTrack *track = NULL;
+	BraseroTrackType *output = NULL;
+
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (self), output);
+
+	if (!brasero_track_type_get_has_image (output)) {
+		brasero_track_type_free (output);
+		return BRASERO_BURN_ERR;
+	}
+
+	brasero_track_type_free (output);
+
+	format = brasero_track_type_get_image_format (output);
+	brasero_track_tag_lookup (track,
+				  BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+				  &value);
+
+	if (value) {
+		guint64 start, end;
+
+		/* we were given an address to start */
+		start = g_value_get_uint64 (value);
+
+		/* get the length now */
+		value = NULL;
+		brasero_track_tag_lookup (track,
+					  BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+					  &value);
+
+		end = g_value_get_uint64 (value);
+		blocks = end - start;
+	}
+	else if (brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)) > 0) {
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_track_space (medium,
+						brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+						NULL,
+						&blocks);
+	}
+	else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+		BraseroDrive *drive;
+		BraseroMedium *medium;
+
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_last_data_track_space (medium,
+							  NULL,
+							  &blocks);
+	}
+	else
+		brasero_track_get_size (track, &blocks, NULL);
+
+	if (format == BRASERO_IMAGE_FORMAT_BIN) {
+		brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+							       blocks,
+							       blocks * 2048ULL);
+	}
+	else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+		brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+							       blocks,
+							       blocks * 2448ULL);
+	}
+	else
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	/* no need to go any further */
+	return BRASERO_BURN_NOT_RUNNING;
+}
+
+static BraseroBurnResult
+brasero_readcd_set_argv (BraseroProcess *process,
+			 GPtrArray *argv,
+			 GError **error)
+{
+	BraseroBurnResult result = FALSE;
+	BraseroTrackType *output = NULL;
+	BraseroImageFormat format;
+	BraseroJobAction action;
+	BraseroReadcd *readcd;
+	BraseroMedium *medium;
+	BraseroTrack *track;
+	BraseroDrive *drive;
+	BraseroMedia media;
+	gchar *outfile_arg;
+	gchar *dev_str;
+	gchar *device;
+
+	readcd = BRASERO_READCD (process);
+
+	/* This is a kind of shortcut */
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		return brasero_readcd_get_size (readcd, error);
+
+	g_ptr_array_add (argv, g_strdup ("readcd"));
+
+	brasero_job_get_current_track (BRASERO_JOB (readcd), &track);
+	drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+#ifdef HAVE_CAM_LIB_H
+	/* FreeBSD like that better */
+	device = brasero_drive_get_bus_target_lun_string (drive);
+#else
+	device = g_strdup (brasero_drive_get_device (drive));
+#endif
+
+	if (!device)
+		return BRASERO_BURN_ERR;
+
+	dev_str = g_strdup_printf ("dev=%s", device);
+	g_ptr_array_add (argv, dev_str);
+	g_free (device);
+
+	g_ptr_array_add (argv, g_strdup ("-nocorr"));
+
+	medium = brasero_drive_get_medium (drive);
+	media = brasero_medium_get_status (medium);
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (readcd), output);
+	format = brasero_track_type_get_image_format (output);
+	brasero_track_type_free (output);
+
+	if ((media & BRASERO_MEDIUM_DVD) && format != BRASERO_IMAGE_FORMAT_BIN) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("An internal error occured"));
+		return BRASERO_BURN_ERR;
+	}
+
+	if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+		/* NOTE: with this option the sector size is 2448 
+		 * because it is raw96 (2352+96) otherwise it is 2048  */
+		g_ptr_array_add (argv, g_strdup ("-clone"));
+	}
+	else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+		g_ptr_array_add (argv, g_strdup ("-noerror"));
+
+		/* don't do it for clone since we need the entire disc */
+		result = brasero_readcd_argv_set_iso_boundary (readcd, argv, error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (readcd);
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (readcd), NULL) != BRASERO_BURN_OK) {
+		gchar *image;
+
+		if (format != BRASERO_IMAGE_FORMAT_CLONE
+		&&  format != BRASERO_IMAGE_FORMAT_BIN)
+			BRASERO_JOB_NOT_SUPPORTED (readcd);
+
+		result = brasero_job_get_image_output (BRASERO_JOB (readcd),
+						       &image,
+						       NULL);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		outfile_arg = g_strdup_printf ("-f=%s", image);
+		g_ptr_array_add (argv, outfile_arg);
+		g_free (image);
+	}
+	else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+		outfile_arg = g_strdup ("-f=-");
+		g_ptr_array_add (argv, outfile_arg);
+	}
+	else 	/* unfortunately raw images can't be piped out */
+		BRASERO_JOB_NOT_SUPPORTED (readcd);
+
+	brasero_job_set_use_average_rate (BRASERO_JOB (process), TRUE);
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_readcd_class_init (BraseroReadcdClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS(klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_readcd_finalize;
+
+	process_class->stderr_func = brasero_readcd_read_stderr;
+	process_class->set_argv = brasero_readcd_set_argv;
+}
+
+static void
+brasero_readcd_init (BraseroReadcd *obj)
+{ }
+
+static void
+brasero_readcd_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_readcd_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "readcd",
+			       _("Use readcd to create disc images"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("readcd", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* that's for clone mode only The only one to copy audio */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_IMAGE_FORMAT_CLONE);
+
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+				       BRASERO_MEDIUM_ROM|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_HAS_AUDIO|
+				       BRASERO_MEDIUM_HAS_DATA);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* that's for regular mode: it accepts the previous type of discs 
+	 * plus the DVDs types as well */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_IMAGE_FORMAT_BIN);
+
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+				       BRASERO_MEDIUM_DVD|
+				       BRASERO_MEDIUM_DUAL_L|
+				       BRASERO_MEDIUM_PLUS|
+				       BRASERO_MEDIUM_SEQUENTIAL|
+				       BRASERO_MEDIUM_RESTRICTED|
+				       BRASERO_MEDIUM_ROM|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_HAS_DATA);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	brasero_plugin_register_group (plugin, _(CDRTOOLS_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrtools/burn-readcd.h b/plugins/cdrtools/burn-readcd.h
new file mode 100644
index 0000000..730d3ae
--- /dev/null
+++ b/plugins/cdrtools/burn-readcd.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *            readcd.h
+ *
+ *  dim jan 22 18:06:10 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef READCD_H
+#define READCD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_READCD         (brasero_readcd_get_type ())
+#define BRASERO_READCD(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_READCD, BraseroReadcd))
+#define BRASERO_READCD_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_READCD, BraseroReadcdClass))
+#define BRASERO_IS_READCD(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_READCD))
+#define BRASERO_IS_READCD_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_READCD))
+#define BRASERO_READCD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_READCD, BraseroReadcdClass))
+
+G_END_DECLS
+
+#endif /* READCD_H */
diff --git a/plugins/checksum/Makefile.am b/plugins/checksum/Makefile.am
new file mode 100644
index 0000000..b3269a3
--- /dev/null
+++ b/plugins/checksum/Makefile.am
@@ -0,0 +1,34 @@
+
+INCLUDES = \
+	-I$(top_srcdir)							\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/				\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_GTK_CFLAGS)				\
+	$(BRASERO_GCONF_CFLAGS)
+
+checksumdir = $(libdir)/brasero/plugins
+checksum_LTLIBRARIES = libbrasero-checksum.la
+libbrasero_checksum_la_SOURCES = burn-checksum-image.c	\
+				 burn-checksum-image.h
+
+libbrasero_checksum_la_LDFLAGS = -module -avoid-version
+libbrasero_checksum_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+
+checksumfiledir = $(libdir)/brasero/plugins
+checksumfile_LTLIBRARIES = libbrasero-checksum-file.la
+libbrasero_checksum_file_la_SOURCES = burn-checksum-files.c	\
+				      burn-checksum-files.h\
+				      burn-volume-read.c  \
+				      burn-volume-read.h
+
+libbrasero_checksum_file_la_LDFLAGS = -module -avoid-version
+libbrasero_checksum_file_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) $(BRASERO_GTK_LIBS) ../../libbrasero-burn/libbrasero-burn.la
diff --git a/plugins/checksum/burn-checksum-files.c b/plugins/checksum/burn-checksum-files.c
new file mode 100644
index 0000000..02a8cd9
--- /dev/null
+++ b/plugins/checksum/burn-checksum-files.c
@@ -0,0 +1,1506 @@
+/***************************************************************************
+ *            burn-sum.c
+ *
+ *  ven aoû  4 19:46:34 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "scsi-device.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-checksum-files.h"
+
+#include "brasero-tags.h"
+#include "brasero-track-data.h"
+#include "brasero-track-disc.h"
+
+#include "burn-volume.h"
+#include "brasero-drive.h"
+#include "brasero-volume.h"
+
+#include "burn-volume-read.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroChecksumFiles, brasero_checksum_files, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroChecksumFilesPrivate {
+	/* the path to read from when we check */
+	gchar *sums_path;
+	BraseroChecksumType checksum_type;
+
+	gint64 file_num;
+
+	/* the FILE to write to when we generate */
+	FILE *file;
+
+	/* this is for the thread and the end of it */
+	GThread *thread;
+	GMutex *mutex;
+	GCond *cond;
+	gint end_id;
+
+	guint cancel;
+};
+typedef struct _BraseroChecksumFilesPrivate BraseroChecksumFilesPrivate;
+
+#define BRASERO_CHECKSUM_FILES_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesPrivate))
+
+#define BLOCK_SIZE			64
+#define GCONF_KEY_CHECKSUM_TYPE		"/apps/brasero/config/checksum_files"
+
+static BraseroJobClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_checksum_files_get_file_checksum (BraseroChecksumFiles *self,
+					  GChecksumType type,
+					  const gchar *path,
+					  gchar **checksum_string,
+					  GError **error)
+{
+	BraseroChecksumFilesPrivate *priv;
+	guchar buffer [BLOCK_SIZE];
+	GChecksum *checksum;
+	gint read_bytes;
+	FILE *file;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	file = fopen (path, "r");
+	if (!file) {
+                int errsv;
+		gchar *name = NULL;
+
+		/* If the file doesn't exist carry on with next */
+		if (errno == ENOENT)
+			return BRASERO_BURN_RETRY;
+
+		name = g_path_get_basename (path);
+
+                errsv = errno;
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("File \"%s\" could not be opened (%s)"),
+			     name,
+			     g_strerror (errsv));
+		g_free (name);
+
+		return BRASERO_BURN_ERR;
+	}
+
+	checksum = g_checksum_new (type);
+
+	read_bytes = fread (buffer, 1, BLOCK_SIZE, file);
+	g_checksum_update (checksum, buffer, read_bytes);
+
+	while (read_bytes == BLOCK_SIZE) {
+		if (priv->cancel) {
+			fclose (file);
+			g_checksum_free (checksum);
+			return BRASERO_BURN_CANCEL;
+		}
+
+		read_bytes = fread (buffer, 1, BLOCK_SIZE, file);
+		g_checksum_update (checksum, buffer, read_bytes);
+	}
+
+	*checksum_string = g_strdup (g_checksum_get_string (checksum));
+	g_checksum_free (checksum);
+	fclose (file);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_add_file_checksum (BraseroChecksumFiles *self,
+					  const gchar *path,
+					  GChecksumType checksum_type,
+					  const gchar *graft_path,
+					  GError **error)
+{
+	BraseroBurnResult result = BRASERO_BURN_OK;
+	BraseroChecksumFilesPrivate *priv;
+	gchar *checksum_string = NULL;
+	gint written;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* write to the file */
+	result = brasero_checksum_files_get_file_checksum (self,
+							   checksum_type,
+							   path,
+							   &checksum_string,
+							   error);
+	if (result != BRASERO_BURN_OK)
+		return BRASERO_BURN_ERR;
+
+	written = fwrite (checksum_string,
+			  strlen (checksum_string),
+			  1,
+			  priv->file);
+	g_free (checksum_string);
+
+	if (written != 1) {
+                int errsv = errno;
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Data could not be written (%s)"),
+			     g_strerror (errsv));
+			
+		return BRASERO_BURN_ERR;
+	}
+
+	written = fwrite ("  ",
+			  2,
+			  1,
+			  priv->file);
+
+	/* NOTE: we remove the first "/" from path so the file can be
+	 * used with md5sum at the root of the disc once mounted */
+	written = fwrite (graft_path + 1,
+			  strlen (graft_path + 1),
+			  1,
+			  priv->file);
+
+	if (written != 1) {
+                int errsv = errno;
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Data could not be written (%s)"),
+			     g_strerror (errsv));
+
+		return BRASERO_BURN_ERR;
+	}
+
+	written = fwrite ("\n",
+			  1,
+			  1,
+			  priv->file);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_explore_directory (BraseroChecksumFiles *self,
+					  GChecksumType checksum_type,
+					  gint64 file_nb,
+					  const gchar *directory,
+					  const gchar *disc_path,
+					  GHashTable *excludedH,
+					  GError **error)
+{
+	BraseroBurnResult result = BRASERO_BURN_OK;
+	BraseroChecksumFilesPrivate *priv;
+	const gchar *name;
+	GDir *dir;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	dir = g_dir_open (directory, 0, error);
+	if (!dir || *error)
+		return BRASERO_BURN_ERR;
+
+	while ((name = g_dir_read_name (dir))) {
+		gchar *path;
+		gchar *graft_path;
+
+		if (priv->cancel) {
+			result = BRASERO_BURN_CANCEL;
+			break;
+		}
+
+		path = g_build_path (G_DIR_SEPARATOR_S, directory, name, NULL);
+		if (g_hash_table_lookup (excludedH, path)) {
+			g_free (path);
+			continue;
+		}
+
+		graft_path = g_build_path (G_DIR_SEPARATOR_S, disc_path, name, NULL);
+		if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
+			result = brasero_checksum_files_explore_directory (self,
+									   checksum_type,
+									   file_nb,
+									   path,
+									   graft_path,
+									   excludedH,
+									   error);
+			g_free (path);
+			g_free (graft_path);
+
+			if (result != BRASERO_BURN_OK)
+				break;
+
+			continue;
+		}
+
+		/* Only checksum regular files and avoid fifos, ... */
+		if (!g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
+			g_free (path);
+			g_free (graft_path);
+			continue;
+		}
+
+		result = brasero_checksum_files_add_file_checksum (self,
+								   path,
+								   checksum_type,
+								   graft_path,
+								   error);
+		g_free (graft_path);
+		g_free (path);
+
+		if (result != BRASERO_BURN_OK)
+			break;
+
+		priv->file_num ++;
+		brasero_job_set_progress (BRASERO_JOB (self),
+					  (gdouble) priv->file_num /
+					  (gdouble) file_nb);
+	}
+	g_dir_close (dir);
+
+	/* NOTE: we don't care if the file is twice or more on the disc,
+	 * that would be too much overhead/memory consumption for something
+	 * that scarcely happens and that way each file can be checked later*/
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_file_process_former_line (BraseroChecksumFiles *self,
+					   BraseroTrack *track,
+					   const gchar *line,
+					   GError **error)
+{
+	guint i;
+	gchar *path;
+	GSList *grafts;
+	guint written_bytes;
+	BraseroChecksumFilesPrivate *priv;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* first skip the checksum string */
+	i = 0;
+	while (!isspace (line [i])) i ++;
+
+	/* skip white spaces */
+	while (isspace (line [i])) i ++;
+
+	/* get the path string */
+	path = g_strdup (line + i);
+
+	for (grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track)); grafts; grafts = grafts->next) {
+		BraseroGraftPt *graft;
+		guint len;
+
+		/* NOTE: graft->path + 1 is because in the checksum files on the 
+		 * disc there is not first "/" so if we want to compare ... */
+		graft = grafts->data;
+		if (!strcmp (graft->path + 1, path)) {
+			g_free (path);
+			return BRASERO_BURN_OK;
+		}
+
+		len = strlen (graft->path + 1);
+		if (!strncmp (graft->path + 1, path, len)
+		&&   path [len] == G_DIR_SEPARATOR) {
+			g_free (path);
+			return BRASERO_BURN_OK;
+		}
+	}
+
+	g_free (path);
+
+	/* write the whole line in the new file */
+	written_bytes = fwrite (line, 1, strlen (line), priv->file);
+	if (written_bytes != strlen (line)) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     "%s",
+			     g_strerror (errno));
+		return BRASERO_BURN_ERR;
+	}
+
+	if (!fwrite ("\n", 1, 1, priv->file)) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     "%s",
+			     g_strerror (errno));
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_merge_with_former_session (BraseroChecksumFiles *self,
+						  GError **error)
+{
+	BraseroBurnFlag flags = BRASERO_BURN_FLAG_NONE;
+	BraseroChecksumFilesPrivate *priv;
+	BraseroDeviceHandle *dev_handle;
+	BraseroVolFileHandle *handle;
+	BraseroBurnResult result;
+	BraseroVolFile *file;
+	BraseroTrack *track;
+	gchar buffer [2048];
+	BraseroVolSrc *vol;
+	guint64 start_block;
+	gchar *device;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* Now we need to know if we're merging. If so, we need to merge the
+	 * former checksum file with the new ones. */
+	brasero_job_get_flags (BRASERO_JOB (self), &flags);
+	if (!(flags & BRASERO_BURN_FLAG_MERGE))
+		return BRASERO_BURN_OK;
+
+	/* get the former file */
+	result = brasero_job_get_last_session_address (BRASERO_JOB (self), &start_block);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* try every file and make sure they are of the same type */
+	brasero_job_get_device (BRASERO_JOB (self), &device);
+	dev_handle = brasero_device_handle_open (device, FALSE, NULL);
+	g_free (device);
+
+	vol = brasero_volume_source_open_device_handle (dev_handle, error);
+	file = brasero_volume_get_file (vol,
+					"/"BRASERO_MD5_FILE,
+					start_block,
+					NULL);
+
+	if (!file) {
+		file = brasero_volume_get_file (vol,
+						"/"BRASERO_SHA1_FILE,
+						start_block,
+						NULL);
+		if (!file) {
+			file = brasero_volume_get_file (vol,
+							"/"BRASERO_SHA256_FILE,
+							start_block,
+							NULL);
+			if (!file) {
+				brasero_volume_source_close (vol);
+				BRASERO_JOB_LOG (self, "no checksum file found");
+				return BRASERO_BURN_OK;
+			}
+			else if (priv->checksum_type != BRASERO_CHECKSUM_SHA256_FILE) {
+				brasero_volume_source_close (vol);
+				BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
+						 priv->checksum_type,
+						 BRASERO_CHECKSUM_SHA256_FILE);
+				return BRASERO_BURN_OK;
+			}
+		}
+		else if (priv->checksum_type != BRASERO_CHECKSUM_SHA1_FILE) {
+			BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
+					 priv->checksum_type,
+					 BRASERO_CHECKSUM_SHA1_FILE);
+			brasero_volume_source_close (vol);
+			return BRASERO_BURN_OK;
+		}
+	}
+	else if (priv->checksum_type != BRASERO_CHECKSUM_MD5_FILE) {
+		brasero_volume_source_close (vol);
+		BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
+				 priv->checksum_type,
+				 BRASERO_CHECKSUM_MD5_FILE);
+		return BRASERO_BURN_OK;
+	}
+
+	BRASERO_JOB_LOG (self, "Found file %p", file);
+	handle = brasero_volume_file_open (vol, file);
+	brasero_volume_source_close (vol);
+
+	if (!handle) {
+		BRASERO_JOB_LOG (self, "Failed to open file");
+		brasero_device_handle_close (dev_handle);
+		brasero_volume_file_free (file);
+		return BRASERO_BURN_ERR;
+	}
+
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+	/* Now check the files that have been replaced; to do that check the 
+	 * paths of the new image whenever a read path from former file is a
+	 * child of one of the new paths, then it must not be included. */
+	result = brasero_volume_file_read_line (handle, buffer, sizeof (buffer));
+	while (result == BRASERO_BURN_RETRY) {
+		if (priv->cancel) {
+			brasero_volume_file_close (handle);
+			brasero_volume_file_free (file);
+			brasero_device_handle_close (dev_handle);
+			return BRASERO_BURN_CANCEL;
+		}
+
+		result = brasero_checksum_file_process_former_line (self,
+								    track,
+								    buffer,
+								    error);
+		if (result != BRASERO_BURN_OK) {
+			brasero_volume_file_close (handle);
+			brasero_volume_file_free (file);
+			brasero_device_handle_close (dev_handle);
+			return result;
+		}
+
+		result = brasero_volume_file_read_line (handle, buffer, sizeof (buffer));
+	}
+
+	result = brasero_checksum_file_process_former_line (self, track, buffer, error);
+	brasero_volume_file_close (handle);
+	brasero_volume_file_free (file);
+	brasero_device_handle_close (dev_handle);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_create_checksum (BraseroChecksumFiles *self,
+					GError **error)
+{
+	GSList *iter;
+	guint64 file_nb;
+	BraseroTrack *track;
+	GConfClient *client;
+	GHashTable *excludedH;
+	GChecksumType gchecksum_type;
+	BraseroChecksumFilesPrivate *priv;
+	BraseroChecksumType checksum_type;
+	BraseroBurnResult result = BRASERO_BURN_OK;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* get the checksum type */
+	client = gconf_client_get_default ();
+	checksum_type = gconf_client_get_int (client, GCONF_KEY_CHECKSUM_TYPE, NULL);
+	g_object_unref (client);
+
+	if (checksum_type == BRASERO_CHECKSUM_NONE)
+		gchecksum_type = G_CHECKSUM_MD5;
+	else if (checksum_type & BRASERO_CHECKSUM_MD5_FILE)
+		gchecksum_type = G_CHECKSUM_MD5;
+	else if (checksum_type & BRASERO_CHECKSUM_SHA1_FILE)
+		gchecksum_type = G_CHECKSUM_SHA1;
+	else if (checksum_type & BRASERO_CHECKSUM_SHA256_FILE)
+		gchecksum_type = G_CHECKSUM_SHA256;
+	else
+		gchecksum_type = G_CHECKSUM_MD5;
+
+	/* opens a file for the sums */
+	switch (gchecksum_type) {
+	case G_CHECKSUM_MD5:
+		priv->checksum_type = BRASERO_CHECKSUM_MD5_FILE;
+		result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+						   ".md5",
+						   &priv->sums_path,
+						   error);
+		break;
+	case G_CHECKSUM_SHA1:
+		priv->checksum_type = BRASERO_CHECKSUM_SHA1_FILE;
+		result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+						   ".sha1",
+						   &priv->sums_path,
+						   error);
+		break;
+	case G_CHECKSUM_SHA256:
+		priv->checksum_type = BRASERO_CHECKSUM_SHA256_FILE;
+		result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+						   ".sha256",
+						   &priv->sums_path,
+						   error);
+		break;
+	default:
+		result = BRASERO_BURN_CANCEL;
+		break;
+	}
+
+	if (result != BRASERO_BURN_OK || !priv->sums_path)
+		return result;
+
+	priv->file = fopen (priv->sums_path, "w");
+	if (!priv->file) {
+                int errsv = errno;
+
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("File \"%s\" could not be opened (%s)"),
+			     priv->sums_path,
+			     g_strerror (errsv));
+
+		return BRASERO_BURN_ERR;
+	}
+
+	if (brasero_job_get_current_track (BRASERO_JOB (self), &track) != BRASERO_BURN_OK) 
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	/* we fill a hash table with all the files that are excluded globally */
+	excludedH = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	iter = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (track), FALSE);
+	for (; iter; iter = iter->next) {
+		gchar *uri;
+		gchar *path;
+
+		/* get the path */
+		uri = iter->data;
+		path = g_filename_from_uri (uri, NULL, NULL);
+
+		if (path)
+			g_hash_table_insert (excludedH, path, path);
+	}
+
+	/* it's now time to start reporting our progress */
+	brasero_job_set_current_action (BRASERO_JOB (self),
+				        BRASERO_BURN_ACTION_CHECKSUM,
+					_("Creating checksum for image files"),
+					TRUE);
+
+	file_nb = -1;
+	priv->file_num = 0;
+	brasero_track_data_get_file_num (BRASERO_TRACK_DATA (track), &file_nb);
+	if (file_nb > 0)
+		brasero_job_start_progress (BRASERO_JOB (self), TRUE);
+	else
+		file_nb = -1;
+
+	iter = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+	for (; iter; iter = iter->next) {
+		BraseroGraftPt *graft;
+		gchar *graft_path;
+		gchar *path;
+
+		if (priv->cancel) {
+			result = BRASERO_BURN_CANCEL;
+			break;
+		}
+
+		graft = iter->data;
+		if (!graft->uri)
+			continue;
+
+		/* get the current and future paths */
+		/* FIXME: graft->uri can be path or URIs ... This should be
+		 * fixed for graft points. */
+		if (!graft->uri)
+			path = NULL;
+		else if (graft->uri [0] == '/')
+			path = g_strdup (graft->uri);
+		else if (g_str_has_prefix (graft->uri, "file://"))
+			path = g_filename_from_uri (graft->uri, NULL, NULL);
+		else
+			path = NULL;
+
+		graft_path = graft->path;
+
+		if (g_file_test (path, G_FILE_TEST_IS_DIR))
+			result = brasero_checksum_files_explore_directory (self,
+									   gchecksum_type,
+									   file_nb,
+									   path,
+									   graft_path,
+									   excludedH,
+									   error);
+		else {
+			result = brasero_checksum_files_add_file_checksum (self,
+									   path,
+									   gchecksum_type,
+									   graft_path,
+									   error);
+			priv->file_num ++;
+			brasero_job_set_progress (BRASERO_JOB (self),
+						  (gdouble) priv->file_num /
+						  (gdouble) file_nb);
+		}
+
+		g_free (path);
+		if (result != BRASERO_BURN_OK)
+			break;
+	}
+
+	g_hash_table_destroy (excludedH);
+
+	if (result == BRASERO_BURN_OK)
+		result = brasero_checksum_files_merge_with_former_session (self, error);
+
+	/* that's finished we close the file */
+	fclose (priv->file);
+	priv->file = NULL;
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_sum_on_disc_file (BraseroChecksumFiles *self,
+					 GChecksumType type,
+					 BraseroVolSrc *src,
+					 BraseroVolFile *file,
+					 gchar **checksum_string,
+					 GError **error)
+{
+	guchar buffer [64 * 2048];
+	BraseroChecksumFilesPrivate *priv;
+	BraseroVolFileHandle *handle;
+	GChecksum *checksum;
+	gint read_bytes;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	handle = brasero_volume_file_open_direct (src, file);
+	if (!handle)
+		return BRASERO_BURN_ERR;
+
+	checksum = g_checksum_new (type);
+
+	read_bytes = brasero_volume_file_read_direct (handle,
+						      buffer,
+						      64);
+	g_checksum_update (checksum, buffer, read_bytes);
+
+	while (read_bytes == sizeof (buffer)) {
+		if (priv->cancel) {
+			brasero_volume_file_close (handle);
+			return BRASERO_BURN_CANCEL;
+		}
+
+		read_bytes = brasero_volume_file_read_direct (handle,
+							      buffer,
+							      64);
+		g_checksum_update (checksum, buffer, read_bytes);
+	}
+
+	*checksum_string = g_strdup (g_checksum_get_string (checksum));
+	g_checksum_free (checksum);
+
+	brasero_volume_file_close (handle);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroVolFile *
+brasero_checksum_files_get_on_disc_checksum_type (BraseroChecksumFiles *self,
+						  BraseroVolSrc *vol,
+						  guint start_block)
+{
+	BraseroVolFile *file;
+	BraseroChecksumFilesPrivate *priv;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+
+	file = brasero_volume_get_file (vol,
+					"/"BRASERO_MD5_FILE,
+					start_block,
+					NULL);
+
+	if (!file) {
+		file = brasero_volume_get_file (vol,
+						"/"BRASERO_SHA1_FILE,
+						start_block,
+						NULL);
+		if (!file) {
+			file = brasero_volume_get_file (vol,
+							"/"BRASERO_SHA256_FILE,
+							start_block,
+							NULL);
+			if (!file || !(priv->checksum_type & (BRASERO_CHECKSUM_SHA256_FILE|BRASERO_CHECKSUM_DETECT))) {
+				BRASERO_JOB_LOG (self, "no checksum file found");
+				if (file)
+					brasero_volume_file_free (file);
+
+				return NULL;
+			}
+			priv->checksum_type = BRASERO_CHECKSUM_SHA256_FILE;
+		}
+		else if (priv->checksum_type & (BRASERO_CHECKSUM_SHA1_FILE|BRASERO_CHECKSUM_DETECT))
+			priv->checksum_type = BRASERO_CHECKSUM_SHA1_FILE;
+		else {
+			brasero_volume_file_free (file);
+			file = NULL;
+		}
+	}
+	else if (priv->checksum_type & (BRASERO_CHECKSUM_MD5_FILE|BRASERO_CHECKSUM_DETECT))
+		priv->checksum_type = BRASERO_CHECKSUM_MD5_FILE;
+	else {
+		brasero_volume_file_free (file);
+		file = NULL;
+	}
+
+	BRASERO_JOB_LOG (self, "Found file %p", file);
+	return file;
+}
+
+static gint
+brasero_checksum_files_get_line_num (BraseroChecksumFiles *self,
+				     BraseroVolFileHandle *handle)
+{
+	BraseroBurnResult result;
+	int num = 0;
+
+	while ((result = brasero_volume_file_read_line (handle, NULL, 0)) == BRASERO_BURN_RETRY)
+		num ++;
+
+	if (result == BRASERO_BURN_ERR)
+		return -1;
+
+	brasero_volume_file_rewind (handle);
+	return num;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_check_files (BraseroChecksumFiles *self,
+				    GError **error)
+{
+	GValue *value;
+	guint file_nb;
+	guint file_num;
+	gint checksum_len;
+	BraseroVolSrc *vol;
+	guint64 start_block;
+	BraseroTrack *track;
+	const gchar *device;
+	BraseroVolFile *file;
+	BraseroDrive *drive;
+	BraseroMedium *medium;
+	BraseroVolFileHandle *handle;
+	GChecksumType gchecksum_type;
+	GArray *wrong_checksums = NULL;
+	BraseroDeviceHandle *dev_handle;
+	BraseroChecksumFilesPrivate *priv;
+	BraseroBurnResult result = BRASERO_BURN_OK;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* get medium */
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+	medium = brasero_drive_get_medium (drive);
+
+	/* open volume */
+	if (!brasero_medium_get_last_data_track_address (medium, NULL, &start_block))
+		return BRASERO_BURN_ERR;
+
+	device = brasero_drive_get_device (brasero_medium_get_drive (medium));
+	dev_handle = brasero_device_handle_open (device, FALSE, NULL);
+	vol = brasero_volume_source_open_device_handle (dev_handle, error);
+
+	/* open checksum file */
+	file = brasero_checksum_files_get_on_disc_checksum_type (self,
+								 vol,
+								 start_block);
+	if (!file) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("No checksum file could be found on the disc"));
+
+		BRASERO_JOB_LOG (self, "No checksum file");
+		result = BRASERO_BURN_ERR;
+		goto end;
+	}
+
+	handle = brasero_volume_file_open (vol, file);
+	if (!handle) {
+		BRASERO_JOB_LOG (self, "Cannot open checksum file");
+		/* FIXME: error here ? */
+		result = BRASERO_BURN_ERR;
+		goto end;
+	}
+
+	/* get the number of files at this time and rewind */
+	file_nb = brasero_checksum_files_get_line_num (self, handle);
+	if (file_nb == 0) {
+		BRASERO_JOB_LOG (self, "Empty checksum file");
+		result = BRASERO_BURN_OK;
+		goto end;
+	}
+
+	if (file_nb < 0) {
+		/* An error here */
+		BRASERO_JOB_LOG (self, "Failed to retrieve the number of lines");
+		result = BRASERO_BURN_ERR;
+		goto end;
+	}
+
+	/* signal we're ready to start */
+	file_num = 0;
+	brasero_job_set_current_action (BRASERO_JOB (self),
+				        BRASERO_BURN_ACTION_CHECKSUM,
+					_("Checking file integrity"),
+					TRUE);
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+	/* Get the checksum type */
+	switch (priv->checksum_type) {
+	case BRASERO_CHECKSUM_MD5_FILE:
+		gchecksum_type = G_CHECKSUM_MD5;
+		break;
+	case BRASERO_CHECKSUM_SHA1_FILE:
+		gchecksum_type = G_CHECKSUM_SHA1;
+		break;
+	case BRASERO_CHECKSUM_SHA256_FILE:
+		gchecksum_type = G_CHECKSUM_SHA256;
+		break;
+	default:
+		gchecksum_type = G_CHECKSUM_MD5;
+		break;
+	}
+
+	checksum_len = g_checksum_type_get_length (gchecksum_type) * 2;
+	while (1) {
+		gchar file_path [MAXPATHLEN + 1];
+		gchar checksum_file [512 + 1];
+		BraseroVolFile *disc_file;
+		gchar *checksum_real;
+		gint read_bytes;
+
+		if (priv->cancel)
+			break;
+
+		/* first read the checksum */
+		read_bytes = brasero_volume_file_read (handle,
+						       checksum_file,
+						       checksum_len);
+		if (read_bytes == 0)
+			break;
+
+		if (read_bytes != checksum_len) {
+			/* FIXME: an error here */
+			BRASERO_JOB_LOG (self, "Impossible to read the checksum from file");
+			result = BRASERO_BURN_ERR;
+			break;
+		}
+		checksum_file [checksum_len] = '\0';
+
+		if (priv->cancel)
+			break;
+
+		/* skip spaces in between */
+		while (1) {
+			gchar c [2];
+
+			read_bytes = brasero_volume_file_read (handle, c, 1);
+			if (read_bytes == 0) {
+				result = BRASERO_BURN_OK;
+				goto end;
+			}
+
+			if (read_bytes < 0) {
+				/* FIXME: an error here */
+				BRASERO_JOB_LOG (self, "Impossible to read checksum file");
+				result = BRASERO_BURN_ERR;
+				goto end;
+			}
+
+			if (!isspace (c [0])) {
+				file_path [0] = '/';
+				file_path [1] = c [0];
+				break;
+			}
+		}
+
+		/* get the filename */
+		result = brasero_volume_file_read_line (handle, file_path + 2, sizeof (file_path) - 2);
+
+		/* FIXME: an error here */
+		if (result == BRASERO_BURN_ERR) {
+			BRASERO_JOB_LOG (self, "Impossible to read checksum file");
+			break;
+		}
+
+		checksum_real = NULL;
+
+		/* get the file handle itself */
+		BRASERO_JOB_LOG (self, "Getting file %s", file_path);
+		disc_file = brasero_volume_get_file (vol,
+						     file_path,
+						     start_block,
+						     NULL);
+		if (!disc_file) {
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("File \"%s\" could not be opened"),
+				     file_path);
+			result = BRASERO_BURN_ERR;
+			break;
+		}
+
+		/* we certainly don't want to checksum anything but regular file
+		 * if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+		 *	brasero_volume_file_free (disc_file);
+		 *	continue;
+		 * }
+		 */
+
+		/* checksum the file */
+		result = brasero_checksum_files_sum_on_disc_file (self,
+								  gchecksum_type,
+								  vol,
+								  disc_file,
+								  &checksum_real,
+								  error);
+		brasero_volume_file_free (disc_file);
+		if (result == BRASERO_BURN_ERR) {
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("File \"%s\" could not be opened"),
+				     file_path);
+			break;
+		}
+
+		if (result != BRASERO_BURN_OK)
+			break;
+
+		file_num++;
+		brasero_job_set_progress (BRASERO_JOB (self),
+					  (gdouble) file_num /
+					  (gdouble) file_nb);
+		BRASERO_JOB_LOG (self,
+				 "comparing checksums for file %s : %s (from md5 file) / %s (current)",
+				 file_path, checksum_file, checksum_real);
+
+		if (strcmp (checksum_file, checksum_real)) {
+			gchar *string;
+
+			BRASERO_JOB_LOG (self, "Wrong checksum");
+			if (!wrong_checksums)
+				wrong_checksums = g_array_new (TRUE,
+							       TRUE, 
+							       sizeof (gchar *));
+
+			string = g_strdup (file_path);
+			wrong_checksums = g_array_append_val (wrong_checksums, string);
+		}
+
+		g_free (checksum_real);
+		if (priv->cancel)
+			break;
+	}
+
+end:
+
+	if (handle)
+		brasero_volume_file_close (handle);
+
+	if (file)
+		brasero_volume_file_free (file);
+
+	if (vol)
+		brasero_volume_source_close (vol);
+
+	if (dev_handle)
+		brasero_device_handle_close (dev_handle);
+
+	if (result != BRASERO_BURN_OK) {
+		BRASERO_JOB_LOG (self, "Ended with an error");
+		if (wrong_checksums) {
+			g_strfreev ((gchar **) wrong_checksums->data);
+			g_array_free (wrong_checksums, FALSE);
+		}
+		return result;
+	}
+
+	if (!wrong_checksums)
+		return BRASERO_BURN_OK;
+
+	/* add the tag */
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_STRV);
+	g_value_take_boxed (value, wrong_checksums->data);
+	g_array_free (wrong_checksums, FALSE);
+
+	brasero_track_tag_add (track,
+			       BRASERO_TRACK_MEDIUM_WRONG_CHECKSUM_TAG,
+			       value);
+
+	g_set_error (error,
+		     BRASERO_BURN_ERROR,
+		     BRASERO_BURN_ERROR_BAD_CHECKSUM,
+		     _("Some files may be corrupted on the disc"));
+
+	return BRASERO_BURN_ERR;
+}
+
+struct _BraseroChecksumFilesThreadCtx {
+	BraseroChecksumFiles *sum;
+	BraseroBurnResult result;
+	GError *error;
+};
+typedef struct _BraseroChecksumFilesThreadCtx BraseroChecksumFilesThreadCtx;
+
+static gboolean
+brasero_checksum_files_end (gpointer data)
+{
+	BraseroJobAction action;
+	BraseroChecksumFiles *self;
+	BraseroTrack *current = NULL;
+	BraseroChecksumFilesPrivate *priv;
+	BraseroChecksumFilesThreadCtx *ctx;
+
+	ctx = data;
+	self = ctx->sum;
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* NOTE ctx/data is destroyed in its own callback */
+	priv->end_id = 0;
+
+	if (ctx->result != BRASERO_BURN_OK) {
+		GError *error;
+
+		error = ctx->error;
+		ctx->error = NULL;
+
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	brasero_job_get_action (BRASERO_JOB (self), &action);
+	if (action == BRASERO_JOB_ACTION_CHECKSUM) {
+		/* everything was done in thread */
+		brasero_job_finished_track (BRASERO_JOB (self));
+		return FALSE;
+	}
+
+	/* we were asked to create a checksum. Its type depends on the input */
+	brasero_job_get_current_track (BRASERO_JOB (self), &current);
+
+	/* let's create a new DATA track with the md5 file created */
+	if (BRASERO_IS_TRACK_DATA (current)) {
+		GSList *grafts;
+		GSList *excluded;
+		BraseroGraftPt *graft;
+		GSList *new_grafts = NULL;
+		BraseroTrackData *track = NULL;
+
+		/* for DATA track we add the file to the track */
+		grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
+		for (; grafts; grafts = grafts->next) {
+			graft = grafts->data;
+			graft = brasero_graft_point_copy (graft);
+			new_grafts = g_slist_prepend (new_grafts, graft);
+		}
+
+		graft = g_new0 (BraseroGraftPt, 1);
+		graft->uri = g_strconcat ("file://", priv->sums_path, NULL);
+		switch (priv->checksum_type) {
+		case BRASERO_CHECKSUM_SHA1_FILE:
+			graft->path = g_strdup ("/"BRASERO_SHA1_FILE);
+			break;
+		case BRASERO_CHECKSUM_SHA256_FILE:
+			graft->path = g_strdup ("/"BRASERO_SHA256_FILE);
+			break;
+		case BRASERO_CHECKSUM_MD5_FILE:
+		default:
+			graft->path = g_strdup ("/"BRASERO_MD5_FILE);
+			break;
+		}
+
+		BRASERO_JOB_LOG (self,
+				 "Adding graft for checksum file %s %s",
+				 graft->path,
+				 graft->uri);
+
+		new_grafts = g_slist_prepend (new_grafts, graft);
+		excluded = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), TRUE);
+
+		track = brasero_track_data_new ();
+		brasero_track_data_add_fs (track, brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
+		brasero_track_data_set_source (track, new_grafts, excluded);
+		brasero_track_set_checksum (BRASERO_TRACK (track),
+					    priv->checksum_type,
+					    graft->uri);
+
+		brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
+
+		/* It's good practice to unref the track afterwards as we don't
+		 * need it anymore. BraseroTaskCtx refs it. */
+		g_object_unref (track);
+		
+		brasero_job_finished_track (BRASERO_JOB (self));
+		return FALSE;
+	}
+	else
+		goto error;
+
+	return FALSE;
+
+error:
+{
+	GError *error = NULL;
+
+	error = g_error_new (BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_BAD_CHECKSUM,
+			     _("Some files may be corrupted on the disc"));
+	brasero_job_error (BRASERO_JOB (self), error);
+	return FALSE;
+}
+}
+
+static void
+brasero_checksum_files_destroy (gpointer data)
+{
+	BraseroChecksumFilesThreadCtx *ctx;
+
+	ctx = data;
+	if (ctx->error) {
+		g_error_free (ctx->error);
+		ctx->error = NULL;
+	}
+
+	g_free (ctx);
+}
+
+static gpointer
+brasero_checksum_files_thread (gpointer data)
+{
+	GError *error = NULL;
+	BraseroJobAction action;
+	BraseroChecksumFiles *self;
+	BraseroTrack *current = NULL;
+	BraseroChecksumFilesPrivate *priv;
+	BraseroChecksumFilesThreadCtx *ctx;
+	BraseroBurnResult result = BRASERO_BURN_NOT_SUPPORTED;
+
+	self = BRASERO_CHECKSUM_FILES (data);
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+	/* check DISC types and add checksums for DATA and IMAGE-bin types */
+	brasero_job_get_action (BRASERO_JOB (self), &action);
+	brasero_job_get_current_track (BRASERO_JOB (self), &current);
+	if (action == BRASERO_JOB_ACTION_CHECKSUM) {
+		priv->checksum_type = brasero_track_get_checksum_type (current);
+		if (priv->checksum_type & (BRASERO_CHECKSUM_MD5_FILE|BRASERO_CHECKSUM_SHA1_FILE|BRASERO_CHECKSUM_SHA256_FILE|BRASERO_CHECKSUM_DETECT))
+			result = brasero_checksum_files_check_files (self, &error);
+		else
+			result = BRASERO_BURN_ERR;
+	}
+	else if (action == BRASERO_JOB_ACTION_IMAGE) {
+		if (BRASERO_IS_TRACK_DATA (current))
+			result = brasero_checksum_files_create_checksum (self, &error);
+		else
+			result = BRASERO_BURN_ERR;
+	}
+
+	if (result != BRASERO_BURN_CANCEL) {
+		ctx = g_new0 (BraseroChecksumFilesThreadCtx, 1);
+		ctx->sum = self;
+		ctx->error = error;
+		ctx->result = result;
+		priv->end_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+						brasero_checksum_files_end,
+						ctx,
+						brasero_checksum_files_destroy);
+	}
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	priv->thread = NULL;
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_start (BraseroJob *job,
+			      GError **error)
+{
+	BraseroChecksumFilesPrivate *priv;
+	GError *thread_error = NULL;
+	BraseroJobAction action;
+
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		/* say we won't write to disc */
+		brasero_job_set_output_size_for_current_track (job, 0, 0);
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	/* we start a thread for the exploration of the graft points */
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_checksum_files_thread,
+					BRASERO_CHECKSUM_FILES (job),
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_activate (BraseroJob *job,
+				 GError **error)
+{
+	GSList *grafts;
+	BraseroTrack *track = NULL;
+	BraseroTrackType *output = NULL;
+
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (job, output);
+
+	if (!brasero_track_type_get_has_data (output)) {
+		brasero_track_type_free (output);
+		return BRASERO_BURN_OK;
+	}
+
+	brasero_track_type_free (output);
+
+	/* see that a file with graft "/BRASERO_CHECKSUM_FILE" doesn't already
+	 * exists (possible when doing several copies) or when a simulation 
+	 * already took place before. */
+	brasero_job_get_current_track (job, &track);
+	grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+	for (; grafts; grafts = grafts->next) {
+		BraseroGraftPt *graft;
+
+		graft = grafts->data;
+		if (graft->path) {
+			if (!strcmp (graft->path, "/"BRASERO_MD5_FILE))
+				return BRASERO_BURN_NOT_RUNNING;
+			if (!strcmp (graft->path, "/"BRASERO_SHA1_FILE))
+				return BRASERO_BURN_NOT_RUNNING;
+			if (!strcmp (graft->path, "/"BRASERO_SHA256_FILE))
+				return BRASERO_BURN_NOT_RUNNING;
+		}
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_clock_tick (BraseroJob *job)
+{
+	BraseroChecksumFilesPrivate *priv;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
+
+	/* we'll need that function later. For the moment, when generating a
+	 * file we can't know how many files there are. Just when checking it */
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_stop (BraseroJob *job,
+			     GError **error)
+{
+	BraseroChecksumFilesPrivate *priv;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread) {
+		priv->cancel = 1;
+		g_cond_wait (priv->cond, priv->mutex);
+		priv->cancel = 0;
+		priv->thread = NULL;
+	}
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->end_id) {
+		g_source_remove (priv->end_id);
+		priv->end_id = 0;
+	}
+
+	if (priv->file) {
+		fclose (priv->file);
+		priv->file = NULL;
+	}
+
+	if (priv->sums_path) {
+		g_free (priv->sums_path);
+		priv->sums_path = NULL;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_checksum_files_init (BraseroChecksumFiles *obj)
+{
+	BraseroChecksumFilesPrivate *priv;
+
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (obj);
+
+	priv->mutex = g_mutex_new ();
+	priv->cond = g_cond_new ();
+}
+
+static void
+brasero_checksum_files_finalize (GObject *object)
+{
+	BraseroChecksumFilesPrivate *priv;
+	
+	priv = BRASERO_CHECKSUM_FILES_PRIVATE (object);
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread) {
+		priv->cancel = 1;
+		g_cond_wait (priv->cond, priv->mutex);
+		priv->cancel = 0;
+		priv->thread = NULL;
+	}
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->end_id) {
+		g_source_remove (priv->end_id);
+		priv->end_id = 0;
+	}
+
+	if (priv->file) {
+		fclose (priv->file);
+		priv->file = NULL;
+	}
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cond) {
+		g_cond_free (priv->cond);
+		priv->cond = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_checksum_files_class_init (BraseroChecksumFilesClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroChecksumFilesPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_checksum_files_finalize;
+
+	job_class->activate = brasero_checksum_files_activate;
+	job_class->start = brasero_checksum_files_start;
+	job_class->stop = brasero_checksum_files_stop;
+	job_class->clock_tick = brasero_checksum_files_clock_tick;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	BraseroPluginConfOption *checksum_type;
+
+	brasero_plugin_define (plugin,
+			       /* Translators: this is the name of the plugin
+				* which will be translated only when it needs
+				* displaying. */
+			       N_("File Checksum"),
+			       _("Allows to check file integrities on a disc"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* we can only generate a file for DATA input */
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
+	brasero_plugin_process_caps (plugin, input);
+	g_slist_free (input);
+
+	/* we can run on initial track or later for whatever a DATA track */
+	brasero_plugin_set_process_flags (plugin,
+					  BRASERO_PLUGIN_RUN_PREPROCESSING|
+					  BRASERO_PLUGIN_RUN_BEFORE_TARGET);
+
+	/* For discs, we can only check each files on a disc against an md5sum 
+	 * file (provided we managed to mount the disc).
+	 * NOTE: we can't generate md5 from discs anymore. There are too many
+	 * problems reading straight from the disc dev. So we use readcd or 
+	 * equivalent instead */
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+				       BRASERO_MEDIUM_DVD|
+				       BRASERO_MEDIUM_DUAL_L|
+				       BRASERO_MEDIUM_PLUS|
+				       BRASERO_MEDIUM_RESTRICTED|
+				       BRASERO_MEDIUM_SEQUENTIAL|
+				       BRASERO_MEDIUM_WRITABLE|
+				       BRASERO_MEDIUM_REWRITABLE|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_APPENDABLE|
+				       BRASERO_MEDIUM_HAS_DATA);
+	brasero_plugin_check_caps (plugin,
+				   BRASERO_CHECKSUM_DETECT|				   
+				   BRASERO_CHECKSUM_MD5_FILE|
+				   BRASERO_CHECKSUM_SHA1_FILE|
+				   BRASERO_CHECKSUM_SHA256_FILE,
+				   input);
+	g_slist_free (input);
+
+	/* add some configure options */
+	checksum_type = brasero_plugin_conf_option_new (GCONF_KEY_CHECKSUM_TYPE,
+							_("Hashing algorithm to be used:"),
+							BRASERO_PLUGIN_OPTION_CHOICE);
+	brasero_plugin_conf_option_choice_add (checksum_type,
+					       _("MD5"), BRASERO_CHECKSUM_MD5_FILE);
+	brasero_plugin_conf_option_choice_add (checksum_type,
+					       _("SHA1"), BRASERO_CHECKSUM_SHA1_FILE);
+	brasero_plugin_conf_option_choice_add (checksum_type,
+					       _("SHA256"), BRASERO_CHECKSUM_SHA256_FILE);
+
+	brasero_plugin_add_conf_option (plugin, checksum_type);
+
+	brasero_plugin_set_compulsory (plugin, FALSE);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/checksum/burn-checksum-files.h b/plugins/checksum/burn-checksum-files.h
new file mode 100644
index 0000000..191f346
--- /dev/null
+++ b/plugins/checksum/burn-checksum-files.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            burn-sum.h
+ *
+ *  ven aoû  4 19:46:34 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef BURN_SUM_FILE_H
+#define BURN_SUM_FILE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CHECKSUM_FILES		(brasero_checksum_files_get_type ())
+#define BRASERO_CHECKSUM_FILES(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFiles))
+#define BRASERO_CHECKSUM_FILES_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesClass))
+#define BRASERO_IS_CHECKSUM_FILES(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CHECKSUM_FILES))
+#define BRASERO_IS_CHECKSUM_FILES_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CHECKSUM_FILES))
+#define BRASERO_CHECKSUM_FILES_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesClass))
+
+G_END_DECLS
+
+#endif /* BURN_SUM_FILE_H */
diff --git a/plugins/checksum/burn-checksum-image.c b/plugins/checksum/burn-checksum-image.c
new file mode 100644
index 0000000..e71072f
--- /dev/null
+++ b/plugins/checksum/burn-checksum-image.c
@@ -0,0 +1,824 @@
+/***************************************************************************
+ *            burn-sum.c
+ *
+ *  ven aoû  4 19:46:34 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-checksum-image.h"
+#include "burn-volume.h"
+#include "brasero-drive.h"
+#include "brasero-track-disc.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroChecksumImage, brasero_checksum_image, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroChecksumImagePrivate {
+	GChecksum *checksum;
+	BraseroChecksumType checksum_type;
+
+	/* That's for progress reporting */
+	guint64 total;
+	guint64 bytes;
+
+	/* this is for the thread and the end of it */
+	GThread *thread;
+	GMutex *mutex;
+	GCond *cond;
+	gint end_id;
+
+	guint cancel;
+};
+typedef struct _BraseroChecksumImagePrivate BraseroChecksumImagePrivate;
+
+#define BRASERO_CHECKSUM_IMAGE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImagePrivate))
+
+#define GCONF_KEY_CHECKSUM_TYPE		"/apps/brasero/config/checksum_image"
+
+static BraseroJobClass *parent_class = NULL;
+
+static gint
+brasero_checksum_image_read (BraseroChecksumImage *self,
+			     int fd,
+			     guchar *buffer,
+			     gint bytes,
+			     GError **error)
+{
+	gint total = 0;
+	gint read_bytes;
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	while (1) {
+		read_bytes = read (fd, buffer + total, (bytes - total));
+
+		/* maybe that's the end of the stream ... */
+		if (!read_bytes)
+			return total;
+
+		if (priv->cancel)
+			return -2;
+
+		/* ... or an error =( */
+		if (read_bytes == -1) {
+			if (errno != EAGAIN && errno != EINTR) {
+                                int errsv = errno;
+
+				g_set_error (error,
+					     BRASERO_BURN_ERROR,
+					     BRASERO_BURN_ERROR_GENERAL,
+					     _("Data could not be read (%s)"),
+					     g_strerror (errsv));
+				return -1;
+			}
+		}
+		else {
+			total += read_bytes;
+
+			if (total == bytes)
+				return total;
+		}
+
+		g_usleep (500);
+	}
+
+	return total;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_write (BraseroChecksumImage *self,
+			      int fd,
+			      guchar *buffer,
+			      gint bytes,
+			      GError **error)
+{
+	gint bytes_remaining;
+	gint bytes_written = 0;
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	bytes_remaining = bytes;
+	while (bytes_remaining) {
+		gint written;
+
+		written = write (fd,
+				 buffer + bytes_written,
+				 bytes_remaining);
+
+		if (priv->cancel)
+			return BRASERO_BURN_CANCEL;
+
+		if (written != bytes_remaining) {
+			if (errno != EINTR && errno != EAGAIN) {
+                                int errsv = errno;
+
+				/* unrecoverable error */
+				g_set_error (error,
+					     BRASERO_BURN_ERROR,
+					     BRASERO_BURN_ERROR_GENERAL,
+					     _("Data could not be written (%s)"),
+					     g_strerror (errsv));
+				return BRASERO_BURN_ERR;
+			}
+		}
+
+		g_usleep (500);
+
+		if (written > 0) {
+			bytes_remaining -= written;
+			bytes_written += written;
+		}
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_checksum (BraseroChecksumImage *self,
+				 GChecksumType checksum_type,
+				 int fd_in,
+				 int fd_out,
+				 GError **error)
+{
+	gint read_bytes;
+	guchar buffer [2048];
+	BraseroBurnResult result;
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	priv->checksum = g_checksum_new (checksum_type);
+	result = BRASERO_BURN_OK;
+	while (1) {
+		read_bytes = brasero_checksum_image_read (self,
+							  fd_in,
+							  buffer,
+							  sizeof (buffer),
+							  error);
+		if (read_bytes == -2)
+			return BRASERO_BURN_CANCEL;
+
+		if (read_bytes == -1)
+			return BRASERO_BURN_ERR;
+
+		if (!read_bytes)
+			break;
+
+		/* it can happen when we're just asked to generate a checksum
+		 * that we don't need to output the received data */
+		if (fd_out > 0) {
+			result = brasero_checksum_image_write (self,
+							       fd_out,
+							       buffer,
+							       read_bytes, error);
+			if (result != BRASERO_BURN_OK)
+				break;
+		}
+
+		g_checksum_update (priv->checksum,
+				   buffer,
+				   read_bytes);
+
+		priv->bytes += read_bytes;
+	}
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_checksum_fd_input (BraseroChecksumImage *self,
+					  GChecksumType checksum_type,
+					  GError **error)
+{
+	int fd_in = -1;
+	int fd_out = -1;
+	BraseroBurnResult result;
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	BRASERO_JOB_LOG (self, "Starting checksum generation live (size = %lli)", priv->total);
+	result = brasero_job_set_nonblocking (BRASERO_JOB (self), error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	brasero_job_get_fd_in (BRASERO_JOB (self), &fd_in);
+	brasero_job_get_fd_out (BRASERO_JOB (self), &fd_out);
+
+	return brasero_checksum_image_checksum (self, checksum_type, fd_in, fd_out, error);
+}
+
+static BraseroBurnResult
+brasero_checksum_image_checksum_file_input (BraseroChecksumImage *self,
+					    GChecksumType checksum_type,
+					    GError **error)
+{
+	BraseroChecksumImagePrivate *priv;
+	BraseroBurnResult result;
+	BraseroTrack *track;
+	int fd_out = -1;
+	int fd_in = -1;
+	gchar *path;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	/* get all information */
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+	if (!path) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_FILE_NOT_LOCAL,
+			     _("The file is not stored locally"));
+		return BRASERO_BURN_ERR;
+	}
+
+	BRASERO_JOB_LOG (self,
+			 "Starting checksuming file %s (size = %i)",
+			 path,
+			 priv->total);
+
+	fd_in = open (path, O_RDONLY);
+	if (!fd_in) {
+                int errsv;
+		gchar *name = NULL;
+
+		if (errno == ENOENT)
+			return BRASERO_BURN_RETRY;
+
+		name = g_path_get_basename (path);
+
+                errsv = errno;
+
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: first %s is the filename, second %s
+			      * is the error generated from errno */
+			     _("\"%s\" could not be opened (%s)"),
+			     name,
+			     g_strerror (errsv));
+		g_free (name);
+		g_free (path);
+
+		return BRASERO_BURN_ERR;
+	}
+
+	/* and here we go */
+	brasero_job_get_fd_out (BRASERO_JOB (self), &fd_out);
+	result = brasero_checksum_image_checksum (self, checksum_type, fd_in, fd_out, error);
+	g_free (path);
+	close (fd_in);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_create_checksum (BraseroChecksumImage *self,
+					GError **error)
+{
+	BraseroBurnResult result;
+	BraseroTrack *track = NULL;
+	GChecksumType checksum_type;
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	/* get the checksum type */
+	switch (priv->checksum_type) {
+		case BRASERO_CHECKSUM_MD5:
+			checksum_type = G_CHECKSUM_MD5;
+			break;
+		case BRASERO_CHECKSUM_SHA1:
+			checksum_type = G_CHECKSUM_SHA1;
+			break;
+		case BRASERO_CHECKSUM_SHA256:
+			checksum_type = G_CHECKSUM_SHA256;
+			break;
+		default:
+			return BRASERO_BURN_ERR;
+	}
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_CHECKSUM,
+					_("Creating image checksum"),
+					FALSE);
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+	/* see if another plugin is sending us data to checksum */
+	if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK) {
+		BraseroMedium *medium;
+		BraseroDrive *drive;
+
+		/* we're only able to checksum ISO format at the moment so that
+		 * means we can only handle last session */
+		drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+		medium = brasero_drive_get_medium (drive);
+		brasero_medium_get_last_data_track_space (medium,
+							  &priv->total,
+							  NULL);
+
+		return brasero_checksum_image_checksum_fd_input (self, checksum_type, error);
+	}
+	else {
+		result = brasero_track_get_size (track,
+						 NULL,
+						 &priv->total);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		return brasero_checksum_image_checksum_file_input (self, checksum_type, error);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroChecksumType
+brasero_checksum_get_checksum_type (void)
+{
+	GConfClient *client;
+	GChecksumType checksum_type;
+
+	client = gconf_client_get_default ();
+	checksum_type = gconf_client_get_int (client, GCONF_KEY_CHECKSUM_TYPE, NULL);
+	g_object_unref (client);
+
+	if (!checksum_type)
+		checksum_type = BRASERO_CHECKSUM_MD5;
+
+	return checksum_type;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_image_and_checksum (BraseroChecksumImage *self,
+					   GError **error)
+{
+	BraseroBurnResult result;
+	GChecksumType checksum_type;
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	priv->checksum_type = brasero_checksum_get_checksum_type ();
+	if (priv->checksum_type == BRASERO_CHECKSUM_NONE)
+		checksum_type = G_CHECKSUM_MD5;
+	else if (priv->checksum_type & BRASERO_CHECKSUM_MD5)
+		checksum_type = G_CHECKSUM_MD5;
+	else if (priv->checksum_type & BRASERO_CHECKSUM_SHA1)
+		checksum_type = G_CHECKSUM_SHA1;
+	else if (priv->checksum_type & BRASERO_CHECKSUM_SHA256)
+		checksum_type = G_CHECKSUM_SHA256;
+	else
+		checksum_type = G_CHECKSUM_MD5;
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_CHECKSUM,
+					_("Creating image checksum"),
+					FALSE);
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+	if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
+		BraseroTrack *track;
+
+		brasero_job_get_current_track (BRASERO_JOB (self), &track);
+		result = brasero_track_get_size (track,
+						 NULL,
+						 &priv->total);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		result = brasero_checksum_image_checksum_file_input (self,
+								     checksum_type,
+								     error);
+	}
+	else
+		result = brasero_checksum_image_checksum_fd_input (self,
+								   checksum_type,
+								   error);
+
+	return result;
+}
+
+struct _BraseroChecksumImageThreadCtx {
+	BraseroChecksumImage *sum;
+	BraseroBurnResult result;
+	GError *error;
+};
+typedef struct _BraseroChecksumImageThreadCtx BraseroChecksumImageThreadCtx;
+
+static gboolean
+brasero_checksum_image_end (gpointer data)
+{
+	BraseroChecksumImage *self;
+	BraseroTrack *track;
+	const gchar *checksum;
+	BraseroBurnResult result;
+	BraseroChecksumImagePrivate *priv;
+	BraseroChecksumImageThreadCtx *ctx;
+
+	ctx = data;
+	self = ctx->sum;
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	/* NOTE ctx/data is destroyed in its own callback */
+	priv->end_id = 0;
+
+	if (ctx->result != BRASERO_BURN_OK) {
+		GError *error;
+
+		error = ctx->error;
+		ctx->error = NULL;
+
+		g_checksum_free (priv->checksum);
+		priv->checksum = NULL;
+
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	/* we were asked to check the sum of the track so get the type
+	 * of the checksum first to see what to do */
+	track = NULL;
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+	/* Set the checksum for the track and at the same time compare it to a
+	 * potential previous one. */
+	checksum = g_checksum_get_string (priv->checksum);
+	BRASERO_JOB_LOG (self,
+			 "Setting new checksum (type = %i) %s (%s before)",
+			 priv->checksum_type,
+			 checksum,
+			 brasero_track_get_checksum (track));
+	result = brasero_track_set_checksum (track,
+					     priv->checksum_type,
+					     checksum);
+	g_checksum_free (priv->checksum);
+	priv->checksum = NULL;
+
+	if (result != BRASERO_BURN_OK)
+		goto error;
+
+	brasero_job_finished_track (BRASERO_JOB (self));
+	return FALSE;
+
+error:
+{
+	GError *error = NULL;
+
+	error = g_error_new (BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_BAD_CHECKSUM,
+			     _("Some files may be corrupted on the disc"));
+	brasero_job_error (BRASERO_JOB (self), error);
+	return FALSE;
+}
+}
+
+static void
+brasero_checksum_image_destroy (gpointer data)
+{
+	BraseroChecksumImageThreadCtx *ctx;
+
+	ctx = data;
+	if (ctx->error) {
+		g_error_free (ctx->error);
+		ctx->error = NULL;
+	}
+
+	g_free (ctx);
+}
+
+static gpointer
+brasero_checksum_image_thread (gpointer data)
+{
+	GError *error = NULL;
+	BraseroJobAction action;
+	BraseroTrack *track = NULL;
+	BraseroChecksumImage *self;
+	BraseroChecksumImagePrivate *priv;
+	BraseroChecksumImageThreadCtx *ctx;
+	BraseroBurnResult result = BRASERO_BURN_NOT_SUPPORTED;
+
+	self = BRASERO_CHECKSUM_IMAGE (data);
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+	/* check DISC types and add checksums for DATA and IMAGE-bin types */
+	brasero_job_get_action (BRASERO_JOB (self), &action);
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+	if (action == BRASERO_JOB_ACTION_CHECKSUM) {
+		priv->checksum_type = brasero_track_get_checksum_type (track);
+		if (priv->checksum_type & (BRASERO_CHECKSUM_MD5|BRASERO_CHECKSUM_SHA1|BRASERO_CHECKSUM_SHA256))
+			result = brasero_checksum_image_create_checksum (self, &error);
+		else
+			result = BRASERO_BURN_ERR;
+	}
+	else if (action == BRASERO_JOB_ACTION_IMAGE) {
+		if (BRASERO_IS_TRACK_IMAGE (track))
+			result = brasero_checksum_image_image_and_checksum (self, &error);
+		else
+			result = BRASERO_BURN_ERR;
+	}
+
+	if (result != BRASERO_BURN_CANCEL) {
+		ctx = g_new0 (BraseroChecksumImageThreadCtx, 1);
+		ctx->sum = self;
+		ctx->error = error;
+		ctx->result = result;
+		priv->end_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+						brasero_checksum_image_end,
+						ctx,
+						brasero_checksum_image_destroy);
+	}
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	priv->thread = NULL;
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_start (BraseroJob *job,
+			      GError **error)
+{
+	BraseroChecksumImagePrivate *priv;
+	GError *thread_error = NULL;
+	BraseroJobAction action;
+
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		/* say we won't write to disc if we're just checksuming "live" */
+		if (brasero_job_get_fd_in (job, NULL) == BRASERO_BURN_OK)
+			return BRASERO_BURN_NOT_SUPPORTED;
+
+		/* otherwise return an output of 0 since we're not actually 
+		 * writing anything to the disc. That will prevent a disc space
+		 * failure. */
+		brasero_job_set_output_size_for_current_track (job, 0, 0);
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	/* we start a thread for the exploration of the graft points */
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (job);
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_checksum_image_thread,
+					BRASERO_CHECKSUM_IMAGE (job),
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_activate (BraseroJob *job,
+				 GError **error)
+{
+	BraseroBurnFlag flags = BRASERO_BURN_FLAG_NONE;
+	BraseroTrack *track = NULL;
+	BraseroJobAction action;
+
+	brasero_job_get_current_track (job, &track);
+	brasero_job_get_action (job, &action);
+
+	if (action == BRASERO_JOB_ACTION_IMAGE
+	&&  brasero_track_get_checksum_type (track) == brasero_checksum_get_checksum_type ()) {
+		BRASERO_JOB_LOG (job,
+				 "There is a checksum already %d",
+				 brasero_track_get_checksum_type (track));
+		/* if there is a checksum already, if so no need to redo one */
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	flags = BRASERO_BURN_FLAG_NONE;
+	brasero_job_get_flags (job, &flags);
+	if (flags & BRASERO_BURN_FLAG_DUMMY) {
+		BRASERO_JOB_LOG (job, "Dummy operation, skipping");
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_clock_tick (BraseroJob *job)
+{
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (job);
+	if (!priv->checksum)
+		return BRASERO_BURN_OK;
+
+	if (!priv->total)
+		return BRASERO_BURN_OK;
+
+	brasero_job_set_progress (job,
+				  (gdouble) priv->bytes /
+				  (gdouble) priv->total);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_stop (BraseroJob *job,
+			     GError **error)
+{
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (job);
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread) {
+		priv->cancel = 1;
+		g_cond_wait (priv->cond, priv->mutex);
+		priv->cancel = 0;
+		priv->thread = NULL;
+	}
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->end_id) {
+		g_source_remove (priv->end_id);
+		priv->end_id = 0;
+	}
+
+	if (priv->checksum) {
+		g_checksum_free (priv->checksum);
+		priv->checksum = NULL;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_checksum_image_init (BraseroChecksumImage *obj)
+{
+	BraseroChecksumImagePrivate *priv;
+
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (obj);
+
+	priv->mutex = g_mutex_new ();
+	priv->cond = g_cond_new ();
+}
+
+static void
+brasero_checksum_image_finalize (GObject *object)
+{
+	BraseroChecksumImagePrivate *priv;
+	
+	priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (object);
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread) {
+		priv->cancel = 1;
+		g_cond_wait (priv->cond, priv->mutex);
+		priv->cancel = 0;
+		priv->thread = NULL;
+	}
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->end_id) {
+		g_source_remove (priv->end_id);
+		priv->end_id = 0;
+	}
+
+	if (priv->checksum) {
+		g_checksum_free (priv->checksum);
+		priv->checksum = NULL;
+	}
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cond) {
+		g_cond_free (priv->cond);
+		priv->cond = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_checksum_image_class_init (BraseroChecksumImageClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroChecksumImagePrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_checksum_image_finalize;
+
+	job_class->activate = brasero_checksum_image_activate;
+	job_class->start = brasero_checksum_image_start;
+	job_class->stop = brasero_checksum_image_stop;
+	job_class->clock_tick = brasero_checksum_image_clock_tick;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	BraseroPluginConfOption *checksum_type;
+
+	brasero_plugin_define (plugin,
+			       /* Translators: this is the name of the plugin
+				* which will be translated only when it needs
+				* displaying. */
+			       N_("Image Checksum"),
+			       _("Allows to check data integrity on disc after it is burnt"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* For images we can process (thus generating a sum on the fly or simply
+	 * test images). */
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					BRASERO_IMAGE_FORMAT_BIN);
+	brasero_plugin_process_caps (plugin, input);
+
+	brasero_plugin_set_process_flags (plugin,
+					  BRASERO_PLUGIN_RUN_PREPROCESSING|
+					  BRASERO_PLUGIN_RUN_BEFORE_TARGET);
+
+	brasero_plugin_check_caps (plugin,
+				   BRASERO_CHECKSUM_MD5|
+				   BRASERO_CHECKSUM_SHA1|
+				   BRASERO_CHECKSUM_SHA256,
+				   input);
+	g_slist_free (input);
+
+	/* add some configure options */
+	checksum_type = brasero_plugin_conf_option_new (GCONF_KEY_CHECKSUM_TYPE,
+							_("Hashing algorithm to be used:"),
+							BRASERO_PLUGIN_OPTION_CHOICE);
+	brasero_plugin_conf_option_choice_add (checksum_type,
+					       _("MD5"), BRASERO_CHECKSUM_MD5);
+	brasero_plugin_conf_option_choice_add (checksum_type,
+					       _("SHA1"), BRASERO_CHECKSUM_SHA1);
+	brasero_plugin_conf_option_choice_add (checksum_type,
+					       _("SHA256"), BRASERO_CHECKSUM_SHA256);
+
+	brasero_plugin_add_conf_option (plugin, checksum_type);
+
+	brasero_plugin_set_compulsory (plugin, FALSE);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/checksum/burn-checksum-image.h b/plugins/checksum/burn-checksum-image.h
new file mode 100644
index 0000000..aada24a
--- /dev/null
+++ b/plugins/checksum/burn-checksum-image.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            burn-sum.h
+ *
+ *  ven aoû  4 19:46:34 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef BURN_SUM_H
+#define BURN_SUM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CHECKSUM_IMAGE		(brasero_checksum_image_get_type ())
+#define BRASERO_CHECKSUM_IMAGE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImage))
+#define BRASERO_CHECKSUM_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImageClass))
+#define BRASERO_IS_CHECKSUM_IMAGE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CHECKSUM_IMAGE))
+#define BRASERO_IS_CHECKSUM_IMAGE_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CHECKSUM_IMAGE))
+#define BRASERO_CHECKSUM_GET_CLASS(o)		(G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImageClass))
+
+G_END_DECLS
+
+#endif /* BURN_SUM_H */
diff --git a/plugins/checksum/burn-volume-read.c b/plugins/checksum/burn-volume-read.c
new file mode 100644
index 0000000..29c9772
--- /dev/null
+++ b/plugins/checksum/burn-volume-read.c
@@ -0,0 +1,397 @@
+/***************************************************************************
+ *            brasero-medium-handle.c
+ *
+ *  Sat Mar 15 17:27:29 2008
+ *  Copyright  2008  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+
+#include "scsi-device.h"
+#include "scsi-mmc1.h"
+#include "burn-volume.h"
+#include "burn-iso9660.h"
+#include "burn-volume-read.h"
+
+struct _BraseroVolFileHandle {
+	/* 64 is an empirical value based on one of my drives. */
+	guchar buffer [2048 * 64];
+	guint buffer_max;
+
+	/* position in buffer */
+	guint offset;
+
+	/* address (in blocks) for current extent */
+	guint extent_last;
+
+	/* size in bytes for the current extent */
+	guint extent_size;
+
+	BraseroVolSrc *src;
+	GSList *extents_backward;
+	GSList *extents_forward;
+	guint position;
+};
+
+void
+brasero_volume_file_close (BraseroVolFileHandle *handle)
+{
+	g_slist_free (handle->extents_forward);
+	g_slist_free (handle->extents_backward);
+	brasero_volume_source_close (handle->src);
+	g_free (handle);
+}
+
+static gboolean
+brasero_volume_file_fill_buffer (BraseroVolFileHandle *handle)
+{
+	guint blocks;
+	gboolean result;
+
+	blocks = MIN (sizeof (handle->buffer) / 2048,
+		      handle->extent_last - handle->position);
+
+	result = BRASERO_VOL_SRC_READ (handle->src,
+				       (char *) handle->buffer,
+				       blocks,
+				       NULL);
+	if (!result)
+		return FALSE;
+
+	handle->offset = 0;
+	handle->position += blocks;
+
+	if (handle->position == handle->extent_last)
+		handle->buffer_max = (blocks - 1) * 2048 +
+				     ((handle->extent_size % 2048) ?
+				      (handle->extent_size % 2048) :
+				       2048);
+	else
+		handle->buffer_max = sizeof (handle->buffer);
+
+	return TRUE;
+}
+
+static gboolean
+brasero_volume_file_next_extent (BraseroVolFileHandle *handle)
+{
+	BraseroVolFileExtent *extent;
+	gint res_seek;
+	GSList *node;
+
+	node = handle->extents_forward;
+	extent = node->data;
+
+	handle->extents_forward = g_slist_remove_link (handle->extents_forward, node);
+	node->next = handle->extents_backward;
+	handle->extents_backward = node;
+
+	handle->position = extent->block;
+	handle->extent_size = extent->size;
+	handle->extent_last = BRASERO_BYTES_TO_SECTORS (extent->size, 2048) + extent->block;
+
+	res_seek = BRASERO_VOL_SRC_SEEK (handle->src, handle->position, SEEK_SET,  NULL);
+	if (res_seek == -1)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_volume_file_rewind_real (BraseroVolFileHandle *handle)
+{
+	if (!brasero_volume_file_next_extent (handle))
+		return FALSE;
+
+	return brasero_volume_file_fill_buffer (handle);
+}
+
+BraseroVolFileHandle *
+brasero_volume_file_open (BraseroVolSrc *src,
+			  BraseroVolFile *file)
+{
+	BraseroVolFileHandle *handle;
+
+	if (file->isdir)
+		return NULL;
+
+	handle = g_new0 (BraseroVolFileHandle, 1);
+	handle->src = src;
+	brasero_volume_source_ref (src);
+
+	handle->extents_forward = g_slist_copy (file->specific.file.extents);
+	if (!brasero_volume_file_rewind_real (handle)) {
+		brasero_volume_file_close (handle);
+		return NULL;
+	}
+
+	return handle;
+}
+
+gboolean
+brasero_volume_file_rewind (BraseroVolFileHandle *handle)
+{
+	GSList *node, *next;
+
+	/* Put back all extents in the unread list */
+	for (node = handle->extents_backward; node; node = next) {
+		next = node->next;
+		handle->extents_backward = g_slist_remove_link (handle->extents_backward, node);
+
+		node->next = handle->extents_forward;
+		handle->extents_forward = node;
+	}
+	return brasero_volume_file_rewind_real (handle);
+}
+
+BraseroBurnResult
+brasero_volume_file_check_state (BraseroVolFileHandle *handle)
+{
+	/* check if we need to load a new block */
+	if (handle->offset < handle->buffer_max)
+		return BRASERO_BURN_RETRY;
+
+	/* check if we need to change our extent */
+	if (handle->position >= handle->extent_last) {
+		/* we are at the end of current extent try to find another */
+		if (!handle->extents_forward) {
+			/* we reached the end of our file */
+			return BRASERO_BURN_OK;
+		}
+
+		if (!brasero_volume_file_next_extent (handle))
+			return BRASERO_BURN_ERR;
+	}
+
+	/* Refill buffer */
+	if (!brasero_volume_file_fill_buffer (handle))
+		return BRASERO_BURN_ERR;
+
+	return BRASERO_BURN_RETRY;
+}
+
+gint
+brasero_volume_file_read (BraseroVolFileHandle *handle,
+			  gchar *buffer,
+			  guint len)
+{
+	guint buffer_offset = 0;
+	BraseroBurnResult result;
+
+	while ((len - buffer_offset) > (handle->buffer_max - handle->offset)) {
+		/* copy what is already in the buffer and refill the latter */
+		memcpy (buffer + buffer_offset,
+			handle->buffer + handle->offset,
+			handle->buffer_max - handle->offset);
+
+		buffer_offset += handle->buffer_max - handle->offset;
+		handle->offset = handle->buffer_max;
+
+		result = brasero_volume_file_check_state (handle);
+		if (result == BRASERO_BURN_OK)
+			return buffer_offset;
+
+		if (result == BRASERO_BURN_ERR)
+			return -1;
+	}
+
+	/* we filled the buffer and put len bytes in it */
+	memcpy (buffer + buffer_offset,
+		handle->buffer + handle->offset,
+		len - buffer_offset);
+
+	handle->offset += len - buffer_offset;
+
+	result = brasero_volume_file_check_state (handle);
+	if (result == BRASERO_BURN_ERR)
+		return -1;
+
+	return len;
+}
+
+static gint
+brasero_volume_file_find_line_break (BraseroVolFileHandle *handle,
+				     guint buffer_offset,
+				     gchar *buffer,
+				     guint len)
+{
+	guchar *break_line;
+	guint line_len;
+
+	/* search the next end of line characher in the buffer */
+	break_line = memchr (handle->buffer + handle->offset,
+			     '\n',
+			     handle->buffer_max - handle->offset);
+
+	if (!break_line)
+		return FALSE;
+
+	line_len = break_line - (handle->buffer + handle->offset);
+	if (len && line_len >= len) {
+		/* - 1 is to be able to set last character to '\0' */
+		if (buffer) {
+			memcpy (buffer + buffer_offset,
+				handle->buffer + handle->offset,
+				len - buffer_offset - 1);
+
+			buffer [len - 1] = '\0';
+		}
+
+		handle->offset += len - buffer_offset - 1;
+		return TRUE;
+	}
+
+	if (buffer) {
+		memcpy (buffer, handle->buffer + handle->offset, line_len);
+		buffer [line_len] = '\0';
+	}
+
+	/* add 1 to skip the line break */
+	handle->offset += line_len + 1;
+	return TRUE;
+}
+
+BraseroBurnResult
+brasero_volume_file_read_line (BraseroVolFileHandle *handle,
+			       gchar *buffer,
+			       guint len)
+{
+	guint buffer_offset = 0;
+	gboolean found;
+
+	found = brasero_volume_file_find_line_break (handle,
+						     buffer_offset,
+						     buffer,
+						     len);
+	if (found)
+		return brasero_volume_file_check_state (handle);
+
+	/* continue while remaining data is too small to fit buffer */
+	while (!len || (len - buffer_offset) > (handle->buffer_max - handle->offset)) {
+		BraseroScsiResult result;
+
+		/* copy what we already have in the buffer. */
+		if (buffer)
+			memcpy (buffer + buffer_offset,
+				handle->offset + handle->buffer,
+				handle->buffer_max - handle->offset);
+
+		buffer_offset += handle->buffer_max - handle->offset;
+		handle->offset = handle->buffer_max;
+
+		/* refill buffer */
+		result = brasero_volume_file_check_state (handle);
+		if (result == BRASERO_BURN_OK) {
+			if (buffer)
+				buffer [len - 1] = '\0';
+
+			return result;
+		}
+
+		found = brasero_volume_file_find_line_break (handle,
+							     buffer_offset,
+							     buffer,
+							     len);
+		if (found)
+			return brasero_volume_file_check_state (handle);
+	}
+
+	/* we filled the buffer */
+	if (buffer) {
+		memcpy (buffer + buffer_offset,
+			handle->buffer + handle->offset,
+			len - buffer_offset - 1);
+		buffer [len - 1] = '\0';
+	}
+
+	/* NOTE: when len == 0 we never reach this part */
+	handle->offset += len - buffer_offset - 1;
+
+	return brasero_volume_file_check_state (handle);
+}
+
+BraseroVolFileHandle *
+brasero_volume_file_open_direct (BraseroVolSrc *src,
+				 BraseroVolFile *file)
+{
+	BraseroVolFileHandle *handle;
+
+	if (file->isdir)
+		return NULL;
+
+	handle = g_new0 (BraseroVolFileHandle, 1);
+	handle->src = src;
+	brasero_volume_source_ref (src);
+
+	handle->extents_forward = g_slist_copy (file->specific.file.extents);
+
+	/* Here the buffer stays unused, we copy straight to the buffer passed
+	 * in the read direct function. */
+	if (!brasero_volume_file_next_extent (handle)) {
+		brasero_volume_file_close (handle);
+		return NULL;
+	}
+
+	return handle;
+}
+
+gint64
+brasero_volume_file_read_direct (BraseroVolFileHandle *handle,
+				 guchar *buffer,
+				 guint blocks)
+{
+	gboolean result;
+	guint block2read;
+	guint readblocks = 0;
+
+start:
+
+	block2read = MIN (blocks - readblocks, handle->extent_last - handle->position);
+	if (!block2read)
+		return readblocks * 2048;
+
+	result = BRASERO_VOL_SRC_READ (handle->src,
+				       (char *) buffer + readblocks * 2048,
+				       block2read,
+				       NULL);
+	if (!result)
+		return -1;
+
+	handle->position += block2read;
+	readblocks += block2read;
+
+	if (handle->position == handle->extent_last) {
+		/* we are at the end of current extent try to find another */
+		if (!handle->extents_forward) {
+			/* we reached the end of our file */
+			return (readblocks - 1) * 2048 +
+			       ((handle->extent_size % 2048) != 0?
+			        (handle->extent_size % 2048) :
+				 2048);
+		}
+
+		if (!brasero_volume_file_next_extent (handle))
+			return -1;
+
+		goto start;
+	}
+
+	return readblocks * 2048;
+}
+
diff --git a/plugins/checksum/burn-volume-read.h b/plugins/checksum/burn-volume-read.h
new file mode 100644
index 0000000..973a40d
--- /dev/null
+++ b/plugins/checksum/burn-volume-read.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *            brasero-medium-handle.h
+ *
+ *  Sat Mar 15 17:28:02 2008
+ *  Copyright  2008  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef _BRASERO_MEDIUM_HANDLE_H
+#define BRASERO_MEDIUM_HANDLE_H
+
+#include <glib.h>
+
+#include "burn-basics.h"
+#include "burn-volume-source.h"
+
+G_BEGIN_DECLS
+
+typedef struct _BraseroVolFileHandle BraseroVolFileHandle;
+
+
+BraseroVolFileHandle *
+brasero_volume_file_open (BraseroVolSrc *src,
+			  BraseroVolFile *file);
+
+void
+brasero_volume_file_close (BraseroVolFileHandle *handle);
+
+gboolean
+brasero_volume_file_rewind (BraseroVolFileHandle *handle);
+
+gint
+brasero_volume_file_read (BraseroVolFileHandle *handle,
+			  gchar *buffer,
+			  guint len);
+
+BraseroBurnResult
+brasero_volume_file_read_line (BraseroVolFileHandle *handle,
+			       gchar *buffer,
+			       guint len);
+
+BraseroVolFileHandle *
+brasero_volume_file_open_direct (BraseroVolSrc *src,
+				 BraseroVolFile *file);
+
+gint64
+brasero_volume_file_read_direct (BraseroVolFileHandle *handle,
+				 guchar *buffer,
+				 guint blocks);
+
+G_END_DECLS
+
+#endif /* BRASERO_MEDIUM_HANDLE_H */
+
+ 
diff --git a/plugins/dvdauthor/Makefile.am b/plugins/dvdauthor/Makefile.am
new file mode 100644
index 0000000..deefcf5
--- /dev/null
+++ b/plugins/dvdauthor/Makefile.am
@@ -0,0 +1,23 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_LIBXML_CFLAGS)
+
+dvdauthordir = $(libdir)/brasero/plugins
+dvdauthor_LTLIBRARIES = libbrasero-dvdauthor.la
+
+libbrasero_dvdauthor_la_SOURCES = burn-dvdauthor.c burn-dvdauthor.h
+libbrasero_dvdauthor_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBXML_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_dvdauthor_la_LDFLAGS = -module -avoid-version
+
diff --git a/plugins/dvdauthor/burn-dvdauthor.c b/plugins/dvdauthor/burn-dvdauthor.c
new file mode 100644
index 0000000..436610b
--- /dev/null
+++ b/plugins/dvdauthor/burn-dvdauthor.c
@@ -0,0 +1,423 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * burn-dvdauthor.c
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ * 
+ * burn-dvdauthor.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * burn-dvdauthor.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with burn-dvdauthor.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <libxml/xmlerror.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xmlstring.h>
+#include <libxml/uri.h>
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-dvdauthor.h"
+#include "brasero-track-data.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdAuthor, brasero_dvd_author, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+typedef struct _BraseroDvdAuthorPrivate BraseroDvdAuthorPrivate;
+struct _BraseroDvdAuthorPrivate
+{
+	gchar *output;
+};
+
+#define BRASERO_DVD_AUTHOR_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorPrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_dvd_author_add_track (BraseroJob *job)
+{
+	gchar *path;
+	GSList *grafts = NULL;
+	BraseroGraftPt *graft;
+	BraseroTrackData *track;
+	BraseroDvdAuthorPrivate *priv;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (job);
+
+	/* create the track */
+	track = brasero_track_data_new ();
+
+	/* audio */
+	graft = g_new (BraseroGraftPt, 1);
+	path = g_build_path (G_DIR_SEPARATOR_S,
+			     priv->output,
+			     "AUDIO_TS",
+			     NULL);
+	graft->uri = g_filename_to_uri (path, NULL, NULL);
+	g_free (path);
+
+	graft->path = g_strdup ("/AUDIO_TS");
+	grafts = g_slist_prepend (grafts, graft);
+
+	BRASERO_JOB_LOG (job, "Adding graft point for %s", graft->uri);
+
+	/* video */
+	graft = g_new (BraseroGraftPt, 1);
+	path = g_build_path (G_DIR_SEPARATOR_S,
+			     priv->output,
+			     "VIDEO_TS",
+			     NULL);
+	graft->uri = g_filename_to_uri (path, NULL, NULL);
+	g_free (path);
+
+	graft->path = g_strdup ("/VIDEO_TS");
+	grafts = g_slist_prepend (grafts, graft);
+
+	BRASERO_JOB_LOG (job, "Adding graft point for %s", graft->uri);
+
+	brasero_track_data_add_fs (track,
+				   BRASERO_IMAGE_FS_ISO|
+				   BRASERO_IMAGE_FS_UDF|
+				   BRASERO_IMAGE_FS_VIDEO);
+	brasero_track_data_set_source (track,
+				       grafts,
+				       NULL);
+	brasero_job_add_track (job, BRASERO_TRACK (track));
+	g_object_unref (track);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_read_stdout (BraseroProcess *process,
+				const gchar *line)
+{
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_read_stderr (BraseroProcess *process,
+				const gchar *line)
+{
+	gint percent = 0;
+
+	if (sscanf (line, "STAT: fixing VOBU at %*s (%*d/%*d, %d%%)", &percent) == 1) {
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+		brasero_job_set_progress (BRASERO_JOB (process),
+					  (gdouble) ((gdouble) percent) / 100.0);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_generate_xml_file (BraseroProcess *process,
+				      const gchar *path,
+				      GError **error)
+{
+	BraseroDvdAuthorPrivate *priv;
+	BraseroBurnResult result;
+	GSList *tracks = NULL;
+	xmlTextWriter *xml;
+	gint success;
+	GSList *iter;
+
+	BRASERO_JOB_LOG (process, "Creating DVD layout xml file(%s)", path);
+
+	xml = xmlNewTextWriterFilename (path, 0);
+	if (!xml)
+		return BRASERO_BURN_ERR;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (process);
+
+	xmlTextWriterSetIndent (xml, 1);
+	xmlTextWriterSetIndentString (xml, (xmlChar *) "\t");
+
+	success = xmlTextWriterStartDocument (xml,
+					      NULL,
+					      "UTF8",
+					      NULL);
+	if (success < 0)
+		goto error;
+
+	result = brasero_job_get_tmp_dir (BRASERO_JOB (process),
+					  &priv->output,
+					  error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* let's start */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "dvdauthor");
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterWriteAttribute (xml,
+					       (xmlChar *) "dest",
+					       (xmlChar *) priv->output);
+	if (success < 0)
+		goto error;
+
+	/* This is needed to finalize */
+	success = xmlTextWriterWriteElement (xml, (xmlChar *) "vmgm", (xmlChar *) "");
+	if (success < 0)
+		goto error;
+
+	/* the tracks */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "titleset");
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "titles");
+	if (success < 0)
+		goto error;
+
+	/* get all tracks */
+	brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+	for (iter = tracks; iter; iter = iter->next) {
+		BraseroTrack *track;
+		gchar *video;
+
+		track = iter->data;
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "pgc");
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "vob");
+		if (success < 0)
+			goto error;
+
+		video = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "file",
+						       (xmlChar *) video);
+		g_free (video);
+
+		if (success < 0)
+			goto error;
+
+		/* vob */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+
+		/* pgc */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+	}
+
+	/* titles */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* titleset */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* close dvdauthor */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	return BRASERO_BURN_OK;
+
+error:
+
+	BRASERO_JOB_LOG (process, "Error");
+
+	/* close everything */
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	/* FIXME: get the error */
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_set_argv (BraseroProcess *process,
+			     GPtrArray *argv,
+			     GError **error)
+{
+	BraseroDvdAuthorPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	gchar *output;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (process);
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		BRASERO_JOB_NOT_SUPPORTED (process);
+
+	g_ptr_array_add (argv, g_strdup ("dvdauthor"));
+	
+	/* get all arguments to write XML file */
+	result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+					   NULL,
+					   &output,
+					   error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	g_ptr_array_add (argv, g_strdup ("-x"));
+	g_ptr_array_add (argv, output);
+
+	result = brasero_dvd_author_generate_xml_file (process, output, error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	brasero_job_set_current_action (BRASERO_JOB (process),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					_("Creating file layout"),
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_post (BraseroJob *job)
+{
+	BraseroDvdAuthorPrivate *priv;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (job);
+
+	brasero_dvd_author_add_track (job);
+
+	if (priv->output) {
+		g_free (priv->output);
+		priv->output = NULL;
+	}
+
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_dvd_author_init (BraseroDvdAuthor *object)
+{}
+
+static void
+brasero_dvd_author_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_dvd_author_class_init (BraseroDvdAuthorClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass* process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroDvdAuthorPrivate));
+
+	object_class->finalize = brasero_dvd_author_finalize;
+
+	process_class->stdout_func = brasero_dvd_author_read_stdout;
+	process_class->stderr_func = brasero_dvd_author_read_stderr;
+	process_class->set_argv = brasero_dvd_author_set_argv;
+	process_class->post = brasero_dvd_author_post;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	/* NOTE: it seems that cdrecord can burn cue files on the fly */
+	brasero_plugin_define (plugin,
+			       "dvdauthor",
+			       _("Use dvdauthor to create Video DVDs"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("dvdauthor", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_AC3|
+					BRASERO_AUDIO_FORMAT_MP2|
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_AUDIO_FORMAT_48000|
+					BRASERO_METADATA_INFO|
+					BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+
+	output = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+					BRASERO_IMAGE_FS_UDF|
+					BRASERO_IMAGE_FS_VIDEO);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_AC3|
+					BRASERO_AUDIO_FORMAT_MP2|
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_AUDIO_FORMAT_48000|
+					BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* we only support DVDs */
+	brasero_plugin_set_flags (plugin,
+  				  BRASERO_MEDIUM_FILE|
+				  BRASERO_MEDIUM_DVDR|
+				  BRASERO_MEDIUM_DVDR_PLUS|
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW|
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_DVDRW_RESTRICTED|
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/dvdauthor/burn-dvdauthor.h b/plugins/dvdauthor/burn-dvdauthor.h
new file mode 100644
index 0000000..4c39910
--- /dev/null
+++ b/plugins/dvdauthor/burn-dvdauthor.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * burn-dvdauthor.c
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ * 
+ * burn-dvdauthor.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * burn-dvdauthor.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with burn-dvdauthor.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_DVD_AUTHOR_H_
+#define _BRASERO_DVD_AUTHOR_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVD_AUTHOR             (brasero_dvd_author_get_type ())
+#define BRASERO_DVD_AUTHOR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthor))
+#define BRASERO_DVD_AUTHOR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorClass))
+#define BRASERO_IS_DVD_AUTHOR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_DVD_AUTHOR))
+#define BRASERO_IS_DVD_AUTHOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_DVD_AUTHOR))
+#define BRASERO_DVD_AUTHOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_DVD_AUTHOR_H_ */
diff --git a/plugins/dvdcss/Makefile.am b/plugins/dvdcss/Makefile.am
new file mode 100644
index 0000000..626105a
--- /dev/null
+++ b/plugins/dvdcss/Makefile.am
@@ -0,0 +1,22 @@
+plugindir = $(libdir)/brasero/plugins
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)
+
+plugin_LTLIBRARIES = libbrasero-dvdcss.la
+
+libbrasero_dvdcss_la_SOURCES = burn-dvdcss.c burn-dvdcss.h \
+	burn-dvdcss-private.h 
+libbrasero_dvdcss_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GMODULE_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_dvdcss_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/dvdcss/burn-dvdcss-private.h b/plugins/dvdcss/burn-dvdcss-private.h
new file mode 100644
index 0000000..8dd37d8
--- /dev/null
+++ b/plugins/dvdcss/burn-dvdcss-private.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ *            burn-dvdcss-private.h
+ *
+ *  Thu Nov 16 16:20:39 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+
+
+#include <gmodule.h>
+
+#ifndef _BURN_DVDCSS_PRIVATE_H
+#define _BURN_DVDCSS_PRIVATE_H
+
+G_BEGIN_DECLS
+
+static gboolean css_ready = FALSE;
+
+typedef gpointer dvdcss_handle;
+
+#define DVDCSS_NOFLAGS		0x00
+
+#define DVDCSS_READ_DECRYPT	(1 << 0)
+
+#define DVDCSS_SEEK_MPEG	(1 << 0)
+#define DVDCSS_SEEK_KEY		(1 << 1)
+
+#define DVDCSS_BLOCK_SIZE	2048ULL
+
+static dvdcss_handle *
+(*dvdcss_open)	(const gchar *device) = NULL;
+
+static gint
+(*dvdcss_close)	(dvdcss_handle *handle) = NULL;
+
+static gint
+(*dvdcss_read)	(dvdcss_handle *handle, gpointer p_buffer, gint i_blocks, gint i_flags) = NULL;
+
+static gint
+(*dvdcss_seek)	(dvdcss_handle *handle, gint i_blocks, gint i_flags) = NULL;
+
+static gchar *
+(*dvdcss_error)	(dvdcss_handle *handle) = NULL;
+
+G_END_DECLS
+
+#endif /* _BURN_DVDCSS_PRIVATE_H */
+
+ 
diff --git a/plugins/dvdcss/burn-dvdcss.c b/plugins/dvdcss/burn-dvdcss.c
new file mode 100644
index 0000000..3c4a4d5
--- /dev/null
+++ b/plugins/dvdcss/burn-dvdcss.c
@@ -0,0 +1,698 @@
+/***************************************************************************
+ *            burn-dvdcss.c
+ *
+ *  lun aoû 21 14:34:32 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  TBrasero is free software; you can redistribute itand/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TBrasero is distributed in the hope that it will be useful
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to t:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.30, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "brasero-units.h"
+
+#include "burn-debug.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-dvdcss.h"
+#include "burn-dvdcss-private.h"
+#include "burn-volume.h"
+#include "brasero-medium.h"
+#include "brasero-track-image.h"
+#include "brasero-track-disc.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdcss, brasero_dvdcss, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroDvdcssPrivate {
+	GError *error;
+	GThread *thread;
+	GMutex *mutex;
+	GCond *cond;
+	guint thread_id;
+
+	guint cancel:1;
+};
+typedef struct _BraseroDvdcssPrivate BraseroDvdcssPrivate;
+
+#define BRASERO_DVDCSS_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DVDCSS, BraseroDvdcssPrivate))
+
+#define BRASERO_DVDCSS_I_BLOCKS	16ULL
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+brasero_dvdcss_library_init (GError **error)
+{
+	GModule *module;
+	gpointer address;
+	gchar *dvdcss_interface_2 = NULL;
+
+	if (css_ready)
+		return TRUE;
+
+	/* load libdvdcss library and see the version (mine is 1.2.0) */
+	module = g_module_open ("libdvdcss.so.2", G_MODULE_BIND_LOCAL);
+	if (!module)
+		goto error_doesnt_exist;
+
+	if (!g_module_symbol (module, "dvdcss_interface_2", &address))
+		goto error_version;
+
+	dvdcss_interface_2 = address;
+	BRASERO_BURN_LOG ("libdvdcss version %d.%d.%d\n",
+			  (guchar) dvdcss_interface_2 [0],
+			  (guchar) dvdcss_interface_2 [1],
+			  (guchar) dvdcss_interface_2 [2]);
+
+	if (!g_module_symbol (module, "dvdcss_open", &address))
+		goto error_loading;
+	dvdcss_open = address;
+
+	if (!g_module_symbol (module, "dvdcss_close", &address))
+		goto error_loading;
+	dvdcss_close = address;
+
+	if (!g_module_symbol (module, "dvdcss_read", &address))
+		goto error_loading;
+	dvdcss_read = address;
+
+	if (!g_module_symbol (module, "dvdcss_seek", &address))
+		goto error_loading;
+	dvdcss_seek = address;
+
+	if (!g_module_symbol (module, "dvdcss_error", &address))
+		goto error_loading;
+	dvdcss_error = address;
+
+	css_ready = TRUE;
+	return TRUE;
+
+error_doesnt_exist:
+	g_set_error (error,
+		     BRASERO_BURN_ERROR,
+		     BRASERO_BURN_ERROR_GENERAL,
+		     _("Encrypted DVD: please install libdvdcss version 1.2.x"));
+	return FALSE;
+
+error_version:
+	g_set_error (error,
+		     BRASERO_BURN_ERROR,
+		     BRASERO_BURN_ERROR_GENERAL,
+		     _("Libdvdcss version %s is not supported.\nPlease install libdvdcss version 1.2.x"),
+		     dvdcss_interface_2);
+	g_module_close (module);
+	return FALSE;
+
+
+error_loading:
+	g_set_error (error,
+		     BRASERO_BURN_ERROR,
+		     BRASERO_BURN_ERROR_GENERAL,
+		     _("Libdvdcss could not be loaded properly"));
+	g_module_close (module);
+	return FALSE;
+}
+
+static gboolean
+brasero_dvdcss_thread_finished (gpointer data)
+{
+	gchar *image = NULL;
+	BraseroDvdcss *self = data;
+	BraseroDvdcssPrivate *priv;
+	BraseroTrackImage *track = NULL;
+
+	priv = BRASERO_DVDCSS_PRIVATE (self);
+	priv->thread_id = 0;
+
+	if (priv->error) {
+		GError *error;
+
+		error = priv->error;
+		priv->error = NULL;
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	track = brasero_track_image_new ();
+	brasero_job_get_image_output (BRASERO_JOB (self),
+				      &image,
+				      NULL);
+	brasero_track_image_set_source (track,
+					image,
+					NULL,
+					BRASERO_IMAGE_FORMAT_BIN);
+
+	brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
+
+	/* It's good practice to unref the track afterwards as we don't need it
+	 * anymore. BraseroTaskCtx refs it. */
+	g_object_unref (track);
+
+	brasero_job_finished_track (BRASERO_JOB (self));
+
+	return FALSE;
+}
+
+static BraseroBurnResult
+brasero_dvdcss_write_sector_to_fd (BraseroDvdcss *self,
+				   gpointer buffer,
+				   gint bytes_remaining)
+{
+	int fd;
+	gint bytes_written = 0;
+	BraseroDvdcssPrivate *priv;
+
+	priv = BRASERO_DVDCSS_PRIVATE (self);
+
+	brasero_job_get_fd_out (BRASERO_JOB (self), &fd);
+	while (bytes_remaining) {
+		gint written;
+
+		written = write (fd,
+				 buffer + bytes_written,
+				 bytes_remaining);
+
+		if (priv->cancel)
+			break;
+
+		if (written != bytes_remaining) {
+			if (errno != EINTR && errno != EAGAIN) {
+                                int errsv = errno;
+
+				/* unrecoverable error */
+				priv->error = g_error_new (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   _("Data could not be written (%s)"),
+							   g_strerror (errsv));
+				return BRASERO_BURN_ERR;
+			}
+
+			g_thread_yield ();
+		}
+
+		if (written > 0) {
+			bytes_remaining -= written;
+			bytes_written += written;
+		}
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+struct _BraseroScrambledSectorRange {
+	gint start;
+	gint end;
+};
+typedef struct _BraseroScrambledSectorRange BraseroScrambledSectorRange;
+
+static gboolean
+brasero_dvdcss_create_scrambled_sectors_map (GQueue *map,
+					     dvdcss_handle *handle,
+					     BraseroVolFile *parent,
+					     GError **error)
+{
+	GList *iter;
+
+	/* this allows to cache keys for encrypted files */
+	for (iter = parent->specific.dir.children; iter; iter = iter->next) {
+		BraseroVolFile *file;
+
+		file = iter->data;
+		if (!file->isdir) {
+			if (!strncmp (file->name + strlen (file->name) - 6, ".VOB", 4)) {
+				BraseroScrambledSectorRange *range;
+				GSList *extents;
+
+				range = g_new0 (BraseroScrambledSectorRange, 1);
+
+				/* take the first address for each extent of the file */
+				if (!file->specific.file.extents)
+					return FALSE;
+
+				for (extents = file->specific.file.extents; extents; extents = extents->next) {
+					BraseroVolFileExtent *extent;
+
+					extent = extents->data;
+					range->start = extent->block;
+					range->end = extent->block + BRASERO_BYTES_TO_SECTORS (extent->size, DVDCSS_BLOCK_SIZE);
+
+					g_queue_push_head (map, range);
+
+					if (dvdcss_seek (handle, range->start, DVDCSS_SEEK_KEY) != range->start) {
+						g_set_error (error,
+							     BRASERO_BURN_ERROR,
+							     BRASERO_BURN_ERROR_GENERAL,
+							     _("Error reading video DVD (%s)"),
+							     dvdcss_error (handle));
+						return FALSE;
+					}
+				}
+			}
+		}
+		else if (!brasero_dvdcss_create_scrambled_sectors_map (map, handle, file, error))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gint
+brasero_dvdcss_sort_ranges (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+	const BraseroScrambledSectorRange *range_a = a;
+	const BraseroScrambledSectorRange *range_b = b;
+
+	return range_a->start - range_b->start;
+}
+
+static gpointer
+brasero_dvdcss_write_image_thread (gpointer data)
+{
+	guchar buf [DVDCSS_BLOCK_SIZE * BRASERO_DVDCSS_I_BLOCKS];
+	BraseroScrambledSectorRange *range = NULL;
+	BraseroMedium *medium = NULL;
+	BraseroVolFile *files = NULL;
+	dvdcss_handle *handle = NULL;
+	BraseroDrive *drive = NULL;
+	BraseroDvdcssPrivate *priv;
+	gint64 written_sectors = 0;
+	BraseroDvdcss *self = data;
+	BraseroTrack *track = NULL;
+	guint64 remaining_sectors;
+	FILE *output_fd = NULL;
+	BraseroVolSrc *vol;
+	gint64 volume_size;
+	GQueue *map = NULL;
+
+	brasero_job_set_use_average_rate (BRASERO_JOB (self), TRUE);
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_ANALYSING,
+					_("Retrieving DVD keys"),
+					FALSE);
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+	priv = BRASERO_DVDCSS_PRIVATE (self);
+
+	/* get the contents of the DVD */
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+	vol = brasero_volume_source_open_file (brasero_drive_get_device (drive), &priv->error);
+	files = brasero_volume_get_files (vol,
+					  0,
+					  NULL,
+					  NULL,
+					  NULL,
+					  &priv->error);
+	brasero_volume_source_close (vol);
+	if (!files)
+		goto end;
+
+	medium = brasero_drive_get_medium (drive);
+	brasero_medium_get_data_size (medium, NULL, &volume_size);
+	if (volume_size == -1) {
+		priv->error = g_error_new (BRASERO_BURN_ERROR,
+					   BRASERO_BURN_ERROR_GENERAL,
+					   _("The size of the volume could not be retrieved"));
+		goto end;
+	}
+
+	/* create a handle/open DVD */
+	handle = dvdcss_open (brasero_drive_get_device (drive));
+	if (!handle) {
+		priv->error = g_error_new (BRASERO_BURN_ERROR,
+					   BRASERO_BURN_ERROR_GENERAL,
+					   _("Video DVD could not be opened"));
+		goto end;
+	}
+
+	/* look through the files to get the ranges of encrypted sectors
+	 * and cache the CSS keys while at it. */
+	map = g_queue_new ();
+	if (!brasero_dvdcss_create_scrambled_sectors_map (map, handle, files, &priv->error))
+		goto end;
+
+	g_queue_sort (map, brasero_dvdcss_sort_ranges, NULL);
+
+	brasero_volume_file_free (files);
+	files = NULL;
+
+	if (dvdcss_seek (handle, 0, DVDCSS_NOFLAGS) != 0) {
+		priv->error = g_error_new (BRASERO_BURN_ERROR,
+					   BRASERO_BURN_ERROR_GENERAL,
+					   _("Error while reading video DVD (%s)"),
+					   dvdcss_error (handle));
+		goto end;
+	}
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_DRIVE_COPY,
+					_("Copying Video DVD"),
+					FALSE);
+
+	brasero_job_start_progress (BRASERO_JOB (self), TRUE);
+
+	remaining_sectors = volume_size;
+	range = g_queue_pop_head (map);
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
+		gchar *output = NULL;
+
+		brasero_job_get_image_output (BRASERO_JOB (self), &output, NULL);
+		output_fd = fopen (output, "w");
+		g_free (output);
+
+		if (!output_fd) {
+			priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   g_strerror (errno));
+			goto end;
+		}
+	}
+
+	while (remaining_sectors) {
+		gint flag;
+		guint64 num_blocks, data_size;
+
+		if (priv->cancel)
+			break;
+
+		num_blocks = BRASERO_DVDCSS_I_BLOCKS;
+
+		/* see if we are approaching the end of the dvd */
+		if (num_blocks > remaining_sectors)
+			num_blocks = remaining_sectors;
+
+		/* see if we need to update the key */
+		if (!range || written_sectors < range->start) {
+			/* this is in a non scrambled sectors range */
+			flag = DVDCSS_NOFLAGS;
+	
+			/* we don't want to mix scrambled and non scrambled sectors */
+			if (range && written_sectors + num_blocks > range->start)
+				num_blocks = range->start - written_sectors;
+		}
+		else {
+			/* this is in a scrambled sectors range */
+			flag = DVDCSS_READ_DECRYPT;
+
+			/* see if we need to update the key */
+			if (written_sectors == range->start
+			&&  dvdcss_seek (handle, written_sectors, DVDCSS_SEEK_KEY) != written_sectors) {
+				priv->error = g_error_new (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   _("Error while reading video DVD (%s)"),
+							   dvdcss_error (handle));
+				break;
+			}
+
+			/* we don't want to mix scrambled and non scrambled sectors
+			 * NOTE: range->end address is the next non scrambled sector */
+			if (written_sectors + num_blocks > range->end)
+				num_blocks = range->end - written_sectors;
+
+			if (written_sectors + num_blocks == range->end) {
+				/* update to get the next range of scrambled sectors */
+				g_free (range);
+				range = g_queue_pop_head (map);
+			}
+		}
+
+		if (dvdcss_read (handle, buf, num_blocks, flag) != num_blocks) {
+			priv->error = g_error_new (BRASERO_BURN_ERROR,
+						   BRASERO_BURN_ERROR_GENERAL,
+						   _("Error while reading video DVD (%s)"),
+						   dvdcss_error (handle));
+			break;
+		}
+
+		data_size = num_blocks * DVDCSS_BLOCK_SIZE;
+		if (output_fd) {
+			if (fwrite (buf, 1, data_size, output_fd) != data_size) {
+                                int errsv = errno;
+
+				priv->error = g_error_new (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   _("Data could not be written (%s)"),
+							   g_strerror (errsv));
+				break;
+			}
+		}
+		else {
+			BraseroBurnResult result;
+
+			result = brasero_dvdcss_write_sector_to_fd (self,
+								    buf,
+								    data_size);
+			if (result != BRASERO_BURN_OK)
+				break;
+		}
+
+		written_sectors += num_blocks;
+		remaining_sectors -= num_blocks;
+		brasero_job_set_written_track (BRASERO_JOB (self), written_sectors * DVDCSS_BLOCK_SIZE);
+	}
+
+end:
+
+	if (range)
+		g_free (range);
+
+	if (handle)
+		dvdcss_close (handle);
+
+	if (files)
+		brasero_volume_file_free (files);
+
+	if (output_fd)
+		fclose (output_fd);
+
+	if (map) {
+		g_queue_foreach (map, (GFunc) g_free, NULL);
+		g_queue_free (map);
+	}
+
+	if (!priv->cancel)
+		priv->thread_id = g_idle_add (brasero_dvdcss_thread_finished, self);
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	priv->thread = NULL;
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_dvdcss_start (BraseroJob *job,
+		      GError **error)
+{
+	BraseroDvdcss *self;
+	BraseroJobAction action;
+	BraseroDvdcssPrivate *priv;
+	GError *thread_error = NULL;
+
+	self = BRASERO_DVDCSS (job);
+	priv = BRASERO_DVDCSS_PRIVATE (self);
+
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		guint64 blocks = 0;
+		BraseroTrack *track;
+
+		brasero_job_get_current_track (job, &track);
+		brasero_track_get_size (track, &blocks, NULL);
+		brasero_job_set_output_size_for_current_track (job,
+							       blocks,
+							       blocks * DVDCSS_BLOCK_SIZE);
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	if (priv->thread)
+		return BRASERO_BURN_RUNNING;
+
+	if (!brasero_dvdcss_library_init (error))
+		return BRASERO_BURN_ERR;
+
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_dvdcss_write_image_thread,
+					self,
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_dvdcss_stop_real (BraseroDvdcss *self)
+{
+	BraseroDvdcssPrivate *priv;
+
+	priv = BRASERO_DVDCSS_PRIVATE (self);
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread) {
+		priv->cancel = 1;
+		g_cond_wait (priv->cond, priv->mutex);
+		priv->cancel = 0;
+	}
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->thread_id) {
+		g_source_remove (priv->thread_id);
+		priv->thread_id = 0;
+	}
+
+	if (priv->error) {
+		g_error_free (priv->error);
+		priv->error = NULL;
+	}
+}
+
+static BraseroBurnResult
+brasero_dvdcss_stop (BraseroJob *job,
+		     GError **error)
+{
+	BraseroDvdcss *self;
+
+	self = BRASERO_DVDCSS (job);
+
+	brasero_dvdcss_stop_real (self);
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_dvdcss_class_init (BraseroDvdcssClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroDvdcssPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_dvdcss_finalize;
+
+	job_class->start = brasero_dvdcss_start;
+	job_class->stop = brasero_dvdcss_stop;
+}
+
+static void
+brasero_dvdcss_init (BraseroDvdcss *obj)
+{
+	BraseroDvdcssPrivate *priv;
+
+	priv = BRASERO_DVDCSS_PRIVATE (obj);
+
+	priv->mutex = g_mutex_new ();
+	priv->cond = g_cond_new ();
+}
+
+static void
+brasero_dvdcss_finalize (GObject *object)
+{
+	BraseroDvdcssPrivate *priv;
+
+	priv = BRASERO_DVDCSS_PRIVATE (object);
+
+	brasero_dvdcss_stop_real (BRASERO_DVDCSS (object));
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cond) {
+		g_cond_free (priv->cond);
+		priv->cond = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_dvdcss_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GError *gerror = NULL;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "dvdcss",
+			       _("Dvdcss allows to read css encrypted video DVDs"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* see if libdvdcss can be initted */
+	if (!brasero_dvdcss_library_init (&gerror)) {
+		if (gerror) {
+			*error = g_strdup (gerror->message);
+			g_error_free (gerror);
+		}
+		return BRASERO_BURN_ERR;
+	}
+
+	/* to my knowledge, css can only be applied to pressed discs so no need
+	 * to specify anything else but ROM */
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_IMAGE_FORMAT_BIN);
+	input = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+				       BRASERO_MEDIUM_DUAL_L|
+				       BRASERO_MEDIUM_ROM|
+				       BRASERO_MEDIUM_CLOSED|
+				       BRASERO_MEDIUM_HAS_DATA|
+				       BRASERO_MEDIUM_PROTECTED);
+
+	brasero_plugin_link_caps (plugin, output, input);
+
+	g_slist_free (input);
+	g_slist_free (output);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/dvdcss/burn-dvdcss.h b/plugins/dvdcss/burn-dvdcss.h
new file mode 100644
index 0000000..0ccae4c
--- /dev/null
+++ b/plugins/dvdcss/burn-dvdcss.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *            burn-dvdcss.h
+ *
+ *  lun aoû 21 14:34:32 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifndef BURN_DVDCSS_H
+#define BURN_DVDCSS_H
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVDCSS         (brasero_dvdcss_get_type ())
+#define BRASERO_DVDCSS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_DVDCSS, BraseroDvdcss))
+#define BRASERO_DVDCSS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_DVDCSS, BraseroDvdcssClass))
+#define BRASERO_IS_DVDCSS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_DVDCSS))
+#define BRASERO_IS_DVDCSS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_DVDCSS))
+#define BRASERO_DVDCSS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_DVDCSS, BraseroDvdcssClass))
+
+G_END_DECLS
+
+#endif /* BURN_DVDCSS_H */
diff --git a/plugins/growisofs/Makefile.am b/plugins/growisofs/Makefile.am
new file mode 100644
index 0000000..eb128f0
--- /dev/null
+++ b/plugins/growisofs/Makefile.am
@@ -0,0 +1,30 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_GCONF_CFLAGS)
+
+#growisofs
+growisofsdir = $(libdir)/brasero/plugins
+growisofs_LTLIBRARIES = libbrasero-growisofs.la
+libbrasero_growisofs_la_SOURCES = burn-growisofs.c burn-growisofs.h \
+	burn-growisofs-common.h 
+libbrasero_growisofs_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_growisofs_la_LDFLAGS = -module -avoid-version
+
+#dvdrwformat
+dvdrwformatdir = $(libdir)/brasero/plugins
+dvdrwformat_LTLIBRARIES = libbrasero-dvdrwformat.la
+libbrasero_dvdrwformat_la_SOURCES = burn-dvd-rw-format.c burn-dvd-rw-format.h
+libbrasero_dvdrwformat_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_dvdrwformat_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/growisofs/burn-dvd-rw-format.c b/plugins/growisofs/burn-dvd-rw-format.c
new file mode 100644
index 0000000..e0be9c5
--- /dev/null
+++ b/plugins/growisofs/burn-dvd-rw-format.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+ *            dvd-rw-format.c
+ *
+ *  sam fév  4 13:50:07 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include <gmodule.h>
+
+#include "burn-basics.h"
+#include "brasero-plugin.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-medium.h"
+#include "burn-dvd-rw-format.h"
+#include "burn-growisofs-common.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdRwFormat, brasero_dvd_rw_format, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_dvd_rw_format_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	int perc_1 = 0, perc_2 = 0;
+	float percent;
+
+	if (strstr (line, "unable to proceed with format")
+	||  strstr (line, "media is not blank")
+	||  strstr (line, "media is already formatted")
+	||  strstr (line, "you have the option to re-run")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_INVALID,
+						_("The disc is not supported")));
+		return BRASERO_BURN_OK;
+	}
+	else if (strstr (line, "unable to umount")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_DRIVE_BUSY,
+						_("The drive is busy")));
+		return BRASERO_BURN_OK;
+	}
+
+	if ((sscanf (line, "* blanking %d.%1d%%,", &perc_1, &perc_2) == 2)
+	||  (sscanf (line, "* formatting %d.%1d%%,", &perc_1, &perc_2) == 2)
+	||  (sscanf (line, "* relocating lead-out %d.%1d%%,", &perc_1, &perc_2) == 2))
+		brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+	else 
+		sscanf (line, "%d.%1d%%", &perc_1, &perc_2);
+
+	percent = (float) perc_1 / 100.0 + (float) perc_2 / 1000.0;
+	if (percent) {
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+		brasero_job_set_progress (BRASERO_JOB (process), percent);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_rw_format_set_argv (BraseroProcess *process,
+				GPtrArray *argv,
+				GError **error)
+{
+	BraseroMedia media;
+	BraseroBurnFlag flags;
+	gchar *device;
+
+	g_ptr_array_add (argv, g_strdup ("dvd+rw-format"));
+
+	/* undocumented option to show progress */
+	g_ptr_array_add (argv, g_strdup ("-gui"));
+
+	brasero_job_get_media (BRASERO_JOB (process), &media);
+	brasero_job_get_flags (BRASERO_JOB (process), &flags);
+        if (!BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_BDRE)
+	&&  !BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)
+	&&  !BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED)) {
+		gchar *blank_str;
+
+		/* This creates a sequential DVD-RW */
+		blank_str = g_strdup_printf ("-blank%s",
+					     (flags & BRASERO_BURN_FLAG_FAST_BLANK) ? "" : "=full");
+		g_ptr_array_add (argv, blank_str);
+	}
+	else {
+		gchar *format_str;
+
+		/* This creates a restricted overwrite DVD-RW or reformat a + */
+		format_str = g_strdup ("-force");
+		g_ptr_array_add (argv, format_str);
+	}
+
+	brasero_job_get_device (BRASERO_JOB (process), &device);
+	g_ptr_array_add (argv, device);
+
+	brasero_job_set_current_action (BRASERO_JOB (process),
+					BRASERO_BURN_ACTION_BLANKING,
+					NULL,
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_dvd_rw_format_class_init (BraseroDvdRwFormatClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+	object_class->finalize = brasero_dvd_rw_format_finalize;
+
+	process_class->set_argv = brasero_dvd_rw_format_set_argv;
+	process_class->stderr_func = brasero_dvd_rw_format_read_stderr;
+	process_class->post = brasero_job_finished_session;
+}
+
+static void
+brasero_dvd_rw_format_init (BraseroDvdRwFormat *obj)
+{ }
+
+static void
+brasero_dvd_rw_format_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_dvd_rw_format_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	/* NOTE: sequential and restricted are added later on demand */
+	const BraseroMedia media = BRASERO_MEDIUM_DVD|
+				   BRASERO_MEDIUM_DUAL_L|
+				   BRASERO_MEDIUM_REWRITABLE|
+				   BRASERO_MEDIUM_APPENDABLE|
+				   BRASERO_MEDIUM_CLOSED|
+				   BRASERO_MEDIUM_HAS_DATA|
+				   BRASERO_MEDIUM_UNFORMATTED|
+				   BRASERO_MEDIUM_BLANK;
+	BraseroBurnResult result;
+	GSList *output;
+
+	brasero_plugin_define (plugin,
+			       "dvd+rw-format",
+			       _("Dvd+rw-format erases and formats DVD+/-R(W)"),
+			       "Philippe Rouquier",
+			       4);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("dvd+rw-format", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	output = brasero_caps_disc_new (media|
+					BRASERO_MEDIUM_BDRE|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_SEQUENTIAL);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+					media|
+					BRASERO_MEDIUM_BDRE|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_RESTRICTED,
+					BRASERO_BURN_FLAG_NOGRACE,
+					BRASERO_BURN_FLAG_NONE);
+	brasero_plugin_set_blank_flags (plugin,
+					media|
+					BRASERO_MEDIUM_SEQUENTIAL,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_register_group (plugin, _(GROWISOFS_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/growisofs/burn-dvd-rw-format.h b/plugins/growisofs/burn-dvd-rw-format.h
new file mode 100644
index 0000000..9e25f46
--- /dev/null
+++ b/plugins/growisofs/burn-dvd-rw-format.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *            dvd-rw-format.h
+ *
+ *  sam fév  4 13:50:07 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef DVD_RW_FORMAT_H
+#define DVD_RW_FORMAT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVD_RW_FORMAT         (brasero_dvd_rw_format_get_type ())
+#define BRASERO_DVD_RW_FORMAT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_DVD_RW_FORMAT, BraseroDvdRwFormat))
+#define BRASERO_DVD_RW_FORMAT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_DVD_RW_FORMAT, BraseroDvdRwFormatClass))
+#define BRASERO_IS_DVD_RW_FORMAT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_DVD_RW_FORMAT))
+#define BRASERO_IS_DVD_RW_FORMAT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_DVD_RW_FORMAT))
+#define BRASERO_DVD_RW_FORMAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_DVD_RW_FORMAT, BraseroDvdRwFormatClass))
+
+G_END_DECLS
+
+#endif /* DVD_RW_FORMAT_H */
diff --git a/plugins/growisofs/burn-growisofs-common.h b/plugins/growisofs/burn-growisofs-common.h
new file mode 100644
index 0000000..6250ba5
--- /dev/null
+++ b/plugins/growisofs/burn-growisofs-common.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *            burn-growisofs-common.h
+ *
+ *  Mon Oct 29 12:37:28 2007
+ *  Copyright  2007  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef _BURN_GROWISOFS_COMMON_H
+#define _BURN_GROWISOFS_COMMON_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GROWISOFS_DESCRIPTION		N_("Growisofs burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_GROWISOFS_COMMON_H */
+
+ 
diff --git a/plugins/growisofs/burn-growisofs.c b/plugins/growisofs/burn-growisofs.c
new file mode 100644
index 0000000..a544445
--- /dev/null
+++ b/plugins/growisofs/burn-growisofs.c
@@ -0,0 +1,924 @@
+/***************************************************************************
+ *            growisofs.c
+ *
+ *  dim jan  15:8:51 6
+ *  Copyright  6  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version  of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.t, Fifth Floor
+ * 	Boston, MA  02110-1301, USA., Boston, MA 111-17, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h> 
+
+#include "brasero-units.h"
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-drive.h"
+#include "burn-growisofs.h"
+#include "burn-growisofs-common.h"
+#include "brasero-track-data.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroGrowisofs, brasero_growisofs, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct BraseroGrowisofsPrivate {
+	guint use_utf8:1;
+	guint use_genisoimage:1;
+  	guint use_dao:1;
+};
+typedef struct BraseroGrowisofsPrivate BraseroGrowisofsPrivate;
+
+#define BRASERO_GROWISOFS_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_GROWISOFS, BraseroGrowisofsPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_DAO_FLAG "/apps/brasero/config/dao_flag" 
+
+/* Process start */
+static BraseroBurnResult
+brasero_growisofs_read_stdout (BraseroProcess *process, const gchar *line)
+{
+	int perc_1, perc_2;
+	int speed_1, speed_2;
+	long long b_written, b_total;
+
+	/* Newer growisofs version have a different line pattern that shows
+	 * drive buffer filling. */
+	if (sscanf (line, "%10lld/%lld (%4d.%1d%%) @%2d.%1dx, remaining %*d:%*d",
+		    &b_written, &b_total, &perc_1, &perc_2, &speed_1, &speed_2) == 6) {
+		BraseroJobAction action;
+
+		brasero_job_get_action (BRASERO_JOB (process), &action);
+		if (action == BRASERO_JOB_ACTION_ERASE && b_written >= 65536) {
+			/* we nullified 65536 that's enough. A signal SIGTERM
+			 * will be sent in process.c. That's not the best way
+			 * to do it but it works. */
+			brasero_job_finished_session (BRASERO_JOB (process));
+			return BRASERO_BURN_OK;
+		}
+
+		brasero_job_set_written_session (BRASERO_JOB (process), b_written);
+		brasero_job_set_rate (BRASERO_JOB (process), (gdouble) (speed_1 * 10 + speed_2) / 10.0 * (gdouble) DVD_RATE);
+
+		if (action == BRASERO_JOB_ACTION_ERASE) {
+			brasero_job_set_current_action (BRASERO_JOB (process),
+							BRASERO_BURN_ACTION_BLANKING,
+							NULL,
+							FALSE);
+		}
+		else
+			brasero_job_set_current_action (BRASERO_JOB (process),
+							BRASERO_BURN_ACTION_RECORDING,
+							NULL,
+							FALSE);
+
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+	}
+	else if (strstr (line, "About to execute") || strstr (line, "Executing"))
+		brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_read_stderr (BraseroProcess *process, const gchar *line)
+{
+	int perc_1, perc_2;
+
+	if (sscanf (line, " %2d.%2d%% done, estimate finish", &perc_1, &perc_2) == 2) {
+		gdouble fraction;
+		BraseroBurnAction action;
+
+		fraction = (gdouble) ((gdouble) perc_1 +
+			   ((gdouble) perc_2 / (gdouble) 100.0)) /
+			   (gdouble) 100.0;
+
+		brasero_job_set_progress (BRASERO_JOB (process), fraction);
+
+		brasero_job_get_current_action (BRASERO_JOB (process), &action);
+		if (action == BRASERO_BURN_ACTION_BLANKING
+		&&  fraction >= 0.01) {
+			/* we nullified 1% of the medium (more than 65536)
+			 * that's enough to make the filesystem unusable and
+			 * looking blank. A signal SIGTERM will be sent to stop
+			 * us. */
+			brasero_job_finished_session (BRASERO_JOB (process));
+			return BRASERO_BURN_OK;
+		}
+
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_RECORDING,
+						NULL,
+						FALSE);
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+	}
+	else if (strstr (line, "Total extents scheduled to be written = ")) {
+		BraseroJobAction action;
+
+		line += strlen ("Total extents scheduled to be written = ");
+		brasero_job_get_action (BRASERO_JOB (process), &action);
+		if (action == BRASERO_JOB_ACTION_SIZE) {
+			gint64 sectors;
+
+			sectors = strtoll (line, NULL, 10);
+
+			/* NOTE: this has to be a multiple of 2048 */
+			brasero_job_set_output_size_for_current_track (BRASERO_JOB (process),
+								       sectors,
+								       sectors * 2048ULL);
+
+			/* we better tell growisofs to stop here as it returns 
+			 * a value of 1 when mkisofs is run with --print-size */
+			brasero_job_finished_session (BRASERO_JOB (process));
+		}
+	}
+	else if (strstr (line, "flushing cache") != NULL) {
+		brasero_job_set_progress (BRASERO_JOB (process), 1.0);
+		brasero_job_set_current_action (BRASERO_JOB (process),
+						BRASERO_BURN_ACTION_FIXATING,
+						NULL,
+						FALSE);
+	}
+	else if (strstr (line, "unable to open")
+	     ||  strstr (line, "unable to stat")
+	     ||  strstr (line, "unable to proceed with recording: unable to unmount")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_DRIVE_BUSY,
+							_("The drive is busy")));
+	}
+	else if (strstr (line, "not enough space available")
+	     ||  strstr (line, "end of user area encountered on this track")
+	     ||  strstr (line, "blocks are free")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_SPACE,
+						_("Not enough space available on the disc")));
+	}
+	else if (strstr (line, "Input/output error. Read error on old image")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+							_("Last session import failed")));
+	}
+	else if (strstr (line, "Unable to sort directory")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_WRITE_IMAGE,
+							_("An image could not be created")));
+	}
+	else if (strstr (line, "have the same joliet name")
+	     ||  strstr (line, "Joliet tree sort failed.")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_IMAGE_JOLIET,
+							_("An image could not be created")));
+	}
+	else if (strstr (line, "Incorrectly encoded string")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT_INVALID,
+							_("Some files have invalid filenames")));
+	}
+	else if (strstr (line, "Unknown charset")) {
+		brasero_job_error (BRASERO_JOB (process),
+				   g_error_new_literal (BRASERO_BURN_ERROR,
+							BRASERO_BURN_ERROR_INPUT_INVALID,
+							_("Unknown character encoding")));
+	}
+
+	/** REMINDER! removed messages:
+	   else if (strstr (line, ":-(") != NULL || strstr (line, "FATAL"))
+
+	   else if (strstr (line, "already carries isofs") && strstr (line, "FATAL:")) {
+		brasero_job_error (BRASERO_JOB (process), 
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_MEDIUM_INVALID,
+						_("The disc is already burnt")));
+	   }
+	**/
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_set_mkisofs_argv (BraseroGrowisofs *growisofs,
+				    GPtrArray *argv,
+				    GError **error)
+{
+	BraseroGrowisofsPrivate *priv;
+	BraseroTrack *track = NULL;
+	gchar *excluded_path = NULL;
+	gchar *grafts_path = NULL;
+	BraseroJobAction action;
+	BraseroBurnResult result;
+	BraseroImageFS fs_type;
+	gchar *emptydir = NULL;
+	gchar *videodir = NULL;
+
+	priv = BRASERO_GROWISOFS_PRIVATE (growisofs);
+
+	if (priv->use_genisoimage) {
+		BRASERO_JOB_LOG (growisofs, "Using genisoimage");
+	}
+	else {
+		BRASERO_JOB_LOG (growisofs, "Using mkisofs");
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-r"));
+
+	brasero_job_get_current_track (BRASERO_JOB (growisofs), &track);
+	fs_type = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+	if (fs_type & BRASERO_IMAGE_FS_JOLIET)
+		g_ptr_array_add (argv, g_strdup ("-J"));
+
+	if ((fs_type & BRASERO_IMAGE_FS_ISO)
+	&&  (fs_type & BRASERO_IMAGE_ISO_FS_LEVEL_3)) {
+		/* That's the safest option. A few OS don't support that though,
+		 * like MacOSX and freebsd.*/
+		g_ptr_array_add (argv, g_strdup ("-iso-level"));
+		g_ptr_array_add (argv, g_strdup ("3"));
+
+		/* NOTE: the following is specific to genisoimage
+		 * It allows to burn files over 4 GiB.
+		 * The only problem here is which are we using? mkisofs or
+		 * genisoimage? That's what we determined first. */
+		if (priv->use_genisoimage)
+			g_ptr_array_add (argv, g_strdup ("-allow-limited-size"));
+	}
+
+	if (fs_type & BRASERO_IMAGE_FS_UDF)
+		g_ptr_array_add (argv, g_strdup ("-udf"));
+
+	if (fs_type & BRASERO_IMAGE_FS_VIDEO) {
+		g_ptr_array_add (argv, g_strdup ("-dvd-video"));
+
+		result = brasero_job_get_tmp_dir (BRASERO_JOB (growisofs),
+						  &videodir,
+						  error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+
+	if (priv->use_utf8) {
+		g_ptr_array_add (argv, g_strdup ("-input-charset"));
+		g_ptr_array_add (argv, g_strdup ("utf8"));
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-graft-points"));
+
+	if (fs_type & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY)
+		g_ptr_array_add (argv, g_strdup ("-D"));	// This is dangerous the manual says but apparently it works well
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (growisofs),
+					   NULL,
+					   &grafts_path,
+					   error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		return result;
+	}
+
+	result = brasero_job_get_tmp_file (BRASERO_JOB (growisofs),
+					   NULL,
+					   &excluded_path,
+					   error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (grafts_path);
+		g_free (videodir);
+		return result;
+	}
+
+	result = brasero_job_get_tmp_dir (BRASERO_JOB (growisofs),
+					  &emptydir,
+					  error);
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		g_free (excluded_path);
+		return result;
+	}
+
+	result = brasero_track_data_get_paths (BRASERO_TRACK_DATA (track),
+					       (fs_type & BRASERO_IMAGE_FS_JOLIET) != 0,
+					       grafts_path,
+					       excluded_path,
+					       emptydir,
+					       videodir,
+					       error);
+	g_free (emptydir);
+
+	if (result != BRASERO_BURN_OK) {
+		g_free (videodir);
+		g_free (grafts_path);
+		g_free (excluded_path);
+		return result;
+	}
+
+	g_ptr_array_add (argv, g_strdup ("-path-list"));
+	g_ptr_array_add (argv, grafts_path);
+
+	g_ptr_array_add (argv, g_strdup ("-exclude-list"));
+	g_ptr_array_add (argv, excluded_path);
+
+	brasero_job_get_action (BRASERO_JOB (growisofs), &action);
+	if (action != BRASERO_JOB_ACTION_SIZE) {
+		gchar *label = NULL;
+
+		brasero_job_get_data_label (BRASERO_JOB (growisofs), &label);
+		if (label) {
+			g_ptr_array_add (argv, g_strdup ("-V"));
+			g_ptr_array_add (argv, label);
+		}
+
+		g_ptr_array_add (argv, g_strdup ("-A"));
+		g_ptr_array_add (argv, g_strdup_printf ("Brasero-%i.%i.%i",
+							BRASERO_MAJOR_VERSION,
+							BRASERO_MINOR_VERSION,
+							BRASERO_SUB));
+	
+		g_ptr_array_add (argv, g_strdup ("-sysid"));
+		g_ptr_array_add (argv, g_strdup ("LINUX"));
+	
+		/* FIXME! -sort is an interesting option allowing to decide where the 
+		 * files are written on the disc and therefore to optimize later reading */
+		/* FIXME: -hidden --hidden-list -hide-jolie -hide-joliet-list will allow to hide
+		 * some files when we will display the contents of a disc we will want to merge */
+		/* FIXME: support preparer publisher options */
+
+		g_ptr_array_add (argv, g_strdup ("-v"));
+	}
+	else {
+		/* we don't specify -q as there wouldn't be anything */
+		g_ptr_array_add (argv, g_strdup ("-print-size"));
+	}
+
+	if (videodir) {
+		g_ptr_array_add (argv, g_strdup ("-f"));
+		g_ptr_array_add (argv, videodir);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+/**
+ * Some info about use-the-force-luke options
+ * dry-run => stops after invoking mkisofs
+ * no_tty => avoids fatal error if an isofs exists and an image is piped
+ *  	  => skip the five seconds waiting
+ * 
+ */
+ 
+static BraseroBurnResult
+brasero_growisofs_set_argv_record (BraseroGrowisofs *growisofs,
+				   GPtrArray *argv,
+				   GError **error)
+{
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroBurnFlag flags;
+	guint64 sectors = 0;
+	gchar *device;
+	guint speed;
+
+	/* This seems to help to eject tray after burning (at least with mine) */
+	g_ptr_array_add (argv, g_strdup ("growisofs"));
+	g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=notray"));
+
+	brasero_job_get_flags (BRASERO_JOB (growisofs), &flags);
+	if (flags & BRASERO_BURN_FLAG_DUMMY)
+		g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=dummy"));
+
+	/* NOTE 1: dao is not a good thing if you want to make multisession
+	 * DVD+-R. It will close the disc. Which make sense since DAO means
+	 * Disc At Once. That's checked in burn-caps.c with coherency checks.
+	 * NOTE 2: dao is supported for DL DVD after 6.0 (think about that for
+	 * BurnCaps)
+	 * Moreover even for single session DVDs it doesn't work properly so
+	 * there is a workaround to turn it off entirely. */
+	if (flags & BRASERO_BURN_FLAG_DAO)
+		g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=dao"));
+
+	/* This is necessary for multi session discs when a new session starts
+	 * beyond the 4Gio boundary since it may not be readable afterward.
+	 * To work, this requires a kernel > 2.6.8.
+	 * FIXME: This would deserve a flag to warn the user. */
+	g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=4gms"));
+
+	if (!(flags & BRASERO_BURN_FLAG_MULTI)) {
+		/* This option seems to help creating DVD more compatible
+		 * with DVD readers.
+		 * NOTE: it doesn't work with DVD+RW and DVD-RW in restricted
+		 * overwrite mode */
+		g_ptr_array_add (argv, g_strdup ("-dvd-compat"));
+	}
+
+	brasero_job_get_speed (BRASERO_JOB (growisofs), &speed);
+	if (speed > 0)
+		g_ptr_array_add (argv, g_strdup_printf ("-speed=%d", speed));
+
+	/* see if we're asked to merge some new data: in this case we MUST have
+	 * a list of grafts. The image can't come through stdin or an already 
+	 * made image */
+	brasero_job_get_device (BRASERO_JOB (growisofs), &device);
+	brasero_job_get_action (BRASERO_JOB (growisofs), &action);
+	brasero_job_get_session_output_size (BRASERO_JOB (growisofs),
+					     &sectors,
+					     NULL);
+	if (sectors) {
+		/* NOTE: tracksize is in block number (2048 bytes) */
+		g_ptr_array_add (argv,
+				 g_strdup_printf ("-use-the-force-luke=tracksize:%"
+						  G_GINT64_FORMAT,
+						  sectors));
+	}
+
+	if (flags & BRASERO_BURN_FLAG_MERGE) {
+		g_ptr_array_add (argv, g_strdup ("-M"));
+		g_ptr_array_add (argv, device);
+		
+		/* this can only happen if source->type == BRASERO_TRACK_SOURCE_GRAFTS */
+		if (action == BRASERO_JOB_ACTION_SIZE)
+			g_ptr_array_add (argv, g_strdup ("-dry-run"));
+
+		result = brasero_growisofs_set_mkisofs_argv (growisofs, 
+							     argv,
+							     error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+	}
+	else {
+		BraseroTrack *current = NULL;
+
+		/* apparently we are not merging but growisofs will refuse to 
+		 * write a piped image if there is one already on the disc;
+		 * except with this option */
+		g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=tty"));
+
+		brasero_job_get_current_track (BRASERO_JOB (growisofs), &current);
+		if (brasero_job_get_fd_in (BRASERO_JOB (growisofs), NULL) == BRASERO_BURN_OK) {
+			/* set the buffer. NOTE: apparently this needs to be a power of 2 */
+			/* FIXME: is it right to mess with it ? 
+			   g_ptr_array_add (argv, g_strdup_printf ("-use-the-force-luke=bufsize:%im", 32)); */
+
+			if (!g_file_test ("/proc/self/fd/0", G_FILE_TEST_EXISTS)) {
+				g_set_error (error,
+					     BRASERO_BURN_ERROR,
+					     BRASERO_BURN_ERROR_FILE_NOT_FOUND,
+					     _("\"%s\" could not be found"),
+					     "/proc/self/fd/0");
+				return BRASERO_BURN_ERR;
+			}
+
+			/* FIXME: should we use DAO ? */
+			g_ptr_array_add (argv, g_strdup ("-Z"));
+			g_ptr_array_add (argv, g_strdup_printf ("%s=/proc/self/fd/0", device));
+			g_free (device);
+		}
+		else if (BRASERO_IS_TRACK_IMAGE (current)) {
+			gchar *localpath;
+
+			localpath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), FALSE);
+			if (!localpath) {
+				g_set_error (error,
+					     BRASERO_BURN_ERROR,
+					     BRASERO_BURN_ERROR_FILE_NOT_LOCAL,
+					     _("The file is not stored locally"));
+				return BRASERO_BURN_ERR;
+			}
+
+			g_ptr_array_add (argv, g_strdup ("-Z"));
+			g_ptr_array_add (argv, g_strdup_printf ("%s=%s",
+								device,
+								localpath));
+
+			g_free (device);
+			g_free (localpath);
+		}
+		else if (BRASERO_IS_TRACK_DATA (current)) {
+			g_ptr_array_add (argv, g_strdup ("-Z"));
+			g_ptr_array_add (argv, device);
+
+			/* this can only happen if source->type == BRASERO_TRACK_SOURCE_DATA */
+			if (action == BRASERO_JOB_ACTION_SIZE)
+				g_ptr_array_add (argv, g_strdup ("-dry-run"));
+
+			result = brasero_growisofs_set_mkisofs_argv (growisofs, 
+								     argv,
+								     error);
+			if (result != BRASERO_BURN_OK)
+				return result;
+		}
+		else
+			BRASERO_JOB_NOT_SUPPORTED (growisofs);
+	}
+
+	if (action == BRASERO_JOB_ACTION_SIZE)
+		brasero_job_set_current_action (BRASERO_JOB (growisofs),
+						BRASERO_BURN_ACTION_GETTING_SIZE,
+						NULL,
+						FALSE);
+	else
+		brasero_job_set_current_action (BRASERO_JOB (growisofs),
+						BRASERO_BURN_ACTION_START_RECORDING,
+						NULL,
+						FALSE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_set_argv_blank (BraseroGrowisofs *growisofs,
+				  GPtrArray *argv)
+{
+	BraseroBurnFlag flags;
+	gchar *device;
+	guint speed;
+
+	g_ptr_array_add (argv, g_strdup ("growisofs"));
+	brasero_job_get_flags (BRASERO_JOB (growisofs), &flags);
+	if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK))
+		BRASERO_JOB_NOT_SUPPORTED (growisofs);
+
+	g_ptr_array_add (argv, g_strdup ("-Z"));
+
+	/* NOTE: /dev/zero works but not /dev/null. Why ? */
+	brasero_job_get_device (BRASERO_JOB (growisofs), &device);
+	g_ptr_array_add (argv, g_strdup_printf ("%s=%s", device, "/dev/zero"));
+	g_free (device);
+
+	/* That should fix a problem where when the DVD had an isofs
+	 * growisofs warned that it had an isofs already on the disc */
+	g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=tty"));
+
+	/* set maximum write speed */
+	brasero_job_get_max_speed (BRASERO_JOB (growisofs), &speed);
+	g_ptr_array_add (argv, g_strdup_printf ("-speed=%d", speed));
+
+	/* we only need to nullify 64 KiB: we'll stop the process when
+	 * at least 65536 bytes have been written. We put a little more
+	 * so in stdout parsing function remaining time is not negative
+	 * if that's too fast. */
+	g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=tracksize:1024"));
+
+	if (flags & BRASERO_BURN_FLAG_DUMMY)
+		g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=dummy"));
+
+	brasero_job_set_current_action (BRASERO_JOB (growisofs),
+					BRASERO_BURN_ACTION_BLANKING,
+					NULL,
+					FALSE);
+	brasero_job_start_progress (BRASERO_JOB (growisofs), FALSE);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_set_argv (BraseroProcess *process,
+			    GPtrArray *argv,
+			    GError **error)
+{
+	BraseroJobAction action;
+	BraseroBurnResult result;
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		BraseroTrack *track = NULL;
+
+		/* only do it if that's DATA as input */
+		brasero_job_get_current_track (BRASERO_JOB (process), &track);
+		if (!BRASERO_IS_TRACK_DATA (track))
+			return BRASERO_BURN_NOT_SUPPORTED;
+
+		result = brasero_growisofs_set_argv_record (BRASERO_GROWISOFS (process),
+							    argv,
+							    error);
+	}
+	else if (action == BRASERO_JOB_ACTION_RECORD)
+		result = brasero_growisofs_set_argv_record (BRASERO_GROWISOFS (process),
+							    argv,
+							    error);
+	else if (action == BRASERO_JOB_ACTION_ERASE)
+		result = brasero_growisofs_set_argv_blank (BRASERO_GROWISOFS (process),
+							   argv);
+	else
+		BRASERO_JOB_NOT_READY (process);
+
+	return result;
+}
+static void
+brasero_growisofs_class_init (BraseroGrowisofsClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroGrowisofsPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_growisofs_finalize;
+
+	process_class->stdout_func = brasero_growisofs_read_stdout;
+	process_class->stderr_func = brasero_growisofs_read_stderr;
+	process_class->set_argv = brasero_growisofs_set_argv;
+	process_class->post = brasero_job_finished_session;
+}
+
+static void
+brasero_growisofs_init (BraseroGrowisofs *obj)
+{
+	BraseroGrowisofsPrivate *priv;
+	gchar *standard_error = NULL;
+	gchar *prog_name;
+	gboolean res;
+
+	priv = BRASERO_GROWISOFS_PRIVATE (obj);
+
+	/* this code (remotely) comes from ncb_mkisofs_supports_utf8 */
+	/* Added a way to detect whether we'll use mkisofs or genisoimage */
+
+	prog_name = g_find_program_in_path ("mkisofs");
+        if (prog_name && g_file_test (prog_name, G_FILE_TEST_IS_EXECUTABLE)) {
+		gchar *standard_output = NULL;
+
+		res = g_spawn_command_line_sync ("mkisofs -version",
+						 &standard_output,
+						 NULL,
+						 NULL,
+						 NULL);
+		if (res) {
+			/* Really make sure it is mkisofs and not a symlink */
+			if (standard_output && strstr (standard_output, "genisoimage"))
+				priv->use_genisoimage = TRUE;
+
+			if (standard_output)
+				g_free (standard_output);
+		}
+		else
+			priv->use_genisoimage = TRUE;
+	}
+	else
+		priv->use_genisoimage = TRUE;
+
+	/* Don't use BRASERO_JOB_LOG () here!! */
+	if (priv->use_genisoimage)
+		res = g_spawn_command_line_sync ("genisoimage -input-charset utf8",
+						 NULL,
+						 &standard_error,
+						 NULL,
+						 NULL);
+	else
+	  	res = g_spawn_command_line_sync ("mkisofs -input-charset utf8",
+						 NULL,
+						 &standard_error,
+						 NULL,
+						 NULL);
+
+	if (res && !g_strrstr (standard_error, "Unknown charset"))
+		priv->use_utf8 = TRUE;
+	else
+		priv->use_utf8 = FALSE;
+
+	g_free (standard_error);
+}
+
+static void
+brasero_growisofs_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_growisofs_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroPluginConfOption *use_dao;
+	gboolean use_dao_gconf_key;
+	BraseroBurnResult result;
+	GSList *input_symlink;
+	GSList *input_joliet;
+	GConfClient *client;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "growisofs",
+			       _("Growisofs burns DVDs"),
+			       "Philippe Rouquier",
+			       7);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("growisofs", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* growisofs can write images to any type of BD/DVD-R as long as it's blank */
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_BIN);
+
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+					BRASERO_MEDIUM_SRM|
+					BRASERO_MEDIUM_POW|
+					BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_DUAL_L|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_JUMP|
+					BRASERO_MEDIUM_SEQUENTIAL|
+					BRASERO_MEDIUM_WRITABLE|
+					BRASERO_MEDIUM_BLANK);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_SEQUENTIAL|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	/* and images to BD/DVD RW +/-(restricted) whatever the status */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+					BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_RAM|
+					BRASERO_MEDIUM_DUAL_L|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_HAS_DATA);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* for DATA type recording discs can be also appended */
+	input_joliet = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+					      BRASERO_IMAGE_FS_UDF|
+					      BRASERO_IMAGE_ISO_FS_LEVEL_3|
+					      BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+					      BRASERO_IMAGE_FS_JOLIET|
+					      BRASERO_IMAGE_FS_VIDEO);
+
+	input_symlink = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+					       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+					       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+					       BRASERO_IMAGE_FS_SYMLINK);
+
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+					BRASERO_MEDIUM_SRM|
+					BRASERO_MEDIUM_POW|
+					BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_DUAL_L|
+					BRASERO_MEDIUM_RAM|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_SEQUENTIAL|
+					BRASERO_MEDIUM_JUMP|
+					BRASERO_MEDIUM_WRITABLE|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_HAS_DATA);
+	brasero_plugin_link_caps (plugin, output, input_joliet);
+	brasero_plugin_link_caps (plugin, output, input_symlink);
+	g_slist_free (output);
+
+	/* growisofs has the possibility to record to closed BD/DVD+RW
+    	 * +/-restricted and to append some more data to them which makes them
+     	 * unique */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+					BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_DUAL_L|
+					BRASERO_MEDIUM_RAM|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA);
+
+	brasero_plugin_link_caps (plugin, output, input_joliet);
+	brasero_plugin_link_caps (plugin, output, input_symlink);
+	g_slist_free (output);
+	g_slist_free (input_joliet);
+	g_slist_free (input_symlink);
+
+	/* For DVD-RW sequential */
+	BRASERO_PLUGIN_ADD_STANDARD_DVDRW_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+	/* see NOTE for DVD-RW restricted overwrite */
+	BRASERO_PLUGIN_ADD_STANDARD_DVDRW_RESTRICTED_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+	/* DVD+R and DVD-R. DAO and growisofs doesn't always work well with
+	 * these types of media and with some drives. So don't allow it if the
+	 * workaround is set in GConf (and it should be by default). */
+	client = gconf_client_get_default ();
+	use_dao_gconf_key = gconf_client_get_bool (client,
+						   GCONF_KEY_DAO_FLAG,
+						   NULL);
+	g_object_unref (client);
+
+	if (use_dao_gconf_key == TRUE) {
+		BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+		BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+	}
+	else {
+		/* All above standard flags minus DAO flag support */
+		BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_DAO);
+		BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_DAO);
+	}
+
+	/* for DVD+RW */
+	BRASERO_PLUGIN_ADD_STANDARD_DVDRW_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+	/* for BD-RE */
+	BRASERO_PLUGIN_ADD_STANDARD_BD_RE_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+	/* blank caps for +/restricted RW */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_DUAL_L|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_BLANK);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+					BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_BLANK|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_CLOSED,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_FAST_BLANK);
+
+	/* again DVD+RW don't support dummy */
+	brasero_plugin_set_blank_flags (plugin,
+					BRASERO_MEDIUM_DVDRW_PLUS|
+					BRASERO_MEDIUM_DUAL_L|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_BLANK|
+					BRASERO_MEDIUM_UNFORMATTED|
+					BRASERO_MEDIUM_CLOSED,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_FAST_BLANK);
+
+	use_dao = brasero_plugin_conf_option_new (GCONF_KEY_DAO_FLAG,
+						  _("Allow DAO use"),
+						  BRASERO_PLUGIN_OPTION_BOOL);
+
+	brasero_plugin_add_conf_option (plugin, use_dao); 
+
+	brasero_plugin_register_group (plugin, _(GROWISOFS_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/growisofs/burn-growisofs.h b/plugins/growisofs/burn-growisofs.h
new file mode 100644
index 0000000..a3ab278
--- /dev/null
+++ b/plugins/growisofs/burn-growisofs.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            growisofs.h
+ *
+ *  dim jan 22 15:38:51 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef GROWISOFS_H
+#define GROWISOFS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_GROWISOFS         (brasero_growisofs_get_type ())
+#define BRASERO_GROWISOFS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_GROWISOFS, BraseroGrowisofs))
+#define BRASERO_GROWISOFS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_GROWISOFS, BraseroGrowisofsClass))
+#define BRASERO_IS_GROWISOFS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_GROWISOFS))
+#define BRASERO_IS_GROWISOFS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_GROWISOFS))
+#define BRASERO_GROWISOFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_GROWISOFS, BraseroGrowisofsClass))
+
+G_END_DECLS
+
+#endif /* GROWISOFS_H */
diff --git a/plugins/libburnia/Makefile.am b/plugins/libburnia/Makefile.am
new file mode 100644
index 0000000..22381b9
--- /dev/null
+++ b/plugins/libburnia/Makefile.am
@@ -0,0 +1,36 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_LIBISOFS_CFLAGS)			\
+	$(BRASERO_LIBBURN_CFLAGS)			\
+	$(BRASERO_GLIB_CFLAGS)
+
+#libburn
+libburndir = $(libdir)/brasero/plugins
+libburn_LTLIBRARIES = libbrasero-libburn.la
+libbrasero_libburn_la_SOURCES = burn-libburn.c 		\
+				burn-libburn.h		\
+				burn-libburn-common.c	\
+				burn-libburn-common.h  \
+				burn-libburnia.h 
+libbrasero_libburn_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBBURNIA_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_libburn_la_LDFLAGS = -module -avoid-version
+
+#libisofs (apparently libisofs needs one libburn function)
+libisofsdir = $(libdir)/brasero/plugins
+libisofs_LTLIBRARIES = libbrasero-libisofs.la
+libbrasero_libisofs_la_SOURCES = burn-libisofs.c burn-libisofs.h	\
+	burn-libburn-common.c burn-libburn-common.h			\
+	burn-libburnia.h 
+libbrasero_libisofs_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBBURNIA_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_libisofs_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/libburnia/burn-libburn-common.c b/plugins/libburnia/burn-libburn-common.c
new file mode 100644
index 0000000..2d036ee
--- /dev/null
+++ b/plugins/libburnia/burn-libburn-common.c
@@ -0,0 +1,377 @@
+/***************************************************************************
+ *            burn-libburn-common.c
+ *
+ *  mer aoû 30 16:35:40 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include "burn-basics.h"
+#include "burn-debug.h"
+#include "burn-job.h"
+#include "burn-libburn-common.h"
+
+#include <libburn/libburn.h>
+
+static void
+brasero_libburn_common_ctx_free_real (BraseroLibburnCtx *ctx)
+{
+	BRASERO_BURN_LOG ("Drive stopped");
+
+	if (ctx->disc) {
+		burn_disc_free (ctx->disc);
+		ctx->disc = NULL;
+	}
+
+	/* This must be done in this order since:
+	 * ctx->drive = ctx->drive_info->drive */
+
+	if (ctx->drive) {
+		burn_drive_release (ctx->drive, 0);
+		ctx->drive = NULL;
+	}
+
+	if (ctx->drive_info) {
+		burn_drive_info_free (ctx->drive_info);
+		ctx->drive_info = NULL;
+	}
+
+	g_free (ctx);
+
+	/* Since the library is not needed any more call burn_finish ().
+	 * NOTE: it itself calls burn_abort (). */
+	burn_finish ();
+}
+
+static gboolean
+brasero_libburn_common_ctx_wait_for_idle_drive (gpointer data)
+{
+	BraseroLibburnCtx *ctx = data;
+	enum burn_drive_status status;
+
+	/* try to properly cancel the drive */
+	status = burn_drive_get_status (ctx->drive, NULL);
+	if (status == BURN_DRIVE_WRITING || status == BURN_DRIVE_READING) {
+		BRASERO_BURN_LOG ("Cancelling operation");
+		burn_drive_cancel (ctx->drive);
+	}
+
+	if (status == BURN_DRIVE_GRABBING) {
+		/* This should probably never happen */
+		BRASERO_BURN_LOG ("Grabbing state, try to forget");
+		burn_drive_info_forget (ctx->drive_info, 1);
+	}
+
+	if (status != BURN_DRIVE_IDLE) {
+		BRASERO_BURN_LOG ("Drive not idle yet");
+		return TRUE;
+	}
+
+	brasero_libburn_common_ctx_free_real (ctx);
+	return FALSE;
+}
+
+void
+brasero_libburn_common_ctx_free (BraseroLibburnCtx *ctx)
+{
+	enum burn_drive_status status;
+
+	BRASERO_BURN_LOG ("Stopping Drive");
+
+	/* try to properly cancel the drive */
+	status = burn_drive_get_status (ctx->drive, NULL);
+	if (status == BURN_DRIVE_WRITING || status == BURN_DRIVE_READING) {
+		BRASERO_BURN_LOG ("Cancelling operation");
+		burn_drive_cancel (ctx->drive);
+	}
+
+	if (status == BURN_DRIVE_GRABBING) {
+		/* This should probably never happen */
+		BRASERO_BURN_LOG ("Grabbing state, try to forget");
+		burn_drive_info_forget (ctx->drive_info, 1);
+	}
+	
+	if (status != BURN_DRIVE_IDLE) {
+		/* otherwise wait for the drive to calm down */
+		BRASERO_BURN_LOG ("Drive not idle yet");
+		g_timeout_add (200,
+			       brasero_libburn_common_ctx_wait_for_idle_drive,
+			       ctx);
+		return;
+	}
+
+	brasero_libburn_common_ctx_free_real (ctx);
+}
+
+BraseroLibburnCtx *
+brasero_libburn_common_ctx_new (BraseroJob *job,
+				GError **error)
+{
+	gchar libburn_device [BURN_DRIVE_ADR_LEN];
+	BraseroLibburnCtx *ctx = NULL;
+	gchar *device;
+	int res;
+
+	/* initialize the library */
+	if (!burn_initialize ()) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Libburn library could not be initialized"));
+		return NULL;
+	}
+
+	/* We want all types of messages but not them printed */
+	burn_msgs_set_severities ("ALL", "NEVER", "");
+
+	/* we just want to scan the drive proposed by drive */
+	brasero_job_get_device (job, &device);
+	res = burn_drive_convert_fs_adr (device, libburn_device);
+	g_free (device);
+	if (res <= 0) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("The drive address could not be retrieved"));
+		return NULL;
+	}
+
+	ctx = g_new0 (BraseroLibburnCtx, 1);
+	res = burn_drive_scan_and_grab (&ctx->drive_info, libburn_device, 0);
+	BRASERO_JOB_LOG (job, "Drive (%s) init result = %d", libburn_device, res);
+	if (res <= 0) {
+		g_free (ctx);
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_DRIVE_BUSY,
+			     _("The drive is busy"));
+		return NULL;
+	}
+
+	ctx->drive = ctx->drive_info->drive;
+	return ctx;	
+}
+
+static gboolean
+brasero_libburn_common_process_message (BraseroJob *self)
+{
+	int ret;
+	GError *error;
+	int err_code = 0;
+	int err_errno = 0;
+	char err_sev [80];
+	char err_txt [BURN_MSGS_MESSAGE_LEN] = {0};
+
+	/* Get all messages, indicating an error */
+	memset (err_txt, 0, sizeof (err_txt));
+	ret = burn_msgs_obtain ("ALL",
+				&err_code,
+				err_txt,
+				&err_errno,
+				err_sev);
+	if (ret == 0)
+		return TRUE;
+
+	if (strcmp ("FATAL", err_sev)
+	&&  strcmp ("ABORT", err_sev)) {
+		/* libburn didn't reported any FATAL message but maybe it did
+		 * report some debugging output */
+		BRASERO_JOB_LOG (self, err_txt);
+	        return TRUE;
+	}
+
+	BRASERO_JOB_LOG (self, "Libburn reported an error %s", err_txt);
+	error = g_error_new (BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     err_txt);
+	brasero_job_error (BRASERO_JOB (self), error);
+	return FALSE;
+}
+
+static gboolean
+brasero_libburn_common_status_changed (BraseroJob *self,
+				       BraseroLibburnCtx *ctx,
+				       enum burn_drive_status status,
+				       struct burn_progress *progress)
+{
+	BraseroBurnAction action = BRASERO_BURN_ACTION_NONE;
+
+	switch (status) {
+		case BURN_DRIVE_WRITING:
+			/* we ignore it if it happens after leadout */
+			if (ctx->status == BURN_DRIVE_WRITING_LEADOUT
+			||  ctx->status == BURN_DRIVE_CLOSING_TRACK
+			||  ctx->status == BURN_DRIVE_CLOSING_SESSION)
+				return TRUE;
+
+			if (ctx->status == BURN_DRIVE_WRITING_LEADIN
+			||  ctx->status == BURN_DRIVE_WRITING_PREGAP) {
+				ctx->sectors += ctx->track_sectors;
+				ctx->track_sectors = progress->sectors;
+				ctx->track_num = progress->track;
+			}
+
+			action = BRASERO_BURN_ACTION_RECORDING;
+			brasero_job_set_dangerous (BRASERO_JOB (self), TRUE);
+			break;
+
+		case BURN_DRIVE_WRITING_LEADIN:		/* DAO */
+		case BURN_DRIVE_WRITING_PREGAP:		/* TAO */
+			ctx->has_leadin = 1;
+			action = BRASERO_BURN_ACTION_START_RECORDING;
+			brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+			break;
+
+		case BURN_DRIVE_WRITING_LEADOUT: 	/* DAO */
+		case BURN_DRIVE_CLOSING_TRACK:		/* TAO */
+		case BURN_DRIVE_CLOSING_SESSION:	/* Multisession end */
+			ctx->sectors += ctx->track_sectors;
+			ctx->track_sectors = progress->sectors;
+
+			action = BRASERO_BURN_ACTION_FIXATING;
+			brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+			break;
+
+		case BURN_DRIVE_ERASING:
+		case BURN_DRIVE_FORMATTING:
+			action = BRASERO_BURN_ACTION_BLANKING;
+			brasero_job_set_dangerous (BRASERO_JOB (self), TRUE);
+			break;
+
+		case BURN_DRIVE_IDLE:
+			/* That's the end of activity */
+			return FALSE;
+
+		case BURN_DRIVE_SPAWNING:
+			if (ctx->status == BURN_DRIVE_IDLE)
+				action = BRASERO_BURN_ACTION_START_RECORDING;
+			else
+				action = BRASERO_BURN_ACTION_FIXATING;
+			brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+			break;
+
+		case BURN_DRIVE_READING:
+			action = BRASERO_BURN_ACTION_DRIVE_COPY;
+			brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+			break;
+
+		default:
+			BRASERO_JOB_LOG (self, "Unknown drive state (%i)", status);
+			return TRUE;
+	}
+
+	ctx->status = status;
+	brasero_job_set_current_action (self,
+					action,
+					NULL,
+					FALSE);
+	return TRUE;
+}
+
+BraseroBurnResult
+brasero_libburn_common_status (BraseroJob *self,
+			       BraseroLibburnCtx *ctx)
+{
+	enum burn_drive_status status;
+	struct burn_progress progress;
+
+	/* see if there is any pending message */
+	if (!brasero_libburn_common_process_message (self))
+		return BRASERO_BURN_ERR;
+
+	if (!ctx->drive)
+		return BRASERO_BURN_ERR;
+
+	status = burn_drive_get_status (ctx->drive, &progress);
+
+	/* FIXME! for some operations that libburn can't perform the drive stays
+	 * idle and we've got no way to tell that kind of use case */
+	if (ctx->status != status) {
+		gboolean running;
+
+		running = brasero_libburn_common_status_changed (self,
+								 ctx,
+								 status,
+								 &progress);
+		if (!running)
+			return BRASERO_BURN_OK;
+	}
+
+	if (status == BURN_DRIVE_IDLE
+	||  status == BURN_DRIVE_SPAWNING
+	||  !progress.sectors
+	||  !progress.sector) {
+		ctx->sectors = 0;
+
+		ctx->track_num = progress.track;
+		ctx->track_sectors = progress.sectors;
+		return BRASERO_BURN_RETRY;
+	}
+
+	if (status == BURN_DRIVE_CLOSING_SESSION
+	||  status == BURN_DRIVE_WRITING_LEADOUT) {
+		brasero_job_set_progress (self, 1.0);
+	}
+	else if (status != BURN_DRIVE_ERASING
+	     &&  status != BURN_DRIVE_FORMATTING) {
+		gint64 cur_sector;
+
+		if (ctx->track_num != progress.track) {
+			gchar *string;
+
+			ctx->sectors += ctx->track_sectors;
+			ctx->track_sectors = progress.sectors;
+			ctx->track_num = progress.track;
+
+			string = g_strdup_printf (_("Writing track %02i"), progress.track);
+			brasero_job_set_current_action (self,
+							BRASERO_BURN_ACTION_RECORDING,
+							string,
+							TRUE);
+			g_free (string);
+		}
+
+		cur_sector = progress.sector + ctx->sectors;
+		brasero_job_set_written_session (self, (gint64) ((gint64) cur_sector * 2048ULL));
+	}
+	else {
+		gdouble fraction;
+
+		/* when erasing only set progress */
+		fraction = (gdouble) (progress.sector) /
+			   (gdouble) (progress.sectors);
+
+		brasero_job_set_progress (self, fraction);
+	}
+
+	brasero_job_start_progress (self, FALSE);
+	return BRASERO_BURN_RETRY;
+}
diff --git a/plugins/libburnia/burn-libburn-common.h b/plugins/libburnia/burn-libburn-common.h
new file mode 100644
index 0000000..4cf8b5c
--- /dev/null
+++ b/plugins/libburnia/burn-libburn-common.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *            burn-libburn-common.h
+ *
+ *  mer aoû 30 16:35:40 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef BURN_LIBBURN_COMMON_H
+#define BURN_LIBBURN_COMMON_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-job.h"
+
+#include <libburn/libburn.h>
+
+G_BEGIN_DECLS
+
+struct _BraseroLibburnCtx {
+	struct burn_drive_info *drive_info;
+	struct burn_drive *drive;
+	struct burn_disc *disc;
+
+	enum burn_drive_status status;
+
+	/* used detect track hops */
+	gint track_num;
+
+	/* used to report current written sector */
+	gint64 sectors;
+	gint64 cur_sector;
+	gint64 track_sectors;
+
+	gint has_leadin;
+};
+typedef struct _BraseroLibburnCtx BraseroLibburnCtx;
+
+BraseroLibburnCtx *
+brasero_libburn_common_ctx_new (BraseroJob *job,
+				GError **error);
+
+void
+brasero_libburn_common_ctx_free (BraseroLibburnCtx *ctx);
+
+BraseroBurnResult
+brasero_libburn_common_status (BraseroJob *job,
+			       BraseroLibburnCtx *ctx);
+
+G_END_DECLS
+
+#endif /* BURN_LIBBURN_COMMON_H */
diff --git a/plugins/libburnia/burn-libburn.c b/plugins/libburnia/burn-libburn.c
new file mode 100644
index 0000000..2725cbe
--- /dev/null
+++ b/plugins/libburnia/burn-libburn.c
@@ -0,0 +1,1026 @@
+/***************************************************************************
+ *            burn-libburn.c
+ *
+ *  lun aoû 21 14:33:24 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <libburn/libburn.h>
+
+#include "brasero-units.h"
+#include "burn-job.h"
+#include "burn-debug.h"
+#include "brasero-plugin-registration.h"
+#include "burn-libburn-common.h"
+#include "burn-libburnia.h"
+#include "burn-libburn.h"
+#include "brasero-track-image.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroLibburn, brasero_libburn, BRASERO_TYPE_JOB, BraseroJob);
+
+#define BRASERO_PVD_SIZE	32ULL * 2048ULL
+
+struct _BraseroLibburnPrivate {
+	BraseroLibburnCtx *ctx;
+
+	/* This buffer is used to capture Primary Volume Descriptor for
+	 * for overwrite media so as to "grow" the latter. */
+	unsigned char *pvd;
+
+	guint sig_handler:1;
+};
+typedef struct _BraseroLibburnPrivate BraseroLibburnPrivate;
+
+#define BRASERO_LIBBURN_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LIBBURN, BraseroLibburnPrivate))
+
+/**
+ * taken from scsi-get-configuration.h
+ */
+
+typedef enum {
+BRASERO_SCSI_PROF_DVD_RW_RESTRICTED	= 0x0013,
+BRASERO_SCSI_PROF_DVD_RW_PLUS		= 0x001A,
+} BraseroScsiProfile;
+
+static GObjectClass *parent_class = NULL;
+
+struct _BraseroLibburnSrcData {
+	int fd;
+	off_t size;
+
+	/* That's for the primary volume descriptor used for overwrite media */
+	int pvd_size;						/* in blocks */
+	unsigned char *pvd;
+
+	int read_pvd:1;
+};
+typedef struct _BraseroLibburnSrcData BraseroLibburnSrcData;
+
+static void
+brasero_libburn_src_free_data (struct burn_source *src)
+{
+	BraseroLibburnSrcData *data;
+
+	data = src->data;
+	close (data->fd);
+	g_free (data);
+}
+
+static off_t
+brasero_libburn_src_get_size (struct burn_source *src)
+{
+	BraseroLibburnSrcData *data;
+
+	data = src->data;
+	return data->size;
+}
+
+static int
+brasero_libburn_src_set_size (struct burn_source *src,
+			      off_t size)
+{
+	BraseroLibburnSrcData *data;
+
+	data = src->data;
+	data->size = size;
+	return 1;
+}
+
+/**
+ * This is a copy from burn-volume.c
+ */
+
+struct _BraseroVolDesc {
+	guchar type;
+	gchar id			[5];
+	guchar version;
+};
+typedef struct _BraseroVolDesc BraseroVolDesc;
+
+static int
+brasero_libburn_src_read_xt (struct burn_source *src,
+			     unsigned char *buffer,
+			     int size)
+{
+	int total;
+	BraseroLibburnSrcData *data;
+
+	data = src->data;
+
+	total = 0;
+	while (total < size) {
+		int bytes;
+
+		bytes = read (data->fd, buffer + total, size - total);
+		if (bytes < 0)
+			return -1;
+
+		if (!bytes)
+			break;
+
+		total += bytes;
+	}
+
+	/* copy the primary volume descriptor if a buffer is provided */
+	if (data->pvd
+	&& !data->read_pvd
+	&&  data->pvd_size < BRASERO_PVD_SIZE) {
+		unsigned char *current_pvd;
+		int i;
+
+		current_pvd = data->pvd + data->pvd_size;
+
+		/* read volume descriptors until we reach the end of the
+		 * buffer or find a volume descriptor set end. */
+		for (i = 0; (i << 11) < size && data->pvd_size + (i << 11) < BRASERO_PVD_SIZE; i ++) {
+			BraseroVolDesc *desc;
+
+			/* No need to check the first 16 blocks */
+			if ((data->pvd_size >> 11) + i < 16)
+				continue;
+
+			desc = (BraseroVolDesc *) (buffer + sizeof (BraseroVolDesc) * i);
+			if (desc->type == 255) {
+				data->read_pvd = 1;
+				BRASERO_BURN_LOG ("found volume descriptor set end");
+				break;
+			}
+		}
+
+		memcpy (current_pvd, buffer, i << 11);
+		data->pvd_size += i << 11;
+	}
+
+	return total;
+}
+
+static struct burn_source *
+brasero_libburn_create_fd_source (int fd,
+				  gint64 size,
+				  unsigned char *pvd)
+{
+	struct burn_source *src;
+	BraseroLibburnSrcData *data;
+
+	data = g_new0 (BraseroLibburnSrcData, 1);
+	data->fd = fd;
+	data->size = size;
+	data->pvd = pvd;
+
+	/* FIXME: this could be wrapped into a fifo source to get a smoother
+	 * data delivery. But that means another thread ... */
+	src = g_new0 (struct burn_source, 1);
+	src->version = 1;
+	src->refcount = 1;
+	src->read_xt = brasero_libburn_src_read_xt;
+	src->get_size = brasero_libburn_src_get_size;
+	src->set_size = brasero_libburn_src_set_size;
+	src->free_data = brasero_libburn_src_free_data;
+	src->data = data;
+
+	return src;
+}
+
+static BraseroBurnResult
+brasero_libburn_add_track (struct burn_session *session,
+			   struct burn_track *track,
+			   struct burn_source *src,
+			   gint mode,
+			   GError **error)
+{
+	if (burn_track_set_source (track, src) != BURN_SOURCE_OK) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Libburn track could not be created"));
+		return BRASERO_BURN_ERR;
+	}
+
+	if (!burn_session_add_track (session, track, BURN_POS_END)) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Libburn track could not be created"));
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_add_fd_track (struct burn_session *session,
+			      int fd,
+			      gint mode,
+			      gint64 size,
+			      unsigned char *pvd,
+			      GError **error)
+{
+	struct burn_source *src;
+	struct burn_track *track;
+	BraseroBurnResult result;
+
+	track = burn_track_create ();
+	burn_track_define_data (track, 0, 0, 0, mode);
+
+	src = brasero_libburn_create_fd_source (fd, size, pvd);
+	result = brasero_libburn_add_track (session, track, src, mode, error);
+
+	burn_source_free (src);
+	burn_track_free (track);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_add_file_track (struct burn_session *session,
+				const gchar *path,
+				gint mode,
+				off_t size,
+				unsigned char *pvd,
+				GError **error)
+{
+	int fd;
+
+	fd = open (path, O_RDONLY);
+	if (fd == -1) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     "%s",
+			     g_strerror (errno));
+		return BRASERO_BURN_ERR;
+	}
+
+	return brasero_libburn_add_fd_track (session, fd, mode, size, pvd, error);
+}
+
+static BraseroBurnResult
+brasero_libburn_setup_session_fd (BraseroLibburn *self,
+			          struct burn_session *session,
+			          GError **error)
+{
+	int fd;
+	guint64 size = 0;
+	BraseroLibburnPrivate *priv;
+	BraseroTrackType *type = NULL;
+	BraseroBurnResult result = BRASERO_BURN_OK;
+
+	priv = BRASERO_LIBBURN_PRIVATE (self);
+
+	brasero_job_get_fd_in (BRASERO_JOB (self), &fd);
+
+	/* need to find out what type of track the imager will output */
+	type = brasero_track_type_new ();
+	brasero_job_get_input_type (BRASERO_JOB (self), type);
+
+	if (brasero_track_type_get_has_image (type)) {
+		gint mode;
+
+		/* FIXME: implement other IMAGE types */
+		if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_BIN)
+			mode = BURN_MODE1;
+		else
+			mode = BURN_MODE1|BURN_MODE_RAW|BURN_SUBCODE_R96;
+
+		brasero_track_type_free (type);
+
+		brasero_job_get_session_output_size (BRASERO_JOB (self),
+						     NULL,
+						     &size);
+
+		result = brasero_libburn_add_fd_track (session,
+						       fd,
+						       mode,
+						       size,
+						       priv->pvd,
+						       error);
+	}
+	else if (brasero_track_type_get_has_stream (type)) {
+		GSList *tracks;
+
+		brasero_track_type_free (type);
+
+		brasero_job_get_tracks (BRASERO_JOB (self), &tracks);
+		for (; tracks; tracks = tracks->next) {
+			BraseroTrack *track;
+
+			track = tracks->data;
+			brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &size);
+			size = BRASERO_DURATION_TO_BYTES (size);
+
+			/* we dup the descriptor so the same 
+			 * will be shared by all tracks */
+			result = brasero_libburn_add_fd_track (session,
+							       dup (fd),
+							       BURN_AUDIO,
+							       size,
+							       NULL,
+							       error);
+			if (result != BRASERO_BURN_OK)
+				return result;
+		}
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_setup_session_file (BraseroLibburn *self, 
+				    struct burn_session *session,
+				    GError **error)
+{
+	BraseroLibburnPrivate *priv;
+	BraseroBurnResult result;
+	GSList *tracks = NULL;
+
+	priv = BRASERO_LIBBURN_PRIVATE (self);
+
+	/* create the track(s) */
+	result = BRASERO_BURN_OK;
+	brasero_job_get_tracks (BRASERO_JOB (self), &tracks);
+	for (; tracks; tracks = tracks->next) {
+		BraseroTrack *track;
+
+		track = tracks->data;
+		if (BRASERO_IS_TRACK_STREAM (track)) {
+			gchar *audiopath;
+			guint64 size;
+
+			audiopath = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+			brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &size);
+			size = BRASERO_DURATION_TO_BYTES (size);
+
+			result = brasero_libburn_add_file_track (session,
+								 audiopath,
+								 BURN_AUDIO,
+								 size,
+								 NULL,
+								 error);
+			if (result != BRASERO_BURN_OK)
+				break;
+		}
+		else if (BRASERO_IS_TRACK_IMAGE (track)) {
+			BraseroImageFormat format;
+			gchar *imagepath;
+			guint64 size;
+			gint mode;
+
+			format = brasero_track_image_get_format (BRASERO_TRACK_IMAGE (track));
+			if (format == BRASERO_IMAGE_FORMAT_BIN) {
+				mode = BURN_MODE1;
+				imagepath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			}
+			else if (format == BRASERO_IMAGE_FORMAT_NONE) {
+				mode = BURN_MODE1;
+				imagepath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+			}
+			else
+				BRASERO_JOB_NOT_SUPPORTED (self);
+
+			if (!imagepath)
+				return BRASERO_BURN_ERR;
+
+			result = brasero_track_get_size (track,
+							 NULL,
+							 &size);
+			if (result != BRASERO_BURN_OK)
+				return BRASERO_BURN_ERR;
+
+			result = brasero_libburn_add_file_track (session,
+								 imagepath,
+								 mode,
+								 size,
+								 priv->pvd,
+								 error);
+			g_free (imagepath);
+		}
+		else
+			BRASERO_JOB_NOT_SUPPORTED (self);
+	}
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_create_disc (BraseroLibburn *self,
+			     struct burn_disc **retval,
+			     GError **error)
+{
+	struct burn_disc *disc;
+	BraseroBurnResult result;
+	struct burn_session *session;
+
+	/* set the source image */
+	disc = burn_disc_create ();
+
+	/* create the session */
+	session = burn_session_create ();
+	burn_disc_add_session (disc, session, BURN_POS_END);
+	burn_session_free (session);
+
+	if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK)
+		result = brasero_libburn_setup_session_fd (self, session, error);
+	else
+		result = brasero_libburn_setup_session_file (self, session, error);
+
+	if (result != BRASERO_BURN_OK) {
+		burn_disc_free (disc);
+		return result;
+	}
+
+	*retval = disc;
+	return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_start_record (BraseroLibburn *self,
+			      GError **error)
+{
+	guint64 rate;
+	guint64 blocks = 0;
+	BraseroMedia media;
+	BraseroBurnFlag flags;
+	BraseroBurnResult result;
+	BraseroLibburnPrivate *priv;
+	struct burn_write_opts *opts;
+	gchar reason [BURN_REASONS_LEN];
+
+	priv = BRASERO_LIBBURN_PRIVATE (self);
+
+	/* if appending a DVD+-RW get PVD */
+	brasero_job_get_flags (BRASERO_JOB (self), &flags);
+	brasero_job_get_media (BRASERO_JOB (self), &media);
+
+	if (flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND)
+	&&  BRASERO_MEDIUM_RANDOM_WRITABLE (media)
+	&& (media & BRASERO_MEDIUM_HAS_DATA))
+		priv->pvd = g_new0 (unsigned char, BRASERO_PVD_SIZE);
+
+	result = brasero_libburn_create_disc (self, &priv->ctx->disc, error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* Note: we don't need to call burn_drive_get_status nor
+	 * burn_disc_get_status since we took care of the disc
+	 * checking thing earlier ourselves. Now there is a proper
+	 * disc and tray is locked. */
+	opts = burn_write_opts_new (priv->ctx->drive);
+	burn_write_opts_set_perform_opc (opts, 0);
+
+	if (flags & BRASERO_BURN_FLAG_DAO)
+		burn_write_opts_set_write_type (opts,
+						BURN_WRITE_SAO,
+						BURN_BLOCK_SAO);
+	else {
+		burn_write_opts_set_write_type (opts,
+						BURN_WRITE_TAO,
+						BURN_BLOCK_MODE1);
+
+		/* we also set the start block to write from if MERGE is set.
+		 * That only for random writable media; for other media libburn
+		 * handles all by himself where to start writing. */
+		if (BRASERO_MEDIUM_RANDOM_WRITABLE (media)
+		&& (flags & BRASERO_BURN_FLAG_MERGE)) {
+			guint64 address = 0;
+
+			brasero_job_get_next_writable_address (BRASERO_JOB (self), &address);
+
+			BRASERO_JOB_LOG (self, "Starting to write at block = %lli and byte %lli", address, address * 2048);
+			burn_write_opts_set_start_byte (opts, address * 2048);
+		}
+	}
+
+	if (!BRASERO_MEDIUM_RANDOM_WRITABLE (media))
+		burn_write_opts_set_multi (opts, (flags & BRASERO_BURN_FLAG_MULTI) != 0);
+
+	burn_write_opts_set_underrun_proof (opts, (flags & BRASERO_BURN_FLAG_BURNPROOF) != 0);
+	burn_write_opts_set_simulate (opts, (flags & BRASERO_BURN_FLAG_DUMMY) != 0);
+
+	brasero_job_get_rate (BRASERO_JOB (self), &rate);
+	burn_drive_set_speed (priv->ctx->drive, rate, 0);
+
+	if (burn_precheck_write (opts, priv->ctx->disc, reason, 0) < 1) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     reason);
+		return BRASERO_BURN_ERR;
+	}
+
+	/* If we're writing to a disc remember that the session can't be under
+	 * 300 sectors (= 614400 bytes) */
+	brasero_job_get_session_output_size (BRASERO_JOB (self), &blocks, NULL);
+	if (blocks < 300)
+		brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+							       300L - blocks,
+							       614400L - blocks * 2048);
+
+	if (!priv->sig_handler) {
+		burn_set_signal_handling ("brasero", NULL, 0);
+		priv->sig_handler = 1;
+	}
+
+	burn_disc_write (opts, priv->ctx->disc);
+	burn_write_opts_free (opts);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_start_erase (BraseroLibburn *self,
+			     GError **error)
+{
+	char reasons [BURN_REASONS_LEN];
+	struct burn_session *session;
+	struct burn_write_opts *opts;
+	BraseroLibburnPrivate *priv;
+	BraseroBurnResult result;
+	BraseroBurnFlag flags;
+	char prof_name [80];
+	int profile;
+	int fd;
+
+	priv = BRASERO_LIBBURN_PRIVATE (self);
+	if (burn_disc_get_profile (priv->ctx->drive, &profile, prof_name) <= 0) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_MEDIUM_INVALID,
+			     _("The disc is not supported"));
+		return BRASERO_BURN_ERR;
+	}
+
+	/* here we try to respect the current formatting of DVD-RW. For 
+	 * overwritable media fast option means erase the first 64 Kib
+	 * and long a forced reformatting */
+	brasero_job_get_flags (BRASERO_JOB (self), &flags);
+	if (profile == BRASERO_SCSI_PROF_DVD_RW_RESTRICTED) {
+		if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
+			/* leave libburn choose the best format */
+			if (!priv->sig_handler) {
+				burn_set_signal_handling ("brasero", NULL, 0);
+				priv->sig_handler = 1;
+			}
+
+			burn_disc_format (priv->ctx->drive,
+					  (off_t) 0,
+					  (1 << 4));
+			return BRASERO_BURN_OK;
+		}
+	}
+	else if (profile == BRASERO_SCSI_PROF_DVD_RW_PLUS) {
+		if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
+			/* Bit 2 is for format max available size
+			 * Bit 4 is enforce (re)-format if needed
+			 * 0x26 is DVD+RW format is to be set from bit 8
+			 * in the latter case bit 7 needs to be set as 
+			 * well. */
+			if (!priv->sig_handler) {
+				burn_set_signal_handling ("brasero", NULL, 0);
+				priv->sig_handler = 1;
+			}
+
+			burn_disc_format (priv->ctx->drive,
+					  (off_t) 0,
+					  (1 << 2)|(1 << 4));
+			return BRASERO_BURN_OK;
+		}
+	}
+	else if (burn_disc_erasable (priv->ctx->drive)) {
+		/* This is mainly for CDRW and sequential DVD-RW */
+		if (!priv->sig_handler) {
+			burn_set_signal_handling ("brasero", NULL, 0);
+			priv->sig_handler = 1;
+		}
+
+		burn_disc_erase (priv->ctx->drive, (flags & BRASERO_BURN_FLAG_FAST_BLANK) != 0);
+		return BRASERO_BURN_OK;
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	/* This is the "fast option": basically we only write 64 Kib of 0 from
+	 * /dev/null */
+	fd = open ("/dev/null", O_RDONLY);
+	if (fd == -1) {
+		int errnum = errno;
+
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: first %s is the filename, second %s is the error
+			      * generated from errno */
+			     _("\"%s\" could not be opened (%s)"),
+			     "/dev/null",
+			     g_strerror (errnum));
+		return BRASERO_BURN_ERR;
+	}
+
+	priv->ctx->disc = burn_disc_create ();
+
+	/* create the session */
+	session = burn_session_create ();
+	burn_disc_add_session (priv->ctx->disc, session, BURN_POS_END);
+	burn_session_free (session);
+
+	result = brasero_libburn_add_fd_track (session,
+					       fd,
+					       BURN_MODE1,
+					       65536,		/* 32 blocks */
+					       priv->pvd,
+					       error);
+	close (fd);
+
+	opts = burn_write_opts_new (priv->ctx->drive);
+	burn_write_opts_set_perform_opc (opts, 0);
+	burn_write_opts_set_underrun_proof (opts, 1);
+	burn_write_opts_set_simulate (opts, (flags & BRASERO_BURN_FLAG_DUMMY));
+
+	burn_drive_set_speed (priv->ctx->drive, burn_drive_get_write_speed (priv->ctx->drive), 0);
+	burn_write_opts_set_write_type (opts,
+					BURN_WRITE_TAO,
+					BURN_BLOCK_MODE1);
+
+	if (burn_precheck_write (opts, priv->ctx->disc, reasons, 0) <= 0) {
+		burn_write_opts_free (opts);
+
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: %s is the error returned by libburn */
+			     _("An internal error occured (%s)"),
+			     reasons);
+		return BRASERO_BURN_ERR;
+	}
+
+	if (!priv->sig_handler) {
+		burn_set_signal_handling ("brasero", NULL, 0);
+		priv->sig_handler = 1;
+	}
+
+	burn_disc_write (opts, priv->ctx->disc);
+	burn_write_opts_free (opts);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_start (BraseroJob *job,
+		       GError **error)
+{
+	BraseroLibburn *self;
+	BraseroJobAction action;
+	BraseroBurnResult result;
+	BraseroLibburnPrivate *priv;
+
+	self = BRASERO_LIBBURN (job);
+	priv = BRASERO_LIBBURN_PRIVATE (self);
+
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_RECORD) {
+		priv->ctx = brasero_libburn_common_ctx_new (job, error);
+		if (!priv->ctx)
+			return BRASERO_BURN_ERR;
+
+		result = brasero_libburn_start_record (self, error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		brasero_job_set_current_action (job,
+						BRASERO_BURN_ACTION_START_RECORDING,
+						NULL,
+						FALSE);
+	}
+	else if (action == BRASERO_JOB_ACTION_ERASE) {
+		priv->ctx = brasero_libburn_common_ctx_new (job, error);
+		if (!priv->ctx)
+			return BRASERO_BURN_ERR;
+
+		result = brasero_libburn_start_erase (self, error);
+		if (result != BRASERO_BURN_OK)
+			return result;
+
+		brasero_job_set_current_action (job,
+						BRASERO_BURN_ACTION_BLANKING,
+						NULL,
+						FALSE);
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_stop (BraseroJob *job,
+		      GError **error)
+{
+	BraseroLibburn *self;
+	BraseroLibburnPrivate *priv;
+
+	self = BRASERO_LIBBURN (job);
+	priv = BRASERO_LIBBURN_PRIVATE (self);
+
+	if (priv->sig_handler) {
+		priv->sig_handler = 0;
+		burn_set_signal_handling (NULL, NULL, 1);
+	}
+
+	if (priv->ctx) {
+		brasero_libburn_common_ctx_free (priv->ctx);
+		priv->ctx = NULL;
+	}
+
+	if (priv->pvd) {
+		g_free (priv->pvd);
+		priv->pvd = NULL;
+	}
+
+	if (BRASERO_JOB_CLASS (parent_class)->stop)
+		BRASERO_JOB_CLASS (parent_class)->stop (job, error);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_clock_tick (BraseroJob *job)
+{
+	BraseroLibburnPrivate *priv;
+	BraseroBurnResult result;
+	int ret;
+
+	priv = BRASERO_LIBBURN_PRIVATE (job);
+	result = brasero_libburn_common_status (job, priv->ctx);
+
+	if (result != BRASERO_BURN_OK)
+		return BRASERO_BURN_OK;
+
+	/* Double check that everything went well */
+	if (!burn_drive_wrote_well (priv->ctx->drive)) {
+		BRASERO_JOB_LOG (job, "Something went wrong");
+		brasero_job_error (job,
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_WRITE_MEDIUM,
+						_("An error occured while writing to disc")));
+		return BRASERO_BURN_OK;
+	}
+
+	/* That's finished */
+	if (!priv->pvd) {
+		brasero_job_set_dangerous (job, FALSE);
+		brasero_job_finished_session (job);
+		return BRASERO_BURN_OK;
+	}
+
+	/* In case we append data to a DVD+RW or DVD-RW
+	 * (restricted overwrite) medium , we're not
+	 * done since we need to overwrite the primary
+	 * volume descriptor at sector 0.
+	 * NOTE: This is a synchronous call but given the size of the buffer
+	 * that shouldn't block.
+	 * NOTE 2: in source we read the volume descriptors until we reached
+	 * either the end of the buffer or the volume descriptor set end. That's
+	 * kind of useless since for a DVD 16 blocks are written at a time. */
+	BRASERO_JOB_LOG (job, "Starting to overwrite primary volume descriptor");
+	ret = burn_random_access_write (priv->ctx->drive,
+					0,
+					(char*)priv->pvd,
+					BRASERO_PVD_SIZE,
+					0);
+	if (ret != 1) {
+		BRASERO_JOB_LOG (job, "Random write failed");
+		brasero_job_error (job,
+				   g_error_new (BRASERO_BURN_ERROR,
+						BRASERO_BURN_ERROR_WRITE_MEDIUM,
+						_("An error occured while writing to disc")));
+		return BRASERO_BURN_OK;
+	}
+
+	brasero_job_set_dangerous (job, FALSE);
+	brasero_job_finished_session (job);
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_libburn_class_init (BraseroLibburnClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroLibburnPrivate));
+
+	parent_class = g_type_class_peek_parent(klass);
+	object_class->finalize = brasero_libburn_finalize;
+
+	job_class->start = brasero_libburn_start;
+	job_class->stop = brasero_libburn_stop;
+	job_class->clock_tick = brasero_libburn_clock_tick;
+}
+
+static void
+brasero_libburn_init (BraseroLibburn *obj)
+{
+
+}
+
+static void
+brasero_libburn_finalize (GObject *object)
+{
+	BraseroLibburn *cobj;
+	BraseroLibburnPrivate *priv;
+
+	cobj = BRASERO_LIBBURN (object);
+	priv = BRASERO_LIBBURN_PRIVATE (cobj);
+
+	if (priv->ctx) {
+		brasero_libburn_common_ctx_free (priv->ctx);
+		priv->ctx = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_libburn_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	const BraseroMedia media_cd = BRASERO_MEDIUM_CD|
+				      BRASERO_MEDIUM_REWRITABLE|
+				      BRASERO_MEDIUM_WRITABLE|
+				      BRASERO_MEDIUM_BLANK|
+				      BRASERO_MEDIUM_APPENDABLE|
+				      BRASERO_MEDIUM_HAS_AUDIO|
+				      BRASERO_MEDIUM_HAS_DATA;
+	const BraseroMedia media_dvd_w = BRASERO_MEDIUM_DVD|
+					 BRASERO_MEDIUM_PLUS|
+					 BRASERO_MEDIUM_SEQUENTIAL|
+					 BRASERO_MEDIUM_WRITABLE|
+					 BRASERO_MEDIUM_APPENDABLE|
+					 BRASERO_MEDIUM_HAS_DATA|
+					 BRASERO_MEDIUM_BLANK;
+	const BraseroMedia media_dvd_rw = BRASERO_MEDIUM_DVD|
+					  BRASERO_MEDIUM_SEQUENTIAL|
+					  BRASERO_MEDIUM_REWRITABLE|
+					  BRASERO_MEDIUM_APPENDABLE|
+					  BRASERO_MEDIUM_HAS_DATA|
+					  BRASERO_MEDIUM_BLANK;
+	const BraseroMedia media_dvd_rw_plus = BRASERO_MEDIUM_DVD|
+					       BRASERO_MEDIUM_DUAL_L|
+					       BRASERO_MEDIUM_PLUS|
+					       BRASERO_MEDIUM_RESTRICTED|
+					       BRASERO_MEDIUM_REWRITABLE|
+					       BRASERO_MEDIUM_UNFORMATTED|
+					       BRASERO_MEDIUM_BLANK|
+					       BRASERO_MEDIUM_APPENDABLE|
+					       BRASERO_MEDIUM_CLOSED|
+					       BRASERO_MEDIUM_HAS_DATA;
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "libburn",
+			       _("Libburn burns CD(RW), DVD+/-(RW)"),
+			       "Philippe Rouquier",
+			       15);
+
+	/* libburn has no OVERBURN capabilities */
+
+	/* CD(R)W */
+	BRASERO_PLUGIN_ADD_STANDARD_CDR_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+	BRASERO_PLUGIN_ADD_STANDARD_CDRW_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+	/* audio support for CDs only */
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
+	
+	output = brasero_caps_disc_new (media_cd);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	/* Image support for CDs ... */
+	input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+					BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_IMAGE_FORMAT_BIN);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	/* ... and DVD-R and DVD+R ... */
+	output = brasero_caps_disc_new (media_dvd_w);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+	BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+	/* ... and DVD-RW (sequential) */
+	output = brasero_caps_disc_new (media_dvd_rw);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	BRASERO_PLUGIN_ADD_STANDARD_DVDRW_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+	/* for DVD+/-RW restricted */
+	output = brasero_caps_disc_new (media_dvd_rw_plus);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	BRASERO_PLUGIN_ADD_STANDARD_DVDRW_RESTRICTED_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+	BRASERO_PLUGIN_ADD_STANDARD_DVDRW_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+	/* add blank caps */
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_HAS_AUDIO|
+					BRASERO_MEDIUM_BLANK);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_PLUS|
+					BRASERO_MEDIUM_SEQUENTIAL|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+				        BRASERO_MEDIUM_BLANK);
+	brasero_plugin_blank_caps (plugin, output);
+	g_slist_free (output);
+
+	brasero_plugin_set_blank_flags (plugin,
+					BRASERO_MEDIUM_CD|
+					BRASERO_MEDIUM_DVD|
+					BRASERO_MEDIUM_SEQUENTIAL|
+					BRASERO_MEDIUM_RESTRICTED|
+					BRASERO_MEDIUM_REWRITABLE|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_HAS_AUDIO|
+					BRASERO_MEDIUM_UNFORMATTED|
+				        BRASERO_MEDIUM_BLANK,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	/* no dummy mode for DVD+RW */
+	brasero_plugin_set_blank_flags (plugin,
+					BRASERO_MEDIUM_DVDRW_PLUS|
+					BRASERO_MEDIUM_APPENDABLE|
+					BRASERO_MEDIUM_CLOSED|
+					BRASERO_MEDIUM_HAS_DATA|
+					BRASERO_MEDIUM_UNFORMATTED|
+				        BRASERO_MEDIUM_BLANK,
+					BRASERO_BURN_FLAG_NOGRACE|
+					BRASERO_BURN_FLAG_FAST_BLANK,
+					BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_register_group (plugin, _(LIBBURNIA_DESCRIPTION));
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/libburnia/burn-libburn.h b/plugins/libburnia/burn-libburn.h
new file mode 100644
index 0000000..b13f5b9
--- /dev/null
+++ b/plugins/libburnia/burn-libburn.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *            burn-libburn.h
+ *
+ *  lun aoû 21 14:33:24 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifndef BURN_LIBBURN_H
+#define BURN_LIBBURN_H
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LIBBURN         (brasero_libburn_get_type ())
+#define BRASERO_LIBBURN(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBBURN, BraseroLibburn))
+#define BRASERO_LIBBURN_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBBURN, BraseroLibburnClass))
+#define BRASERO_IS_LIBBURN(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBBURN))
+#define BRASERO_IS_LIBBURN_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBBURN))
+#define BRASERO_LIBBURN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBBURN, BraseroLibburnClass))
+
+G_END_DECLS
+
+#endif /* BURN_LIBBURN_H */
diff --git a/plugins/libburnia/burn-libburnia.h b/plugins/libburnia/burn-libburnia.h
new file mode 100644
index 0000000..2165e78
--- /dev/null
+++ b/plugins/libburnia/burn-libburnia.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ *            burn-libburnia.h
+ *
+ *  Mon Oct 29 12:30:42 2007
+ *  Copyright  2007  Philippe Rouquier
+ *  <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef _BURN_LIBBURNIA_H
+#define _BURN_LIBBURNIA_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define LIBBURNIA_DESCRIPTION		N_("Libburnia burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_LIBBURNIA_H */
+
+ 
diff --git a/plugins/libburnia/burn-libisofs.c b/plugins/libburnia/burn-libisofs.c
new file mode 100644
index 0000000..55402f9
--- /dev/null
+++ b/plugins/libburnia/burn-libisofs.c
@@ -0,0 +1,1074 @@
+/***************************************************************************
+ *            burn-libisofs.c
+ *
+ *  lun aoû 21 14:34:32 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <libisofs/libisofs.h>
+#include <libburn/libburn.h>
+
+#include "burn-libburnia.h"
+#include "burn-libisofs.h"
+#include "burn-job.h"
+#include "brasero-units.h"
+#include "brasero-plugin-registration.h"
+#include "burn-libburn-common.h"
+#include "brasero-track-data.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroLibisofs, brasero_libisofs, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroLibisofsPrivate {
+	struct burn_source *libburn_src;
+
+	/* that's for multisession */
+	BraseroLibburnCtx *ctx;
+
+	GError *error;
+	GThread *thread;
+	GMutex *mutex;
+	GCond *cond;
+	guint thread_id;
+
+	guint cancel:1;
+};
+typedef struct _BraseroLibisofsPrivate BraseroLibisofsPrivate;
+
+#define BRASERO_LIBISOFS_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LIBISOFS, BraseroLibisofsPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+brasero_libisofs_thread_finished (gpointer data)
+{
+	BraseroLibisofs *self = data;
+	BraseroLibisofsPrivate *priv;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	priv->thread_id = 0;
+	if (priv->error) {
+		GError *error;
+
+		error = priv->error;
+		priv->error = NULL;
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
+		BraseroTrackImage *track = NULL;
+		gchar *output = NULL;
+
+		/* Let's make a track */
+		track = brasero_track_image_new ();
+		brasero_job_get_image_output (BRASERO_JOB (self),
+					      &output,
+					      NULL);
+		brasero_track_image_set_source (track,
+						output,
+						NULL,
+						BRASERO_IMAGE_FORMAT_BIN);
+
+		brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
+
+		/* It's good practice to unref the track afterwards as we don't
+		 * need it anymore. BraseroBurnSession refs it. */
+		g_object_unref (track);
+	}
+
+	brasero_job_finished_track (BRASERO_JOB (self));
+	return FALSE;
+}
+
+static BraseroBurnResult
+brasero_libisofs_write_sector_to_fd (BraseroLibisofs *self,
+				     int fd,
+				     gpointer buffer,
+				     gint bytes_remaining)
+{
+	gint bytes_written = 0;
+	BraseroLibisofsPrivate *priv;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	while (bytes_remaining) {
+		gint written;
+
+		written = write (fd,
+				 buffer + bytes_written,
+				 bytes_remaining);
+
+		if (priv->cancel)
+			break;
+
+		if (written != bytes_remaining) {
+			if (errno != EINTR && errno != EAGAIN) {
+                                int errsv = errno;
+
+				/* unrecoverable error */
+				priv->error = g_error_new (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   _("Data could not be written (%s)"),
+							   g_strerror (errsv));
+				return BRASERO_BURN_ERR;
+			}
+
+			g_thread_yield ();
+		}
+
+		if (written > 0) {
+			bytes_remaining -= written;
+			bytes_written += written;
+		}
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_libisofs_write_image_to_fd_thread (BraseroLibisofs *self)
+{
+	const gint sector_size = 2048;
+	BraseroLibisofsPrivate *priv;
+	gint64 written_sectors = 0;
+	BraseroBurnResult result;
+	guchar buf [sector_size];
+	int fd = -1;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					NULL,
+					FALSE);
+
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+	brasero_job_get_fd_out (BRASERO_JOB (self), &fd);
+
+	BRASERO_JOB_LOG (self, "Writing to pipe");
+	while (priv->libburn_src->read_xt (priv->libburn_src, buf, sector_size) == sector_size) {
+		if (priv->cancel)
+			break;
+
+		result = brasero_libisofs_write_sector_to_fd (self,
+							      fd,
+							      buf,
+							      sector_size);
+		if (result != BRASERO_BURN_OK)
+			break;
+
+		written_sectors ++;
+		brasero_job_set_written_track (BRASERO_JOB (self), written_sectors << 11);
+	}
+}
+
+static void
+brasero_libisofs_write_image_to_file_thread (BraseroLibisofs *self)
+{
+	const gint sector_size = 2048;
+	BraseroLibisofsPrivate *priv;
+	gint64 written_sectors = 0;
+	guchar buf [sector_size];
+	gchar *output;
+	FILE *file;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	brasero_job_get_image_output (BRASERO_JOB (self), &output, NULL);
+	file = fopen (output, "w");
+	if (!file) {
+		int errnum = errno;
+
+		if (errno == EACCES)
+			priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_PERMISSION,
+							   _("You do not have the required permission to write at this location"));
+		else
+			priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   g_strerror (errnum));
+		return;
+	}
+
+	BRASERO_JOB_LOG (self, "writing to file %s", output);
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					NULL,
+					FALSE);
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+	while (priv->libburn_src->read_xt (priv->libburn_src, buf, sector_size) == sector_size) {
+		if (priv->cancel)
+			break;
+
+		if (fwrite (buf, 1, sector_size, file) != sector_size) {
+                        int errsv = errno;
+
+			priv->error = g_error_new (BRASERO_BURN_ERROR,
+						   BRASERO_BURN_ERROR_GENERAL,
+						   _("Data could not be written (%s)"),
+						   g_strerror (errsv));
+			break;
+		}
+
+		if (priv->cancel)
+			break;
+
+		written_sectors ++;
+		brasero_job_set_written_track (BRASERO_JOB (self), written_sectors << 11);
+	}
+
+	fclose (file);
+	file = NULL;
+}
+
+static gpointer
+brasero_libisofs_thread_started (gpointer data)
+{
+	BraseroLibisofsPrivate *priv;
+	BraseroLibisofs *self;
+
+	self = BRASERO_LIBISOFS (data);
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	BRASERO_JOB_LOG (self, "Entering thread");
+	if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK)
+		brasero_libisofs_write_image_to_fd_thread (self);
+	else
+		brasero_libisofs_write_image_to_file_thread (self);
+
+	if (!priv->cancel)
+		priv->thread_id = g_idle_add (brasero_libisofs_thread_finished, self);
+
+	BRASERO_JOB_LOG (self, "Getting out thread");
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	priv->thread = NULL;
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_libisofs_create_image (BraseroLibisofs *self,
+			       GError **error)
+{
+	BraseroLibisofsPrivate *priv;
+	GError *thread_error = NULL;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	if (priv->thread)
+		return BRASERO_BURN_RUNNING;
+
+	if (iso_init () < 0) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Libisofs could not be initialized."));
+		return BRASERO_BURN_ERR;
+	}
+
+	iso_set_msgs_severities ("NEVER", "ALL", "brasero (libisofs)");
+
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_libisofs_thread_started,
+					self,
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_libisofs_create_volume_thread_finished (gpointer data)
+{
+	BraseroLibisofs *self = data;
+	BraseroLibisofsPrivate *priv;
+	BraseroJobAction action;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	priv->thread_id = 0;
+	if (priv->error) {
+		GError *error;
+
+		error = priv->error;
+		priv->error = NULL;
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	brasero_job_get_action (BRASERO_JOB (self), &action);
+	if (action == BRASERO_JOB_ACTION_IMAGE) {
+		BraseroBurnResult result;
+		GError *error = NULL;
+
+		result = brasero_libisofs_create_image (self, &error);
+		if (error)
+		brasero_job_error (BRASERO_JOB (self), error);
+		else
+			return FALSE;
+	}
+
+	brasero_job_finished_track (BRASERO_JOB (self));
+	return FALSE;
+}
+
+static gint
+brasero_libisofs_sort_graft_points (gconstpointer a, gconstpointer b)
+{
+	const BraseroGraftPt *graft_a, *graft_b;
+	gint len_a, len_b;
+
+	graft_a = a;
+	graft_b = b;
+
+	/* we only want to know if:
+	 * - a is a parent of b (a > b, retval < 0) 
+	 * - b is a parent of a (b > a, retval > 0). */
+	len_a = strlen (graft_a->path);
+	len_b = strlen (graft_b->path);
+
+	return len_a - len_b;
+}
+
+static int 
+brasero_libisofs_import_read (IsoDataSource *src, uint32_t lba, uint8_t *buffer)
+{
+	struct burn_drive *d;
+	off_t data_count;
+	gint result;
+
+	d = (struct burn_drive*)src->data;
+
+	result = burn_read_data(d,
+				(off_t) lba * (off_t) 2048,
+				(char*)buffer, 
+				2048,
+				&data_count,
+				0);
+	if (result < 0 )
+		return -1; /* error */
+
+	return 1;
+}
+
+static int
+brasero_libisofs_import_open (IsoDataSource *src)
+{
+	return 1;
+}
+
+static int
+brasero_libisofs_import_close (IsoDataSource *src)
+{
+	return 1;
+}
+    
+static void 
+brasero_libisofs_import_free (IsoDataSource *src)
+{ }
+
+static BraseroBurnResult
+brasero_libisofs_import_last_session (BraseroLibisofs *self,
+				      IsoImage *image,
+				      IsoWriteOpts *wopts,
+				      GError **error)
+{
+	int result;
+	IsoReadOpts *opts;
+	BraseroMedia media;
+	IsoDataSource *src;
+	guint64 start_block;
+	guint64 session_block;
+	BraseroLibisofsPrivate *priv;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	priv->ctx = brasero_libburn_common_ctx_new (BRASERO_JOB (self), error);
+	if (!priv->ctx)
+		return BRASERO_BURN_ERR;
+
+	src = g_new0 (IsoDataSource, 1);
+	src->version = 0;
+	src->refcount = 1;
+	src->read_block = brasero_libisofs_import_read;
+	src->open = brasero_libisofs_import_open;
+	src->close = brasero_libisofs_import_close;
+	src->free_data = brasero_libisofs_import_free;
+	src->data = priv->ctx->drive;
+
+	result = iso_read_opts_new (&opts, 0);
+	if (result < 0) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Read options could not be created"));
+		return BRASERO_BURN_ERR;
+	}
+
+	brasero_job_get_last_session_address (BRASERO_JOB (self), &session_block);
+	iso_read_opts_set_start_block (opts, session_block);
+
+	/* import image */
+	result = iso_image_import (image, src, opts, NULL);
+	iso_data_source_unref (src);
+	iso_read_opts_free (opts);
+
+	/* release the drive */
+	if (priv->ctx) {
+		/* This may not be a good idea ...*/
+		brasero_libburn_common_ctx_free (priv->ctx);
+		priv->ctx = NULL;
+	}
+
+	if (result < 0) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+			     _("Last session import failed"));	
+		return BRASERO_BURN_ERR;
+	}
+
+	/* check is this is a DVD+RW */
+	brasero_job_get_next_writable_address (BRASERO_JOB (self), &start_block);
+
+	brasero_job_get_media (BRASERO_JOB (self), &media);
+	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)
+	||  BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED)
+	||  BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS_DL)) {
+		/* This is specific to overwrite media; the start address is the
+		 * size of all the previous data written */
+		BRASERO_JOB_LOG (self, "Growing image (start %i)", start_block);
+	}
+
+	/* set the start block for the multisession image */
+	iso_write_opts_set_ms_block (wopts, start_block);
+	iso_write_opts_set_appendable (wopts, 1);
+
+	iso_tree_set_replace_mode (image, ISO_REPLACE_ALWAYS);
+	return BRASERO_BURN_OK;
+}
+
+static gpointer
+brasero_libisofs_create_volume_thread (gpointer data)
+{
+	BraseroLibisofs *self = BRASERO_LIBISOFS (data);
+	BraseroLibisofsPrivate *priv;
+	BraseroTrack *track = NULL;
+	IsoWriteOpts *opts = NULL;
+	IsoImage *image = NULL;
+	BraseroBurnFlag flags;
+	GSList *grafts = NULL;
+	gchar *label = NULL;
+	gchar *publisher;
+	GSList *excluded;
+	GSList *iter;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	if (priv->libburn_src) {
+		burn_source_free (priv->libburn_src);
+		priv->libburn_src = NULL;
+	}
+
+	BRASERO_JOB_LOG (self, "creating volume");
+
+	/* create volume */
+	brasero_job_get_data_label (BRASERO_JOB (self), &label);
+	if (!iso_image_new (label, &image)) {
+		priv->error = g_error_new (BRASERO_BURN_ERROR,
+					   BRASERO_BURN_ERROR_GENERAL,
+					   _("Volume could not be created"));
+		g_free (label);
+		goto end;
+	}
+
+	publisher = g_strdup_printf ("Brasero-%i.%i.%i",
+				     BRASERO_MAJOR_VERSION,
+				     BRASERO_MINOR_VERSION,
+				     BRASERO_SUB);
+
+	if (label)
+		iso_image_set_volume_id (image, label);
+
+	iso_image_set_publisher_id (image, publisher);
+	iso_image_set_data_preparer_id (image, g_get_real_name ());
+
+	g_free (publisher);
+	g_free (label);
+
+	iso_write_opts_new (&opts, 2);
+
+	brasero_job_get_flags (BRASERO_JOB (self), &flags);
+	if (flags & BRASERO_BURN_FLAG_MERGE) {
+		BraseroBurnResult result;
+
+		result = brasero_libisofs_import_last_session (self,
+							       image,
+							       opts,
+							       &priv->error);
+		if (result != BRASERO_BURN_OK)
+			goto end;
+	}
+	else if (flags & BRASERO_BURN_FLAG_APPEND) {
+		guint64 start_block;
+
+		brasero_job_get_next_writable_address (BRASERO_JOB (self), &start_block);
+		iso_write_opts_set_ms_block (opts, start_block);
+	}
+
+
+	brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+	/* copy the list as we're going to reorder it */
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+	grafts = g_slist_copy (grafts);
+	grafts = g_slist_sort (grafts, brasero_libisofs_sort_graft_points);
+
+	/* add global exclusions */
+	for (excluded = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (track), FALSE);
+	     excluded; excluded = excluded->next) {
+		gchar *uri, *local;
+
+		uri = excluded->data;
+		local = g_filename_from_uri (uri, NULL, NULL);
+		iso_tree_add_exclude (image, local);
+		g_free (local);
+	}
+
+	for (iter = grafts; iter; iter = iter->next) {
+		BraseroGraftPt *graft;
+		gboolean is_directory;
+		gchar *path_parent;
+		gchar *path_name;
+		IsoNode *parent;
+
+		if (priv->cancel)
+			goto end;
+
+		graft = iter->data;
+
+		BRASERO_JOB_LOG (self,
+				 "Adding graft disc path = %s, URI = %s",
+				 graft->path,
+				 graft->uri);
+
+		/* search for parent node.
+		 * NOTE: because of mkisofs/genisoimage, we add a "/" at the end
+		 * directories. So make sure there isn't one when getting the 
+		 * parent path or g_path_get_dirname () will return the same
+		 * exact name */
+		if (g_str_has_suffix (graft->path, G_DIR_SEPARATOR_S)) {
+			gchar *tmp;
+
+			/* remove trailing "/" */
+			tmp = g_strdup (graft->path);
+			tmp [strlen (tmp) - 1] = '\0';
+			path_parent = g_path_get_dirname (tmp);
+			path_name = g_path_get_basename (tmp);
+			g_free (tmp);
+
+			is_directory = TRUE;
+		}
+		else {
+			path_parent = g_path_get_dirname (graft->path);
+			path_name = g_path_get_basename (graft->path);
+			is_directory = FALSE;
+		}
+
+		iso_tree_path_to_node (image, path_parent, &parent);
+		g_free (path_parent);
+
+		if (!parent) {
+			/* an error has occured, possibly libisofs hasn't been
+			 * able to find a parent for this node */
+			g_free (path_name);
+			priv->error = g_error_new (BRASERO_BURN_ERROR,
+						   BRASERO_BURN_ERROR_GENERAL,
+						   /* Translators: %s is the path */
+						   _("No parent could be found in the tree for the path \"%s\""),
+						   graft->path);
+			goto end;
+		}
+
+		BRASERO_JOB_LOG (self, "Found parent");
+
+		/* add the file/directory to the volume */
+		if (graft->uri) {
+			gchar *local_path;
+			IsoDirIter *sibling;
+
+			/* graft->uri can be a path or a URI */
+			if (graft->uri [0] == '/')
+				local_path = g_strdup (graft->uri);
+			else if (g_str_has_prefix (graft->uri, "file://"))
+				local_path = g_filename_from_uri (graft->uri, NULL, NULL);
+			else
+				local_path = NULL;
+
+			if (!local_path){
+				priv->error = g_error_new (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_FILE_NOT_LOCAL,
+							   _("The file is not stored locally"));
+				g_free (path_name);
+				goto end;
+			}
+
+			/* see if the node exists with the same name among the 
+			 * children of the parent directory. If there is a
+			 * sibling destroy it. */
+			sibling = NULL;
+			iso_dir_find_children (ISO_DIR (parent),
+					       iso_new_find_conditions_name (path_name),
+					       &sibling);
+			if (sibling) {
+				IsoNode *node;
+
+				BRASERO_JOB_LOG (self,
+						 "Looking for sibling for %s",
+						 path_name);
+
+				while (iso_dir_iter_next (sibling, &node) == 1) {
+					BRASERO_JOB_LOG (self,
+							 "Found sibling for %s: removing %x",
+							 path_name,
+							 iso_dir_iter_remove (sibling));
+				}
+
+				iso_dir_iter_free (sibling);
+			}
+
+			if  (is_directory) {
+				int result;
+				IsoDir *directory;
+
+				/* add directory node */
+				result = iso_tree_add_new_dir (ISO_DIR (parent), path_name, &directory);
+				if (result < 0) {
+					BRASERO_JOB_LOG (self,
+							 "ERROR %s %x",
+							 path_name,
+							 result);
+					priv->error = g_error_new (BRASERO_BURN_ERROR,
+								   BRASERO_BURN_ERROR_GENERAL,
+								   _("Libisofs reported an error while creating directory \"%s\""),
+								   graft->path);
+					g_free (path_name);
+					goto end;
+				}
+
+				/* add contents */
+				result = iso_tree_add_dir_rec (image, directory, local_path);
+				if (result < 0) {
+					BRASERO_JOB_LOG (self,
+							 "ERROR %s %x",
+							 path_name,
+							 result);
+					priv->error = g_error_new (BRASERO_BURN_ERROR,
+								   BRASERO_BURN_ERROR_GENERAL,
+								   _("Libisofs reported an error while adding contents to directory \"%s\" (%x)"),
+								   graft->path,
+								   result);
+					g_free (path_name);
+					goto end;
+				}
+			}
+			else {
+				IsoNode *node;
+				int err;
+
+				err = iso_tree_add_node (image,
+							 ISO_DIR (parent),
+							 local_path,
+							 &node);
+				if (err < 0) {
+					BRASERO_JOB_LOG (self,
+							 "ERROR %s %x",
+							 path_name,
+							 err);
+					priv->error = g_error_new (BRASERO_BURN_ERROR,
+								   BRASERO_BURN_ERROR_GENERAL,
+								   _("Libisofs reported an error while adding file at path \"%s\""),
+								   graft->path);
+					g_free (path_name);
+					goto end;
+				}
+
+				if (iso_node_get_name (node)
+				&&  strcmp (iso_node_get_name (node), path_name)) {
+					err = iso_node_set_name (node, path_name);
+					if (err < 0) {
+						BRASERO_JOB_LOG (self,
+								 "ERROR %s %x",
+								 path_name,
+								 err);
+						priv->error = g_error_new (BRASERO_BURN_ERROR,
+									   BRASERO_BURN_ERROR_GENERAL,
+									   _("Libisofs reported an error while adding file at path \"%s\""),
+									   graft->path);
+						g_free (path_name);
+						goto end;
+					}
+				}
+			}
+
+			g_free (local_path);
+		}
+		else if (iso_tree_add_new_dir (ISO_DIR (parent), path_name, NULL) < 0) {
+			priv->error = g_error_new (BRASERO_BURN_ERROR,
+						   BRASERO_BURN_ERROR_GENERAL,
+						   _("Libisofs reported an error while creating directory \"%s\""),
+						   graft->path);
+			g_free (path_name);
+			goto end;
+
+		}
+
+		g_free (path_name);
+	}
+
+
+end:
+
+	if (grafts)
+		g_slist_free (grafts);
+
+	if (!priv->error && !priv->cancel) {
+		gint64 size;
+		BraseroImageFS image_fs;
+
+		image_fs = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+
+		if ((image_fs & BRASERO_IMAGE_FS_ISO)
+		&&  (image_fs & BRASERO_IMAGE_ISO_FS_LEVEL_3))
+			iso_write_opts_set_iso_level (opts, 3);
+		else
+			iso_write_opts_set_iso_level (opts, 2);
+
+		iso_write_opts_set_rockridge (opts, 1);
+		iso_write_opts_set_joliet (opts, (image_fs & BRASERO_IMAGE_FS_JOLIET) != 0);
+		iso_write_opts_set_allow_deep_paths (opts, (image_fs & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY) != 0);
+
+		if (iso_image_create_burn_source (image, opts, &priv->libburn_src) >= 0) {
+			size = priv->libburn_src->get_size (priv->libburn_src);
+			brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+								       BRASERO_BYTES_TO_SECTORS (size, 2048),
+								       size);
+		}
+	}
+
+	if (opts)
+		iso_write_opts_free (opts);
+
+	if (image)
+		iso_image_unref (image);
+
+	if (!priv->cancel)
+		priv->thread_id = g_idle_add (brasero_libisofs_create_volume_thread_finished, self);
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	priv->thread = NULL;
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_libisofs_create_volume (BraseroLibisofs *self, GError **error)
+{
+	BraseroLibisofsPrivate *priv;
+	GError *thread_error = NULL;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+	if (priv->thread)
+		return BRASERO_BURN_RUNNING;
+
+	if (iso_init () < 0) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Libisofs could not be initialized."));
+		return BRASERO_BURN_ERR;
+	}
+
+	iso_set_msgs_severities ("NEVER", "ALL", "brasero (libisofs)");
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_libisofs_create_volume_thread,
+					self,
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libisofs_start (BraseroJob *job,
+			GError **error)
+{
+	BraseroLibisofs *self;
+	BraseroJobAction action;
+	BraseroLibisofsPrivate *priv;
+
+	self = BRASERO_LIBISOFS (job);
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		brasero_job_set_current_action (BRASERO_JOB (self),
+						BRASERO_BURN_ACTION_GETTING_SIZE,
+						NULL,
+						FALSE);
+		return brasero_libisofs_create_volume (self, error);
+	}
+
+	/* we need the source before starting anything */
+	if (!priv->libburn_src)
+		return brasero_libisofs_create_volume (self, error);
+
+	return brasero_libisofs_create_image (self, error);
+}
+
+static void
+brasero_libisofs_stop_real (BraseroLibisofs *self)
+{
+	BraseroLibisofsPrivate *priv;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	/* NOTE: this can only happen when we're preparing the volumes for a
+	 * multi session disc. At this point we're only running to get the size
+	 * of the future volume and we can't race with libburn plugin that isn't
+	 * operating at this stage. */
+	if (priv->ctx) {
+		brasero_libburn_common_ctx_free (priv->ctx);
+		priv->ctx = NULL;
+	}
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread) {
+		if (priv->libburn_src)
+			priv->libburn_src->cancel (priv->libburn_src);
+
+		priv->cancel = 1;
+		g_cond_wait (priv->cond, priv->mutex);
+		priv->cancel = 0;
+	}
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->thread_id) {
+		g_source_remove (priv->thread_id);
+		priv->thread_id = 0;
+	}
+
+	if (priv->error) {
+		g_error_free (priv->error);
+		priv->error = NULL;
+	}
+}
+
+static BraseroBurnResult
+brasero_libisofs_stop (BraseroJob *job,
+		       GError **error)
+{
+	BraseroLibisofs *self;
+
+	self = BRASERO_LIBISOFS (job);
+	brasero_libisofs_stop_real (self);
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_libisofs_class_init (BraseroLibisofsClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroLibisofsPrivate));
+
+	parent_class = g_type_class_peek_parent(klass);
+	object_class->finalize = brasero_libisofs_finalize;
+
+	job_class->start = brasero_libisofs_start;
+	job_class->stop = brasero_libisofs_stop;
+}
+
+static void
+brasero_libisofs_init (BraseroLibisofs *obj)
+{
+	BraseroLibisofsPrivate *priv;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (obj);
+	priv->mutex = g_mutex_new ();
+	priv->cond = g_cond_new ();
+}
+
+static void
+brasero_libisofs_clean_output (BraseroLibisofs *self)
+{
+	BraseroLibisofsPrivate *priv;
+
+	priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+	if (priv->libburn_src) {
+		burn_source_free (priv->libburn_src);
+		priv->libburn_src = NULL;
+	}
+
+	/* close libisofs library */
+	iso_finish ();
+}
+
+static void
+brasero_libisofs_finalize (GObject *object)
+{
+	BraseroLibisofs *cobj;
+	BraseroLibisofsPrivate *priv;
+
+	cobj = BRASERO_LIBISOFS (object);
+	priv = BRASERO_LIBISOFS_PRIVATE (object);
+
+	brasero_libisofs_stop_real (cobj);
+	brasero_libisofs_clean_output (cobj);
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cond) {
+		g_cond_free (priv->cond);
+		priv->cond = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_libisofs_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *output;
+	GSList *input;
+
+	brasero_plugin_define (plugin,
+			       "libisofs",
+			       _("Libisofs creates disc images from files"),
+			       "Philippe Rouquier",
+			       0);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CDR|
+				  BRASERO_MEDIUM_CDRW|
+				  BRASERO_MEDIUM_DVDR|
+				  BRASERO_MEDIUM_DVDRW|
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_AUDIO|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_RESTRICTED|
+				  BRASERO_MEDIUM_DUAL_L|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_APPEND|
+				  BRASERO_BURN_FLAG_MERGE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_IMAGE_FORMAT_BIN);
+
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+				       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+				       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+				       BRASERO_IMAGE_FS_JOLIET);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+				       BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+				       BRASERO_IMAGE_ISO_FS_LEVEL_3|
+				       BRASERO_IMAGE_FS_SYMLINK);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	g_slist_free (output);
+
+	brasero_plugin_register_group (plugin, _(LIBBURNIA_DESCRIPTION));
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/libburnia/burn-libisofs.h b/plugins/libburnia/burn-libisofs.h
new file mode 100644
index 0000000..1224e96
--- /dev/null
+++ b/plugins/libburnia/burn-libisofs.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *            burn-libisofs.h
+ *
+ *  lun aoû 21 14:34:32 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifndef BURN_LIBISOFS_H
+#define BURN_LIBISOFS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LIBISOFS         (brasero_libisofs_get_type ())
+#define BRASERO_LIBISOFS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBISOFS, BraseroLibisofs))
+#define BRASERO_LIBISOFS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBISOFS, BraseroLibisofsClass))
+#define BRASERO_IS_LIBISOFS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBISOFS))
+#define BRASERO_IS_LIBISOFS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBISOFS))
+#define BRASERO_LIBISOFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBISOFS, BraseroLibisofsClass))
+
+G_END_DECLS
+
+#endif /* BURN_LIBISOFS_H */
diff --git a/plugins/libburnia/burn-libread-disc.h b/plugins/libburnia/burn-libread-disc.h
new file mode 100644
index 0000000..3a08a95
--- /dev/null
+++ b/plugins/libburnia/burn-libread-disc.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *            burn-libread-disc.h
+ *
+ *  ven aoû 25 22:15:11 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef BURN_LIBREAD_DISC_H
+#define BURN_LIBREAD_DISC_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-libburn-common.h"
+
+#ifdef HAVE_LIBBURN
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LIBREAD_DISC         (brasero_libread_disc_get_type ())
+#define BRASERO_LIBREAD_DISC(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBREAD_DISC, BraseroLibreadDisc))
+#define BRASERO_LIBREAD_DISC_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBREAD_DISC, BraseroLibreadDiscClass))
+#define BRASERO_IS_LIBREAD_DISC(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBREAD_DISC))
+#define BRASERO_IS_LIBREAD_DISC_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBREAD_DISC))
+#define BRASERO_LIBREAD_DISC_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBREAD_DISC, BraseroLibreadDiscClass))
+
+typedef struct _BraseroLibreadDisc BraseroLibreadDisc;
+typedef struct _BraseroLibreadDiscPrivate BraseroLibreadDiscPrivate;
+typedef struct _BraseroLibreadDiscClass BraseroLibreadDiscClass;
+
+struct _BraseroLibreadDisc {
+	BraseroLibburnCommon parent;
+	BraseroLibreadDiscPrivate *priv;
+};
+
+struct _BraseroLibreadDiscClass {
+	BraseroLibburnCommonClass parent_class;
+};
+
+GType brasero_libread_disc_get_type ();
+BraseroLibreadDisc *brasero_libread_disc_new ();
+
+G_END_DECLS
+
+#else
+
+#define BRASERO_TYPE_LIBREAD_DISC G_TYPE_NONE
+
+#endif /* HAVE_LIBBURN*/
+
+#endif /* BURN_LIBREAD_DISC_H */
diff --git a/plugins/local-track/Makefile.am b/plugins/local-track/Makefile.am
new file mode 100644
index 0000000..fad0244
--- /dev/null
+++ b/plugins/local-track/Makefile.am
@@ -0,0 +1,31 @@
+
+INCLUDES = \
+	-I$(top_srcdir)						\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/			\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)					\
+	$(BRASERO_GLIB_CFLAGS)					\
+	$(BRASERO_GIO_CFLAGS)
+
+#local-track
+local_trackdir = $(libdir)/brasero/plugins
+local_track_LTLIBRARIES = libbrasero-local-track.la
+
+libbrasero_local_track_la_SOURCES = burn-local-image.c burn-local-image.h
+libbrasero_local_track_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GIO_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_local_track_la_LDFLAGS = -module -avoid-version
+
+#burn-uri
+burn_uridir = $(libdir)/brasero/plugins
+burn_uri_LTLIBRARIES = libbrasero-burn-uri.la
+
+libbrasero_burn_uri_la_SOURCES = burn-uri.c burn-uri.h
+libbrasero_burn_uri_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GIO_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_burn_uri_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/local-track/burn-local-image.c b/plugins/local-track/burn-local-image.c
new file mode 100644
index 0000000..e0e50e8
--- /dev/null
+++ b/plugins/local-track/burn-local-image.c
@@ -0,0 +1,946 @@
+/***************************************************************************
+ *            burn-local-image.c
+ *
+ *  dim jui  9 10:54:14 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/* This is for getline() and isblank() */
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gio/gio.h>
+
+#include <gmodule.h>
+
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-local-image.h"
+#include "brasero-xfer.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroLocalTrack, brasero_local_track, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroLocalTrackPrivate {
+	GCancellable *cancel;
+	BraseroXferCtx *xfer_ctx;
+
+	gchar *checksum;
+	gchar *checksum_path;
+	GChecksumType gchecksum_type;
+	BraseroChecksumType checksum_type;
+
+	GHashTable *nonlocals;
+
+	guint thread_id;
+	GThread *thread;
+	GMutex *mutex;
+	GCond *cond;
+
+	GSList *src_list;
+	GSList *dest_list;
+
+	GError *error;
+
+	guint download_checksum:1;
+};
+typedef struct _BraseroLocalTrackPrivate BraseroLocalTrackPrivate;
+
+#define BRASERO_LOCAL_TRACK_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrackPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_local_track_clock_tick (BraseroJob *job)
+{
+	BraseroLocalTrackPrivate *priv;
+	goffset written = 0;
+	goffset total = 0;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (job);
+
+	if (!priv->xfer_ctx)
+		return BRASERO_BURN_OK;
+
+	brasero_job_start_progress (job, FALSE);
+
+	brasero_xfer_get_progress (priv->xfer_ctx,
+				   &written,
+				   &total);
+	brasero_job_set_progress (job, (gdouble) written / (gdouble) total);
+
+	return BRASERO_BURN_OK;
+}
+
+/**
+ * That's for URI translation ...
+ */
+
+static gchar *
+brasero_local_track_translate_uri (BraseroLocalTrack *self,
+				   const gchar *uri)
+{
+	gchar *newuri;
+	gchar *parent;
+	BraseroLocalTrackPrivate *priv;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	if (!uri)
+		return NULL;
+
+	/* see if it is a local file */
+	if (g_str_has_prefix (uri, "file://"))
+		return g_strdup (uri);
+
+	/* see if it was downloaded itself */
+	newuri = g_hash_table_lookup (priv->nonlocals, uri);
+	if (newuri) {
+		/* we copy this string as it will be freed when freeing 
+		 * downloaded GSList */
+		return g_strdup (newuri);
+	}
+
+	/* see if one of its parent will be downloaded */
+	parent = g_path_get_dirname (uri);
+	while (parent [1] != '\0') {
+		gchar *tmp;
+
+		tmp = g_hash_table_lookup (priv->nonlocals, parent);
+		if (tmp) {
+			newuri = g_build_path (G_DIR_SEPARATOR_S,
+					       tmp,
+					       uri + strlen (parent),
+					       NULL);
+			g_free (parent);
+			return newuri;
+		}
+
+		tmp = parent;
+		parent = g_path_get_dirname (tmp);
+		g_free (tmp);
+	}
+
+	/* that should not happen */
+	BRASERO_JOB_LOG (self, "Can't find a downloaded parent for %s", uri);
+
+	g_free (parent);
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_local_track_read_checksum (BraseroLocalTrack *self)
+{
+	gint size;
+	FILE *file;
+	gchar *name;
+	gchar *source;
+	gchar *line = NULL;
+	size_t line_len = 0;
+	BraseroTrack *track = NULL;
+	BraseroLocalTrackPrivate *priv;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	/* get the file_checksum from the checksum file */
+	file = fopen (priv->checksum_path, "r");
+
+	/* get the name of the file that was downloaded */
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	source = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+	name = g_path_get_basename (source);
+	g_free (source);
+
+	if (!file) {
+		g_free (name);
+		BRASERO_JOB_LOG (self, "Impossible to open the downloaded checksum file");
+		return BRASERO_BURN_ERR;
+	}
+
+	/* find a line with the name of our file (there could be several ones) */
+	BRASERO_JOB_LOG (self, "Searching %s in file", name);
+	while ((size = getline (&line, &line_len, file)) > 0) {
+		if (strstr (line, name)) {
+			gchar *ptr;
+
+			/* Skip blanks */
+			ptr = line;
+			while (isblank (*ptr)) { ptr ++; size --; }
+
+			if (g_checksum_type_get_length (priv->checksum_type) * 2 > size) {
+				g_free (line);
+				line = NULL;
+				continue;
+			}
+	
+			ptr [g_checksum_type_get_length (priv->gchecksum_type) * 2] = '\0';
+			priv->checksum = g_strdup (ptr);
+			g_free (line);
+			BRASERO_JOB_LOG (self, "Found checksum %s", priv->checksum);
+			break;
+		}
+
+		g_free (line);
+		line = NULL;
+	}
+	fclose (file);
+
+	return (priv->checksum? BRASERO_BURN_OK:BRASERO_BURN_ERR);
+}
+
+static BraseroBurnResult
+brasero_local_track_download_checksum (BraseroLocalTrack *self)
+{
+	BraseroLocalTrackPrivate *priv;
+	BraseroBurnResult result;
+	BraseroTrack *track;
+	gchar *checksum_src;
+	GFile *src, *dest;
+	GFile *tmp;
+	gchar *uri;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	BRASERO_JOB_LOG (self, "Copying checksum file");
+
+	/* generate a unique name for destination */
+	result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+					   NULL,
+					   &priv->checksum_path,
+					   NULL);
+	if (result != BRASERO_BURN_OK)
+		goto error;
+
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_FILE_COPY,
+					_("Copying checksum file"),
+					TRUE);
+
+	/* This is an image. See if there is any checksum sitting in the same
+	 * directory to check our download integrity.
+	 * Try all types of checksum. */
+	brasero_job_get_current_track (BRASERO_JOB (self), &track);
+	uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+	dest = g_file_new_for_path (priv->checksum_path);
+
+	/* Try with three difference sources */
+	checksum_src = g_strdup_printf ("%s.md5", uri);
+	src = g_file_new_for_uri (checksum_src);
+	g_free (checksum_src);
+
+	result = brasero_xfer_start (priv->xfer_ctx,
+				     src,
+				     dest,
+				     priv->cancel,
+				     NULL);
+	g_object_unref (src);
+
+	if (result == BRASERO_BURN_OK) {
+		priv->gchecksum_type = G_CHECKSUM_MD5;
+		priv->checksum_type = BRASERO_CHECKSUM_MD5;
+		goto end;
+	}
+
+	checksum_src = g_strdup_printf ("%s.sha1", uri);
+	src = g_file_new_for_uri (checksum_src);
+	g_free (checksum_src);
+
+	result = brasero_xfer_start (priv->xfer_ctx,
+				     src,
+				     dest,
+				     priv->cancel,
+				     NULL);
+	g_object_unref (src);
+
+	if (result == BRASERO_BURN_OK) {
+		priv->gchecksum_type = G_CHECKSUM_SHA1;
+		priv->checksum_type = BRASERO_CHECKSUM_SHA1;
+		goto end;
+	}
+
+	checksum_src = g_strdup_printf ("%s.sha256", uri);
+	src = g_file_new_for_uri (checksum_src);
+	g_free (checksum_src);
+
+	result = brasero_xfer_start (priv->xfer_ctx,
+				     src,
+				     dest,
+				     priv->cancel,
+				     NULL);
+	g_object_unref (src);
+
+	if (result == BRASERO_BURN_OK) {
+		priv->gchecksum_type = G_CHECKSUM_SHA256;
+		priv->checksum_type = BRASERO_CHECKSUM_SHA256;
+		goto end;
+	}
+
+	/* There are also ftp sites that includes all images checksum in one big
+	 * SHA1 file. */
+	tmp = g_file_new_for_uri (uri);
+	src = g_file_get_parent (tmp);
+	g_object_unref (tmp);
+
+	tmp = src;
+	src = g_file_get_child_for_display_name (tmp, "SHA1SUM", NULL);
+	g_object_unref (tmp);
+
+	result = brasero_xfer_start (priv->xfer_ctx,
+				     src,
+				     dest,
+				     priv->cancel,
+				     NULL);
+	g_object_unref (src);
+
+	if (result != BRASERO_BURN_OK) {
+		g_free (uri);
+		g_object_unref (dest);
+		goto error;
+	}
+
+	priv->gchecksum_type = G_CHECKSUM_SHA1;
+	priv->checksum_type = BRASERO_CHECKSUM_SHA1;
+
+end:
+
+	g_object_unref (dest);
+	g_free (uri);
+
+	return result;
+
+error:
+
+	/* we give up */
+	BRASERO_JOB_LOG (self, "No checksum file available");
+	g_free (priv->checksum_path);
+	priv->checksum_path = NULL;
+	return result;
+}
+
+static BraseroBurnResult
+brasero_local_track_update_track (BraseroLocalTrack *self)
+{
+	BraseroTrack *track;
+	BraseroTrack *current = NULL;
+	BraseroLocalTrackPrivate *priv;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	/* now we update all the track with the local uris in retval */
+	brasero_job_get_current_track (BRASERO_JOB (self), &current);
+
+	/* make a copy of the tracks instead of modifying them */
+	if (BRASERO_IS_TRACK_DATA (current)) {
+		GSList *next;
+		GSList *grafts;
+		GSList *unreadable;
+		guint64 file_num = 0;
+
+		track = BRASERO_TRACK (brasero_track_data_new ());
+		brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+
+		brasero_track_data_add_fs (BRASERO_TRACK_DATA (track), brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
+
+		brasero_track_data_get_file_num (BRASERO_TRACK_DATA (current), &file_num);
+		brasero_track_data_set_file_num (BRASERO_TRACK_DATA (track), file_num);
+
+		grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
+		for (; grafts; grafts = grafts->next) {
+			BraseroGraftPt *graft;
+			gchar *uri;
+
+			graft = grafts->data;
+			uri = brasero_local_track_translate_uri (self, graft->uri);
+			if (uri) {
+				g_free (graft->uri);
+				graft->uri = uri;
+			}
+		}
+
+		BRASERO_JOB_LOG (self, "Translating unreadable");
+
+		/* Translate the globally excluded.
+		 * NOTE: if we can't find a parent for an excluded URI that
+		 * means it shouldn't be included. */
+		unreadable = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), FALSE);
+		for (; unreadable; unreadable = next) {
+			gchar *new_uri;
+
+			next = unreadable->next;
+			new_uri = brasero_local_track_translate_uri (self, unreadable->data);
+			g_free (unreadable->data);
+
+			if (new_uri)
+				unreadable->data = new_uri;
+			else
+				unreadable = g_slist_remove (unreadable, unreadable->data);
+		}
+	}
+	else if (BRASERO_IS_TRACK_STREAM (track)) {
+		gchar *uri;
+		gchar *newuri;
+
+		uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (current), TRUE);
+		newuri = brasero_local_track_translate_uri (self, uri);
+
+		track = BRASERO_TRACK (brasero_track_stream_new ());
+		brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+		brasero_track_stream_set_source (BRASERO_TRACK_STREAM (track), newuri);
+		brasero_track_stream_set_format (BRASERO_TRACK_STREAM (track), brasero_track_stream_get_format (BRASERO_TRACK_STREAM (current)));
+		brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track),
+						     brasero_track_stream_get_start (BRASERO_TRACK_STREAM (current)),
+						     brasero_track_stream_get_end (BRASERO_TRACK_STREAM (current)),
+						     brasero_track_stream_get_gap (BRASERO_TRACK_STREAM (current)));
+		g_free (uri);
+	}
+	else if (BRASERO_IS_TRACK_IMAGE (track)) {
+		gchar *uri;
+		gchar *newtoc;
+		gchar *newimage;
+		guint64 blocks = 0;
+
+		uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), TRUE);
+		newimage = brasero_local_track_translate_uri (self, uri);
+		g_free (uri);
+
+		uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (current), TRUE);
+		newtoc = brasero_local_track_translate_uri (self, uri);
+		g_free (uri);
+
+		brasero_track_get_size (current, &blocks, NULL);
+
+		track = BRASERO_TRACK (brasero_track_image_new ());
+		brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+		brasero_track_image_set_source (BRASERO_TRACK_IMAGE (track),
+						newimage,
+						newtoc,
+						brasero_track_image_get_format (BRASERO_TRACK_IMAGE (current)));
+		brasero_track_image_set_block_num (BRASERO_TRACK_IMAGE (track), blocks);
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	if (priv->download_checksum)
+		brasero_track_set_checksum (track,
+					    priv->checksum_type,
+					    priv->checksum);
+
+	brasero_job_add_track (BRASERO_JOB (self), track);
+
+	/* It's good practice to unref the track afterwards as we don't need it
+	 * anymore. BraseroTaskCtx refs it. */
+	g_object_unref (track);
+
+	return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_local_track_thread_finished (BraseroLocalTrack *self)
+{
+	BraseroLocalTrackPrivate *priv;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	priv->thread_id = 0;
+
+	if (priv->xfer_ctx) {
+		brasero_xfer_free (priv->xfer_ctx);
+		priv->xfer_ctx = NULL;
+	}
+
+	if (priv->cancel) {
+		g_object_unref (priv->cancel);
+		priv->cancel = NULL;
+		if (g_cancellable_is_cancelled (priv->cancel))
+			return FALSE;
+	}
+
+	if (priv->error) {
+		GError *error;
+
+		error = priv->error;
+		priv->error = NULL;
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	brasero_local_track_update_track (self);
+
+	brasero_job_finished_track (BRASERO_JOB (self));
+	return FALSE;
+}
+
+static gpointer
+brasero_local_track_thread (gpointer data)
+{
+	BraseroLocalTrack *self = BRASERO_LOCAL_TRACK (data);
+	BraseroLocalTrackPrivate *priv;
+	GSList *src, *dest;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_FILE_COPY,
+					_("Copying files locally"),
+					TRUE);
+
+	for (src = priv->src_list, dest = priv->dest_list;
+	     src && dest;
+	     src = src->next, dest = dest->next) {
+		gchar *name;
+		gchar *string;
+		GFile *src_file;
+		GFile *dest_file;
+		BraseroBurnResult result;
+
+		src_file = src->data;
+		dest_file = dest->data;
+
+		name = g_file_get_basename (src_file);
+		BRASERO_JOB_LOG (self, "Downloading %s", name);
+		string = g_strdup_printf (_("Copying `%s` locally"), name);
+		g_free (name);
+
+		result = brasero_xfer_start (priv->xfer_ctx,
+					     src_file,
+					     dest_file,
+					     priv->cancel,
+					     &priv->error);
+
+		if (g_cancellable_is_cancelled (priv->cancel))
+			goto end;
+
+		if (result != BRASERO_BURN_OK)
+			goto end;
+	}
+
+	/* successfully downloaded files, get a checksum if we can. */
+	if (priv->download_checksum
+	&& !priv->checksum_path
+	&&  brasero_local_track_download_checksum (self) == BRASERO_BURN_OK)
+		brasero_local_track_read_checksum (self);
+
+end:
+
+	if (!g_cancellable_is_cancelled (priv->cancel))
+		priv->thread_id = g_idle_add ((GSourceFunc) brasero_local_track_thread_finished, self);
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	priv->thread = NULL;
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_local_track_start_thread (BraseroLocalTrack *self,
+				  GError **error)
+{
+	BraseroLocalTrackPrivate *priv;
+	GError *thread_error = NULL;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	if (priv->thread)
+		return BRASERO_BURN_RUNNING;
+
+	priv->cancel = g_cancellable_new ();
+	priv->xfer_ctx = brasero_xfer_new ();
+
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_local_track_thread,
+					self,
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static gboolean
+_foreach_non_local_cb (const gchar *uri,
+		       const gchar *localuri,
+		       gpointer *data)
+{
+	BraseroLocalTrack *self = BRASERO_LOCAL_TRACK (data);
+	BraseroLocalTrackPrivate *priv;
+	GFile *file, *tmpfile;
+	gchar *parent;
+	gchar *tmp;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (data);
+
+	/* check that is hasn't any parent in the hash */
+	parent = g_path_get_dirname (uri);
+	while (parent [1] != '\0') {
+		gchar *uri_local;
+
+		uri_local = g_hash_table_lookup (priv->nonlocals, parent);
+		if (uri_local) {
+			BRASERO_JOB_LOG (self, "Parent for %s was found %s", uri, parent);
+			g_free (parent);
+			return TRUE;
+		}
+
+		tmp = parent;
+		parent = g_path_get_dirname (tmp);
+		g_free (tmp);
+	}
+	g_free (parent);
+
+	file = g_file_new_for_uri (uri);
+	priv->src_list = g_slist_append (priv->src_list, file);
+
+	tmpfile = g_file_new_for_uri (localuri);
+	priv->dest_list = g_slist_append (priv->dest_list, tmpfile);
+
+	BRASERO_JOB_LOG (self, "%s set to be downloaded to %s", uri, localuri);
+	return FALSE;
+}
+
+static BraseroBurnResult
+brasero_local_track_add_if_non_local (BraseroLocalTrack *self,
+				      const gchar *uri,
+				      GError **error)
+{
+	BraseroLocalTrackPrivate *priv;
+	BraseroBurnResult result;
+	gchar *localuri = NULL;
+
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	if (!uri
+	||   uri [0] == '\0'
+	||   uri [0] == '/'
+	||   g_str_has_prefix (uri, "file://")
+	||   g_str_has_prefix (uri, "burn://"))
+		return BRASERO_BURN_OK;
+
+	/* add it to the list or uris to download */
+	if (!priv->nonlocals)
+		priv->nonlocals = g_hash_table_new_full (g_str_hash,
+							 g_str_equal,
+							 NULL,
+							 g_free);
+
+	/* generate a unique name */
+	result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+					   NULL,
+					   &localuri,
+					   error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	if (!g_str_has_prefix (localuri, "file://")) {
+		gchar *tmp;
+
+		tmp = localuri;
+		localuri = g_strconcat ("file://", tmp, NULL);
+		g_free (tmp);
+	}
+
+	/* we don't want to replace it if it has already been downloaded */
+	if (!g_hash_table_lookup (priv->nonlocals, uri))
+		g_hash_table_insert (priv->nonlocals, g_strdup (uri), localuri);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_local_track_start (BraseroJob *job,
+			   GError **error)
+{
+	BraseroLocalTrackPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroLocalTrack *self;
+	BraseroTrack *track;
+	GSList *grafts;
+	gchar *uri;
+
+	self = BRASERO_LOCAL_TRACK (job);
+	priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+	/* skip that part */
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		/* say we won't write to disc */
+		brasero_job_set_output_size_for_current_track (job, 0, 0);
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	/* can't be piped so brasero_job_get_current_track will work */
+	brasero_job_get_current_track (job, &track);
+
+	result = BRASERO_BURN_OK;
+
+	/* make a list of all non local uris to be downloaded and put them in a
+	 * list to avoid to download the same file twice. */
+	if (BRASERO_IS_TRACK_DATA (track)) {
+		/* we put all the non local graft point uris in the hash */
+		grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+		for (; grafts; grafts = grafts->next) {
+			BraseroGraftPt *graft;
+
+			graft = grafts->data;
+			result = brasero_local_track_add_if_non_local (self, graft->uri, error);
+			if (result != BRASERO_BURN_OK)
+				break;
+		}
+	}
+	else if (BRASERO_IS_TRACK_STREAM (track)) {
+		/* NOTE: don't delete URI as they will be inserted in hash */
+		uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+		result = brasero_local_track_add_if_non_local (self, uri, error);
+		g_free (uri);
+	}
+	else if (BRASERO_IS_TRACK_IMAGE (track)) {
+		/* NOTE: don't delete URI as they will be inserted in hash */
+		uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+		result = brasero_local_track_add_if_non_local (self, uri, error);
+		g_free (uri);
+
+		if (result == BRASERO_BURN_OK) {
+			priv->download_checksum = TRUE;
+
+			uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), TRUE);
+			result = brasero_local_track_add_if_non_local (self, uri, error);
+			g_free (uri);
+		}
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* see if there is anything to download */
+	if (!priv->nonlocals) {
+		BRASERO_JOB_LOG (self, "no remote URIs");
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	/* first we create a list of all the non local files that need to be
+	 * downloaded. To be elligible a file must not have one of his parent
+	 * in the hash. */
+	g_hash_table_foreach_remove (priv->nonlocals,
+				     (GHRFunc) _foreach_non_local_cb,
+				     job);
+
+	return brasero_local_track_start_thread (self, error);
+}
+
+static BraseroBurnResult
+brasero_local_track_stop (BraseroJob *job,
+			  GError **error)
+{
+	BraseroLocalTrackPrivate *priv = BRASERO_LOCAL_TRACK_PRIVATE (job);
+
+	if (priv->cancel) {
+		/* signal that we've been cancelled */
+		g_cancellable_cancel (priv->cancel);
+	}
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread)
+		g_cond_wait (priv->cond, priv->mutex);
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->xfer_ctx) {
+		brasero_xfer_free (priv->xfer_ctx);
+		priv->xfer_ctx = NULL;
+	}
+
+	if (priv->cancel) {
+		/* unref it after the thread has stopped */
+		g_object_unref (priv->cancel);
+		priv->cancel = NULL;
+	}
+
+	if (priv->thread_id) {
+		g_source_remove (priv->thread_id);
+		priv->thread_id = 0;
+	}
+
+	if (priv->error) {
+		g_error_free (priv->error);
+		priv->error = NULL;
+	}
+
+	if (priv->src_list) {
+		g_slist_foreach (priv->src_list, (GFunc) g_object_unref, NULL);
+		g_slist_free (priv->src_list);
+		priv->src_list = NULL;
+	}
+
+	if (priv->dest_list) {
+		g_slist_foreach (priv->dest_list, (GFunc) g_object_unref, NULL);
+		g_slist_free (priv->dest_list);
+		priv->dest_list = NULL;
+	}
+
+	if (priv->nonlocals) {
+		g_hash_table_destroy (priv->nonlocals);
+		priv->nonlocals = NULL;
+	}
+
+	if (priv->checksum_path) {
+		g_free (priv->checksum_path);
+		priv->checksum_path = NULL;
+	}
+
+	if (priv->checksum) {
+		g_free (priv->checksum);
+		priv->checksum = NULL;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_local_track_finalize (GObject *object)
+{
+	BraseroLocalTrackPrivate *priv = BRASERO_LOCAL_TRACK_PRIVATE (object);
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cond) {
+		g_cond_free (priv->cond);
+		priv->cond = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_local_track_class_init (BraseroLocalTrackClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroLocalTrackPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_local_track_finalize;
+
+	job_class->start = brasero_local_track_start;
+	job_class->stop = brasero_local_track_stop;
+	job_class->clock_tick = brasero_local_track_clock_tick;
+}
+
+static void
+brasero_local_track_init (BraseroLocalTrack *obj)
+{
+	BraseroLocalTrackPrivate *priv = BRASERO_LOCAL_TRACK_PRIVATE (obj);
+
+	priv->mutex = g_mutex_new ();
+	priv->cond = g_cond_new ();
+}
+
+static BraseroBurnResult
+brasero_local_track_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *caps;
+
+	brasero_plugin_define (plugin,
+			       /* Translators: this is the name of the plugin
+				* which will be translated only when it needs
+				* displaying. */
+			       N_("File Downloader"),
+			       _("Allows to burn files not stored locally"),
+			       "Philippe Rouquier",
+			       10);
+
+	caps = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+				       BRASERO_IMAGE_FORMAT_ANY);
+	brasero_plugin_process_caps (plugin, caps);
+	g_slist_free (caps);
+
+	caps = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+				       BRASERO_AUDIO_FORMAT_UNDEFINED|
+				       BRASERO_AUDIO_FORMAT_4_CHANNEL|
+				       BRASERO_AUDIO_FORMAT_RAW|
+				       BRASERO_VIDEO_FORMAT_UNDEFINED|
+				       BRASERO_VIDEO_FORMAT_VCD|
+				       BRASERO_VIDEO_FORMAT_VIDEO_DVD|
+				       BRASERO_AUDIO_FORMAT_AC3|
+				       BRASERO_AUDIO_FORMAT_MP2|
+				       BRASERO_AUDIO_FORMAT_44100|
+				       BRASERO_AUDIO_FORMAT_48000|
+				       BRASERO_METADATA_INFO);
+	brasero_plugin_process_caps (plugin, caps);
+	g_slist_free (caps);
+
+	caps = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+				       BRASERO_AUDIO_FORMAT_UNDEFINED|
+				       BRASERO_AUDIO_FORMAT_4_CHANNEL|
+				       BRASERO_AUDIO_FORMAT_RAW|
+				       BRASERO_VIDEO_FORMAT_UNDEFINED|
+				       BRASERO_VIDEO_FORMAT_VCD|
+				       BRASERO_VIDEO_FORMAT_VIDEO_DVD|
+				       BRASERO_AUDIO_FORMAT_AC3|
+				       BRASERO_AUDIO_FORMAT_MP2|
+				       BRASERO_AUDIO_FORMAT_44100|
+				       BRASERO_AUDIO_FORMAT_48000);
+	brasero_plugin_process_caps (plugin, caps);
+	g_slist_free (caps);
+	caps = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
+	brasero_plugin_process_caps (plugin, caps);
+	g_slist_free (caps);
+
+	brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
+
+	brasero_plugin_set_compulsory (plugin, FALSE);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/local-track/burn-local-image.h b/plugins/local-track/burn-local-image.h
new file mode 100644
index 0000000..697dea2
--- /dev/null
+++ b/plugins/local-track/burn-local-image.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            burn-local-track.h
+ *
+ *  dim jui  9 10:54:14 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef BURN_LOCAL_TRACK_H
+#define BURN_LOCAL_TRACK_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LOCAL_TRACK         (brasero_local_track_get_type ())
+#define BRASERO_LOCAL_TRACK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrack))
+#define BRASERO_LOCAL_TRACK_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrackClass))
+#define BRASERO_IS_LOCAL_TRACK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LOCAL_TRACK))
+#define BRASERO_IS_LOCAL_TRACK_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LOCAL_TRACK))
+#define BRASERO_LOCAL_TRACK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrackClass))
+
+G_END_DECLS
+
+#endif /* BURN_LOCAL_TRACK_H */
diff --git a/plugins/local-track/burn-uri.c b/plugins/local-track/burn-uri.c
new file mode 100644
index 0000000..e420548
--- /dev/null
+++ b/plugins/local-track/burn-uri.c
@@ -0,0 +1,746 @@
+/***************************************************************************
+ *            burn-local-image.c
+ *
+ *  dim jui  9 10:54:14 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gio/gio.h>
+
+#include <gmodule.h>
+
+#include "brasero-units.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-uri.h"
+
+#include "brasero-track.h"
+#include "brasero-track-data.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroBurnURI, brasero_burn_uri, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroBurnURIPrivate {
+	GCancellable *cancel;
+
+	BraseroTrack *track;
+
+	guint thread_id;
+	GThread *thread;
+	GMutex *mutex;
+	GCond *cond;
+
+	GError *error;
+};
+typedef struct _BraseroBurnURIPrivate BraseroBurnURIPrivate;
+
+#define BRASERO_BURN_URI_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURIPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static gboolean
+brasero_burn_uri_thread_finished (BraseroBurnURI *self)
+{
+	BraseroBurnURIPrivate *priv;
+
+	priv = BRASERO_BURN_URI_PRIVATE (self);
+
+	priv->thread_id = 0;
+
+	if (priv->cancel) {
+		g_object_unref (priv->cancel);
+		priv->cancel = NULL;
+		if (g_cancellable_is_cancelled (priv->cancel))
+			return FALSE;
+	}
+
+	if (priv->error) {
+		GError *error;
+
+		error = priv->error;
+		priv->error = NULL;
+		brasero_job_error (BRASERO_JOB (self), error);
+		return FALSE;
+	}
+
+	brasero_job_add_track (BRASERO_JOB (self), priv->track);
+	brasero_job_finished_track (BRASERO_JOB (self));
+
+	return FALSE;
+}
+
+static gint
+brasero_burn_uri_find_graft (gconstpointer A, gconstpointer B)
+{
+	const BraseroGraftPt *graft = A;
+
+	if (graft && graft->path)
+		return strcmp (graft->path, B);
+
+	return 1;
+}
+
+static GSList *
+brasero_burn_uri_explore_directory (BraseroBurnURI *self,
+				    GSList *grafts,
+				    GFile *file,
+				    const gchar *path,
+				    GCancellable *cancel,
+				    GError **error)
+{
+	BraseroTrack *current = NULL;
+	GFileEnumerator *enumerator;
+	GSList *current_grafts;
+	GFileInfo *info;
+
+	enumerator = g_file_enumerate_children (file,
+						G_FILE_ATTRIBUTE_STANDARD_NAME ","
+						G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+						"burn::backing-file",
+						G_FILE_QUERY_INFO_NONE,
+						cancel,
+						error);
+
+	if (!enumerator) {
+		g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
+		g_slist_free (grafts);
+		return NULL;
+	}
+
+	brasero_job_get_current_track (BRASERO_JOB (self), &current);
+	current_grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
+
+	while ((info = g_file_enumerator_next_file (enumerator, cancel, error))) {
+		if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+			gchar *disc_path;
+			GFile *directory;
+			BraseroGraftPt *graft;
+
+			/* Make sure it's not one of the original grafts */
+			/* we need to know if that's a directory or not since if
+			 * it is then mkisofs (but not genisoimage) requires the
+			 * disc path to end with '/'; if there isn't '/' at the 
+			 * end then only the directory contents are added. */
+			disc_path = g_build_filename (path, g_file_info_get_name (info), G_DIR_SEPARATOR_S, NULL);
+			if (g_slist_find_custom (current_grafts, disc_path, (GCompareFunc) brasero_burn_uri_find_graft)) {
+				BRASERO_JOB_LOG (self, "Graft already in list %s", disc_path);
+				g_object_unref (info);
+				g_free (disc_path);
+				continue;
+			}
+
+			/* we need a dummy directory */
+			graft = g_new0 (BraseroGraftPt, 1);
+			graft->uri = NULL;
+			graft->path = disc_path;
+			grafts = g_slist_prepend (grafts, graft);
+
+			BRASERO_JOB_LOG (self, "Adding directory %s at %s", graft->uri, graft->path);
+
+			directory = g_file_get_child (file, g_file_info_get_name (info));
+			grafts = brasero_burn_uri_explore_directory (self,
+								     grafts,
+								     directory,
+								     graft->path,
+								     cancel,
+								     error);
+			g_object_unref (directory);
+
+			if (!grafts) {
+				g_object_unref (info);
+				g_object_unref (enumerator);
+				return NULL;
+			}
+		}
+		else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
+		     /* NOTE: burn:// URI allows symlink */
+		     ||  g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
+			const gchar *real_path;
+			BraseroGraftPt *graft;
+			gchar *disc_path;
+
+			real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
+			if (!real_path) {
+				g_set_error (error,
+					     BRASERO_BURN_ERROR,
+					     BRASERO_BURN_ERROR_GENERAL,
+					     _("Impossible to retrieve local file path"));
+
+				g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
+				g_slist_free (grafts);
+				g_object_unref (info);
+				g_object_unref (file);
+				return NULL;
+			}
+
+			/* Make sure it's not one of the original grafts */
+			disc_path = g_build_filename (path, g_file_info_get_name (info), NULL);
+			if (g_slist_find_custom (current_grafts, disc_path, (GCompareFunc) brasero_burn_uri_find_graft)) {
+				BRASERO_JOB_LOG (self, "Graft already in list %s", disc_path);
+				g_object_unref (info);
+				g_free (disc_path);
+				continue;
+			}
+
+			graft = g_new0 (BraseroGraftPt, 1);
+			graft->path = disc_path;
+			graft->uri = g_strdup (real_path);
+			/* FIXME: maybe one day, graft->uri will always be an URI */
+			/* graft->uri = g_filename_to_uri (real_path, NULL, NULL); */
+
+			/* Make sure it's not one of the original grafts */
+			
+			grafts = g_slist_prepend (grafts, graft);
+
+			BRASERO_JOB_LOG (self, "Added file %s at %s", graft->uri, graft->path);
+		}
+
+		g_object_unref (info);
+	}
+	g_object_unref (enumerator);
+
+	return grafts;
+}
+
+static gboolean
+brasero_burn_uri_retrieve_path (BraseroBurnURI *self,
+				const gchar *uri,
+				gchar **path)
+{
+	GFile *file;
+	GFileInfo *info;
+	BraseroBurnURIPrivate *priv;
+
+	priv = BRASERO_BURN_URI_PRIVATE (self);
+
+	file = g_file_new_for_uri (uri);
+	info = g_file_query_info (file,
+				  G_FILE_ATTRIBUTE_STANDARD_NAME ","
+				  G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+				  "burn::backing-file",
+				  G_FILE_QUERY_INFO_NONE,
+				  priv->cancel,
+				  &priv->error);
+
+	if (priv->error) {
+		g_object_unref (file);
+		return FALSE;
+	}
+
+	if (g_cancellable_is_cancelled (priv->cancel)) {
+		g_object_unref (file);
+		return FALSE;
+	}
+
+	if (!info) {
+		/* Error */
+		g_object_unref (file);
+		g_object_unref (info);
+		return FALSE;
+	}
+		
+	if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+		*path = NULL;
+	}
+	else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
+	     /* NOTE: burn:// URI allows symlink */
+	     ||  g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
+		const gchar *real_path;
+
+		real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
+		if (!real_path) {
+			priv->error = g_error_new (BRASERO_BURN_ERROR,
+						   BRASERO_BURN_ERROR_GENERAL,
+						   _("Impossible to retrieve local file path"));
+			g_object_unref (info);
+			g_object_unref (file);
+			return FALSE;
+		}
+
+		*path = g_strdup (real_path);
+	}
+
+	g_object_unref (file);
+	g_object_unref (info);
+	return TRUE;
+}
+
+static gpointer
+brasero_burn_uri_thread (gpointer data)
+{
+	BraseroBurnURI *self = BRASERO_BURN_URI (data);
+	BraseroTrack *current = NULL;
+	BraseroBurnURIPrivate *priv;
+	BraseroTrackData *track;
+	GSList *excluded = NULL;
+	GSList *grafts = NULL;
+	guint64 num = 0;
+	GSList *src;
+
+	priv = BRASERO_BURN_URI_PRIVATE (self);
+	brasero_job_set_current_action (BRASERO_JOB (self),
+					BRASERO_BURN_ACTION_FILE_COPY,
+					_("Copying files locally"),
+					TRUE);
+
+	brasero_job_get_current_track (BRASERO_JOB (self), &current);
+
+	/* This is for IMAGE tracks */
+	if (BRASERO_IS_TRACK_IMAGE (current)) {
+		gchar *uri;
+		gchar *path_toc;
+		gchar *path_image;
+		guint64 blocks = 0;
+		BraseroTrackImage *image;
+
+		path_image = NULL;
+		uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), TRUE);
+		if (!brasero_burn_uri_retrieve_path (self, uri, &path_image)) {
+			g_free (uri);
+			goto end;
+		}
+		g_free (uri);
+
+		path_toc = NULL;
+		uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (current), TRUE);
+		if (!brasero_burn_uri_retrieve_path (self, uri, &path_toc)) {
+			g_free (path_image);
+			g_free (uri);
+			goto end;
+		}
+		g_free (uri);
+
+		brasero_track_get_size (current, &blocks, NULL);
+
+		image = brasero_track_image_new ();
+		brasero_track_tag_copy_missing (BRASERO_TRACK (image), current);
+		brasero_track_image_set_source (image,
+						path_image,
+						path_toc,
+						brasero_track_image_get_format (BRASERO_TRACK_IMAGE (current)));
+		brasero_track_image_set_block_num (image, blocks);
+
+		priv->track = BRASERO_TRACK (image);
+
+		g_free (path_toc);
+		g_free (path_image);
+		goto end;
+	}
+
+	/* This is for DATA tracks */
+	for (src = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current)); src; src = src->next) {
+		GFile *file;
+		GFileInfo *info;
+		BraseroGraftPt *graft;
+
+		graft = src->data;
+
+		if (!graft->uri) {
+			grafts = g_slist_prepend (grafts, brasero_graft_point_copy (graft));
+			continue;
+		}
+
+		if (!g_str_has_prefix (graft->uri, "burn://")) {
+			grafts = g_slist_prepend (grafts, brasero_graft_point_copy (graft));
+			continue;
+		}
+
+		BRASERO_JOB_LOG (self, "Information retrieval for %s", graft->uri);
+
+		file = g_file_new_for_uri (graft->uri);
+		info = g_file_query_info (file,
+					  G_FILE_ATTRIBUTE_STANDARD_NAME ","
+					  G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+					  "burn::backing-file",
+					  G_FILE_QUERY_INFO_NONE,
+					  priv->cancel,
+					  &priv->error);
+
+		if (priv->error) {
+			g_object_unref (file);
+			goto end;
+		}
+
+		if (g_cancellable_is_cancelled (priv->cancel)) {
+			g_object_unref (file);
+			goto end;
+		}
+
+		if (!info) {
+			/* Error */
+			g_object_unref (file);
+			g_object_unref (info);
+			goto end;
+		}
+
+		/* See if we were passed the burn:/// uri itself (the root).
+		 * Then skip graft point addition */
+		if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+			if (g_file_info_get_name (info)
+			&&  strcmp (g_file_info_get_name (info), "/")) {
+				BraseroGraftPt *newgraft;
+
+				/* we need a dummy directory */
+				newgraft = g_new0 (BraseroGraftPt, 1);
+				newgraft->uri = NULL;
+				newgraft->path = g_strdup (graft->path);
+				grafts = g_slist_prepend (grafts, newgraft);
+
+				BRASERO_JOB_LOG (self,
+						 "Adding directory %s at %s",
+						 newgraft->uri,
+						 newgraft->path);
+				grafts = brasero_burn_uri_explore_directory (self,
+									     grafts,
+									     file,
+									     newgraft->path,
+									     priv->cancel,
+									     &priv->error);
+			}
+			else {
+				BRASERO_JOB_LOG (self, "Directory is root");
+				grafts = brasero_burn_uri_explore_directory (self,
+									     grafts,
+									     file,
+									     "/",
+									     priv->cancel,
+									     &priv->error);
+			}
+
+			if (!grafts) {
+				g_object_unref (info);
+				g_object_unref (file);
+				goto end;
+			}
+		}
+		else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
+		     /* NOTE: burn:// URI allows symlink */
+		     ||  g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
+			const gchar *real_path;
+			BraseroGraftPt *newgraft;
+
+			real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
+			if (!real_path) {
+				priv->error = g_error_new (BRASERO_BURN_ERROR,
+							   BRASERO_BURN_ERROR_GENERAL,
+							   _("Impossible to retrieve local file path"));
+
+				g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
+				g_slist_free (grafts);
+				g_object_unref (info);
+				g_object_unref (file);
+				goto end;
+			}
+
+			newgraft = brasero_graft_point_copy (graft);
+			g_free (newgraft->uri);
+
+			newgraft->uri = g_strdup (real_path);
+			/* FIXME: maybe one day, graft->uri will always be an URI */
+			/* newgraft->uri = g_filename_to_uri (real_path, NULL, NULL); */
+
+			BRASERO_JOB_LOG (self,
+					 "Added file %s at %s",
+					 newgraft->uri,
+					 newgraft->path);
+			grafts = g_slist_prepend (grafts, newgraft);
+		}
+
+		g_object_unref (info);
+		g_object_unref (file);
+	}
+	grafts = g_slist_reverse (grafts);
+
+	/* remove all excluded starting by burn:// from the list */
+	for (src = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), FALSE); src; src = src->next) {
+		gchar *uri;
+
+		uri = src->data;
+
+		if (uri && g_str_has_prefix (uri, "burn://"))
+			continue;
+
+		uri = g_strdup (uri);
+		excluded = g_slist_prepend (excluded, uri);
+
+		BRASERO_JOB_LOG (self, "Added excluded file %s", uri);
+	}
+	excluded = g_slist_reverse (excluded);
+
+	track = brasero_track_data_new ();
+	brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+	
+	brasero_track_data_add_fs (track, brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
+
+	brasero_track_data_get_file_num (BRASERO_TRACK_DATA (current), &num);
+	brasero_track_data_set_file_num (track, num);
+
+	brasero_track_data_set_source (track,
+				       grafts,
+				       excluded);
+	priv->track = BRASERO_TRACK (track);
+
+end:
+
+	if (!g_cancellable_is_cancelled (priv->cancel))
+		priv->thread_id = g_idle_add ((GSourceFunc) brasero_burn_uri_thread_finished, self);
+
+	/* End thread */
+	g_mutex_lock (priv->mutex);
+	g_atomic_pointer_set (&priv->thread, NULL);
+	g_cond_signal (priv->cond);
+	g_mutex_unlock (priv->mutex);
+
+	g_thread_exit (NULL);
+
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_start_thread (BraseroBurnURI *self,
+			       GError **error)
+{
+	BraseroBurnURIPrivate *priv;
+	GError *thread_error = NULL;
+
+	priv = BRASERO_BURN_URI_PRIVATE (self);
+
+	if (priv->thread)
+		return BRASERO_BURN_RUNNING;
+
+	priv->cancel = g_cancellable_new ();
+
+	g_mutex_lock (priv->mutex);
+	priv->thread = g_thread_create (brasero_burn_uri_thread,
+					self,
+					TRUE,
+					&thread_error);
+	g_mutex_unlock (priv->mutex);
+
+	/* Reminder: this is not necessarily an error as the thread may have finished */
+	//if (!priv->thread)
+	//	return BRASERO_BURN_ERR;
+	if (thread_error) {
+		g_propagate_error (error, thread_error);
+		return BRASERO_BURN_ERR;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_start_if_found (BraseroBurnURI *self,
+				 const gchar *uri,
+				 GError **error)
+{
+	if (!uri)
+		return BRASERO_BURN_NOT_RUNNING;
+
+	/* Find any graft point with burn:// URI */
+	if (!g_str_has_prefix (uri, "burn://"))
+		return BRASERO_BURN_NOT_RUNNING;
+
+	BRASERO_JOB_LOG (self, "burn:// URI found %s", uri);
+	brasero_burn_uri_start_thread (self, error);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_start (BraseroJob *job,
+			GError **error)
+{
+	BraseroBurnURIPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroBurnURI *self;
+	BraseroTrack *track;
+	GSList *grafts;
+	gchar *uri;
+
+	self = BRASERO_BURN_URI (job);
+	priv = BRASERO_BURN_URI_PRIVATE (self);
+
+	/* skip that part */
+	brasero_job_get_action (job, &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		/* say we won't write to disc */
+		brasero_job_set_output_size_for_current_track (job, 0, 0);
+		return BRASERO_BURN_NOT_RUNNING;
+	}
+
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	/* can't be piped so brasero_job_get_current_track will work */
+	brasero_job_get_current_track (job, &track);
+
+	result = BRASERO_BURN_NOT_RUNNING;
+
+	/* make a list of all non local uris to be downloaded and put them in a
+	 * list to avoid to download the same file twice. */
+	if (BRASERO_IS_TRACK_DATA (track)) {
+		/* we put all the non local graft point uris in the hash */
+		grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+		for (; grafts; grafts = grafts->next) {
+			BraseroGraftPt *graft;
+
+			graft = grafts->data;
+			result = brasero_burn_uri_start_if_found (self, graft->uri, error);
+			if (result != BRASERO_BURN_NOT_RUNNING)
+				break;
+		}
+	}
+	else if (BRASERO_IS_TRACK_IMAGE (track)) {
+		/* NOTE: don't delete URI as they will be inserted in hash */
+		uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+		result = brasero_burn_uri_start_if_found (self, uri, error);
+		g_free (uri);
+
+		if (result == BRASERO_BURN_NOT_RUNNING) {
+			uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), TRUE);
+			result = brasero_burn_uri_start_if_found (self, uri, error);
+			g_free (uri);
+		}
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (self);
+
+	if (!priv->thread)
+		BRASERO_JOB_LOG (self, "no burn:// URI found");
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_stop (BraseroJob *job,
+		       GError **error)
+{
+	BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (job);
+
+	if (priv->cancel) {
+		/* signal that we've been cancelled */
+		g_cancellable_cancel (priv->cancel);
+	}
+
+	g_mutex_lock (priv->mutex);
+	if (priv->thread)
+		g_cond_wait (priv->cond, priv->mutex);
+	g_mutex_unlock (priv->mutex);
+
+	if (priv->cancel) {
+		/* unref it after the thread has stopped */
+		g_object_unref (priv->cancel);
+		priv->cancel = NULL;
+	}
+
+	if (priv->thread_id) {
+		g_source_remove (priv->thread_id);
+		priv->thread_id = 0;
+	}
+
+	if (priv->error) {
+		g_error_free (priv->error);
+		priv->error = NULL;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_burn_uri_finalize (GObject *object)
+{
+	BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (object);
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cond) {
+		g_cond_free (priv->cond);
+		priv->cond = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_burn_uri_class_init (BraseroBurnURIClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroBurnURIPrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_burn_uri_finalize;
+
+	job_class->start = brasero_burn_uri_start;
+	job_class->stop = brasero_burn_uri_stop;
+}
+
+static void
+brasero_burn_uri_init (BraseroBurnURI *obj)
+{
+	BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (obj);
+
+	priv->mutex = g_mutex_new ();
+	priv->cond = g_cond_new ();
+}
+
+static BraseroBurnResult
+brasero_burn_uri_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *caps;
+
+	brasero_plugin_define (plugin,
+			       /* Translators: this is the name of the plugin
+				* which will be translated only when it needs
+				* displaying. */
+			       N_("CD/DVD Creator Folder"),
+			       _("Allows to burn files added to \"CD/DVD Creator Folder\" in Nautilus"),
+			       "Philippe Rouquier",
+			       11);
+
+	caps = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+				       BRASERO_IMAGE_FORMAT_ANY);
+	brasero_plugin_process_caps (plugin, caps);
+	g_slist_free (caps);
+
+	caps = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
+	brasero_plugin_process_caps (plugin, caps);
+	g_slist_free (caps);
+
+	brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/local-track/burn-uri.h b/plugins/local-track/burn-uri.h
new file mode 100644
index 0000000..199cb4a
--- /dev/null
+++ b/plugins/local-track/burn-uri.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            burn-local-track.h
+ *
+ *  dim jui  9 10:54:14 2006
+ *  Copyright  2006  Rouquier Philippe
+ *  brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BURN_URI_H_
+#define _BURN_URI_H_
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_BURN_URI         (brasero_burn_uri_get_type ())
+#define BRASERO_BURN_URI(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURI))
+#define BRASERO_BURN_URI_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_BURN_URI, BraseroBurnURIClass))
+#define BRASERO_IS_BURN_URI(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_BURN_URI))
+#define BRASERO_IS_BURN_URI_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_BURN_URI))
+#define BRASERO_BURN_URI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURIClass))
+
+G_END_DECLS
+
+#endif /* _BURN_URI_H */
diff --git a/plugins/transcode/Makefile.am b/plugins/transcode/Makefile.am
new file mode 100644
index 0000000..e2ff2c7
--- /dev/null
+++ b/plugins/transcode/Makefile.am
@@ -0,0 +1,36 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_GLIB_CFLAGS)				\
+	$(BRASERO_GSTREAMER_CFLAGS)
+
+transcodedir = $(libdir)/brasero/plugins
+transcode_LTLIBRARIES = libbrasero-transcode.la
+
+libbrasero_transcode_la_SOURCES = burn-transcode.c burn-transcode.h burn-normalize.h
+libbrasero_transcode_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GSTREAMER_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_transcode_la_LDFLAGS = -module -avoid-version
+
+normalizedir = $(libdir)/brasero/plugins
+normalize_LTLIBRARIES = libbrasero-normalize.la
+
+libbrasero_normalize_la_SOURCES = burn-normalize.c burn-normalize.h
+libbrasero_normalize_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GSTREAMER_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_normalize_la_LDFLAGS = -module -avoid-version
+
+vobdir = $(libdir)/brasero/plugins
+vob_LTLIBRARIES = libbrasero-vob.la
+
+libbrasero_vob_la_SOURCES = burn-vob.c burn-vob.h
+libbrasero_vob_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GSTREAMER_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_vob_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/transcode/burn-normalize.c b/plugins/transcode/burn-normalize.c
new file mode 100644
index 0000000..f510fe0
--- /dev/null
+++ b/plugins/transcode/burn-normalize.c
@@ -0,0 +1,628 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-normalize.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero-normalize.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero-normalize.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-normalize.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-normalize.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroNormalize, brasero_normalize, BRASERO_TYPE_JOB, BraseroJob);
+
+typedef struct _BraseroNormalizePrivate BraseroNormalizePrivate;
+struct _BraseroNormalizePrivate
+{
+	GstElement *pipeline;
+	GstElement *analysis;
+	GstElement *decode;
+	GstElement *resample;
+	GstElement *source;
+
+	GSList *tracks;
+	BraseroTrack *track;
+
+	gdouble album_peak;
+	gdouble album_gain;
+	gdouble track_peak;
+	gdouble track_gain;
+};
+
+#define BRASERO_NORMALIZE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_NORMALIZE, BraseroNormalizePrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static gboolean
+brasero_normalize_bus_messages (GstBus *bus,
+				GstMessage *msg,
+				BraseroNormalize *normalize);
+
+static gboolean
+brasero_normalize_set_next_track (BraseroJob *job,
+				  BraseroTrack *track,
+				  GError **error)
+{
+	gchar *uri;
+	GstBus *bus = NULL;
+	GstElement *source;
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+	/* destroy previous source */
+	if (priv->source) {
+		gst_element_unlink (priv->source, priv->decode);
+		gst_bin_remove (GST_BIN (priv->pipeline), priv->source);
+		priv->source = NULL;
+	}
+
+	/* create a new one */
+	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+	source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+	if (source == NULL) {
+		g_free (uri);
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Source\"");
+		return FALSE;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), source);
+	g_object_set (source,
+		      "typefind", FALSE,
+		      NULL);
+
+	priv->source = source;
+	if (!gst_element_link_many (source, priv->decode, NULL)) {
+		BRASERO_JOB_LOG (job, "Elements could not be linked");
+		return FALSE;
+	}
+
+	/* reconnect to the bus */	
+	bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+	gst_bus_add_watch (bus,
+			   (GstBusFunc) brasero_normalize_bus_messages,
+			   job);
+	gst_object_unref (bus);
+
+	priv->track = track;
+
+	BRASERO_JOB_LOG (job, "Analysing track %s", uri);
+	g_free (uri);
+
+	return TRUE;
+}
+
+static void
+brasero_normalize_stop_pipeline (BraseroNormalize *normalize)
+{
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+	if (!priv->pipeline)
+		return;
+
+	gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+	gst_object_unref (GST_OBJECT (priv->pipeline));
+	priv->pipeline = NULL;
+	priv->resample = NULL;
+	priv->analysis = NULL;
+	priv->decode = NULL;
+	priv->source = NULL;
+}
+
+static BraseroBurnResult
+brasero_normalize_stop (BraseroJob *job,
+			GError **error)
+{
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+	brasero_normalize_stop_pipeline (BRASERO_NORMALIZE (job));
+	if (priv->tracks) {
+		g_slist_free (priv->tracks);
+		priv->tracks = NULL;
+	}
+
+	priv->track = NULL;
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+foreach_tag (const GstTagList *list,
+	     const gchar *tag,
+	     BraseroNormalize *normalize)
+{
+	gdouble value = 0.0;
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+	/* Those next two are generated at the end only */
+	if (!strcmp (tag, GST_TAG_ALBUM_GAIN)) {
+		gst_tag_list_get_double (list, tag, &value);
+		priv->album_gain = value;
+	}
+	else if (!strcmp (tag, GST_TAG_ALBUM_PEAK)) {
+		gst_tag_list_get_double (list, tag, &value);
+		priv->album_peak = value;
+	}
+	else if (!strcmp (tag, GST_TAG_TRACK_PEAK)) {
+		gst_tag_list_get_double (list, tag, &value);
+		priv->track_peak = value;
+	}
+	else if (!strcmp (tag, GST_TAG_TRACK_GAIN)) {
+		gst_tag_list_get_double (list, tag, &value);
+		priv->track_gain = value;
+	}
+}
+
+static void
+brasero_normalize_song_end_reached (BraseroNormalize *normalize)
+{
+	GValue *value;
+	BraseroTrack *track;
+	GError *error = NULL;
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+	
+	/* finished track: set tags */
+	BRASERO_JOB_LOG (normalize,
+			 "Setting track peak (%lf) and gain (%lf)",
+			 priv->track_peak,
+			 priv->track_gain);
+
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_DOUBLE);
+	g_value_set_double (value, priv->track_peak);
+	brasero_track_tag_add (priv->track,
+			       BRASERO_TRACK_PEAK_VALUE,
+			       value);
+
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_DOUBLE);
+	g_value_set_double (value, priv->track_gain);
+	brasero_track_tag_add (priv->track,
+			       BRASERO_TRACK_GAIN_VALUE,
+			       value);
+
+	priv->track_peak = 0.0;
+	priv->track_gain = 0.0;
+
+	if (!priv->tracks) {
+		BRASERO_JOB_LOG (normalize,
+				 "Setting album peak (%lf) and gain (%lf)",
+				 priv->album_peak,
+				 priv->album_gain);
+
+		/* finished: set tags */
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_DOUBLE);
+		g_value_set_double (value, priv->album_peak);
+		brasero_job_tag_add (BRASERO_JOB (normalize),
+				     BRASERO_ALBUM_PEAK_VALUE,
+				     value);
+
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_DOUBLE);
+		g_value_set_double (value, priv->album_gain);
+		brasero_job_tag_add (BRASERO_JOB (normalize),
+				     BRASERO_ALBUM_GAIN_VALUE,
+				     value);
+
+		brasero_job_finished_session (BRASERO_JOB (normalize));
+		return;
+	}
+
+	/* jump to next track */
+	/* NOTE: why lock state? because otherwise analysis would lose all 
+	 * information about tracks already analysed by going into the NULL
+	 * state. */
+	gst_element_set_locked_state (priv->analysis, TRUE);
+	gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+	track = priv->tracks->data;
+	priv->tracks = g_slist_remove (priv->tracks, track);
+	if (!brasero_normalize_set_next_track (BRASERO_JOB (normalize), track, &error)) {
+		gst_element_set_locked_state (priv->analysis, FALSE);
+		brasero_job_error (BRASERO_JOB (normalize), error);
+		return;
+	}
+
+	gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+	gst_element_set_locked_state (priv->analysis, FALSE);
+}
+
+static gboolean
+brasero_normalize_bus_messages (GstBus *bus,
+				GstMessage *msg,
+				BraseroNormalize *normalize)
+{
+	BraseroNormalizePrivate *priv;
+	GstTagList *tags = NULL;
+	GError *error = NULL;
+	gchar *debug;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_TAG:
+		/* This is the information we've been waiting for.
+		 * NOTE: levels for whole album is delivered at the end */
+		gst_message_parse_tag (msg, &tags);
+		gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, normalize);
+		gst_tag_list_free (tags);
+		return TRUE;
+
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error (msg, &error, &debug);
+		BRASERO_JOB_LOG (normalize, debug);
+		g_free (debug);
+
+	        brasero_job_error (BRASERO_JOB (normalize), error);
+		return FALSE;
+
+	case GST_MESSAGE_EOS:
+		brasero_normalize_song_end_reached (normalize);
+		return FALSE;
+
+	case GST_MESSAGE_STATE_CHANGED:
+		break;
+
+	default:
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+static void
+brasero_normalize_new_decoded_pad_cb (GstElement *decode,
+				      GstPad *pad,
+				      gboolean arg2,
+				      BraseroNormalize *normalize)
+{
+	GstPad *sink;
+	GstCaps *caps;
+	GstStructure *structure;
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+	sink = gst_element_get_pad (priv->resample, "sink");
+	if (GST_PAD_IS_LINKED (sink)) {
+		BRASERO_JOB_LOG (normalize, "New decoded pad already linked");
+		return;
+	}
+
+	/* make sure we only have audio */
+	caps = gst_pad_get_caps (pad);
+	if (!caps)
+		return;
+
+	structure = gst_caps_get_structure (caps, 0);
+	if (structure && g_strrstr (gst_structure_get_name (structure), "audio")) {
+		if (gst_pad_link (pad, sink) != GST_PAD_LINK_OK) {
+			BRASERO_JOB_LOG (normalize, "New decoded pad can't be linked");
+			brasero_job_error (BRASERO_JOB (normalize), NULL);
+		}
+		else
+			BRASERO_JOB_LOG (normalize, "New decoded pad linked");
+	}
+	else
+		BRASERO_JOB_LOG (normalize, "New decoded pad with unsupported stream time");
+		
+	gst_object_unref (sink);
+	gst_caps_unref (caps);
+}
+
+static gboolean
+brasero_normalize_build_pipeline (BraseroNormalize *normalize,
+				  GError **error)
+{
+	GstElement *decode;
+	GstElement *pipeline;
+	GstElement *sink = NULL;
+	GstElement *convert = NULL;
+	GstElement *analysis = NULL;
+	GstElement *resample = NULL;
+	BraseroNormalizePrivate *priv;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+	BRASERO_JOB_LOG (normalize, "Creating new pipeline");
+
+	/* create filesrc ! decodebin ! audioresample ! audioconvert ! rganalysis ! fakesink */
+	pipeline = gst_pipeline_new (NULL);
+	priv->pipeline = pipeline;
+
+	/* NOTE: a new source is created at start of every track */
+
+	/* decode */
+	decode = gst_element_factory_make ("decodebin", NULL);
+	if (decode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Decodebin\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), decode);
+	priv->decode = decode;
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioconvert\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), convert);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioresample\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), resample);
+	priv->resample = resample;
+
+	/* rganalysis: set the number of tracks to be expected */
+	analysis = gst_element_factory_make ("rganalysis", NULL);
+	if (analysis == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Rganalysis\"");
+		goto error;
+	}
+	priv->analysis = analysis;
+	gst_bin_add (GST_BIN (pipeline), analysis);
+
+	/* sink */
+	sink = gst_element_factory_make ("fakesink", NULL);
+	if (!sink) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Fakesink\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), sink);
+	g_object_set (sink,
+		      "sync", FALSE,
+		      NULL);
+
+	/* link everything */
+	g_signal_connect (G_OBJECT (decode),
+			  "new-decoded-pad",
+			  G_CALLBACK (brasero_normalize_new_decoded_pad_cb),
+			  normalize);
+	gst_element_link_many (resample,
+			       convert,
+			       analysis,
+			       sink,
+			       NULL);
+	return TRUE;
+
+error:
+
+	if (error && (*error))
+		BRASERO_JOB_LOG (normalize,
+				 "can't create object : %s \n",
+				 (*error)->message);
+
+	gst_object_unref (GST_OBJECT (pipeline));
+	return FALSE;
+}
+
+static BraseroBurnResult
+brasero_normalize_start (BraseroJob *job,
+			 GError **error)
+{
+	BraseroNormalizePrivate *priv;
+	BraseroTrack *track;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+	priv->album_gain = -1.0;
+	priv->album_peak = -1.0;
+
+	/* get tracks */
+	brasero_job_get_tracks (job, &priv->tracks);
+	if (!priv->tracks)
+		return BRASERO_BURN_ERR;
+
+	priv->tracks = g_slist_copy (priv->tracks);
+	track = priv->tracks->data;
+	priv->tracks = g_slist_remove (priv->tracks, track);
+
+	if (!brasero_normalize_build_pipeline (BRASERO_NORMALIZE (job), error))
+		return BRASERO_BURN_ERR;
+
+	g_object_set (priv->analysis,
+		      "num-tracks", g_slist_length (priv->tracks),
+		      NULL);
+
+	if (!brasero_normalize_set_next_track (job, track, error))
+		return BRASERO_BURN_ERR;
+
+	/* ready to go */
+	brasero_job_set_current_action (job,
+					BRASERO_BURN_ACTION_ANALYSING,
+					_("Normalizing tracks"),
+					FALSE);
+	gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_normalize_activate (BraseroJob *job,
+			    GError **error)
+{
+	GSList *tracks;
+	BraseroJobAction action;
+
+	brasero_job_get_action (job, &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		return BRASERO_BURN_NOT_RUNNING;
+
+	/* check we have more than one track */
+	brasero_job_get_tracks (job, &tracks);
+	if (g_slist_length (tracks) < 2)
+		return BRASERO_BURN_NOT_RUNNING;
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_normalize_clock_tick (BraseroJob *job)
+{
+	gint64 position = 0.0;
+	gint64 duration = 0.0;
+	BraseroNormalizePrivate *priv;
+	GstFormat format = GST_FORMAT_TIME;
+
+	priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+	gst_element_query_duration (priv->pipeline, &format, &duration);
+	gst_element_query_position (priv->pipeline, &format, &position);
+
+	if (duration > 0) {
+		GSList *tracks;
+		gdouble progress;
+
+		brasero_job_get_tracks (job, &tracks);
+		progress = (gdouble) position / (gdouble) duration;
+
+		if (tracks) {
+			gdouble num_tracks;
+
+			num_tracks = g_slist_length (tracks);
+			progress = (gdouble) (num_tracks - 1.0 - (gdouble) g_slist_length (priv->tracks) + progress) / (gdouble) num_tracks;
+			brasero_job_set_progress (job, progress);
+		}
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_normalize_init (BraseroNormalize *object)
+{}
+
+static void
+brasero_normalize_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_normalize_class_init (BraseroNormalizeClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroNormalizePrivate));
+
+	object_class->finalize = brasero_normalize_finalize;
+
+	job_class->activate = brasero_normalize_activate;
+	job_class->start = brasero_normalize_start;
+	job_class->clock_tick = brasero_normalize_clock_tick;
+	job_class->stop = brasero_normalize_stop;
+}
+
+static BraseroBurnResult
+brasero_normalize_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	GstElement *element;
+
+	brasero_plugin_define (plugin,
+			       N_("Normalize"),
+			       _("Normalize allows to set consistent sound levels between tracks"),
+			       "Philippe Rouquier",
+			       0);
+
+	/* Let's see if we've got the plugins we need */
+	element = gst_element_factory_make ("rgvolume", NULL);
+	if (!element) {
+		*error = g_strdup_printf (_("%s element could not be created"),
+					  "\"Rgvolume\"");
+		return BRASERO_BURN_ERR;
+	}
+	gst_object_unref (element);
+
+	element = gst_element_factory_make ("rganalysis", NULL);
+	if (!element) {
+		*error = g_strdup_printf (_("%s element could not be created"),
+					  "\"Rganalysis\"");
+		return BRASERO_BURN_ERR;
+	}
+	gst_object_unref (element);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED|
+					BRASERO_METADATA_INFO);
+	brasero_plugin_process_caps (plugin, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED);
+	brasero_plugin_process_caps (plugin, input);
+	g_slist_free (input);
+
+	/* We should run first */
+	brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
+
+	brasero_plugin_set_compulsory (plugin, FALSE);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/transcode/burn-normalize.h b/plugins/transcode/burn-normalize.h
new file mode 100644
index 0000000..0a5d138
--- /dev/null
+++ b/plugins/transcode/burn-normalize.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-normalize.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero-normalize.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero-normalize.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-normalize.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_NORMALIZE_H_
+#define _BRASERO_NORMALIZE_H_
+
+#include <glib-object.h>
+
+#include "burn-job.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_NORMALIZE             (brasero_normalize_get_type ())
+#define BRASERO_NORMALIZE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_NORMALIZE, BraseroNormalize))
+#define BRASERO_NORMALIZE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_NORMALIZE, BraseroNormalizeClass))
+#define BRASERO_IS_NORMALIZE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_NORMALIZE))
+#define BRASERO_IS_NORMALIZE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_NORMALIZE))
+#define BRASERO_NORMALIZE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_NORMALIZE, BraseroNormalizeClass))
+
+#define BRASERO_ALBUM_PEAK_VALUE	"peak_value"
+#define BRASERO_ALBUM_GAIN_VALUE	"gain_value"
+#define BRASERO_TRACK_PEAK_VALUE	"peak_value"
+#define BRASERO_TRACK_GAIN_VALUE	"gain_value"
+
+G_END_DECLS
+
+#endif /* _BRASERO_NORMALIZE_H_ */
diff --git a/plugins/transcode/burn-transcode.c b/plugins/transcode/burn-transcode.c
new file mode 100644
index 0000000..5b67160
--- /dev/null
+++ b/plugins/transcode/burn-transcode.c
@@ -0,0 +1,1647 @@
+/***************************************************************************
+ *            transcode.c
+ *
+ *  ven jui  8 16:15:04 2005
+ *  Copyright  2005  Philippe Rouquier
+ *  Brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "burn-basics.h"
+#include "brasero-medium.h"
+#include "brasero-tags.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-transcode.h"
+#include "burn-normalize.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroTranscode, brasero_transcode, BRASERO_TYPE_JOB, BraseroJob);
+
+static gboolean brasero_transcode_bus_messages (GstBus *bus,
+						GstMessage *msg,
+						BraseroTranscode *transcode);
+static void brasero_transcode_new_decoded_pad_cb (GstElement *decode,
+						  GstPad *pad,
+						  gboolean arg2,
+						  BraseroTranscode *transcode);
+
+struct BraseroTranscodePrivate {
+	GstElement *pipeline;
+	GstElement *convert;
+	GstElement *source;
+	GstElement *decode;
+	GstElement *sink;
+
+	/* element to link decode to */
+	GstElement *link;
+
+	gint pad_size;
+	gint pad_fd;
+	gint pad_id;
+
+	gint64 size;
+	gint64 pos;
+
+	gulong probe;
+	gint64 segment_start;
+	gint64 segment_end;
+
+	guint set_active_state:1;
+	guint mp3_size_pipeline:1;
+};
+typedef struct BraseroTranscodePrivate BraseroTranscodePrivate;
+
+#define BRASERO_TRANSCODE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TRANSCODE, BraseroTranscodePrivate))
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+brasero_transcode_buffer_handler (GstPad *pad,
+				  GstBuffer *buffer,
+				  BraseroTranscode *self)
+{
+	BraseroTranscodePrivate *priv;
+	GstPad *peer;
+	gint64 size;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (self);
+
+	size = GST_BUFFER_SIZE (buffer);
+
+	if (priv->segment_start <= 0 && priv->segment_end <= 0)
+		return TRUE;
+
+	/* what we do here is more or less what gstreamer does when seeking:
+	 * it reads and process from 0 to the seek position (I tried).
+	 * It even forwards the data before the seek position to the sink (which
+	 * is a problem in our case as it would be written) */
+	if (priv->size > priv->segment_end) {
+		priv->size += size;
+		return FALSE;
+	}
+
+	if (priv->size + size > priv->segment_end) {
+		GstBuffer *new_buffer;
+		int data_size;
+
+		/* the entire the buffer is not interesting for us */
+		/* create a new buffer and push it on the pad:
+		 * NOTE: we're going to receive it ... */
+		data_size = priv->segment_end - priv->size;
+		new_buffer = gst_buffer_new_and_alloc (data_size);
+		memcpy (GST_BUFFER_DATA (new_buffer), GST_BUFFER_DATA (buffer), data_size);
+
+		/* Recursive: the following calls ourselves BEFORE we finish */
+		peer = gst_pad_get_peer (pad);
+		gst_pad_push (peer, new_buffer);
+
+		priv->size += size - data_size;
+
+		/* post an EOS event to stop pipeline */
+		gst_pad_push_event (peer, gst_event_new_eos ());
+		gst_object_unref (peer);
+		return FALSE;
+	}
+
+	/* see if the buffer is in the segment */
+	if (priv->size < priv->segment_start) {
+		GstBuffer *new_buffer;
+		gint data_size;
+
+		/* see if all the buffer is interesting for us */
+		if (priv->size + size < priv->segment_start) {
+			priv->size += size;
+			return FALSE;
+		}
+
+		/* create a new buffer and push it on the pad:
+		 * NOTE: we're going to receive it ... */
+		data_size = priv->size + size - priv->segment_start;
+		new_buffer = gst_buffer_new_and_alloc (data_size);
+		memcpy (GST_BUFFER_DATA (new_buffer),
+			GST_BUFFER_DATA (buffer) +
+			GST_BUFFER_SIZE (buffer) -
+			data_size,
+			data_size);
+		GST_BUFFER_TIMESTAMP (new_buffer) = GST_BUFFER_TIMESTAMP (buffer) + data_size;
+
+		/* move forward by the size of bytes we dropped */
+		priv->size += size - data_size;
+
+		/* this is recursive the following calls ourselves 
+		 * BEFORE we finish */
+		peer = gst_pad_get_peer (pad);
+		gst_pad_push (peer, new_buffer);
+		gst_object_unref (peer);
+
+		return FALSE;
+	}
+
+	priv->size += size;
+	priv->pos += size;
+
+	return TRUE;
+}
+
+static BraseroBurnResult
+brasero_transcode_set_boundaries (BraseroTranscode *transcode)
+{
+	BraseroTranscodePrivate *priv;
+	BraseroTrack *track;
+	gint64 start;
+	gint64 end;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	/* we need to reach the song start and set a possible end; this is only
+	 * needed when it is decoding a song. Otherwise*/
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track));
+	end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track));
+
+	priv->segment_start = BRASERO_DURATION_TO_BYTES (start);
+	priv->segment_end = BRASERO_DURATION_TO_BYTES (end);
+
+	BRASERO_JOB_LOG (transcode, "settings track boundaries time = %lli %lli / bytes = %lli %lli",
+			 start, end,
+			 priv->segment_start, priv->segment_end);
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_transcode_send_volume_event (BraseroTranscode *transcode)
+{
+	BraseroTranscodePrivate *priv;
+	gdouble track_peak = 0.0;
+	gdouble track_gain = 0.0;
+	GstTagList *tag_list;
+	BraseroTrack *track;
+	GstEvent *event;
+	GValue *value;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+
+	BRASERO_JOB_LOG (transcode, "Sending audio levels tags");
+	if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, &value) == BRASERO_BURN_OK)
+		track_peak = g_value_get_double (value);
+
+	if (brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, &value) == BRASERO_BURN_OK)
+		track_gain = g_value_get_double (value);
+
+	/* it's possible we fail */
+	tag_list = gst_tag_list_new ();
+	gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+			  GST_TAG_TRACK_GAIN, track_gain,
+			  GST_TAG_TRACK_PEAK, track_peak,
+			  NULL);
+
+	/* NOTE: that event is goind downstream */
+	event = gst_event_new_tag (tag_list);
+	if (!gst_element_send_event (priv->convert, event))
+		BRASERO_JOB_LOG (transcode, "Couldn't send tags to rgvolume");
+
+	BRASERO_JOB_LOG (transcode, "Set volume level %lf %lf", track_gain, track_peak);
+}
+
+static GstElement *
+brasero_transcode_create_volume (BraseroTranscode *transcode,
+				 BraseroTrack *track)
+{
+	GstElement *volume = NULL;
+
+	/* see if we need a volume object */
+	if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, NULL) == BRASERO_BURN_OK
+	||  brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, NULL) == BRASERO_BURN_OK) {
+		BRASERO_JOB_LOG (transcode, "Found audio levels tags");
+		volume = gst_element_factory_make ("rgvolume", NULL);
+		if (volume)
+			g_object_set (volume,
+				      "album-mode", FALSE,
+				      NULL);
+		else
+			BRASERO_JOB_LOG (transcode, "rgvolume object couldn't be created");
+	}
+
+	return volume;
+}
+
+static gboolean
+brasero_transcode_create_pipeline_size_mp3 (BraseroTranscode *transcode,
+					    GstElement *pipeline,
+					    GstElement *source,				       GError **error)
+{
+	BraseroTranscodePrivate *priv;
+	GstElement *parse;
+	GstElement *sink;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	BRASERO_JOB_LOG (transcode, "Creating specific pipeline for MP3s");
+
+	parse = gst_element_factory_make ("mp3parse", NULL);
+	if (!parse) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Mp3parse\"");
+		g_object_unref (pipeline);
+		return FALSE;
+	}
+	gst_bin_add (GST_BIN (pipeline), parse);
+
+	sink = gst_element_factory_make ("fakesink", NULL);
+	if (!sink) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Fakesink\"");
+		g_object_unref (pipeline);
+		return FALSE;
+	}
+	gst_bin_add (GST_BIN (pipeline), sink);
+
+	/* Link */
+	if (!gst_element_link_many (source, parse, sink, NULL)) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("Impossible to link plugin pads"));
+		BRASERO_JOB_LOG (transcode, "Impossible to link elements");
+		g_object_unref (pipeline);
+		return FALSE;
+	}
+
+	priv->convert = NULL;
+
+	priv->sink = sink;
+	priv->source = source;
+	priv->pipeline = pipeline;
+
+	/* Get it going */
+	gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+	return TRUE;
+}
+
+static gboolean
+brasero_transcode_create_pipeline (BraseroTranscode *transcode,
+				   GError **error)
+{
+	gchar *uri;
+	GstElement *decode;
+	GstElement *source;
+	GstBus *bus = NULL;
+	GstCaps *filtercaps;
+	GstElement *pipeline;
+	GstElement *sink = NULL;
+	BraseroJobAction action;
+	GstElement *filter = NULL;
+	GstElement *volume = NULL;
+	GstElement *convert = NULL;
+	BraseroTrack *track = NULL;
+	GstElement *resample = NULL;
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	BRASERO_JOB_LOG (transcode, "Creating new pipeline");
+
+	priv->set_active_state = 0;
+
+	/* free the possible current pipeline and create a new one */
+	if (priv->pipeline) {
+		gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+		gst_object_unref (G_OBJECT (priv->pipeline));
+		priv->link = NULL;
+		priv->sink = NULL;
+		priv->source = NULL;
+		priv->convert = NULL;
+		priv->pipeline = NULL;
+	}
+
+	/* create three types of pipeline according to the needs: (possibly adding grvolume)
+	 * - filesrc ! decodebin ! audioconvert ! fakesink (find size) and filesrc!mp3parse!fakesink for mp3s
+	 * - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw-int,rate=44100,width=16,depth=16,endianness=4321,signed ! filesink
+	 * - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw-int,rate=44100,width=16,depth=16,endianness=4321,signed ! fdsink
+	 */
+	pipeline = gst_pipeline_new (NULL);
+
+	bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+	gst_bus_add_watch (bus,
+			   (GstBusFunc) brasero_transcode_bus_messages,
+			   transcode);
+	gst_object_unref (bus);
+
+	/* source */
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+	source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+	g_free (uri);
+
+	if (source == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: %s is the name of the GstElement that 
+			      * could not be created */
+			     _("%s element could not be created"),
+			     "\"Source\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), source);
+	g_object_set (source,
+		      "typefind", FALSE,
+		      NULL);
+
+	/* sink */
+	brasero_job_get_action (BRASERO_JOB (transcode), &action);
+	switch (action) {
+	case BRASERO_JOB_ACTION_SIZE:
+		if (priv->mp3_size_pipeline)
+			return brasero_transcode_create_pipeline_size_mp3 (transcode, pipeline, source, error);
+
+		sink = gst_element_factory_make ("fakesink", NULL);
+		break;
+
+	case BRASERO_JOB_ACTION_IMAGE:
+		volume = brasero_transcode_create_volume (transcode, track);
+
+		if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) {
+			gchar *output;
+
+			brasero_job_get_image_output (BRASERO_JOB (transcode),
+						      &output,
+						      NULL);
+			sink = gst_element_factory_make ("filesink", NULL);
+			g_object_set (sink,
+				      "location", output,
+				      NULL);
+		}
+		else {
+			int fd;
+
+			brasero_job_get_fd_out (BRASERO_JOB (transcode), &fd);
+			sink = gst_element_factory_make ("fdsink", NULL);
+			g_object_set (sink,
+				      "fd", fd,
+				      NULL);
+		}
+		break;
+
+	default:
+		goto error;
+	}
+
+	if (!sink) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Sink\"");
+		goto error;
+	}
+
+	gst_bin_add (GST_BIN (pipeline), sink);
+	g_object_set (sink,
+		      "sync", FALSE,
+		      NULL);
+		
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioconvert\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), convert);
+
+	if (action == BRASERO_JOB_ACTION_IMAGE) {
+		/* audioresample */
+		resample = gst_element_factory_make ("audioresample", NULL);
+		if (resample == NULL) {
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("%s element could not be created"),
+				     "\"Audioresample\"");
+			goto error;
+		}
+		gst_bin_add (GST_BIN (pipeline), resample);
+
+		/* filter */
+		filter = gst_element_factory_make ("capsfilter", NULL);
+		if (!filter) {
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("%s element could not be created"),
+				     "\"Filter\"");
+			goto error;
+		}
+		gst_bin_add (GST_BIN (pipeline), filter);
+		filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+								   "channels", G_TYPE_INT, 2,
+								   "width", G_TYPE_INT, 16,
+								   "depth", G_TYPE_INT, 16,
+								   "endianness", G_TYPE_INT, 1234,
+								   "rate", G_TYPE_INT, 44100,
+								   "signed", G_TYPE_BOOLEAN, TRUE,
+								   NULL),
+						NULL);
+		g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+		gst_caps_unref (filtercaps);
+	}
+
+	/* decode */
+	decode = gst_element_factory_make ("decodebin", NULL);
+	if (decode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Decodebin\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), decode);
+
+	priv->sink = sink;
+	priv->decode = decode;
+	priv->source = source;
+	priv->convert = convert;
+	priv->pipeline = pipeline;
+
+	if (action == BRASERO_JOB_ACTION_IMAGE) {
+		GstPad *sinkpad;
+
+		gst_element_link_many (source, decode, NULL);
+		priv->link = resample;
+		g_signal_connect (G_OBJECT (decode),
+				  "new-decoded-pad",
+				  G_CALLBACK (brasero_transcode_new_decoded_pad_cb),
+				  transcode);
+
+		if (volume) {
+			gst_bin_add (GST_BIN (pipeline), volume);
+			gst_element_link_many (resample,
+					       convert,
+					       volume,
+					       filter,
+					       sink,
+					       NULL);
+		}
+		else
+			gst_element_link_many (resample,
+					       convert,
+					       filter,
+					       sink,
+					       NULL);
+
+		/* This is an ugly workaround for the lack of accuracy with
+		 * gstreamer. Yet this is unfortunately a necessary evil. */
+		priv->pos = 0;
+		priv->size = 0;
+		sinkpad = gst_element_get_pad (priv->sink, "sink");
+		priv->probe = gst_pad_add_buffer_probe (sinkpad,
+							G_CALLBACK (brasero_transcode_buffer_handler),
+							transcode);
+		gst_object_unref (sinkpad);
+	}
+	else {
+		gst_element_link (source, decode);
+		gst_element_link (convert, sink);
+
+		priv->link = convert;
+		g_signal_connect (G_OBJECT (decode),
+				  "new-decoded-pad",
+				  G_CALLBACK (brasero_transcode_new_decoded_pad_cb),
+				  transcode);
+	}
+
+	gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+	return TRUE;
+
+error:
+
+	if (error && (*error))
+		BRASERO_JOB_LOG (transcode,
+				 "can't create object : %s \n",
+				 (*error)->message);
+
+	gst_object_unref (GST_OBJECT (pipeline));
+	return FALSE;
+}
+
+static void
+brasero_transcode_set_track_size (BraseroTranscode *transcode,
+				  gint64 duration)
+{
+	gchar *uri;
+	BraseroTrack *track;
+
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track), -1, duration, -1);
+	duration += brasero_track_stream_get_gap (BRASERO_TRACK_STREAM (track));
+
+	/* if transcoding on the fly we should add some length just to make
+	 * sure we won't be too short (gstreamer duration discrepancy) */
+	brasero_job_set_output_size_for_current_track (BRASERO_JOB (transcode),
+						       BRASERO_DURATION_TO_SECTORS (duration),
+						       BRASERO_DURATION_TO_BYTES (duration));
+
+	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+	BRASERO_JOB_LOG (transcode,
+			 "Song %s"
+			 "\nsectors %" G_GINT64_FORMAT
+			 "\ntime %" G_GINT64_FORMAT, 
+			 uri,
+			 BRASERO_DURATION_TO_SECTORS (duration),
+			 duration);
+	g_free (uri);
+}
+
+/**
+ * These functions are to deal with siblings
+ */
+
+static BraseroBurnResult
+brasero_transcode_create_sibling_size (BraseroTranscode *transcode,
+				        BraseroTrack *src,
+				        GError **error)
+{
+	BraseroTrack *dest;
+	guint64 duration;
+
+	/* it means the same file uri is in the selection and was already
+	 * checked. Simply get the values for the length and other information
+	 * and copy them. */
+	/* NOTE: no need to copy the length since if they are sibling that means
+	 * that they have the same length */
+	brasero_track_stream_get_length (BRASERO_TRACK_STREAM (src), &duration);
+	brasero_job_set_output_size_for_current_track (BRASERO_JOB (transcode),
+						       BRASERO_DURATION_TO_SECTORS (duration),
+						       BRASERO_DURATION_TO_BYTES (duration));
+
+	/* copy the info we are missing */
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &dest);
+	brasero_track_tag_copy_missing (dest, src);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_transcode_create_sibling_image (BraseroTranscode *transcode,
+					BraseroTrack *src,
+					GError **error)
+{
+	BraseroTrackStream *dest;
+	BraseroTrack *track;
+	guint64 length = 0;
+	gchar *path_dest;
+	gchar *path_src;
+
+	/* it means the file is already in the selection. Simply create a 
+	 * symlink pointing to first file in the selection with the same uri */
+	path_src = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (src), FALSE);
+	brasero_job_get_audio_output (BRASERO_JOB (transcode), &path_dest);
+
+	if (symlink (path_src, path_dest) == -1) {
+                int errsv = errno;
+
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: the %s is the error message from errno */
+			     _("An internal error occured (%s)"),
+			     g_strerror (errsv));
+
+		goto error;
+	}
+
+	dest = brasero_track_stream_new ();
+	brasero_track_stream_set_source (dest, path_dest);
+	brasero_track_stream_set_format (dest,
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100);
+
+	/* NOTE: there is no gap and start = 0 since these tracks are the result
+	 * of the transformation of previous ones */
+	brasero_track_stream_get_length (BRASERO_TRACK_STREAM (src), &length);
+	brasero_track_stream_set_boundaries (dest, 0, length, 0);
+
+	/* copy all infos but from the current track */
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	brasero_track_tag_copy_missing (BRASERO_TRACK (dest), track);
+	brasero_job_add_track (BRASERO_JOB (transcode), BRASERO_TRACK (dest));
+
+	/* It's good practice to unref the track afterwards as we don't need it
+	 * anymore. BraseroTaskCtx refs it. */
+	g_object_unref (dest);
+
+	g_free (path_src);
+	g_free (path_dest);
+
+	return BRASERO_BURN_NOT_RUNNING;
+
+error:
+	g_free (path_src);
+	g_free (path_dest);
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroTrack *
+brasero_transcode_search_for_sibling (BraseroTranscode *transcode)
+{
+	BraseroJobAction action;
+	GSList *iter, *songs;
+	BraseroTrack *track;
+	gint64 start;
+	gint64 end;
+	gchar *uri;
+
+	brasero_job_get_action (BRASERO_JOB (transcode), &action);
+
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track));
+	end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track));
+	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+
+	brasero_job_get_done_tracks (BRASERO_JOB (transcode), &songs);
+
+	for (iter = songs; iter; iter = iter->next) {
+		gchar *iter_uri;
+		gint64 iter_end;
+		gint64 iter_start;
+		BraseroTrack *iter_track;
+
+		iter_track = iter->data;
+		iter_uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (iter_track), TRUE);
+
+		if (strcmp (iter_uri, uri))
+			continue;
+
+		iter_end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (iter_track));
+		if (!iter_end)
+			continue;
+
+		if (iter_end != end)
+			continue;
+
+		iter_start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track));
+		if (iter_start == start) {
+			g_free (uri);
+			return iter_track;
+		}
+	}
+
+	g_free (uri);
+	return NULL;
+}
+
+static BraseroBurnResult
+brasero_transcode_has_track_sibling (BraseroTranscode *transcode,
+				     GError **error)
+{
+	BraseroJobAction action;
+	BraseroTrack *sibling = NULL;
+	BraseroBurnResult result = BRASERO_BURN_OK;
+
+	if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) == BRASERO_BURN_OK)
+		return BRASERO_BURN_OK;
+
+	sibling = brasero_transcode_search_for_sibling (transcode);
+	if (!sibling)
+		return BRASERO_BURN_OK;
+
+	BRASERO_JOB_LOG (transcode, "found sibling: skipping");
+	brasero_job_get_action (BRASERO_JOB (transcode), &action);
+	if (action == BRASERO_JOB_ACTION_IMAGE)
+		result = brasero_transcode_create_sibling_image (transcode,
+								 sibling,
+								 error);
+	else if (action == BRASERO_JOB_ACTION_SIZE)
+		result = brasero_transcode_create_sibling_size (transcode,
+								sibling,
+								error);
+
+	return result;
+}
+
+static BraseroBurnResult
+brasero_transcode_start (BraseroJob *job,
+			 GError **error)
+{
+	BraseroTranscode *transcode;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+
+	transcode = BRASERO_TRANSCODE (job);
+
+	brasero_job_get_action (job, &action);
+	brasero_job_set_use_average_rate (job, TRUE);
+
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		BraseroTrack *track;
+
+		/* see if the track size was already set since then no need to 
+		 * carry on with a lengthy get size and the library will do it
+		 * itself. */
+		brasero_job_get_current_track (job, &track);
+		if (brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track)) > 0)
+			return BRASERO_BURN_NOT_SUPPORTED;
+
+		if (!brasero_transcode_create_pipeline (transcode, error))
+			return BRASERO_BURN_ERR;
+
+		brasero_job_set_current_action (job,
+						BRASERO_BURN_ACTION_GETTING_SIZE,
+						NULL,
+						TRUE);
+
+		brasero_job_start_progress (job, FALSE);
+		return BRASERO_BURN_OK;
+	}
+
+	if (action == BRASERO_JOB_ACTION_IMAGE) {
+		/* Look for a sibling to avoid transcoding twice. In this case
+		 * though start and end of this track must be inside start and
+		 * end of the previous track. Of course if we are piping that
+		 * operation is simply impossible. */
+		if (brasero_job_get_fd_out (job, NULL) != BRASERO_BURN_OK) {
+			result = brasero_transcode_has_track_sibling (BRASERO_TRANSCODE (job), error);
+			if (result != BRASERO_BURN_OK)
+				return result;
+		}
+
+		brasero_transcode_set_boundaries (transcode);
+		if (!brasero_transcode_create_pipeline (transcode, error))
+			return BRASERO_BURN_ERR;
+	}
+	else
+		BRASERO_JOB_NOT_SUPPORTED (transcode);
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_transcode_stop_pipeline (BraseroTranscode *transcode)
+{
+	BraseroTranscodePrivate *priv;
+	GstPad *sinkpad;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+	if (!priv->pipeline)
+		return;
+
+	sinkpad = gst_element_get_pad (priv->sink, "sink");
+	if (priv->probe)
+		gst_pad_remove_buffer_probe (sinkpad, priv->probe);
+
+	gst_object_unref (sinkpad);
+
+	gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+	gst_object_unref (GST_OBJECT (priv->pipeline));
+
+	priv->link = NULL;
+	priv->sink = NULL;
+	priv->source = NULL;
+	priv->convert = NULL;
+	priv->pipeline = NULL;
+
+	priv->set_active_state = 0;
+}
+
+static BraseroBurnResult
+brasero_transcode_stop (BraseroJob *job,
+			GError **error)
+{
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (job);
+
+	priv->mp3_size_pipeline = 0;
+
+	if (priv->pad_id) {
+		g_source_remove (priv->pad_id);
+		priv->pad_id = 0;
+	}
+
+	brasero_transcode_stop_pipeline (BRASERO_TRANSCODE (job));
+	return BRASERO_BURN_OK;
+}
+
+/* we must make sure that the track size is a multiple
+ * of 2352 to be burnt by cdrecord with on the fly */
+
+static gint64
+brasero_transcode_pad_real (BraseroTranscode *transcode,
+			    int fd,
+			    gint64 bytes2write,
+			    GError **error)
+{
+	const int buffer_size = 512;
+	char buffer [buffer_size];
+	gint64 b_written;
+	gint64 size;
+
+	b_written = 0;
+	bzero (buffer, sizeof (buffer));
+	for (; bytes2write; bytes2write -= b_written) {
+		size = bytes2write > buffer_size ? buffer_size : bytes2write;
+		b_written = write (fd, buffer, (int) size);
+
+		BRASERO_JOB_LOG (transcode,
+				 "written %" G_GINT64_FORMAT " bytes for padding",
+				 b_written);
+
+		/* we should not handle EINTR and EAGAIN as errors */
+		if (b_written < 0) {
+			if (errno == EINTR || errno == EAGAIN) {
+				BRASERO_JOB_LOG (transcode, "got EINTR / EAGAIN, retrying");
+	
+				/* we'll try later again */
+				return bytes2write;
+			}
+		}
+
+		if (size != b_written) {
+                        int errsv = errno;
+
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     /* Translators: %s is the string error from errno */
+				     _("Error while padding file (%s)"),
+				     g_strerror (errsv));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void
+brasero_transcode_push_track (BraseroTranscode *transcode)
+{
+	guint64 length = 0;
+	gchar *output = NULL;
+	BraseroTrack *src = NULL;
+	BraseroTrackStream *track;
+
+	brasero_job_get_audio_output (BRASERO_JOB (transcode), &output);
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &src);
+
+	brasero_track_stream_get_length (BRASERO_TRACK_STREAM (src), &length);
+
+	track = brasero_track_stream_new ();
+	brasero_track_stream_set_source (track, output);
+	brasero_track_stream_set_format (track,
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100);
+	brasero_track_stream_set_boundaries (track, 0, length, 0);
+	brasero_track_tag_copy_missing (BRASERO_TRACK (track), src);
+
+	brasero_job_add_track (BRASERO_JOB (transcode), BRASERO_TRACK (track));
+
+	/* It's good practice to unref the track afterwards as we don't need it
+	 * anymore. BraseroTaskCtx refs it. */
+	g_object_unref (track);
+
+	brasero_job_finished_track (BRASERO_JOB (transcode));
+}
+
+static gboolean
+brasero_transcode_pad_idle (BraseroTranscode *transcode)
+{
+	gint64 bytes2write;
+	GError *error = NULL;
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+	bytes2write = brasero_transcode_pad_real (transcode,
+						  priv->pad_fd,
+						  priv->pad_size,
+						  &error);
+
+	if (bytes2write == -1) {
+		priv->pad_id = 0;
+		brasero_job_error (BRASERO_JOB (transcode), error);
+		return FALSE;
+	}
+
+	if (bytes2write) {
+		priv->pad_size = bytes2write;
+		return TRUE;
+	}
+
+	/* we are finished with padding */
+	priv->pad_id = 0;
+	close (priv->pad_fd);
+	priv->pad_fd = -1;
+
+	/* set the next song or finish */
+	brasero_transcode_push_track (transcode);
+	return FALSE;
+}
+
+static gboolean
+brasero_transcode_pad (BraseroTranscode *transcode, int fd, GError **error)
+{
+	guint64 length = 0;
+	gint64 bytes2write = 0;
+	BraseroTrack *track = NULL;
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+	if (priv->pos < 0)
+		return TRUE;
+
+	/* Padding is important for two reasons:
+	 * - first if didn't output enough bytes compared to what we should have
+	 * - second we must output a multiple of 2352 to respect sector
+	 *   boundaries */
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
+
+	if (priv->pos < BRASERO_DURATION_TO_BYTES (length)) {
+		gint64 b_written = 0;
+
+		/* Check bytes boundary for length */
+		b_written = BRASERO_DURATION_TO_BYTES (length);
+		b_written += (b_written % 2352) ? 2352 - (b_written % 2352):0;
+		bytes2write = b_written - priv->pos;
+
+		BRASERO_JOB_LOG (transcode,
+				 "wrote %lli bytes (= %lli ns) out of %lli (= %lli ns)"
+				 "\n=> padding %lli bytes",
+				 priv->pos,
+				 BRASERO_BYTES_TO_DURATION (priv->pos),
+				 BRASERO_DURATION_TO_BYTES (length),
+				 length,
+				 bytes2write);
+	}
+	else {
+		gint64 b_written = 0;
+
+		/* wrote more or the exact amount of bytes. Check bytes boundary */
+		b_written = priv->pos;
+		bytes2write = (b_written % 2352) ? 2352 - (b_written % 2352):0;
+		BRASERO_JOB_LOG (transcode,
+				 "wrote %lli bytes (= %lli ns)"
+				 "\n=> padding %lli bytes",
+				 b_written,
+				 priv->pos,
+				 bytes2write);
+	}
+
+	if (!bytes2write)
+		return TRUE;
+
+	bytes2write = brasero_transcode_pad_real (transcode,
+						  fd,
+						  bytes2write,
+						  error);
+	if (bytes2write == -1)
+		return TRUE;
+
+	if (bytes2write) {
+		BraseroTranscodePrivate *priv;
+
+		priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+		/* when writing to a pipe it can happen that its buffer is full
+		 * because cdrecord is not fast enough. Therefore we couldn't
+		 * write/pad it and we'll have to wait for the pipe to become
+		 * available again */
+		priv->pad_fd = fd;
+		priv->pad_size = bytes2write;
+		priv->pad_id = g_timeout_add (50,
+					     (GSourceFunc) brasero_transcode_pad_idle,
+					      transcode);
+		return FALSE;		
+	}
+
+	return TRUE;
+}
+
+static gboolean
+brasero_transcode_pad_pipe (BraseroTranscode *transcode, GError **error)
+{
+	int fd;
+	gboolean result;
+
+	brasero_job_get_fd_out (BRASERO_JOB (transcode), &fd);
+	fd = dup (fd);
+
+	result = brasero_transcode_pad (transcode, fd, error);
+	if (result)
+		close (fd);
+
+	return result;
+}
+
+static gboolean
+brasero_transcode_pad_file (BraseroTranscode *transcode, GError **error)
+{
+	int fd;
+	gchar *output;
+	gboolean result;
+
+	output = NULL;
+	brasero_job_get_audio_output (BRASERO_JOB (transcode), &output);
+	fd = open (output, O_WRONLY | O_CREAT | O_APPEND, S_IRWXU | S_IRGRP | S_IROTH);
+	g_free (output);
+
+	if (fd == -1) {
+                int errsv = errno;
+
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: %s is the string error from errno */
+			     _("Error while padding file (%s)"),
+			     g_strerror (errsv));
+		return FALSE;
+	}
+
+	result = brasero_transcode_pad (transcode, fd, error);
+	if (result)
+		close (fd);
+
+	return result;
+}
+
+static gboolean
+brasero_transcode_is_mp3 (BraseroTranscode *transcode)
+{
+	BraseroTranscodePrivate *priv;
+	GstElement *typefind;
+	GstCaps *caps = NULL;
+	const gchar *mime;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	/* find the type of the file */
+	typefind = gst_bin_get_by_name (GST_BIN (priv->decode), "typefind");
+	g_object_get (typefind, "caps", &caps, NULL);
+	if (!caps) {
+		gst_object_unref (typefind);
+		return TRUE;
+	}
+
+	if (caps && gst_caps_get_size (caps) > 0) {
+		mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+		gst_object_unref (typefind);
+
+		if (mime && !strcmp (mime, "application/x-id3"))
+			return TRUE;
+
+		if (!strcmp (mime, "audio/mpeg"))
+			return TRUE;
+	}
+	else
+		gst_object_unref (typefind);
+
+	return FALSE;
+}
+
+static gint64
+brasero_transcode_get_duration (BraseroTranscode *transcode)
+{
+	gint64 duration = -1;
+	BraseroTranscodePrivate *priv;
+	GstFormat format = GST_FORMAT_TIME;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	/* This part is specific to MP3s */
+	if (priv->mp3_size_pipeline) {
+		/* This is the most reliable way to get the duration for mp3
+		 * read them till the end and get the position. */
+		gst_element_query_position (priv->pipeline,
+					    &format,
+					    &duration);
+	}
+
+	/* This is for any sort of files */
+	if (duration == -1 || duration == 0)
+		gst_element_query_duration (priv->pipeline,
+					    &format,
+					    &duration);
+
+	BRASERO_JOB_LOG (transcode, "got duration %"G_GINT64_FORMAT, duration);
+
+	if (duration == -1 || duration == 0)	
+	    brasero_job_error (BRASERO_JOB (transcode),
+			       g_error_new (BRASERO_BURN_ERROR,
+					    BRASERO_BURN_ERROR_GENERAL,
+					    _("Error while getting duration")));
+	return duration;
+}
+
+static gboolean
+brasero_transcode_song_end_reached (BraseroTranscode *transcode)
+{
+	GError *error = NULL;
+	BraseroJobAction action;
+
+	brasero_job_get_action (BRASERO_JOB (transcode), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		gint64 duration;
+
+		/* this is when we need to write infs:
+		 * - when asked to create infs
+		 * - when decoding to a file */
+		duration = brasero_transcode_get_duration (transcode);
+		if (duration == -1)
+			return FALSE;
+
+		brasero_transcode_set_track_size (transcode, duration);
+		brasero_job_finished_track (BRASERO_JOB (transcode));
+		return TRUE;
+	}
+
+	if (action == BRASERO_JOB_ACTION_IMAGE) {
+		gboolean result;
+
+		/* pad file so it is a multiple of 2352 (= 1 sector) */
+		if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) == BRASERO_BURN_OK)
+			result = brasero_transcode_pad_pipe (transcode, &error);
+		else
+			result = brasero_transcode_pad_file (transcode, &error);
+	
+		if (error) {
+			brasero_job_error (BRASERO_JOB (transcode), error);
+			return FALSE;
+		}
+
+		if (!result) {
+			brasero_transcode_stop_pipeline (transcode);
+			return FALSE;
+		}
+	}
+
+	brasero_transcode_push_track (transcode);
+	return TRUE;
+}
+
+static void
+foreach_tag (const GstTagList *list,
+	     const gchar *tag,
+	     BraseroTranscode *transcode)
+{
+	BraseroTrack *track;
+	BraseroJobAction action;
+
+	brasero_job_get_action (BRASERO_JOB (transcode), &action);
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+
+	BRASERO_JOB_LOG (transcode, "Retrieving tags");
+
+	if (!strcmp (tag, GST_TAG_TITLE)) {
+		if (!brasero_track_tag_lookup_string (track, BRASERO_TRACK_STREAM_TITLE_TAG)) {
+			gchar *title = NULL;
+
+			gst_tag_list_get_string (list, tag, &title);
+			brasero_track_tag_add_string (track,
+						      BRASERO_TRACK_STREAM_TITLE_TAG,
+						      title);
+			g_free (title);
+		}
+	}
+	else if (!strcmp (tag, GST_TAG_ARTIST)) {
+		if (!brasero_track_tag_lookup_string (track, BRASERO_TRACK_STREAM_ARTIST_TAG)) {
+			gchar *artist = NULL;
+
+			gst_tag_list_get_string (list, tag, &artist);
+			brasero_track_tag_add_string (track,
+						      BRASERO_TRACK_STREAM_ARTIST_TAG,
+						      artist);
+			g_free (artist);
+		}
+	}
+	else if (!strcmp (tag, GST_TAG_ISRC)) {
+		if (!brasero_track_tag_lookup_int (track, BRASERO_TRACK_STREAM_ISRC_TAG)) {
+			gint isrc = 0;
+
+			gst_tag_list_get_int (list, tag, &isrc);
+			brasero_track_tag_add_int (track,
+						   BRASERO_TRACK_STREAM_ARTIST_TAG,
+						   isrc);
+		}
+	}
+	else if (!strcmp (tag, GST_TAG_PERFORMER)) {
+		if (!brasero_track_tag_lookup_string (track, BRASERO_TRACK_STREAM_ARTIST_TAG)) {
+			gchar *artist = NULL;
+
+			gst_tag_list_get_string (list, tag, &artist);
+			brasero_track_tag_add_string (track,
+						      BRASERO_TRACK_STREAM_ARTIST_TAG,
+						      artist);
+			g_free (artist);
+		}
+	}
+	else if (action == BRASERO_JOB_ACTION_SIZE
+	     &&  !strcmp (tag, GST_TAG_DURATION)) {
+		guint64 duration;
+
+		/* this is only useful when we try to have the size */
+		gst_tag_list_get_uint64 (list, tag, &duration);
+		brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track), 0, duration, -1);
+	}
+}
+
+/* NOTE: the return value is whether or not we should stop the bus callback */
+static gboolean
+brasero_transcode_active_state (BraseroTranscode *transcode)
+{
+	BraseroTranscodePrivate *priv;
+	gchar *name, *string, *uri;
+	BraseroJobAction action;
+	BraseroTrack *track;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	if (priv->set_active_state)
+		return TRUE;
+
+	priv->set_active_state = TRUE;
+
+	brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+
+	brasero_job_get_action (BRASERO_JOB (transcode), &action);
+	if (action == BRASERO_JOB_ACTION_SIZE) {
+		BRASERO_JOB_LOG (transcode,
+				 "Analysing Track %s",
+				 uri);
+
+		if (priv->mp3_size_pipeline) {
+			/* Run the pipeline till the end */
+			BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
+			string = g_strdup_printf (_("Analysing \"%s\""), name);
+			g_free (name);
+		
+			brasero_job_set_current_action (BRASERO_JOB (transcode),
+							BRASERO_BURN_ACTION_ANALYSING,
+							string,
+							TRUE);
+			g_free (string);
+
+			brasero_job_start_progress (BRASERO_JOB (transcode), FALSE);
+			g_free (uri);
+			return TRUE;
+		}
+
+		if (brasero_transcode_is_mp3 (transcode)) {
+			GError *error = NULL;
+
+			/* Rebuild another pipeline which is specific to MP3s. */
+			priv->mp3_size_pipeline = TRUE;
+			brasero_transcode_stop_pipeline (transcode);
+
+			if (!brasero_transcode_create_pipeline (transcode, &error))
+				brasero_job_error (BRASERO_JOB (transcode), error);
+		}
+		else
+			brasero_transcode_song_end_reached (transcode);
+
+		g_free (uri);
+		return FALSE;
+	}
+	else {
+		BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
+		string = g_strdup_printf (_("Transcoding \"%s\""), name);
+		g_free (name);
+
+		brasero_job_set_current_action (BRASERO_JOB (transcode),
+						BRASERO_BURN_ACTION_TRANSCODING,
+						string,
+						TRUE);
+		g_free (string);
+		brasero_job_start_progress (BRASERO_JOB (transcode), FALSE);
+
+		if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) {
+			gchar *dest = NULL;
+
+			brasero_job_get_audio_output (BRASERO_JOB (transcode), &dest);
+			BRASERO_JOB_LOG (transcode,
+					 "start decoding %s to %s",
+					 uri,
+					 dest);
+		}
+		else
+			BRASERO_JOB_LOG (transcode,
+					 "start piping %s",
+					 uri)
+	}
+
+	g_free (uri);
+	return TRUE;
+}
+
+static gboolean
+brasero_transcode_bus_messages (GstBus *bus,
+				GstMessage *msg,
+				BraseroTranscode *transcode)
+{
+	BraseroTranscodePrivate *priv;
+	GstTagList *tags = NULL;
+	GError *error = NULL;
+	GstState state;
+	gchar *debug;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_TAG:
+		/* we use the information to write an .inf file 
+		 * for the time being just store the information */
+		gst_message_parse_tag (msg, &tags);
+		gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, transcode);
+		gst_tag_list_free (tags);
+		return TRUE;
+
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error (msg, &error, &debug);
+		BRASERO_JOB_LOG (transcode, debug);
+		g_free (debug);
+
+	        brasero_job_error (BRASERO_JOB (transcode), error);
+		return FALSE;
+
+	case GST_MESSAGE_EOS:
+		brasero_transcode_song_end_reached (transcode);
+		return FALSE;
+
+	case GST_MESSAGE_STATE_CHANGED: {
+		GstStateChangeReturn result;
+
+		result = gst_element_get_state (priv->pipeline,
+						&state,
+						NULL,
+						1);
+
+		if (result != GST_STATE_CHANGE_SUCCESS)
+			return TRUE;
+
+		if (state == GST_STATE_PLAYING)
+			return brasero_transcode_active_state (transcode);
+
+		break;
+	}
+
+	default:
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+static void
+brasero_transcode_error_on_pad_linking (BraseroTranscode *self)
+{
+	BraseroTranscodePrivate *priv;
+	GstMessage *message;
+	GstBus *bus;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (self);
+
+	BRASERO_JOB_LOG (self, "Error on pad linking");
+	message = gst_message_new_error (GST_OBJECT (priv->pipeline),
+					 g_error_new (BRASERO_BURN_ERROR,
+						      BRASERO_BURN_ERROR_GENERAL,
+						      /* Translators: This message is sent
+						       * when brasero could not link together
+						       * two gstreamer plugins so that one
+						       * sends its data to the second for further
+						       * processing. This data transmission is
+						       * done through a pad. Maybe this is a bit
+						       * too technical and should be removed? */
+						      _("Impossible to link plugin pads")),
+					 "Sent by brasero_metadata_error_on_pad_linking");
+
+	bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+	gst_bus_post (bus, message);
+	g_object_unref (bus);
+}
+
+static void
+brasero_transcode_new_decoded_pad_cb (GstElement *decode,
+				      GstPad *pad,
+				      gboolean arg2,
+				      BraseroTranscode *transcode)
+{
+	GstCaps *caps;
+	GstStructure *structure;
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+	BRASERO_JOB_LOG (transcode, "New pad");
+
+	/* make sure we only have audio */
+	caps = gst_pad_get_caps (pad);
+	if (!caps)
+		return;
+
+	structure = gst_caps_get_structure (caps, 0);
+	if (structure) {
+		if (g_strrstr (gst_structure_get_name (structure), "audio")) {
+			GstPad *sink;
+			GstElement *queue;
+			GstPadLinkReturn res;
+
+			/* before linking pads (before any data reach grvolume), send tags */
+			brasero_transcode_send_volume_event (transcode);
+
+			/* This is necessary in case there is a video stream
+			 * (see brasero-metadata.c). we need to queue to avoid
+			 * a deadlock. */
+			queue = gst_element_factory_make ("queue", NULL);
+			gst_bin_add (GST_BIN (priv->pipeline), queue);
+			if (!gst_element_link (queue, priv->link)) {
+				brasero_transcode_error_on_pad_linking (transcode);
+				goto end;
+			}
+
+			sink = gst_element_get_pad (queue, "sink");
+			if (GST_PAD_IS_LINKED (sink)) {
+				brasero_transcode_error_on_pad_linking (transcode);
+				goto end;
+			}
+
+			res = gst_pad_link (pad, sink);
+			if (res == GST_PAD_LINK_OK)
+				gst_element_set_state (queue, GST_STATE_PLAYING);
+			else
+				brasero_transcode_error_on_pad_linking (transcode);
+
+			gst_object_unref (sink);
+		}
+		/* For video streams add a fakesink (see brasero-metadata.c) */
+		else if (g_strrstr (gst_structure_get_name (structure), "video")) {
+			GstPad *sink;
+			GstElement *fakesink;
+			GstPadLinkReturn res;
+
+			BRASERO_JOB_LOG (transcode, "Adding a fakesink for video stream");
+
+			fakesink = gst_element_factory_make ("fakesink", NULL);
+			if (!fakesink) {
+				brasero_transcode_error_on_pad_linking (transcode);
+				goto end;
+			}
+
+			sink = gst_element_get_static_pad (fakesink, "sink");
+			if (!sink) {
+				brasero_transcode_error_on_pad_linking (transcode);
+				gst_object_unref (fakesink);
+				goto end;
+			}
+
+			gst_bin_add (GST_BIN (priv->pipeline), fakesink);
+			res = gst_pad_link (pad, sink);
+
+			if (res == GST_PAD_LINK_OK)
+				gst_element_set_state (fakesink, GST_STATE_PLAYING);
+			else
+				brasero_transcode_error_on_pad_linking (transcode);
+
+			gst_object_unref (sink);
+		}
+	}
+
+end:
+	gst_caps_unref (caps);
+}
+
+static BraseroBurnResult
+brasero_transcode_clock_tick (BraseroJob *job)
+{
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (job);
+
+	if (!priv->pipeline)
+		return BRASERO_BURN_ERR;
+
+	brasero_job_set_written_track (job, priv->pos);
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_transcode_class_init (BraseroTranscodeClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroTranscodePrivate));
+
+	parent_class = g_type_class_peek_parent (klass);
+	object_class->finalize = brasero_transcode_finalize;
+
+	job_class->start = brasero_transcode_start;
+	job_class->clock_tick = brasero_transcode_clock_tick;
+	job_class->stop = brasero_transcode_stop;
+}
+
+static void
+brasero_transcode_init (BraseroTranscode *obj)
+{ }
+
+static void
+brasero_transcode_finalize (GObject *object)
+{
+	BraseroTranscodePrivate *priv;
+
+	priv = BRASERO_TRANSCODE_PRIVATE (object);
+
+	if (priv->pad_id) {
+		g_source_remove (priv->pad_id);
+		priv->pad_id = 0;
+	}
+
+	brasero_transcode_stop_pipeline (BRASERO_TRANSCODE (object));
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_transcode_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	GSList *output;
+
+	brasero_plugin_define (plugin,
+			       "transcode",
+			       _("Transcode converts song files into a format proper to burn them on CDs"),
+			       "Philippe Rouquier",
+			       0);
+
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_METADATA_INFO);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED|
+					BRASERO_METADATA_INFO);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/transcode/burn-transcode.h b/plugins/transcode/burn-transcode.h
new file mode 100644
index 0000000..fb42802
--- /dev/null
+++ b/plugins/transcode/burn-transcode.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *            transcode.h
+ *
+ *  ven jui  8 16:15:04 2005
+ *  Copyright  2005  Philippe Rouquier
+ *  Brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ *  Brasero is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Brasero is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef TRANSCODE_H
+#define TRANSCODE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_TRANSCODE         (brasero_transcode_get_type ())
+#define BRASERO_TRANSCODE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_TRANSCODE, BraseroTranscode))
+#define BRASERO_TRANSCODE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_TRANSCODE, BraseroTranscodeClass))
+#define BRASERO_IS_TRANSCODE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_TRANSCODE))
+#define BRASERO_IS_TRANSCODE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_TRANSCODE))
+#define BRASERO_TRANSCODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_TRANSCODE, BraseroTranscodeClass))
+
+G_END_DECLS
+
+#endif				/* TRANSCODE_H */
diff --git a/plugins/transcode/burn-vob.c b/plugins/transcode/burn-vob.c
new file mode 100644
index 0000000..94f300c
--- /dev/null
+++ b/plugins/transcode/burn-vob.c
@@ -0,0 +1,1269 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-vob.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero-vob.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero-vob.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-vob.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "brasero-tags.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-vob.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroVob, brasero_vob, BRASERO_TYPE_JOB, BraseroJob);
+
+typedef struct _BraseroVobPrivate BraseroVobPrivate;
+struct _BraseroVobPrivate
+{
+	GstElement *pipeline;
+
+	GstElement *audio;
+	GstElement *video;
+
+	BraseroStreamFormat format;
+
+	guint svcd:1;
+	guint is_video_dvd:1;
+};
+
+#define BRASERO_VOB_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VOB, BraseroVobPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static void
+brasero_vob_stop_pipeline (BraseroVob *vob)
+{
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+	if (!priv->pipeline)
+		return;
+
+	gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+	gst_object_unref (GST_OBJECT (priv->pipeline));
+	priv->pipeline = NULL;
+}
+
+static BraseroBurnResult
+brasero_vob_stop (BraseroJob *job,
+		  GError **error)
+{
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (job);
+
+	brasero_vob_stop_pipeline (BRASERO_VOB (job));
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_vob_finished (BraseroVob *vob)
+{
+	BraseroTrackType *type = NULL;
+	BraseroTrackStream *track;
+	BraseroVobPrivate *priv;
+	gchar *output = NULL;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	type = brasero_track_type_new ();
+	brasero_job_get_output_type (BRASERO_JOB (vob), type);
+	brasero_job_get_audio_output (BRASERO_JOB (vob), &output);
+
+	track = brasero_track_stream_new ();
+	brasero_track_stream_set_source (track, output);
+	brasero_track_stream_set_format (track, brasero_track_type_get_stream_format (type));
+
+	brasero_job_add_track (BRASERO_JOB (vob), BRASERO_TRACK (track));
+	g_object_unref (track);
+
+	brasero_track_type_free (type);
+	g_free (output);
+
+	brasero_job_finished_track (BRASERO_JOB (vob));
+}
+
+static gboolean
+brasero_vob_bus_messages (GstBus *bus,
+			  GstMessage *msg,
+			  BraseroVob *vob)
+{
+	BraseroVobPrivate *priv;
+	GError *error = NULL;
+	gchar *debug;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_TAG:
+		return TRUE;
+
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error (msg, &error, &debug);
+		BRASERO_JOB_LOG (vob, debug);
+		g_free (debug);
+
+	        brasero_job_error (BRASERO_JOB (vob), error);
+		return FALSE;
+
+	case GST_MESSAGE_EOS:
+		BRASERO_JOB_LOG (vob, "Transcoding finished");
+
+		/* add a new track and terminate */
+		brasero_vob_finished (vob);
+		return FALSE;
+
+	case GST_MESSAGE_STATE_CHANGED:
+		break;
+
+	default:
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+static void
+brasero_vob_new_decoded_pad_cb (GstElement *decode,
+				GstPad *pad,
+				gboolean arg2,
+				BraseroVob *vob)
+{
+	GstPad *sink;
+	GstCaps *caps;
+	GstStructure *structure;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* make sure we only have audio */
+	caps = gst_pad_get_caps (pad);
+	if (!caps)
+		return;
+
+	structure = gst_caps_get_structure (caps, 0);
+	if (structure) {
+		if (g_strrstr (gst_structure_get_name (structure), "video")) {
+			sink = gst_element_get_pad (priv->video, "sink");
+			gst_pad_link (pad, sink);
+			gst_object_unref (sink);
+
+			gst_element_set_state (priv->video, GST_STATE_PLAYING);
+		}
+
+		if (g_strrstr (gst_structure_get_name (structure), "audio")) {
+			sink = gst_element_get_pad (priv->audio, "sink");
+			gst_pad_link (pad, sink);
+			gst_object_unref (sink);
+
+			gst_element_set_state (priv->audio, GST_STATE_PLAYING);
+		}
+	}
+
+	gst_caps_unref (caps);
+}
+
+static gboolean
+brasero_vob_link_audio (BraseroVob *vob,
+			GstElement *start,
+			GstElement *end,
+			GstElement *tee,
+			GstElement *muxer)
+{
+	GstPad *srcpad;
+	GstPad *sinkpad;
+	GstPadLinkReturn res;
+
+	srcpad = gst_element_get_request_pad (tee, "src%d");
+	sinkpad = gst_element_get_static_pad (start, "sink");
+	res = gst_pad_link (srcpad, sinkpad);
+	gst_object_unref (sinkpad);
+	gst_object_unref (srcpad);
+
+	BRASERO_JOB_LOG (vob, "Linked audio bin to tee == %d", res);
+	if (res != GST_PAD_LINK_OK)
+		return FALSE;
+
+	sinkpad = gst_element_get_request_pad (muxer, "audio_%d");
+	srcpad = gst_element_get_static_pad (end, "src");
+	res = gst_pad_link (srcpad, sinkpad);
+	gst_object_unref (sinkpad);
+	gst_object_unref (srcpad);
+
+	BRASERO_JOB_LOG (vob, "Linked audio bin to muxer == %d", res);
+	if (res != GST_PAD_LINK_OK)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_vob_build_audio_pcm (BraseroVob *vob,
+			     GstElement *tee,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GstElement *queue;
+	GstElement *queue1;
+	GstElement *filter;
+	GstElement *convert;
+	GstCaps *filtercaps;
+	GstElement *resample;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* NOTE: this can only be used for Video DVDs as PCM cannot be used for
+	 * (S)VCDs. */
+
+	/* queue */
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: %s is the name of the GstElement that 
+			      * could not be created */
+			     _("%s element could not be created"),
+			     "\"Queue\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: %s is the name of the GstElement that 
+			      * could not be created */
+			     _("%s element could not be created"),
+			     "\"Audioresample\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     /* Translators: %s is the name of the GstElement that 
+			      * element could not be created */
+			     _("%s element could not be created"),
+			     "\"Audioconvert\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+	/* another queue */
+	queue1 = gst_element_factory_make ("queue", NULL);
+	if (queue1 == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue1\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+	/* create a filter */
+	filter = gst_element_factory_make ("capsfilter", NULL);
+	if (filter == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Filter\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+	/* NOTE: what about the number of channels (up to 6) ? */
+	filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+							   "width", G_TYPE_INT, 16,
+							   "depth", G_TYPE_INT, 16,
+							   "rate", G_TYPE_INT, 48000,
+							   NULL),
+					NULL);
+
+	g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+	gst_caps_unref (filtercaps);
+
+	gst_element_link_many (queue, resample, convert, filter, queue1, NULL);
+	brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+
+	return TRUE;
+
+error:
+
+	return FALSE;
+}
+
+static gboolean
+brasero_vob_build_audio_mp2 (BraseroVob *vob,
+			     GstElement *tee,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GstElement *queue;
+	GstElement *queue1;
+	GstElement *encode;
+	GstElement *filter;
+	GstElement *convert;
+	GstCaps *filtercaps;
+	GstElement *resample;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* queue */
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioconvert\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioresample\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+	/* encoder */
+	encode = gst_element_factory_make ("ffenc_mp2", NULL);
+	if (encode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"ffenc_mp2\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+	/* another queue */
+	queue1 = gst_element_factory_make ("queue", NULL);
+	if (queue1 == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue1\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+	/* create a filter */
+	filter = gst_element_factory_make ("capsfilter", NULL);
+	if (filter == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Filter\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+	if (priv->is_video_dvd) {
+		BRASERO_JOB_LOG (vob, "Setting mp2 bitrate to 448000, 48000 khz");
+		g_object_set (encode,
+			      "bitrate", 448000, /* it could go up to 912k */
+			      NULL);
+
+		/* NOTE: what about the number of channels (up to 7.1) ? */
+		filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+								   "rate", G_TYPE_INT, 48000,
+								   NULL),
+						NULL);
+	}
+	else if (!priv->svcd) {
+		/* VCD */
+		BRASERO_JOB_LOG (vob, "Setting mp2 bitrate to 224000, 44100 khz");
+		g_object_set (encode,
+			      "bitrate", 224000,
+			      NULL);
+
+		/* 2 channels tops */
+		filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+								   "channels", G_TYPE_INT, 2,
+								   "rate", G_TYPE_INT, 44100,
+								   NULL),
+						NULL);
+	}
+	else {
+		/* SVCDs */
+		BRASERO_JOB_LOG (vob, "Setting mp2 bitrate to 384000, 44100 khz");
+		g_object_set (encode,
+			      "bitrate", 384000,
+			      NULL);
+
+		/* NOTE: channels up to 5.1 or dual */
+		filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+								   "rate", G_TYPE_INT, 44100,
+								   NULL),
+						NULL);
+	}
+
+	g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+	gst_caps_unref (filtercaps);
+
+	gst_element_link_many (queue, convert, resample, filter, encode, queue1, NULL);
+
+	brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+	return TRUE;
+
+error:
+
+	return FALSE;
+}
+
+static gboolean
+brasero_vob_build_audio_ac3 (BraseroVob *vob,
+			     GstElement *tee,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GstElement *queue;
+	GstElement *queue1;
+	GstElement *filter;
+	GstElement *encode;
+	GstElement *convert;
+	GstCaps *filtercaps;
+	GstElement *resample;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* NOTE: This has to be a DVD since AC3 is not supported by (S)VCD */
+
+	/* queue */
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioconvert\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Audioresample\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+	/* create a filter */
+	filter = gst_element_factory_make ("capsfilter", NULL);
+	if (filter == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Filter\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+	BRASERO_JOB_LOG (vob, "Setting AC3 rate to 48000");
+	/* NOTE: we may want to limit the number of channels. */
+	filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+							   "rate", G_TYPE_INT, 48000,
+							   NULL),
+					NULL);
+
+	g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+	gst_caps_unref (filtercaps);
+
+	/* encoder */
+	encode = gst_element_factory_make ("ffenc_ac3", NULL);
+	if (encode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Ffenc_ac3\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+	BRASERO_JOB_LOG (vob, "Setting AC3 bitrate to 448000");
+	g_object_set (encode,
+		      "bitrate", 448000, /* Maximum allowed, is it useful ? */
+		      NULL);
+
+	/* another queue */
+	queue1 = gst_element_factory_make ("queue", NULL);
+	if (queue1 == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue1\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+	gst_element_link_many (queue, convert, resample, filter, encode, queue1, NULL);
+	brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+
+	return TRUE;
+
+error:
+
+	return FALSE;
+}
+
+static GstElement *
+brasero_vob_build_audio_bins (BraseroVob *vob,
+			      GstElement *muxer,
+			      GError **error)
+{
+	GValue *value;
+	GstElement *tee;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* tee */
+	tee = gst_element_factory_make ("tee", NULL);
+	if (tee == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Tee\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), tee);
+
+	if (priv->is_video_dvd) {
+		/* Get output format */
+		value = NULL;
+		brasero_job_tag_lookup (BRASERO_JOB (vob),
+					BRASERO_DVD_STREAM_FORMAT,
+					&value);
+
+		if (value)
+			priv->format = g_value_get_int (value);
+
+		if (priv->format == BRASERO_AUDIO_FORMAT_NONE)
+			priv->format = BRASERO_AUDIO_FORMAT_RAW;
+
+		/* FIXME: for the moment even if we use tee, we can't actually
+		 * encode and use more than one audio stream */
+		if (priv->format & BRASERO_AUDIO_FORMAT_RAW) {
+			/* PCM : on demand */
+			BRASERO_JOB_LOG (vob, "Adding PCM audio stream");
+			if (!brasero_vob_build_audio_pcm (vob, tee, muxer, error))
+				goto error;
+		}
+
+		if (priv->format & BRASERO_AUDIO_FORMAT_AC3) {
+			/* AC3 : on demand */
+			BRASERO_JOB_LOG (vob, "Adding AC3 audio stream");
+			if (!brasero_vob_build_audio_ac3 (vob, tee, muxer, error))
+				goto error;
+		}
+
+		if (priv->format & BRASERO_AUDIO_FORMAT_MP2) {
+			/* MP2 : on demand */
+			BRASERO_JOB_LOG (vob, "Adding MP2 audio stream");
+			if (!brasero_vob_build_audio_mp2 (vob, tee, muxer, error))
+				goto error;
+		}
+	}
+	else if (!brasero_vob_build_audio_mp2 (vob, tee, muxer, error))
+		goto error;
+
+	return tee;
+
+error:
+	return NULL;
+}
+
+static GstElement *
+brasero_vob_build_video_bin (BraseroVob *vob,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GValue *value;
+	GstPad *srcpad;
+	GstPad *sinkpad;
+	GstElement *scale;
+	GstElement *queue;
+	GstElement *queue1;
+	GstElement *filter;
+	GstElement *encode;
+	GstPadLinkReturn res;
+	GstElement *framerate;
+	GstElement *colorspace;
+	BraseroVobPrivate *priv;
+	BraseroBurnResult result;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+	/* framerate and video type control */
+	framerate = gst_element_factory_make ("videorate", NULL);
+	if (framerate == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Framerate\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), framerate);
+	g_object_set (framerate,
+		      "silent", TRUE,
+		      NULL);
+
+	/* size scaling */
+	scale = gst_element_factory_make ("videoscale", NULL);
+	if (scale == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Videoscale\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), scale);
+
+	/* create a filter */
+	filter = gst_element_factory_make ("capsfilter", NULL);
+	if (filter == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Filter\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+	colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
+	if (colorspace == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Ffmepgcolorspace\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), colorspace);
+
+	encode = gst_element_factory_make ("mpeg2enc", NULL);
+	if (encode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Mpeg2enc\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+	if (priv->is_video_dvd)
+		g_object_set (encode,
+			      "format", 8,
+			      NULL);
+	else if (priv->svcd) {
+		/* Option to improve compatibility with vcdimager */
+		g_object_set (encode,
+			      "dummy-svcd-sof", TRUE,
+			      NULL);
+		g_object_set (encode,
+			      "format", 4,
+			      NULL);
+	}
+	else
+		g_object_set (encode,
+			      "format", 1,
+			      NULL);
+
+	/* settings */
+	value = NULL;
+	result = brasero_job_tag_lookup (BRASERO_JOB (vob),
+					 BRASERO_VIDEO_OUTPUT_FRAMERATE,
+					 &value);
+
+	if (result == BRASERO_BURN_OK && value) {
+		gint rate;
+		GstCaps *filtercaps = NULL;
+
+		rate = g_value_get_int (value);
+
+		if (rate == BRASERO_VIDEO_FRAMERATE_NTSC) {
+			g_object_set (encode,
+				      "norm", 110,
+				      "framerate", 4,
+				      NULL);
+
+			if (priv->is_video_dvd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								NULL);
+			else if (priv->svcd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								NULL);
+			else
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 240,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 240,
+										   NULL),
+								NULL);
+		}
+		else if (rate == BRASERO_VIDEO_FRAMERATE_PAL_SECAM) {
+			g_object_set (encode,
+				      "norm", 112,
+				      "framerate", 3,
+				      NULL);
+
+			if (priv->is_video_dvd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								NULL);
+			else if (priv->svcd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								NULL);
+			else
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 288,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 288,
+										   NULL),
+								NULL);
+		}
+
+		if (filtercaps) {
+			g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+			gst_caps_unref (filtercaps);
+		}
+	}
+
+	if (priv->is_video_dvd || priv->svcd) {
+		value = NULL;
+		result = brasero_job_tag_lookup (BRASERO_JOB (vob),
+						 BRASERO_VIDEO_OUTPUT_ASPECT,
+						 &value);
+		if (result == BRASERO_BURN_OK && value) {
+			gint aspect;
+
+			aspect = g_value_get_int (value);
+			if (aspect == BRASERO_VIDEO_ASPECT_4_3) {
+				BRASERO_JOB_LOG (vob, "Setting ration 4:3");
+				g_object_set (encode,
+					      "aspect", 2,
+					      NULL);
+			}
+			else if (aspect == BRASERO_VIDEO_ASPECT_16_9) {
+				BRASERO_JOB_LOG (vob, "Setting ration 16:9");
+				g_object_set (encode,
+					      "aspect", 3,
+					      NULL);	
+			}
+		}
+	}
+	else {
+		/* VCDs only support 4:3 */
+		BRASERO_JOB_LOG (vob, "Setting ration 4:3");
+		g_object_set (encode,
+			      "aspect", 2,
+			      NULL);
+	}
+
+	/* another queue */
+	queue1 = gst_element_factory_make ("queue", NULL);
+	if (queue1 == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Queue1\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+	gst_element_link_many (queue, framerate, scale, colorspace, filter, encode, queue1, NULL);
+
+	srcpad = gst_element_get_static_pad (queue1, "src");
+	sinkpad = gst_element_get_request_pad (muxer, "video_%d");
+	res = gst_pad_link (srcpad, sinkpad);
+	BRASERO_JOB_LOG (vob, "Linked video bin to muxer == %d", res)
+	gst_object_unref (sinkpad);
+	gst_object_unref (srcpad);
+
+	return queue;
+
+error:
+
+	return NULL;
+}
+
+static gboolean
+brasero_vob_build_pipeline (BraseroVob *vob,
+			    GError **error)
+{
+	gchar *uri;
+	GstBus *bus;
+	gchar *output;
+	GstElement *sink;
+	GstElement *muxer;
+	GstElement *source;
+	GstElement *decode;
+	BraseroTrack *track;
+	GstElement *pipeline;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	BRASERO_JOB_LOG (vob, "Creating new pipeline");
+
+	pipeline = gst_pipeline_new (NULL);
+	priv->pipeline = pipeline;
+
+	/* source */
+	brasero_job_get_current_track (BRASERO_JOB (vob), &track);
+	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+	source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+	if (source == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Source\"");
+		return FALSE;
+	}
+	gst_bin_add (GST_BIN (pipeline), source);
+	g_object_set (source,
+		      "typefind", FALSE,
+		      NULL);
+
+	/* decode */
+	decode = gst_element_factory_make ("decodebin", NULL);
+	if (decode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Decodebin\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), decode);
+	gst_element_link_many (source, decode, NULL);
+
+	/* muxer: "mplex" */
+	muxer = gst_element_factory_make ("mplex", NULL);
+	if (muxer == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Mplex\"");
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), muxer);
+
+	if (priv->is_video_dvd)
+		g_object_set (muxer,
+			      "format", 8,
+			      NULL);
+	else if (priv->svcd)
+		g_object_set (muxer,
+			      "format", 4,
+			      NULL);
+	else	/* This should be 1 but it causes frame drops */
+		g_object_set (muxer,
+			      "format", 4,
+			      NULL);
+
+	/* create sink */
+	output = NULL;
+	brasero_job_get_audio_output (BRASERO_JOB (vob), &output);
+	sink = gst_element_factory_make ("filesink", NULL);
+	if (sink == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("%s element could not be created"),
+			     "\"Sink\"");
+		return FALSE;
+	}
+	g_object_set (sink,
+		      "location", output,
+		      NULL);
+
+	gst_bin_add (GST_BIN (pipeline), sink);
+	gst_element_link (muxer, sink);
+
+	/* video encoding */
+	priv->video = brasero_vob_build_video_bin (vob, muxer, error);
+	if (!priv->video)
+		goto error;
+
+	/* audio encoding */
+	priv->audio = brasero_vob_build_audio_bins (vob, muxer, error);
+	if (!priv->audio)
+		goto error;
+
+	/* to be able to link everything */
+	g_signal_connect (G_OBJECT (decode),
+			  "new-decoded-pad",
+			  G_CALLBACK (brasero_vob_new_decoded_pad_cb),
+			  vob);
+
+	/* connect to the bus */	
+	bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+	gst_bus_add_watch (bus,
+			   (GstBusFunc) brasero_vob_bus_messages,
+			   vob);
+	gst_object_unref (bus);
+
+	return TRUE;
+
+error:
+
+	if (error && (*error))
+		BRASERO_JOB_LOG (vob,
+				 "can't create object : %s \n",
+				 (*error)->message);
+
+	gst_object_unref (GST_OBJECT (pipeline));
+	return FALSE;
+}
+
+static BraseroBurnResult
+brasero_vob_start (BraseroJob *job,
+		   GError **error)
+{
+	BraseroVobPrivate *priv;
+	BraseroJobAction action;
+	BraseroTrackType *output = NULL;
+
+	brasero_job_get_action (job, &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	priv = BRASERO_VOB_PRIVATE (job);
+
+	/* get destination medium type */
+	output = brasero_track_type_new ();
+	brasero_job_get_output_type (job, output);
+
+	if (brasero_track_type_get_stream_format (output) & BRASERO_VIDEO_FORMAT_VCD) {
+		GValue *value = NULL;
+
+		priv->is_video_dvd = FALSE;
+		brasero_job_tag_lookup (job,
+					BRASERO_VCD_TYPE,
+					&value);
+		if (value)
+			priv->svcd = (g_value_get_int (value) == BRASERO_SVCD);
+	}
+	else
+		priv->is_video_dvd = TRUE;
+
+	BRASERO_JOB_LOG (job,
+			 "Got output type (is DVD %i, is SVCD %i)",
+			 priv->is_video_dvd,
+			 priv->svcd);
+
+	brasero_track_type_free (output);
+
+	if (!brasero_vob_build_pipeline (BRASERO_VOB (job), error))
+		return BRASERO_BURN_ERR;
+
+	/* ready to go */
+	brasero_job_set_current_action (job,
+					BRASERO_BURN_ACTION_ANALYSING,
+					_("Converting video file to MPEG2"),
+					FALSE);
+	brasero_job_start_progress (job, FALSE);
+
+	gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vob_clock_tick (BraseroJob *job)
+{
+	gint64 position = 0.0;
+	gint64 duration = 0.0;
+	BraseroVobPrivate *priv;
+	GstFormat format = GST_FORMAT_TIME;
+
+	priv = BRASERO_VOB_PRIVATE (job);
+
+	gst_element_query_duration (priv->pipeline, &format, &duration);
+	gst_element_query_position (priv->pipeline, &format, &position);
+
+	if (duration > 0.0) {
+		gdouble progress;
+
+		progress = (gdouble) position / (gdouble) duration;
+		brasero_job_set_progress (job, progress);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_vob_init (BraseroVob *object)
+{}
+
+static void
+brasero_vob_finalize (GObject *object)
+{
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (object);
+
+	if (priv->pipeline) {
+		gst_object_unref (priv->pipeline);
+		priv->pipeline = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_vob_class_init (BraseroVobClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass* job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVobPrivate));
+
+	object_class->finalize = brasero_vob_finalize;
+
+	job_class->start = brasero_vob_start;
+	job_class->clock_tick = brasero_vob_clock_tick;
+	job_class->stop = brasero_vob_stop;
+}
+
+static BraseroBurnResult
+brasero_vob_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	GSList *output;
+	GstElement *element;
+
+	/* Let's see if we've got the plugins we need */
+	element = gst_element_factory_make ("ffenc_mpeg2video", NULL);
+	if (!element) {
+		*error = g_strdup_printf (_("%s element could not be created"),
+					  "\"ffenc_mpeg2video\"");
+		return BRASERO_BURN_ERR;
+	}
+	gst_object_unref (element);
+
+	element = gst_element_factory_make ("ffenc_ac3", NULL);
+	if (!element) {
+		*error = g_strdup_printf (_("%s element could not be created"),
+					  "\"ffenc_ac3\"");
+		return BRASERO_BURN_ERR;
+	}
+	gst_object_unref (element);
+
+	element = gst_element_factory_make ("ffenc_mp2", NULL);
+	if (!element) {
+		*error = g_strdup_printf (_("%s element could not be created"),
+					  "\"ffenc_mp2\"");
+		return BRASERO_BURN_ERR;
+	}
+	gst_object_unref (element);
+
+	element = gst_element_factory_make ("mplex", NULL);
+	if (!element) {
+		*error = g_strdup_printf (_("%s element could not be created"),
+					  "\"mplex\"");
+		return BRASERO_BURN_ERR;
+	}
+	gst_object_unref (element);
+
+	brasero_plugin_define (plugin,
+			       "transcode2vob",
+			       _("Vob allows to transcode any video file to a format suitable for video DVDs"),
+			       "Philippe Rouquier",
+			       0);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED|
+					BRASERO_VIDEO_FORMAT_UNDEFINED|
+					BRASERO_METADATA_INFO);
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_AUDIO_FORMAT_MP2|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_METADATA_INFO|
+					 BRASERO_VIDEO_FORMAT_VCD);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_AUDIO_FORMAT_AC3|
+					 BRASERO_AUDIO_FORMAT_MP2|
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_AUDIO_FORMAT_48000|
+					 BRASERO_METADATA_INFO|
+					 BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED|
+					BRASERO_VIDEO_FORMAT_UNDEFINED);
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_AUDIO_FORMAT_MP2|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_VIDEO_FORMAT_VCD);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_AUDIO_FORMAT_AC3|
+					 BRASERO_AUDIO_FORMAT_MP2|
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_AUDIO_FORMAT_48000|
+					 BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+	return BRASERO_BURN_OK;
+}
diff --git a/plugins/transcode/burn-vob.h b/plugins/transcode/burn-vob.h
new file mode 100644
index 0000000..5f3caf4
--- /dev/null
+++ b/plugins/transcode/burn-vob.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-vob.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero-vob.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero-vob.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-vob.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_VOB_H_
+#define _BRASERO_VOB_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VOB             (brasero_vob_get_type ())
+#define BRASERO_VOB(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VOB, BraseroVob))
+#define BRASERO_VOB_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VOB, BraseroVobClass))
+#define BRASERO_IS_VOB(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VOB))
+#define BRASERO_IS_VOB_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VOB))
+#define BRASERO_VOB_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VOB, BraseroVobClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_VOB_H_ */
diff --git a/plugins/vcdimager/Makefile.am b/plugins/vcdimager/Makefile.am
new file mode 100644
index 0000000..465bfce
--- /dev/null
+++ b/plugins/vcdimager/Makefile.am
@@ -0,0 +1,23 @@
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_srcdir)/libbrasero-media/					\
+	-I$(top_builddir)/libbrasero-media/		\
+	-I$(top_srcdir)/libbrasero-burn				\
+	-I$(top_builddir)/libbrasero-burn/				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)					\
+	$(BRASERO_GLIB_CFLAGS)					\
+	$(BRASERO_LIBXML_CFLAGS)
+
+vcdimagerdir = $(libdir)/brasero/plugins
+vcdimager_LTLIBRARIES = libbrasero-vcdimager.la
+
+libbrasero_vcdimager_la_SOURCES = burn-vcdimager.c burn-vcdimager.h
+libbrasero_vcdimager_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBXML_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_vcdimager_la_LDFLAGS = -module -avoid-version
+
diff --git a/plugins/vcdimager/burn-vcdimager.c b/plugins/vcdimager/burn-vcdimager.c
new file mode 100644
index 0000000..c5384a1
--- /dev/null
+++ b/plugins/vcdimager/burn-vcdimager.c
@@ -0,0 +1,527 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <libxml/xmlerror.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xmlstring.h>
+#include <libxml/uri.h>
+
+#include "brasero-tags.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-vcdimager.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroVcdImager, brasero_vcd_imager, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+typedef struct _BraseroVcdImagerPrivate BraseroVcdImagerPrivate;
+struct _BraseroVcdImagerPrivate
+{
+	guint num_tracks;
+
+	guint svcd:1;
+};
+
+#define BRASERO_VCD_IMAGER_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerPrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_vcd_imager_read_stdout (BraseroProcess *process,
+				const gchar *line)
+{
+	gint percent = 0;
+	guint track_num = 0;
+	BraseroVcdImagerPrivate *priv;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+	if (sscanf (line, "#scan[track-%d]: %*d/%*d (%d)", &track_num, &percent) == 2) {
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+		brasero_job_set_progress (BRASERO_JOB (process),
+					  (gdouble) ((gdouble) percent) /
+					  100.0 /
+					  (gdouble) (priv->num_tracks + 1) +
+					  (gdouble) (track_num) /
+					  (gdouble) (priv->num_tracks + 1));
+	}
+	else if (sscanf (line, "#write[%*d/%*d]: %*d/%*d (%d)", &percent) == 1) {
+		gdouble progress;
+
+		/* NOTE: percent can be over 100% ???? */
+		brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+		progress = (gdouble) ((gdouble) percent) /
+			   100.0 /
+			   (gdouble) (priv->num_tracks + 1) +
+			   (gdouble) (priv->num_tracks) /
+			   (gdouble) (priv->num_tracks + 1);
+
+		if (progress > 1.0)
+			progress = 1.0;
+
+		brasero_job_set_progress (BRASERO_JOB (process), progress);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_read_stderr (BraseroProcess *process,
+				const gchar *line)
+{
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_generate_xml_file (BraseroProcess *process,
+				      const gchar *path,
+				      GError **error)
+{
+	BraseroVcdImagerPrivate *priv;
+	GSList *tracks = NULL;
+	xmlTextWriter *xml;
+	gchar buffer [64];
+	gint success;
+	GSList *iter;
+	gchar *name;
+	gint i;
+
+	BRASERO_JOB_LOG (process, "Creating (S)VCD layout xml file (%s)", path);
+
+	xml = xmlNewTextWriterFilename (path, 0);
+	if (!xml)
+		return BRASERO_BURN_ERR;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+	xmlTextWriterSetIndent (xml, 1);
+	xmlTextWriterSetIndentString (xml, (xmlChar *) "\t");
+
+	success = xmlTextWriterStartDocument (xml,
+					      NULL,
+					      "UTF8",
+					      NULL);
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterWriteDTD (xml,
+					(xmlChar *) "videocd",
+					(xmlChar *) "-//GNU//DTD VideoCD//EN",
+					(xmlChar *) "http://www.gnu.org/software/vcdimager/videocd.dtd";,
+					(xmlChar *) NULL);
+	if (success < 0)
+		goto error;
+
+	/* let's start */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "videocd");
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterWriteAttribute (xml,
+					       (xmlChar *) "xmlns",
+					       (xmlChar *) "http://www.gnu.org/software/vcdimager/1.0/";);
+	if (success < 0)
+		goto error;
+
+	if (priv->svcd)
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "class",
+						       (xmlChar *) "svcd");
+	else
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "class",
+						       (xmlChar *) "vcd");
+
+	if (success < 0)
+		goto error;
+
+	if (priv->svcd)
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "version",
+						       (xmlChar *) "1.0");
+	else
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "version",
+						       (xmlChar *) "2.0");
+	if (success < 0)
+		goto error;
+
+	/* info part */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "info");
+	if (success < 0)
+		goto error;
+
+	/* name of the volume */
+	name = NULL;
+	brasero_job_get_audio_title (BRASERO_JOB (process), &name);
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "album-id",
+					     (xmlChar *) name);
+	g_free (name);
+	if (success < 0)
+		goto error;
+
+	/* number of CDs */
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "volume-count",
+					     (xmlChar *) "1");
+	if (success < 0)
+		goto error;
+
+	/* CD number */
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "volume-number",
+					     (xmlChar *) "1");
+	if (success < 0)
+		goto error;
+
+	/* close info part */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* Primary Volume descriptor */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "pvd");
+	if (success < 0)
+		goto error;
+
+	/* NOTE: no need to convert a possible non compliant name as this will 
+	 * be done by vcdimager. */
+	name = NULL;
+	brasero_job_get_audio_title (BRASERO_JOB (process), &name);
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "volume-id",
+					     (xmlChar *) name);
+	g_free (name);
+	if (success < 0)
+		goto error;
+
+	/* Makes it CD-i compatible */
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "system-id",
+					     (xmlChar *) "CD-RTOS CD-BRIDGE");
+	if (success < 0)
+		goto error;
+
+	/* Close Primary Volume descriptor */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* the tracks */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "sequence-items");
+	if (success < 0)
+		goto error;
+
+	/* get all tracks */
+	brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+	priv->num_tracks = g_slist_length (tracks);
+	for (i = 0, iter = tracks; iter; iter = iter->next, i++) {
+		BraseroTrack *track;
+		gchar *video;
+
+		track = iter->data;
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "sequence-item");
+		if (success < 0)
+			goto error;
+
+		video = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "src",
+						       (xmlChar *) video);
+		g_free (video);
+
+		if (success < 0)
+			goto error;
+
+		sprintf (buffer, "track-%i", i);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "id",
+						       (xmlChar *) buffer);
+		if (success < 0)
+			goto error;
+
+		/* close sequence-item */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+	}
+
+	/* sequence-items */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* the navigation */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "pbc");
+	if (success < 0)
+		goto error;
+
+	/* get all tracks */
+	brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+	for (i = 0, iter = tracks; iter; iter = iter->next, i++) {
+		BraseroTrack *track;
+
+		track = iter->data;
+
+		sprintf (buffer, "playlist-%i", i);
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "playlist");
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "id",
+						       (xmlChar *) buffer);
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterWriteElement (xml,
+						     (xmlChar *) "wait",
+						     (xmlChar *) "0");
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "play-item");
+		if (success < 0)
+			goto error;
+
+		sprintf (buffer, "track-%i", i);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "ref",
+						       (xmlChar *) buffer);
+		if (success < 0)
+			goto error;
+
+		/* play-item */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+
+		/* playlist */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+	}
+
+	/* pbc */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* close videocd */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	return BRASERO_BURN_OK;
+
+error:
+
+	BRASERO_JOB_LOG (process, "Error");
+
+	/* close everything */
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	/* FIXME: get the error */
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_set_argv (BraseroProcess *process,
+			     GPtrArray *argv,
+			     GError **error)
+{
+	BraseroVcdImagerPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroMedia medium;
+	gchar *output;
+	gchar *image;
+	gchar *toc;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		BRASERO_JOB_NOT_SUPPORTED (process);
+
+	g_ptr_array_add (argv, g_strdup ("vcdxbuild"));
+
+	g_ptr_array_add (argv, g_strdup ("--progress"));
+	g_ptr_array_add (argv, g_strdup ("-v"));
+
+	/* specifies output */
+	image = toc = NULL;
+	brasero_job_get_image_output (BRASERO_JOB (process),
+				      &image,
+				      &toc);
+
+	g_ptr_array_add (argv, g_strdup ("-c"));
+	g_ptr_array_add (argv, toc);
+	g_ptr_array_add (argv, g_strdup ("-b"));
+	g_ptr_array_add (argv, image);
+
+	/* get temporary file to write XML */
+	result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+					   NULL,
+					   &output,
+					   error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	g_ptr_array_add (argv, output);
+
+	brasero_job_get_media (BRASERO_JOB (process), &medium);
+	if (medium & BRASERO_MEDIUM_CD) {
+		GValue *value = NULL;
+
+		brasero_job_tag_lookup (BRASERO_JOB (process),
+					BRASERO_VCD_TYPE,
+					&value);
+		if (value)
+			priv->svcd = (g_value_get_int (value) == BRASERO_SVCD);
+	}
+
+	result = brasero_vcd_imager_generate_xml_file (process, output, error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+	
+	brasero_job_set_current_action (BRASERO_JOB (process),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					_("Creating file layout"),
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_post (BraseroJob *job)
+{
+	BraseroVcdImagerPrivate *priv;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (job);
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_vcd_imager_init (BraseroVcdImager *object)
+{}
+
+static void
+brasero_vcd_imager_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_vcd_imager_class_init (BraseroVcdImagerClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass* process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVcdImagerPrivate));
+
+	object_class->finalize = brasero_vcd_imager_finalize;
+	process_class->stdout_func = brasero_vcd_imager_read_stdout;
+	process_class->stderr_func = brasero_vcd_imager_read_stderr;
+	process_class->set_argv = brasero_vcd_imager_set_argv;
+	process_class->post = brasero_vcd_imager_post;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	/* NOTE: it seems that cdrecord can burn cue files on the fly */
+	brasero_plugin_define (plugin,
+			       "vcdimager",
+			       _("Use vcdimager to create SVCDs"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("vcdimager", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_MP2|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_VIDEO_FORMAT_VCD|
+					BRASERO_METADATA_INFO);
+
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_IMAGE_FORMAT_CUE);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (input);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_MP2|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_VIDEO_FORMAT_VCD);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* we only support CDs they must be blank */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CDRW|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA|
+				  BRASERO_MEDIUM_HAS_AUDIO,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_FILE|
+				  BRASERO_MEDIUM_CDR|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA|
+				  BRASERO_MEDIUM_HAS_AUDIO,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+	return BRASERO_BURN_OK;
+}
+
diff --git a/plugins/vcdimager/burn-vcdimager.h b/plugins/vcdimager/burn-vcdimager.h
new file mode 100644
index 0000000..f50343c
--- /dev/null
+++ b/plugins/vcdimager/burn-vcdimager.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BRASERO_VCD_IMAGER_H_
+#define _BRASERO_VCD_IMAGER_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VCD_IMAGER             (brasero_vcd_imager_get_type ())
+#define BRASERO_VCD_IMAGER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImager))
+#define BRASERO_VCD_IMAGER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerClass))
+#define BRASERO_IS_VCD_IMAGER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VCD_IMAGER))
+#define BRASERO_IS_VCD_IMAGER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VCD_IMAGER))
+#define BRASERO_VCD_IMAGER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_VCD_IMAGER_H_ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]