~ubuntu-branches/ubuntu/utopic/cdrdao/utopic

« back to all changes in this revision

Viewing changes to xdao/CdDevice.cc

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Suffield
  • Date: 2004-06-24 22:33:16 UTC
  • Revision ID: james.westby@ubuntu.com-20040624223316-534onzugaeeyq61j
Tags: upstream-1.1.9
ImportĀ upstreamĀ versionĀ 1.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  cdrdao - write audio CD-Rs in disc-at-once mode
 
2
 *
 
3
 *  Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 */
 
19
 
 
20
#include <sys/time.h>
 
21
#include <sys/types.h>
 
22
#include <stddef.h>
 
23
#include <stdio.h>
 
24
#include <unistd.h>
 
25
#include <stdlib.h>
 
26
#include <errno.h>
 
27
#include <ctype.h>
 
28
#include <assert.h>
 
29
 
 
30
#include <gtkmm.h>
 
31
#include <gnome.h>
 
32
 
 
33
#include "TocEdit.h"
 
34
#include "CdDevice.h"
 
35
#include "ProcessMonitor.h"
 
36
#include "xcdrdao.h"
 
37
#include "guiUpdate.h"
 
38
#include "ProgressDialog.h"
 
39
#include "Settings.h"
 
40
 
 
41
#include "config.h"
 
42
#include "remote.h"
 
43
#include "ScsiIf.h"
 
44
#include "CdrDriver.h"
 
45
#include "util.h"
 
46
#include "Toc.h"
 
47
 
 
48
#define DRIVER_IDS 13
 
49
#define DRIVER_ID_DEFAULT 2
 
50
 
 
51
CdDevice *CdDevice::DEVICE_LIST_ = NULL;
 
52
 
 
53
char *CdDevice::DRIVER_NAMES_[DRIVER_IDS] = {
 
54
  "Undefined",
 
55
  "cdd2600",
 
56
  "generic-mmc",
 
57
  "generic-mmc-raw",
 
58
  "plextor",
 
59
  "plextor-scan",
 
60
  "ricoh-mp6200",
 
61
  "sony-cdu920",
 
62
  "sony-cdu948",
 
63
  "taiyo-yuden",
 
64
  "teac-cdr55",
 
65
  "toshiba",
 
66
  "yamaha-cdr10x"
 
67
};
 
68
  
 
69
 
 
70
CdDevice::CdDevice(const char* dev, const char *vendor, const char *product)
 
71
{
 
72
  dev_ = dev;
 
73
  vendor_ = vendor;
 
74
  product_ = product;
 
75
  
 
76
  driverId_ = 0; // undefined
 
77
  options_ = 0;
 
78
 
 
79
  deviceType_ = CD_R;
 
80
 
 
81
  manuallyConfigured_ = false;
 
82
 
 
83
  status_ = DEV_UNKNOWN;
 
84
 
 
85
  exitStatus_ = 0;
 
86
 
 
87
  progressStatusChanged_ = 0;
 
88
  progressStatus_ = 0;
 
89
  progressTotalTracks_ = 0;
 
90
  progressTrack_ = 0;
 
91
  progressTotal_ = 0;
 
92
  progressTrackRelative_ = 0;
 
93
  progressBufferFill_ = 0;
 
94
  progressWriterFill_ = 0;
 
95
 
 
96
  process_ = NULL;
 
97
 
 
98
  scsiIf_ = NULL;
 
99
  scsiIfInitFailed_ = 0;
 
100
 
 
101
  next_ = NULL;
 
102
  slaveDevice_ = NULL;
 
103
 
 
104
  autoSelectDriver();
 
105
}
 
106
 
 
107
CdDevice::~CdDevice()
 
108
{
 
109
  delete scsiIf_;
 
110
  scsiIf_ = NULL;
 
111
}
 
112
 
 
113
char *CdDevice::settingString() const
 
114
{
 
115
  char buf[100];
 
116
  std::string s;
 
117
 
 
118
  s = "'" + dev_ + "','";
 
119
  s += vendor_;
 
120
  s += "','";
 
121
  s += product_;
 
122
  s += "',";
 
123
 
 
124
  switch (deviceType_) {
 
125
  case CD_R:
 
126
    s += "CD_R";
 
127
    break;
 
128
  case CD_RW:
 
129
    s += "CD_RW";
 
130
    break;
 
131
  case CD_ROM:
 
132
    s+= "CD_ROM";
 
133
    break;
 
134
  }
 
135
 
 
136
  s += ",";
 
137
 
 
138
  s += driverName(driverId_);
 
139
 
 
140
  s += ",";
 
141
 
 
142
  sprintf(buf, "0x%lx", options_);
 
143
  s += buf;
 
144
 
 
145
  return strdupCC(s.c_str());
 
146
}
 
147
 
 
148
void CdDevice::driverId(int id)
 
149
{
 
150
  if (id >= 0 && id < DRIVER_IDS) 
 
151
    driverId_ = id;
 
152
}
 
153
 
 
154
void CdDevice::status(Status s)
 
155
{
 
156
  status_ = s;
 
157
}
 
158
 
 
159
int CdDevice::exitStatus() const
 
160
{
 
161
  return exitStatus_;
 
162
}
 
163
 
 
164
int CdDevice::autoSelectDriver()
 
