/* * This part was hacked by Harald Kipp * * Bug reports should be sent to * * harald@os2point.ping.de * harald@haport.sesam.com * Fido: 2:2448/434 * * This module contains routines to deal with the active file. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct { char *tag; /* string pointer to group name */ long hi; /* highest message number */ long lo; /* lowest message number */ char post[2]; /* "y"=can post, "n"=cannot post, "m"=moderated */ } ACTIVEGROUP; static char *actbuf; static int num_ag; static ACTIVEGROUP *aga; int act_cmp(); /************************************************************************/ int grp_cmp(ACTIVEGROUP *ptr1, ACTIVEGROUP *ptr2) { return (stricmp(ptr1->tag, ptr2->tag)); } int act_cmp(char **ptr1, char **ptr2) { return (strcmp(*ptr1, *ptr2)); } /************************************************************************/ /* */ /* load_active */ /* */ /* Reads the active file into a sorted array in static memory. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to read. */ /* ------------ ------------------------------------------------------- */ /* Return value Number of newsgroups read. Zero on error. */ /* */ /************************************************************************/ int load_active(const char *activefile) { int i; int fh; char *cp, *cp1; long flen; size_t slen; /* * If we're reloading, free up previously allocated memory. */ if (num_ag != 0) { free(aga); free(actbuf); } /* * Read the whole file into a single buffer */ if((fh = sopen(activefile, O_RDONLY, SH_DENYNO, S_IREAD)) < 0) { lperror(activefile); return (0); } if((flen = filelength(fh)) == -1) { lperror(activefile); close(fh); return (0); } slen = (size_t)flen; if((long)slen != flen) { lprintf("Active file too big"); close(fh); return (0); } actbuf = malloc(slen + 1); if ((slen = read(fh, actbuf, slen)) == -1) { lperror(activefile); close(fh); return (0); } close(fh); *(actbuf + slen) = '\0'; /* * Count the number of lines and allocate the active group array */ for(i = 0, cp = actbuf; *cp; cp++) if(*cp == '\n') { i++; } aga = malloc(i * sizeof(ACTIVEGROUP)); /* * Fill the group array */ for(i = 0, cp = actbuf; cp;) { cp1 = cp; while(*cp && *cp != '\n') { if(*cp == ' ' || *cp == '\t') { *cp++ = '\0'; if(sscanf(cp, "%ld %ld %1s\n", &aga[i].hi, &aga[i].lo, aga[i].post) == 3) { aga[i].tag = cp1; if(aga[i].lo == 0) aga[i].lo = 1; i++; } break; } cp++; } if((cp = strchr(cp, '\n')) != NULL) cp++; } qsort(aga, i, sizeof(ACTIVEGROUP), grp_cmp); return (num_ag = i); } /************************************************************************/ /* */ /* write_active */ /* */ /* Writes the active file from static memory back to the disk. This is */ /* the local work horse for save_active. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to write. */ /* ------------ ------------------------------------------------------- */ /* Return value Zero if OK, -1 otherwise. */ /* */ /************************************************************************/ static int wsave_active(const char *activefile) { int rc = 0; FILE *fp; register int i; if((fp = xopen(activefile, "wt")) != NULL) { for(i = 0; i < num_ag; i++) { if(fprintf(fp, "%s %ld %ld %c\n", aga[i].tag, aga[i].hi, aga[i].lo, aga[i].post[0]) <= 0) { lperror(activefile); rc = -1; break; } } fclose(fp); } else { lperror(activefile); rc = -1; } return(rc); } /************************************************************************/ /* */ /* save_active */ /* */ /* Writes the active file from static memory back to the disk. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to write. */ /* ------------ ------------------------------------------------------- */ /* Return value Zero if OK, -1 otherwise. */ /* */ /************************************************************************/ int save_active(const char *activefile) { int rc; char *activetemp = maketemp(malloc(_MAX_PATH), "active.tmp"); if((rc = wsave_active(activetemp)) == 0) rc = file_copy(activetemp, activefile, "bm"); else rc = wsave_active(activefile); free(activetemp); return(rc); } /************************************************************************/ /* */ /* wadd_active */ /* */ /* Adds a new group to the active file. This is the local work horse */ /* of add_active. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to update. */ /* */ /* group Points to the string that specifies the name of the */ /* newsgroup to add. */ /* */ /* mc Modecharacter of the new group. */ /* 'y' if posting OK. */ /* 'n' if posting is disabled. */ /* 'm' if group is moderated. */ /* ------------ ------------------------------------------------------- */ /* Return value 1 if added successfully */ /* 2 if posting mode has changed */ /* 0 if group was not new */ /* -1 if update failed */ /* */ /************************************************************************/ static int wadd_active(const char *activefile, char *group, char mc) { FILE *fp; int i; int isnew = 1; if((fp = xopen(activefile, "wt")) != NULL) { for(i = 0; i < num_ag; i++) { if(isnew == 1 && stricmp(aga[i].tag, group) == 0) { if(mc != aga[i].post[0]) { aga[i].post[0] = mc; isnew = 2; lprintf("Newsgroup %s changed to %smoderated.", group, (mc == 'm') ? "" : "un"); } else { isnew = 0; lprintf("Newsgroup %s already %smoderated.", group, (mc == 'm') ? "" : "un"); } } fprintf(fp, "%s %ld %ld %c\n", aga[i].tag, aga[i].hi, aga[i].lo, aga[i].post[0]); } if(isnew == 1) { fprintf(fp, "%s 0 1 %c\n", group, mc); lprintf("Added %smoderated newsgroup %s", (mc == 'm') ? "" : "un", group); } fclose(fp); } else { lperror(activefile); isnew = -1; } return(isnew); } /************************************************************************/ /* */ /* add_active */ /* */ /* Adds a new group to the active file and appends an entry to */ /* active.time. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to update. */ /* */ /* active_times Points to the string that specifies the name of active- */ /* times-file to update. */ /* */ /* group Points to the string that specifies the name of the */ /* newsgroup to add. */ /* */ /* mc Modecharacter of the new group. */ /* 'y' if posting OK. */ /* 'n' if posting is disabled. */ /* 'm' if group is moderated. */ /* ------------ ------------------------------------------------------- */ /* Return value 1 if added successfully */ /* 2 if posting mode has changed */ /* 0 if group was not new */ /* -1 if update failed */ /* */ /************************************************************************/ int add_active(const char *activefile, const char *active_times, char *group, char mc) { int isnew; char *activetemp = maketemp(malloc(_MAX_PATH), "active.tmp"); if((isnew = wadd_active(activetemp, group, mc)) > 0) { if(file_copy(activetemp, activefile, "mb")) { isnew = -1; } } else if(isnew == 0) { unlink(activetemp); } else { isnew = wadd_active(activefile, group, mc); } free(activetemp); if(isnew > 0) reload_active(activefile); if(isnew == 1) { FILE *fp; if((fp = xopen(active_times, "at")) != NULL) { if(fprintf(fp, "%s %ld changi\n", group, local_to_gmt(time(NULL))) <= 0) lperror(active_times); fclose(fp); } else lperror(active_times); } return(isnew); } /************************************************************************/ /* */ /* wdel_active */ /* */ /* Removes a group from the active file. This is the work horse of */ /* del_active. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to read. */ /* */ /* group Points to the string that specifies the name of the */ /* newsgroup to be removed. */ /* ------------ ------------------------------------------------------- */ /* Return value 1 if removed successfully */ /* 0 if group was not found */ /* -1 if update failed */ /* */ /************************************************************************/ static int wdel_active(const char *activefile, char *group) { FILE *fp; int i; int removed = 0; if((fp = xopen(activefile, "wt")) != NULL) { for(i = 0; i < num_ag; i++) { if(stricmp(aga[i].tag, group)) fprintf(fp, "%s %ld %ld %c\n", aga[i].tag, aga[i].hi, aga[i].lo, aga[i].post[0]); else { removed = 1; lprintf("Newsgroup %s has been removed", group); } } fclose(fp); if(removed) reload_active(activefile); else lprintf("Newsgroup %s not found to remove", group); } else { lperror(activefile); removed = -1; } return(removed); } /************************************************************************/ /* */ /* del_active */ /* */ /* Removes a group from the active file. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to read. */ /* */ /* group Points to the string that specifies the name of the */ /* newsgroup to be removed. */ /* ------------ ------------------------------------------------------- */ /* Return value 1 if removed successfully */ /* 0 if group was not found */ /* -1 if update failed */ /* */ /************************************************************************/ int del_active(const char *activefile, char *group) { int removed; char *activetemp = maketemp(malloc(_MAX_PATH), "active.tmp"); if((removed = wdel_active(activetemp, group)) == 1) { if(file_copy(activetemp, activefile, "wb")) removed = -1; } else if(removed == 0) unlink(activetemp); else removed = wdel_active(activefile, group); free(activetemp); if(removed == 1) reload_active(activefile); return(removed); } /************************************************************************/ /* */ /* reload_active */ /* */ /* Rereads the active file if it has been changed since the last time */ /* this function was called. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to read. */ /* ------------ ------------------------------------------------------- */ /* Return value Number of newsgroups read. Zero on error. */ /* */ /************************************************************************/ int reload_active(const char *activefile) { static long last_mtime = 0; /* Last time active file was changed */ struct stat statbuf; if (stat((char *)activefile, &statbuf)) lperror(activefile); else { if (statbuf.st_mtime != last_mtime) { last_mtime = statbuf.st_mtime; num_ag = load_active(activefile); } } return(num_ag); } /************************************************************************/ int search_group(const char *activefile, const char *group) { int cond; int l = 0, h, m; if(activefile) reload_active(activefile); h = num_ag - 1; while (l <= h) { m = (l + h) / 2; if ((cond = stricmp(group, aga[m].tag)) < 0) h = m - 1; else if (cond > 0) l = m + 1; else { return(m); } } return (-1); } /************************************************************************/ /* */ /* find_active */ /* */ /* Used to query high and low message numbers of an active newsgroup. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* activefile Points to the string that specifies the name of active- */ /* file to read. This pointer may be NULL to avoid */ /* rereading. */ /* */ /* group Points to the string that specifies the name of the */ /* newsgroup to be find. */ /* */ /* lomsg Points to the variable receiving the lowest message */ /* number in this group. This pointer may be NULL if the */ /* caller is not interested in this value. */ /* */ /* himsg Points to the variable receiving the highest message */ /* number in this group. This pointer may be NULL if the */ /* caller is not interested in this value. */ /* ------------ ------------------------------------------------------- */ /* Return value 'y' if posting OK. */ /* 'n' if posting is disabled. */ /* 'm' if group is moderated. */ /* '\0' if group is not active. */ /* */ /************************************************************************/ char find_active(const char *activefile, char *group, long *lomsg, long *himsg) { int i; char ch = '\0'; if((i = search_group(activefile, group)) != -1) { if(himsg) *himsg = aga[i].hi; if(lomsg) *lomsg = aga[i].lo; ch = aga[i].post[0]; } return (ch); } /************************************************************************/ /* */ /* upd_active */ /* */ /* This routine is used to increment/decrement the lowest/highest */ /* message number of a group. */ /* */ /* Parameter Description */ /* ------------ ------------------------------------------------------- */ /* group Points to the string that specifies the name of the */ /* newsgroup to be updated. */ /* */ /* updlo This value is added to the lowest message number. */ /* */ /* updhi This value is added to the highest message number. */ /* ------------ ------------------------------------------------------- */ /* Return value The boolean result is 1 on success, 0 otherwise. */ /* */ /************************************************************************/ int upd_active(char *group, long updlo, long updhi) { int i; if((i = search_group(NULL, group)) != -1) { aga[i].hi += updhi; aga[i].lo += updlo; return (1); } return (0); }