1: #define MAINLINE 2: #include "parms.h" 3: #include "structs.h" 4: #include "newsgate.h" 5: #ifdef SYSLOG 6: # include <syslog.h> 7: # undef stderr 8: # define fprintf syslog 9: # define stderr LOG_NOTICE 10: #endif SYSLOG 11: 12: #ifdef RCSIDENT 13: static char rcsid[] = "$Header: /usr/local/src/usenet/notes/src/RCS/newsinput.c,v 1.8 88/11/11 00:58:33 paul Exp $"; 14: #endif RCSIDENT 15: 16: /* 17: * newsinput 18: * 19: * A total re-coding of the original. Makes use of the 20: * work that Lou Salkind and Tw Cook have done. Lou rearranged 21: * a bunch of stuff and Tw put the notes headers into the 22: * news header. 23: */ 24: 25: static char title[TITLEN + 1]; /* hold titles */ 26: extern char fromsys[SYSSZ + 1]; /* gave it to us */ 27: static struct when_f entered; /* date written */ 28: extern char origsys[SYSSZ + 1]; /* originator */ 29: extern char authname[NAMESZ + 1]; /* author */ 30: static int has_suffix = 0; /* had -(nf) suffix */ 31: static int ShowTruncated = 1; /* log truncated id's */ 32: static int JustFirstGroup = 0; /* into only 1 group */ 33: 34: #define dprintf if (0) printf 35: 36: 37: main (argc, argv) 38: int argc; 39: char **argv; 40: { 41: FILE * rawnews; 42: FILE * body; 43: char pathname[BUFSIZ]; 44: struct io_f io; 45: struct hbuf header; 46: char nf[WDLEN]; 47: struct nflist_f *nfptr; /* expand newsgroups */ 48: int c; 49: int onechar; 50: char *tail; 51: int fid; /* for close */ 52: int i; /* scratch */ 53: 54: 55: #ifdef SYSLOG 56: openlog ("newsinput", LOG_PID, SYSLOG); 57: #endif SYSLOG 58: setuid (geteuid ()); /* force to "notes" */ 59: startup (argc, argv); /* common init */ 60: rawnews = stdin; /* usually here */ 61: for (fid = 3; fid < 20; fid++) /* close all extras */ 62: close (fid); 63: 64: /* 65: * run down the arg vector. looking for various procesing options. 66: * 67: * -t do not log "truncated message id" situations in nfmaint. 68: * -1 for multi-newsgroup articles, save this in the first 69: * group listed and none of the others. 70: */ 71: 72: for (i = 1; i < argc; i++) 73: { 74: if (argv[i] == (char *) NULL) /* done */ 75: break; 76: if (strcmp (argv[i], "-t") == 0) /* suppress truncation msgs */ 77: { 78: ShowTruncated = 0; 79: continue; 80: } 81: if (strcmp (argv[i], "-1") == 0) /* just first group */ 82: { 83: JustFirstGroup++; 84: continue; 85: } 86: } 87: 88: /* 89: * Parse the Header. Follow all the USENET standards 90: * for doing this. Result is left in a fun little 91: * structure. 92: * Internalize some of the information to help us figure out 93: * some things quickly. 94: */ 95: 96: if (!newsheader (&header, rawnews, TRUE)) /* read the headers */ 97: { 98: fprintf (stderr, "Incoming News mangled more than usual\n"); 99: exit (BAD); 100: } 101: 102: /* 103: * Parse things like origsys, fromsys, author, date written 104: */ 105: parsepath (header.path, header.from); /* systems, authors */ 106: parsetime (header.subdate, &entered); /* submitted */ 107: sprintf (pathname, "/tmp/nfxx%d", getpid ()); 108: dprintf ("Origsys: %s\n", origsys); 109: dprintf ("fromsys: %s\n", fromsys); 110: dprintf ("Date Written:"); 111: #ifdef notdef 112: prdate (&entered); 113: #endif 114: dprintf ("\nauthor: %s\n", authname); 115: /* 116: * See if this might be a control message. Notes readers don't 117: * care to see these. 118: * 119: * News code also recognizes titles with first 5 characters set 120: * to "cmsg " as control messages. We should clean them up too. 121: */ 122: if (header.ctlmsg[0] != '\0') /* is control */ 123: { 124: fprintf (stderr, "Control message (ignored): %s\n", header.ctlmsg); 125: exit (0); /* "success" */ 126: } 127: /* 128: * Save the body of the article somewhere safe (like not in 129: * memory). 130: */ 131: if ((body = fopen (pathname, "w")) == NULL) /* failed */ 132: { 133: fprintf (stderr, "Had problems creating/opening file %s\n", pathname); 134: exit (BAD); /* die */ 135: } 136: while ((onechar = getc (rawnews)) != EOF) /* save it */ 137: putc (onechar, body); 138: fflush (body); /* make sure */ 139: fclose (body); /* and close it */ 140: 141: /* 142: * Now run through the specified list of newsgroups, 143: * re-scan the body and such each time. 144: */ 145: 146: expand (header.nbuf); /* expand groups */ 147: while ((nfptr = nextgroup ()) != (struct nflist_f *) NULL) 148: { 149: 150: newsgroup (nfptr -> nf_name, nf, NEWSNF); /* map it */ 151: dprintf ("Newsgroup %s maps to notesfile %s\n", nfptr -> nf_name, nf); 152: tail = rindex (nfptr -> nf_name, '.'); /* catch ctl msgs */ 153: if (tail != (char *) NULL && !strcmp (tail, CTL))/* it is one */ 154: { 155: char pbuf[256]; /* for title fixing */ 156: 157: /* 158: * re-route the control message to NFMAINT. 159: */ 160: strcpy (nf, NFMAINT); /* map it */ 161: dprintf ("Control newsgroup %s mapped to %s\n", 162: nfptr -> nf_name, nf); 163: sprintf (pbuf, "%s:%s", nfptr -> nf_name, header.title); 164: strncpy (header.title, pbuf, BUFLEN); /* prefix title */ 165: header.title[BUFLEN - 1] = '\0'; /* ensure terminater */ 166: } 167: 168: if ((body = fopen (pathname, "r")) == NULL) 169: { 170: goto failed; /* shit */ 171: } 172: if (init (&io, nf) < 0) /* open the nf */ 173: { 174: char pbuf[512]; 175: char tbuf[128]; 176: #ifdef AUTOCREATE 177: /* 178: * create the notesfile; we are allowed to do this. 179: */ 180: sprintf (pbuf, 181: "Notesfile: %s\nNewsgroup: %s\n\nCreated by newsinput\n", 182: nf, nfptr -> nf_name); 183: if (strlen (nf) >= 14) 184: { 185: /* 186: * could be a truncation error; mark that in the message 187: */ 188: sprintf (tbuf, "\n'%s' >= 14 characters long; check for abbreviations\n", 189: nf); 190: strcat (pbuf, tbuf); 191: } 192: sprintf (tbuf, "New NF: %s", nf); 193: nfcomment (NFMAINT, pbuf, tbuf, TRUE, 0); 194: buildnf (nf, Mstdir, 0, 1, 1); /* open and networked */ 195: x (init (&io, nf) < 0, "newsinput: open newly created notesfile"); 196: #else 197: /* 198: * drop the article, log it in nfmaint 199: */ 200: sprintf (pbuf, 201: "Notesfile: %s\nNewsgroup %s\n\nNOT created by newsinput\n", 202: nf, nfptr -> nf_name); 203: sprintf (tbuf, "No Such NF: %s", nf); 204: nfcomment (NFMAINT, pbuf, tbuf, 0, 0); 205: fclose (body); /* close article */ 206: goto nextstep; 207: #endif AUTOCREATE 208: } 209: 210: if (nfgen (&io, &header, body, pathname) < 0) /* not from notes */ 211: { 212: dprintf ("Nfgen returns failure\n"); 213: fclose (body); /* give bnewsgen */ 214: body = fopen (pathname, "r"); /* a clean copy */ 215: if (bnewsgen (&io, &header, body) < 0) /* or news */ 216: { 217: dprintf ("bnewsgen returns failure\n"); 218: goto failed; /* drop out */ 219: } 220: } 221: fclose (body); /* ready for loop */ 222: finish (&io); 223: nextstep: 224: if (JustFirstGroup) /* only wanted 1 */ 225: { 226: break; /* so exit this loop */ 227: } 228: } 229: 230: unlink (pathname); 231: exit (GOOD); 232: 233: /* 234: * jump here on totally screwed up article. 235: */ 236: failed: 237: dprintf ("Jumped to failed\n"); 238: unlink (pathname); /* body of article */ 239: exit (BAD); 240: } 241: 242: /* 243: * nfgen(&io,&header,&FILE,pathname) 244: * 245: * parse a notesfile-generated article. Check the fields of 246: * header and look for # lines in the body of the article to 247: * determine if it came from notes. 248: * 249: * returns: 0 no permission for author 250: * > 0 signifies note or response where it wound up 251: * -1 if the article wasn't generated by notes 252: */ 253: 254: nfgen (io, header, body, pathname) 255: struct io_f *io; 256: struct hbuf *header; 257: FILE * body; 258: char *pathname; 259: { 260: register int i; 261: register char *p; 262: struct note_f note; 263: struct note_f note2; 264: struct id_f respid; 265: struct daddr_f where; 266: struct when_f whentime; 267: struct auth_f auth; /* author */ 268: int oldstyle = 0; 269: int found; 270: char line[CMDLEN]; /* scratch */ 271: char *suffix; 272: int notenum; 273: int status; 274: int fosterstat; /* for foster parents */ 275: int count; 276: char hline1[BUFLEN]; /* in-text header */ 277: char hline2[BUFLEN]; /* in-text header 2 */ 278: int onechar; /* scratch character */ 279: char field1[100], /* scanf tmps */ 280: field2[100]; 281: 282: /* 283: * Check for titles ending in "- nf". 284: * We always remove these. 285: */ 286: suffix = rindex (header -> title, '-'); /* find last */ 287: if (suffix != (char *) NULL && /* have suffix */ 288: (!strcmp (suffix, NFSUFFIX) || !strcmp (suffix, OLDSUFFIX))) 289: { /* and it matches */ 290: if (--suffix > header -> title) /* if we can */ 291: *suffix = '\0'; /* strip "- (nf)" */ 292: has_suffix++; /* flag it */ 293: } 294: /* 295: * at this point we should check for embodied #N.... lines and 296: * remove them. This is conditional on having a "- (nf)" in the 297: * title of the note. 298: */ 299: 300: strcpy (hline1, ""); /* empty these */ 301: strcpy (hline2, ""); 302: if (has_suffix) /* look for embedded */ 303: { 304: long position, /* place marker */ 305: ftell (); /* for types */ 306: 307: position = ftell (body); /* save it */ 308: while (fgets (hline1, sizeof hline1, body) != NULL) 309: { 310: if (hline1[0] == '#' && 311: (hline1[1] == 'N' || hline1[1] == 'R')) 312: { 313: break; /* found one */ 314: } 315: } 316: /* 317: * could probably have looked for "#N:" and "#R:". i 318: * think that the old style lines had those colons. 319: * ok; we either EOF'ed or found an appropriate line 320: */ 321: if (hline1[0] != '#' || 322: (hline1[1] != 'N' && hline1[1] != 'R')) /* actually didn't */ 323: { /* it wasn't really a #N or #R line */ 324: fseek (body, position, 0); /* rewind */ 325: strcpy (hline1, ""); /* empty it */ 326: } 327: else 328: { /* grab line 2 */ 329: fgets (hline2, sizeof hline2, body); 330: while ((onechar = getc (body)) != '\n' && onechar != EOF) 331: ; /* zap separator line */ 332: } 333: } 334: 335: if (strlen (header -> nline1) == 0) /* no new headers */ 336: { 337: /* 338: * No notes header in the B news article header... 339: * If title ends with "- nf", look for the 340: * header in the body of the text. 341: * (for backwards compatability) 342: */ 343: if (has_suffix == 0) /* not from notes */ 344: { 345: dprintf ("No NFSUFFIX and no header lines\n"); 346: return (-1); 347: } 348: oldstyle = 1; 349: found = 0; 350: if (hline1[0] == '#') /* got them earlier */ 351: { 352: strcpy (header -> nline1, hline1); /* first line */ 353: strcpy (header -> nline2, hline2); /* second line */ 354: found++; /* and mark it */ 355: } 356: while (!found && /* search body */ 357: fgets (header -> nline1, sizeof header -> nline1, body)) 358: { 359: if (header -> nline1[0] == '#') /* bingo */ 360: { 361: found++; 362: break; 363: } 364: } 365: if (!found || 366: fgets (header -> nline2, sizeof header -> nline2, body) == NULL) 367: { 368: dprintf ("no header lines in text body\n"); 369: return (-1); /* not from notes */ 370: } 371: } 372: 373: /* 374: * We now have the header lines. 375: * Check validity and do the appropriate action. 376: */ 377: if (header -> nline1[0] != '#') 378: { 379: dprintf ("Invalid first header line\n"); 380: return (-1); 381: } 382: dprintf ("First line is: %s\n", header -> nline1); 383: dprintf ("Second line is: %s\n", header -> nline2); 384: strncpy (title, header -> title, TITLEN); /* get title */ 385: title[TITLEN - 1] = '\0'; /* terminate for sure */ 386: 387: switch (header -> nline1[1]) /* parse it */ 388: { 389: case 'N': /* base note */ 390: if (sscanf (header -> nline1, "#N:%99[^:]:%ld:%o:%d", field1, 391: ¬e.n_id.uniqid, &status, &count) != 4) 392: { 393: return (-1); /* no good */ 394: } 395: strncpy (note.n_id.sys, field1, SYSSZ); /* copy */ 396: note.n_id.sys[SYSSZ - 1] = '\0'; /* and terminate */ 397: status |= FRMNEWS; /* it's been there */ 398: 399: /* 400: * parse the second header line 401: */ 402: 403: p = header -> nline2; 404: for (i = 0; (i < HOMESYSSZ - 1) && (*p != '!' && *p != '\0'); i++) 405: auth.asystem[i] = *p++; /* get the author */ 406: auth.asystem[i] = '\0'; /* terminate */ 407: while (*p != '!' && *p != '\0') 408: p++; /* skip to end of system */ 409: if (*p == '!') 410: p++; /* skip the ! */ 411: for (i = 0; (i < NAMESZ - 1) && (*p != ' ' && *p != '\0'); i++) 412: auth.aname[i] = *p++; /* get the author */ 413: auth.aname[i] = '\0'; /* terminate */ 414: auth.aid = Anonuid; 415: 416: while (*p != ' ' && *p) 417: p++; /* drop rest of author */ 418: while (*p == ' ') /* find the date */ 419: p++; 420: parsetime (p, ¬e.n_date); /* and parse it */ 421: 422: getperms (io, 1, note.n_id.sys); /* check permissions */ 423: if (allow (io, WRITOK) == 0) /* not a chance */ 424: return (0); /* sort of success */ 425: 426: locknf (io, DSCRLOCK); /* MUTEX */ 427: if ((notenum = chknote (io, ¬e.n_id, ¬e2)) == 0) 428: { /* not in data base */ 429: pagein (io, body, &where); /* grab text */ 430: status |= FRMNEWS; /* through news */ 431: strcpy (note.n_from, fromsys); /* who gave it to us */ 432: i = putnote (io, &where, title, status, ¬e, &auth, 433: NOPOLICY, NOLOCKIT, NOADDID, fromsys, ADDTIME); 434: io -> nnotrcvd++; /* count it */ 435: unlocknf (io, DSCRLOCK); /* MUTEX done */ 436: return (i); /* return notenum */ 437: } 438: if ((note2.n_stat & ORPHND) && (status & ORPHND) == 0) 439: { /* replace foster */ 440: /* with true parent */ 441: pagein (io, body, ¬e2.n_addr); /* the text */ 442: gettime (¬e2.n_rcvd); /* update timestamp */ 443: gettime (¬e2.n_lmod); /* time stamp it */ 444: copyauth (&auth, ¬e2.n_auth); /* correct author */ 445: note2.n_stat = status | FRMNEWS; /* and status bits */ 446: strncpy (note2.ntitle, title, TITLEN); 447: note2.n_date = entered; 448: strcpy (note2.n_from, fromsys); 449: putnrec (io, notenum, ¬e2); /* and replace */ 450: io -> adopted++; /* count adoption */ 451: io -> nnotrcvd++; /* count in */ 452: unlocknf (io, DSCRLOCK); 453: dprintf ("Orphaned response chain adopted\n"); 454: return (notenum); /* note number */ 455: } 456: else 457: dprintf ("Duplicate note handed back by news\n"); 458: unlocknf (io, DSCRLOCK); 459: return (0); /* mark resolved */ 460: 461: case 'R': /* response */ 462: if (sscanf (header -> nline1, "#R:%99[^:]:%ld:%99[^:]:%ld:%o:%d", 463: field1, ¬e.n_id.uniqid, field2, 464: &respid.uniqid, &status, &count) != 6) 465: { 466: return (-1); /* no good */ 467: } 468: strncpy (note.n_id.sys, field1, SYSSZ); /* copy them */ 469: strncpy (respid.sys, field2, SYSSZ); /* both and */ 470: note.n_id.sys[SYSSZ - 1] = respid.sys[SYSSZ - 1] = '\0';/* stop */ 471: status |= FRMNEWS; /* it's been there */ 472: 473: getperms (io, 1, respid.sys); /* check modes */ 474: if (allow (io, RESPOK) == 0) /* not a chance */ 475: return (0); /* resolved */ 476: 477: p = header -> nline2; /* second line */ 478: for (i = 0; (i < HOMESYSSZ - 1) && (*p != '!' && *p != '\0'); i++) 479: auth.asystem[i] = *p++; /* get the author */ 480: auth.asystem[i] = '\0'; /* terminate */ 481: while (*p != '!' && *p != '\0') 482: p++; /* skip to end of system */ 483: if (*p == '!') 484: p++; /* skip the ! */ 485: for (i = 0; (i < NAMESZ - 1) && (*p != ' ' && *p != '\0'); i++) 486: auth.aname[i] = *p++; /* parse author */ 487: auth.aname[i] = '\0'; /* terminate */ 488: auth.aid = Anonuid; /* default */ 489: while (*p != ' ' && *p) 490: p++; /* rest of author */ 491: while (*p == ' ') /* find the date */ 492: p++; 493: parsetime (p, &entered); /* and parse it */ 494: 495: locknf (io, DSCRLOCK); /* MUTEX */ 496: notenum = chknote (io, ¬e.n_id, ¬e2); 497: if (notenum == 0) /* found parent? */ 498: { /* build foster */ 499: dprintf ("Orphaned response handed in by news\n"); 500: strcpy (note.n_from, fromsys); /* make basic info */ 501: note.n_nresp = 0; 502: note.n_auth.aid = Anonuid; 503: strcpy (note.n_auth.aname, "Unknown"); 504: strcpy (note.n_auth.asystem, note.n_id.sys);/* system */ 505: note.n_date = entered; 506: gettime (&whentime); /* current time */ 507: fosterstat = ORPHND | FRMNEWS; /* combo there */ 508: #ifdef notdef 509: strcpy (note.ntitle, "(Orphan) "); /* prefix */ 510: #else 511: strcpy (note.ntitle, ""); /* empty */ 512: #endif 513: i = strlen (note.ntitle); /* index */ 514: for (p = header -> title; i < TITLEN && *p; i++, p++)/* rest of title */ 515: note.ntitle[i] = *p; /* basic title */ 516: if (i < TITLEN) 517: note.ntitle[i] = '\0'; /* null it */ 518: else 519: note.ntitle[TITLEN - 1] = '\0'; /* null */ 520: where.addr = 0; /* no text */ 521: where.textlen = 0; /* still no text */ 522: notenum = putnote (io, &where, note.ntitle, fosterstat, 523: ¬e, ¬e.n_auth, NOPOLICY, NOLOCKIT, NOADDID, 524: fromsys, ADDTIME); /* insert him */ 525: io -> norphans++; /* orphan census */ 526: getnrec (io, notenum, ¬e2); /* get good one */ 527: } 528: /* 529: * At this point we know we have a parent because if there wasn't 530: * one before, we built a foster parent. 531: */ 532: if (chkresp (io, &respid, ¬e2, notenum) == 0) 533: { /* none, insert it */ 534: status |= FRMNEWS; 535: pagein (io, body, &where); 536: i = putresp (io, &where, status, notenum, &entered, &auth, 537: ¬e, NOLOCKIT, &respid, NOADDID, fromsys, 538: ADDTIME, &whentime); 539: io -> nrsprcvd++; /* count him in */ 540: unlocknf (io, DSCRLOCK); /* UNMUTEX */ 541: return (i); /* resp number */ 542: } 543: else 544: dprintf ("Duplicate response handed back by news\n"); 545: unlocknf (io, DSCRLOCK); 546: return (0); /* resolved */ 547: 548: default: /* bad news */ 549: return (-1); 550: } /* NOTREACHED */ 551: return (0); 552: } 553: 554: /* 555: * bnewsgen(&io,&header,&FILE) 556: * 557: * parse an article that came through B-news. We've already 558: * checked to see if it was a notesfile generated article 559: * so all we have to do is decide if it's a note/response 560: * and put it in the appropriate place. 561: */ 562: 563: bnewsgen (io, header, body) 564: struct io_f *io; 565: struct hbuf *header; 566: FILE * body; 567: { 568: register int i; 569: char *p; 570: struct note_f note; 571: struct note_f note2; 572: struct when_f whentime; 573: struct daddr_f where; 574: int notenum; 575: int status; 576: char pbuf[BUFLEN]; /* scratch */ 577: long newsseq; 578: char newssys[SYSSZ]; 579: struct id_f newsid; 580: struct auth_f auth; 581: char *lead, 582: *trail; /* references */ 583: char basesys[SYSSZ]; /* references */ 584: long baseseq; /* ditto */ 585: struct id_f baseid; /* ditto ditto */ 586: char field1[100], /* scanf tmps */ 587: field2[100]; 588: 589: getperms (io, 1, origsys); 590: if (allow (io, WRITOK) == 0) /* let him* */ 591: { 592: fprintf (stderr, "System %s not allowed to write notes\n", origsys); 593: return (0); /* NO! */ 594: } 595: 596: i = sscanf (header -> ident, "<%ld@%99[^>]>", &newsseq, field1, pbuf); 597: if (i < 2) /* try old */ 598: { 599: i = sscanf (header -> ident, "%99[^.].%ld", field1, &newsseq); 600: } 601: /* 602: * new tricks with saving the entire message id in the 603: * system portion of the id_f structure 604: */ 605: if (i < 2 && index (header -> ident, ':') == (char *) NULL) 606: { /* not unpacked yet */ 607: newsseq = strlen (header -> ident); /* save length */ 608: if (newsseq < SYSSZ) /* all fits */ 609: { 610: strcpy (field1, header -> ident); /* entire id */ 611: } 612: else 613: { /* too long */ 614: #ifdef NFMAINT 615: char pbuf[BUFSIZ]; 616: #endif NFMAINT 617: 618: strncpy (field1, header -> ident, SYSSZ); 619: field1[SYSSZ - 1] = '\0'; /* truncate */ 620: dprintf ("Chopped %d byte message id '%s' to '%s'\n", 621: newsseq, header -> ident, field1); 622: #ifdef NFMAINT 623: if (ShowTruncated) /* log it */ 624: { 625: sprintf (pbuf, 626: "%d byte Message-ID: '%s' truncated to '%s'\nPath: %s\nFrom: %s\nNewsgroups: %s\n", 627: newsseq, header -> ident, field1, 628: header -> path, header -> from, header -> nbuf); 629: nfcomment (NFMAINT, pbuf, "Truncated Message-ID", 0, 0); 630: } 631: #endif NFMAINT 632: } 633: newsseq = -newsseq; /* make it < 0 */ 634: i = 2; /* mark done */ 635: } 636: if (i < 2) /* no id */ 637: { 638: #ifdef NFMAINT 639: char pbuf[BUFSIZ]; 640: 641: sprintf (pbuf, 642: "Message-ID: %s\nPath: %s\nFrom: %s\nNewsgroups: %s\n", 643: header -> ident, header -> path, 644: header -> from, header -> nbuf); 645: nfcomment (NFMAINT, pbuf, "UnManageable Message-ID", 0, 0); 646: #endif NFMAINT 647: dprintf ("can't fathom Message-ID: %s\n", header -> ident); 648: return (-1); /* mark bogus */ 649: } 650: strncpy (newssys, field1, SYSSZ); /* copy */ 651: newssys[SYSSZ - 1] = '\0'; /* and truncate */ 652: 653: note.n_date = entered; 654: strcpy (note.n_from, fromsys); 655: strncpy (auth.aname, authname, NAMESZ); /* fill in author */ 656: strncpy (auth.asystem, origsys, HOMESYSSZ); /* system */ 657: auth.asystem[HOMESYSSZ - 1] = auth.aname[NAMESZ - 1] = '\0'; 658: auth.aid = Anonuid; 659: status = FRMNEWS; /* came through news */ 660: strncpy (title, header -> title, TITLEN); /* move new title */ 661: title[TITLEN - 1] = '\0'; /* sure it stops */ 662: 663: locknf (io, DSCRLOCK); /* MUTEX */ 664: /* 665: * first thing is to see if it's a base note somewhere. 666: */ 667: strcpy (newsid.sys, newssys); /* build uniq id */ 668: strcpy (note.n_id.sys, newssys); /* build descriptor */ 669: note.n_id.uniqid = newsid.uniqid = newsseq; 670: notenum = chknote (io, ¬e.n_id, ¬e2); /* try normal */ 671: if (notenum == 0) /* try -100 trick */ 672: { 673: note.n_id.uniqid = newsid.uniqid = newsseq * -100; 674: notenum = chknote (io, ¬e.n_id, ¬e2); 675: if (notenum == 0) /* restore number */ 676: { 677: note.n_id.uniqid = newsid.uniqid = newsseq; 678: } 679: } 680: if (notenum != 0) 681: { 682: if (!(note2.n_stat & ORPHND)) 683: { 684: dprintf ("Duplicate news article received\n"); 685: io -> nnotdrop++; /* count as dropped */ 686: unlocknf (io, DSCRLOCK); 687: return (0); /* done with it */ 688: } 689: /* 690: * replace foster parent 691: */ 692: pagein (io, body, ¬e2.n_addr); /* collect text */ 693: gettime (¬e2.n_rcvd); /* current tod */ 694: gettime (¬e2.n_lmod); /* last touched */ 695: copyauth (&auth, note2.n_auth); /* fill in author */ 696: note2.n_stat |= FRMNEWS; /* brand it */ 697: strncpy (note2.ntitle, title, TITLEN); /* move title */ 698: note2.n_date = entered; 699: strcpy (note2.n_from, fromsys); /* who sent it to us */ 700: putnrec (io, notenum, ¬e2); /* and replace */ 701: io -> adopted++; /* count it */ 702: io -> nnotrcvd++; /* count in */ 703: unlocknf (io, DSCRLOCK); 704: dprintf ("Orphaned Response Chain adopted\n"); 705: return (notenum); /* correctly placed */ 706: } 707: 708: /* 709: * See if we can turn this into a response to some base note. 710: * First priority is to match it to any of the articles listed 711: * in a References field if there is one. 712: */ 713: 714: notenum = 0; /* init to not found */ 715: if (header -> followid[0]) /* references */ 716: { 717: trail = header -> followid; 718: while ((lead = index (trail, '<')) && (trail = index (lead, '>'))) 719: { /* delimited id */ 720: i = sscanf (lead, "<%ld@%99[^>]>", &baseseq, field1, pbuf); 721: if (i < 2) /* try old format */ 722: i = sscanf (lead, "%99[^.].%ld", field1, &baseseq); 723: if (i < 2) 724: continue; /* try next one */ 725: strncpy (basesys, field1, SYSSZ); 726: basesys[SYSSZ - 1] = '\0'; /* and truncate */ 727: 728: strcpy (baseid.sys, basesys); /* build goal */ 729: baseid.uniqid = baseseq; /* try notes source */ 730: if ((notenum = chknote (io, &baseid, ¬e2)))/* WANT ASSIGN */ 731: break; /* yes! */ 732: 733: baseid.uniqid = baseseq * -100; /* try news source */ 734: if ((notenum = chknote (io, &baseid, ¬e2)))/* WANT ASSIGN */ 735: break; /* yes! */ 736: 737: notenum = 0; /* ensure "unfound" */ 738: } 739: } 740: 741: /* 742: * If References did any good, "notenum" is positive non-zero. 743: * Otherwise it didn't help out at all and we have to resort to 744: * parsing the title for "re:" prefixes 745: * If we can find a base title, use the title search code to 746: * scan for it. 747: */ 748: 749: if (notenum == 0 && /* not found */ 750: !strncmp (header -> title, "re: ", 4) || /* and looks like */ 751: !strncmp (header -> title, "Re: ", 4) || /* a response */ 752: !strncmp (header -> title, "RE: ", 4)) 753: { 754: dprintf ("Looking at titles\n"); 755: p = header -> title; 756: do 757: { 758: for (p += 3; *p == ' ' || *p == '\t'; p++); /* drop spaces */ 759: } while (!strncmp (p, "re: ", 4) || 760: !strncmp (p, "Re: ", 4) || 761: !strncmp (p, "RE: ", 4)); 762: strncpy (io -> xstring, p, TITLEN); /* load it */ 763: io -> xstring[TITLEN - 1] = '\0'; /* and terminate it */ 764: notenum = findtitle (io, io -> descr.d_nnote, FALSE);/* start at back */ 765: if (notenum > 0) /* found one */ 766: getnrec (io, notenum, ¬e2); /* get a ptr to it */ 767: } 768: 769: /* 770: * OK. By now, we have a "notenum" if the article can be pegged 771: * as a response to one of our notes. 772: * Otherwise, notenum==0 and we'll have to turn it into 773: * a base note. 774: */ 775: 776: if (notenum > 0) 777: { 778: dprintf ("Looking in response chain for note %d\n", notenum); 779: if (!chkresp (io, &newsid, ¬e2, notenum)) 780: { /* no copy here */ 781: pagein (io, body, &where); 782: gettime (&whentime); 783: i = putresp (io, &where, status, notenum, &entered, &auth, ¬e, 784: NOLOCKIT, &newsid, NOADDID, fromsys, ADDTIME, &whentime); 785: unlocknf (io, DSCRLOCK); /* un-MUTEX */ 786: return (i); 787: } 788: else 789: { /* copy there */ 790: unlocknf (io, DSCRLOCK); /* all done */ 791: dprintf ("Duplicate Response handed back by news\n"); 792: io -> nrspdrop++; /* bong it */ 793: return (0); /* count as done */ 794: } 795: } 796: /* 797: * If we are going to do things this way, here is the point 798: * where we should check about turning a news-generated 799: * article into an orphaned response. 800: * 801: * Basically, look for a non-empty references line and 802: * make a foster parent with the first article id on that 803: * line. 804: */ 805: 806: /* 807: * by this point, it's obvious that we can't turn the note into 808: * a response. We can skip the check to see if it is already 809: * there because we did that at the very top of this loop 810: * and since we've locked the notesfile up while we're doing this, 811: * we know that nobody added a note. 812: */ 813: dprintf ("Processing article as a base note\n"); 814: pagein (io, body, &where); 815: notenum = putnote (io, &where, title, status, ¬e, 816: &auth, NOPOLICY, NOLOCKIT, NOADDID, fromsys, ADDTIME); 817: io -> nnotrcvd++; /* count it */ 818: unlocknf (io, DSCRLOCK); 819: return (notenum); 820: }