165
{
 
166
  unsigned long options = 0;
 
167
  const char *driverName;
 
168
 
 
169
  driverName = CdrDriver::selectDriver(1, vendor_.c_str(), product_.c_str(),
 
170
                                       &options);
 
171
 
 
172
  if (driverName) {
 
173
    driverId_ = driverName2Id(driverName);
 
174
    options_ = options;
 
175
 
 
176
  } else {
 
177
    bool r_cdr, w_cdr, r_cdrw, w_cdrw;
 
178
 
 
179
    ScsiIf* sif = new ScsiIf(dev_.c_str());
 
180
 
 
181
    if (sif && sif->init() == 0 &&
 
182
        sif->checkMmc(&r_cdr, &w_cdr, &r_cdrw, &w_cdrw)) {
 
183
 
 
184
      driverId_ = driverName2Id("generic-mmc");
 
185
      if (r_cdr)  deviceType_ = CD_ROM;
 
186
      if (w_cdr)  deviceType_ = CD_R;
 
187
      if (w_cdrw) deviceType_ = CD_RW;
 
188
    } else {
 
189
      driverId_ = DRIVER_ID_DEFAULT;
 
190
      options_ = 0;
 
191
    }
 
192
    if (sif) delete sif;
 
193
  }
 
194
 
 
195
  return 1;
 
196
}
 
197
 
 
198
int CdDevice::updateStatus()
 
199
{
 
200
  Status newStatus = status_;
 
201
 
 
202
  if (process_ != NULL) {
 
203
    if (process_->exited()) {
 
204
      newStatus = DEV_UNKNOWN;
 
205
      exitStatus_ = process_->exitStatus();
 
206
 
 
207
      progressStatusChanged_ = 1;
 
208
 
 
209
      PROCESS_MONITOR->remove(process_);
 
210
      process_ = NULL;
 
211
 
 
212
      if (slaveDevice_ != NULL) {
 
213
        slaveDevice_->status(DEV_UNKNOWN);
 
214
        slaveDevice_ = NULL;
 
215
      }
 
216
    }
 
217
  }
 
218
 
 
219
  if (status_ == DEV_READY || status_ == DEV_BUSY || status_ == DEV_NO_DISK ||
 
220
      status_ == DEV_UNKNOWN) {
 
221
    if (scsiIf_ == NULL)
 
222
      createScsiIf();
 
223
 
 
224
    if (scsiIf_ != NULL) {
 
225
      switch (scsiIf_->testUnitReady()) {
 
226
      case 0:
 
227
        newStatus = DEV_READY;
 
228
        break;
 
229
      case 1:
 
230
        newStatus = DEV_BUSY;
 
231
        break;
 
232
      case 2:
 
233
        newStatus = DEV_NO_DISK;
 
234
        break;
 
235
      case 3:
 
236
        newStatus = DEV_FAULT;
 
237
        break;
 
238
      }
 
239
    }
 
240
    else {
 
241
      newStatus = DEV_FAULT;
 
242
    }
 
243
  }
 
244
 
 
245
  if (newStatus != status_) {
 
246
    status_ = newStatus;
 
247
    return 1;
 
248
  }
 
249
  
 
250
  return 0;
 
251
}
 
252
 
 
253
bool CdDevice::updateProgress(Glib::IOCondition cond, int fd)
 
254
{
 
255
  static char msgSync[4] = { 0xff, 0x00, 0xff, 0x00 };
 
256
  fd_set fds;
 
257
  int state = 0;
 
258
  char buf[10];
 
259
  struct timeval timeout = { 0, 0 };
 
260
 
 
261
  if (process_ == NULL)
 
262
    return false;
 
263
 
 
264
  if (!(cond & Gdk::INPUT_READ))
 
265
    return false;
 
266
 
 
267
  FD_ZERO(&fds);
 
268
  FD_SET(fd, &fds);
 
269
 
 
270
  while (select(fd + 1, &fds, NULL, NULL, &timeout) > 0 &&
 
271
         FD_ISSET(fd, &fds)) {
 
272
    FD_ZERO(&fds);
 
273
    FD_SET(fd, &fds);
 
274
 
 
275
    state = 0;
 
276
 
 
277
    while (state < 4) {
 
278
      if (read(fd, buf, 1) != 1) {
 
279
        //message(-2, "Reading of msg sync failed.");
 
280
        return false;
 
281
      }
 
282
 
 
283
      if (buf[0] == msgSync[state]) {
 
284
        state++;
 
285
      }
 
286
      else {
 
287
        state = 0;
 
288
        
 
289
        if (buf[0] == msgSync[state]) {
 
290
          state++;
 
291
        }
 
292
      }
 
293
    }
 
294
 
 
295
    ProgressMsg msg;
 
296
 
 
297
    int msgsize = read(fd, (char *)&msg, sizeof(msg));
 
298
    if (msgsize >= PSGMSG_MINSIZE) {
 
299
      if (msg.status >= PGSMSG_MIN && msg.status <= PGSMSG_MAX &&
 
300
          msg.track >= 0 &&
 
301
          msg.totalProgress >= 0 && msg.totalProgress <= 1000 &&
 
302
          msg.bufferFillRate >= 0 && msg.bufferFillRate <= 100) {
 
303
        progressStatus_ = msg.status;
 
304
        progressTotalTracks_ = msg.totalTracks;
 
305
        progressTrack_ = msg.track;
 
306
        progressTrackRelative_ = msg.trackProgress;
 
307
        progressTotal_ = msg.totalProgress;
 
308
        progressBufferFill_ = msg.bufferFillRate;
 
309
        if (msgsize == sizeof(msg))
 
310
          progressWriterFill_ = msg.writerFillRate;
 
311
        else
 
312
          progressWriterFill_ = 0;
 
313
        
 
314
        progressStatusChanged_ = 1;
 
315
      }
 
316
    }
 
317
    else {
 
318
      message(-1, _("Reading of progress message failed."));
 
319
    }
 
320
  }
 
321
 
 
322
  if (progressStatusChanged_)
 
323
    guiUpdate(UPD_PROGRESS_STATUS);
 
324
 
 
325
  return true;
 
326
}
 
