1: /* getbbent.c - subroutines for accessing the BBoards file */
   2: 
   3: /* LINTLIBRARY */
   4: 
   5: #include "bboards.h"
   6: #ifndef MMDFONLY
   7: #include "../h/strings.h"
   8: #else   MMDFONLY
   9: #include "strings.h"
  10: #endif	MMDFONLY
  11: #include <ctype.h>
  12: #include <pwd.h>
  13: #include <grp.h>
  14: #include <stdio.h>
  15: #include <sys/types.h>
  16: #include <sys/stat.h>
  17: 
  18: 
  19: #define NOTOK   (-1)
  20: #define OK  0
  21: 
  22: 
  23: #define MaxBBAka    100
  24: #define MaxBBLdr    100
  25: #define MaxBBDist   100
  26: 
  27: #define COLON   ':'
  28: #define COMMA   ','
  29: #define NEWLINE '\n'
  30: 
  31: 
  32: #define ARCHIVE "archive"
  33: #define CNTFILE ".cnt"
  34: #define DSTFILE ".dist"
  35: #define MAPFILE ".map"
  36: 
  37: /*  */
  38: 
  39: static int  BBuid = -1;
  40: 
  41: static unsigned int  BBflags = SB_NULL;
  42: 
  43: static char BBName[BUFSIZ] = BBOARDS;
  44: static char BBDir[BUFSIZ] = "";
  45: static char BBData[BUFSIZ] = "";
  46: 
  47: static  FILE *BBfile = NULL;
  48: 
  49: 
  50: static struct bboard    BB;
  51: static struct bboard   *bb = &BB;
  52: 
  53: static int  BBload = 1;
  54: 
  55: static char BBFile[BUFSIZ];
  56: static char BBArchive[BUFSIZ];
  57: static char BBInfo[BUFSIZ];
  58: static char BBMap[BUFSIZ];
  59: static char *BBAkas[MaxBBAka];
  60: static char *BBLeaders[MaxBBLdr];
  61: static char *BBDists[MaxBBDist];
  62: static char BBAddr[BUFSIZ];
  63: static char BBRequest[BUFSIZ];
  64: static char BBDate[BUFSIZ];
  65: static char BBErrors[BUFSIZ];
  66: 
  67: 
  68: char   *bbskip (), *getcpy ();
  69: 
  70: char   *crypt (), *getpass ();
  71: struct group  *getgrnam ();
  72: struct passwd *getpwnam (), *getpwuid ();
  73: 
  74: /*  */
  75: 
  76: int     setbbfile (file, f)
  77: register char  *file;
  78: register int    f;
  79: {
  80:     if (BBuid == -1)
  81:     return setbbinfo (BBOARDS, file, f);
  82: 
  83:     (void) strcpy (BBData, file);
  84: 
  85:     BBflags = SB_NULL;
  86:     (void) endbbent ();
  87: 
  88:     return setbbent (f);
  89: }
  90: 
  91: /*  */
  92: 
  93: int setbbinfo (user, file, f)
  94: register char  *user,
  95:                *file;
  96: register int    f;
  97: {
  98:     register struct passwd *pw;
  99: 
 100:     if ((pw = getpwnam (user)) == NULL) {
 101:     (void) sprintf (BBErrors, "unknown user: %s", user);
 102:     return 0;
 103:     }
 104: 
 105:     return setpwinfo (pw, file, f);
 106: }
 107: 
 108: 
 109: int setpwinfo (pw, file, f)
 110: register struct passwd *pw;
 111: register char  *file;
 112: register int    f;
 113: {
 114:     if (!setpwaux (pw, file))
 115:     return 0;
 116: 
 117:     BBflags = SB_NULL;
 118:     (void) endbbent ();
 119: 
 120:     return setbbent (f);
 121: }
 122: 
 123: /*  */
 124: 
 125: static int  setbbaux (name, file)
 126: register char  *name,
 127:            *file;
 128: {
 129:     register struct passwd *pw;
 130: 
 131:     if ((pw = getpwnam (name)) == NULL) {
 132:     (void) sprintf (BBErrors, "unknown user: %s", name);
 133:     return 0;
 134:     }
 135: 
 136:     return setpwaux (pw, file);
 137: }
 138: 
 139: 
 140: static int  setpwaux (pw, file)
 141: register struct passwd *pw;
 142: register char  *file;
 143: {
 144:     (void) strcpy (BBName, pw -> pw_name);
 145:     BBuid = pw -> pw_uid;
 146:     (void) strcpy (BBDir, pw -> pw_dir);
 147:     (void) sprintf (BBData, "%s/%s",
 148:         *file != '/' ? BBDir : "",
 149:         *file != '/' ? file : file + 1);
 150: 
 151:     BBflags = SB_NULL;
 152: 
 153:     return 1;
 154: }
 155: 
 156: /*  */
 157: 
 158: int     setbbent (f)
 159: register int     f;
 160: {
 161:     if (BBfile == NULL) {
 162:     if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
 163:         return 0;
 164: 
 165:     if ((BBfile = fopen (BBData, "r")) == NULL) {
 166:         (void) sprintf (BBErrors, "unable to open: %s", BBData);
 167:         return 0;
 168:     }
 169:     }
 170:     else
 171:     rewind (BBfile);
 172: 
 173:     BBflags |= f;
 174:     return (BBfile != NULL);
 175: }
 176: 
 177: 
 178: int     endbbent () {
 179:     if (BBfile != NULL && !(BBflags & SB_STAY)) {
 180:     (void) fclose (BBfile);
 181:     BBfile = NULL;
 182:     }
 183: 
 184:     return 1;
 185: }
 186: 
 187: 
 188: long    getbbtime () {
 189:     struct stat st;
 190: 
 191:     if (BBfile == NULL) {
 192:     if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
 193:         return 0;
 194: 
 195:     if (stat (BBData, &st) == NOTOK) {
 196:         (void) sprintf (BBErrors, "unable to stat: %s", BBData);
 197:         return 0;
 198:     }
 199:     }
 200:     else
 201:     if (fstat (fileno (BBfile), &st) == NOTOK) {
 202:         (void) sprintf (BBErrors, "unable to fstat: %s", BBData);
 203:         return 0;
 204:     }
 205: 
 206:     return ((long) st.st_mtime);
 207: }
 208: 
 209: /*  */
 210: 
 211: struct bboard  *getbbent () {
 212:     register char  *p,
 213:                    *q,
 214:                    *r,
 215:                    *d,
 216:                    *f,
 217:                   **s;
 218:     static char line[BUFSIZ];
 219: 
 220:     if (BBfile == NULL && !setbbent (SB_NULL))
 221:     return NULL;
 222: 
 223:     if ((p = fgets (line, sizeof line, BBfile)) == NULL)
 224:     return NULL;
 225: 
 226:     bb -> bb_name = p;
 227:     p = q = bbskip (p, COLON);
 228:     p = bb -> bb_file = bbskip (p, COLON);
 229:     bb -> bb_archive = bb -> bb_info = bb -> bb_map = "";
 230:     p = bb -> bb_passwd = bbskip (p, COLON);
 231:     p = r = bbskip (p, COLON);
 232:     p = bb -> bb_addr = bbskip (p, COLON);
 233:     p = bb -> bb_request = bbskip (p, COLON);
 234:     p = bb -> bb_relay = bbskip (p, COLON);
 235:     p = d = bbskip (p, COLON);
 236:     p = f = bbskip (p, COLON);
 237:     (void) bbskip (p, NEWLINE);
 238: 
 239:     s = bb -> bb_aka = BBAkas;
 240:     while (*q) {
 241:     *s++ = q;
 242:     q = bbskip (q, COMMA);
 243:     }
 244:     *s = NULL;
 245: 
 246:     s = bb -> bb_leader = BBLeaders;
 247:     if (*r == NULL) {
 248:     if (!(BBflags & SB_FAST))
 249:         *s++ = BBName;
 250:     }
 251:     else
 252:     while (*r) {
 253:         *s++ = r;
 254:         r = bbskip (r, COMMA);
 255:     }
 256:     *s = NULL;
 257: 
 258:     s = bb -> bb_dist = BBDists;
 259:     while (*d) {
 260:     *s++ = d;
 261:     d = bbskip (d, COMMA);
 262:     }
 263:     *s = NULL;
 264: 
 265:     if (*f)
 266:     (void) sscanf (f, "%o", &bb -> bb_flags);
 267:     else
 268:     bb -> bb_flags = BB_NULL;
 269:     bb -> bb_count = bb -> bb_maxima = 0;
 270:     bb -> bb_date = NULL;
 271:     bb -> bb_next = bb -> bb_link = bb -> bb_chain = NULL;
 272: 
 273:     if (BBload)
 274:     BBread ();
 275: 
 276:     return bb;
 277: }
 278: 
 279: /*  */
 280: 
 281: struct bboard  *getbbnam (name)
 282: register char   *name;
 283: {
 284:     register struct bboard *b = NULL;
 285: 
 286:     if (!setbbent (SB_NULL))
 287:     return NULL;
 288:     BBload = 0;
 289:     while ((b = getbbent ()) && strcmp (name, b -> bb_name))
 290:     continue;
 291:     BBload = 1;
 292:     (void) endbbent ();
 293: 
 294:     if (b != NULL)
 295:     BBread ();
 296: 
 297:     return b;
 298: }
 299: 
 300: 
 301: struct bboard  *getbbaka (aka)
 302: register char   *aka;
 303: {
 304:     register char **ap;
 305:     register struct bboard *b = NULL;
 306: 
 307:     if (!setbbent (SB_NULL))
 308:     return NULL;
 309:     BBload = 0;
 310:     while ((b = getbbent ()) != NULL)
 311:     for (ap = b -> bb_aka; *ap; ap++)
 312:         if (strcmp (aka, *ap) == 0)
 313:         goto hit;
 314: hit: ;
 315:     BBload = 1;
 316:     (void) endbbent ();
 317: 
 318:     if (b != NULL)
 319:     BBread ();
 320: 
 321:     return b;
 322: }
 323: 
 324: /*  */
 325: 
 326: static int  BBread () {
 327:     register int    i;
 328:     register char  *cp,
 329:                    *dp,
 330:            *p,
 331:            *r;
 332:     char    prf[BUFSIZ];
 333:     static char line[BUFSIZ];
 334:     register    FILE * info;
 335: 
 336:     if (BBflags & SB_FAST)
 337:     return;
 338: 
 339:     p = index (bb -> bb_request, '@');
 340:     r = index (bb -> bb_addr, '@');
 341:     BBRequest[0] = NULL;
 342: 
 343:     if (*bb -> bb_request == '-')
 344:     if (p == NULL && r && *r == '@')
 345:         (void) sprintf (BBRequest, "%s%s%s",
 346:             bb -> bb_name, bb -> bb_request, r);
 347:     else
 348:         (void) sprintf (BBRequest, "%s%s",
 349:             bb -> bb_name, bb -> bb_request);
 350:     else
 351:     if (p == NULL && r && *r == '@' && *bb -> bb_request)
 352:         (void) sprintf (BBRequest, "%s%s", bb -> bb_request, r);
 353: 
 354:     if (BBRequest[0])
 355:     bb -> bb_request = BBRequest;
 356:     else
 357:     if (*bb -> bb_request == NULL)
 358:         bb -> bb_request = *bb -> bb_addr ? bb -> bb_addr
 359:         : bb -> bb_leader[0];
 360: 
 361:     if (*bb -> bb_addr == '@') {
 362:     (void) sprintf (BBAddr, "%s%s", bb -> bb_name, bb -> bb_addr);
 363:     bb -> bb_addr = BBAddr;
 364:     }
 365:     else
 366:     if (*bb -> bb_addr == NULL)
 367:         bb -> bb_addr = bb -> bb_name;
 368: 
 369:     if (*bb -> bb_file == NULL)
 370:     return;
 371:     if (*bb -> bb_file != '/') {
 372:     (void) sprintf (BBFile, "%s/%s", BBDir, bb -> bb_file);
 373:     bb -> bb_file = BBFile;
 374:     }
 375: 
 376:     if ((cp = rindex (bb -> bb_file, '/')) == NULL || *++cp == NULL)
 377:     (void) strcpy (prf, ""), cp = bb -> bb_file;
 378:     else
 379:     (void) sprintf (prf, "%.*s", cp - bb -> bb_file, bb -> bb_file);
 380:     if ((dp = index (cp, '.')) == NULL)
 381:     dp = cp + strlen (cp);
 382: 
 383:     (void) sprintf (BBArchive, "%s%s/%s", prf, ARCHIVE, cp);
 384:     bb -> bb_archive = BBArchive;
 385:     (void) sprintf (BBInfo, "%s.%.*s%s", prf, dp - cp, cp, CNTFILE);
 386:     bb -> bb_info = BBInfo;
 387:     (void) sprintf (BBMap, "%s.%.*s%s", prf, dp - cp, cp, MAPFILE);
 388:     bb -> bb_map = BBMap;
 389: 
 390:     if ((info = fopen (bb -> bb_info, "r")) == NULL)
 391:     return;
 392: 
 393:     if (fgets (line, sizeof line, info) && (i = atoi (line)) > 0)
 394:     bb -> bb_maxima = (unsigned) i;
 395:     if (!feof (info) && fgets (line, sizeof line, info)) {
 396:     (void) strcpy (BBDate, line);
 397:     if (cp = index (BBDate, NEWLINE))
 398:         *cp = NULL;
 399:     bb -> bb_date = BBDate;
 400:     }
 401: 
 402:     (void) fclose (info);
 403: }
 404: 
 405: /*  */
 406: 
 407: int     ldrbb (b)
 408: register struct bboard  *b;
 409: {
 410:     register char  *p,
 411:                   **q,
 412:                   **r;
 413:     static int  uid = 0,
 414:                 gid = 0;
 415:     static char username[10] = "";
 416:     register struct passwd *pw;
 417:     register struct group  *gr;
 418: 
 419:     if (b == NULL)
 420:     return 0;
 421:     if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
 422:     return 0;
 423: 
 424:     if (username[0] == NULL) {
 425:     if ((pw = getpwuid (uid = getuid ())) == NULL)
 426:         return 0;
 427:     gid = getgid ();
 428:     (void) strcpy (username, pw -> pw_name);
 429:     }
 430: 
 431:     if (uid == BBuid)
 432:     return 1;
 433: 
 434:     q = b -> bb_leader;
 435:     while (p = *q++)
 436:     if (*p == '=') {
 437:         if ((gr = getgrnam (++p)) == NULL)
 438:         continue;
 439:         if (gid == gr -> gr_gid)
 440:         return 1;
 441:         r = gr -> gr_mem;
 442:         while (p = *r++)
 443:         if (strcmp (username, p) == 0)
 444:             return 1;
 445:     }
 446:     else
 447:         if (strcmp (username, p) == 0)
 448:         return 1;
 449: 
 450:     return 0;
 451: }
 452: 
 453: /*  */
 454: 
 455: int     ldrchk (b)
 456: register struct bboard  *b;
 457: {
 458:     if (b == NULL)
 459:     return 0;
 460: 
 461:     if (*b -> bb_passwd == NULL)
 462:     return 1;
 463: 
 464:     if (strcmp (b -> bb_passwd,
 465:         crypt (getpass ("Password: "), b -> bb_passwd)) == 0)
 466:     return 1;
 467: 
 468:     fprintf (stderr, "Sorry\n");
 469:     return 0;
 470: }
 471: 
 472: /*  */
 473: 
 474: struct bboard  *getbbcpy (bp)
 475: register struct bboard  *bp;
 476: {
 477:     register char **p,
 478:                   **q;
 479:     register struct bboard *b;
 480: 
 481:     if (bp == NULL)
 482:     return NULL;
 483: 
 484:     b = (struct bboard *) malloc ((unsigned) sizeof *b);
 485:     if (b == NULL)
 486:     return NULL;
 487: 
 488:     b -> bb_name = getcpy (bp -> bb_name);
 489:     b -> bb_file = getcpy (bp -> bb_file);
 490:     b -> bb_archive = getcpy (bp -> bb_archive);
 491:     b -> bb_info = getcpy (bp -> bb_info);
 492:     b -> bb_map = getcpy (bp -> bb_map);
 493:     b -> bb_passwd = getcpy (bp -> bb_passwd);
 494:     b -> bb_flags = bp -> bb_flags;
 495:     b -> bb_count = bp -> bb_count;
 496:     b -> bb_maxima = bp -> bb_maxima;
 497:     b -> bb_date = getcpy (bp -> bb_date);
 498:     b -> bb_addr = getcpy (bp -> bb_addr);
 499:     b -> bb_request = getcpy (bp -> bb_request);
 500:     b -> bb_relay = getcpy (bp -> bb_relay);
 501: 
 502:     for (p = bp -> bb_aka; *p; p++)
 503:     continue;
 504:     b -> bb_aka =
 505:     q = (char **) calloc ((unsigned) (p - bp -> bb_aka + 1), sizeof *q);
 506:     if (q == NULL)
 507:     return NULL;
 508:     for (p = bp -> bb_aka; *p; *q++ = getcpy (*p++))
 509:     continue;
 510:     *q = NULL;
 511: 
 512:     for (p = bp -> bb_leader; *p; p++)
 513:     continue;
 514:     b -> bb_leader =
 515:     q = (char **) calloc ((unsigned) (p - bp -> bb_leader + 1), sizeof *q);
 516:     if (q == NULL)
 517:     return NULL;
 518:     for (p = bp -> bb_leader; *p; *q++ = getcpy (*p++))
 519:     continue;
 520:     *q = NULL;
 521: 
 522:     for (p = bp -> bb_dist; *p; p++)
 523:     continue;
 524:     b -> bb_dist =
 525:     q = (char **) calloc ((unsigned) (p - bp -> bb_dist + 1), sizeof *q);
 526:     if (q == NULL)
 527:     return NULL;
 528:     for (p = bp -> bb_dist; *p; *q++ = getcpy (*p++))
 529:     continue;
 530:     *q = NULL;
 531: 
 532:     b -> bb_next = bp -> bb_next;
 533:     b -> bb_link = bp -> bb_link;
 534:     b -> bb_chain = bp -> bb_chain;
 535: 
 536:     return b;
 537: }
 538: 
 539: /*  */
 540: 
 541: int     getbbdist (bb, action)
 542: register struct bboard  *bb;
 543: register int     (*action) ();
 544: {
 545:     register int    result;
 546:     register char **dp;
 547: 
 548:     BBErrors[0] = NULL;
 549:     for (dp = bb -> bb_dist; *dp; dp++)
 550:     if (result = getbbitem (bb, *dp, action))
 551:         return result;
 552: 
 553:     return result;
 554: }
 555: 
 556: char    *getbberr () {
 557:     return (BBErrors[0] ? BBErrors : NULL);
 558: };
 559: 
 560: /*  */
 561: 
 562: static int  getbbitem (bb, item, action)
 563: register struct bboard  *bb;
 564: register char   *item;
 565: register int     (*action) ();
 566: {
 567:     register int    result;
 568:     register char  *cp,
 569:                    *dp,
 570:                    *hp,
 571:                    *np;
 572:     char    mbox[BUFSIZ],
 573:             buffer[BUFSIZ],
 574:             file[BUFSIZ],
 575:             host[BUFSIZ],
 576:             prf[BUFSIZ];
 577:     register FILE *fp;
 578: 
 579:     switch (*item) {
 580:     case '*':
 581:         switch (*++item) {
 582:         case '/':
 583:             hp = item;
 584:             break;
 585: 
 586:         case NULL:
 587:             if ((cp = rindex (bb -> bb_file, '/')) == NULL || *++cp == NULL)
 588:             (void) strcpy (prf, ""), cp = bb -> bb_file;
 589:             else
 590:             (void) sprintf (prf, "%.*s", cp - bb -> bb_file, bb -> bb_file);
 591:             if ((dp = index (cp, '.')) == NULL)
 592:             dp = cp + strlen (cp);
 593:             (void) sprintf (file, "%s.%.*s%s", prf, dp - cp, cp, DSTFILE);
 594:             hp = file;
 595:             break;
 596: 
 597:         default:
 598:             (void) sprintf (file, "%s/%s", BBDir, item);
 599:             hp = file;
 600:             break;
 601:         }
 602: 
 603:         if ((fp = fopen (hp, "r")) == NULL)
 604:         return bblose ("unable to read file %s", hp);
 605:         while (fgets (buffer, sizeof buffer, fp)) {
 606:         if (np = index (buffer, '\n'))
 607:             *np = NULL;
 608:         if (result = getbbitem (bb, buffer, action)) {
 609:             (void) fclose (fp);
 610:             (void) bblose ("error with file %s, item %s", hp, buffer);
 611:             return result;
 612:         }
 613:         }
 614:         (void) fclose (fp);
 615:         return OK;
 616: 
 617:     default:
 618:         if (hp = rindex (item, '@')) {
 619:         *hp++ = NULL;
 620:         (void) strcpy (mbox, item);
 621:         (void) strcpy (host, hp);
 622:         *--hp = '@';
 623:         }
 624:         else {
 625:         (void) sprintf (mbox, "%s%s", DISTADR, bb -> bb_name);
 626:         (void) strcpy (host, item);
 627:         }
 628:         if (result = (*action) (mbox, host))
 629:         (void) bblose ("action (%s, %s) returned 0%o", mbox, host, result);
 630:         return result;
 631:     }
 632: }
 633: 
 634: /*  */
 635: 
 636: /* VARARGS1 */
 637: 
 638: static int  bblose (fmt, a, b, c)
 639: char   *fmt,
 640:        *a,
 641:        *b,
 642:        *c;
 643: {
 644:     if (BBErrors[0] == NULL)
 645:     (void) sprintf (BBErrors, fmt, a, b, c);
 646: 
 647:     return NOTOK;
 648: }
 649: 
 650: /*  */
 651: 
 652: void    make_lower (s1, s2)
 653: register char   *s1,
 654:         *s2;
 655: {
 656:     if (s1 == NULL || s2 == NULL)
 657:     return;
 658: 
 659:     for (; *s2; s2++)
 660:     *s1++ = isupper (*s2) ? tolower (*s2) : *s2;
 661:     *s1 = NULL;
 662: }
 663: 
 664: /*  */
 665: 
 666: static char *bbskip (p, c)
 667: register char  *p,
 668:         c;
 669: {
 670:     if (p == NULL)
 671:     return NULL;
 672: 
 673:     while (*p && *p != c)
 674:     p++;
 675:     if (*p)
 676:     *p++ = NULL;
 677: 
 678:     return p;
 679: }
 680: 
 681: 
 682: static  char   *getcpy (s)
 683: register char   *s;
 684: {
 685:     register char  *p;
 686: 
 687:     if (s == NULL)
 688:     return NULL;
 689: 
 690:     if (p = malloc ((unsigned) (strlen (s) + 1)))
 691:     (void) strcpy (p, s);
 692:     return p;
 693: }

