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