327
 
 
328
CdDevice::DeviceType CdDevice::deviceType() const
 
329
{
 
330
  return deviceType_;
 
331
}
 
332
 
 
333
void CdDevice::deviceType(DeviceType t)
 
334
{
 
335
  deviceType_ = t;
 
336
}
 
337
 
 
338
unsigned long CdDevice::driverOptions() const
 
339
{
 
340
  return options_;
 
341
}
 
342
 
 
343
void CdDevice::driverOptions(unsigned long o)
 
344
{
 
345
  options_ = o;
 
346
}
 
347
 
 
348
// Starts a 'cdrdao' for recording given toc. Returns false if an
 
349
// error occured and the process was not successfully launched.
 
350
bool CdDevice::recordDao(Gtk::Window& parent, TocEdit *tocEdit, int simulate,
 
351
                        int multiSession, int speed, int eject, int reload,
 
352
                        int buffer, int overburn)
 
353
{
 
354
  char tocFileName[30];
 
355
  char *args[30];
 
356
  int n = 0;
 
357
  char devname[30];
 
358
  char drivername[50];
 
359
  char speedbuf[20];
 
360
  char *execName;
 
361
  const char *s;
 
362
  char bufferbuf[20];
 
363
  int remoteFdArgNum = 0;
 
364
 
 
365
  if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN)
 
366
      || process_ != NULL)
 
367
    return false;
 
368
 
 
369
  sprintf(tocFileName, "/tmp/gcdm.toc.XXXXXX");
 
370
  int fd = mkstemp(tocFileName);
 
371
  if (!fd) {
 
372
    message(-2, _("Cannot create temporary toc-file: %s"), strerror(errno));
 
373
    return false;
 
374
  }
 
375
 
 
376
  if (!tocEdit->toc()->write(fd)) {
 
377
    close(fd);
 
378
    message(-2, _("Cannot write temporary toc-file."));
 
379
    return false;
 
380
  }
 
381
 
 
382
  close(fd);
 
383
  if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL)
 
384
    execName = strdupCC(s);
 
385
  else
 
386
    execName = strdupCC("cdrdao");
 
387
 
 
388
 
 
389
  args[n++] = execName;
 
390
 
 
391
  if (simulate)
 
392
    args[n++] = "simulate";
 
393
  else
 
394
    args[n++] = "write";
 
395
 
 
396
  args[n++] = "--remote";
 
397
 
 
398
  remoteFdArgNum = n;
 
399
  args[n++] = NULL;
 
400
 
 
401
  args[n++] = "-v0";
 
402
 
 
403
  if (multiSession)
 
404
    args[n++] = "--multi";
 
405
 
 
406
  if (speed > 0) {
 
407
    sprintf(speedbuf, "%d", speed);
 
408
    args[n++] = "--speed";
 
409
    args[n++] = speedbuf;
 
410
  }
 
411
 
 
412
  if (eject)
 
413
    args[n++] = "--eject";
 
414
 
 
415
  if (reload)
 
416
    args[n++] = "--reload";
 
417
 
 
418
  if (overburn)
 
419
    args[n++] = "--overburn";
 
420
 
 
421
  args[n++] = "--device";
 
422
  args[n++] = (char*)dev_.c_str();
 
423
 
 
424
  if (driverId_ > 0) {
 
425
    sprintf(drivername, "%s:0x%lx", driverName(driverId_), options_);
 
426
    args[n++] = "--driver";
 
427
    args[n++] = drivername;
 
428
  }
 
429
 
 
430
  if (buffer >= 10) {
 
431
    sprintf(bufferbuf, "%i", buffer);
 
432
    args[n++] = "--buffers";
 
433
    args[n++] = bufferbuf;
 
434
  }
 
435
 
 
436
  args[n++] = tocFileName;
 
437
 
 
438
  args[n++] = NULL;
 
439
  
 
440
  assert(n <= 20);
 
441
  
 
442
  PROGRESS_POOL->start(parent, this, tocEdit->filename());
 
443
 
 
444
  // Remove the SCSI interface of this device to avoid problems with double
 
445
  // usage of device nodes.
 
446
  delete scsiIf_;
 
447
  scsiIf_ = NULL;
 
448
 
 
449
  process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum);
 
450
 
 
451
  delete execName;
 
452
  if (process_ != NULL) {
 
453
    status_ = DEV_RECORDING;
 
454
    action_ = A_RECORD;
 
455
 
 
456
    if (process_->commFd() >= 0) {
 
457
        Glib::signal_io().connect(bind(slot(*this, &CdDevice::updateProgress),
 
458
                                       process_->commFd()),
 
459
                                  process_->commFd(),
 
460
                                  Glib::IO_IN | Glib::IO_HUP);
 
461
    }
 
462
 
 
463
    return true;
 
464
  }
 
465
  else {
 
466
    unlink(tocFileName);
 
467
    free(tocFileName);
 
468
    return false;
 
469
  }
 
470
}
 
471
 
 
472
void CdDevice::abortDaoRecording()
 
473
{
 
474
  if (process_ != NULL && !process_->exited()) {
 
475
    PROCESS_MONITOR->stop(process_);
 
476
  }
 
477
}
 
478
 
 
479
int CdDevice::progressStatusChanged()
 
480
{
 
481
  if (progressStatusChanged_) {
 
482
    progressStatusChanged_ = 0;
 
483
    return 1;
 
484
  }
 
485
 
 
486
  return 0;
 
487
}
 
