1 /* readcd.c
2  * Copyright (C) 2004, 2005 Sylvain Cresto <scresto@gmail.com>
3  *
4  * This file is part of graveman!
5  *
6  * graveman! is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or
9  * (at your option) any later version.
10  *
11  * graveman! is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with program; see the file COPYING. If not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19  * MA 02111-1307, USA.
20  *
21  * URL: http://www.nongnu.org/graveman/
22  *
23  */
24 
25 #include "graveman.h"
26 
27 /* communication avec readcd */
28 
29 #define READCD_CAPACITY "end:"
30 #define READCD_PROGRESS "addr:"
31 #define READCD_MSG "readcd:"
32 #define READCD_DONE "Time total:"
33 #define READCD_READSPEED "Read  speed:"
34 #define READCD_READSPEED_CD "CD"
35 
36 #define READCD_DETECTCAPACITY "kBytes = "
37 #define CDRECORD_COPY "Track"
38 #define CDRECORD_FIFO "fifo"
39 #define CDRECORD_MB "MB"
40 #define CDRECORD_BUF "buf"
41 #define CDRECORD_STATUS "fifo was "
42 
readcd_makeimage_callback(GIOChannel * Astd,GIOCondition Acond,gpointer Adata)43 gboolean readcd_makeimage_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata)
44 {
45   GIOStatus Lstatus;
46   Tgrave *Lg = (Tgrave *)Adata;
47   GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Lg, "gravetitle"));
48   GtkProgressBar *Lprogressbar = GTK_PROGRESS_BAR(sc_grave_get_data(Lg, "pb_total"));
49   GtkProgressBar *Lprogressbar2 = GTK_PROGRESS_BAR(sc_grave_get_data(Lg, "pb_step"));
50   gint *Lcont = (gint *) sc_grave_get_data(Lg, "cont"); /* on traite encore des donnees ? */
51   GError **Lerreur = (GError **) sc_grave_get_data(Lg, "gerror"); /* pointeur erreur */
52   gdouble *Lreadtodo = (gdouble *) sc_grave_get_data(Lg, "readtodo"); /* nombre de secteur a traiter */
53   gint *Ltodo = (gint *) sc_grave_get_data(Lg, "todo"); /* nombre de piste a traiter */
54   gint *Ldone = (gint *) sc_grave_get_data(Lg, "done"); /* nombre de piste deja traite */
55   gchar *Lvitesse = (gchar *) sc_grave_get_data(Lg, "tmpdir");  /* en fait la vitesse de lecture */
56   gchar Lbuffer[_BUF_SIZE];
57   gdouble Ltotaldone, Lpct, Ltava;
58   gchar *e, *f;
59   gchar Lsbuf[200];
60   gsize Llu = 0;
61   gchar *Ltxt;
62 
63   /* fin du callback lorsque l'on recoi un signal comme quoi le pipe est ferme */
64   if (Acond == G_IO_HUP || Acond == G_IO_ERR) {
65     *Lcont = 0;
66     return FALSE;
67   }
68 
69   Lstatus = g_io_channel_read_chars(Astd, Lbuffer, _BUF_SIZE-1, &Llu, NULL);
70   if (!*Lbuffer || Lstatus == G_IO_STATUS_ERROR || Lstatus == G_IO_STATUS_AGAIN) return FALSE;
71   Lbuffer[Llu]=0;
72 _DEB("=>%s", Lbuffer);
73   if ((f=strstr(Lbuffer, READCD_READSPEED))) {
74     f=f+strlen(READCD_READSPEED);
75     f=strstr(f, READCD_READSPEED_CD);
76 
77     if (f) {
78       f=ltrim(f+strlen(READCD_READSPEED_CD));
79 
80       if ((e=strchr(f, 'x'))) *e=0;
81 
82       g_strlcpy(Lvitesse, f, MAXPATHLEN-1);
83     }
84 
85   } else if ((f=strstr(Lbuffer, READCD_CAPACITY))) {
86     /* on re�oi la taille du cd, c'est l'une des premieres lignes renvoyes par readcd,
87      * une foi cette ligne re�u c'est le veritable debut de la creation de l'image cd */
88     f=f+strlen(READCD_CAPACITY);
89     f=ltrim(f);
90     if ((e=strchr(f, ' '))) *e=0;
91     *Lreadtodo = atof(f);
92 
93     if (*Lreadtodo == 0) {
94       g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_UNKNOWN_ERROR,
95             _("Communication error with readcd while trying to read cd size."));
96       *Lcont = 0;
97       return FALSE;
98     }
99     if (*Lvitesse) {
100       Ltxt=g_strdup_printf(_("Reading CD at %sx..."), Lvitesse);
101     } else {
102       Ltxt = g_strdup(_("Reading CD..."));
103     }
104     gtk_label_set_text(GTK_LABEL(Ltitle), Ltxt);
105     g_free(Ltxt);
106   } else if (!strncmp(Lbuffer, READCD_PROGRESS, strlen(READCD_PROGRESS))) {
107     f=Lbuffer+strlen(READCD_PROGRESS);
108     f=ltrim(f);
109     if ((e=strchr(f, ' '))) *e=0;
110     Ltotaldone = atof(ltrim(f));
111     /* avancement operation */
112     Lpct = (1.0/ *Lreadtodo) * Ltotaldone;
113     gtk_progress_bar_set_fraction(Lprogressbar2, Lpct);
114     g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%.0f%%", Lpct*100);
115     gtk_progress_bar_set_text(Lprogressbar2, Lsbuf);
116 
117     /* avancement total */
118     Ltava = (1.0/ (*Ltodo)) * ((*Ldone)-1+Lpct);
119     gtk_progress_bar_set_fraction(Lprogressbar, Ltava);
120     g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%.0f%%", Ltava*100);
121     gtk_progress_bar_set_text(Lprogressbar, Lsbuf);
122   } else if ((f=strstr(Lbuffer, READCD_MSG))) {
123     /* erreur readcd !*/
124     _DEB(" MSG = [%s]\n", Lbuffer);
125 
126     Ltxt = g_strdup_printf(_("Cannot create image: %s"), Lbuffer);
127     g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_READCD, Ltxt);
128     g_free(Ltxt);
129     return FALSE;
130   } else if ((f=strstr(Lbuffer, READCD_DONE))) {
131     /* fin de l'operation */
132     gboolean *Lstatus = (gboolean *) sc_grave_get_data(Lg, "operationstatus");
133     *Lstatus = TRUE;
134   }
135 
136   return TRUE;
137 }
138 
139 /* creation d'une image iso */
make_image(Tgrave * Ag,GError ** Aerror)140 gboolean make_image(Tgrave *Ag, GError **Aerror)
141 {
142   gchar **Lcmd;
143   gchar *Lcommandline;
144   GIOChannel *Lcom, *Lcomerr;
145   guint Lcomevent, Lcomerrevent;
146   gint *Lcont = sc_grave_get_data(Ag, "cont");
147   gboolean *Labort = (gboolean *) sc_grave_get_data(Ag, "gabort");
148   GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_widget(Ag, "gravetitle"));
149   gint *Lpid = (gint *) sc_grave_get_data(Ag, "pid");
150   GtkWidget *Lvitesse = sc_grave_get_widget(Ag, "dstcopyspeed");
151   gchar *Liso = (gchar *)sc_grave_get_data(Ag, "iso"); /* image iso */
152   gdouble Lreadtodo = 0;
153   gint g_in, g_out, g_err, Lnbrarg;
154   gboolean Lstatus = FALSE;
155   gchar *Lbufvitesse;
156   Tdriveinfo *Ldevice = matos_get_drive_info(Ag, "srccopycombo");
157 
158   gtk_label_set_text(Ltitle, _("Duplication will start shortly..."));
159 
160   Lbufvitesse = get_combo_value(Lvitesse);
161 
162   /* try to umount device before device access */
163   matos_umount_device(Ldevice, NULL);
164 
165   Lcommandline = g_strdup_printf("%s dev=%s f=\"%s\" %s%s -v",
166         conf_get_string("readcd"), DRIVE_DEV(Ldevice), Liso, *Lbufvitesse != '0' ? "speed=" : "", *Lbufvitesse != '0' ? Lbufvitesse : "");
167   g_free(Lbufvitesse);
168 
169   _DEB("execution [%s]\n", Lcommandline);
170   Lstatus = g_shell_parse_argv(Lcommandline, &Lnbrarg, &Lcmd, Aerror);
171   g_free(Lcommandline);
172   if (Lstatus == FALSE) {
173     return FALSE;
174   }
175   Lstatus = g_spawn_async_with_pipes(NULL, Lcmd, NULL, /* env argument */
176     (GSpawnFlags ) (G_SPAWN_DO_NOT_REAP_CHILD),
177      NULL, NULL, Lpid, &g_in, &g_out, &g_err, Aerror);
178   g_strfreev(Lcmd);
179 
180   if (Lstatus == FALSE) {
181     g_warning("ERROR EXECUTION !\n");
182     return FALSE;
183   }
184   *Lcont = 1;
185   sc_grave_set_data(Ag, &Lreadtodo, "readtodo");
186 
187   Lcom = g_io_channel_unix_new( g_out );
188   g_io_channel_set_encoding (Lcom, NULL, NULL);
189   g_io_channel_set_flags( Lcom, G_IO_FLAG_NONBLOCK, NULL );
190   Lcomevent = g_io_add_watch (Lcom, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
191                                       readcd_makeimage_callback, Ag);
192 
193   Lcomerr = g_io_channel_unix_new( g_err );
194   g_io_channel_set_encoding (Lcomerr, NULL, NULL);
195   g_io_channel_set_flags( Lcomerr, G_IO_FLAG_NONBLOCK, NULL );
196   Lcomerrevent = g_io_add_watch (Lcomerr, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
197                                       readcd_makeimage_callback, Ag);
198   while (*Lcont>0 && *Labort == FALSE) {
199    gtk_main_iteration();
200   }
201 
202   exit_prog(*Lpid, *Labort, Aerror, _("Error while reading CD"));
203 
204   g_source_remove(Lcomevent);
205   g_source_remove(Lcomerrevent);
206 
207   /* fermeture readcd */
208   g_io_channel_shutdown(Lcomerr, FALSE, NULL);
209   g_io_channel_unref(Lcomerr);
210   g_io_channel_shutdown(Lcom, FALSE, NULL);
211   g_io_channel_unref(Lcom);
212 
213   g_spawn_close_pid(*Lpid);
214   *Lpid = 0;
215 
216   sc_grave_del_data(Ag, "readtodo");
217 
218   if (*Aerror) {
219     _DEB("IL Y A UNE ERREUR !!");
220     return FALSE;
221   }
222 
223   return Lstatus;
224 }
225 
226 /* callback appele lors de la copie d'un cd a la vole
227  * renvoi en fait ce qui est lu sur cdrecord */
228 #if 0
229 
230  NON UTILISE POUR LE MOMENT, ET A REVOIR ..
231 gboolean readcd_redirect_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata)
232 {
233   GtkWidget *Lwindow1 = (GtkWidget *) Adata;
234   gchar Lbuffer[_BUF_SIZE];
235   gint *Lcont = (gint *) g_object_get_data(G_OBJECT(Lwindow1), "contsrc"); /* on traite encore des donnees ? */
236   GError **Lerreur = (GError **) g_object_get_data(G_OBJECT(Lwindow1), "gerror"); /* pointeur erreur */
237   GIOChannel *Lcdrecord = (GIOChannel *) g_object_get_data(G_OBJECT(Lwindow1), "cdrecord");
238   gsize Llu = 0, Lecris = 0;
239 
240   /* fin du callback lorsque l'on recoi un signal comme quoi le pipe est ferme */
241   if (Acond == G_IO_HUP || Acond == G_IO_ERR) {
242     *Lcont = 0;
243     return FALSE;
244   }
245   g_io_channel_read_chars(Astd, Lbuffer, _BUF_SIZE-1, &Llu, Lerreur);
246   if (!Llu) {
247     _DEB("stop !");
248     return FALSE;
249   }
250   Lbuffer[Llu]=0;
251 
252   g_io_channel_write_chars(Lcdrecord, (const gchar *)Lbuffer, Llu, &Lecris, Lerreur);
253 
254   return TRUE;
255 }
256 #endif
257 
258 
259 /* callback appele lorsque readcd determine la taille d'un cd */
readcd_getsize_callback(GIOChannel * Astd,GIOCondition Acond,gpointer Adata)260 gboolean readcd_getsize_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata)
261 {
262   GIOStatus Lstatus;
263   Tgrave *Lg = (Tgrave *)Adata;
264   gint *Lcont = (gint *) sc_grave_get_data(Lg, "cont"); /* on traite encore des donnees ? */
265   gint *Ltodo = (gint *) sc_grave_get_data(Lg, "todo"); /* nombre de piste a traiter */
266   gchar *f, *e;
267   gchar *Lbuffer = NULL;
268 
269   /* fin du callback lorsque l'on recoi un signal comme quoi le pipe est ferme */
270   if (Acond == G_IO_HUP || Acond == G_IO_ERR) {
271     *Lcont = 0;
272     return FALSE;
273   }
274 
275   Lstatus = g_io_channel_read_line(Astd, &Lbuffer, NULL, NULL, NULL);
276   if (!Lbuffer) return TRUE;
277   if ((f=strstr(Lbuffer, READCD_DETECTCAPACITY))) {
278     f=f+strlen(READCD_DETECTCAPACITY);
279     if ((e=strchr(f, ' '))) {
280       *e=0;
281       *Ltodo = atoi(f);
282     }
283     *Lcont = 0;
284     return FALSE;
285   }
286   g_free(Lbuffer);
287 
288   return TRUE;
289 }
290 
291 /*
292  * vim:et:ts=8:sts=2:sw=2
293  */
294