~ubuntu-branches/ubuntu/edgy/ggz-client-libs/edgy

« back to all changes in this revision

Viewing changes to ggz-config/ggz-config.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Eisentraut, Josef Spillner, Peter Eisentraut
  • Date: 2006-09-09 13:37:14 UTC
  • mfrom: (2.1.2 edgy)
  • Revision ID: james.westby@ubuntu.com-20060909133714-q49a9kvjfkc0wcc3
Tags: 0.0.13-3
[ Josef Spillner ]
* Change ggzcore-bin dependency from ggzmod to recommends from ggzcore
  (closes: #384671).

[ Peter Eisentraut ]
* Make package dependencies binNMU-safe through use of ${binary:Version}
  (closes: #386126)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * File: ggz-config.c
 
3
 * Author: Rich Gade
 
4
 * Project: GGZ Core Client Lib
 
5
 * Date: 02/19/01
 
6
 * $Id: ggz-config.c 7712 2006-01-02 16:45:48Z josef $
 
7
 *
 
8
 * Configuration query and module install program.
 
9
 *
 
10
 * Copyright (C) 2001 Rich Gade.
 
11
 *
 
12
 * This program is free software; you can redistribute it and/or modify
 
13
 * it under the terms of the GNU General Public License as published by
 
14
 * the Free Software Foundation; either version 2 of the License, or
 
15
 * (at your option) any later version.
 
16
 *
 
17
 * This program is distributed in the hope that it will be useful,
 
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 * GNU General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU General Public License
 
23
 * along with this program; if not, write to the Free Software
 
24
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
25
 */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#  include <config.h>           /* Site-specific config */
 
29
#endif
 
30
 
 
31
#include <stdio.h>
 
32
#include <stdlib.h>
 
33
#include <string.h>
 
34
#include <unistd.h>
 
35
#include <getopt.h>
 
36
 
 
37
#include <sys/stat.h>
 
38
#include <dirent.h>
 
39
 
 
40
#include <ggz.h>
 
41
 
 
42
#include "protocol.h"
 
43
 
 
44
#include <locale.h>
 
45
#include <libintl.h>
 
46
 
 
47
#define _(x) gettext(x)
 
48
#define N_(x) (x)
 
49
 
 
50
/* Command line arguments and global variables */
 
51
static char *modname = NULL;
 
52
static char *modversion = NULL;
 
53
static char *modpengine = NULL;
 
54
static char *modpversion = NULL;
 
55
static char *modexec = NULL;
 
56
static char *modui = NULL;
 
57
static char *modauthor = NULL;
 
58
static char *modurl = NULL;
 
59
static char *modenvironment = NULL;
 
60
static char *modicon = NULL;
 
61
static char *modhelp = NULL;
 
62
static char *modfile = NULL;
 
63
static char *iconfile = NULL;
 
64
static char *copydir = NULL;
 
65
static char *managediconfile = NULL;
 
66
static int modforce = 0;
 
67
static int moddest = 0;
 
68
static char *destdir = NULL;
 
69
static int install_mod = 0;
 
70
static int remove_mod = 0;
 
71
static int check_file = 0;
 
72
 
 
73
/* Command line options */
 
74
/* If they are changed make sure to edit the manpage! */
 
75
static struct option options[] =
 
76
{
 
77
        {"configdir", no_argument, 0, 'c'},
 
78
        {"gamedir", no_argument, 0, 'g'},
 
79
        {"datadir", no_argument, 0, 'd'},
 
80
        {"version", no_argument, 0, 'v'},
 
81
        {"protocol", no_argument, 0, 'p'},
 
82
        {"install", no_argument, 0, 'i'},
 
83
        {"remove", no_argument, 0, 'r'},
 
84
        {"check", no_argument, 0, 'C'},
 
85
        {"modfile", required_argument, 0, 'm'},
 
86
        {"iconfile", required_argument, 0, 'I'},
 
87
        {"noregistry", required_argument, 0, 'n'},
 
88
        {"force", no_argument, 0, 'f'},
 
89
        {"destdir", no_argument, 0, 'D'},
 
90
        {"help", no_argument, 0, 'h'},
 
91
        {"usage", no_argument, 0, 'u'},
 
92
        {0, 0, 0, 0}
 
93
};
 
94
 
 
95
/* Help for the command line options */
 
96
static char *options_help[] = {
 
97
         N_("Query GGZCONFDIR - location of configuration directory"),
 
98
         N_("Query GGZGAMEDIR - location of game modules directory"),
 
99
         N_("Query GGZDATADIR - location of game data directory"),
 
100
         N_("Query VERSION - version identifier of ggzcore files"),
 
101
         N_("Query GGZ_CS_PROTO_VERSION - version of core protocol"),
 
102
         N_("Install a module"),
 
103
         N_("Remove a module"),
 
104
         N_("Check/repair module installation file"),
 
105
         N_("Specifies module installation file (needs argument)"),
 
106
         N_("Specifies icon file to use for the game (needs argument)"),
 
107
         N_("Use auxiliary directory instead of ggz.modules (needs argument)"),
 
108
         N_("Install over an existing module"),
 
109
         N_("Use $DESTDIR as offset to ggz.modules file"),
 
110
         N_("Display help"),
 
111
         N_("Display usage"),
 
112
         NULL
 
113
};
 
114
 
 
115
 
 
116
static int load_modfile(void)
 
117
{
 
118
        int from;
 
119
        int status = 1;
 
120
 
 
121
        from = ggz_conf_parse(modfile, GGZ_CONF_RDONLY);
 
122
 
 
123
        modname = ggz_conf_read_string(from, "ModuleInfo",
 
124
                                             "Name", NULL);
 
125
        if(modname == NULL) {
 
126
                fprintf(stderr, _("Critical: Module name not specified.\n"));
 
127
                status = 0;
 
128
        }
 
129
 
 
130
        modversion = ggz_conf_read_string(from, "ModuleInfo",
 
131
                                                "Version", NULL);
 
132
        if(modversion == NULL) {
 
133
                fprintf(stderr, _("Critical: Module version not specified.\n"));
 
134
                status = 0;
 
135
        }
 
136
 
 
137
        modexec = ggz_conf_read_string(from, "ModuleInfo",
 
138
                                             "CommandLine", NULL);
 
139
        if(modexec == NULL) {
 
140
                fprintf(stderr, _("Critical: Executable not specified.\n"));
 
141
                status = 0;
 
142
        }
 
143
 
 
144
        modui = ggz_conf_read_string(from, "ModuleInfo",
 
145
                                           "Frontend", NULL);
 
146
        if(modui == NULL) {
 
147
                fprintf(stderr, _("Critical: User interface not specified.\n"));
 
148
                status = 0;
 
149
        }
 
150
 
 
151
        modpengine = ggz_conf_read_string(from, "ModuleInfo",
 
152
                                                "ProtocolEngine", NULL);
 
153
        if(modpengine == NULL) {
 
154
                fprintf(stderr, _("Critical: Protocol engine not specified.\n"));
 
155
                status = 0;
 
156
        }
 
157
 
 
158
        modpversion = ggz_conf_read_string(from, "ModuleInfo",
 
159
                                                 "ProtocolVersion", NULL);
 
160
        if(modpversion == NULL) {
 
161
                fprintf(stderr, _("Critical: Protocol version not specified.\n"));
 
162
                status = 0;
 
163
        }
 
164
 
 
165
        modauthor = ggz_conf_read_string(from, "ModuleInfo",
 
166
                                               "Author", NULL);
 
167
        if(modauthor == NULL) {
 
168
                fprintf(stderr, _("Critical: Module author not specified.\n"));
 
169
                status = 0;
 
170
        }
 
171
 
 
172
        modurl = ggz_conf_read_string(from, "ModuleInfo",
 
173
                                            "Homepage", NULL);
 
174
        if(modurl == NULL)
 
175
                fprintf(stderr, _("Warning: Module homepage not specified.\n"));
 
176
 
 
177
        modenvironment = ggz_conf_read_string(from, "ModuleInfo",
 
178
                                            "Environment", NULL);
 
179
        /*if(modenvironment == NULL)
 
180
                fprintf(stderr, _("Warning: Module environment not specified.\n"));*/
 
181
 
 
182
        modicon = ggz_conf_read_string(from, "ModuleInfo",
 
183
                                             "IconPath", NULL);
 
184
        modhelp = ggz_conf_read_string(from, "ModuleInfo",
 
185
                                             "HelpPath", NULL);
 
186
 
 
187
        return status;
 
188
}
 
189
 
 
190
 
 
191
static int purge_engine_name(int global)
 
192
{
 
193
        int items;
 
194
        char **engine_list;
 
195
        int index;
 
196
 
 
197
        ggz_conf_read_list(global, "Games", "*Engines*",
 
198
                                 &items, &engine_list);
 
199
 
 
200
        for(index=0; index<items; index++)
 
201
                if(!strcmp(engine_list[index], modpengine))
 
202
                        break;
 
203
 
 
204
        if(index != items-1)
 
205
                engine_list[index] = engine_list[items-1];
 
206
        items--;
 
207
 
 
208
        if(items != 0)
 
209
                ggz_conf_write_list(global, "Games", "*Engines*",
 
210
                                          items, engine_list);
 
211
        else
 
212
                ggz_conf_remove_key(global, "Games", "*Engines*");
 
213
 
 
214
        return 0;
 
215
}
 
216
 
 
217
 
 
218
static char *new_engine_id(int global)
 
219
{
 
220
        char **engine_list, **engine_id_list;
 
221
        int engines, ids;
 
222
        int hi=0, t;
 
223
        int i, j;
 
224
        static char new_id[10];
 
225
 
 
226
        ggz_conf_read_list(global, "Games", "*Engines*",
 
227
                                 &engines, &engine_list);
 
228
 
 
229
        for(i=0; i<engines; i++) {
 
230
                ggz_conf_read_list(global, "Games", engine_list[i],
 
231
                                                 &ids, &engine_id_list);
 
232
                for(j=0; j<ids; j++) {
 
233
                        t = atoi(engine_id_list[j] + 1);
 
234
                        if(t > hi)
 
235
                                hi = t;
 
236
                }
 
237
        }
 
238
 
 
239
        snprintf(new_id, 10, "p%d", hi+1);
 
240
 
 
241
        return new_id;
 
242
}
 
243
 
 
244
 
 
245
static char *get_engine_id(int global)
 
246
{
 
247
        int items;
 
248
        char **engine_list;
 
249
        char *engine_id=NULL;
 
250
        char *author, *ui, *version;
 
251
        int index;
 
252
 
 
253
        ggz_conf_read_list(global, "Games", modpengine,
 
254
                                 &items, &engine_list);
 
255
        if(items == 0)
 
256
                return NULL;
 
257
 
 
258
        for(index=0; index<items; index++) {
 
259
                engine_id = engine_list[index];
 
260
                author = ggz_conf_read_string(global, engine_id,
 
261
                                                    "Author", NULL);
 
262
                ui = ggz_conf_read_string(global, engine_id,
 
263
                                                "Frontend", NULL);
 
264
                managediconfile = ggz_conf_read_string(global, engine_id,
 
265
                                                "IconPath", NULL);
 
266
 
 
267
                if((!author) || (!ui))
 
268
                {
 
269
                        return "error";
 
270
                }
 
271
 
 
272
                if(modversion) {
 
273
                        version = ggz_conf_read_string(global, engine_id,
 
274
                                                             "Version", NULL);
 
275
                        if(!strcmp(author, modauthor) && !strcmp(ui, modui) &&
 
276
                           !strcmp(version, modversion))
 
277
                                break;
 
278
                } else if(!strcmp(author, modauthor) && !strcmp(ui, modui))
 
279
                        break;
 
280
        }
 
281
 
 
282
        if(index >= items)
 
283
                return NULL;
 
284
        else
 
285
                return engine_id;
 
286
}
 
287
 
 
288
 
 
289
static void purge_engine_id(int global, char *engine_id)
 
290
{
 
291
        int items;
 
292
        char **engine_list;
 
293
        int index;
 
294
 
 
295
        ggz_conf_read_list(global, "Games", modpengine,
 
296
                                 &items, &engine_list);
 
297
 
 
298
        for(index=0; index<items; index++)
 
299
                if(!strcmp(engine_list[index], engine_id))
 
300
                        break;
 
301
 
 
302
        if(index != items-1)
 
303
                engine_list[index] = engine_list[items-1];
 
304
        items--;
 
305
 
 
306
        if(items != 0)
 
307
                ggz_conf_write_list(global, "Games", modpengine,
 
308
                                          items, engine_list);
 
309
        else {
 
310
                ggz_conf_remove_key(global, "Games", modpengine);
 
311
                purge_engine_name(global);
 
312
        }
 
313
}
 
314
 
 
315
 
 
316
static int open_conffile(void)
 
317
{
 
318
        char    *global_filename = "ggz.modules";
 
319
        char global_pathname[(moddest ? strlen(destdir) : 0)
 
320
                             + strlen(GGZCONFDIR)
 
321
                             + strlen(global_filename) + 3];
 
322
        int     global;
 
323
 
 
324
        if(moddest)
 
325
                sprintf(global_pathname, "%s/%s/%s", destdir,
 
326
                                          GGZCONFDIR, global_filename);
 
327
        else
 
328
                sprintf(global_pathname, "%s/%s", GGZCONFDIR, global_filename);
 
329
 
 
330
        global = ggz_conf_parse(global_pathname, GGZ_CONF_RDONLY);
 
331
        if(global < 0) {
 
332
                printf(_("Setting up GGZ game modules configuration in %s\n"), global_pathname);
 
333
        }
 
334
        global = ggz_conf_parse(global_pathname, GGZ_CONF_CREATE | GGZ_CONF_RDWR);
 
335
        if(global < 0) {
 
336
                fprintf(stderr, _("Insufficient permission to install modules\n"));
 
337
                ggz_conf_cleanup();
 
338
                return -1;
 
339
        } else {
 
340
#ifndef HAVE_WINSOCK2_H
 
341
                /* HACK: chmod flags aren't available on windows. */
 
342
                chmod(global_pathname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
343
#endif
 
344
        }
 
345
 
 
346
        return global;
 
347
}
 
348
 
 
349
 
 
350
static int filecopy(const char *src, const char *dst)
 
351
{
 
352
        FILE *fin, *fout;
 
353
        int ch;
 
354
 
 
355
        fin = fopen(src, "r");
 
356
        if(!fin) {
 
357
                fprintf(stderr, _("File cannot be read (%s)\n"), src);
 
358
                return -1;
 
359
        }
 
360
        fout = fopen(dst, "w");
 
361
        if(!fout) {
 
362
                fprintf(stderr, _("File cannot be written to (%s)\n"), dst);
 
363
                fclose(fin);
 
364
                return -1;
 
365
        }
 
366
        while((ch = fgetc(fin)) != EOF) {
 
367
                fputc(ch, fout);
 
368
        }
 
369
        fclose(fout);
 
370
        fclose(fin);
 
371
 
 
372
        return 0;
 
373
}
 
374
 
 
375
 
 
376
static void handle_icon(void)
 
377
{
 
378
        int ret;
 
379
 
 
380
        if(install_mod) {
 
381
                if(!iconfile) return;
 
382
                /*modicon = modname;*/
 
383
                modicon = iconfile;
 
384
                while(strchr(modicon, '/')) {
 
385
                        modicon = strchr(modicon, '/') + 1;
 
386
                }
 
387
 
 
388
                {
 
389
                        char path[strlen(GGZDATADIR) + strlen(modicon) + 30];
 
390
 
 
391
                        strcpy(path, GGZDATADIR);
 
392
                        strcat(path, "/ggz-config/");
 
393
#ifdef MKDIR_TAKES_ONE_ARG
 
394
                        mkdir(path);
 
395
#else
 
396
                        mkdir(path, 0700);
 
397
#endif
 
398
                        strcat(path, modicon);
 
399
                        ret = filecopy(iconfile, path);
 
400
                        if(ret != 0) modicon = NULL;
 
401
                }
 
402
        } else if(remove_mod) {
 
403
                modicon = managediconfile;
 
404
                if (modicon && modicon[0] != '/') {
 
405
                        char path[strlen(GGZDATADIR) + strlen(modicon) + 30];
 
406
 
 
407
                        strcpy(path, GGZDATADIR);
 
408
                        strcat(path, "/ggz-config/");
 
409
                        strcat(path, modicon);
 
410
                        unlink(path);
 
411
                }
 
412
        }
 
413
}
 
414
 
 
415
 
 
416
static int remove_module(void)
 
417
{
 
418
        char    *engine_id;
 
419
        int     global, rc;
 
420
 
 
421
        if((global = open_conffile()) < 0)
 
422
                return global;
 
423
 
 
424
        engine_id = get_engine_id(global);
 
425
 
 
426
        if(engine_id == NULL) {
 
427
                fprintf(stderr, _("Warning: Tried to remove nonexistant module\n"));
 
428
                ggz_conf_cleanup();
 
429
                return -1;
 
430
        }
 
431
 
 
432
        handle_icon();
 
433
 
 
434
        rc = ggz_conf_remove_section(global, engine_id);
 
435
        if(rc == 0) {
 
436
                purge_engine_id(global, engine_id);
 
437
                rc = ggz_conf_commit(global);
 
438
        }
 
439
 
 
440
        if(rc != 0) {
 
441
                fprintf(stderr, _("ggz.modules configuration may be corrupt\n"));
 
442
                fprintf(stderr, _("Module removal failed, see documentation\n"));
 
443
        }
 
444
 
 
445
        ggz_conf_cleanup();
 
446
 
 
447
        return rc;
 
448
}
 
449
 
 
450
 
 
451
static int noregister_module(void)
 
452
{
 
453
        char *suffix = ".module.dsc";
 
454
        char global_pathname[(moddest ? strlen(destdir) : 0)
 
455
                             + strlen(copydir)
 
456
                             + strlen(modname)
 
457
                             + strlen(suffix) + 3];
 
458
        char fixedmodname[strlen(modname) + 1];
 
459
        unsigned int i;
 
460
 
 
461
        if(moddest)
 
462
                sprintf(global_pathname, "%s/%s", destdir, copydir);
 
463
        else
 
464
                sprintf(global_pathname, "%s", copydir);
 
465
 
 
466
        if (ggz_make_path(global_pathname) != 0) {
 
467
                fprintf(stderr, _("Directory cannot be created (%s)\n"),
 
468
                        global_pathname);
 
469
                return -1;
 
470
        }
 
471
 
 
472
        strcpy(fixedmodname, modname);
 
473
        for(i = 0; i < strlen(fixedmodname); i++) {
 
474
                if(fixedmodname[i] == '/') fixedmodname[i] = '_';
 
475
        }
 
476
        sprintf(global_pathname, "%s/%s%s", global_pathname, fixedmodname, suffix);
 
477
 
 
478
        printf(_("Preserving %s as %s...\n"), modfile, global_pathname);
 
479
        return filecopy(modfile, global_pathname);
 
480
}
 
481
 
 
482
 
 
483
static int install_module(void)
 
484
{
 
485
        char    *engine_id;
 
486
        int     global, rc;
 
487
        char    *engine_id_list, *engine_list;
 
488
        char    bigstr[1024];
 
489
 
 
490
        if((global = open_conffile()) < 0)
 
491
                return global;
 
492
 
 
493
        engine_id = get_engine_id(global);
 
494
 
 
495
        if((engine_id) && (!strcmp(engine_id, "error")))
 
496
        {
 
497
                fprintf(stderr, _("Your configuration is broken - aborting\n"));
 
498
                ggz_conf_cleanup();
 
499
                return -1;
 
500
        }
 
501
 
 
502
        if(!modforce) {
 
503
                if(engine_id != NULL) {
 
504
                        fprintf(stderr, _("Cannot overwrite existing module\n"));
 
505
                        ggz_conf_cleanup();
 
506
                        return -1;
 
507
                }
 
508
        }
 
509
 
 
510
        if(engine_id == NULL) {
 
511
                engine_id = new_engine_id(global);
 
512
                modforce = 0;
 
513
        }
 
514
 
 
515
        handle_icon();
 
516
 
 
517
        rc = ggz_conf_write_string(global, engine_id, "Name", modname);
 
518
        if(rc == 0) {
 
519
                ggz_conf_write_string(global, engine_id,
 
520
                                            "ProtocolEngine", modpengine);
 
521
                ggz_conf_write_string(global, engine_id,
 
522
                                            "ProtocolVersion", modpversion);
 
523
                ggz_conf_write_string(global, engine_id,
 
524
                                            "Frontend", modui);
 
525
                ggz_conf_write_string(global, engine_id,
 
526
                                            "Version", modversion);
 
527
                ggz_conf_write_string(global, engine_id,
 
528
                                            "Author", modauthor);
 
529
                ggz_conf_write_string(global, engine_id,
 
530
                                            "CommandLine", modexec);
 
531
                ggz_conf_write_string(global, engine_id,
 
532
                                            "Homepage", modurl);
 
533
                if(modenvironment)
 
534
                        ggz_conf_write_string(global, engine_id,
 
535
                                                    "Environment", modenvironment);
 
536
                if(modicon)
 
537
                        ggz_conf_write_string(global, engine_id,
 
538
                                                    "IconPath", modicon);
 
539
                if(modhelp)
 
540
                        ggz_conf_write_string(global, engine_id,
 
541
                                                    "HelpPath", modhelp);
 
542
 
 
543
                engine_id_list = ggz_conf_read_string(global, "Games",
 
544
                                                            modpengine, NULL);
 
545
                if(engine_id_list == NULL && !modforce) {
 
546
                        ggz_conf_write_string(global, "Games",
 
547
                                                    modpengine, engine_id);
 
548
                        engine_list = ggz_conf_read_string(global,"Games",
 
549
                                                    "*Engines*", NULL);
 
550
                        if(engine_list == NULL)
 
551
                                ggz_conf_write_string(global, "Games",
 
552
                                                    "*Engines*", modpengine);
 
553
                        else {
 
554
                                snprintf(bigstr, 1024, "%s %s",
 
555
                                         engine_list, modpengine);
 
556
                                ggz_conf_write_string(global, "Games",
 
557
                                                    "*Engines*", bigstr);
 
558
                        }
 
559
                } else if(!modforce) {
 
560
                        snprintf(bigstr, 1024, "%s %s",
 
561
                                 engine_id_list, engine_id);
 
562
                        ggz_conf_write_string(global, "Games",
 
563
                                                modpengine, bigstr);
 
564
                }
 
565
 
 
566
                rc = ggz_conf_commit(global);
 
567
        }
 
568
 
 
569
        if(rc != 0) {
 
570
                fprintf(stderr, _("ggz.modules configuration may be corrupt\n"));
 
571
                fprintf(stderr, _("Module installation failed, see documentation\n"));
 
572
        }
 
573
 
 
574
        ggz_conf_cleanup();
 
575
 
 
576
        return rc;
 
577
}
 
578
 
 
579
 
 
580
static int noregister_all()
 
581
{
 
582
        DIR *d;
 
583
        struct dirent *e;
 
584
        int ret;
 
585
        
 
586
        d = opendir(copydir);
 
587
        if(!d) {
 
588
                fprintf(stderr, _("Could not open auxiliary directory\n"));
 
589
                return -1;
 
590
        }
 
591
        while((e = readdir(d)) != NULL) {
 
592
#ifdef _DIRENT_HAVE_D_TYPE
 
593
                /* _DIRENT_HAVE_D_TYPE is defined in dirent.h...but this
 
594
                 * should be replaced by a configure check. */
 
595
                if(e->d_type != DT_REG) continue;
 
596
#endif
 
597
                modfile = (char*)ggz_malloc(strlen(copydir) + strlen(e->d_name) + 2);
 
598
                sprintf(modfile, "%s/%s", copydir, e->d_name);
 
599
                if(load_modfile()) {
 
600
                        if(install_mod) {
 
601
                                printf("- register %s\n", e->d_name);
 
602
                                ret = install_module();
 
603
                        } else if(remove_mod) {
 
604
                                printf("- unregister %s\n", e->d_name);
 
605
                                ret = remove_module();
 
606
                        } else ret = -1;
 
607
                } else {
 
608
                        ret = -1;
 
609
                }
 
610
                ggz_free(modfile);
 
611
                modfile = NULL;
 
612
                if(ret != 0) {
 
613
                        fprintf(stderr, _("An error occured, which is ignored.\n"));
 
614
                }
 
615
        }
 
616
        closedir(d);
 
617
 
 
618
        return 0;
 
619
}
 
620
 
 
621
 
 
622
#if 0 /* unused */
 
623
static int query(char *name, char *text, int def)
 
624
{
 
625
        char buf[3];
 
626
 
 
627
        fflush(stdin);
 
628
        printf("\n%s: %s [%c] ", name, text, def == 1?'Y':'N');
 
629
        fgets(buf, 3, stdin);
 
630
        if(def == 0) {
 
631
                if(*buf == 'Y' || *buf == 'y')
 
632
                        return 1;
 
633
        } else {
 
634
                if(*buf == 'N' || *buf == 'n')
 
635
                        return 0;
 
636
        }
 
637
 
 
638
        return def;
 
639
}
 
640
#endif
 
641
 
 
642
 
 
643
static int check_module_file(void)
 
644
{
 
645
        int     global;
 
646
        int     rc;
 
647
        int     e_count, s_count, k_count, g_count;
 
648
        char    **e_list, **s_list, **k_list, **g_list;
 
649
        char    *str, *str2;
 
650
        int     kill, ok, alt;
 
651
        int     i, j, k;
 
652
        int     *section_refd;
 
653
        int     errs=0;
 
654
 
 
655
        const char *reqd_keys[] = {
 
656
                "Author",
 
657
                "Frontend",
 
658
                "Name",
 
659
                "ProtocolEngine",
 
660
                "ProtocolVersion",
 
661
                "Version",
 
662
                NULL
 
663
        };
 
664
 
 
665
        if((global = open_conffile()) < 0)
 
666
                return global;
 
667
 
 
668
        /* Phase One */
 
669
        /* Check that every game engine section has req'd entries */
 
670
        if((rc = ggz_conf_get_sections(global, &s_count, &s_list)) <0
 
671
           || s_count == 0) {
 
672
                printf(_("Error getting config file sections list\n"));
 
673
                printf(_("May be an empty config file?\n"));
 
674
                return rc;
 
675
        }
 
676
        for(i=0; i<s_count; i++) {
 
677
                if(!strcmp(s_list[i], "Games")) {
 
678
                        ggz_free(s_list[i]);
 
679
                        continue;
 
680
                }
 
681
                printf(_("*** Checking game config section [%s]\n"), s_list[i]);
 
682
                kill=0;
 
683
                for(j=0; reqd_keys[j]; j++) {
 
684
                        str = ggz_conf_read_string(global, s_list[i],
 
685
                                                     reqd_keys[j], NULL);
 
686
                        if(str == NULL) {
 
687
                                errs++;
 
688
                                printf(_("ERR: missing required key '%s'\n"),
 
689
                                        reqd_keys[j]);
 
690
                                kill=1;
 
691
                        } else
 
692
                                ggz_free(str);
 
693
                }
 
694
                if(!kill) {
 
695
                        str = ggz_conf_read_string(global, s_list[i],
 
696
                                                     "CommandLine", NULL);
 
697
                        if(str != NULL) {
 
698
                                /* Without command line args */
 
699
                                str2 = str;
 
700
                                while(*str2 && *str2 != ' ') str2++;
 
701
                                *str2 = '\0';
 
702
                                if(access(str, X_OK))
 
703
                                        kill=1;
 
704
                                ggz_free(str);
 
705
                        }
 
706
                        if(kill) {
 
707
                                errs++;
 
708
                                printf(_("ERR: missing or invalid executable\n"));
 
709
                        }
 
710
                }
 
711
                if(kill) {
 
712
                        printf(_("Removing section for '%s'\n"), s_list[i]);
 
713
                        modpengine = ggz_conf_read_string(global, s_list[i], "ProtocolEngine", NULL);
 
714
                        rc = ggz_conf_remove_section(global, s_list[i]);
 
715
                        if(rc == 0) {
 
716
                                if(modpengine) {
 
717
                                        purge_engine_id(global, s_list[i]);
 
718
                                }
 
719
                                rc = ggz_conf_commit(global);
 
720
                        }
 
721
                }
 
722
 
 
723
                ggz_free(s_list[i]);
 
724
        }
 
725
        ggz_free(s_list);
 
726
 
 
727
 
 
728
        /* Phase Two */
 
729
        /* Check for cross references (multiple engines -> one game section) */
 
730
        if((rc = ggz_conf_get_sections(global, &s_count, &s_list)) <0) {
 
731
                printf(_("Error getting config file sections list\n"));
 
732
                return rc;
 
733
        }
 
734
phase_two:
 
735
        if((rc = ggz_conf_get_keys(global, "Games", &k_count, &k_list)) <0
 
736
           || k_count == 0) {
 
737
                printf(_("Error getting config file [Games]:keys list\n"));
 
738
                printf(_("May be an empty config file?\n"));
 
739
                return rc;
 
740
        }
 
741
        printf(_("*** Computing section cross references\n"));
 
742
        section_refd = ggz_malloc(s_count * sizeof(int));
 
743
        for(i=0; i<k_count; i++) {
 
744
                if(!strcmp(k_list[i], "*Engines*"))
 
745
                        continue;
 
746
                /*str = ggz_conf_read_string(global, "Games", k_list[i], NULL);*/
 
747
                ggz_conf_read_list(global, "Games", k_list[i], &g_count, &g_list);
 
748
                for(k = 0; k < g_count; k++)
 
749
                {
 
750
                        str = g_list[k];
 
751
 
 
752
                        for(j=0; j<s_count; j++) {
 
753
                                if(!strcmp(str, s_list[j])) {
 
754
                                        if(!section_refd[j]) {
 
755
                                                section_refd[j] = i+1;
 
756
                                                continue;
 
757
                                        }
 
758
                                        /* Check name in [p#] to see if it matches */
 
759
                                        /* either of the xrefs to decide smartly */
 
760
                                        str2 = ggz_conf_read_string(global, s_list[j],
 
761
                                                                    "Name", NULL);
 
762
                                        if(str2 && !strcmp(k_list[i], str2))
 
763
                                                kill = section_refd[j]-1;
 
764
                                        else
 
765
                                                kill = i;
 
766
                                        if(str2)
 
767
                                                ggz_free(str2);
 
768
                                        errs++;
 
769
                                        printf(_("ERR %s and %s references [%s], deleting %s reference\n"),
 
770
                                                k_list[i], k_list[section_refd[j]-1],
 
771
                                                s_list[j], k_list[kill]);
 
772
                                        ggz_conf_remove_key(global, "Games", k_list[kill]);
 
773
                                        for(i=0; i<k_count; i++)
 
774
                                                ggz_free(k_list[i]);
 
775
                                        ggz_free(k_list);
 
776
                                        for(i=k; i<g_count; i++)
 
777
                                                ggz_free(g_list[i]);
 
778
                                        ggz_free(g_list);
 
779
                                        ggz_free(section_refd);
 
780
 
 
781
                                        /* Restart the phase */
 
782
                                        goto phase_two;
 
783
                                }
 
784
                        }
 
785
                        ggz_free(g_list[k]);
 
786
                }
 
787
                ggz_free(g_list);
 
788
        }
 
789
        ggz_free(section_refd);
 
790
        for(i=0; i<s_count; i++)
 
791
                ggz_free(s_list[i]);
 
792
        ggz_free(s_list);
 
793
        /* Since we made it through phase two, k_list hasn't */
 
794
        /* changed, so we carry it over to phase three */
 
795
 
 
796
 
 
797
        /* Phase Three */
 
798
        /* Check each game key for correct engine name */
 
799
        for(i=0; i<k_count; i++) {
 
800
                if(!strcmp(k_list[i], "*Engines*")) {
 
801
                        ggz_free(k_list[i]);
 
802
                        continue;
 
803
                }
 
804
                printf(_("*** Checking ProtocolEngine key for engine '%s'\n"), k_list[i]);
 
805
                /*str = ggz_conf_read_string(global, "Games", k_list[i], NULL);*/
 
806
                ggz_conf_read_list(global, "Games", k_list[i], &g_count, &g_list);
 
807
                for(k = 0; k < g_count; k++) {
 
808
                        str = g_list[k];
 
809
 
 
810
                        str2 = ggz_conf_read_string(global, str, "ProtocolEngine", NULL);
 
811
                        if(str2 && strcmp(k_list[i], str2)) {
 
812
                                errs++;
 
813
                                printf(_("ERR Setting ProtocolEngine key [%s] to '%s'\n"),
 
814
                                        str, k_list[i]);
 
815
                                ggz_conf_write_string(global, str, "ProtocolEngine", k_list[i]);
 
816
                        }
 
817
                        /*ggz_free(str);*/
 
818
                        if(str2) ggz_free(str2);
 
819
                        ggz_free(g_list[k]);
 
820
                }
 
821
                ggz_free(g_list);
 
822
                ggz_free(k_list[i]);
 
823
        }
 
824
        ggz_free(k_list);
 
825
 
 
826
 
 
827
        /* Phase Four */
 
828
        /* Check that each section references back to a [Games]:key */
 
829
        printf(_("*** Checking back references\n"));
 
830
        if((rc = ggz_conf_get_sections(global, &s_count, &s_list)) <0) {
 
831
                printf(_("Error getting config file sections list\n"));
 
832
                return rc;
 
833
        }
 
834
        for(i=0; i<s_count; i++) {
 
835
                if(!strcmp(s_list[i], "Games")) {
 
836
                        ggz_free(s_list[i]);
 
837
                        continue;
 
838
                }
 
839
                str = ggz_conf_read_string(global, s_list[i], "ProtocolEngine", NULL);
 
840
                ggz_conf_read_list(global, "Games", str, &g_count, &g_list);
 
841
 
 
842
                ok = 0;
 
843
                for(j = 0; j < g_count; j++) {
 
844
                        if(!strcmp(s_list[i], g_list[j])) {
 
845
                                ok = 1;
 
846
                        }
 
847
                }
 
848
 
 
849
                if(!ok) {
 
850
                        errs++;
 
851
                        printf(_("ERR Adding [Games]:%s key pointing to [%s]\n"),
 
852
                                 str, s_list[i]);
 
853
                        g_count++;
 
854
                        g_list = ggz_realloc(g_list, g_count * sizeof(char*));
 
855
                        g_list[g_count - 1] = ggz_strdup(s_list[i]);
 
856
                        ggz_conf_write_list(global, "Games", str, g_count, g_list);
 
857
                }
 
858
 
 
859
                for(j = 0; j < g_count; j++) {
 
860
                        ggz_free(g_list[j]);
 
861
                }
 
862
                ggz_free(g_list);
 
863
 
 
864
                ggz_free(str);
 
865
                ggz_free(s_list[i]);
 
866
        }
 
867
        ggz_free(s_list);
 
868
 
 
869
        /* Phase Four/b */
 
870
        /* Check that each section key actually has a section*/
 
871
        printf(_("*** Checking forward references\n"));
 
872
        if((rc = ggz_conf_get_keys(global, "Games", &k_count, &k_list)) <0) {
 
873
                printf(_("Error getting config file [Games]:keys list\n"));
 
874
                return rc;
 
875
        }
 
876
 
 
877
        for(i = 0; i < k_count; i++) {
 
878
                if(!strcmp(k_list[i], "*Engines*")) {
 
879
                        ggz_free(k_list[i]);
 
880
                        continue;
 
881
                }
 
882
                ggz_conf_read_list(global, "Games", k_list[i], &g_count, &g_list);
 
883
 
 
884
                for(k = 0; k < g_count; k++) {
 
885
                        str = ggz_conf_read_string(global, g_list[k], "ProtocolEngine", NULL);
 
886
                        if(!str)
 
887
                        {
 
888
                                errs++;
 
889
                                printf(_("ERR Section %s doesn't exist in %s, removed reference\n"),
 
890
                                        g_list[k], k_list[i]);
 
891
                                ggz_free(g_list[k]);
 
892
                                g_count -= 1;
 
893
                                if(g_count) {
 
894
                                        if(k <= g_count)
 
895
                                                g_list[k] = g_list[g_count];
 
896
                                        ggz_conf_write_list(global, "Games", k_list[i], g_count, g_list);
 
897
                                } else {
 
898
                                        ggz_conf_remove_key(global, "Games", k_list[i]);
 
899
                                }
 
900
                        }
 
901
                        else ggz_free(str);
 
902
                }
 
903
                for(k = 0; k < g_count; k++)
 
904
                        ggz_free(g_list[k]);
 
905
                ggz_free(g_list);
 
906
        }
 
907
        ggz_free(k_list);
 
908
 
 
909
        /* Phase Five */
 
910
        /* Check that each entry in *Engines* points to something */
 
911
        printf(_("*** Checking for spurious game engine entries\n"));
 
912
phase_five:
 
913
        ggz_conf_read_list(global, "Games", "*Engines*", &e_count, &e_list);
 
914
        for(i=0; i<e_count; i++) {
 
915
                str = ggz_conf_read_string(global, "Games", e_list[i], NULL);
 
916
 
 
917
                        if(!str) {
 
918
                                errs++;
 
919
                                printf(_("ERR Game engine '%s' invalid, removing\n"),
 
920
                                       e_list[i]);
 
921
                                ggz_free(e_list[i]);
 
922
                                e_count--;
 
923
                                if(e_count) {
 
924
                                        if(i < e_count)
 
925
                                                e_list[i] = e_list[e_count];
 
926
                                        ggz_conf_write_list(global, "Games", "*Engines*",
 
927
                                                e_count, e_list);
 
928
                                } else {
 
929
                                        ggz_conf_remove_key(global, "Games", "*Engines*");
 
930
                                }
 
931
                                for(i=0; i<e_count; i++)
 
932
                                        ggz_free(e_list[i]);
 
933
                                ggz_free(e_list);
 
934
 
 
935
                                /*** Restart the phase ***/
 
936
                                goto phase_five;
 
937
                        }
 
938
                        ggz_free(str);
 
939
        }
 
940
        /* e_list is still valid and used in next phase */
 
941
 
 
942
        /* Final Phase */
 
943
        /* Make sure that every [Games]:key exists in [Games]:*Engines* */
 
944
        printf(_("*** Checking for missing game engine pointers\n"));
 
945
        if((rc = ggz_conf_get_keys(global, "Games", &k_count, &k_list)) <0) {
 
946
                printf(_("Error getting config file [Games]:keys list\n"));
 
947
                return rc;
 
948
        }
 
949
        alt = 0;
 
950
        for(i=0; i<k_count; i++) {
 
951
                if(!strcmp(k_list[i], "*Engines*")) {
 
952
                        ggz_free(k_list[i]);
 
953
                        continue;
 
954
                }
 
955
                ok = 0;
 
956
                for(j=0; j<e_count; j++)
 
957
                        if(!strcmp(k_list[i], e_list[j]))
 
958
                                ok=1;
 
959
                if(!ok) {
 
960
                        errs++;
 
961
                        printf(_("ERR Adding '%s' to game engine list\n"),
 
962
                                k_list[i]);
 
963
                        e_count++;
 
964
                        e_list = ggz_realloc(e_list, e_count*sizeof(char *));
 
965
                        e_list[e_count-1] = ggz_strdup(k_list[i]);
 
966
                        alt=1;
 
967
                }
 
968
                ggz_free(k_list[i]);
 
969
        }
 
970
        if(k_list) ggz_free(k_list);
 
971
        if(e_count)
 
972
                ggz_conf_write_list(global, "Games", "*Engines*", e_count, e_list);
 
973
        for(i=0; i<e_count; i++)
 
974
                if(alt || i<e_count-1)
 
975
                        ggz_free(e_list[i]);
 
976
        if(e_list) ggz_free(e_list);
 
977
 
 
978
        if(errs)
 
979
                printf(_("Finished - writing %d repairs\n"), errs);
 
980
        else
 
981
                printf(_("Finished - no configuration errors detected\n"));
 
982
        ggz_conf_commit(global);
 
983
 
 
984
        ggz_conf_cleanup();
 
985
 
 
986
        return 0;
 
987
}
 
988
 
 
989
int main(int argc, char *argv[])
 
990
{
 
991
        int optindex;
 
992
        int opt;
 
993
        int i;
 
994
        int rc;
 
995
 
 
996
        /* Set up translation */
 
997
        bindtextdomain("ggz-config", PREFIX "/share/locale");
 
998
        textdomain("ggz-config");
 
999
        setlocale(LC_ALL, "");
 
1000
 
 
1001
        /* Parse the command line options */
 
1002
        while(1)
 
1003
        {
 
1004
                opt = getopt_long(argc, argv, "cgdvpirCm:I:n:fDhu", options, &optindex);
 
1005
                if(opt == -1) break;
 
1006
                switch(opt)
 
1007
                {
 
1008
                        case 'h':
 
1009
                                printf(_("GGZ-Config - the GGZ Gaming Zone Configuration Utility\n"));
 
1010
                                printf(_("Copyright (C) 2001 Rich Gade, rgade@users.sourceforge.net\n"));
 
1011
                                printf(_("Copyright (C) 2002 - 2005 The GGZ Gaming Zone developers\n"));
 
1012
                                printf(_("Published under GNU GPL conditions\n"));
 
1013
                                printf("\n");
 
1014
                                printf(_("Recognized options:\n"));
 
1015
 
 
1016
                                for(i = 0; options[i].name; i++)
 
1017
                                {
 
1018
                                        printf("[-%c | --%-10s]: %s\n",
 
1019
                                                options[i].val, options[i].name, _(options_help[i]));
 
1020
                                }
 
1021
 
 
1022
                                return 0;
 
1023
                                break;
 
1024
                        case 'u':
 
1025
                                printf(_("Usage:\n"));
 
1026
                                printf("\tggz-config --install --modfile=<module.dsc> [--force]\n");
 
1027
                                printf("\tggz-config --remove --modfile=<module.dsc> [--force]\n");
 
1028
                                printf("\tggz-config --check\n");
 
1029
                                return 0;
 
1030
                                break;
 
1031
                        case 'm':
 
1032
                                modfile = optarg;
 
1033
                                break;
 
1034
                        case 'I':
 
1035
                                iconfile = optarg;
 
1036
                                break;
 
1037
                        case 'n':
 
1038
                                copydir = optarg;
 
1039
                                break;
 
1040
                        case 'f':
 
1041
                                modforce = 1;
 
1042
                                break;
 
1043
                        case 'D':
 
1044
                                moddest = 1;
 
1045
                                break;
 
1046
                        case 'i':
 
1047
                                install_mod = 1;
 
1048
                                break;
 
1049
                        case 'r':
 
1050
                                remove_mod = 1;
 
1051
                                break;
 
1052
                        case 'C':
 
1053
                                check_file = 1;
 
1054
                                break;
 
1055
                        case 'c':
 
1056
                                printf("%s\n", GGZCONFDIR);
 
1057
                                return 0;
 
1058
                                break;
 
1059
                        case 'g':
 
1060
                                printf("%s\n", GAMEDIR);
 
1061
                                return 0;
 
1062
                                break;
 
1063
                        case 'd':
 
1064
                                printf("%s\n", GGZDATADIR);
 
1065
                                return 0;
 
1066
                                break;
 
1067
                        case 'v':
 
1068
                                printf("%s\n", VERSION);
 
1069
                                return 0;
 
1070
                                break;
 
1071
                        case 'p':
 
1072
                                printf("%i\n", GGZ_CS_PROTO_VERSION);
 
1073
                                return 0;
 
1074
                                break;
 
1075
                        default:
 
1076
                                /*fprintf(stderr, _("Unknown command line option, try --help.\n"));*/
 
1077
                                return 1;
 
1078
                                break;
 
1079
                }
 
1080
        }
 
1081
 
 
1082
        /* Execute at least one operation (install or remove or check) */
 
1083
        if(install_mod + remove_mod + check_file != 1) {
 
1084
                fprintf(stderr, _("No operation specified, try --help.\n"));
 
1085
                return 1;
 
1086
        }
 
1087
 
 
1088
        if(check_file)
 
1089
                return check_module_file();
 
1090
 
 
1091
        if(modfile == NULL) {
 
1092
                if(copydir) {
 
1093
                        printf(_("Using auxiliary directory to proceed...\n"));
 
1094
                } else {
 
1095
                        fprintf(stderr, _("Must specify module installation file.\n"));
 
1096
                        return 1;
 
1097
                }
 
1098
        } else if(!load_modfile()) {
 
1099
                fprintf(stderr, _("Required installation file entries missing\n"));
 
1100
                return 1;
 
1101
        }
 
1102
 
 
1103
        if(moddest) {
 
1104
                destdir = getenv("DESTDIR");
 
1105
                if(destdir == NULL)
 
1106
                        moddest = 0;
 
1107
        }
 
1108
 
 
1109
        if(modfile) {
 
1110
                if(install_mod) {
 
1111
                        if(copydir) {
 
1112
                                rc = noregister_module();
 
1113
                        } else {
 
1114
                                rc = install_module();
 
1115
                        }
 
1116
                } else if(remove_mod)
 
1117
                        rc = remove_module();
 
1118
                else
 
1119
                        rc = -1;
 
1120
        } else {
 
1121
                        rc = noregister_all();
 
1122
        }
 
1123
 
 
1124
        return rc;
 
1125
}