488
 
 
489
void CdDevice::progress(int *status, int *totalTracks, int *track,
 
490
                        int *trackProgress, int *totalProgress,
 
491
                        int *bufferFill, int *writerFill) const
 
492
{
 
493
  *status = progressStatus_;
 
494
  *totalTracks = progressTotalTracks_;
 
495
  *track = progressTrack_;
 
496
  *trackProgress = progressTrackRelative_;
 
497
  *totalProgress = progressTotal_;
 
498
  *bufferFill = progressBufferFill_;
 
499
  *writerFill = progressWriterFill_;
 
500
}
 
501
 
 
502
// Starts a 'cdrdao' for reading whole cd.
 
503
// Return: 0: OK, process succesfully launched
 
504
//         1: error occured
 
505
int CdDevice::extractDao(Project& parent, const char *tocFileName,
 
506
                         int correction, int readSubChanMode)
 
507
{
 
508
  char *args[30];
 
509
  int n = 0;
 
510
  char devname[30];
 
511
  char drivername[50];
 
512
  char *execName;
 
513
  const char *s; 
 
514
  char correctionbuf[20];
 
515
  int remoteFdArgNum = 0;
 
516
 
 
517
  if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN)
 
518
      || process_ != NULL)
 
519
    return 1;
 
520
 
 
521
  if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL)
 
522
    execName = strdupCC(s);
 
523
  else
 
524
    execName = strdupCC("cdrdao");
 
525
 
 
526
 
 
527
  args[n++] = execName;
 
528
 
 
529
  args[n++] = "read-cd";
 
530
 
 
531
  args[n++] = "--remote";
 
532
 
 
533
  remoteFdArgNum = n;
 
534
  args[n++] = NULL;
 
535
 
 
536
  args[n++] = "-v0";
 
537
 
 
538
  args[n++] = "--read-raw";
 
539
 
 
540
  switch (readSubChanMode) {
 
541
  case 1:
 
542
    args[n++] = "--read-subchan";
 
543
    args[n++] = "rw";
 
544
    break;
 
545
 
 
546
  case 2:
 
547
    args[n++] = "--read-subchan";
 
548
    args[n++] = "rw_raw";
 
549
    break;
 
550
  }
 
551
 
 
552
  args[n++] = "--device";
 
553
  args[n++] = (char*)dev_.c_str();
 
554
 
 
555
  if (driverId_ > 0) {
 
556
    sprintf(drivername, "%s:0x%lx", driverName(driverId_), options_);
 
557
    args[n++] = "--driver";
 
558
    args[n++] = drivername;
 
559
  }
 
560
 
 
561
  sprintf(correctionbuf, "%d", correction);
 
562
  args[n++] = "--paranoia-mode";
 
563
  args[n++] = correctionbuf;
 
564
 
 
565
  args[n++] = "--datafile";
 
566
  args[n++] = g_strdup_printf("%s.bin", tocFileName);
 
567
 
 
568
  args[n++] = g_strdup_printf("%s.toc", tocFileName);
 
569
 
 
570
  args[n++] = NULL;
 
571
  
 
572
  assert(n <= 20);
 
573
  
 
574
  PROGRESS_POOL->start(parent, this, tocFileName, false, false);
 
575
 
 
576
  // Remove the SCSI interface of this device to avoid problems with double
 
577
  // usage of device nodes.
 
578
  delete scsiIf_;
 
579
  scsiIf_ = NULL;
 
580
 
 
581
  process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum);
 
582
 
 
583
  delete[] execName;
 
584
 
 
585
  if (process_ != NULL) {
 
586
    status_ = DEV_READING;
 
587
    action_ = A_READ;
 
588
 
 
589
    if (process_->commFd() >= 0) {
 
590
        Glib::signal_io().connect(bind(slot(*this, &CdDevice::updateProgress),
 
591
                                       process_->commFd()),
 
592
                                  process_->commFd(),
 
593
                                  Glib::IO_IN | Glib::IO_PRI |
 
594
                                  Glib::IO_ERR | Glib::IO_HUP);
 
595
    }
 
596
    return 0;
 
597
  }
 
598
  else {
 
599
    return 1;
 
600
  }
 
601
}
 
602
 
 
603
 
 
604
void CdDevice::abortDaoReading()
 
605
{
 
606
  if (process_ != NULL && !process_->exited()) {
 
607
    PROCESS_MONITOR->stop(process_);
 
608
  }
 
609
}
 
610
 
 
611
// Starts a 'cdrdao' for duplicating a CD.
 
612
// Return: 0: OK, process succesfully launched
 
613
//         1: error occured
 
614
int CdDevice::duplicateDao(Project& parent, int simulate, int multiSession,
 
615
                           int speed, int eject, int reload, int buffer,
 
616
                           int onthefly, int correction, int readSubChanMode, 
 
617
                           CdDevice *readdev)
 
618
{
 
619
  char *args[30];
 
620
  int n = 0;
 
621
  char devname[30];
 
622
  char drivername[50];
 
623
  char r_drivername[50];
 
624
  char speedbuf[20];
 
625
  char correctionbuf[20];
 
626
  char *execName;
 
627
  const char *s;
 
628
  char bufferbuf[20];
 
629
  int remoteFdArgNum = 0;
 
630
 
 
631
 
 
632
  int rdstat = readdev->status();
 
633
  if ((rdstat != DEV_READY && rdstat != DEV_UNKNOWN && rdstat != DEV_FAULT) ||
 
634
      readdev->process() != NULL)
 
635
    return 1;
 
636
 
 
637
  if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN)
 
638
      || process_ != NULL)
 
639
    return 1;
 
640
 
 
641
  if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL)
 
