1: #ifndef lint 2: static char *sccsid = "@(#)misc.c 1.25 (Berkeley) 2/6/88"; 3: #endif 4: 5: #include "../common/conf.h" 6: 7: #include "common.h" 8: 9: /* 10: * open_valid_art -- determine if a given article name is valid; 11: * if it is, return a file pointer to the open article, 12: * along with a unique id of the article. 13: * 14: * Parameters: "artname" is a string containing the 15: * name of the article. 16: * "id" is space for us to put the article 17: * id in. 18: * 19: * Returns: File pointer to the open article if the 20: * article is valid; NULL otherwise 21: * 22: * Side effects: None. 23: */ 24: 25: FILE * 26: open_valid_art(artname, id) 27: char *artname; 28: char *id; 29: { 30: static int crnt_art_num; 31: static char crnt_art_id[MAXBUFLEN]; 32: int fd; 33: struct stat statbuf; 34: 35: if (art_fp != NULL) { 36: if (crnt_art_num == atoi(artname)) { 37: if (fseek(art_fp, (long) 0, 0) < 0) 38: close_crnt(); 39: else { 40: (void) strcpy(id, crnt_art_id); 41: return (art_fp); 42: } 43: } else 44: close_crnt(); 45: } 46: 47: art_fp = fopen(artname, "r"); 48: 49: if (art_fp == NULL) 50: return (NULL); 51: 52: fd = fileno(art_fp); 53: 54: if (fstat(fd, &statbuf) < 0) { 55: close_crnt(); 56: return (NULL); 57: } 58: 59: if ((statbuf.st_mode & S_IFREG) != S_IFREG) { 60: close_crnt(); 61: return (NULL); 62: } 63: 64: get_id(art_fp, id); 65: (void) strcpy(crnt_art_id, id); 66: crnt_art_num = atoi(artname); 67: return (art_fp); 68: } 69: 70: 71: /* 72: * gethistent -- return the path name of an article if it's 73: * in the history file. 74: * 75: * Parameters: "msg_id" is the message ID of the 76: * article, enclosed in <>'s. 77: * 78: * Returns: A char pointer to a static data area 79: * containing the full pathname of the 80: * article, or NULL if the message-id is not 81: * in thef history file. 82: * 83: * Side effects: opens dbm database 84: * (only once, keeps it open after that). 85: * Converts "msg_id" to lower case. 86: */ 87: 88: #ifndef NDBM 89: # ifndef DBM 90: # ifndef USGHIST 91: # define USGHIST 92: # endif not USGHIST 93: # endif not DBM 94: #endif not DBM 95: 96: char * 97: gethistent(msg_id) 98: char *msg_id; 99: { 100: char line[MAXBUFLEN]; 101: char *tmp; 102: register char *cp; 103: long ltmp; 104: static char path[MAXPATHLEN]; 105: #ifdef USGHIST 106: char *histfile(); 107: register int len; 108: #else not USGHIST 109: #ifdef DBM 110: static int dbopen = 0; 111: datum fetch(); 112: #else not DBM 113: static DBM *db = NULL; /* History file, dbm version */ 114: #endif DBM 115: datum key, content; 116: #endif USGHIST 117: static FILE *hfp = NULL; /* history file, text version */ 118: 119: for (cp = msg_id; *cp != '\0'; ++cp) 120: if (isupper(*cp)) 121: *cp = tolower(*cp); 122: 123: #ifdef USGHIST 124: hfp = fopen(histfile(msg_id), "r"); 125: if (hfp == NULL) { 126: #ifdef SYSLOG 127: syslog(LOG_ERR, "gethistent: histfile: %m"); 128: #endif SYSLOG 129: return (NULL); 130: } 131: 132: len = strlen(msg_id); 133: while (fgets(line, sizeof (line), hfp)) 134: if (!strncasecmp(msg_id, line, len)) 135: break; 136: 137: if (feof(hfp)) { 138: (void) fclose(hfp); 139: return (NULL); 140: } 141: #else not USGHIST 142: #ifdef DBM 143: if (!dbopen) { 144: if (dbminit(historyfile) < 0) { 145: #ifdef SYSLOG 146: syslog(LOG_ERR, "openartbyid: dbminit %s: %m", 147: historyfile); 148: #endif SYSLOG 149: return (NULL); 150: } else 151: dbopen = 1; 152: } 153: #else /* ndbm */ 154: if (db == NULL) { 155: db = dbm_open(historyfile, O_RDONLY, 0); 156: if (db == NULL) { 157: #ifdef SYSLOG 158: syslog(LOG_ERR, "openartbyid: dbm_open %s: %m", 159: historyfile); 160: #endif SYSLOG 161: return (NULL); 162: } 163: } 164: #endif DBM 165: 166: key.dptr = msg_id; 167: key.dsize = strlen(msg_id) + 1; 168: 169: #ifdef DBM 170: content = fetch(key); 171: #else /* ndbm */ 172: content = dbm_fetch(db, key); 173: #endif DBM 174: if (content.dptr == NULL) 175: return (NULL); 176: 177: if (hfp == NULL) { 178: hfp = fopen(historyfile, "r"); 179: if (hfp == NULL) { 180: #ifdef SYSLOG 181: syslog(LOG_ERR, "message: fopen %s: %m", 182: historyfile); 183: #endif SYSLOG 184: return (NULL); 185: } 186: } 187: 188: bcopy(content.dptr, (char *)<mp, sizeof (long)); 189: if (fseek(hfp, ltmp, 0) < 0) { 190: #ifdef SYSLOG 191: syslog(LOG_ERR, "message: fseek: %m"); 192: #endif SYSLOG 193: return (NULL); 194: } 195: 196: (void) fgets(line, sizeof(line), hfp); 197: #endif USGHIST 198: 199: if ((cp = index(line, '\n')) != NULL) 200: *cp = '\0'; 201: cp = index(line, '\t'); 202: if (cp != NULL) 203: cp = index(cp+1, '\t'); 204: if (cp == NULL) { 205: #ifdef SYSLOG 206: syslog(LOG_ERR, 207: "message: malformed line in history file at %ld bytes, id %s", 208: ltmp, msg_id); 209: #endif SYSLOG 210: return (NULL); 211: } 212: tmp = cp+1; 213: 214: if ((cp = index(tmp, ' ')) != NULL) 215: *cp = '\0'; 216: 217: while ((cp = index(tmp, '.')) != NULL) 218: *cp = '/'; 219: 220: (void) strcpy(path, spooldir); 221: (void) strcat(path, "/"); 222: (void) strcat(path, tmp); 223: 224: return (path); 225: } 226: 227: /* 228: * openartbyid -- open an article by message-id. 229: * 230: * Arguments: "msg_id" is the message-id of the article 231: * to open. 232: * 233: * Returns: File pointer to opened article, or NULL if 234: * the article was not in the history file or 235: * could not be opened. 236: * 237: * Side effects: Opens article. 238: */ 239: 240: FILE * 241: openartbyid(msg_id) 242: char *msg_id; 243: { 244: char *path; 245: 246: path = gethistent(msg_id); 247: if (path != NULL) 248: return (fopen(path, "r")); 249: else 250: return (NULL); 251: } 252: 253: 254: /* 255: * check_ngperm -- check to see if they're allowed to see this 256: * article by matching Newsgroups: and Distribution: line. 257: * 258: * Parameters: "fp" is the file pointer of this article. 259: * 260: * Returns: 0 if they're not allowed to see it. 261: * 1 if they are. 262: * 263: * Side effects: None. 264: */ 265: 266: check_ngperm(fp) 267: register FILE *fp; 268: { 269: char buf[MAXBUFLEN]; 270: register char *cp; 271: static char **ngarray; 272: int ngcount; 273: 274: if (ngpermcount == 0) 275: return (1); 276: 277: while (fgets(buf, sizeof (buf), fp) != NULL) { 278: if (buf[0] == '\n') /* End of header */ 279: break; 280: if (buf[0] != 'N' && buf[0] != 'n') 281: continue; 282: cp = index(buf, '\n'); 283: if (cp) 284: *cp = '\0'; 285: cp = index(buf, ':'); 286: if (cp == NULL) 287: continue; 288: *cp = '\0'; 289: if (!strcasecmp(buf, "newsgroups")) { 290: ngcount = get_nglist(&ngarray, cp+2); 291: break; 292: } 293: } 294: 295: (void) rewind(fp); 296: 297: if (ngcount == 0) /* Either no newgroups or null entry */ 298: return (1); 299: 300: return (ngmatch(s1strneql, ALLBUT, 301: ngpermlist, ngpermcount, ngarray, ngcount)); 302: } 303: 304: 305: /* 306: * spew -- spew out the contents of a file to stdout, doing 307: * the necessary cr-lf additions at the end. Finish with 308: * a "." on a line by itself, and an fflush(stdout). 309: * 310: * Parameters: "how" tells what part of the file we 311: * want spewed: 312: * ARTICLE The entire thing. 313: * HEAD Just the first part. 314: * BODY Just the second part. 315: * "fp" is the open file to spew from. 316: * 317: * Returns: Nothing. 318: * 319: * Side effects: Changes current position in file. 320: */ 321: 322: spew(fp, how) 323: FILE *fp; 324: int how; 325: { 326: char line[NNTP_STRLEN]; 327: register char *cp; 328: 329: #ifdef LOG 330: ++arts_acsd; 331: #endif 332: 333: if (how == STAT) { 334: (void) fflush(stdout); 335: return; 336: } 337: 338: while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') { 339: if (how == BODY) /* We need to skip this anyway */ 340: continue; 341: cp = index(line, '\n'); 342: if (cp != NULL) 343: *cp = '\0'; 344: if (*line == '.') 345: putchar('.'); 346: putline(line); 347: if (cp == NULL) { 348: for (;;) { 349: if ((fgets(line, sizeof(line)-6, fp) == NULL) 350: || (index(line, '\n') != NULL)) 351: break; 352: } 353: } 354: } 355: 356: if (how == HEAD) { 357: putchar('.'); 358: putchar('\r'); 359: putchar('\n'); 360: (void) fflush(stdout); 361: return; 362: } else if (how == ARTICLE) { 363: putchar('\r'); 364: putchar('\n'); 365: } 366: 367: while (fgets(line, sizeof(line)-6, fp) != NULL) { 368: cp = index(line, '\n'); 369: if (cp != NULL) 370: *cp = '\0'; 371: if (*line == '.') 372: putchar('.'); 373: putline(line); 374: 375: if (cp == NULL) { 376: for (;;) { 377: if ((fgets(line, sizeof(line)-6, fp) == NULL) 378: || (index(line, '\n') != NULL)) 379: break; 380: } 381: } 382: } 383: putchar('.'); 384: putchar('\r'); 385: putchar('\n'); 386: (void) fflush(stdout); 387: } 388: 389: 390: /* 391: * get_id -- get the message id of the current article. 392: * 393: * Parameters: "art_fp" is a pointer to the open file. 394: * "id" is space for the message ID. 395: * 396: * Returns: Nothing. 397: * 398: * Side effects: Seeks and rewinds on "art_fp". 399: * Changes space pointed to by "id". 400: */ 401: 402: get_id(art_fp, id) 403: register FILE *art_fp; 404: char *id; 405: { 406: char line[MAXBUFLEN]; 407: register char *cp; 408: 409: while (fgets(line, sizeof(line), art_fp) != NULL) { 410: if (*line == '\n') 411: break; 412: if (*line == 'M' || *line == 'm') { /* "Message-ID" */ 413: if ((cp = index(line, ' ')) != NULL) { 414: *cp = '\0'; 415: if (!strcasecmp(line, "Message-ID:")) { 416: (void) strcpy(id, cp + 1); 417: if ((cp = index(id, '\n')) != NULL) 418: *cp = '\0'; 419: (void) rewind(art_fp); 420: return; 421: } 422: } 423: } 424: } 425: (void) rewind(art_fp); 426: (void) strcpy(id, "<0>"); 427: } 428: 429: 430: /* 431: * close_crnt -- close the current article file pointer, if it's 432: * open. 433: * 434: * Parameters: None. 435: * 436: * Returns: Nothing. 437: * 438: * Side effects: Closes "art_fp" if it's open; sets "art_fp" to NULL. 439: */ 440: 441: close_crnt() 442: { 443: if (art_fp != NULL) 444: (void) fclose(art_fp); 445: art_fp = NULL; 446: } 447: 448: 449: /* 450: * findart -- find an article number in the article array. 451: * 452: * Parameters: "artname" is a string containing 453: * the name of the article. 454: * 455: * Returns: An index into "art_array", 456: * or -1 if "artname" isn't in "art_array". 457: * 458: * Side effects: None. 459: * 460: * Improvement: Replace this linear search with a binary one. 461: */ 462: 463: findart(artname) 464: char *artname; 465: { 466: register int i, artnum; 467: 468: artnum = atoi(artname); 469: 470: for (i = 0; i < num_arts; ++i) 471: if (art_array[i] == artnum) 472: return(i); 473: 474: return (-1); 475: } 476: 477: 478: /* 479: * get_distlist -- return a nicely set up array of distribution groups 480: * along with a count, when given an NNTP-spec distribution list 481: * in the form <dist1,dist2,...,distn>. 482: * 483: * Parameters: "array" is storage for our array, 484: * set to point at some static data. 485: * "list" is the NNTP distribution list. 486: * 487: * Returns: Number of distributions found. 488: * -1 on error. 489: * 490: * Side effects: Changes static data area. 491: */ 492: 493: get_distlist(array, list) 494: char ***array; 495: char *list; 496: { 497: char *cp; 498: int distcount; 499: static char **dist_list = (char **) NULL; 500: 501: if (list[0] != '<') 502: return (-1); 503: 504: cp = index(list + 1, '>'); 505: if (cp != NULL) 506: *cp = '\0'; 507: else 508: return (-1); 509: 510: for (cp = list + 1; *cp != '\0'; ++cp) 511: if (*cp == ',') 512: *cp = ' '; 513: distcount = parsit(list + 1, &dist_list); 514: *array = dist_list; 515: return (distcount); 516: } 517: 518: 519: /* 520: * lower -- convert a character to lower case, if it's upper case. 521: * 522: * Parameters: "c" is the character to be 523: * converted. 524: * 525: * Returns: "c" if the character is not 526: * upper case, otherwise the lower 527: * case eqivalent of "c". 528: * 529: * Side effects: None. 530: */ 531: 532: char 533: lower(c) 534: register char c; 535: { 536: if (isascii(c) && isupper(c)) 537: c = c - 'A' + 'a'; 538: return (c); 539: } 540: 541: 542: /* the following is from news 2.11 */ 543: 544: #ifdef USG 545: /* 546: ** Generate the appropriate history subfile name 547: */ 548: char * 549: histfile(hline) 550: char *hline; 551: { 552: char chr; /* least significant digit of article number */ 553: static char subfile[BUFSIZ]; 554: 555: chr = findhfdigit(hline); 556: sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr); 557: return subfile; 558: } 559: 560: findhfdigit(fn) 561: char *fn; 562: { 563: register char *p; 564: register int chr; 565: 566: p = index(fn, '@'); 567: if (p != NULL && p > fn) 568: chr = *(p - 1); 569: else 570: chr = '0'; 571: if (!isdigit(chr)) 572: chr = '0'; 573: return chr; 574: } 575: bcopy(s, d, l) 576: register char *s, *d; 577: register int l; 578: { 579: while (l-- > 0) 580: *d++ = *s++; 581: } 582: 583: bcmp(s1, s2, l) 584: register char *s1, *s2; 585: register int l; 586: { 587: if (l == 0) 588: return (0); 589: 590: do 591: if (*s1++ != *s2++) 592: break; 593: while (--l); 594: 595: return (l); 596: } 597: 598: bzero(p, l) 599: register char *p; 600: register int l; 601: { 602: while (l-- > 0) 603: *p++ = 0; 604: } 605: 606: dup2(x,y) 607: int x,y; 608: { 609: close(y); 610: return(fcntl(x, F_DUPFD,y )); 611: } 612: #endif USG