4
* Project: GGZ Core Client Lib
6
* $Id: ggz-config.c 7712 2006-01-02 16:45:48Z josef $
8
* Configuration query and module install program.
10
* Copyright (C) 2001 Rich Gade.
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.
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.
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
28
# include <config.h> /* Site-specific config */
47
#define _(x) gettext(x)
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;
73
/* Command line options */
74
/* If they are changed make sure to edit the manpage! */
75
static struct option options[] =
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'},
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"),
116
static int load_modfile(void)
121
from = ggz_conf_parse(modfile, GGZ_CONF_RDONLY);
123
modname = ggz_conf_read_string(from, "ModuleInfo",
125
if(modname == NULL) {
126
fprintf(stderr, _("Critical: Module name not specified.\n"));
130
modversion = ggz_conf_read_string(from, "ModuleInfo",
132
if(modversion == NULL) {
133
fprintf(stderr, _("Critical: Module version not specified.\n"));
137
modexec = ggz_conf_read_string(from, "ModuleInfo",
138
"CommandLine", NULL);
139
if(modexec == NULL) {
140
fprintf(stderr, _("Critical: Executable not specified.\n"));
144
modui = ggz_conf_read_string(from, "ModuleInfo",
147
fprintf(stderr, _("Critical: User interface not specified.\n"));
151
modpengine = ggz_conf_read_string(from, "ModuleInfo",
152
"ProtocolEngine", NULL);
153
if(modpengine == NULL) {
154
fprintf(stderr, _("Critical: Protocol engine not specified.\n"));
158
modpversion = ggz_conf_read_string(from, "ModuleInfo",
159
"ProtocolVersion", NULL);
160
if(modpversion == NULL) {
161
fprintf(stderr, _("Critical: Protocol version not specified.\n"));
165
modauthor = ggz_conf_read_string(from, "ModuleInfo",
167
if(modauthor == NULL) {
168
fprintf(stderr, _("Critical: Module author not specified.\n"));
172
modurl = ggz_conf_read_string(from, "ModuleInfo",
175
fprintf(stderr, _("Warning: Module homepage not specified.\n"));
177
modenvironment = ggz_conf_read_string(from, "ModuleInfo",
178
"Environment", NULL);
179
/*if(modenvironment == NULL)
180
fprintf(stderr, _("Warning: Module environment not specified.\n"));*/
182
modicon = ggz_conf_read_string(from, "ModuleInfo",
184
modhelp = ggz_conf_read_string(from, "ModuleInfo",
191
static int purge_engine_name(int global)
197
ggz_conf_read_list(global, "Games", "*Engines*",
198
&items, &engine_list);
200
for(index=0; index<items; index++)
201
if(!strcmp(engine_list[index], modpengine))
205
engine_list[index] = engine_list[items-1];
209
ggz_conf_write_list(global, "Games", "*Engines*",
212
ggz_conf_remove_key(global, "Games", "*Engines*");
218
static char *new_engine_id(int global)
220
char **engine_list, **engine_id_list;
224
static char new_id[10];
226
ggz_conf_read_list(global, "Games", "*Engines*",
227
&engines, &engine_list);
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);
239
snprintf(new_id, 10, "p%d", hi+1);
245
static char *get_engine_id(int global)
249
char *engine_id=NULL;
250
char *author, *ui, *version;
253
ggz_conf_read_list(global, "Games", modpengine,
254
&items, &engine_list);
258
for(index=0; index<items; index++) {
259
engine_id = engine_list[index];
260
author = ggz_conf_read_string(global, engine_id,
262
ui = ggz_conf_read_string(global, engine_id,
264
managediconfile = ggz_conf_read_string(global, engine_id,
267
if((!author) || (!ui))
273
version = ggz_conf_read_string(global, engine_id,
275
if(!strcmp(author, modauthor) && !strcmp(ui, modui) &&
276
!strcmp(version, modversion))
278
} else if(!strcmp(author, modauthor) && !strcmp(ui, modui))
289
static void purge_engine_id(int global, char *engine_id)
295
ggz_conf_read_list(global, "Games", modpengine,
296
&items, &engine_list);
298
for(index=0; index<items; index++)
299
if(!strcmp(engine_list[index], engine_id))
303
engine_list[index] = engine_list[items-1];
307
ggz_conf_write_list(global, "Games", modpengine,
310
ggz_conf_remove_key(global, "Games", modpengine);
311
purge_engine_name(global);
316
static int open_conffile(void)
318
char *global_filename = "ggz.modules";
319
char global_pathname[(moddest ? strlen(destdir) : 0)
321
+ strlen(global_filename) + 3];
325
sprintf(global_pathname, "%s/%s/%s", destdir,
326
GGZCONFDIR, global_filename);
328
sprintf(global_pathname, "%s/%s", GGZCONFDIR, global_filename);
330
global = ggz_conf_parse(global_pathname, GGZ_CONF_RDONLY);
332
printf(_("Setting up GGZ game modules configuration in %s\n"), global_pathname);
334
global = ggz_conf_parse(global_pathname, GGZ_CONF_CREATE | GGZ_CONF_RDWR);
336
fprintf(stderr, _("Insufficient permission to install modules\n"));
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);
350
static int filecopy(const char *src, const char *dst)
355
fin = fopen(src, "r");
357
fprintf(stderr, _("File cannot be read (%s)\n"), src);
360
fout = fopen(dst, "w");
362
fprintf(stderr, _("File cannot be written to (%s)\n"), dst);
366
while((ch = fgetc(fin)) != EOF) {
376
static void handle_icon(void)
381
if(!iconfile) return;
382
/*modicon = modname;*/
384
while(strchr(modicon, '/')) {
385
modicon = strchr(modicon, '/') + 1;
389
char path[strlen(GGZDATADIR) + strlen(modicon) + 30];
391
strcpy(path, GGZDATADIR);
392
strcat(path, "/ggz-config/");
393
#ifdef MKDIR_TAKES_ONE_ARG
398
strcat(path, modicon);
399
ret = filecopy(iconfile, path);
400
if(ret != 0) modicon = NULL;
402
} else if(remove_mod) {
403
modicon = managediconfile;
404
if (modicon && modicon[0] != '/') {
405
char path[strlen(GGZDATADIR) + strlen(modicon) + 30];
407
strcpy(path, GGZDATADIR);
408
strcat(path, "/ggz-config/");
409
strcat(path, modicon);
416
static int remove_module(void)
421
if((global = open_conffile()) < 0)
424
engine_id = get_engine_id(global);
426
if(engine_id == NULL) {
427
fprintf(stderr, _("Warning: Tried to remove nonexistant module\n"));
434
rc = ggz_conf_remove_section(global, engine_id);
436
purge_engine_id(global, engine_id);
437
rc = ggz_conf_commit(global);
441
fprintf(stderr, _("ggz.modules configuration may be corrupt\n"));
442
fprintf(stderr, _("Module removal failed, see documentation\n"));
451
static int noregister_module(void)
453
char *suffix = ".module.dsc";
454
char global_pathname[(moddest ? strlen(destdir) : 0)
457
+ strlen(suffix) + 3];
458
char fixedmodname[strlen(modname) + 1];
462
sprintf(global_pathname, "%s/%s", destdir, copydir);
464
sprintf(global_pathname, "%s", copydir);
466
if (ggz_make_path(global_pathname) != 0) {
467
fprintf(stderr, _("Directory cannot be created (%s)\n"),
472
strcpy(fixedmodname, modname);
473
for(i = 0; i < strlen(fixedmodname); i++) {
474
if(fixedmodname[i] == '/') fixedmodname[i] = '_';
476
sprintf(global_pathname, "%s/%s%s", global_pathname, fixedmodname, suffix);
478
printf(_("Preserving %s as %s...\n"), modfile, global_pathname);
479
return filecopy(modfile, global_pathname);
483
static int install_module(void)
487
char *engine_id_list, *engine_list;
490
if((global = open_conffile()) < 0)
493
engine_id = get_engine_id(global);
495
if((engine_id) && (!strcmp(engine_id, "error")))
497
fprintf(stderr, _("Your configuration is broken - aborting\n"));
503
if(engine_id != NULL) {
504
fprintf(stderr, _("Cannot overwrite existing module\n"));
510
if(engine_id == NULL) {
511
engine_id = new_engine_id(global);
517
rc = ggz_conf_write_string(global, engine_id, "Name", modname);
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,
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,
534
ggz_conf_write_string(global, engine_id,
535
"Environment", modenvironment);
537
ggz_conf_write_string(global, engine_id,
538
"IconPath", modicon);
540
ggz_conf_write_string(global, engine_id,
541
"HelpPath", modhelp);
543
engine_id_list = ggz_conf_read_string(global, "Games",
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",
550
if(engine_list == NULL)
551
ggz_conf_write_string(global, "Games",
552
"*Engines*", modpengine);
554
snprintf(bigstr, 1024, "%s %s",
555
engine_list, modpengine);
556
ggz_conf_write_string(global, "Games",
557
"*Engines*", bigstr);
559
} else if(!modforce) {
560
snprintf(bigstr, 1024, "%s %s",
561
engine_id_list, engine_id);
562
ggz_conf_write_string(global, "Games",
566
rc = ggz_conf_commit(global);
570
fprintf(stderr, _("ggz.modules configuration may be corrupt\n"));
571
fprintf(stderr, _("Module installation failed, see documentation\n"));
580
static int noregister_all()
586
d = opendir(copydir);
588
fprintf(stderr, _("Could not open auxiliary directory\n"));
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;
597
modfile = (char*)ggz_malloc(strlen(copydir) + strlen(e->d_name) + 2);
598
sprintf(modfile, "%s/%s", copydir, e->d_name);
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();
613
fprintf(stderr, _("An error occured, which is ignored.\n"));
623
static int query(char *name, char *text, int def)
628
printf("\n%s: %s [%c] ", name, text, def == 1?'Y':'N');
629
fgets(buf, 3, stdin);
631
if(*buf == 'Y' || *buf == 'y')
634
if(*buf == 'N' || *buf == 'n')
643
static int check_module_file(void)
647
int e_count, s_count, k_count, g_count;
648
char **e_list, **s_list, **k_list, **g_list;
655
const char *reqd_keys[] = {
665
if((global = open_conffile()) < 0)
669
/* Check that every game engine section has req'd entries */
670
if((rc = ggz_conf_get_sections(global, &s_count, &s_list)) <0
672
printf(_("Error getting config file sections list\n"));
673
printf(_("May be an empty config file?\n"));
676
for(i=0; i<s_count; i++) {
677
if(!strcmp(s_list[i], "Games")) {
681
printf(_("*** Checking game config section [%s]\n"), s_list[i]);
683
for(j=0; reqd_keys[j]; j++) {
684
str = ggz_conf_read_string(global, s_list[i],
688
printf(_("ERR: missing required key '%s'\n"),
695
str = ggz_conf_read_string(global, s_list[i],
696
"CommandLine", NULL);
698
/* Without command line args */
700
while(*str2 && *str2 != ' ') str2++;
702
if(access(str, X_OK))
708
printf(_("ERR: missing or invalid executable\n"));
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]);
717
purge_engine_id(global, s_list[i]);
719
rc = ggz_conf_commit(global);
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"));
735
if((rc = ggz_conf_get_keys(global, "Games", &k_count, &k_list)) <0
737
printf(_("Error getting config file [Games]:keys list\n"));
738
printf(_("May be an empty config file?\n"));
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*"))
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++)
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;
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],
762
if(str2 && !strcmp(k_list[i], str2))
763
kill = section_refd[j]-1;
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++)
776
for(i=k; i<g_count; i++)
779
ggz_free(section_refd);
781
/* Restart the phase */
789
ggz_free(section_refd);
790
for(i=0; i<s_count; i++)
793
/* Since we made it through phase two, k_list hasn't */
794
/* changed, so we carry it over to 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*")) {
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++) {
810
str2 = ggz_conf_read_string(global, str, "ProtocolEngine", NULL);
811
if(str2 && strcmp(k_list[i], str2)) {
813
printf(_("ERR Setting ProtocolEngine key [%s] to '%s'\n"),
815
ggz_conf_write_string(global, str, "ProtocolEngine", k_list[i]);
818
if(str2) ggz_free(str2);
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"));
834
for(i=0; i<s_count; i++) {
835
if(!strcmp(s_list[i], "Games")) {
839
str = ggz_conf_read_string(global, s_list[i], "ProtocolEngine", NULL);
840
ggz_conf_read_list(global, "Games", str, &g_count, &g_list);
843
for(j = 0; j < g_count; j++) {
844
if(!strcmp(s_list[i], g_list[j])) {
851
printf(_("ERR Adding [Games]:%s key pointing to [%s]\n"),
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);
859
for(j = 0; j < g_count; j++) {
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"));
877
for(i = 0; i < k_count; i++) {
878
if(!strcmp(k_list[i], "*Engines*")) {
882
ggz_conf_read_list(global, "Games", k_list[i], &g_count, &g_list);
884
for(k = 0; k < g_count; k++) {
885
str = ggz_conf_read_string(global, g_list[k], "ProtocolEngine", NULL);
889
printf(_("ERR Section %s doesn't exist in %s, removed reference\n"),
890
g_list[k], k_list[i]);
895
g_list[k] = g_list[g_count];
896
ggz_conf_write_list(global, "Games", k_list[i], g_count, g_list);
898
ggz_conf_remove_key(global, "Games", k_list[i]);
903
for(k = 0; k < g_count; k++)
910
/* Check that each entry in *Engines* points to something */
911
printf(_("*** Checking for spurious game engine entries\n"));
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);
919
printf(_("ERR Game engine '%s' invalid, removing\n"),
925
e_list[i] = e_list[e_count];
926
ggz_conf_write_list(global, "Games", "*Engines*",
929
ggz_conf_remove_key(global, "Games", "*Engines*");
931
for(i=0; i<e_count; i++)
935
/*** Restart the phase ***/
940
/* e_list is still valid and used in next 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"));
950
for(i=0; i<k_count; i++) {
951
if(!strcmp(k_list[i], "*Engines*")) {
956
for(j=0; j<e_count; j++)
957
if(!strcmp(k_list[i], e_list[j]))
961
printf(_("ERR Adding '%s' to game engine list\n"),
964
e_list = ggz_realloc(e_list, e_count*sizeof(char *));
965
e_list[e_count-1] = ggz_strdup(k_list[i]);
970
if(k_list) ggz_free(k_list);
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)
976
if(e_list) ggz_free(e_list);
979
printf(_("Finished - writing %d repairs\n"), errs);
981
printf(_("Finished - no configuration errors detected\n"));
982
ggz_conf_commit(global);
989
int main(int argc, char *argv[])
996
/* Set up translation */
997
bindtextdomain("ggz-config", PREFIX "/share/locale");
998
textdomain("ggz-config");
999
setlocale(LC_ALL, "");
1001
/* Parse the command line options */
1004
opt = getopt_long(argc, argv, "cgdvpirCm:I:n:fDhu", options, &optindex);
1005
if(opt == -1) break;
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"));
1014
printf(_("Recognized options:\n"));
1016
for(i = 0; options[i].name; i++)
1018
printf("[-%c | --%-10s]: %s\n",
1019
options[i].val, options[i].name, _(options_help[i]));
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");
1056
printf("%s\n", GGZCONFDIR);
1060
printf("%s\n", GAMEDIR);
1064
printf("%s\n", GGZDATADIR);
1068
printf("%s\n", VERSION);
1072
printf("%i\n", GGZ_CS_PROTO_VERSION);
1076
/*fprintf(stderr, _("Unknown command line option, try --help.\n"));*/
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"));
1089
return check_module_file();
1091
if(modfile == NULL) {
1093
printf(_("Using auxiliary directory to proceed...\n"));
1095
fprintf(stderr, _("Must specify module installation file.\n"));
1098
} else if(!load_modfile()) {
1099
fprintf(stderr, _("Required installation file entries missing\n"));
1104
destdir = getenv("DESTDIR");
1112
rc = noregister_module();
1114
rc = install_module();
1116
} else if(remove_mod)
1117
rc = remove_module();
1121
rc = noregister_all();