1 | /*
2 | * $Log: users.c,v $
3 | * Revision 1.12 2003/02/28 20:16:47 nzmb
4 | * Changed the name of resignation ratio to CD ratio, to avoid confusion with
5 | * Doug Massey's DRR.
6 | *
7 | * Revision 1.11 2002/11/24 23:22:23 millis
8 | * Removed unused function "checklist"
9 | *
10 | * Revision 1.10 2002/11/08 21:59:26 millis
11 | * Fixed bug 36, to check if player is really blacklisted or simply trying
12 | * on a restricted judge
13 | *
14 | * Revision 1.9 2002/08/27 22:27:58 millis
15 | * Updated for automake/autoconf functionality
16 | *
17 | * Revision 1.8 2002/06/23 22:56:29 nzmb
18 | * Cosmetic change to infoplayer/getdedication display.
19 | *
20 | * Revision 1.7 2001/12/29 20:38:04 nzmb
21 | *
22 | * Added infoplayer, record commands. Put judge version to 1.0.0 as we think it is
23 | * stable.
24 | *
25 | * Revision 1.6 2001/07/15 09:20:56 greg
26 | * added support for game directories in a sub directory
27 | *
28 | * Revision 1.5 2001/06/24 06:08:18 nzmb
29 | * Added code so players may now see their plyrdata records via the "get
30 | * dedication" command.
31 | *
32 | * Revision 1.4 2001/05/08 07:47:47 greg
33 | * minor fix to allow whogame command by players after a gunboat game ends, unless it's noreveal
34 | *
35 | * Revision 1.3 2001/01/06 18:20:42 davidn
36 | * Correction to parsing of players.DENY to only read lines with = at the
37 | * start. This stops it reading lines which are commented out.
38 | *
39 | * Revision 1.2 2000/11/14 14:27:37 miller
40 | * Minor changes only
41 | *
42 | * Revision 1.1 1998/02/28 17:49:42 david
43 | * Initial revision
44 | *
45 | * Revision 1.1 1996/10/20 12:29:45 rpaar
46 | * Morrolan v9.0
47 | */
48 |
49 | /* users.c
50 | * Copyright 1989, Lowe.
51 | *
52 | * Diplomacy is a trademark of the Avalon Hill Game Company, Baltimore,
53 | * Maryland, all rights reserved; used with permission.
54 | *
55 | * Redistribution and use in source and binary forms are permitted
56 | * provided that it is for non-profit purposes, that this and the
57 | * above notices are preserved and that due credit is given to Mr.
58 | * Lowe.
59 | */
60 |
61 | #include <stdio.h>
62 | #include <stdlib.h>
63 | #include <string.h>
64 | #include <sys/stat.h>
65 |
66 | #include "config.h"
67 | #include "dip.h"
68 | #include "mail.h"
69 | #include "functions.h"
70 | #include "plyrdata.h"
71 |
72 | /* Max. number of lines in which necessary information must appear */
73 |
74 | #define MAXLINE 30
75 |
76 | /* Defines for registration commands */
77 |
78 | #define PHONE 1
79 | #define EMAIL 2
80 | #define SITE 3
81 | #define LEVEL 4
82 | #define USER 5
83 | #define COUNTRY 6
84 | #define _PACKAGE 7
85 |
86 | /* Defines for "Package:" options */
87 |
88 | #define DFT_SEND 0 /* Default: check for Package.Autosend file */
89 | #define SEND 1 /* Definitely send the package */
90 | #define NO_SEND 2 /* Definitely don't send the package */
91 |
92 | /*
93 | * Keep track of a database of users for Diplomacy.
94 | */
95 |
96 | /*
97 | * newuser(addr). Add or replace an entry to the user database. More
98 | * user information is on the input file until an "end" command is found.
99 | */
100 |
101 | int newuser(char *addr, FILE * fp)
102 | {
103 |
104 | int i, j, k, n, userid, siteid, level, got, sded = nded, new_entry,
105 | send_pkg = DFT_SEND;
106 | char *s, *t;
107 | char line[1024], *lines[MAXLINE], *lookfor();
108 | char *phone = NULL, *mail = NULL, *site = NULL, *country = NULL,
109 | *not_eof;
110 | FILE *fp1, *fp2;
111 | struct stat sbuf;
112 |
113 | static char *keys[] =
114 | {"", "phone:", "email:", "e-mail:", "site:", "level:",
115 | "user:", "country:", "package:"};
116 | static int vals[] =
117 | {0, PHONE, EMAIL, EMAIL, SITE, LEVEL, USER, COUNTRY,
118 | _PACKAGE};
119 |
120 | static char *levs[] =
121 | {"", "novice", "advanced", "intermediate",
122 | "amateur", "expert", "winner"};
123 | static int lval[] =
124 | {L_AMATEUR, L_NOVICE, L_ADVANCED, L_INTERMEDIATE,
125 | L_AMATEUR, L_EXPERT, L_WINNER};
126 | static char *pkgs[] =
127 | {"", "yes", "send", "no", "don't send", "don't"};
128 | /* TODO
129 | * pval is unused... unlike most it looks important, so i'm leaving it
130 | * in, but commented out -- nw Sat Jun 7 22:18:24 GMT 1997
131 | */
132 | /* static int pval[] = {DFT_SEND, SEND, SEND, NO_SEND, NO_SEND, NO_SEND}; */
133 | n = got = level = 0;
134 | while ((not_eof = fgets(line, sizeof(line), fp))) {
135 | fputs(line, log_fp);
136 | fputs(line, ifp);
137 | if (!strchr(line, ':')) {
138 | not_eof = NULL;
139 | break;
140 | }
141 | if (!(lines[n++] = (char *) malloc(strlen(line) + 1))) {
142 | fprintf(rfp, "Unable to malloc space in newuser.\n");
143 | return E_FATAL;
144 | }
145 | strcpy(lines[n - 1], line);
146 | s = lookfor(lines[n - 1], keys, nentry(keys), &i);
147 | switch (vals[i]) {
148 | case PHONE:
149 | got |= 1;
150 | phone = s;
151 | break;
152 |
153 | case COUNTRY:
154 | got |= 16;
155 | country = s;
156 | break;
157 |
158 | case EMAIL:
159 | got |= 2;
160 | mail = s;
161 | break;
162 |
163 | case SITE:
164 | got |= 4;
165 | site = s;
166 | break;
167 |
168 | case LEVEL:
169 | got |= 8;
170 | lookfor(s, levs, nentry(levs), &i);
171 | if (!i)
172 | fprintf(rfp, "Unrecognized level specified, assuming %s.\n",
173 | levs[lval[i]]);
174 | level = lval[i];
175 | break;
176 |
177 | case USER:
178 | free(lines[--n]); /* Don't save 'User:' line */
179 | break;
180 |
181 | case _PACKAGE:
182 | printf("found package: %s\n", s);
183 | lookfor(s, pkgs, nentry(pkgs), &send_pkg);
184 | free(lines[--n]); /* Don't save 'Package:' line */
185 | break;
186 | }
187 | if ((n >= MAXLINE) || (got == (1 | 2 | 4 | 8 | 16)))
188 | break;
189 | }
190 |
191 | if ((got & (1 | 2 | 4 | 16)) != (1 | 2 | 4 | 16)) {
192 | fprintf(rfp, "Your phone number, email addresses, country and the ");
193 | fprintf(rfp, "name of your site must\n");
194 | fprintf(rfp, "appear within the first %d lines of the registration ", MAXLINE);
195 | fprintf(rfp, "data and you must supply\n");
196 | fprintf(rfp, "a colon following the keyword on each line.\n");
197 | return E_WARN;
198 | }
199 | if (!(fp1 = fopen("dip.addr", "r"))) {
200 | perror("addresses");
201 | fprintf(rfp, "Unable to open addresses.\n");
202 | return E_FATAL;
203 | }
204 | userid = 1;
205 | while ((s = fgets(line, sizeof(line), fp1))) {
206 | i = atoi(line + 1);
207 | if (i >= userid)
208 | userid = i + 1;
209 | s = strchr(line, '=');
210 | if (!s) {
211 | fprintf(rfp, "Address data is corrupted.\n");
212 | return E_FATAL;
213 | }
214 | s++;
215 | if (cmpaddr(s, addr))
216 | break;
217 | if (cmpaddr(s, mail))
218 | break;
219 | }
220 | fclose(fp1);
221 |
222 | /*
223 | * Set the site code based on the phone number.
224 | */
225 |
226 | if (s) {
227 | new_entry = 0;
228 | sscanf(line + 1, "%d %d", &userid, &siteid);
229 | } else {
230 | new_entry = 1;
231 | s = phone;
232 | while (*s && !isdigit(*s))
233 | s++;
234 | siteid = atoi(s) * 100;
235 | }
236 |
237 | /*
238 | * Attempt to get a better site code based on the country.
239 | */
240 |
241 | if (country) {
242 | while (isspace(*country))
243 | country++;
244 | s = country + strlen(country) - 1;
245 | while (isspace(*s))
246 | *s-- = '\0';
247 | i = -1;
248 | if ((fp1 = fopen("data/countries.x", "r"))) {
249 | while (fgets(line, sizeof(line), fp1)) {
250 | if ((s = strchr(line, ':'))) {
251 | *s++ = '\0';
252 | if (!strcasecmp(country, line)) {
253 | if ((i = atoi(s)))
254 | siteid = i * 100;
255 | break;
256 | }
257 | }
258 | }
259 | fclose(fp1);
260 | }
261 | if (i == -1) {
262 | fprintf(xfp, "Unknown country name: [%s].\n", country);
263 | }
264 | strcat(country, "\n");
265 | }
266 | /* if the siteid is 0, don't process the registration. */
267 | if (!siteid) {
268 | fprintf(rfp, "Your Site ID resolved to a 0. Please verify your phone ");
269 | fprintf(rfp, "number and your country.\nIf you think there is a problem ");
270 | fprintf(rfp, "on the judge's end, please contact the JK (%s).\n", GAMES_MASTER);
271 | return E_WARN;
272 | }
273 | if (userid >= MAXUSER) {
274 | fprintf(rfp, "Too many people registered. Increase MAXUSER.\n");
275 | return E_FATAL;
276 | }
277 | /*
278 | * Build a new whois database. Check for other people at this site.
279 | */
280 |
281 | if (!(fp1 = fopen("dip.whois", "r"))) {
282 | perror("whois");
283 | fprintf(rfp, "Unable to open whois database.\n");
284 | return E_FATAL;
285 | }
286 | if (!(fp2 = fopen("dip.whois.new", "w"))) {
287 | perror("whois.new");
288 | fprintf(rfp, "Unable to create whois database.\n");
289 | return E_FATAL;
290 | }
291 | while (fgets(line, sizeof(line), fp1)) {
292 | if (!strncmp(line, "User:", 5)) {
293 | sscanf(line + 5, "%d%d%d", &i, &j, &k);
294 | if (i >= sded) {
295 | if (i > MAXUSER - 1 || i < 0) {
296 | fprintf(rfp, "Whois database corrupted. Bad userid.\n");
297 | return E_FATAL;
298 | }
299 | if (i >= nded)
300 | nded = i + 1;
301 | ded[i].r = k;
302 | }
303 | if (i == userid) {
304 | while ((s = fgets(line, sizeof(line), fp1)) && strncmp(line, "User:", 5));
305 | if (!s)
306 | break;
307 | sscanf(line + 5, "%d%d%d", &i, &j, &k);
308 | if (i >= sded) {
309 | if (i > MAXUSER - 1 || i < 0) {
310 | fprintf(rfp, "Whois database corrupted. Bad userid.\n");
311 | return E_FATAL;
312 | }
313 | if (i >= nded)
314 | nded = i + 1;
315 | ded[i].r = k;
316 | }
317 | }
318 | }
319 | if (!strncasecmp(line, "Site:", 5)) {
320 | for (s = line + 5; isspace(*s); s++);
321 | if (!strcasecmp(s, site))
322 | siteid = j;
323 | }
324 | fputs(line, fp2);
325 | }
326 | fclose(fp1);
327 |
328 | fprintf(xfp, "Registration request processed:\n");
329 |
330 | fprintf(xfp, "User: %4d %d %d\n", userid, siteid, ded[userid].r);
331 | fprintf(fp2, "User: %4d %d %d\n", userid, siteid, ded[userid].r);
332 | for (i = 0; i < n; i++) {
333 | fputs(lines[i], xfp);
334 | fputs(lines[i], fp2);
335 | }
336 |
337 | while ((not_eof = fgets(line, sizeof(line), fp))) {
338 | fputs(line, log_fp);
339 | fputs(line, ifp);
340 | if (!strchr(line, ':'))
341 | break;
342 | s = lookfor(line, keys, nentry(keys), &i);
343 | switch (i) {
344 | case USER:
345 | /* Ignore 'User:' if entered */
346 | break;
347 |
348 | case _PACKAGE:
349 | lookfor(s, pkgs, nentry(pkgs), &send_pkg);
350 | /* Don't write 'Package:' to dip.whois file */
351 | break;
352 |
353 | default:
354 | fputs(line, xfp);
355 | fputs(line, fp2);
356 | }
357 | }
358 |
359 | for (s = line; isspace(*s); s++);
360 | if (*s && strncasecmp("end", line, 3)) {
361 | fprintf(rfp, "Warning, end of registration command not found.\n");
362 | fprintf(rfp, "Discarding: %s", s);
363 | }
364 | fprintf(xfp, "\n");
365 |
366 | ferrck(fp2, 4001);
367 | fclose(fp2);
368 |
369 | /*
370 | * Rebuild the addresses file.
371 | */
372 |
373 | if (!(fp1 = fopen("dip.addr", "r"))) {
374 | perror("addresses");
375 | fprintf(rfp, "Unable to open address file.\n");
376 | return E_FATAL;
377 | }
378 | if (!(fp2 = fopen("dip.addr.new", "w"))) {
379 | perror("address.new");
380 | fprintf(rfp, "Unable to create new address file.\n");
381 | return E_FATAL;
382 | }
383 | while (fgets(line, sizeof(line), fp1)) {
384 | if (atoi(line + 1) == userid) {
385 | if (*line != '+')
386 | continue;
387 | s = strchr(line, '=');
388 | if (!s) {
389 | fprintf(rfp, "Address data is corrupted.\n");
390 | return E_FATAL;
391 | }
392 | s++;
393 | if (cmpaddr(s, addr))
394 | continue;
395 | if (cmpaddr(s, mail))
396 | continue;
397 | }
398 | fputs(line, fp2);
399 | }
400 | fprintf(fp2, "+%d %d %d =%s\n", userid, siteid, level, addr);
401 | s = mail;
402 | while (*s) {
403 | t = s;
404 | while (*t && !isspace(*t) && *t != ',')
405 | t++;
406 | if (*t)
407 | *t++ = '\0';
408 | fprintf(fp2, "*%d %d %d =%s\n", userid, siteid, level, s);
409 | s = t;
410 | while (isspace(*s))
411 | s++;
412 | }
413 | fclose(fp1);
414 | ferrck(fp2, 4002);
415 | fclose(fp2);
416 |
417 | /*
418 | * Rename the files and get rid of excess baggage.
419 | */
420 |
421 | rename("dip.whois.new", "dip.whois");
422 | rename("dip.addr.new", "dip.addr");
423 | for (i = 0; i < n; i++)
424 | free(lines[i]);
425 |
426 | /*
427 | * If this is a new registration, check whether to send the package.
428 | */
429 |
430 | if (new_entry) {
431 | if ((send_pkg == SEND) ||
432 | ((send_pkg == DFT_SEND) && !stat("Package.Autosend", &sbuf))) {
433 | fprintf(rfp, "Newuser package being sent separately.\n");
434 | send_package(addr);
435 | } else {
436 | fprintf(rfp, "Newuser package is not being sent. To get it, send ");
437 | fprintf(rfp, "'get package' to the Judge.\n");
438 | }
439 | } else {
440 | fprintf(rfp, "This is an update to an existing registration; newuser ");
441 | fprintf(rfp, "package is not sent.\n");
442 | fprintf(rfp, "To get it, send 'get package' to the Judge.\n");
443 | }
444 |
445 | fprintf(rfp, "Registration processed.\n");
446 |
447 | return 0;
448 |
449 | }
450 |
451 | /***************************************************************************/
452 |
453 | /*
454 | * Send Newuser Package of Files (upon registration, or upon request)
455 | */
456 |
457 | void send_package(char *addr)
458 | {
459 | char line[150], cmd[150], *eol;
460 | FILE *pfp;
461 | struct stat sbuf;
462 |
463 | if (!(pfp = fopen("data/package", "r"))) {
464 | fprintf(rfp, "Package list is not available. Please request individual ");
465 | fprintf(rfp, "files separately.\n");
466 | } else {
467 | while (fgets(line, sizeof(line), pfp)) {
468 | for (eol = line; *eol && !isspace(*eol); ++eol);
469 | *eol = '\0';
470 | if (stat(line, &sbuf)) {
471 | fprintf(rfp, "Package file %s is not available.\n", line);
472 | } else {
473 | sprintf(cmd, "%s %s 'Diplomacy file %s' '%s'", SMAIL_CMD,line, line, addr);
474 | execute(cmd);
475 | fprintf(rfp, "Package file %s sent.\n", line);
476 | }
477 | }
478 | fclose(pfp);
479 | fprintf(rfp, "\nPackage send completed.\n");
480 | }
481 | return;
482 | }
483 |
484 | /***************************************************************************/
485 |
486 | /*
487 | * I am Also: Add a new entry to the addresses file.
488 | */
489 |
490 | int iamalso(char *addr, char *oldaddr)
491 | {
492 |
493 | int userid, siteid, level;
494 | char *s, line[200];
495 | FILE *fp1, *fp2;
496 |
497 | if (!(fp1 = fopen("dip.addr", "r"))) {
498 | perror("address");
499 | bailout(1);
500 | }
501 | if (!(fp2 = fopen("dip.addr.new", "w"))) {
502 | perror("address.new");
503 | bailout(1);
504 | }
505 | userid = 0;
506 | while (fgets(line, sizeof(line), fp1)) {
507 | s = strchr(line, '=');
508 | if (s && !strcasecmp(s + 1, addr)) {
509 | fprintf(rfp, "IamAlso ignored, %s already registered.\n", addr);
510 | fclose(fp1);
511 | fclose(fp2);
512 | remove("dip.addr.new");
513 | return 0;
514 | }
515 | if (s && cmpaddr(s + 1, oldaddr))
516 | sscanf(line + 1, "%d %d %d", &userid, &siteid, &level);
517 | fputs(line, fp2);
518 | }
519 |
520 | if (!userid) {
521 | fprintf(rfp, "IamAlso %sAddress not found as registered.\n", oldaddr);
522 | fclose(fp1);
523 | fclose(fp2);
524 | remove("dip.addr.new");
525 | return 1;
526 | }
527 | fprintf(rfp, "%s registered as user #%d.\n", addr, userid);
528 | fprintf(xfp, "%s registered as user #%d.\n", addr, userid);
529 | fprintf(fp2, "+%d %d %d =%s\n", userid, siteid, level, addr);
530 | fclose(fp1);
531 | ferrck(fp2, 4003);
532 | fclose(fp2);
533 | rename("dip.addr.new", "dip.addr");
534 | return 0;
535 |
536 | }
537 |
538 | /***************************************************************************/
539 |
540 | /*
541 | * Get user: search the database to find the user and site ids.
542 | */
543 |
544 | int getuser(char *addr, int *userid, int *siteid, int *level)
545 | {
546 |
547 | char *s, line[200];
548 | FILE *fp;
549 |
550 | if (!(fp = fopen("dip.addr", "r"))) {
551 | perror("address");
552 | bailout(1);
553 | }
554 | while (fgets(line, sizeof(line), fp)) {
555 | s = strchr(line, '=');
556 | if (s && cmpaddr(s + 1, addr)) {
557 | sscanf(line + 1, "%d %d %d", userid, siteid, level);
558 | return 1;
559 | }
560 | }
561 | return 0;
562 | }
563 |
564 |
565 | /***************************************************************************/
566 |
567 | /*
568 | * Whogame: search dip.master for a game, and whois the players.
569 | */
570 |
571 | void whogame(int f)
572 | {
573 | int x;
574 |
575 | if ((dipent.flags & F_GUNBOAT)
576 | && (!signedon || dipent.players[player].power != MASTER)
577 | && (dipent.phase[6] != 'X'))
578 | fprintf(rfp, "Game '%s' is a gunboat game.\n", dipent.name);
579 | else
580 | if ((dipent.flags & F_GUNBOAT) && (dipent.flags & F_NOREVEAL)
581 | && (!signedon || dipent.players[player].power != MASTER))
582 | fprintf(rfp, "Game '%s' is a gunboat noreveal game.\n", dipent.name);
583 | else
584 | for (x = 0; x < dipent.n; x++)
585 | if (dipent.players[x].power < 0)
586 | continue;
587 | else if (!f && (dipent.players[x].power == AUTONOMOUS ||
588 | dipent.players[x].power == OBSERVER))
589 | continue;
590 | else {
591 | fprintf(rfp, "%s in game '%s':\n\n",
592 | powers[dipent.players[x].power], dipent.name);
593 | if (!strcmp(dipent.players[x].address, "*"))
594 | fprintf(rfp, "%s is abandoned. Address unknown.\n\n",
595 | powers[dipent.players[x].power]);
596 | else
597 | whois(dipent.players[x].address);
598 | }
599 | putc('\n', rfp);
600 | return;
601 | }
602 |
603 | /***************************************************************************/
604 |
605 | /*
606 | * Whois: dump user info to the reply file.
607 | */
608 |
609 | void whois(char *t)
610 | {
611 |
612 | int users[MAXUSER], user, i, n = 0, len;
613 | char *s, *p, *q, line[200];
614 | FILE *fp;
615 |
616 | if (!*t) {
617 | fprintf(rfp, "Who is whom?\n\n");
618 | return;
619 | }
620 | fprintf(rfp, "Whois %s", t);
621 | if (!(fp = fopen("dip.addr", "r"))) {
622 | fprintf(rfp, "Whois: can't open address file.\n\n");
623 | } else {
624 | n = 0;
625 | while (fgets(line, sizeof(line), fp)) {
626 | user = atoi(line + 1);
627 | for (i = 0; i < n; i++)
628 | if (user == users[i])
629 | break;
630 | if (i < n)
631 | continue;
632 | if (!(s = strchr(line, '=')))
633 | continue;
634 | p = t;
635 | while (*p) {
636 | for (len = 0, q = p; *q && !isspace(*q); q++, len++);
637 | if (!strncasecmp(s + 1, p, len)) {
638 | users[n++] = user;
639 | break;
640 | }
641 | p = q;
642 | while (isspace(*p))
643 | p++;
644 | }
645 | if (n >= MAXUSER)
646 | break;
647 | }
648 | fclose(fp);
649 | }
650 |
651 | if (!n) {
652 | fprintf(rfp, "No matching Email addresses found.\n\n");
653 | } else {
654 | if (!(fp = fopen("dip.whois", "r"))) {
655 | fprintf(rfp, "Whois: can't open whois file.\n\n");
656 | } else {
657 | i = 0;
658 | while (fgets(line, sizeof(line), fp)) {
659 | if (!strncasecmp(line, "User:", 5)) {
660 | user = atoi(line + 5);
661 | for (i = 0; i < n; i++)
662 | if (user == users[i])
663 | break;
664 | if (i < n) {
665 | putc('\n', rfp);
666 | }
667 | }
668 | if (i < n)
669 | fputs(line, rfp);
670 | }
671 | putc('\n', rfp);
672 | fclose(fp);
673 | }
674 | }
675 | }
676 |
677 | /***************************************************************************/
678 |
679 | /*
680 | * send_dedication: Send the user's current dedication
681 | */
682 |
683 | int send_dedication(char *raddr)
684 | {
685 | int userid, siteid, level;
686 | float orat,rrat;
687 |
688 | if (!getuser(raddr, &userid, &siteid, &level)) {
689 | if (!msg_header_done)
690 | msg_header(rfp);
691 | fprintf(rfp,
692 | "The address %s is not registered with the judge.\n",
693 | raddr);
694 | fprintf(rfp,
695 | "Use a 'get form' request for information on registering.\n");
696 | return E_WARN;
697 | }
698 | fprintf(rfp, "User ID: %d\n\n", userid);
699 | fprintf(rfp, "Current dedication: %d\n", ded[userid].r);
700 | fprintf(rfp, "Turns ontime: %lu\n",get_data(userid,ontime));
701 | fprintf(rfp, "Turns total: %lu\n",get_data(userid,total));
702 | fprintf(rfp, "Games started: %lu\nPositions taken over: %lu\n",
703 | get_data(userid,started),get_data(userid,tookover));
704 | fprintf(rfp, "Resignations: %lu\n",get_data(userid,resigned));
705 | if(get_data(userid,total) == 0)
706 | {
707 | fprintf(rfp, "Played 0 turns; a perfect timeliness record.\n");
708 | }
709 | else
710 | {
711 | orat = 1.0 * get_data(userid,ontime)/get_data(userid,total);
712 | fprintf(rfp, "Ontime ratio: %.3f\n", orat);
713 | }
714 | if(get_data(userid,started) == 0 && get_data(userid,tookover) == 0)
715 | {
716 | fprintf(rfp, "No started games; perfect resignation record.\n\n");
717 | }
718 | else
719 | {
720 | rrat = 1.0 * get_data(userid,resigned) / (get_data(userid,started) + get_data(userid,tookover));
721 | fprintf(rfp, "CD ratio: %.3f\n\n", rrat);
722 | }
723 | /* TODO i'm not sure what to return here, was no return at all -- nw */
724 | return 0;
725 | }
726 |
727 | /* DEDICATION CODE, WILL BE ACTIVE IN THE FUTURE */
728 | /* Contact Travis C. Ruelle (ruelle@isp.nwu.edu) for details */
729 |
730 | /***************************************************************************/
731 |
732 | /* TODO figure out what we wanted to do here. the next two functions
733 | * were commented out, i changed that to an #if out */
734 |
735 | #if 0
736 | /*
737 | * Getded: Dump dedication information to a reply file.
738 | */
739 |
740 | getded(t)
741 | char *t;
742 | {
743 | fprintf(rfp, "getded: Dedicate %s\n\n", t);
744 | }
745 |
746 |
747 | /****************************************************************************/
748 |
749 | /*
750 | * Dedgame: search dip.master for a game, and dedicate the players
751 | */
752 |
753 | dedgame(int f)
754 | {
755 | int x;
756 |
757 | if ((dipent.flags & F_GUNBOAT)
758 | && (!signedon || dipent.players[player].power != MASTER))
759 | fprintf(rfp, "Game '%s' is a gunboat game.\n", dipent.name);
760 | else
761 | for (x = 0; x < dipent.n; x++)
762 | if (dipent.players[x].power < 0)
763 | continue;
764 | else if (!f && (dipent.players[x].power == WILD_PLAYER ||
765 | dipent.players[x].power == AUTONOMOUS ||
766 | dipent.players[x].power == OBSERVER))
767 | continue;
768 | else {
769 | fprintf(rfp, "%s in game '%s':\n\n",
770 | powers[dipent.players[x].power], dipent.name);
771 | getded(dipent.players[x].address);
772 | }
773 | putc('\n', rfp);
774 | return;
775 | }
776 |
777 | #endif
778 |
779 |
780 | /***************************************************************************/
781 |
782 | /*
783 | * Set a particular site code to a non-generic one.
784 | */
785 |
786 | int setsite(char *s)
787 | {
788 | int i, j, k, n = 0, siteid, userid, users[MAXUSER], sded = nded;
789 | char *t, line[1024];
790 | FILE *fp1, *fp2, *fp3;
791 |
792 |
793 | if ((siteid = atoi(s))) {
794 | while (isdigit(*s))
795 | s++;
796 | while (isspace(*s))
797 | s++;
798 | fprintf(rfp, "Setting siteid to %d for %s", siteid, s);
799 |
800 | /*
801 | * First run through and figure out which users we're talking about.
802 | */
803 |
804 | if (!(fp1 = fopen("dip.whois", "r"))) {
805 | perror("whois");
806 | bailout(1);
807 | }
808 | n = 0;
809 | while (fgets(line, sizeof(line), fp1)) {
810 | if (!strncasecmp(line, "User:", 5))
811 | userid = atoi(line + 5);
812 | else if (!strncasecmp(line, "Site:", 5)) {
813 | for (t = line + 5; isspace(*t); t++);
814 | if (!strcasecmp(t, s)) {
815 | if (n >= MAXUSER) {
816 | fprintf(rfp, "Can't change siteid, too many users.\n");
817 | return 0;
818 | }
819 | users[n++] = userid;
820 | }
821 | }
822 | }
823 |
824 | /*
825 | * Then copy the file while changing their site id.
826 | */
827 |
828 | rewind(fp1);
829 | if (!(fp2 = fopen("dip.whois.new", "w"))) {
830 | perror("whois.new");
831 | bailout(1);
832 | }
833 | while (fgets(line, sizeof(line), fp1)) {
834 | if (!strncasecmp(line, "User:", 5)) {
835 | sscanf(line + 5, "%d%d%d", &userid, &j, &k);
836 | if (userid >= sded) {
837 | if (userid > MAXUSER - 1 || userid < 0) {
838 | fprintf(rfp, "Whois database corrupted. Bad userid: %s", line);
839 | return E_FATAL;
840 | }
841 | if (userid >= nded)
842 | nded = userid + 1;
843 | ded[userid].r = k;
844 | }
845 | for (i = 0; i < n; i++) {
846 | if (userid == users[i]) {
847 | j = siteid;
848 | break;
849 | }
850 | }
851 | fprintf(fp2, "User: %4d %d %d\n", userid, j, ded[userid].r);
852 | continue;
853 | }
854 | fputs(line, fp2);
855 | }
856 |
857 | fclose(fp1);
858 | ferrck(fp2, 4004);
859 | fclose(fp2);
860 |
861 | /*
862 | * Then copy the addresses file.
863 | */
864 |
865 | if (!(fp1 = fopen("dip.addr", "r"))) {
866 | perror("addresses");
867 | bailout(1);
868 | }
869 | if (!(fp2 = fopen("dip.addr.new", "w+"))) {
870 | perror("address.new");
871 | bailout(1);
872 | }
873 | while (fgets(line, sizeof(line), fp1)) {
874 | userid = atoi(line + 1);
875 | for (i = 0; i < n; i++)
876 | if (userid == users[i])
877 | break;
878 | if (i != n) {
879 | t = line + 1;
880 | while (isdigit(*t))
881 | t++; /* Skip over userid */
882 | while (isspace(*t))
883 | t++;
884 | while (isdigit(*t))
885 | t++; /* Skip over siteid */
886 | fprintf(fp2, "%c%d %d%s", *line, userid, siteid, t);
887 | fprintf(rfp, "%c%d %d%s", *line, userid, siteid, t);
888 | continue;
889 | }
890 | fputs(line, fp2);
891 | }
892 |
893 | fclose(fp1);
894 | ferrck(fp2, 4005);
895 | fflush(fp2);
896 | fp3 = fp2;
897 |
898 | rename("dip.whois.new", "dip.whois");
899 | rename("dip.addr.new", "dip.addr");
900 |
901 | } else {
902 | if (!(fp3 = fopen("dip.addr", "r"))) {
903 | perror("addresses");
904 | bailout(1);
905 | }
906 | }
907 |
908 | /*
909 | * Then fix up the master file.
910 | */
911 |
912 | if (!(fp1 = fopen(MASTER_FILE, "r"))) {
913 | perror(MASTER_FILE);
914 | bailout(1);
915 | }
916 | if (!(fp2 = fopen(TMASTER_FILE, "w"))) {
917 | perror(TMASTER_FILE);
918 | bailout(1);
919 | }
920 | while (getdipent(fp1)) {
921 | for (i = 0; i < dipent.n; i++) {
922 | if (!dipent.players[i].userid) {
923 | rewind(fp3);
924 | while (fgets(line, sizeof(line), fp3)) {
925 | t = strchr(line, '=') + 1;
926 | if (cmpaddr(dipent.players[i].address, t)) {
927 | sscanf(line + 1, "%d%d", &dipent.players[i].userid,
928 | &dipent.players[i].siteid);
929 | fprintf(rfp, "Setting userid for %s in '%s' to %d, %s.\n",
930 | powers[dipent.players[i].power], dipent.name,
931 | dipent.players[i].userid, dipent.players[i].address);
932 | break;
933 | }
934 | }
935 | }
936 | for (j = 0; j < n; j++)
937 | if (dipent.players[i].userid == users[j])
938 | break;
939 | if (j != n) {
940 | dipent.players[i].siteid = siteid;
941 | fprintf(rfp, "Setting siteid for %s in '%s' to %d, %s.\n",
942 | powers[dipent.players[i].power], dipent.name,
943 | dipent.players[i].siteid, dipent.players[i].address);
944 | }
945 | }
946 | putdipent(fp2, 1);
947 | }
948 |
949 | fclose(fp1);
950 | ferrck(fp2, 4006);
951 | fclose(fp2);
952 | fclose(fp3);
953 | rename(TMASTER_FILE, MASTER_FILE);
954 |
955 | /* TODO check this return value. there was no return at all originally,
956 | * but there is a return of zero above on what appears to be an error
957 | * of some kind. so i figured that returning one here would be safe.
958 | * -- nw Sat Jun 7 22:29:58 GMT 1997 */
959 |
960 | return 1;
961 | }
962 |
963 | /***************************************************************************
964 | *
965 | * ALLOW/DENY Functionality
966 | * Jan 1995: Larry Richardson
967 | *
968 | **************************************************************************/
969 |
970 | /*
971 | * is_allowed( int type_flag )
972 | * where: type_flag = GLOBAL_PLAYER - global player list
973 | * = GLOBAL_MASTER - global master list
974 | * = GAME_PLAYER - game-specific player list
975 | * = GAME_MASTER - included for completeness, not
976 | * used
977 | * returns: TRUE - player is allowed at the level specified
978 | * FALSE - player is NOT allowed at the level specified
979 | */
980 | #define ALLOW ".ALLOW"
981 | #define DENY ".DENY"
982 |
983 | int is_allowed(int type_flag)
984 | {
985 | char fname[40], uname[40];
986 | int ret_val = 1;
987 | FILE *fp;
988 |
989 | switch (type_flag) {
990 | case GLOBAL_MASTER:
991 | strcpy(fname, "masters");
992 | break;
993 | case GAME_PLAYER:
994 | if (strlen(dipent.name) == 0) {
995 | perror("nogame");
996 | return 0;
997 | }
998 | sprintf(fname, "%s%s/players", GAME_DIR, dipent.name);
999 | break;
1000 | case GAME_MASTER:
1001 | if (strlen(dipent.name) == 0) {
1002 | perror("nogame");
1003 | return 0;
1004 | }
1005 | sprintf(fname, "%s%s/masters", GAME_DIR, dipent.name);
1006 | break;
1007 | case GLOBAL_PLAYER:
1008 | default:
1009 | strcpy(fname, "players");
1010 | break;
1011 | }
1012 | /* Pass #1. Look for a file named fname.ALLOW. If it exists, check to see
1013 | if the name is in there and set the return value accordingly. */
1014 | sprintf(uname, "%s%s", fname, ALLOW);
1015 | fp = fopen(uname, "r");
1016 | if (fp != (FILE *) NULL) {
1017 | ret_val = new_checklist(fp, raddr);
1018 | fclose(fp);
1019 | }
1020 | /* Pass #2. Look for a file named fname.DENY. If it exists, check to see
1021 | if the name is in there and set the return value accordingly. */
1022 | else {
1023 | sprintf(uname, "%s%s", fname, DENY);
1024 | fp = fopen(uname, "r");
1025 | if (fp != (FILE *) NULL) {
1026 | ret_val = !new_checklist(fp, raddr);
1027 | fclose(fp);
1028 | }
1029 | }
1030 |
1031 | /* Pass #3. If neither the .ALLOW or the .DENY file exists, it must be ok,
1032 | so set the return value, and return. */
1033 | return ret_val;
1034 | }
1035 |
1036 | /*
1037 | * is_disallowed( int type_flag )
1038 | * where: type_flag = GLOBAL_PLAYER - global player list
1039 | * = GLOBAL_MASTER - global master list
1040 | * = GAME_PLAYER - game-specific player list
1041 | * = GAME_MASTER - included for completeness, not
1042 | * used
1043 | * returns: TRUE - player is specifically denied at the level specified
1044 | * FALSE - player is NOT specifically denied (but may still not be allowed)
1045 | *
1046 | * Note: This function should only be called after calling is_allowed() to deterimine
1047 | * why player is not allowed
1048 | */
1049 |
1050 | int is_disallowed(int type_flag)
1051 | {
1052 | char fname[40], uname[40];
1053 | int ret_val = 0;
1054 | FILE *fp;
1055 |
1056 | switch (type_flag) {
1057 | case GLOBAL_MASTER:
1058 | strcpy(fname, "masters");
1059 | break;
1060 | case GAME_PLAYER:
1061 | if (strlen(dipent.name) == 0) {
1062 | perror("nogame");
1063 | return 0;
1064 | }
1065 | sprintf(fname, "%s%s/players", GAME_DIR, dipent.name);
1066 | break;
1067 | case GAME_MASTER:
1068 | if (strlen(dipent.name) == 0) {
1069 | perror("nogame");
1070 | return 0;
1071 | }
1072 | sprintf(fname, "%s%s/masters", GAME_DIR, dipent.name);
1073 | break;
1074 | case GLOBAL_PLAYER:
1075 | default:
1076 | strcpy(fname, "players");
1077 | break;
1078 | }
1079 | /* Pass #1. Look for a file named fname.DENY. If it exists, check to see
1080 | if the name is in there and set the return value accordingly. */
1081 | {
1082 | sprintf(uname, "%s%s", fname, DENY);
1083 | fp = fopen(uname, "r");
1084 | if (fp != (FILE *) NULL) {
1085 | ret_val = new_checklist(fp, raddr);
1086 | fclose(fp);
1087 | }
1088 | }
1089 |
1090 | /* Pass #2. If not in .DENY file, player is not banned
1091 | so set the return value, and return. */
1092 | return ret_val;
1093 | }
1094 |
1095 | /*
1096 | * new_checklist: See if the user's name is in the passed file
1097 | *
1098 | * new_checklist( FILE *fp, char *raddr )
1099 | * where: fp - the file pointer to use
1100 | * raddr - the addres to look up
1101 | *
1102 | * returns: TRUE if the address is in the file
1103 | * FALSE if the address is NOT in the file
1104 | */
1105 |
1106 | int new_checklist(FILE * fp, char *addr)
1107 | {
1108 | char *s, line[200];
1109 |
1110 | while (fgets(line, sizeof(line), fp)) {
1111 | if (*(s = line) != '=')
1112 | continue;
1113 | if (cmpaddr(s + 1, addr))
1114 | return 1;
1115 | }
1116 | return 0;
1117 | }
1118 |
1119 | /*
1120 | * add_player: Add/Remove a player's name to one of the ALLOW/DENY files
1121 | *
1122 | * add_player( char *name, char *file, char addflag )
1123 | * where: name - the name to be added/removed
1124 | * file - the file to be operated on
1125 | * addflag - = 0, remove the name
1126 | * = 1, add the name
1127 | *
1128 | * returns: None.
1129 | */
1130 |
1131 | void add_player(char *player_name, char *file, char addflag)
1132 | {
1133 | char line[200], *s;
1134 | FILE *in_fp, *out_fp;
1135 |
1136 | if (addflag) {
1137 | /* First, check that this player isn't already in the file. */
1138 | in_fp = fopen(file, "r");
1139 | if ((in_fp != (FILE *) NULL) &&
1140 | new_checklist(in_fp, player_name)) {
1141 | fprintf(rfp, "Player %s is already in the %s file",
1142 | player_name, file);
1143 | if (!strcmp(dipent.name, "control"))
1144 | fprintf(rfp, ".\n");
1145 | else
1146 | fprintf(rfp, "\nfor Game '%s'.\n",
1147 | dipent.name);
1148 | } else {
1149 | /* S/He isn't, so go ahead and add him/her. */
1150 | if (in_fp != (FILE *) NULL)
1151 | fclose(in_fp);
1152 | in_fp = fopen(file, "a");
1153 | fprintf(in_fp, "=%s\n", player_name);
1154 |
1155 | fprintf(rfp, "Player %s is now in the %s file",
1156 | player_name, file);
1157 | if (!strcmp(dipent.name, "control"))
1158 | fprintf(rfp, ".\n");
1159 | else
1160 | fprintf(rfp, "\nfor Game '%s'.\n",
1161 | dipent.name);
1162 | }
1163 | fclose(in_fp);
1164 | } else {
1165 | /* First, check that this player is already in the file. */
1166 | in_fp = fopen(file, "r");
1167 | if ((in_fp == (FILE *) NULL) ||
1168 | !new_checklist(in_fp, player_name)) {
1169 | if (in_fp != (FILE *) NULL)
1170 | fclose(in_fp);
1171 | fprintf(rfp, "Player %s is not in the %s file",
1172 | player_name, file);
1173 | if (!strcmp(dipent.name, "control"))
1174 | fprintf(rfp, ".\n");
1175 | else
1176 | fprintf(rfp, "\nfor Game '%s'.\n",
1177 | dipent.name);
1178 | } else {
1179 | struct stat file_stat;
1180 |
1181 | rewind(in_fp);
1182 | out_fp = fopen("dip.allowdeny", "w");
1183 | while (fgets(line, sizeof(line), in_fp)) {
1184 | s = strchr(line, '=');
1185 | if (s == 0)
1186 | continue;
1187 | if (!cmpaddr(s + 1, player_name))
1188 | fputs(line, out_fp);
1189 | }
1190 | fclose(out_fp);
1191 | fclose(in_fp);
1192 |
1193 | /* Move the temporary file to the real file after
1194 | saving the original file. */
1195 | sprintf(line, "%s.bak", file);
1196 | rename(file, line);
1197 | rename("dip.allowdeny", file);
1198 |
1199 | fprintf(rfp, "Player %s is no longer in the %s file",
1200 | player_name, file);
1201 | if (!strcmp(dipent.name, "control"))
1202 | fprintf(rfp, ".\n");
1203 | else
1204 | fprintf(rfp, "\nfor Game '%s'.\n",
1205 | dipent.name);
1206 |
1207 | /* As a last step, see if the file is empty,
1208 | if it is, remove it. */
1209 | if (!stat(file, &file_stat)) {
1210 | if (!file_stat.st_size)
1211 | remove(file);
1212 | }
1213 | }
1214 | }
1215 | }
1216 |
1217 | /***************************************************************************/
1218 |
1219 | /*
1220 | * Compare an address to see if it's one we've got.
1221 | */
1222 |
1223 | int cmpaddr(char *addr, char *list)
1224 | {
1225 |
1226 | register char *s, *t, c = 0, d = 0, k;
1227 |
1228 | s = list;
1229 | while (*s) {
1230 | t = addr;
1231 | k = 0;
1232 | while (*t) {
1233 | c = *s++;
1234 | d = *t++;
1235 | if (islower(c))
1236 | c = toupper(c);
1237 | if (islower(d))
1238 | d = toupper(d);
1239 | if (c == '%' || c == '@' || c == '.')
1240 | c = ++k;
1241 | if (d == '%' || d == '@' || d == '.')
1242 | d = k;
1243 | if (c != d)
1244 | break;
1245 | }
1246 | if (c == d)
1247 | return 1;
1248 | if (!c || isspace(c) || c == ',')
1249 | c = 0;
1250 | if (!d || isspace(d) || d == ',')
1251 | d = 0;
1252 | if ((!c && !d) ||
1253 | (!c && d == k && k > 1) ||
1254 | (!d && c == k && k > 1)) {
1255 | return 1;
1256 | }
1257 | while (*s && *s++ != ',');
1258 | while (isspace(*s))
1259 | s++;
1260 | }
1261 | return 0;
1262 | }