/* * This OS/2 port was hacked by Harald Kipp from the * * Network News Transfer Protocol server * * Phil Lapsley * University of California, Berkeley * Stan Barber * Baylor College of Medicine * * Bug reports related to THIS modified version should be sent to * * harald@os2point.ping.de * harald@sesam.com * Fido: 2:2448/434 * */ #define OS2 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "nntp.h" #include "globals.h" #include "changi.h" #ifdef LOG int nn_told = 0; int nn_took = 0; #endif int seekuntil(FILE * fp, char *akey, char *line, int linesize); int get_histlist(char *array[], char *list); int distmatch(char *distlist[], int distcount, char *grouplist[], int groupcount); int getword(FILE * fp, char *w, char *line, int linesize); int compare(char *s, char *t); /* * NEWNEWS newsgroups date time ["GMT"] [] * * Return the message-id's of any news articles past * a certain date and time, within the specified distributions. * */ void newnews(PNEWSCLIENT pnc, int argc, char *argv[]) { char *cp, *ngp; char *cpo; char *key; char datebuf[32]; char line[MAXBUFLEN]; char *histlist[20]; int ngcount = 0; int histcount; int all; FILE *fp; long date; FILE *tmplst; char tmpfile[80]; if (argc < 4) { so_printf(pnc -> s, "%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [].\r\n", ERR_CMDSYN); lprintf("%s: Syntax error in newnews command", pnc->remotehost); return; } if (!pnc -> canread) { so_printf(pnc -> s, "%d You do not have permission to read. Sorry.\r\n", ERR_ACCESS); lprintf("%s: Illegal read access", pnc->remotehost); return; } all = (argv[1][0] == '*' && argv[1][1] == '\0'); if (!all) { ngcount = get_nglist(&pnc -> nglist, argv[1]); if (ngcount == 0) { so_printf(pnc -> s, "%d Bogus newsgroup specifier: %s\r\n", ERR_CMDSYN, argv[1]); lprintf("%s: Bad newsgroup in newnews command", pnc->remotehost); return; } } if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) { so_printf(pnc -> s, "%d Date/time must be in form YYMMDD HHMMSS.\r\n", ERR_CMDSYN); lprintf("%s: Bad date in newnews command", pnc->remotehost); return; } strcpy(datebuf, argv[2]); strcat(datebuf, argv[3]); argc -= 4; argv += 4; key = datebuf; /* Unless they specify GMT */ date = dtol(datebuf); if (date < 0) { so_printf(pnc -> s, "%d Invalid date specification.\r\n", ERR_CMDSYN); lprintf("%s: Bad date in newnews command", pnc->remotehost); return; } if (argc > 0) { if (!stricmp(*argv, "GMT")) { /* Which we handle here */ date = gmt_to_local(date); ++argv; --argc; } } /* * We convert from local to GMT since this is what history file expects */ date = local_to_gmt(date); ltod(date, datebuf); if (argc > 0) { pnc->distcount = get_distlist(&pnc->dist_list, *argv); if (pnc->distcount < 0) { so_printf(pnc -> s, "%d Bad distribution list: %s\r\n", ERR_CMDSYN, *argv); lprintf("%s: Bad distribution list in newnews command", pnc->remotehost); return; } } else pnc->distcount = 0; /* * This might grow very large. We do not use the tmp * directory which could be defined in RAM. */ strcpy(tmpfile, "/liXXXXXX"); if (mktemp(tmpfile) == NULL) { so_printf(pnc -> s, "%d Cannot create temp name.\r\n", ERR_FAULT); return; } if ((tmplst = fopen(tmpfile, "w+")) == NULL) { lperror(tmpfile); so_printf(pnc -> s, "%d Cannot open temp file.\r\n", ERR_FAULT); return; } fp = xopen(cfg.historyfile, "r"); if (fp == NULL) { char *histpag = malloc(strlen(cfg.historyfile) + 5); strcat(strcpy(histpag, cfg.historyfile), ".pag"); fp = xopen(histpag, "r"); free(histpag); } if(fp == NULL) { lperror(cfg.historyfile); fclose(tmplst); so_printf(pnc -> s, "%d Cannot open history file.\r\n", ERR_FAULT); return; } if (seekuntil(fp, key, line, sizeof(line)) < 0) { fclose(tmplst); fclose(fp); so_printf(pnc -> s, "%d Cannot seek history file.\r\n", ERR_FAULT); return; } /* * Every line in the history file looks like: * * <3me19f$s4@sun.net> 800838279 661 comp.robotics:216,comp.sys.dec:81 * ^---------^---^---spaces */ do { if ((cp = strchr(line, ' ')) == NULL) continue; if ((cpo = strchr(cp + 1, ' ')) == NULL) continue; if ((ngp = strchr(cpo + 1, ' ')) == NULL) continue; ++ngp; /* Points at newsgroup list */ if (*ngp == '\n') continue; histcount = get_histlist(histlist, ngp); if (histcount == 0) continue; /* * For each newsgroup on this line in the history file, * check it against the newsgroup names we're given. * If it matches, then see if we're hacking distributions. * If so, open the file and match the distribution line. */ if (!all) if (!ngmatch(restreql, 0, pnc -> nglist, ngcount, histlist, histcount)) continue; if (pnc->distcount) if (!distmatch(pnc->dist_list, pnc->distcount, histlist, histcount)) continue; *cp = '\0'; fputs(line, tmplst); fputc('\n', tmplst); } while (fgets(line, sizeof(line), fp) != NULL); fclose(fp); so_printf(pnc -> s, "%d New news by message id follows\r\n", OK_NEWNEWS); rewind(tmplst); while (fgets(line, sizeof(line), tmplst) != NULL) if (line[0] == '<') { if ((cp = strchr(line, '\n')) != NULL) *cp = '\0'; if(so_puts(pnc -> s, line) == -1) break; if(so_puts(pnc -> s, "\r\n") == -1) break; } so_puts(pnc -> s, ".\r\n"); fclose(tmplst); unlink(tmpfile); } /* * seekuntil -- seek through the history file looking for * a line with date later than "akey". Get that line, and return. * * Parameters: "fp" is the active file. * "akey" is the date, in form YYMMDDHHMMSS * "line" is storage for the first line we find. * * Returns: -1 on error, 0 otherwise. * * Side effects: Seeks in history file, modifies line. */ int seekuntil(FILE * fp, char *akey, char *line, int linesize) { char datetime[32]; int c; long top, bot, mid; bot = 0; fseek(fp, 0L, SEEK_END); top = ftell(fp); for (;;) { mid = (top + bot) / 2; fseek(fp, mid, SEEK_SET); do { c = getc(fp); mid++; } while (c != EOF && c != '\n'); if (!getword(fp, datetime, line, linesize)) return (-1); switch (compare(akey, datetime)) { case -2: case -1: case 0: if (top <= mid) break; top = mid; continue; case 1: case 2: bot = mid; continue; } break; } fseek(fp, bot, SEEK_SET); while (ftell(fp) < top) { if (!getword(fp, datetime, line, linesize)) return (-1); switch (compare(akey, datetime)) { case -2: case -1: case 0: break; case 1: case 2: continue; } break; } return (0); } int compare(char *s, char *t) { for (; *s == *t; s++, t++) if (*s == 0) return (0); return (*s == 0 ? -1 : *t == 0 ? 1 : *s < *t ? -2 : 2); } /* * Combined B and C news version of getword. */ int getword(FILE * fp, char *w, char *line, int linesize) { char *cp; if (fgets(line, linesize, fp) == NULL) return (0); *w = '\0'; /* in case of bad format */ if ((cp = strchr(line, ' ')) != NULL) { /* find 2nd field */ char *endp; while (*cp == ' ' || *cp == '\t') cp++; endp = strchr(cp, ' '); if (endp == NULL) return (1); *endp = '\0'; ltod(atol(cp), w); *endp = ' '; } return (1); } /* * distmatch -- see if a file matches a set of distributions. * We have to do this by (yech!) opening the file, finding * the Distribution: line, if it has one, and seeing if the * things match. * * Parameters: "distlist" is the distribution list * we want. * "distcount" is the count of distributions in it. * "grouplist" is the list of groups (articles) * for this line of the history file. Note that * this isn't quite a filename. * "groupcount" is the count of groups in it. * * Returns: 1 if the article is in the given distribution. * 0 otherwise. */ int distmatch(char *distlist[], int distcount, char *grouplist[], int groupcount) { char c; char *cp; FILE *fp; int i, j; char buf[MAXBUFLEN]; strcpy(buf, cfg.newsdir); strcat(buf, "\\"); strcat(buf, grouplist[0]); for (cp = buf; *cp; cp++) if (*cp == '.') *cp = '\\'; fp = xopen(buf, "rt"); if (fp == NULL) { lperror(buf); return (0); } while (fgets(buf, sizeof(buf), fp) != NULL) { if ((c = buf[0]) == '\n') /* End of header */ break; if (c != 'd' && c != 'D') continue; cp = strchr(cp + 1, '\n'); if (cp) *cp = '\0'; cp = strchr(buf, ':'); if (cp == NULL) continue; *cp = '\0'; if (!stricmp(buf, "distribution")) { for (i = 0; i < distcount; ++i) { if (!stricmp(cp + 2, distlist[i])) { fclose(fp); return (1); } } fclose(fp); return (0); } } fclose(fp); /* * We've finished the header with no distribution field. So we'll assume that the distribution * is the characters up to the first dot in the newsgroup name. */ for (i = 0; i < groupcount; i++) { cp = strchr(grouplist[i], '.'); if (cp) *cp = '\0'; for (j = 0; j < distcount; j++) if (!stricmp(grouplist[i], distlist[j])) return (1); } return (0); } /* * get_histlist -- return a nicely set up array of newsgroups * (actually, net.foo.bar/article_num) along with a count. * * Parameters: "array" is storage for our array, * set to point at some static data. * "list" is the history file newsgroup list. * * Returns: Number of group specs found. * * Side effects: Changes static data area. * Also puts null bytes in "list" * */ int get_histlist(char *hist_list[], char *list) { int histcount = 0; for (;;) { for (; *list == ' ' || *list == '\t'; list++) ; if (*list == '\0' || *list == '\n') break; if (histcount < 20) hist_list[histcount++] = list; for (; *list && *list != ',' && *list != '\n'; list++) ; if (*list) *(list++) = '\0'; } hist_list[histcount] = (char *)NULL; return (histcount); } /* * get_nglist -- return a nicely set up array of newsgroups * along with a count, when given an NNTP-spec newsgroup list * in the form ng1,ng2,ng... * * Parameters: "array" is storage for our array, * set to point at some static data. * "list" is the NNTP newsgroup list. * * Returns: Number of group specs found. * * Side effects: Changes static data area. */ int get_nglist(char ***array, char *list) { char *cp; int ngcount; for (cp = list; *cp != '\0'; ++cp) if (*cp == ',') *cp = ' '; ngcount = parsit(list, array); return (ngcount); }