/* cdrecord.c * Copyright (C) 2004, 2005 Sylvain Cresto * * This file is part of graveman! * * graveman! 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, or * (at your option) any later version. * * graveman! 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 program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * * URL: http://www.nongnu.org/graveman/ * */ #include "graveman.h" /* communication avec cdrdao */ #define SCANDEVICE "scsibus" #define CDRECORD_NOSUCHFILE "No read access for" #define CDRECORD_FIFO "fifo" #define CDRECORD_BUF "buf" #define CDRECORD_STATUS "fifo was " #define CDRECORD_ERRORDISK "No disk / Wrong disk" #define CDRECORD_INAPPROPRIATE "Inappropriate audio coding" #define CDRECORD_INPUTOUTPUT_ERROR "Input/output error." #define CDRECORD_FIXATING "Fixating..." #define CDRECORD_BLANKING "Blanking " #define CDRECORD_BAD_RECORDER "Sorry, no CD/DVD-Recorder or unsupported CD/DVD-Recorder found" #define CDRDAO_TRACK "Track " #define CDRDAO_ATSPEED "at speed " #define CDRDAO_ANALYZING "Analyzing track " #define CDRDAO_NOSPACELEFT "No space left on device" #define CDRDAO_LENGTH "length " #define CDRDAO_WRITING_TRACK "Writing track " #define CDRDAO_COPYING_TRACK "Copying data track " #define CDRDAO_WROTE "Wrote " #define CDRDAO_BLOCKS " blocks. Buffer fill" #define CDRDAO_FLUSHING "Flushing cache..." #define CDRDAO_SUCCESSFULLY "successfully." #define CDRDAO_OF "of " #define CDRDAO_BUFFERS "Buffers " #define CDRDAO_INCOMPATIBLE_MEDIUM "Medium in recorder device is not empty and not appendable" static gchar *get_blank_type(Tgrave *Ahash) { gboolean *Luseautoblank = (gboolean *) sc_grave_get_widget(Ahash, "useautoblank"); if (!*Luseautoblank) return g_strdup(""); return g_strdup_printf("blank=%s", conf_get_boolean("fastblank") == TRUE ? "fast" : "all"); } /* callback appele lorsque cdrdao grave les pistes */ gboolean cdrdao_grave_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata) { GIOStatus Lstatus; Tgrave *Lhash = (Tgrave *)Adata; gchar Lbuffer[_BUF_SIZE]; gint *Lcont = (gint *) sc_grave_get_data(Lhash, "cont"); /* on traite encore des donnees ? */ GError **Lerreur = (GError **) sc_grave_get_data(Lhash, "gerror"); /* pointeur erreur */ gint *Ltodo = (gint *) sc_grave_get_data(Lhash, "todo"); /* nombre de piste a traiter */ gint *Ldone = (gint *) sc_grave_get_data(Lhash, "done"); /* nombre de piste deja traite */ gchar *Llasttrack = (gchar *) sc_grave_get_data(Lhash, "lasttrack"); /* precedente piste traite */ gchar *Latspeed = (gchar *) sc_grave_get_data(Lhash, "atspeed"); /* vitesse reel operation */ glong *Llength = (glong *) sc_grave_get_data(Lhash, "length"); /* longueur total */ gchar *f, *e; gchar *Ltxt; gchar Lsbuf[_BUF_SIZE], Lsbuf2[_BUF_SIZE]; gdouble Ltotaldone = 1, Ltotaltodo, Lpct, Lgbuf = 0, Ltava; gsize Llu = 0; gchar *Ltracknum; GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Lhash, "gravetitle")); GtkProgressBar *Lprogressbar = GTK_PROGRESS_BAR(sc_grave_get_data(Lhash, "pb_total")); GtkProgressBar *Lprogressbar2 = GTK_PROGRESS_BAR(sc_grave_get_data(Lhash, "pb_step")); GtkProgressBar *LprogressbarFifo = GTK_PROGRESS_BAR(sc_grave_get_data(Lhash, "pb_fifo")); GtkProgressBar *LprogressbarBuffer = GTK_PROGRESS_BAR(sc_grave_get_data(Lhash, "pb_buffer")); /* fin du callback lorsque l'on recoi un signal comme quoi le pipe est ferme */ if (Acond == G_IO_HUP || Acond == G_IO_ERR) { (*Lcont) = 0; return FALSE; } *Lbuffer = 0; Lstatus = g_io_channel_read_chars(Astd, Lbuffer, _BUF_SIZE-1, &Llu, NULL); if (!*Lbuffer || Lstatus == G_IO_STATUS_ERROR || Lstatus == G_IO_STATUS_AGAIN) { return FALSE; } Lbuffer[Llu]=0; _DEB("===>%s", Lbuffer); if ((f=strstr(Lbuffer, CDRDAO_WROTE))) { /* copie en cours */ if (strstr(f, CDRDAO_BLOCKS)) { /* fin de l'operation */ gtk_label_set_text(Ltitle, _("Finishing operation...")); } else { // gchar *Lde = NULL, *La = NULL; gdouble Lgbuf = 0, Lfifo = 0; gdouble Lde = 0, La = 0; gboolean Lok = FALSE; /* champ deja grave */ f=f+strlen(CDRDAO_WROTE); Lde = atof(f); if ((f=next_no_numeric(f))) { *(f++)=0; if ((f=strstr(f, CDRDAO_OF))) { f=f+strlen(CDRDAO_OF); La = atof(f); if ((f=next_no_numeric(f))) { *(f++)=0; if ((f=strstr(f, CDRDAO_BUFFERS))) { f=f+strlen(CDRDAO_BUFFERS); e=ltrim(f); Lgbuf = atof(e); if ((f=next_putzero(e, '%'))) { e=ltrim(f); Lfifo = atof(e); if (next_putzero(e, '%')) Lok = TRUE; } } } } } if (Lok) { printf("oui ok => [%.0f] => [%.0f] => [%.0f] => [%.0f]\n", Lde, La, Lgbuf, Lfifo); g_snprintf(Lsbuf, sizeof(Lsbuf)-1, _("Writing track %s - %.0f MB of %.0f MB at %s"), Llasttrack, Lde, La, Latspeed); gtk_label_set_text(Ltitle, Lsbuf); maj_progress(Lprogressbar2, POURCENT(La, Lde)); /* barre fifo */ g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%.0f%%", Lfifo); gtk_progress_bar_set_fraction(LprogressbarFifo, Lfifo * 0.01); gtk_progress_bar_set_text(LprogressbarFifo, Lsbuf); /* barre buffer */ g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%.0f%%", Lgbuf); gtk_progress_bar_set_fraction(LprogressbarBuffer, Lgbuf * 0.01); gtk_progress_bar_set_text(LprogressbarBuffer, Lsbuf); } } /* Ltracknum = f; if (!(f=strchr(f, ':'))) return TRUE; *(f++)=0; g_strstrip(Ltracknum); if (!(e = strstr(f, CDRECORD_OF))) return TRUE; *e=0; e=e+strlen(CDRECORD_OF); Ltotaldone = atof(ltrim(f)); * champ total a graver * f=e; if (!(e=strstr(f, CDRECORD_MB))) { maj_audio_title(Ltitle, Ltracknum, NULL, 0, Ltotaldone); return TRUE; } *e=0; e=e+strlen(CDRECORD_MB); Ltotaltodo = atof(ltrim(f)); * champ fifo * if (!(f=strstr(e, CDRECORD_FIFO))) { maj_audio_title(Ltitle, Ltracknum, NULL, Ltotaltodo, Ltotaldone); return TRUE; } f=f+strlen(CDRECORD_FIFO); if ((e = strchr(++f, ')'))) { *e++=0; } else { e = f; } Lfifo = atof(ltrim(f)); * champ buf * if (!(f=strstr(e, CDRECORD_BUF))) { maj_audio_title(Ltitle, Ltracknum, NULL, Ltotaltodo, Ltotaldone); return TRUE; } f=f+strlen(CDRECORD_BUF); if ((e = strchr(++f, ']'))) { *e++=0; Lgbuf = atof(ltrim(f)); } else { e = f; } e=ltrim(e); if ((f=strchr(e, 'x'))) { *(++f)=0; maj_audio_title(Ltitle, Ltracknum, e, Ltotaltodo, Ltotaldone); } * barres de progression * * avancement operation * Lpct = (1.0/Ltotaltodo) * Ltotaldone; gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(Lprogressbar2), Lpct); g_snprintf(Lsbuf2, sizeof(Lsbuf2)-1, "%.0f%%", Lpct*100); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(Lprogressbar2), Lsbuf2); * avancement total * if (*Ltracknum && (!*Llasttrack || strcmp(Llasttrack, Ltracknum))) { if (strcmp(Llasttrack, "00")) *Ldone=(*Ldone)+1; g_strlcpy(Llasttrack, Ltracknum, _BUF_SIZE - 1); } Ltava = (1.0/ (*Ltodo)) * ((*Ldone)-1+Lpct); gtk_progress_bar_set_fraction(Lprogressbar, Ltava); g_snprintf(Lsbuf2, sizeof(Lsbuf2)-1, "%.0f%%", Ltava*100); gtk_progress_bar_set_text(Lprogressbar, Lsbuf2); * barre fifo * g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%.0f%%", Lfifo); gtk_progress_bar_set_fraction(LprogressbarFifo, Lfifo * 0.01); gtk_progress_bar_set_text(LprogressbarFifo, Lsbuf); * barre buffer * g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%.0f%%", Lgbuf); gtk_progress_bar_set_fraction(LprogressbarBuffer, Lgbuf * 0.01); gtk_progress_bar_set_text(LprogressbarBuffer, Lsbuf); */ } else if ((f=strstr(Lbuffer, CDRDAO_TRACK))) { /* debut lecture d'une piste */ f=f+strlen(CDRDAO_TRACK); e=f; for (e=f; isdigit(*e); e++) ; *e=0; if (*f) { g_snprintf(Llasttrack, _BUF_SIZE-1, "%s", f); g_snprintf(Lsbuf, sizeof(Lsbuf)-1, _("Reading track %s at %s..."), f, Latspeed); gtk_label_set_text(Ltitle, Lsbuf); } } else if ((strchr(Lbuffer, 13))) { /* operation lecture d'une piste en cours */ glong Lcur = get_2time(Lbuffer); if (Lcur > 0) { maj_progress(Lprogressbar2, POURCENT(*Llength, Lcur)); } } else if ((f=strstr(Lbuffer, CDRDAO_LENGTH))) { /* longueur total du cd */ f=f+strlen(CDRDAO_LENGTH); *Llength = get_2time(f); if (*Llength < 0) *Llength = 0; } else if ((f=strstr(Lbuffer, CDRDAO_ATSPEED))) { /* vitesse reel operation */ f=f+strlen(CDRDAO_ATSPEED); e=f; for (e=f; isdigit(*e); e++) ; *e=0; if (*f) { g_snprintf(Latspeed, _BUF_SIZE-1, "%sx", f); } } else if ((f=strstr(Lbuffer, CDRDAO_ANALYZING))) { /* mise a jour du titre analyse de la piste en cours */ f=f+strlen(CDRDAO_ANALYZING); if ((e=next_no_numeric(f))) { *e=0; g_snprintf(Lsbuf, sizeof(Lsbuf)-1, _("Analyzing track %s at %s..."), f, Latspeed); gtk_label_set_text(Ltitle, Lsbuf); } } else if ((f=strstr(Lbuffer, CDRDAO_WRITING_TRACK))) { /* mise a jour du titre ecriture de la piste en cours */ f=f+strlen(CDRDAO_WRITING_TRACK); if ((e=next_no_numeric(f))) { *e=0; g_snprintf(Llasttrack, _BUF_SIZE-1, "%s", f); g_snprintf(Lsbuf, sizeof(Lsbuf)-1, _("Writing track %s at %s..."), f, Latspeed); gtk_label_set_text(Ltitle, Lsbuf); } } else if ((f=strstr(Lbuffer, CDRDAO_COPYING_TRACK))) { /* mise a jour du titre ecriture de la piste en cours */ f=f+strlen(CDRDAO_COPYING_TRACK); if ((e=next_no_numeric(f))) { *e=0; g_snprintf(Llasttrack, _BUF_SIZE-1, "%s", f); g_snprintf(Lsbuf, sizeof(Lsbuf)-1, _("Reading track %s at %s..."), f, Latspeed); gtk_label_set_text(Ltitle, Lsbuf); } } else if (strstr(Lbuffer, CDRDAO_FLUSHING)) { /* blanking disk */ gtk_label_set_text(Ltitle, _("Flushing cache...")); } else if ((f=strstr(Lbuffer, CDRDAO_SUCCESSFULLY))) { gboolean *Lstatus = (gboolean *) sc_grave_get_data(Lhash, "operationstatus"); /* ok tout s'est bien passe ! */ *Lstatus = TRUE; } else if ((strstr(Lbuffer, CDRDAO_INCOMPATIBLE_MEDIUM))) { /* erreur pas de cd vierge */ g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_NO_CD, _("Error, a blank CD-R/CD-RW is required in the cd recorder !")); (*Lcont) = 0; return FALSE; } else if ((f=strstr(Lbuffer, CDRDAO_NOSPACELEFT))) { /* erreur pas assez d'espace disque disponnible ! */ g_snprintf(Lsbuf, sizeof(Lsbuf)-1, _("No space left on device !")); g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_NO_SPACE_LEFT, Lsbuf); (*Lcont) = 0; return FALSE; } return TRUE; } /* operation de copie d'un cd */ gboolean copycd(Tgrave *Ahash, GError **Aerror) { GtkWindow *Lwindow = GTK_WINDOW(sc_grave_get_data(Ahash, "window_burn")); GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Ahash, "gravetitle")); GtkWidget *Lvitesse = sc_grave_get_widget(Ahash, "dstcopyspeed"); GtkWidget *Lsource = sc_grave_get_widget(Ahash, "srccopycombo"); GtkWidget *Lgraveur = sc_grave_get_widget(Ahash, "dstcopycombo"); gchar *Lrepertoire = (gchar *)sc_grave_get_data(Ahash, "tmpdir"); gchar *Liso = (gchar *)sc_grave_get_data(Ahash, "iso"); gboolean *Loperationstatus = (gboolean *)sc_grave_get_data(Ahash, "operationstatus"); gboolean *Labort = (gboolean *) sc_grave_get_data(Ahash, "gabort"); gchar *Lbuftitle = NULL; gchar **Lcmd; gchar *Lcommandline; GIOChannel *Lcom, *Lcomerr; guint Lcomevent, Lcomerrevent; gint *Lcont = (gint *) sc_grave_get_data(Ahash, "cont"); /* on traite encore des donnees ? */ /* nombre d'element total */ gint *Ldone = (gint *)sc_grave_get_data(Ahash, "done"); /* fais */ gint *Ltodo = (gint *) sc_grave_get_data(Ahash, "todo"); gint *Lpid = (gint *) sc_grave_get_data(Ahash, "pid"); gint g_out, g_err, Lnbrarg; gboolean Lstatus = FALSE; gchar *Lbufvitesse, *Lbufgrav, *Lbufsrc; gboolean Lsimul = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ahash, "copysimul"))); gboolean Lonfly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ahash, "copyonfly"))); gint Lnbrgravure = gtk_spin_button_get_value(GTK_SPIN_BUTTON(sc_grave_get_widget(Ahash, "nbrcdcopy"))); gboolean Lwanteject = conf_get_boolean("eject"); gint Lcurcd; gboolean Ldosimul; gint Lnbrpass=1; gchar *Lblank; gboolean Leject = FALSE; gchar Latspeed[_BUF_SIZE]; /* vitesse reel de l'operation */ gchar Llasttrack[_BUF_SIZE]; /* derniere piste traite */ glong Llength; /* longueur total du cd */ Lbufvitesse = get_combo_value(Lvitesse); Lbufsrc = get_combo_value(Lsource); Lbufgrav = get_combo_value(Lgraveur); Lblank = get_blank_type(Ahash); *Ltodo = ((Lnbrgravure) + (Lsimul ? 1 : 0) + (Lonfly ? Lnbrgravure : 0)); sc_grave_set_data(Ahash, &Latspeed, "atspeed"); sc_grave_set_data(Ahash, &Llasttrack, "lasttrack"); sc_grave_set_data(Ahash, &Llength, "length"); for (Lcurcd=1; Lcurcd<= Lnbrgravure; ((Lsimul && Lnbrpass>1) || (!Lsimul)) ? ( Lcurcd++, Lnbrpass=1 ) : ( Lnbrpass++ )) { *Loperationstatus = FALSE; Ldosimul = (Lsimul && Lnbrpass==1); g_strlcpy(Latspeed, "-", sizeof(Latspeed)-1); *Llasttrack = 0; Llength = 0; if (Lcurcd > 1 && !Ldosimul) { /* copie sur un nouveau cd, on demande a l'utilisateur d'inserer le * nouveau cd vierge */ gint Lrep; GtkWidget *Lconfirm = gtk_message_dialog_new(Lwindow, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Now you should insert next CD-R, do you want to continue operation ?")); Lrep = gtk_dialog_run(GTK_DIALOG(Lconfirm)); gtk_widget_destroy(Lconfirm); if (Lrep == GTK_RESPONSE_NO) { /* si c'est non alors on arrete */ *Labort = TRUE; Lstatus = TRUE; } } /* Lbuftitle = get_title(Lnbrgravure, Lcurcd, Ldosimul); gtk_label_set_text(GTK_LABEL(Ltitle), Lbuftitle); g_free(Lbuftitle);*/ /* faut il ejecter le CD-R apres l'operation ? * oui si l'utilisateur a cocher la case "ejecter le cd" ou * si il faut realiser d'autre gravure sur d'autres CD-R */ Leject = ((Lcurcd > 1 && (Lwanteject || Lcurcd0 && *Labort == FALSE) { gtk_main_iteration(); } exit_prog(*Lpid, *Labort, Aerror, NULL); g_source_remove(Lcomerrevent); g_source_remove(Lcomevent); g_io_channel_shutdown(Lcomerr, FALSE, NULL); g_io_channel_unref(Lcomerr); g_io_channel_shutdown(Lcom, FALSE, NULL); g_io_channel_unref(Lcom); g_spawn_close_pid(*Lpid); *Lpid = 0; if (*Aerror) { Lstatus = FALSE; break; } if (*Loperationstatus == FALSE) { /* cdrdao n'a pas reussi a grave le cd mais on n'a intercepte aucune erreur ! argh! * dans tous les cas ce n'est pas normal, on genere une erreur */ g_set_error(Aerror, GRAVEMAN_ERROR, _ERR_UNKNOWN_ERROR, _("Communication error with cdrdao !")); Lstatus = FALSE; break; } if (Ldosimul) { /* fin de la simulation, tout s'est apparement bien passe * on demande confirmation avent de commencer la vrai gravure */ gint Lrep; GtkWidget *Lconfirm = gtk_message_dialog_new(Lwindow, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Simulation successful. Do you want to write the CD for real?")); Lrep = gtk_dialog_run(GTK_DIALOG(Lconfirm)); gtk_widget_destroy(Lconfirm); if (Lrep == GTK_RESPONSE_NO) { /* si c'est non alors on arrete */ *Labort = TRUE; Lstatus = TRUE; break; } } (*Ldone)++; } g_free(Lblank); g_free(Lbufgrav); g_free(Lbufvitesse); sc_grave_del_data(Ahash, "length"); sc_grave_del_data(Ahash, "lasttrack"); sc_grave_del_data(Ahash, "atspeed"); return Lstatus; } /* * vim:et:ts=8:sts=2:sw=2 */