642
    execName = strdupCC(s);
 
643
  else
 
644
    execName = strdupCC("cdrdao");
 
645
 
 
646
  args[n++] = execName;
 
647
 
 
648
  args[n++] = "copy";
 
649
 
 
650
  if (simulate)
 
651
    args[n++] = "--simulate";
 
652
 
 
653
  args[n++] = "--remote";
 
654
 
 
655
  remoteFdArgNum = n;
 
656
  args[n++] = NULL;
 
657
 
 
658
  args[n++] = "-v0";
 
659
 
 
660
  if (multiSession)
 
661
    args[n++] = "--multi";
 
662
 
 
663
  sprintf(correctionbuf, "%d", correction);
 
664
  args[n++] = "--paranoia-mode";
 
665
  args[n++] = correctionbuf;
 
666
 
 
667
  if (speed > 0) {
 
668
    sprintf(speedbuf, "%d", speed);
 
669
    args[n++] = "--speed";
 
670
    args[n++] = speedbuf;
 
671
  }
 
672
 
 
673
  if (eject)
 
674
    args[n++] = "--eject";
 
675
 
 
676
  if (reload)
 
677
    args[n++] = "--reload";
 
678
 
 
679
  if (onthefly)
 
680
    args[n++] = "--on-the-fly";
 
681
 
 
682
  switch (readSubChanMode) {
 
683
  case 1:
 
684
    args[n++] = "--read-subchan";
 
685
    args[n++] = "rw";
 
686
    break;
 
687
 
 
688
  case 2:
 
689
    args[n++] = "--read-subchan";
 
690
    args[n++] = "rw_raw";
 
691
    break;
 
692
  }
 
693
 
 
694
  args[n++] = "--device";
 
695
  args[n++] = (char*)dev_.c_str();
 
696
 
 
697
  if (driverId_ > 0) {
 
698
    sprintf(drivername, "%s:0x%lx", driverName(driverId_), options_);
 
699
    args[n++] = "--driver";
 
700
    args[n++] = drivername;
 
701
  }
 
702
 
 
703
 
 
704
  if (readdev != this) { // reader and write the same, skip source device
 
705
                  
 
706
    args[n++] = "--source-device";
 
707
    args[n++] = (char*)readdev->dev();
 
708
 
 
709
    if (readdev->driverId() > 0) {
 
710
      sprintf(r_drivername, "%s:0x%lx", driverName(readdev->driverId()),
 
711
                         readdev->driverOptions());
 
712
      args[n++] = "--source-driver";
 
713
      args[n++] = r_drivername;
 
714
    }
 
715
  }
 
716
  if (buffer >= 10) {
 
717
    sprintf(bufferbuf, "%i", buffer);
 
718
    args[n++] = "--buffers";
 
719
    args[n++] = bufferbuf;
 
720
  }
 
721
 
 
722
 
 
723
  args[n++] = NULL;
 
724
  
 
725
  assert(n <= 25);
 
726
  
 
727
  PROGRESS_POOL->start(parent, this, _("CD to CD copy"));
 
728
 
 
729
  // Remove the SCSI interface of this device to avoid problems with double
 
730
  // usage of device nodes.
 
731
  delete scsiIf_;
 
732
  scsiIf_ = NULL;
 
733
 
 
734
  process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum);
 
735
 
 
736
  delete[] execName;
 
737
 
 
738
  if (process_ != NULL) {
 
739
    slaveDevice_ = readdev;
 
740
    slaveDevice_->status(DEV_READING);
 
741
    status_ = DEV_RECORDING;
 
742
 
 
743
    action_ = A_DUPLICATE;
 
744
 
 
745
    if (process_->commFd() >= 0) {
 
746
        Glib::signal_io().connect(bind(slot(*this, &CdDevice::updateProgress),
 
747
                                       process_->commFd()),
 
748
                                  process_->commFd(),
 
749
                                  Glib::IO_IN | Glib::IO_HUP);
 
750
    }
 
751
 
 
752
    return 0;
 
753
  }
 
754
  else {
 
755
    return 1;
 
756
  }
 
757
}
 
758
 
 
759
void CdDevice::abortDaoDuplication()
 
760
{
 
761
  if (process_ != NULL && !process_->exited()) {
 
762
    PROCESS_MONITOR->stop(process_);
 
763
  }
 
764
}
 
765
 
 
766
// Starts a 'cdrdao' for blanking a CD.
 
767
// Return: 0: OK, process succesfully launched
 
768
//         1: error occured
 
769
int CdDevice::blank(Project* parent, int fast, int speed, int eject,
 
770
                    int reload)
 
771
{
 
772
  char *args[20];
 
773
  int n = 0;
 
774
  char devname[30];
 
775
  char drivername[50];
 
776
  char speedbuf[20];
 
777
  char *execName;
 
778
  const char *s;
 
779
  int remoteFdArgNum = 0;
 
780
 
 
781
  if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN)
 
782
      || process_ != NULL)
 
783
    return 1;
 
784
 
 
785
  if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL)
 
786
    execName = strdupCC(s);
 
787
  else
 
788
    execName = strdupCC("cdrdao");
 
789
 
 
790
  args[n++] = execName;
 
791
 
 
792
  args[n++] = "blank";
 
793
 
 
794
  args[n++] = "--remote";
 
795
 
 
796
  remoteFdArgNum = n;
 
797
  args[n++] = NULL;
 
798
 
 
799
  args[n++] = "-v0";
 
800
 
 
801
  args[n++] = "--blank-mode";
 
802
 
 
803
  if (fast)
 
804
    args[n++] = "minimal";
 
805
  else
 
806
    args[n++] = "full";
 
