~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to kscd/libwm/database.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: database.c,v 1.2 2000/05/30 15:18:44 dfoerste Exp $
 
3
 *
 
4
 * This file is part of WorkMan, the civilized CD player library
 
5
 * (c) 1991-1997 by Steven Grimm (original author)
 
6
 * (c) by Dirk Fļæ½rsterling (current 'author' = maintainer)
 
7
 * The maintainer can be contacted by his e-mail address:
 
8
 * milliByte@DeathsDoor.com 
 
9
 *
 
10
 * This library is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU Library General Public
 
12
 * License as published by the Free Software Foundation; either
 
13
 * version 2 of the License, or (at your option) any later version.
 
14
 *
 
15
 * This library is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 * Library General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU Library General Public
 
21
 * License along with this library; if not, write to the Free
 
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 *
 
24
 *
 
25
 * Manage the CD database.  All these routines assume that the "cd" global
 
26
 * structure contains current information (as far as the outside world knows;
 
27
 * obviously it won't contain track titles just after a CD is inserted.)
 
28
 */
 
29
 
 
30
static char database_id[] = "$Id: database.c,v 1.2 2000/05/30 15:18:44 dfoerste Exp $";
 
31
 
 
32
#define RCFILE "/.workmanrc"
 
33
#define DBFILE "/.workmandb"
 
34
#define FUZZFRAMES 75
 
35
 
 
36
#include <errno.h>
 
37
#include <stdio.h>
 
38
#include <fcntl.h>
 
39
#include <unistd.h>
 
40
#include <ctype.h>
 
41
#include <stdlib.h>
 
42
#include <string.h>
 
43
#include <sys/types.h>
 
44
#include <sys/param.h>
 
45
#include <sys/time.h>
 
46
#include <sys/stat.h>
 
47
#include "include/wm_config.h"
 
48
#include "include/wm_helpers.h"
 
49
#include "include/wm_struct.h"
 
50
#include "include/wm_cdinfo.h"
 
51
#include "include/wm_cddb.h"
 
52
#include "include/wm_index.h"
 
53
#include "include/wm_database.h"
 
54
 
 
55
#define WM_MSG_CLASS WM_MSG_CLASS_DB
 
56
 
 
57
#define SWALLOW_LINE(fp) { int c; while ((c = getc(fp)) != '\n' && c != EOF); }
 
58
 
 
59
int     suppress_locking = 0;   /* Turn off locking of datafile (dangerous) */
 
60
 
 
61
char    *rcfile = NULL;         /* Personal rcfile */
 
62
char    *dbfiles = NULL;        /* Colon-separated list of databases */
 
63
char    **databases = NULL;     /* NULL-terminated list of databases */
 
64
 
 
65
char    *otherrc = NULL;        /* Unrecognized cruft from start of rcfile */
 
66
 
 
67
long    rcpos, rclen;           /* XXX */
 
68
 
 
69
int     found_in_db, found_in_rc;
 
70
long    holepos, firstpos;
 
71
 
 
72
int fuzz_frames = FUZZFRAMES;
 
73
 
 
74
int wm_db_save_disabled = FALSE;
 
75
 
 
76
int cur_playnew = -1;
 
77
 
 
78
extern int cur_ntracks, cur_nsections;
 
79
 
 
80
int mark_a = 0;
 
81
int mark_b = 0;
 
82
 
 
83
 
 
84
/*
 
85
 *
 
86
 */
 
87
int wm_db_get_playnew( void )
 
88
{
 
89
        return 0;
 
90
}
 
91
 
 
92
/*
 
93
 * split_workmandb()
 
94
 *
 
95
 * Split the WORKMANDB environment variable, if any, into a list of database
 
96
 * files in the global "databases".  If WORKMANDB is not available, make
 
97
 * a single entry with $HOME/DBFILE.
 
98
 *
 
99
 * Also, fill the "rcfile" global with the personal preferences filename.
 
100
 *
 
101
 * The environment variables should have already been read and placed in the
 
102
 * "rcfile" and "dbfiles" globals, respectively.
 
103
 */
 
104
void
 
105
split_workmandb( void )
 
106
{
 
107
        int     ndbs, i;
 
108
        char    *home, *wmdb;
 
109
        int     no_rc = 0, no_db = 0;
 
110
        
 
111
        if (rcfile == NULL)
 
112
        {
 
113
                if ((home = getenv("HOME")) != NULL)
 
114
                {
 
115
                        rcfile = malloc(strlen(home) + sizeof(RCFILE));
 
116
                        if (rcfile == NULL)
 
117
                        {
 
118
                        
 
119
nomem:
 
120
                                perror("split_workmandb()");
 
121
                                exit(1);
 
122
                        }
 
123
 
 
124
                        strcpy(rcfile, home);
 
125
                        strcat(rcfile, RCFILE);
 
126
                }
 
127
                else
 
128
                        no_rc = 1;
 
129
 
 
130
        }
 
131
 
 
132
        if ((wmdb = dbfiles) == NULL)
 
133
        {
 
134
                if ((home = getenv("HOME")) != NULL)
 
135
                {
 
136
                        wmdb = malloc(strlen(home) + sizeof(DBFILE));
 
137
                        if (wmdb == NULL)
 
138
                                goto nomem;
 
139
 
 
140
                        databases = malloc(2 * sizeof (databases[0]));
 
141
                        if (databases == NULL)
 
142
                                goto nomem;
 
143
 
 
144
                        strcpy(wmdb, home);
 
145
                        strcat(wmdb, DBFILE);
 
146
                        databases[0] = wmdb;
 
147
                        databases[1] = NULL;
 
148
                }
 
149
                else
 
150
                {
 
151
                        static char *emptydb = NULL;
 
152
                
 
153
                        databases = &emptydb;
 
154
                        no_db = 1;
 
155
                }
 
156
        }
 
157
        else
 
158
        {
 
159
                ndbs = 1;
 
160
                for (home = wmdb; *home; home++)
 
161
                        if (*home == ':')
 
162
                        {
 
163
                                *home = '\0';
 
164
                                ndbs++;
 
165
                        }
 
166
                
 
167
                databases = malloc((ndbs + 1) * sizeof(databases[0]));
 
168
                if (databases == NULL)
 
169
                        goto nomem;
 
170
                
 
171
                for (i = 0; i < ndbs; i++)
 
172
                {
 
173
                        databases[i] = wmdb;
 
174
                        wmdb += strlen(wmdb) + 1;
 
175
                }
 
176
 
 
177
                databases[i] = NULL;
 
178
        }
 
179
 
 
180
        if (no_db || no_rc)
 
181
        {
 
182
                fprintf(stderr,
 
183
"WorkMan was run without a home directory, probably by a system daemon.\n");
 
184
                fprintf(stderr, "It doesn't know where to find ");
 
185
                if (no_rc)
 
186
                {
 
187
                        fprintf(stderr, "your personal preferences file ");
 
188
                        if (no_db)
 
189
                                fprintf(stderr, "or the\ndatabase of CD descriptions");
 
190
                }
 
191
                else
 
192
                        fprintf(stderr, "the database of CD descriptions");
 
193
 
 
194
                fprintf(stderr,
 
195
".\nYou can use the X resources \"workman.db.shared\" and \"workman.db.personal\"\nto tell WorkMan where to look.\n");
 
196
 
 
197
                wm_db_save_disabled = TRUE;
 
198
        }
 
199
}
 
200
 
 
201
/*
 
202
 * print_cdinfo(cd, prefs)
 
203
 *
 
204
 * cd           A pointer to a cdinfo struct.
 
205
 * prefs        Flag: write personal preferences?
 
206
 *
 
207
 * Print a CD's information (in more or less readable form) to a buffer.
 
208
 * Returns a pointer to the buffer.
 
209
 *
 
210
 * XXX - could be more efficient about calling wm_strmcat() and strlen().
 
211
 */
 
212
char *
 
213
print_cdinfo(struct wm_cdinfo *cd, int prefs)
 
214
{
 
215
        int             i;
 
216
        char            tempbuf[2000];  /* XXX - is this always big enough? */
 
217
        static char     *cdibuf = NULL;
 
218
        struct wm_playlist      *l;
 
219
 
 
220
        sprintf(tempbuf, "\ntracks %d", cd->ntracks);
 
221
        for (i = 0; i < cur_ntracks; i++)
 
222
                if (cd->trk[i].section < 2)
 
223
                        sprintf(tempbuf + strlen(tempbuf), " %d",
 
224
                                cd->trk[i].start);
 
225
        sprintf(tempbuf + strlen(tempbuf), " %d\n", cd->length);
 
226
 
 
227
        wm_strmcpy(&cdibuf, tempbuf);
 
228
 
 
229
        if (cur_nsections)
 
230
        {
 
231
                sprintf(tempbuf, "sections %d", cur_nsections);
 
232
                /* fixed a bug here */
 
233
                for (i = 0; i < cur_ntracks; i++)
 
234
                        if (cd->trk[i].section > 1)
 
235
                                sprintf(tempbuf + strlen(tempbuf), " %d",
 
236
                                        cd->trk[i].start);
 
237
                sprintf(tempbuf + strlen(tempbuf), "\n");
 
238
 
 
239
                wm_strmcat(&cdibuf, tempbuf);
 
240
        }
 
241
 
 
242
        if (prefs)
 
243
        {
 
244
                if (cd->autoplay)
 
245
                        wm_strmcat(&cdibuf, "autoplay\n");
 
246
                for (l = cd->lists; l != NULL && l->name != NULL; l++)
 
247
                {
 
248
                        wm_strmcat(&cdibuf, "playlist ");
 
249
 
 
250
                        i = strlen(cdibuf) - 1;
 
251
                        wm_strmcat(&cdibuf, l->name);
 
252
                        while (cdibuf[++i])
 
253
                                if (cdibuf[i] == ' ' || cdibuf[i] == '\t')
 
254
                                        cdibuf[i] = '_';
 
255
 
 
256
                        if (l->list != NULL)
 
257
                        {
 
258
                                for (i = 0; l->list[i]; i++)
 
259
                                        ;
 
260
                                sprintf(tempbuf, " %d", i);
 
261
                                wm_strmcat(&cdibuf, tempbuf);
 
262
                                for (i = 0; l->list[i]; i++)
 
263
                                {
 
264
                                        sprintf(tempbuf, " %d", l->list[i]);
 
265
                                        wm_strmcat(&cdibuf, tempbuf);
 
266
                                }
 
267
                                wm_strmcat(&cdibuf, "\n");
 
268
                        }
 
269
                        else
 
270
                                wm_strmcat(&cdibuf, " 0\n");
 
271
                }
 
272
 
 
273
                if (cd->volume)
 
274
                {
 
275
                        /*
 
276
                         * Have to maintain compatibility with old versions,
 
277
                         * where volume was 0-32.
 
278
                         */
 
279
                        sprintf(tempbuf, "cdvolume %d\n", (cd->volume * 32) / 100);
 
280
                        wm_strmcat(&cdibuf, tempbuf);
 
281
                }
 
282
 
 
283
                if (cd->playmode)
 
284
                {
 
285
                        sprintf(tempbuf, "playmode %d\n", cd->playmode);
 
286
                        wm_strmcat(&cdibuf, tempbuf);
 
287
                }
 
288
 
 
289
                if (mark_a)
 
290
                {
 
291
                        sprintf(tempbuf, "mark %d START\n", mark_a);
 
292
                        wm_strmcat(&cdibuf, tempbuf);
 
293
                }
 
294
                if (mark_b)
 
295
                {
 
296
                        sprintf(tempbuf, "mark %d END\n", mark_b);
 
297
                        wm_strmcat(&cdibuf, tempbuf);
 
298
                }
 
299
 
 
300
                if (cd->otherrc)
 
301
                        wm_strmcat(&cdibuf, cd->otherrc);
 
302
 
 
303
                for (i = 0; i < cur_ntracks; i++)
 
304
                {
 
305
                        if (cd->trk[i].avoid)
 
306
                        {
 
307
                                sprintf(tempbuf, "dontplay %d\n", i + 1);
 
308
                                wm_strmcat(&cdibuf, tempbuf);
 
309
                        }
 
310
                        if (cd->trk[i].volume)
 
311
                        {
 
312
                                sprintf(tempbuf, "volume %d %d\n", i + 1,
 
313
                                        (cd->trk[i].volume * 32) / 100);
 
314
                                wm_strmcat(&cdibuf, tempbuf);
 
315
                        }
 
316
                        if (cd->trk[i].otherrc)
 
317
                                wm_strmcat(&cdibuf, cd->trk[i].otherrc);
 
318
                }
 
319
        }
 
320
        else
 
321
        {
 
322
                if (cd->cdname[0])
 
323
                {
 
324
                        wm_strmcat(&cdibuf, "cdname ");
 
325
                        wm_strmcat(&cdibuf, cd->cdname);
 
326
                        wm_strmcat(&cdibuf, "\n");
 
327
                }
 
328
 
 
329
                if (cd->artist[0])
 
330
                {
 
331
                        wm_strmcat(&cdibuf, "artist ");
 
332
                        wm_strmcat(&cdibuf, cd->artist);
 
333
                        wm_strmcat(&cdibuf, "\n");
 
334
                }
 
335
 
 
336
                if (cd->otherdb)
 
337
                        wm_strmcat(&cdibuf, cd->otherdb);
 
338
 
 
339
                for (i = 0; i < cur_ntracks; i++)
 
340
                {
 
341
                        if (cd->trk[i].section > 1)
 
342
                                wm_strmcat(&cdibuf, "s-");
 
343
                        wm_strmcat(&cdibuf, "track ");
 
344
                        if (cd->trk[i].songname != NULL)
 
345
                                wm_strmcat(&cdibuf, cd->trk[i].songname);
 
346
                        wm_strmcat(&cdibuf, "\n");
 
347
                        if (cd->trk[i].contd)
 
348
                        {
 
349
                                if (cd->trk[i].section > 1)
 
350
                                        wm_strmcat(&cdibuf, "s-");
 
351
                                wm_strmcat(&cdibuf, "continue\n");
 
352
                        }
 
353
                        if (cd->trk[i].otherdb)
 
354
                                wm_strmcat(&cdibuf, cd->trk[i].otherdb);
 
355
                }
 
356
        }
 
357
 
 
358
        return (cdibuf);
 
359
} /* print_cdinfo() */
 
360
 
 
361
/*
 
362
 * Open the rcfile for reading or writing.
 
363
 *
 
364
 *      name            Filename
 
365
 *      mode            "r" or "w"
 
366
 */
 
367
FILE *
 
368
open_rcfile(char *name, char *mode)
 
369
{
 
370
        FILE            *fp;
 
371
        struct stat     st;
 
372
 
 
373
        fp = fopen(name, mode);
 
374
        if (fp == NULL)
 
375
        {
 
376
                if (errno != ENOENT || mode[0] == 'w')
 
377
                        perror(name);
 
378
        }
 
379
        else
 
380
        {
 
381
                /* Don't let people open directories or devices */
 
382
                if (fstat(fileno(fp), &st) < 0)
 
383
                {
 
384
                        perror(name);
 
385
                        fclose(fp);
 
386
                        return (NULL);
 
387
                }
 
388
 
 
389
#ifdef S_ISREG
 
390
                if (! S_ISREG(st.st_mode))
 
391
#else
 
392
                if ((st.st_mode & S_IFMT) != S_IFREG)
 
393
#endif
 
394
                {
 
395
                        errno = EISDIR;
 
396
                        perror(name);
 
397
                        fclose(fp);
 
398
                        return (NULL);
 
399
                }
 
400
 
 
401
                if (mode[0] == 'w') /* create -- put data in so locks work */
 
402
                {
 
403
                        fputs("# WorkMan database file\n", fp);
 
404
                        fclose(fp);
 
405
                        fp = fopen(name, "r+");
 
406
                        if (fp == NULL)
 
407
                                if (errno != ENOENT)
 
408
                                        perror(name);
 
409
                }
 
410
        }
 
411
 
 
412
        return (fp);
 
413
}
 
414
 
 
415
/*
 
416
 *
 
417
 * allocate and clear "trackmap".
 
418
 *
 
419
 */
 
420
int *reset_tracks(void)
 
421
{
 
422
    int i, j;
 
423
    int *trackmap;
 
424
    /*
 
425
     * Since we access track numbers indirectly (to handle sections
 
426
     * with at least a little elegance), the track mapping needs to be
 
427
     * set up before we read anything.  Initially it must assume that
 
428
     * no sections will appear in this datafile.
 
429
     */
 
430
    trackmap = malloc(sizeof(int) * cur_ntracks);
 
431
    if (trackmap == NULL)
 
432
    {
 
433
        perror("trackmap");
 
434
        exit(1);
 
435
    }
 
436
    j = 0;
 
437
    for (i = 0; i < cd->ntracks; i++)
 
438
    {
 
439
        trackmap[i] = j;
 
440
        while (cd->trk[++j].section > 1)
 
441
                ;
 
442
    }
 
443
    return trackmap;
 
444
} /* reset_tracks() */
 
445
 
 
446
/*
 
447
 * Load a new-format database file, searching for a match with the currently
 
448
 * inserted CD.  Modify the in-core copy of the CD info based on what's found
 
449
 * in the database.
 
450
 *
 
451
 * Returns 1 if there was a match or 0 if not.
 
452
 *
 
453
 *      fp              FILE* of database or rcfile.
 
454
 *      prefs           1 if we're searching .workmanrc, 0 for .workmandb,
 
455
 *                      2 if just reading settings
 
456
 *      scan            Scan for "tracks" location and entry size only
 
457
 *      holesize_wanted How big a hole we're looking for, if any.
 
458
 *
 
459
 * If a hole was found along the way, update the global "holepos" with its
 
460
 * starting offset in the file.  A hole is defined as a bunch of blank lines
 
461
 * preceding a "tracks" line.  Holepos will contain the best match.
 
462
 *
 
463
 * In addition, "firstpos" will be filled with the position of the first
 
464
 * "tracks" keyword, so we know how much room is available for global
 
465
 * settings at the rcfile's start.
 
466
 */
 
467
int
 
468
search_db( FILE *fp, int prefs, int scan, int holesize_wanted )
 
469
 
 
470
{
 
471
        char    keyword[64], listname[64], *c;
 
472
        int     b, i, j, track = 0, listsize, ntracks, scratch, searching = 1;
 
473
        int     *trackmap = 0, gotsections = 0;
 
474
        int     fudge, maxfudge, sizediff, bestfudge = 0;
 
475
        long    pos = 0, thisholepos = -1, holesize = 99991239;
 
476
        struct  wm_playlist *l;
 
477
 
 
478
        rclen = 0;
 
479
 
 
480
        wm_lib_message(WM_MSG_CLASS_DB|WM_MSG_LEVEL_DEBUG , "db: Reached search_db()\n" );
 
481
 
 
482
        /* We may not find any holes at all! */
 
483
        if (holesize_wanted)
 
484
                holepos = -1;
 
485
 
 
486
        if( prefs != 2 )
 
487
                trackmap = reset_tracks();
 
488
 
 
489
        if (prefs)
 
490
                freeup(&otherrc);
 
491
        firstpos = -1;
 
492
        while (! feof(fp))
 
493
        {
 
494
                pos = ftell(fp);
 
495
                keyword[0] = '\0';
 
496
                do
 
497
                        b = getc(fp);
 
498
                while (b != EOF && b != '\n' && isspace(b));
 
499
 
 
500
                if (b == EOF || feof(fp))
 
501
                        break;
 
502
 
 
503
                if (b != '\n')
 
504
                {
 
505
                        keyword[0] = b;
 
506
                        fscanf(fp, "%s", &keyword[1]);
 
507
                }
 
508
                if (keyword[0] == '\0')         /* Blank line. */
 
509
                {
 
510
                        if (thisholepos < 0)
 
511
                                thisholepos = pos;
 
512
                        continue;
 
513
                }
 
514
 
 
515
                /* Strip off "s-" if we've seen a "sections" keyword */
 
516
                if (gotsections && keyword[0] == 's' && keyword[1] == '-')
 
517
                {
 
518
                        for (c = &keyword[2]; (c[-2] = *c) != '\0'; c++)
 
519
                                ;
 
520
                        wm_lib_message(WM_MSG_CLASS_DB|WM_MSG_LEVEL_DEBUG , "db: stripped off the 's-'. Result is %s\n", keyword);
 
521
                }
 
522
 
 
523
                /* If this is the start of a CD entry, see if it matches. */
 
524
                if (! strcmp(keyword, "tracks"))
 
525
                {
 
526
                        if (prefs == 2)
 
527
                                break;
 
528
 
 
529
                        /* Is this the end of a hole? */
 
530
                        if (holesize_wanted && (thisholepos >= 0))
 
531
                        {
 
532
                                /* Yep.  Is it better than the last one? */
 
533
                                if (pos - thisholepos < holesize && pos -
 
534
                                                thisholepos >= holesize_wanted)
 
535
                                {
 
536
                                        holepos = thisholepos;
 
537
                                        holesize = pos - thisholepos;
 
538
                                }
 
539
                                thisholepos = -1;
 
540
                        }
 
541
 
 
542
                        /* Is it the start of the CD entries? */
 
543
                        if (firstpos == -1)
 
544
                                firstpos = pos;
 
545
 
 
546
                        /* Is this the end of the entry we really wanted? */
 
547
                        if (! searching)
 
548
                        {
 
549
                                rclen = pos - rcpos;
 
550
                                break;
 
551
                        }
 
552
 
 
553
                        /* If we have a near match, indicate that we
 
554
                            should stop reading tracks, etc now */
 
555
                        if (searching == 2)
 
556
                        {
 
557
                            searching = 3;
 
558
                            continue;
 
559
                        }
 
560
 
 
561
                        fscanf(fp, "%d", &ntracks);
 
562
 
 
563
                        if (ntracks != cd->ntracks)
 
564
                        {
 
565
chomp:
 
566
                                SWALLOW_LINE(fp);
 
567
                                continue;
 
568
                        }
 
569
 
 
570
                        fudge = 0;
 
571
                        maxfudge = (ntracks * fuzz_frames) >> 1;
 
572
                        track = 0;
 
573
                        for (i = 0; i < ntracks; i++)
 
574
                        {
 
575
                                fscanf(fp, "%d", &scratch);
 
576
                                if (scratch != cd->trk[track].start)
 
577
                                {
 
578
                                    sizediff = abs(scratch - cd->trk[track].start);
 
579
                                    if (sizediff > fuzz_frames || 
 
580
                                        (sizediff && scan))
 
581
                                      break;
 
582
                                    fudge += sizediff;
 
583
                                }
 
584
                                while (cd->trk[++track].section > 1)
 
585
                                        ;
 
586
                        }
 
587
                        if (i != ntracks)
 
588
                                goto chomp;
 
589
 
 
590
                        if (fudge > 0) /* best near match? */
 
591
                        {
 
592
                            if (fudge > maxfudge)
 
593
                                goto chomp;
 
594
                            if (bestfudge == 0 || fudge < bestfudge)
 
595
                                bestfudge = fudge;
 
596
                            else
 
597
                                goto chomp;
 
598
                            rcpos = pos;
 
599
                            track = 0;
 
600
                            searching = 2;
 
601
                        }
 
602
                        else /* probably exact match */
 
603
                        {
 
604
                            fscanf(fp, "%d", &scratch);
 
605
 
 
606
                            if (scratch != -1 && scratch != cd->length)
 
607
                                    goto chomp;
 
608
 
 
609
                            /* Found it! */
 
610
                            rcpos = pos;
 
611
                            track = 0;
 
612
                            searching = 0;
 
613
                        }
 
614
 
 
615
                        SWALLOW_LINE(fp);       /* Get rid of newline */
 
616
                }
 
617
 
 
618
                /* Global mode stuff goes here */
 
619
                else if (! strcmp(keyword, "cddbprotocol"))
 
620
                {
 
621
                        getc(fp);
 
622
                        i = getc(fp);   /* only first letter is used */
 
623
                        cddb.protocol = i == 'c' ? 1 : 
 
624
                                        i == 'h' ? 2 : 3 ;
 
625
                        do
 
626
                                i = getc(fp);
 
627
                        while (i != '\n' && i != EOF);
 
628
                }
 
629
 
 
630
                else if (! strcmp(keyword, "cddbserver"))
 
631
                {
 
632
                        getc(fp);       /* lose the space */
 
633
                        if (cddb.cddb_server[0])
 
634
                                do
 
635
                                        i = getc(fp);
 
636
                                while (i != '\n' && i != EOF);
 
637
                        else
 
638
                        {
 
639
                                fgets(cddb.cddb_server, 
 
640
                                      sizeof(cddb.cddb_server), fp);
 
641
                                if ((i = strlen(cddb.cddb_server)))
 
642
                                        cddb.cddb_server[i - 1] = '\0';
 
643
                        }
 
644
                }
 
645
 
 
646
                else if (! strcmp(keyword, "cddbmailadress"))
 
647
                {
 
648
                        getc(fp);       /* lose the space */
 
649
                        if (cddb.mail_adress[0])
 
650
                                do
 
651
                                        i = getc(fp);
 
652
                                while (i != '\n' && i != EOF);
 
653
                        else
 
654
                        {
 
655
                                fgets(cddb.mail_adress, 
 
656
                                      sizeof(cddb.mail_adress), fp);
 
657
                                if ((i = strlen(cddb.mail_adress)))
 
658
                                        cddb.mail_adress[i - 1] = '\0';
 
659
                        }
 
660
                }
 
661
 
 
662
                else if (! strcmp(keyword, "cddbpathtocgi"))
 
663
                {
 
664
                        getc(fp);       /* lose the space */
 
665
                        if (cddb.path_to_cgi[0])
 
666
                                do
 
667
                                        i = getc(fp);
 
668
                                while (i != '\n' && i != EOF);
 
669
                        else
 
670
                        {
 
671
                                fgets(cddb.path_to_cgi, 
 
672
                                      sizeof(cddb.path_to_cgi), fp);
 
673
                                if ((i = strlen(cddb.path_to_cgi)))
 
674
                                        cddb.path_to_cgi[i - 1] = '\0';
 
675
                        }
 
676
                }
 
677
 
 
678
                else if (! strcmp(keyword, "cddbproxy"))
 
679
                {
 
680
                        getc(fp);       /* lose the space */
 
681
                        if (cddb.proxy_server[0])
 
682
                                do
 
683
                                        i = getc(fp);
 
684
                                while (i != '\n' && i != EOF);
 
685
                        else
 
686
                        {
 
687
                                fgets(cddb.proxy_server, 
 
688
                                      sizeof(cddb.proxy_server), fp);
 
689
                                if ((i = strlen(cddb.proxy_server)))
 
690
                                        cddb.proxy_server[i - 1] = '\0';
 
691
                        }
 
692
                }
 
693
 
 
694
                else if (! strcmp(keyword, "whendone"))
 
695
                {
 
696
                        getc(fp);
 
697
                        i = getc(fp);   /* only first letter is used */
 
698
                        if (cur_stopmode == -1) /* user's setting preferred */
 
699
                                cur_stopmode = i == 's' ? 0 : i == 'r' ? 1 : 2;
 
700
                        do
 
701
                                i = getc(fp);
 
702
                        while (i != '\n' && i != EOF);
 
703
                }
 
704
 
 
705
                else if (! strcmp(keyword, "playnew"))
 
706
                {
 
707
                        if (cur_playnew == -1)
 
708
                                cur_playnew = 1;
 
709
                        SWALLOW_LINE(fp);
 
710
                }
 
711
 
 
712
                /* If we're searching, skip to the next "tracks" line. */
 
713
                else if (((searching & 1)|| scan) 
 
714
                         && !(prefs && firstpos == -1))
 
715
                        SWALLOW_LINE(fp)
 
716
 
 
717
                else if (! strcmp(keyword, "sections"))
 
718
                {
 
719
                        gotsections = 1;
 
720
                        fscanf(fp, "%d", &ntracks);
 
721
 
 
722
                        free(trackmap);
 
723
                        trackmap = (int *) malloc(sizeof(int) *
 
724
                                                (cur_ntracks + ntracks));
 
725
                        if (trackmap == NULL)
 
726
                        {
 
727
                                perror("section mapping");
 
728
                                exit(1);
 
729
                        }
 
730
 
 
731
                        /*
 
732
                         * If sections are already defined, use these as a
 
733
                         * reference, mapping this CD entry's section numbers
 
734
                         * to the ones in core.
 
735
                         *
 
736
                         * Otherwise, split the CD up according to the sections
 
737
                         * listed here.
 
738
                         */
 
739
                        if (cur_nsections)
 
740
                        {
 
741
                                track = 0;
 
742
                                i = 0;
 
743
                                while (ntracks)
 
744
                                {
 
745
                                        ntracks--;
 
746
                                        fscanf(fp, "%d", &scratch);
 
747
                                        while (scratch > cd->trk[track].start)
 
748
                                        {
 
749
                                                if (cd->trk[track].section < 2)
 
750
                                                        trackmap[i++] = track;
 
751
                                                ++track;
 
752
 
 
753
                                                if (track == cur_ntracks)
 
754
                                                        break;
 
755
                                        }
 
756
 
 
757
                                        /* rc has later sections than db... */
 
758
                                        if (track == cur_ntracks)
 
759
                                                break;
 
760
 
 
761
                                        /* Matches can be approximate */
 
762
                                        if (scratch+75 > cd->trk[track].start &&
 
763
                                            scratch-75 < cd->trk[track].start)
 
764
                                                trackmap[i++] = track++;
 
765
                                        else
 
766
                                                trackmap[i++] = -1;
 
767
                                        
 
768
                                        if (track == cur_ntracks)
 
769
                                                break;
 
770
                                }
 
771
 
 
772
                                /* This only happens if track == cur_ntracks */
 
773
                                while (ntracks--)
 
774
                                        trackmap[i++] = -1;
 
775
 
 
776
                                while (track < cur_ntracks)
 
777
                                {
 
778
                                        if (cd->trk[track].section < 2)
 
779
                                                trackmap[i++] = track;
 
780
                                        track++;
 
781
                                }
 
782
 
 
783
                                track = 0;
 
784
                                SWALLOW_LINE(fp);
 
785
                        }
 
786
                        else
 
787
                        {
 
788
                                while (ntracks--)
 
789
                                {
 
790
                                        fscanf(fp, "%d", &scratch);
 
791
                                        split_trackinfo(scratch);
 
792
                                }
 
793
 
 
794
                                for (i = 0; i < cur_ntracks; i++)
 
795
                                {
 
796
                                        trackmap[i] = i;
 
797
                                        /* split_trackinfo() sets this */
 
798
                                        cd->trk[i].contd = 0;
 
799
                                }
 
800
 
 
801
                                SWALLOW_LINE(fp);
 
802
                        }
 
803
                }
 
804
 
 
805
                else if (! strcmp(keyword, "track"))
 
806
                {
 
807
                        char buf[502];
 
808
 
 
809
                        getc(fp);       /* lose the space */
 
810
 
 
811
                        /* don't overwrite existing track names. */
 
812
                        /* However, overwrite them if there was a "bad" fuzzy match before */
 
813
                        if ((trackmap[track] == -1 || track > (cd->ntracks + cur_nsections)) && (searching == 2))
 
814
                                SWALLOW_LINE(fp)
 
815
                        else if (cd->trk[trackmap[track]].songname &&
 
816
                                        cd->trk[trackmap[track]].songname[0])
 
817
                                do
 
818
                                        i = getc(fp);
 
819
                                while (i != '\n' && i != EOF);
 
820
                        else
 
821
                        {
 
822
                                fgets(buf, sizeof(buf), fp);
 
823
                                wm_lib_message(WM_MSG_CLASS_DB|WM_MSG_LEVEL_DEBUG, "found track %s\n", buf);
 
824
                                if( (i = strlen(buf)) )
 
825
                                        buf[i - 1] = '\0';
 
826
                                wm_strmcpy(&cd->trk[trackmap[track]].songname, buf);
 
827
                        }
 
828
                        track++;
 
829
                }
 
830
 
 
831
                else if (! strcmp(keyword, "playmode"))
 
832
                        fscanf(fp, "%d", &cd->playmode);
 
833
 
 
834
                else if (! strcmp(keyword, "autoplay"))
 
835
                        cd->autoplay = 1;
 
836
 
 
837
                else if (! strcmp(keyword, "cdname"))
 
838
                {
 
839
                        /* because of fuzzy matching that may change
 
840
                           the disk contents, we reset everything when
 
841
                           we find the name, in hopes that we will recover
 
842
                           most, if not all, of the information from the
 
843
                           file. */
 
844
/*
 
845
 * nasty bug was here. Was it? BUGBUGBUG
 
846
 *
 
847
 *                       wipe_cdinfo(); 
 
848
 *                       trackmap = reset_tracks();
 
849
 */
 
850
 
 
851
                        getc(fp);       /* lose the space */
 
852
                        /* don't overwrite existing cd name. */
 
853
                        if (cd->cdname[0] && (searching == 2))
 
854
                                do
 
855
                                        i = getc(fp);
 
856
                                while (i != '\n' && i != EOF);
 
857
                        else
 
858
                        {
 
859
                                if (searching > 1)
 
860
                                {
 
861
                                    strcpy(cd->cdname, "Probably://");
 
862
                                    fgets(cd->cdname + strlen(cd->cdname), sizeof(cd->cdname), fp);
 
863
                                } 
 
864
                                else 
 
865
                                {
 
866
                                    fgets(cd->cdname, sizeof(cd->cdname), fp);
 
867
                                } 
 
868
                                if ( (i = strlen(cd->cdname)) )
 
869
                                        cd->cdname[i - 1] = '\0';
 
870
                        }
 
871
                }
 
872
 
 
873
                else if (! strcmp(keyword, "artist"))
 
874
                {
 
875
                        getc(fp);       /* lose the space */
 
876
                        /* don't overwrite existing artist names. */
 
877
                        if (cd->artist[0])
 
878
                                do
 
879
                                        i = getc(fp);
 
880
                                while (i != '\n' && i != EOF);
 
881
                        else
 
882
                        {
 
883
                                fgets(cd->artist, sizeof(cd->artist), fp);
 
884
                                if( (i = strlen(cd->artist)) )
 
885
                                        cd->artist[i - 1] = '\0';
 
886
                        }
 
887
                }
 
888
 
 
889
                else if (! strcmp(keyword, "cdvolume"))
 
890
                {
 
891
                        fscanf(fp, "%d", &cd->volume);
 
892
                        cd->volume = (cd->volume * 100) / 32;
 
893
                }
 
894
 
 
895
                else if (! strcmp(keyword, "dontplay"))
 
896
                {
 
897
                        fscanf(fp, "%d", &i);
 
898
                        if (trackmap[i - 1] != -1)
 
899
                                cd->trk[trackmap[i - 1]].avoid = 1;
 
900
                }
 
901
 
 
902
                else if (! strcmp(keyword, "continue"))
 
903
                {
 
904
                        if (trackmap[track - 1] != -1)
 
905
                                cd->trk[trackmap[track - 1]].contd = 1;
 
906
                }
 
907
 
 
908
                else if (! strcmp(keyword, "volume"))
 
909
                {
 
910
                        fscanf(fp, "%d", &i);
 
911
                        if (trackmap[i - 1] == -1)
 
912
                                SWALLOW_LINE(fp)
 
913
                        else
 
914
                        {
 
915
                                i = trackmap[i - 1];
 
916
                                fscanf(fp, "%d", &cd->trk[i].volume);
 
917
                                cd->trk[i].volume = (cd->trk[i].volume*100)/32;
 
918
                                if (cd->trk[i].volume > 32)
 
919
                                        cd->trk[i].volume = 0;
 
920
                        }
 
921
                }
 
922
 
 
923
                else if (! strcmp(keyword, "playlist"))
 
924
                {
 
925
                        getc(fp);
 
926
                        fscanf(fp, "%s", listname);
 
927
 
 
928
/* XXX take this out at some point */
 
929
                        if (! strcmp(listname, "Default"))
 
930
                                strcpy(listname, "List A");
 
931
 
 
932
                        for (i = 0; listname[i]; i++)
 
933
                                if (listname[i] == '_')
 
934
                                        listname[i] = ' ';
 
935
 
 
936
                        l = new_list(cd, listname);
 
937
                        if (l == NULL)
 
938
                        {
 
939
plnomem:
 
940
                                perror("playlist read");
 
941
                                exit(1);
 
942
                        }
 
943
 
 
944
                        fscanf(fp, "%d", &listsize);
 
945
 
 
946
                        l->list = malloc(sizeof(int) * (listsize + 1));
 
947
                        if (l->list == NULL)
 
948
                                goto plnomem;
 
949
 
 
950
                        /* Leave out tracks that weren't in .workmandb. */
 
951
                        j = 0;
 
952
                        for (i = 0; i < listsize; i++)
 
953
                        {
 
954
                                fscanf(fp, "%d", &scratch);
 
955
                                scratch = trackmap[scratch - 1];
 
956
                                if (scratch != -1)
 
957
                                        l->list[j++] = scratch + 1;
 
958
                        }
 
959
 
 
960
                        l->list[j] = 0;
 
961
                }
 
962
 
 
963
                else if (! strcmp(keyword, "mark"))
 
964
                {
 
965
                        int mark_val = -1, mark_namelen;
 
966
                        char mark_name[32];
 
967
 
 
968
                        fscanf(fp, "%d", &mark_val);
 
969
                        if (mark_val == -1)
 
970
                                goto chomp;
 
971
 
 
972
                        if (getc(fp) != ' ')
 
973
                                continue;
 
974
 
 
975
                        fgets(mark_name, sizeof(mark_name), fp);
 
976
                        if( ( mark_namelen = strlen(mark_name)) )
 
977
                                mark_name[mark_namelen - 1] = '\0';
 
978
 
 
979
/*
 
980
                        if (! strcmp(mark_name, "START"))
 
981
                                set_abtimer(0, mark_val);
 
982
                        else if (! strcmp(mark_name, "END"))
 
983
                                set_abtimer(1, mark_val);
 
984
 
 
985
*/
 
986
                }
 
987
 
 
988
                /* Unrecognized keyword.  Put it in the right place. */
 
989
                else
 
990
                {
 
991
                        char    **buf, input[BUFSIZ];
 
992
 
 
993
                        if (track && trackmap[track - 1] == -1)
 
994
                        {
 
995
                                SWALLOW_LINE(fp);
 
996
                                continue;
 
997
                        }
 
998
 
 
999
                        i = track ? trackmap[track - 1] : 0;
 
1000
                        buf = prefs ? i ? &cd->trk[i].otherrc : &cd->otherrc :
 
1001
                                i ? &cd->trk[i].otherdb : &cd->otherdb;
 
1002
                        if (firstpos == -1) {
 
1003
                                if (prefs) {
 
1004
                                        buf = &otherrc;
 
1005
                                } else {
 
1006
                                        goto chomp;
 
1007
                                } /* if() else */
 
1008
                        } /* if() */
 
1009
                        wm_strmcat(buf, keyword);
 
1010
                        do {
 
1011
                                input[sizeof(input) - 1] = 'x';
 
1012
                                fgets(input, sizeof(input), fp);
 
1013
                                wm_strmcat(buf, input);
 
1014
                        } while (input[sizeof(input) - 1] != 'x');
 
1015
                }
 
1016
        }
 
1017
 
 
1018
        if (rclen == 0 && !searching)
 
1019
                rclen = pos - rcpos;
 
1020
 
 
1021
        if (searching > 1) /* A near match has been found. Good enough. */
 
1022
            searching = 0;
 
1023
 
 
1024
        cddb_struct2cur();
 
1025
        return (! searching);
 
1026
 
 
1027
} /* search_db() */
 
1028
 
 
1029
/*
 
1030
 * Delay some amount of time without using interval timers.
 
1031
 */
 
1032
void
 
1033
spinwheels(int secs) {
 
1034
        struct timeval  tv;
 
1035
 
 
1036
        tv.tv_usec = 0;
 
1037
        tv.tv_sec = secs;
 
1038
        select(0, NULL, NULL, NULL, &tv);
 
1039
} /* spinwheels() */
 
1040
 
 
1041
/*
 
1042
 * lockit(fd, type)
 
1043
 *
 
1044
 * fd    file descriptor
 
1045
 * type  lock type
 
1046
 *
 
1047
 * Lock a file.  Time out after a little while if we can't get a lock;
 
1048
 * this usually means the locking system is broken.
 
1049
 *
 
1050
 * Unfortunately, if there are lots of people contending for a lock,
 
1051
 * this can result in the file not getting locked when it probably should.
 
1052
 */
 
1053
int
 
1054
lockit(int fd, int type)
 
1055
{
 
1056
        struct flock    fl;
 
1057
        int             result, timer = 0;
 
1058
 
 
1059
        if (suppress_locking)
 
1060
                return (0);
 
1061
 
 
1062
        fl.l_type = type;
 
1063
        fl.l_whence = 0;
 
1064
        fl.l_start = 0;
 
1065
        fl.l_len = 0;
 
1066
 
 
1067
        while ((result = fcntl(fd, F_SETLK, &fl)) < 0)
 
1068
        {
 
1069
                if (errno != EACCES || errno != EAGAIN)
 
1070
                        break;
 
1071
                if (timer++ == 30)
 
1072
                {
 
1073
                        errno = ETIMEDOUT;
 
1074
                        break;
 
1075
                }
 
1076
 
 
1077
                spinwheels(1);
 
1078
        }
 
1079
 
 
1080
        return (result);
 
1081
} /* lockit() */
 
1082
 
 
1083
/*
 
1084
 * Search all the database files and our personal preference file for
 
1085
 * more information about the current CD.
 
1086
 */
 
1087
void
 
1088
load( void )
 
1089
{
 
1090
        FILE            *fp;
 
1091
        char            **dbfile;
 
1092
        int             locked = 0;
 
1093
        int             dbfound = 0, *trklist, i;
 
1094
        unsigned long   dbpos;
 
1095
 
 
1096
/* This is some kind of profiling code. I don't change it
 
1097
   to wm_lib_message() for now... */
 
1098
#ifdef DEBUG
 
1099
        long            t1, t2;
 
1100
        if( getenv( "WORKMAN_DEBUG" ) != NULL )
 
1101
          {
 
1102
                time(&t1);
 
1103
                printf("%s (%d): search start = %ld\n", __FILE__, __LINE__, t1);
 
1104
                fflush(stdout);
 
1105
          }     
 
1106
#endif
 
1107
 
 
1108
        dbfile = databases;
 
1109
 
 
1110
        found_in_db = 0;
 
1111
 
 
1112
        /* Turn the cd->trk array into a simple array of ints. */
 
1113
        trklist = (int *)malloc(sizeof(int) * cd->ntracks);
 
1114
        for (i = 0; i < cd->ntracks; i++)
 
1115
                trklist[i] = cd->trk[i].start;
 
1116
 
 
1117
        do {
 
1118
                if (*dbfile && idx_find_entry(*dbfile, cd->ntracks, trklist,
 
1119
                                cd->length * 75, 0, &dbpos) == 0)
 
1120
                        dbfound = 1;
 
1121
 
 
1122
                fp = *dbfile ? open_rcfile(*dbfile, "r") : NULL;
 
1123
                if (fp != NULL)
 
1124
                {
 
1125
                        if (lockit(fileno(fp), F_RDLCK))
 
1126
                                perror("Couldn't get read (db) lock");
 
1127
                        else
 
1128
                                locked = 1;
 
1129
 
 
1130
                        if (dbfound)
 
1131
                                fseek(fp, dbpos, 0);
 
1132
 
 
1133
                        if (search_db(fp, 0, 0, 0))
 
1134
                        {
 
1135
                                found_in_db = 1;
 
1136
                                cd->whichdb = *dbfile;
 
1137
                        }
 
1138
 
 
1139
                        if (locked && lockit(fileno(fp), F_UNLCK))
 
1140
                                perror("Couldn't relinquish (db) lock");
 
1141
 
 
1142
                        fclose(fp);
 
1143
                }
 
1144
        } while (*++dbfile != NULL && cd->whichdb == NULL);
 
1145
 
 
1146
#ifdef DEBUG
 
1147
        if( getenv( "WORKMAN_DEBUG" ) != NULL )
 
1148
          {
 
1149
                time(&t2);
 
1150
                printf("%s (%d): db search end = %ld, elapsed = %ld\n", __FILE__, __LINE__, t2, t2 - t1);
 
1151
                fflush(stdout);
 
1152
          }     
 
1153
#endif
 
1154
 
 
1155
        fp = rcfile ? open_rcfile(rcfile, "r") : NULL;
 
1156
        if (fp != NULL)
 
1157
        {
 
1158
                locked = 0;
 
1159
                if (lockit(fileno(fp), F_RDLCK))
 
1160
                        perror("Couldn't get read (rc) lock");
 
1161
                else
 
1162
                        locked = 1;
 
1163
 
 
1164
                rcpos = 0;
 
1165
                found_in_rc = search_db(fp, 1, 0, 0);
 
1166
                if (! found_in_rc)
 
1167
                        cd->autoplay = wm_db_get_playnew();
 
1168
 
 
1169
                if (locked && lockit(fileno(fp), F_UNLCK))
 
1170
                        perror("Couldn't relinquish (rc) lock");
 
1171
 
 
1172
                fclose(fp);
 
1173
        }
 
1174
 
 
1175
        free(trklist);
 
1176
 
 
1177
        if (cur_playnew == -1)
 
1178
                cur_playnew = 0;
 
1179
 
 
1180
#ifdef DEBUG
 
1181
        if( getenv( "WORKMAN_DEBUG" ) != NULL )
 
1182
          {
 
1183
                time(&t2);
 
1184
                printf("%s (%d): search end = %ld, elapsed = %ld\n", __FILE__, __LINE__, t2, t2 - t1);
 
1185
                fflush(stdout);
 
1186
          }     
 
1187
#endif
 
1188
} /* load() */
 
1189
 
 
1190
/*
 
1191
 * Load program settings from the rcfile.
 
1192
 */
 
1193
void
 
1194
load_settings( void )
 
1195
{
 
1196
        FILE    *fp;
 
1197
        int     locked;
 
1198
 
 
1199
        fp = rcfile ? open_rcfile(rcfile, "r") : NULL;
 
1200
        if (fp != NULL)
 
1201
        {
 
1202
                locked = 0;
 
1203
                if (lockit(fileno(fp), F_RDLCK))
 
1204
                        perror("Couldn't get read (rc) lock");
 
1205
                else
 
1206
                        locked = 1;
 
1207
 
 
1208
                rcpos = 0;
 
1209
                found_in_rc = search_db(fp, 2, 0, 0);
 
1210
                if (! found_in_rc)
 
1211
                        cd->autoplay = wm_db_get_playnew();
 
1212
 
 
1213
                if (locked && lockit(fileno(fp), F_UNLCK))
 
1214
                        perror("Couldn't relinquish (rc) lock");
 
1215
 
 
1216
                fclose(fp);
 
1217
        }
 
1218
} /* load_settings() */
 
1219
 
 
1220
/*
 
1221
 * save_globals()
 
1222
 *
 
1223
 * Save the global preferences, scooting CD entries to the end if needed.
 
1224
 * The assumption here is that the rcfile is locked, and that firstpos has
 
1225
 * been set by a previous scan.
 
1226
 */
 
1227
void
 
1228
save_globals(FILE *fp)
 
1229
{
 
1230
        char    *globes = NULL, *cdentry = NULL, temp[100];
 
1231
        long    curpos;
 
1232
        int     globesize, hit_cdent = 0, c = 0;
 
1233
 
 
1234
        if (otherrc)
 
1235
                wm_strmcpy(&globes, otherrc);
 
1236
 
 
1237
        if (cddb.protocol)
 
1238
        {
 
1239
                sprintf(temp, "cddbprotocol ");
 
1240
                switch(cddb.protocol)
 
1241
                {
 
1242
                 case 1: /* cddbp */
 
1243
                    sprintf(temp + strlen(temp), "cddbp\n");
 
1244
                    break;
 
1245
                 case 2: /* http */
 
1246
                    sprintf(temp + strlen(temp), "http\n");
 
1247
                    break;
 
1248
                 case 3: /* proxy */
 
1249
                    sprintf(temp + strlen(temp), "proxy\n");
 
1250
                    break;
 
1251
                 default:
 
1252
                    break;
 
1253
                }
 
1254
                wm_strmcat(&globes, temp);
 
1255
            
 
1256
                if(cddb.mail_adress[0])
 
1257
                {
 
1258
                        sprintf(temp,"cddbmailadress %s\n",
 
1259
                                cddb.mail_adress);
 
1260
                        wm_strmcat(&globes, temp);
 
1261
                }
 
1262
 
 
1263
                if(cddb.cddb_server[0])
 
1264
                {
 
1265
                        sprintf(temp,"cddbserver %s\n",
 
1266
                                cddb.cddb_server);
 
1267
                        wm_strmcat(&globes, temp);
 
1268
                }
 
1269
 
 
1270
                if(cddb.path_to_cgi[0])
 
1271
                {
 
1272
                        sprintf(temp,"cddbpathtocgi %s\n",
 
1273
                                cddb.mail_adress);
 
1274
                        wm_strmcat(&globes, temp);
 
1275
                }
 
1276
 
 
1277
                if(cddb.proxy_server[0])
 
1278
                {
 
1279
                        sprintf(temp,"cddbproxy %s\n",
 
1280
                                cddb.mail_adress);
 
1281
                        wm_strmcat(&globes, temp);
 
1282
                }
 
1283
        }
 
1284
 
 
1285
        if (cur_stopmode == 1 || cur_stopmode == 2)
 
1286
        {
 
1287
                sprintf(temp, "whendone %s\n", cur_stopmode == 1 ? "repeat" :
 
1288
                        "eject");
 
1289
                wm_strmcat(&globes, temp);
 
1290
        }
 
1291
 
 
1292
        if (cur_playnew == 1)
 
1293
                wm_strmcat(&globes, "playnew\n");
 
1294
 
 
1295
        curpos = firstpos;
 
1296
        if (curpos < 0)
 
1297
                curpos = 0;
 
1298
 
 
1299
        fseek(fp, curpos, SEEK_SET);
 
1300
 
 
1301
        if (firstpos < (globesize = globes != NULL ? strlen(globes) : 0))
 
1302
        {
 
1303
                while (1)
 
1304
                {
 
1305
                        temp[sizeof(temp)-1] = 'x';
 
1306
 
 
1307
                        if (fgets(temp, sizeof(temp), fp) == NULL)
 
1308
                        {
 
1309
                                fseek(fp, 0, SEEK_SET);
 
1310
                                if (globes != NULL)
 
1311
                                {
 
1312
                                        fwrite(globes, globesize, 1, fp);
 
1313
                                        free(globes);
 
1314
                                }
 
1315
                                if (cdentry != NULL)
 
1316
                                {
 
1317
                                        fwrite(cdentry, strlen(cdentry), 1, fp);
 
1318
                                        free(cdentry);
 
1319
                                }
 
1320
                                return;
 
1321
                        }
 
1322
 
 
1323
                        if (! strncmp(temp, "tracks ", 7))
 
1324
                        {
 
1325
                                hit_cdent = 1;
 
1326
                                if (curpos >= globesize)
 
1327
                                        break;
 
1328
                        }
 
1329
 
 
1330
                        if (! hit_cdent)
 
1331
                        {
 
1332
                                curpos += strlen(temp);
 
1333
                                if (temp[sizeof(temp)-1] == '\0')
 
1334
                                        while ((c = getc(fp)) != '\n' &&
 
1335
                                                                c != EOF)
 
1336
                                                curpos++;
 
1337
                                if (c == '\n')
 
1338
                                        curpos++;
 
1339
 
 
1340
                                continue;
 
1341
                        }
 
1342
 
 
1343
                        wm_strmcat(&cdentry, temp);
 
1344
                        curpos += strlen(temp);
 
1345
                        while (temp[sizeof(temp)-1] == '\0')
 
1346
                        {
 
1347
                                temp[sizeof(temp)-1] = 'x';
 
1348
                                if (fgets(temp, sizeof(temp), fp) == NULL)
 
1349
                                        break;
 
1350
                                wm_strmcat(&cdentry, temp);
 
1351
                                curpos += strlen(temp);
 
1352
                        }
 
1353
                } 
 
1354
 
 
1355
                if (cdentry != NULL)
 
1356
                {
 
1357
                        fseek(fp, 0, SEEK_END);
 
1358
                        fwrite(cdentry, strlen(cdentry), 1, fp);
 
1359
                        free(cdentry);
 
1360
                }
 
1361
        }
 
1362
 
 
1363
        if (globes != NULL)
 
1364
        {
 
1365
                fseek(fp, 0, SEEK_SET);
 
1366
                fwrite(globes, globesize, 1, fp);
 
1367
                free(globes);
 
1368
        }
 
1369
 
 
1370
        while (globesize++ < curpos)
 
1371
                putc('\n', fp);
 
1372
} /* save_globals() */
 
1373
 
 
1374
/*
 
1375
 * save_entry()
 
1376
 *
 
1377
 * Save the CD information to one database.
 
1378
 *
 
1379
 *      filename        Database to save to.
 
1380
 *      pref            0 for hard data, 1 for preferences.
 
1381
 *
 
1382
 * If an entry for this CD exists already, overwrite it with the new entry
 
1383
 * if the new entry is the same size or smaller, or with newlines if the new
 
1384
 * entry is larger (in which case the new entry is appended to the file.)
 
1385
 *
 
1386
 * Also, if the preference information is being updated, save it to the
 
1387
 * file while we've got it locked.  Scoot stuff from the beginning of
 
1388
 * the file to the end as needed to facilitate this.
 
1389
 *
 
1390
 * XXX Preference-saving should probably be done elsewhere, like in an
 
1391
 * Apply button on the Goodies popup, and in any case needs to go to a
 
1392
 * different file (.Xdefaults?)
 
1393
 *
 
1394
 * Returns 0 on success.
 
1395
 */
 
1396
int
 
1397
save_entry(char *filename, int pref)
 
1398
{
 
1399
        FILE            *fp;
 
1400
        char            *buf;
 
1401
        int             len, i, locked = 0;
 
1402
 
 
1403
 
 
1404
        if( filename == NULL )
 
1405
                return (-1);
 
1406
 
 
1407
        fp = open_rcfile(filename, "r+");
 
1408
        if (fp == NULL)
 
1409
        {
 
1410
                if (errno == ENOENT)    /* doesn't exist already */
 
1411
                        fp = open_rcfile(filename, "w");
 
1412
                if (fp == NULL)
 
1413
                        return (-1);
 
1414
        }
 
1415
 
 
1416
        if (lockit(fileno(fp), F_WRLCK))
 
1417
                perror("Warning: Couldn't get write lock");
 
1418
        else
 
1419
                locked = 1;
 
1420
 
 
1421
        buf = print_cdinfo(cd, pref);
 
1422
        len = strlen(buf);      /* doesn't return if there's an error */
 
1423
 
 
1424
        rcpos = -1;
 
1425
        search_db(fp, pref, 1, len);
 
1426
        if (rcpos != -1)                /* XXX */
 
1427
        {
 
1428
                /*
 
1429
                 * Jump to the entry's position in the database file, if
 
1430
                 * it was found.
 
1431
                 */
 
1432
                fseek(fp, rcpos, SEEK_SET);
 
1433
 
 
1434
                if (rclen >= len && holepos == -1)
 
1435
                {
 
1436
                        /*
 
1437
                         * If the new entry will fit in the space occupied by
 
1438
                         * the old one, overwrite the old one and make a hole
 
1439
                         * of the appropriate size at its end.
 
1440
                         *
 
1441
                         * No need to update the index file in this case, as
 
1442
                         * the entry's position hasn't changed.
 
1443
                         */
 
1444
                        fputs(buf, fp);
 
1445
                        for (i = len; i < rclen; i++)
 
1446
                                fputc('\n', fp);
 
1447
                }
 
1448
                else
 
1449
                {
 
1450
                        /*
 
1451
                         * Overwrite the old entry with a hole and delete
 
1452
                         * its pointer in the index file.
 
1453
                         */
 
1454
                        for (i = 0; i < rclen; i++)
 
1455
                                fputc('\n', fp);
 
1456
                        idx_delete_entry(filename, cd->trk[cd->ntracks-1].start,
 
1457
                                        0, rcpos);
 
1458
 
 
1459
                        rcpos = -1;
 
1460
                }
 
1461
        }
 
1462
 
 
1463
        /*
 
1464
         * Old entry wasn't found, or its new version wouldn't fit where
 
1465
         * the old one was.
 
1466
         */
 
1467
        if (rcpos == -1)
 
1468
        {
 
1469
                /*
 
1470
                 * Write the new entry in a hole, if there is one,
 
1471
                 * or at the end of the file.
 
1472
                 */
 
1473
                if (holepos >= 0)
 
1474
                {
 
1475
                        fseek(fp, holepos, SEEK_SET);
 
1476
                        if (holepos < firstpos)
 
1477
                                firstpos = holepos;
 
1478
                }
 
1479
                else
 
1480
                {
 
1481
                        fseek(fp, 0, SEEK_END);
 
1482
                        holepos = ftell(fp);
 
1483
                }
 
1484
                fputs(buf, fp);
 
1485
 
 
1486
                /*
 
1487
                 * Write a new index entry for this CD.
 
1488
                 */
 
1489
                idx_write_entry(filename, cd->trk[cd->ntracks - 1].start,
 
1490
                        holepos);
 
1491
        }
 
1492
 
 
1493
        if (pref)
 
1494
                save_globals(fp);
 
1495
 
 
1496
        fflush(fp);
 
1497
 
 
1498
        if (locked && lockit(fileno(fp), F_UNLCK))
 
1499
                perror("Warning: Couldn't relinquish write lock");
 
1500
 
 
1501
        fclose(fp);
 
1502
 
 
1503
        return (0);
 
1504
} /* save_entry() */
 
1505
 
 
1506
/*
 
1507
 * save()
 
1508
 *
 
1509
 * Save CD information to the appropriate datafile (the first file in the
 
1510
 * list, unless the entry came from another database file) and to the
 
1511
 * personal prefs file.
 
1512
 */
 
1513
int
 
1514
save( void )
 
1515
{
 
1516
 
 
1517
        if( wm_db_save_disabled == FALSE )
 
1518
        {
 
1519
                if (save_entry(rcfile, 1))
 
1520
                        return (0);
 
1521
 
 
1522
                if (cd->whichdb == NULL || access(cd->whichdb, W_OK))
 
1523
                        cd->whichdb = databases[0];
 
1524
 
 
1525
                if (save_entry(cd->whichdb, 0))
 
1526
                        return (0);
 
1527
 
 
1528
                return( WM_DB_SAVE_ERROR );
 
1529
        } else {
 
1530
                return( WM_DB_SAVE_DISABLED );
 
1531
        }
 
1532
} /* save() */