/*
* GROUPCTL.C
*
* Create/Modify/Delete newsgroups in the active file
*
*/
#include "dreaderd/defs.h"
#define MAXCMDARGS 8
const char *GrpCtlCancel(char *article);
const char *GrpCtlGroupInfo(char *group);
const char *GrpCtlListActive(char *match);
const char *GrpCtlListGroupHash(char *match, char *hash, int fname);
const char *GrpCtlListNewsgroups(char *match);
const char *GrpCtlNewGroup(int ac, char **av, int pos);
const char *GrpCtlRmGroup(char *group);
const char *GrpCtlAdjust(int ac, char **av, int pos);
const char *GrpCtlCheckGroups(int ac, char **av, int pos);
KPDB *KDBActive;
typedef struct GrpList {
char *group;
struct GrpList *next;
} GrpList;
void
Usage(void)
{
printf("Usage:\n");
printf(" dgrpctl -s to use server active file (defaults to reader)\n");
printf(" dgrpctl listactive [PATTERN]\n");
printf(" - list the contents of active file\n");
printf(" dgrpctl listnewsgroups [PATTERN]\n");
printf(" - list the newsgroups and their descriptions\n");
printf(" dgrpctl listgrouphash [PATTERN [HASH]]\n");
printf(" - list the hashes of newsgroup names\n");
printf(" dgrpctl listgrouphashfile [PATTERN [HASH]]\n");
printf(" - list the index path/filename of a newsgroup\n");
printf(" dgrpctl groupinfo NEWSGROUP\n");
printf(" - display detailed information about a newsgroup\n");
printf(" dgrpctl rmgroup NEWSGROUP\n");
printf(" - remove the specified newsgroup\n");
printf(" dgrpctl newgroup NEWSGROUP [FLAGS] [MODERATOR] [DESCRIPTION]\n");
printf(" - add/modify the specified newsgroup\n");
printf(" flags = 'y' or 'm' (default is 'y')\n");
printf(" moderator = moderator email address or \"\"\n");
printf(" description = group description\n");
printf(" dgrpctl adjust NEWSGROUP NB|NE|NX value\n");
printf(" - adjust one of the specified numbers for group\n");
printf(" dgrpctl checkgroups [exec] filename|-\n");
printf(" - parse the checkgroups list and print changes required\n");
printf(" exec = actually make all the necessary changes\n");
printf(" - = read list on stdin\n");
printf("\n");
}
int
main(int ac, char **av)
{
int i = 1;
const char *activefile;
LoadDiabloConfig(ac, av);
activefile = PatDbExpand(ReaderDActivePat);
while (av[i] && av[i][0] == '-') {
switch (av[i][1]) {
case 'V':
PrintVersion();
break;
case 's':
activefile = PatDbExpand(ServerDActivePat);
break;
default:
Usage();
}
i++;
}
KDBActive = KPDBOpen(activefile, O_RDWR);
if (!KDBActive) {
printf("Unable to open active file: %s\n", activefile);
exit(1);
}
if (av[i] && av[i+1] && strcmp(av[i], "newgroup") == 0)
GrpCtlNewGroup(ac, av, i+1);
else if (av[i] && av[i+1] && strcmp(av[i], "modgroup") == 0)
GrpCtlNewGroup(ac, av, i+1);
else if (av[i] && av[i+1] && strcmp(av[i], "rmgroup") == 0)
GrpCtlRmGroup(av[i+1]);
else if (av[i] && strcmp(av[i], "listactive") == 0)
GrpCtlListActive(av[i+1]);
else if (av[i] && strcmp(av[i], "listgrouphash") == 0)
GrpCtlListGroupHash(av[i+1], av[i+1] ? av[i+2] : NULL, 0);
else if (av[i] && strcmp(av[i], "listgrouphashfile") == 0)
GrpCtlListGroupHash(av[i+1], av[i+1] ? av[i+2] : NULL, 1);
else if (av[i] && strcmp(av[i], "listnewsgroups") == 0)
GrpCtlListNewsgroups(av[i+1]);
else if (av[i] && strcmp(av[i], "cancel") == 0)
GrpCtlCancel(av[i+1]);
else if (av[i] && strcmp(av[i], "groupinfo") == 0)
GrpCtlGroupInfo(av[i+1]);
else if (av[i] && strcmp(av[i], "adjust") == 0)
GrpCtlAdjust(ac, av, i+1);
else if (av[i] && strcmp(av[i], "checkgroups") == 0)
GrpCtlCheckGroups(ac, av, i+1);
else {
Usage();
}
KPDBClose(KDBActive);
return(0);
}
/*
* CANCEL -
*/
const char *
GrpCtlCancel(char *article)
{
#if 0
char *group;
int artNo;
OverInfo *ov;
MyGroupHome = strdup(PatExpand(GroupHomePat));
if ((group = strchr(article, ':')) == NULL) {
printf(">> cancel: Invalid group:artno (%s)\n", article);
return(NULL);
}
*group++ = '\0';
artNo = atoi(group);
group = article;
if (ValidGroupName(group) < 0) {
printf(">> cancel: Illegal newsgroup name\n");
return(NULL);
}
if (artNo <= 0) {
printf(">> cancel: Illegal article number\n");
return(NULL);
}
ov = GetOverInfo(group);
CancelOverArt(ov, artNo);
#endif
return(NULL);
}
/*
* GROUPINFO -
*/
const char *
GrpCtlGroupInfo(char *group)
{
int recLen;
const char *rec;
int nb;
int iter = 0;
if (ValidGroupName(group) < 0) {
printf(">> groupinfo: Illegal newsgroup name\n");
return(NULL);
}
if ((rec = KPDBReadRecord(KDBActive, group, 0, &recLen)) == NULL) {
printf(">> groupinfo: Unable to access group active data\n");
return(NULL);
} else {
const char *flags;
int n;
int flen;
char buf[MAXGNAME];
printf("%s\n", group);
n = strtol(KPDBGetField(rec, recLen, "NE", NULL, "0"), NULL, 10);
printf(" NE=%010d ", n);
nb = strtol(KPDBGetField(rec, recLen, "NB", NULL, "0"), NULL, 10);
printf("NB=%010d ", nb);
n = strtol(KPDBGetField(rec, recLen, "NX", NULL, "0"), NULL, 10);
printf("NX=%010d ", n);
flags = KPDBGetField(rec, recLen, "S", &flen, "n");
bcopy(flags, buf, flen);
buf[flen] = 0;
printf("flag=%s ", buf);
iter = strtol(KPDBGetField(rec, recLen, "ITER", NULL, "0"), NULL, 10);
printf("ITER=%d\n", iter);
n = strtol(KPDBGetField(rec, recLen, "CTS", NULL, "0"), NULL, 16);
printf(" CTS=%u=%s", n, ctime((const time_t *)&n));
n = strtol(KPDBGetField(rec, recLen, "LMTS", NULL, "0"), NULL, 16);
printf(" LMTS=%u=%s", n, ctime((const time_t *)&n));
flags = KPDBGetField(rec, recLen, "GD", &flen, "?");
bcopy(flags, buf, flen);
buf[flen] = 0;
printf(" GD=%s\n", buf);
}
{
int fd;
int maxarts;
int pos;
char path[PATH_MAX];
OverHead oh;
OverArt oa;
struct stat st;
const char *gname = GFName(group, GRPFTYPE_OVER, 0, 1, iter,
&DOpts.ReaderGroupHashMethod);
printf(" grouphash=%s\n", GFHash(group, &DOpts.ReaderGroupHashMethod));
snprintf(path, sizeof(path), "%s/%s", PatExpand(GroupHomePat), gname);
printf(" overfile=%s\n", path);
if ((fd = open(path, O_RDONLY)) < 0) {
printf(" Unable to open %s\n", path);
return(NULL);
}
if (read(fd, &oh, sizeof(oh)) != sizeof(oh)) {
printf(" Error reading over header data\n");
close(fd);
return(NULL);
}
if (oh.oh_Version != OH_VERSION ||
oh.oh_ByteOrder != OH_BYTEORDER) {
printf(" Wrong version or byte order\n");
close(fd);
return(NULL);
}
fstat(fd, &st);
maxarts = (st.st_size - oh.oh_HeadSize) / sizeof(OverArt);
printf(" overfilesize=%u maxarts=%u\n", (unsigned)st.st_size,
maxarts);
pos = oh.oh_HeadSize + ((nb & 0x7FFFFFFF) % maxarts) *
sizeof(OverArt);
lseek(fd, pos, 0);
if (read(fd, &oa, sizeof(oa)) != sizeof(oa)) {
printf(" Unable to read OverArt\n");
close(fd);
return(NULL);
}
if (oa.oa_ArtNo > 0) {
printf(" StartNo=%u\n", oa.oa_ArtNo);
} else if (oa.oa_ArtNo == -1) {
printf(" Article cancelled\n");
} else if (oa.oa_ArtNo == -2) {
printf(" Article expired\n");
} else {
printf(" Article not found\n");
}
if (oa.oa_ArtNo != nb) {
printf(" artNoMismatch (got=%d wanted=%d)\n", oa.oa_ArtNo, nb);
}
printf(" Time received: %d = %s", oa.oa_TimeRcvd,
ctime((time_t *)&oa.oa_TimeRcvd));
}
return(NULL);
}
/*
* LISTACTIVE -
*/
const char *
GrpCtlListActive(char *match)
{
int recLen;
int recOff;
for (recOff = KPDBScanFirst(KDBActive, 0, &recLen);
recOff;
recOff = KPDBScanNext(KDBActive, recOff, 0, &recLen)
) {
int groupLen;
char grpbuf[MAXGNAME];
const char *rec = KPDBReadRecordAt(KDBActive, recOff, 0, NULL);
const char *group = KPDBGetField(rec, recLen, NULL, &groupLen, NULL);
if (group) {
if (groupLen >= MAXGNAME)
groupLen = MAXGNAME - 1;
bcopy(group, grpbuf, groupLen);
grpbuf[groupLen] = 0;
if (match == NULL || WildCmp(match, grpbuf) == 0) {
const char *flags;
int ne;
int nb;
int flen;
flags = KPDBGetField(rec, recLen, "S", &flen, "n");
ne = strtol(KPDBGetField(rec, recLen, "NE", NULL, "0"), NULL, 10);
nb = strtol(KPDBGetField(rec, recLen, "NB", NULL, "0"), NULL, 10);
printf("%s %010d %010d ", grpbuf, ne, nb);
bcopy(flags, grpbuf, flen);
grpbuf[flen] = 0;
printf("%s\n", grpbuf);
}
}
}
return(NULL);
}
/*
* LISTGROUPHASH -
*/
const char *
GrpCtlListGroupHash(char *match, char *hash, int dir)
{
int recLen;
int recOff;
int wild = 1;
if (hash != NULL)
SetGroupHashMethod(hash, &DOpts.ReaderGroupHashMethod);
if (match != NULL && index(match, '?') == NULL && index(match, '*') == NULL)
wild = 0;
for (recOff = KPDBScanFirst(KDBActive, 0, &recLen);
wild && recOff;
recOff = KPDBScanNext(KDBActive, recOff, 0, &recLen)
) {
int groupLen;
char grpbuf[MAXGNAME];
const char *rec = KPDBReadRecordAt(KDBActive, recOff, 0, NULL);
const char *group = KPDBGetField(rec, recLen, NULL, &groupLen, NULL);
if (group) {
if (groupLen >= MAXGNAME)
groupLen = MAXGNAME - 1;
bcopy(group, grpbuf, groupLen);
grpbuf[groupLen] = 0;
if (match == NULL || WildCmp(match, grpbuf) == 0) {
if (dir)
printf("%s %s\n",
GFName(grpbuf, GRPFTYPE_OVER, 0, 1, 0,
&DOpts.ReaderGroupHashMethod),
grpbuf
);
else
printf("%s %s\n",
GFHash(grpbuf, &DOpts.ReaderGroupHashMethod), grpbuf);
}
}
}
if (!wild) {
if (dir)
printf("%s %s\n",
GFName(match, GRPFTYPE_OVER, 0, 1, 0,
&DOpts.ReaderGroupHashMethod),
match
);
else
printf("%s %s\n",
GFHash(match, &DOpts.ReaderGroupHashMethod),
match);
}
return(NULL);
}
/*
* LISTNEWSGROUPS -
*/
const char *
GrpCtlListNewsgroups(char *match)
{
int recLen;
int recOff;
for (recOff = KPDBScanFirst(KDBActive, 0, &recLen);
recOff;
recOff = KPDBScanNext(KDBActive, recOff, 0, &recLen)
) {
int groupLen;
char grpbuf[MAXGNAME];
const char *rec = KPDBReadRecordAt(KDBActive, recOff, 0, NULL);
const char *group = KPDBGetField(rec, recLen, NULL, &groupLen, NULL);
if (group) {
if (groupLen >= MAXGNAME)
groupLen = MAXGNAME - 1;
bcopy(group, grpbuf, groupLen);
grpbuf[groupLen] = 0;
if (match == NULL || WildCmp(match, grpbuf) == 0) {
const char *desc;
desc = KPDBGetFieldDecode(rec, recLen, "GD", NULL, NULL);
printf("%s\t%s\n", grpbuf, (desc != NULL) ? desc : "?");
}
}
}
return(NULL);
}
/*
* NEWGROUP -
*/
const char *
GrpCtlNewGroup(int ac, char **av, int pos)
{
char *flags;
char *moderator = NULL;
char description[256];
char *group = NULL;
int isNew = 0;
int hasCts = 0;
const char *rec;
int recLen;
description[0] = 0;
group = av[pos++];
if ((flags = av[pos++]) == NULL)
flags = "y";
else {
if (av[pos]) {
moderator = av[pos++];
if (strcmp(moderator, "\"\"") == 0)
moderator = NULL;
}
if (av[pos])
strcpy(description, av[pos]);
}
if (ValidGroupName(group) < 0) {
printf(">> Newgroup: Illegal newsgroup name\n");
return(NULL);
}
if (flags && strlen(flags) != 1) {
printf(">> Newgroup: Illegal flag: %s \n", flags);
return(NULL);
}
/*
* Read and lock the record. If the record does not exist, create a new
* record (and lock that).
*/
if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) {
KPDBWrite(KDBActive, group, "NB", "0000000001", KP_LOCK);
KPDBWrite(KDBActive, group, "NE", "0000000000", KP_LOCK_CONTINUE);
isNew = 1;
} else {
if (KPDBGetField(rec, recLen, "CTS", NULL, NULL) != NULL)
hasCts = 1;
}
if (moderator) {
SanitizeString(moderator);
KPDBWriteEncode(KDBActive, group, "M", moderator, KP_LOCK_CONTINUE);
}
if (description) {
SanitizeDescString(description);
KPDBWriteEncode(KDBActive, group, "GD", description, KP_LOCK_CONTINUE);
}
{
/*
* add creation-time-stamp and last-modified-time-stamp
* for group.
*/
char tsBuf[64];
sprintf(tsBuf, "%08x", (int)time(NULL));
if (hasCts == 0)
KPDBWrite(KDBActive, group, "CTS", tsBuf, KP_LOCK_CONTINUE);
KPDBWrite(KDBActive, group, "LMTS", tsBuf, KP_LOCK_CONTINUE);
}
KPDBWrite(KDBActive, group, "S", flags, KP_UNLOCK);
if (isNew) {
printf(">> Newgroup: Created new group %s flags=%s\n", group, flags );
} else
printf(">> Newgroup: updated group %s flags=%s moderator=%s description=%s\n",
group,
flags,
(moderator ? moderator : "no chg"),
(description ? description : "no chg")
);
return(NULL);
}
const char *
GrpCtlRmGroup(char *options)
{
const char *rec;
int recLen;
char *group;
group = options;
if (ValidGroupName(group) < 0) {
printf(">> Rmgroup: Illegal newsgroup name\n");
return(NULL);
}
/*
* Note that the record isn't locked in this case.
*/
if ((rec = KPDBReadRecord(KDBActive, group, 0, &recLen)) != NULL) {
KPDBDelete(KDBActive, group);
printf(">> RmGroup: Deleted group %s\n", group);
} else {
printf(">> RmGroup: No group %s\n", group);
}
return(NULL);
}
/*
* ADJUST -
*/
const char *
GrpCtlAdjust(int ac, char **av, int pos)
{
char *field;
char *group = NULL;
int adjust = 0;
int oldval = 0;
const char *rec;
int recLen;
if ((group = av[pos++]) == NULL) {
printf(">> adjust: missing newsgroup\n");
return(NULL);
}
if ((field = av[pos++]) == NULL) {
printf(">> adjust: missing field to adjust\n");
return(NULL);
}
if ((av[pos]) == NULL) {
printf(">> adjust: missing adjust value\n");
return(NULL);
}
adjust = strtol(av[pos++], NULL, 0);
if (ValidGroupName(group) < 0) {
printf(">> adjust: Illegal newsgroup name\n");
return(NULL);
}
if (strcmp(field, "NB") != 0 && strcmp(field, "NE") != 0 &&
strcmp(field, "NX") != 0) {
printf(">> adjust: Illegal field: %s \n", field);
return(NULL);
}
/*
* Read and lock the record. If the record does not exist, create a new
* record (and lock that).
*/
if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) != NULL) {
char buf[32];
oldval = strtol(KPDBGetField(rec, recLen, field, NULL, "0"), NULL, 10);
sprintf(buf, "%010d", oldval + adjust);
KPDBWrite(KDBActive, group, field, buf, KP_LOCK);
} else {
printf(">> adjust: group '%s' not found\n", group);
return(NULL);
}
printf(">> adjust: %s for %s adjusted from %d to %d\n", field, group,
oldval, oldval + adjust);
return(NULL);
}
/*
* CHECKGROUPS -
*/
const char *
GrpCtlCheckGroups(int ac, char **av, int pos)
{
char *filename;
int exec = 0;
FILE *f;
char buf[128];
const char *rec;
int recLen;
GrpList *grpList = NULL;
char *hierarchy = NULL;
if (av[pos] != NULL && strcmp(av[pos], "exec") == 0) {
pos++;
exec = 1;
}
if ((filename = av[pos++]) == NULL) {
printf(">> checkgroups: missing filename\n");
return(NULL);
}
if (strcmp(filename, "-") == 0) {
f = stdin;
} else {
f = fopen(filename, "r");
if (f == NULL) {
printf(">> checkgroups: cannot open %s\n", filename);
return(NULL);
}
}
while (fgets(buf, sizeof(buf), f) != NULL) {
char *newsgroup;
char *description = NULL;
char *flags = "y";
if ((newsgroup = strtok(buf, " \t\r\n")) == NULL)
continue;
if (ValidGroupName(newsgroup) < 0) /* valid group name */
continue;
if (strchr(newsgroup, '.') == NULL) /* sanity check */
continue;
if ((description = strtok(NULL, "\r\n")) == NULL)
continue;
if (hierarchy == NULL) {
char *p;
hierarchy = (char *)malloc(strlen(newsgroup) + 2);
strcpy(hierarchy, newsgroup);
p = strchr(hierarchy, '.');
if (p != NULL)
*p = 0;
strcat(hierarchy, ".*");
}
/*
* clean up the description
*/
SanitizeDescString(description);
{
int l = strlen(description);
while (*description == ' ' || *description == '\t') {
++description;
--l;
}
while (l > 0 && (description[l-1] == ' ' || description[l-1] == '\t')) {
description[--l] = 0;
}
}
if (strstr(description, "(Moderated)") != 0)
flags = "m";
else
flags = "y";
/*
* Keep a list of all the newsgroups to check for deleted groups
*/
{
GrpList *gl = (GrpList *)malloc(sizeof(GrpList));
gl->next = grpList;
gl->group = strdup(newsgroup);
grpList = gl;
}
if ((rec = KPDBReadRecord(KDBActive, newsgroup, KP_LOCK, &recLen)) == NULL) {
if (exec) {
KPDBWrite(KDBActive, newsgroup, "NB", "0000000001", KP_LOCK);
KPDBWrite(KDBActive, newsgroup, "NE", "0000000000",
KP_LOCK_CONTINUE);
printf(">> Checkgroups: Added group %s\n", newsgroup);
} else {
printf("dgrpctl newgroup %s %s \"\" \"%s\"\n",
newsgroup,
flags,
description);
}
} else {
const char *p;
char buf[MAXGNAME];
int plen;
int needflags = 0;
int needdesc = 0;
p = KPDBGetField(rec, recLen, "S", &plen, "n");
bcopy(p, buf, plen);
buf[plen] = 0;
if (strcmp(buf, flags) != 0)
needflags = 1;
p = KPDBGetFieldDecode(rec, recLen, "GD", NULL, NULL);
if (p != NULL)
strcpy(buf, p);
else
buf[0] = 0;
if (p == NULL || strcmp(buf, description) != 0)
needdesc = 1;
if (needflags || needdesc) {
if (exec) {
KPDBWrite(KDBActive, newsgroup, "S", flags, KP_UNLOCK);
KPDBWriteEncode(KDBActive, newsgroup, "GD", description,
KP_LOCK_CONTINUE);
printf(">> Checkgroups: Modified group %s\n", newsgroup);
} else {
printf("dgrpctl modgroup %s %s \"\" \"%s\"\n",
newsgroup,
flags,
description);
}
}
}
}
{
int recLen;
int recOff;
for (recOff = KPDBScanFirst(KDBActive, 0, &recLen);
recOff;
recOff = KPDBScanNext(KDBActive, recOff, 0, &recLen)
) {
int groupLen;
char grpbuf[MAXGNAME];
const char *rec = KPDBReadRecordAt(KDBActive, recOff, 0, NULL);
const char *group = KPDBGetField(rec, recLen, NULL, &groupLen, NULL);
if (group) {
if (groupLen >= MAXGNAME)
groupLen = MAXGNAME - 1;
bcopy(group, grpbuf, groupLen);
grpbuf[groupLen] = 0;
if (WildCmp(hierarchy, grpbuf) == 0) {
GrpList *g;
int found = 0;
for (g = grpList; g != NULL; g = g->next) {
if (strcmp(grpbuf, g->group) == 0) {
found = 1;
break;
}
}
if (!found) {
if (exec) {
const char *rec;
if ((rec = KPDBReadRecord(KDBActive, grpbuf, 0, &recLen)) != NULL) {
KPDBDelete(KDBActive, grpbuf);
printf(">> Checkgroups: Deleted group %s\n", grpbuf);
}
} else {
printf("dgrpctl rmgroup %s\n", grpbuf);
}
}
}
}
}
}
return(NULL);
}
syntax highlighted by Code2HTML, v. 0.9.1