807
 
 
808
  if (speed > 0) {
 
809
    sprintf(speedbuf, "%d", speed);
 
810
    args[n++] = "--speed";
 
811
    args[n++] = speedbuf;
 
812
  }
 
813
 
 
814
  if (eject)
 
815
    args[n++] = "--eject";
 
816
 
 
817
  if (reload)
 
818
    args[n++] = "--reload";
 
819
 
 
820
  args[n++] = "--device";
 
821
  args[n++] = (char*)dev_.c_str();
 
822
 
 
823
  if (driverId_ > 0) {
 
824
    sprintf(drivername, "%s:0x%lx", driverName(driverId_), options_);
 
825
    args[n++] = "--driver";
 
826
    args[n++] = drivername;
 
827
  }
 
828
 
 
829
  args[n++] = NULL;
 
830
  
 
831
  assert(n <= 20);
 
832
  
 
833
  if (parent)
 
834
    PROGRESS_POOL->start(*parent, this, _("Blanking CDRW"), false, false);
 
835
  else
 
836
    PROGRESS_POOL->start(this, _("Blanking CDRW"), false, false);
 
837
 
 
838
  // Remove the SCSI interface of this device to avoid problems with double
 
839
  // usage of device nodes.
 
840
  delete scsiIf_;
 
841
  scsiIf_ = NULL;
 
842
 
 
843
  process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum);
 
844
 
 
845
  delete[] execName;
 
846
 
 
847
  if (process_ != NULL) {
 
848
    status_ = DEV_BLANKING;
 
849
    action_ = A_BLANK;
 
850
 
 
851
    if (process_->commFd() >= 0) {
 
852
        Glib::signal_io().connect(bind(slot(*this, &CdDevice::updateProgress),
 
853
                                       process_->commFd()),
 
854
                                  process_->commFd(),
 
855
                                  Glib::IO_IN | Glib::IO_HUP);
 
856
    }
 
857
    return 0;
 
858
  }
 
859
  else {
 
860
    return 1;
 
861
  }
 
862
}
 
863
 
 
864
void CdDevice::abortBlank()
 
865
{
 
866
  if (process_ != NULL && !process_->exited()) {
 
867
    PROCESS_MONITOR->stop(process_);
 
868
  }
 
869
}
 
870
 
 
871
void CdDevice::createScsiIf()
 
872
{
 
873
  char buf[100];
 
874
 
 
875
  if (scsiIfInitFailed_)
 
876
    return;
 
877
 
 
878
  delete scsiIf_;
 
879
  scsiIf_ = new ScsiIf(dev_.c_str());
 
880
 
 
881
  if (scsiIf_->init() != 0) {
 
882
    delete scsiIf_;
 
883
    scsiIf_ = NULL;
 
884
    scsiIfInitFailed_ = 1;
 
885
  }
 
886
}
 
887
 
 
888
int CdDevice::driverName2Id(const char *driverName)
 
889
{
 
890
  int i;
 
891
 
 
892
  for (i = 1; i < DRIVER_IDS; i++) {
 
893
    if (strcmp(DRIVER_NAMES_[i], driverName) == 0)
 
894
      return i;
 
895
  }
 
896
 
 
897
  return 0;
 
898
}
 
899
 
 
900
int CdDevice::maxDriverId()
 
901
{
 
902
  return DRIVER_IDS - 1;
 
903
}
 
904
 
 
905
const char *CdDevice::driverName(int id)
 
906
{
 
907
  if (id >= 0 && id < DRIVER_IDS) {
 
908
    return DRIVER_NAMES_[id];
 
909
  }
 
910
  else {
 
911
    return "Undefined";
 
912
  }
 
913
}
 
914
 
 
915
const char *CdDevice::status2string(Status s)
 
916
{
 
917
  char *ret = NULL;
 
918
 
 
919
  switch (s) {
 
920
  case DEV_READY:
 
921
    ret = "Ready";
 
922
    break;
 
923
  case DEV_RECORDING:
 
924
    ret = "Recording";
 
925
    break;
 
926
  case DEV_READING:
 
927
    ret = "Reading";
 
928
    break;
 
929
  case DEV_WAITING:
 
930
    ret = "Waiting";
 
931
    break;
 
932
  case DEV_BLANKING:
 
933
    ret = "Blanking";
 
934
    break;
 
935
  case DEV_BUSY:
 
936
    ret = "Busy";
 
937
    break;
 
938
  case DEV_NO_DISK:
 
939
    ret = "No disk";
 
940
    break;
 
941
  case DEV_FAULT:
 
942
    ret = "Not available";
 
943
    break;
 
944
  case DEV_UNKNOWN:
 
945
    ret = "Unknown";
 
946
    break;
 
947
  }
 
948
 
 
949
  return ret;
 
950
}
 
951
 
 
952
const char *CdDevice::deviceType2string(DeviceType t)
 
953
{
 
954
  char *ret = NULL;
 
955
 
 
956
  switch (t) {
 
957
  case CD_R:
 
958
    ret = "CD-R";
 
959
    break;
 
960
 
 
961
  case CD_RW:
 
962
    ret = "CD-RW";
 
963
    break;
 
964
 
 
965
  case CD_ROM:
 
966
    ret = "CD-ROM";
 
967
    break;
 
968
  }
 
969
 
 
970
  return ret;
 
971
}
 
972
 
 
973
 
 
974
/* reads configured devices from gnome settings
 
975
 */
 
976
void CdDevice::importSettings()
 
