1: #ifndef lint 2: static char *sccsid = "@(#)misc.c 1.4 (Berkeley) 3/8/86"; 3: #endif 4: 5: #include "common.h" 6: 7: /* 8: * open_valid_art -- determine if a given article name is valid; 9: * if it is, return a file pointer to the open article, 10: * along with a unique id of the article. 11: * 12: * Parameters: "artname" is a string containing the 13: * name of the article. 14: * "id" is space for us to put the article 15: * id in. 16: * 17: * Returns: File pointer to the open article if the 18: * article is valid; NULL otherwise 19: * 20: * Side effects: None. 21: */ 22: 23: FILE * 24: open_valid_art(artname, id) 25: char *artname; 26: char *id; 27: { 28: static int crnt_art_num; 29: static char crnt_art_id[MAX_STRLEN]; 30: int fd; 31: struct stat statbuf; 32: 33: if (art_fp != NULL) { 34: if (crnt_art_num == atoi(artname)) { 35: if (fseek(art_fp, (long) 0, 0) < 0) 36: close_crnt(); 37: else { 38: (void) strcpy(id, crnt_art_id); 39: return(art_fp); 40: } 41: } else 42: close_crnt(); 43: } 44: 45: art_fp = fopen(artname, "r"); 46: 47: if (art_fp == NULL) 48: return(NULL); 49: 50: fd = fileno(art_fp); 51: 52: if (fstat(fd, (struct stat *) &statbuf) < 0) { 53: close_crnt(); 54: return(NULL); 55: } 56: 57: if ((statbuf.st_mode & S_IFREG) != S_IFREG) { 58: close_crnt(); 59: return(NULL); 60: } 61: 62: get_id(art_fp, id); 63: (void) strcpy(crnt_art_id, id); 64: crnt_art_num = atoi(artname); 65: return(art_fp); 66: } 67: 68: 69: /* 70: * openartbyid -- open an article by message-id. 71: * 72: * Parameters: "msg_id" is the message ID of the 73: * article, enclosed in <>'s. 74: * 75: * Returns: A file pointer to the open article, 76: * or NULL if the article doesn't exist. 77: * 78: * Side effects: Displays article, opens dbm database 79: * (only once, keeps it open after that). 80: * Converts "msg_id" to lower case. 81: */ 82: 83: FILE * 84: openartbyid(msg_id) 85: char *msg_id; 86: { 87: char line[MAX_STRLEN], path[MAX_STRLEN]; 88: char *tmp; 89: register char *cp; 90: FILE *art_fp; 91: #ifdef DBM 92: static int dbopen; 93: datum fetch(); 94: #else 95: static DBM *db; /* History file, dbm version */ 96: #endif 97: static FILE *hfp; /* history file, text version */ 98: datum key, content; 99: 100: #ifdef DBM 101: if (!dbopen) { 102: if (dbminit(HISTORY_FILE) < 0) { 103: syslog(LOG_ERR, "nntpd: openartbyid: dbminit %s: %m\n", 104: HISTORY_FILE); 105: return (NULL); 106: } else 107: dbopen = 1; 108: } 109: #else 110: if (db == NULL) { 111: db = dbm_open(HISTORY_FILE, O_RDONLY, 0); 112: if (db == NULL) { 113: syslog(LOG_ERR, "nntpd: openartbyid: dbm_open %s: %m\n", 114: HISTORY_FILE); 115: return (NULL); 116: } 117: } 118: #endif 119: 120: for (cp = msg_id; *cp != '\0'; ++cp) 121: if (isupper(*cp)) 122: *cp = tolower(*cp); 123: 124: key.dptr = msg_id; 125: key.dsize = strlen(msg_id) + 1; 126: 127: #ifdef DBM 128: content = fetch(key); 129: #else 130: content = dbm_fetch(db, key); 131: #endif 132: if (content.dptr == NULL) 133: return (NULL); 134: 135: if (hfp == NULL) { 136: hfp = fopen(HISTORY_FILE, "r"); 137: if (hfp == NULL) { 138: syslog(LOG_ERR, "nntpd: message: fopen %s: %m\n", 139: HISTORY_FILE); 140: return (NULL); 141: } 142: } 143: 144: if (fseek(hfp, (long) *(int *)content.dptr, 0) < 0) { 145: syslog(LOG_ERR, "nntpd: message: fseek: %m\n"); 146: return (NULL); 147: } 148: 149: (void) fgets(line, sizeof(line), hfp); 150: if ((cp = index(line, '\n')) != NULL) 151: *cp = '\0'; 152: cp = index(line, '\t'); 153: if (cp != NULL) 154: cp = index(cp+1, '\t'); 155: if (cp == NULL) { 156: syslog(LOG_ERR, 157: "nntpd: message: malformed line in history file (%d bytes)\n", 158: (int) *(int *)content.dptr); 159: return (NULL); 160: } 161: tmp = cp+1; 162: 163: if ((cp = index(tmp, ' ')) != NULL) 164: *cp = '\0'; 165: 166: while ((cp = index(tmp, '.')) != NULL) 167: *cp = '/'; 168: 169: (void) strcpy(path, homedir); 170: (void) strcat(path, "/"); 171: (void) strcat(path, tmp); 172: 173: art_fp = fopen(path, "r"); 174: return (art_fp); 175: 176: } 177: 178: 179: /* 180: * spew -- spew out the contents of a file to stdout, doing 181: * the necessary cr-lf additions at the end. Finish with 182: * a "." on a line by itself, and an fflush(stdout). 183: * 184: * Parameters: "how" tells what part of the file we 185: * want spewed: 186: * ARTICLE The entire thing. 187: * HEAD Just the first part. 188: * BODY Just the second part. 189: * "fp" is the open file to spew from. 190: * 191: * Returns: Nothing. 192: * 193: * Side effects: Changes current position in file. 194: */ 195: 196: spew(fp, how) 197: FILE *fp; 198: int how; 199: { 200: char line[512]; 201: register char *cp; 202: 203: #ifdef LOG 204: ++arts_acsd; 205: #endif 206: 207: if (how == STAT) { 208: (void) fflush(stdout); 209: return; 210: } 211: 212: while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') { 213: if (how == BODY) /* We need to skip this anyway */ 214: continue; 215: cp = index(line, '\n'); 216: if (cp != NULL) 217: *cp = '\0'; 218: if (*line == '.') 219: putchar('.'); 220: printf("%s\r\n", line); 221: if (cp == NULL) { 222: for (;;) { 223: if ((fgets(line, sizeof(line)-6, fp) == NULL) 224: || (index(line, '\n') != NULL)) 225: break; 226: } 227: } 228: } 229: 230: if (how == HEAD) { 231: putchar('.'); 232: putchar('\r'); 233: putchar('\n'); 234: (void) fflush(stdout); 235: return; 236: } else if (how == ARTICLE) { 237: putchar('\r'); 238: putchar('\n'); 239: } 240: 241: while (fgets(line, sizeof(line)-6, fp) != NULL) { 242: cp = index(line, '\n'); 243: if (cp != NULL) 244: *cp = '\0'; 245: if (*line == '.') 246: putchar('.'); 247: printf("%s\r\n", line); 248: 249: if (cp == NULL) { 250: for (;;) { 251: if ((fgets(line, sizeof(line)-6, fp) == NULL) 252: || (index(line, '\n') != NULL)) 253: break; 254: } 255: } 256: } 257: putchar('.'); 258: putchar('\r'); 259: putchar('\n'); 260: (void) fflush(stdout); 261: } 262: 263: 264: /* 265: * get_id -- get the message id of the current article. 266: * 267: * Parameters: "art_fp" is a pointer to the open file. 268: * "id" is space for the message ID. 269: * 270: * Returns: Nothing. 271: * 272: * Side effects: Seeks and rewinds on "art_fp". 273: * Changes space pointed to by "id". 274: */ 275: 276: get_id(art_fp, id) 277: register FILE *art_fp; 278: char *id; 279: { 280: char line[MAX_STRLEN]; 281: register char *cp; 282: 283: while (fgets(line, sizeof(line), art_fp) != NULL) { 284: if ((cp = index(line, '\n')) != NULL) 285: *cp = '\0'; 286: if (*line == '\0') 287: break; 288: if ((cp = index(line, ' ')) != NULL) { 289: *cp = '\0'; 290: if (streql(line, "Message-ID:")) { 291: (void) strcpy(id, cp + 1); 292: (void) rewind(art_fp); 293: return; 294: } 295: } 296: } 297: (void) strcpy(id, "<0>"); 298: (void) rewind(art_fp); 299: } 300: 301: /* 302: * close_crnt -- close the current article file pointer, if it's 303: * open. 304: * 305: * Parameters: None. 306: * 307: * Returns: Nothing. 308: * 309: * Side effects: Closes "art_fp" if it's open; sets "art_fp" to NULL. 310: */ 311: 312: close_crnt() 313: { 314: if (art_fp != NULL) 315: (void) fclose(art_fp); 316: art_fp = NULL; 317: } 318: 319: 320: /* 321: * findart -- find an article number in the article array. 322: * 323: * Parameters: "artname" is a string containing 324: * the name of the article. 325: * 326: * Returns: An index into "art_array", 327: * or -1 if "artname" isn't in "art_array". 328: * 329: * Side effects: None. 330: * 331: * Improvement: Replace this linear search with a binary one. 332: */ 333: 334: findart(artname) 335: char *artname; 336: { 337: register int i, artnum; 338: 339: artnum = atoi(artname); 340: 341: for (i = 0; i < num_arts; ++i) 342: if (art_array[i] == artnum) 343: return(i); 344: 345: return(-1); 346: } 347: 348: 349: /* 350: * get_distlist -- return a nicely set up array of distribution groups 351: * along with a count, when given an NNTP-spec distribution list 352: * in the form <dist1,dist2,...,distn>. 353: * 354: * Parameters: "array" is storage for our array, 355: * set to point at some static data. 356: * "list" is the NNTP distribution list. 357: * 358: * Returns: Number of distributions found. 359: * -1 on error. 360: * 361: * Side effects: Changes static data area. 362: */ 363: 364: get_distlist(array, list) 365: char ***array; 366: char *list; 367: { 368: char *cp; 369: int distcount; 370: static char **dist_list = (char **) NULL; 371: 372: if (list[0] != '<') 373: return (-1); 374: 375: cp = index(list + 1, '>'); 376: if (cp != NULL) 377: *cp = '\0'; 378: else 379: return (-1); 380: 381: for (cp = list + 1; *cp != '\0'; ++cp) 382: if (*cp == ',') 383: *cp = ' '; 384: distcount = parsit(list + 1, &dist_list); 385: *array = dist_list; 386: return (distcount); 387: } 388: 389: 390: /* 391: * spawn -- create a child process with the input from the client 392: * as stdin. 393: * 394: * Parameters: "path" is the path of the program to invoke. 395: * "name" is the name to call the program. 396: * "flag" is a single flag to be passed to the program. 397: * "cont_code" is the response code to transmit 398: * on successful startup. 399: * "err_code" is the response code to transmit when 400: * something goes wrong. 401: * 402: * Returns: -1 on non-zero return from child, 403: * 0 on error before fork/exec, 404: * 1 otherwise. 405: * 406: * Side effects: Creates and removes temporary file; 407: * accepts input from client; forks and execs. 408: */ 409: 410: spawn(path, name, flag, cont_code, err_code) 411: char *path; 412: char *name; 413: char *flag; 414: int cont_code; 415: int err_code; 416: { 417: char tempfile[256], line[MAX_STRLEN]; 418: register char *cp; 419: int i, nds, fd; 420: int exit_status; 421: union wait status; 422: register FILE *fp; 423: 424: (void) strcpy(tempfile, "/tmp/rpostXXXXXX"); 425: (void) mktemp(tempfile); 426: 427: fp = fopen(tempfile, "w"); 428: if (fp == NULL) { 429: printf("%d Cannot create temporary file.\r\n", err_code); 430: (void) fflush(stdout); 431: return (0); 432: } else { 433: printf("%d Enter news, period on a line by itself to end.\r\n", 434: cont_code); 435: (void) fflush(stdout); 436: } 437: 438: while (fgets(line, sizeof(line), stdin) != NULL) { 439: if ((cp = index(line, '\r')) != NULL) 440: *cp = '\0'; 441: else if ((cp = index(line, '\n')) != NULL) 442: *cp = '\0'; 443: 444: if (strcmp(line, ".") == 0) 445: break; 446: 447: if (line[0] == '.') 448: fprintf(fp, "%s\n", line+1); 449: else 450: fprintf(fp, "%s\n", line); 451: } 452: (void) fclose(fp); 453: 454: /* 455: * Ok, now we have the article in "tempfile". We 456: * should be able to fork off, close fd's 0 to 31 (or 457: * whatever), open "tempfile" for input, thus making 458: * it stdin, and then execl the inews. We think. 459: */ 460: 461: if (fork() == 0) { /* We're in child */ 462: #ifdef POSTER 463: (void) setuid(uid_poster); 464: (void) setgid(gid_poster); 465: #endif 466: 467: nds = getdtablesize(); 468: for (i = 0; i < nds; ++i) 469: (void) close(i); 470: fd = open(tempfile, O_RDONLY); 471: if (fd != 0) { 472: (void) dup2(fd, 0); 473: (void) close(fd); 474: } 475: fd = open("/", O_RDONLY); 476: if (fd != 1) { 477: (void) dup2(fd, 1); 478: (void) close(fd); 479: } 480: (void) dup2(1, 2); 481: 482: execl(path, name, flag, (char *) NULL); 483: exit(-1); /* Error */ 484: } else { 485: while (wait(&status) > 0) 486: exit_status = status.w_T.w_Retcode; 487: (void) unlink(tempfile); 488: (void) fflush(stdout); 489: return (exit_status ? -1 : 1); 490: } 491: } 492: 493: 494: /* 495: * streql -- determine if two strings are equal, ignoring case. 496: * 497: * Parameters: "a" and "b" are the pointers 498: * to characters to be compared. 499: * 500: * Returns: 1 if the strings are equal, 0 otherwise. 501: * 502: * Side effects: None. 503: */ 504: 505: streql(a, b) 506: register char *a, *b; 507: { 508: char lower(); 509: 510: while (lower(*a) == lower(*b)) { 511: if (*a == '\0') 512: return (1); 513: a++; 514: b++; 515: } 516: return (0); 517: } 518: 519: /* 520: * lower -- convert a character to lower case, if it's 521: * upper case. 522: * 523: * Parameters: "c" is the character to be 524: * converted. 525: * 526: * Returns: "c" if the character is not 527: * upper case, otherwise the lower 528: * case eqivalent of "c". 529: * 530: * Side effects: None. 531: */ 532: 533: char lower(c) 534: register char c; 535: { 536: if (isascii(c) && isupper(c)) 537: c = c - 'A' + 'a'; 538: return(c); 539: }