Defined functions

BBread defined in line 326; used 3 times
bblose defined in line 638; used 3 times
bbskip defined in line 666; used 14 times
endbbent defined in line 178; used 5 times
getbbent defined in line 211; used 3 times
getbbitem defined in line 562; used 2 times
getcpy defined in line 682; used 14 times
setbbaux defined in line 125; used 3 times
setbbinfo defined in line 93; used 2 times
setpwaux defined in line 140; used 2 times
setpwinfo defined in line 109; used 2 times

Defined variables

BB defined in line 50; used 1 times
  • in line 51
BBAddr defined in line 62; used 2 times
BBAkas defined in line 59; used 1 times
BBArchive defined in line 56; used 2 times
BBData defined in line 45; used 7 times
BBDate defined in line 64; used 3 times
BBDir defined in line 44; used 4 times
BBDists defined in line 61; used 1 times
BBErrors defined in line 65; used 10 times
BBFile defined in line 55; used 2 times
BBInfo defined in line 57; used 2 times
BBLeaders defined in line 60; used 1 times
BBMap defined in line 58; used 2 times
BBName defined in line 43; used 2 times
BBRequest defined in line 63; used 6 times
BBflags defined in line 41; used 7 times
BBload defined in line 53; used 5 times
BBuid defined in line 39; used 6 times
bb defined in line 51; used 69 times

Defined macros

ARCHIVE defined in line 32; used 1 times
CNTFILE defined in line 33; used 1 times
COLON defined in line 27; used 9 times
COMMA defined in line 28; used 3 times
DSTFILE defined in line 34; used 1 times
MAPFILE defined in line 35; used 1 times
MaxBBAka defined in line 23; used 1 times
  • in line 59
MaxBBDist defined in line 25; used 1 times
  • in line 61
MaxBBLdr defined in line 24; used 1 times
  • in line 60
NEWLINE defined in line 29; used 2 times
NOTOK defined in line 19; used 3 times
OK defined in line 20; used 1 times
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3087
Valid CSS Valid XHTML 1.0 Strict