977
{
 
978
  int i, n;
 
979
  char *s;
 
980
  char buf[20];
 
981
  CdDevice *dev;
 
982
 
 
983
  n = gnome_config_get_int(SET_DEVICES_NUM);
 
984
 
 
985
  if (n > 0) {
 
986
    gnome_config_push_prefix(SET_SECTION_DEVICES);
 
987
    
 
988
    for (i = 0; i < n; i++) {
 
989
      sprintf(buf, "%d", i);
 
990
      s = gnome_config_get_string(buf);
 
991
 
 
992
      if (s != NULL) {
 
993
        if ((dev = CdDevice::add(s)) != NULL)
 
994
          dev->manuallyConfigured(true);
 
995
      }
 
996
    }
 
997
 
 
998
    gnome_config_pop_prefix();
 
999
  }
 
1000
}
 
1001
 
 
1002
 
 
1003
/* saves manually configured devices as gnome settings
 
1004
 */
 
1005
void CdDevice::exportSettings()
 
1006
{
 
1007
  int i, n;
 
1008
  char *s;
 
1009
  char buf[20];
 
1010
  CdDevice *drun;
 
1011
 
 
1012
  gnome_config_clean_section(SET_SECTION_DEVICES);
 
1013
 
 
1014
  for (drun = first(), n = 0; drun != NULL; drun = next(drun)) {
 
1015
    if (drun->manuallyConfigured()) {
 
1016
      n++;
 
1017
    }
 
1018
  }
 
1019
 
 
1020
  if (n > 0) {
 
1021
    gnome_config_set_int(SET_DEVICES_NUM, n);
 
1022
 
 
1023
    gnome_config_push_prefix(SET_SECTION_DEVICES);
 
1024
 
 
1025
    for (drun = first(), i = 0; drun != NULL; drun = next(drun)) {
 
1026
      if (drun->manuallyConfigured()) {
 
1027
        sprintf(buf, "%d", i);
 
1028
        s = drun->settingString();
 
1029
        gnome_config_set_string(buf, s);
 
1030
        delete[] s;
 
1031
 
 
1032
        i++;
 
1033
      }
 
1034
    }
 
1035
 
 
1036
    gnome_config_pop_prefix();
 
1037
  }
 
1038
}
 
1039
 
 
1040
CdDevice *CdDevice::add(const char* dev, const char *vendor,
 
1041
                        const char *product)
 
1042
{
 
1043
  CdDevice *run, *pred, *ent;
 
1044
 
 
1045
  for (pred = NULL, run = DEVICE_LIST_; run != NULL;
 
1046
       pred = run, run = run->next_) {
 
1047
    if (strcmp(run->dev(), dev) == 0)
 
1048
      return run;
 
1049
  }
 
1050
 
 
1051
  ent = new CdDevice(dev, vendor, product);
 
1052
 
 
1053
  if (pred != NULL) {
 
1054
    ent->next_ = pred->next_;
 
1055
    pred->next_ = ent;
 
1056
  }
 
1057
  else {
 
1058
    ent->next_ = DEVICE_LIST_;
 
1059
    DEVICE_LIST_ = ent;
 
1060
  }
 
1061
 
 
1062
  return ent;
 
1063
}
 
1064
 
 
1065
 
 
1066
static char *nextToken(char *&p)
 
1067
{
 
1068
  char *val = NULL;
 
1069
 
 
1070
  if (p == NULL || *p == 0)
 
1071
    return NULL;
 
1072
 
 
1073
  while (*p != 0 && isspace(*p))
 
1074
    p++;
 
1075
 
 
1076
  if (*p == 0)
 
1077
    return NULL;
 
1078
 
 
1079
  if (*p == '\'') {
 
1080
    p++;
 
1081
    val = p;
 
1082
 
 
1083
    while (*p != 0 && *p != '\'')
 
1084
      p++;
 
1085
 
 
1086
    if (*p == 0) {
 
1087
      // error, no matching ' found
 
1088
      return NULL;
 
1089
    }
 
1090
    else {
 
1091
      *p++ = 0;
 
1092
      
 
1093
      // skip over ,
 
1094
      while (*p != 0 && *p != ',')
 
1095
        p++;
 
1096
 
 
1097
      if (*p == ',')
 
1098
        p++;
 
1099
    }
 
1100
  }
 
1101
  else {
 
1102
    val = p;
 
1103
 
 
1104
    while (*p != 0 && *p != ',')
 
1105
      p++;
 
1106
   
 
1107
    if (*p == ',')
 
1108
      *p++ = 0;
 
1109
  }
 
1110
 
 
1111
  return val;
 
1112
}
 
1113
 
 
1114
static CdDevice *addImpl(char *s)
 
1115
{
 
1116
  char *p;
 
1117
  int driverId;
 
1118
  std::string dev;
 
1119
  std::string vendor;
 
1120
  std::string model;
 
1121
  std::string device;
 
1122
  unsigned long options;
 
1123
  char *val;
 
1124
  CdDevice::DeviceType type;
 
1125
  CdDevice *cddev;
 
1126
 
 
1127
  if (s[0] != '\'')
 
1128
    return NULL;
 
1129
 
 
1130
  p = s;
 
1131
 
 
1132
  if ((val = nextToken(p)) == NULL)
 
1133
    return NULL;
 
1134
  dev = val;
 
1135
 
 
1136
  if ((val = nextToken(p)) == NULL)
 
1137
    return NULL;
 
1138
  vendor = val;
 
1139
 
 
1140
  if ((val = nextToken(p)) == NULL)
 
1141
    return NULL;
 
1142
  model = val;
 
1143
 
 
1144
  if ((val = nextToken(p)) == NULL)
 
1145
    return NULL;
 
1146
 
 
1147
  if (strcasecmp(val, "CD_R") == 0)
 
1148
    type = CdDevice::CD_R;
 
1149
  else if (strcasecmp(val, "CD_RW") == 0)
 
1150
    type = CdDevice::CD_RW;
 
1151
  else if (strcasecmp(val, "CD_ROM") == 0)
 
1152
    type = CdDevice::CD_ROM;
 
1153
  else
 
1154
    type = CdDevice::CD_R;
 
1155
 
 
1156
  if ((val = nextToken(p)) == NULL)
 
1157
    return NULL;
 
1158
  driverId = CdDevice::driverName2Id(val);
 
1159
 
 
1160
  if ((val = nextToken(p)) == NULL)
 
1161
    return NULL;
 
1162
  options = strtoul(val, NULL, 0);
 
1163
 
 
1164
  cddev = CdDevice::add(dev.c_str(), vendor.c_str(), model.c_str());
 
1165
 
 
1166
  cddev->driverId(driverId);
 
1167
  cddev->deviceType(type);
 
1168
  cddev->driverOptions(options);
 
1169
  
 
1170
  return cddev;
 
1171
}
 
1172
 
 
1173
CdDevice *CdDevice::add(const char *setting)
 
1174
{
 
1175
  char *s = strdupCC(setting);
 
1176
 
 
1177
  CdDevice *dev = addImpl(s);
 
1178
 
 
1179
  delete[] s;
 
1180
 
 
1181
  return dev;
 
1182
}
 
1183
 
 
1184
 
 
1185
 
 
1186
CdDevice *CdDevice::find(const char* dev)
 
1187
{
 
1188
  CdDevice *run;
 
1189
 
 
1190
  for (run = DEVICE_LIST_; run != NULL; run = run->next_) {
 
1191
    if (strcmp(run->dev(), dev) == 0)
 
1192
      return run;
 
1193
  }
 
1194
 
 
1195
  return NULL;
 
1196
}
 
1197
  
 
1198
void CdDevice::scan()
 
1199
{
 
1200
  int i, len;
 
1201
  ScsiIf::ScanData *sdata = ScsiIf::scan(&len);
 
1202
 
 
1203
  if (sdata) {
 
1204
    for (i = 0; i < len; i++)
 
1205
      CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product);
 
1206
    delete[] sdata;
 
1207
  }
 
1208
 
 
1209
#ifdef SCSI_ATAPI
 
1210
  sdata = ScsiIf::scan(&len, "ATA");
 
1211
  if (sdata) {
 
1212
    for (i = 0; i < len; i++)
 
1213
      CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product);
 
1214
    delete[] sdata;
 
1215
  } else {
 
1216
    // Only scan for ATAPI devices if we got nothing on the ATA
 
1217
    // interface, otherwise every device would show up twice on the
 
1218
    // list.
 
1219
    sdata = ScsiIf::scan(&len, "ATAPI");
 
1220
    if (sdata) {
 
1221
      for (i = 0; i < len; i++)
 
1222
        CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product);
 
1223
      delete[] sdata;
 
1224
    }
 
1225
  }
 
1226
#endif
 
1227
}
 
1228
 
 
1229
void CdDevice::remove(const char* dev)
 
1230
{
 
1231
  CdDevice *run, *pred;
 
1232
 
 
1233
  for (pred = NULL, run = DEVICE_LIST_; run != NULL;
 
1234
       pred = run, run = run->next_) {
 
1235
    if (strcmp(run->dev(), dev) == 0) {
 
1236
      if (run->status() == DEV_RECORDING || run->status() == DEV_BLANKING ||
 
1237
          run->status() == DEV_READING || run->status() == DEV_WAITING)
 
1238
        return;
 
1239
        
 
1240
      if (pred != NULL)
 
1241
        pred->next_ = run->next_;
 
1242
      else
 
1243
        DEVICE_LIST_ = run->next_;
 
1244
 
 
1245
      delete run;
 
1246
      return;
 
1247
    }
 
1248
  }
 
1249
}
 
1250
 
 
1251
void CdDevice::clear()
 
1252
{
 
1253
  CdDevice *next;
 
1254
 
 
1255
  while (DEVICE_LIST_ != NULL) {
 
1256
    next = DEVICE_LIST_->next_;
 
1257
    delete DEVICE_LIST_;
 
1258
    DEVICE_LIST_ = next;
 
1259
  }
 
1260
}
 
1261
 
 
1262
CdDevice *CdDevice::first()
 
1263
{
 
1264
  return DEVICE_LIST_;
 
1265
}
 
1266
 
 
1267
CdDevice *CdDevice::next(const CdDevice *run)
 
1268
{
 
1269
  if (run != NULL)
 
1270
    return run->next_;
 
1271
  else
 
1272
    return NULL;
 
1273
}
 
1274
 
 
1275
int CdDevice::count()
 
1276
{
 
1277
  CdDevice *run;
 
1278
  int cnt = 0;
 
1279
 
 
1280
  for (run = DEVICE_LIST_; run != NULL; run = run->next_)
 
1281
    cnt++;
 
1282
 
 
1283
  return cnt;
 
1284
}
 
1285
 
 
1286
int CdDevice::updateDeviceStatus()
 
1287
{
 
1288
  int newStatus = 0;
 
1289
 
 
1290
  CdDevice *run;
 
1291
 
 
1292
  blockProcessMonitorSignals();
 
1293
 
 
1294
  for (run = DEVICE_LIST_; run != NULL; run = run->next_) {
 
1295
    if (run->updateStatus())
 
1296
      newStatus = 1;
 
1297
  }
 
1298
 
 
1299
  unblockProcessMonitorSignals();
 
1300
 
 
1301
  return newStatus;
 
1302
}