/*
* UTIL/DSYNCGROUPS.C
*
* dsyncgroups -h remotehost [-a] [-o] [-D] [-N[B,E,R]] [-g] [-i] [-m] [-w wildcard] [-p port] [-f/F dactive.kp]
*
* (c)Copyright 1998, Matthew Dillon, All Rights Reserved. Refer to
* the COPYRIGHT file in the base directory of this distribution
* for specific rights granted.
*/
#include "defs.h"
typedef struct Group {
struct Group *gr_Next;
int gr_State;
int gr_StartNo;
int gr_StartDiff;
int gr_EndNo;
int gr_EndDiff;
int gr_SynNo;
int gr_SynDiff;
int gr_NoCTS;
int gr_NoLMTS;
char *gr_GroupName;
char *gr_Flags;
char *gr_Description;
} Group;
#define GRF_DESCRIPTION 0x0001
#define GRF_STARTNO 0x0002
#define GRF_ENDNO 0x0004
#define GRF_FLAGS 0x0008
#define GRF_SYNNO 0x0010
#define GRF_LMTS 0x0020 /* last modified time stamp */
#define GRF_CTS 0x0040 /* creation time stamp */
#define GRF_FROMLOCAL 0x0800
#define GRF_NEW 0x1000
#define GRF_FROMREMOTE 0x2000
#define GRF_MODIFIED 0x8000
#define GHSIZE 1024
#define GHMASK (GHSIZE-1)
FILE *Fi;
FILE *Fo;
Group *GHash[GHSIZE];
KPDB *KDBActive;
int SyncOverwriteOpt = 0; /* allow remote info to replace existing info */
int SyncDeleteOpt = 0; /* delete local info not present on remote */
int SyncGroupsOpt = 0; /* synchronize newsgroup names */
int SyncDescrOpt = 0; /* synchronize newsgroup descriptions */
int SyncModStatusOpt = 0; /* synchronize newsgroup moderation status */
int SyncArtNumbersBegOpt = 0; /* synchronize article numbers */
int SyncArtNumbersEndOpt = 0; /* synchronize article numbers */
int SyncArtNumbersSynOpt = 0; /* synchronize article numbers */
int SyncArtNumbersRange = 0; /* relative sync beginning based on range */
int SyncArtNumbersAddition = 0; /* add this when syncing ending article no. */
int SyncArtNumbersMaxPerc = 0; /* max % value to increase upwards */
int VerboseOpt = 0;
int ForReal = 1;
char *SyncModStatusFlag = NULL;
char *BindHost = NULL;
char *BindPort = NULL;
void Usage(void);
void processLine(char *cmd, char *wild, int *count, int *ok);
char *allocTmpCopy(const char *buf, int bufLen);
Group *EnterGroup(int pass, const char *, int, int, int, int, int, const char *, const char *);
int ConnectToHost(const char *host, int port);
int CommandResponse(const char *cmd, char **pres);
int hash(const char *str);
int SetField(char **pptr, const char *str);
void
Usage(void)
{
fprintf(stderr, "dsyncgroups -h remotehost | -G filename [-p port] [-B hostname] [-w wild] [-f/F file.kp] [-a] [-o] [-g] [-i] [-m] [-M c] [-D] [-N[B,E,X,R]] [-X[EX]] [-n#] [-v] [-z]\n");
fprintf(stderr, " -h remotehost = the host that we connect to\n");
fprintf(stderr, " -G filename = specify an active file to use as input\n");
fprintf(stderr, " -p port = port on remote host (default: 119)\n");
fprintf(stderr, " -B bindhost = interface to bind to\n");
fprintf(stderr, " -w wild = only update groups matching wildmat (default: *)\n");
fprintf(stderr, " -f file.kp = specify the active to update (Default: dactive.kp)\n");
fprintf(stderr, " -F file.kp = create active file if it doesn't exist\n");
fprintf(stderr, " -a = shortcut for -o, -g, -i and -m\n");
fprintf(stderr, " -o = overwrite description\n");
fprintf(stderr, " -g = add missing groups\n");
fprintf(stderr, " -i = sync newsgroup description\n");
fprintf(stderr, " -m = update moderation status\n");
fprintf(stderr, " -M c = update moderation status to the specified flag\n");
fprintf(stderr, " -D = delete local groups in not on remote\n");
fprintf(stderr, " -N = sync begin and end numbers\n");
fprintf(stderr, " -NB = sync begin numbers\n");
fprintf(stderr, " -NE = sync end numbers\n");
fprintf(stderr, " -NX = sync end numbers but only upwards\n");
fprintf(stderr, " -u = Log into remotehost using this password\n");
fprintf(stderr, " -U = Log into remotehost using this username\n");
fprintf(stderr, " -XE = sync NX field - feeder sync\n");
fprintf(stderr, " -XX = sync NX but only upwards\n");
fprintf(stderr, " -n# = if we sync end number then increase local value by remote+#\n");
fprintf(stderr, " -N# = don't sync end number more than #\n");
fprintf(stderr, " -v = be more verbose about what is being done\n");
fprintf(stderr, " -z = don't actually make changes\n");
exit(1);
}
int
main(int ac, char **av)
{
int i;
int ocreate = 0;
char *host = NULL;
char *wild = NULL;
char *dbfile = NULL;
char *grpfile = NULL;
char *username = NULL;
char *password = NULL;
int port = 119;
LoadDiabloConfig(ac, av);
for (i = 1; i < ac; ++i) {
char *p;
char *ptr = av[i];
if (*ptr != '-') {
fprintf(stderr, "Unexpected argument: %s\n", ptr);
exit(1);
}
ptr += 2;
switch(ptr[-1]) {
case 'a':
SyncOverwriteOpt = 1;
SyncGroupsOpt = 1;
SyncDescrOpt = 1;
SyncModStatusOpt = 1;
break;
case 'B':
if (*ptr == 0)
ptr = av[++i];
if ((p = strrchr(ptr, ':')) != NULL) {
*p++ = 0;
BindPort = p;
BindHost = strdup(SanitiseAddr(ptr));
} else {
BindHost = strdup(SanitiseAddr(ptr));
}
break;
case 'C':
if (*ptr == 0)
++i;
break;
case 'D':
SyncDeleteOpt = 1;
break;
case 'd':
DebugOpt = (*ptr) ? strtol(ptr, NULL, 0) : 1;
break;
case 'F':
ocreate = O_CREAT;
/* fall through */
case 'f':
dbfile = (*ptr) ? ptr : av[++i];
break;
case 'G':
grpfile = (*ptr) ? ptr : av[++i];
break;
case 'g':
SyncGroupsOpt = 1;
break;
case 'i':
SyncDescrOpt = 1;
break;
case 'h':
host = (*ptr) ? ptr : av[++i];
break;
case 'm':
SyncModStatusOpt = 1;
break;
case 'M':
SyncModStatusOpt = 1;
SyncModStatusFlag = (*ptr) ? ptr : av[++i];
break;
case 'N':
if (*ptr == 0) {
SyncArtNumbersBegOpt = 1;
SyncArtNumbersEndOpt = 1;
}
while (*ptr) {
if (*ptr == 'B')
SyncArtNumbersBegOpt = 1;
if (*ptr == 'E')
SyncArtNumbersEndOpt = 1;
if (*ptr == 'X')
SyncArtNumbersEndOpt = 2;
if (*ptr == 'R')
SyncArtNumbersRange = 1;
++ptr;
}
break;
case 'n':
SyncArtNumbersAddition = strtol((*ptr) ? ptr : av[++i], NULL, 0);
break;
case 'o':
SyncOverwriteOpt = 1;
break;
case 'P':
SyncArtNumbersMaxPerc = strtol((*ptr) ? ptr : av[++i], NULL, 0);
break;
case 'p':
ptr = (*ptr) ? ptr : av[++i];
port = strtol(ptr, NULL, 0);
break;
case 'U':
username = (*ptr) ? ptr : av[++i];
break;
case 'u':
password = (*ptr) ? ptr : av[++i];
break;
case 'w':
wild = (*ptr) ? ptr : av[++i];
break;
case 'X':
if (*ptr == 0) {
SyncArtNumbersSynOpt = 1;
}
while (*ptr) {
if (*ptr == 'E')
SyncArtNumbersSynOpt = 1;
if (*ptr == 'X')
SyncArtNumbersSynOpt = 2;
++ptr;
}
break;
case 'V':
PrintVersion();
break;
case 'v':
VerboseOpt = 1;
break;
case 'z':
ForReal = 0;
break;
default:
fprintf(stderr, "Unknown option: %s\n", ptr - 2);
break;
}
}
if (host == NULL && grpfile == NULL) {
if (ac == 1)
Usage();
fprintf(stderr, "Missing host/filename option\n");
exit(1);
}
if (port <= 0) {
fprintf(stderr, "Illegal port option\n");
exit(1);
}
if (wild && strlen(wild) > 128) {
fprintf(stderr, "Wildcard too large\n");
exit(1);
}
/*
* open dactive.kp file
*/
if (VerboseOpt)
printf("%s local active file\n",
ocreate ? "Loading/creating" : "Loading");
if (dbfile) {
KDBActive = KPDBOpen(dbfile, O_RDWR|ocreate);
} else {
KDBActive = KPDBOpen(PatDbExpand(ReaderDActivePat), O_RDWR|ocreate);
}
if (KDBActive == NULL) {
printf("Unable to open/create dactive.kp\n");
exit(1);
}
/*
* scan dactive.kp
*/
{
int recLen;
int recOff;
int saveSyncGroupsOpt = SyncGroupsOpt;
SyncGroupsOpt = 1; /* force new Group structures to be created */
for (recOff = KPDBScanFirst(KDBActive, 0, &recLen);
recOff;
recOff = KPDBScanNext(KDBActive, recOff, 0, &recLen)
) {
int groupLen;
int flagsLen;
const char *rec = KPDBReadRecordAt(KDBActive, recOff, 0, NULL);
const char *group = KPDBGetField(rec, recLen, NULL, &groupLen, NULL);
const char *flags = KPDBGetField(rec, recLen, "S", &flagsLen, "y");
const char *desc = KPDBGetFieldDecode(rec, recLen, "GD", NULL, NULL);
int begNo = strtol(KPDBGetField(rec, recLen, "NB", NULL, "-1"), NULL, 10);
int endNo = strtol(KPDBGetField(rec, recLen, "NE", NULL, "-1"), NULL, 10);
int synNo = strtol(KPDBGetField(rec, recLen, "NX", NULL, "-1"), NULL, 10);
int noCTS = !(int)strtoul(KPDBGetField(rec, recLen, "CTS", NULL, "0"), NULL, 16);
int noLMTS = !(int)strtoul(KPDBGetField(rec, recLen, "LMTS", NULL, "0"), NULL, 16);
Group *grp;
if (group)
group = allocTmpCopy(group, groupLen);
if (flags)
flags = allocTmpCopy(flags, flagsLen);
if (desc)
desc = allocTmpCopy(desc, strlen(desc));
/*
* ignore bad group or group that does not match the wildcard
*/
if (group == NULL)
continue;
if (wild && WildCmp(wild, group) != 0)
continue;
grp = EnterGroup(
1,
group,
begNo,
endNo,
synNo,
noCTS,
noLMTS,
flags,
desc
);
grp->gr_State &= ~(GRF_NEW|GRF_MODIFIED);
grp->gr_State &= ~(GRF_CTS|GRF_LMTS);
grp->gr_State |= GRF_FROMLOCAL;
}
SyncGroupsOpt = saveSyncGroupsOpt;
}
/*
* Connect to remote host
*/
if (host != NULL)
{
int fd;
if (VerboseOpt)
printf("Connecting to %s:%d\n", host, port);
fd = ConnectToHost(host, port);
if (fd < 0) {
fprintf(
stderr,
"Unable to connect to %s:%d (%s)\n",
host,
port,
strerror(errno)
);
exit(1);
}
Fi = fdopen(fd, "r");
Fo = fdopen(dup(fd), "w");
} else {
if (VerboseOpt)
printf("Syncing with %s\n", grpfile);
Fi = fopen(grpfile, "r");
if (Fi == NULL) {
printf("Unable to open %s\n", grpfile);
exit(1);
}
Fo = NULL;
}
/*
* startup
*/
if (host != NULL)
{
char *line;
switch(CommandResponse(NULL, &line)) {
case 200: case 201:
printf("Successful connection: %s\n", line);
break;
default:
printf("Initial Response: %s\n", line);
exit(1);
}
}
/*
* login
*/
if (host != NULL && username != NULL) {
char *line;
char cmd[4096];
sprintf(cmd, "authinfo user %s",username);
switch(CommandResponse(cmd, &line)) {
case 381:
printf("authinfo accepted: %s\n", line);
break;
default:
printf("authinfo denied: %s\n", line);
exit(1);
}
}
if (host != NULL && password != NULL) {
char *line;
char cmd[4096];
sprintf(cmd, "authinfo pass %s",password);
switch(CommandResponse(cmd, &line)) {
case 281:
printf("authinfo accepted: %s\n", line);
break;
default:
printf("authinfo denied: %s\n", line);
exit(1);
}
}
/*
* mode reader
*/
if (host)
{
char *line;
switch(CommandResponse("mode reader", &line)) {
case 200: case 201:
printf("Entering reader mode: %s\n", line);
break;
default:
printf("Unable to switch to reader mode: %s\n", line);
printf("Going on anyway\n");
break;
}
}
/*
* list active [wild]
*/
if (host)
{
char *line;
char cmd[4096];
int count = 0;
int ok = 0;
sprintf(cmd, "list active%s%s", ((wild) ? " " : ""), ((wild) ? wild : ""));
switch(CommandResponse(cmd, &line)) {
case 215:
while (fgets(cmd, sizeof(cmd), Fi) != NULL) {
processLine(cmd, wild, &count, &ok);
if (ok)
break;
}
break;
default:
printf("list active command failed: %s\n", line);
break;
}
printf("%d groups returned by list active\n", count);
if (ok == 0) {
printf("Did not receive . terminator to list active command\n");
exit(1);
}
} else {
char cmd[4096];
int count = 0;
while (fgets(cmd, sizeof(cmd), Fi) != NULL)
processLine(cmd, wild, &count, NULL);
printf("%d groups found\n", count);
}
/*
* list newsgroups [wild]
*/
if (host && SyncDescrOpt)
{
char *line;
char cmd[4096];
int count = 0;
int ok = 0;
sprintf(cmd, "list newsgroups%s%s", ((wild) ? " " : ""), ((wild) ? wild : ""));
switch(CommandResponse(cmd, &line)) {
case 215:
while (fgets(cmd, sizeof(cmd), Fi) != NULL) {
char *group;
char *desc;
Group *grp;
if (strcmp(cmd, ".\r\n") == 0) {
ok = 1;
break;
}
group = strtok(cmd, " \t\r\n");
desc = strtok(NULL, "\r\n");
/*
* ignore group that does not match the wildcard, even though
* the remote end is supposed to do this for us.
*/
if (wild && WildCmp(wild, group) != 0)
continue;
if (group)
grp = EnterGroup(
2,
group,
-1,
-1,
-1,
-1,
-1,
NULL,
desc
); else grp = NULL;
if (grp)
grp->gr_State |= GRF_FROMREMOTE;
++count;
}
break;
default:
printf("list newsgroups command failed: %s\n", line);
break;
}
printf("%d groups returned by list newsgroups\n", count);
if (ok == 0) {
printf("Did not receive . terminator to list newsgroups command\n");
exit(1);
}
}
/*
* close remote connections
*/
if (host)
{
char *line;
printf("All remote commands completed, sending quit\n");
switch(CommandResponse("quit", &line)) {
case 205:
printf("quit response ok\n");
break;
default:
printf("error sending quit command: %s\n", line);
exit(1);
}
}
fclose(Fi);
if (Fo)
fclose(Fo);
printf("Writing to .kp file\n");
fflush(stdout);
/*
* Writeback
*/
{
int i;
int nowt = (int)time(NULL);
for (i = 0; i < GHSIZE; ++i) {
Group *group;
for (group = GHash[i]; group; group = group->gr_Next) {
/*
* If we have a new group not previously in the database,
* we only add it if SyncGroupsOpt is set.
*/
if (group->gr_State & GRF_NEW) {
if (SyncGroupsOpt == 0)
continue;
}
/*
* If group did not come from remote and SyncDeleteOpt is set,
* delete the group.
*/
if (!(group->gr_State & GRF_FROMREMOTE) &&
(group->gr_State & GRF_FROMLOCAL) &&
SyncDeleteOpt
) {
printf("Deleting %s\n", group->gr_GroupName);
if (ForReal)
KPDBDelete(KDBActive, group->gr_GroupName);
} else if (group->gr_State & (GRF_MODIFIED | GRF_NEW)) {
if (group->gr_State & GRF_NEW) {
printf("Creating %s", group->gr_GroupName);
} else {
printf("Updating %s", group->gr_GroupName);
}
if (group->gr_State & GRF_DESCRIPTION) {
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "GD", group->gr_Description, 0);
if (VerboseOpt)
printf(" desc='%s'", group->gr_Description);
}
if (group->gr_State & (GRF_STARTNO | GRF_NEW)) {
char startBuf[16];
sprintf(startBuf, "%010d", group->gr_StartNo);
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "NB", startBuf, 0);
if (VerboseOpt)
printf(" NB=%s(%+d)", startBuf, group->gr_StartDiff);
}
if (group->gr_State & (GRF_ENDNO | GRF_NEW)) {
char endBuf[16];
sprintf(endBuf, "%010d", group->gr_EndNo);
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "NE", endBuf, 0);
if (VerboseOpt)
printf(" NE=%s(%+d)", endBuf, group->gr_EndDiff);
}
if (group->gr_State & (GRF_SYNNO | GRF_NEW)) {
char synBuf[16];
sprintf(synBuf, "%010d", group->gr_SynNo);
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "NX", synBuf, 0);
if (VerboseOpt)
printf(" NX=%s(%+d)", synBuf, group->gr_SynDiff);
}
if (group->gr_State & GRF_CTS) {
char ctsBuf[16];
sprintf(ctsBuf, "%08x", nowt);
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "CTS", ctsBuf, 0);
if (VerboseOpt)
printf(" CTS=%s", ctsBuf);
}
if (group->gr_State & GRF_LMTS) {
char lmtsBuf[16];
sprintf(lmtsBuf, "%08x", nowt);
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "LMTS", lmtsBuf, 0);
if (VerboseOpt)
printf(" LMTS=%s", lmtsBuf);
}
if (group->gr_Flags && group->gr_State & GRF_FLAGS) {
if (ForReal)
KPDBWriteEncode(KDBActive, group->gr_GroupName, "S", group->gr_Flags, 0);
if (VerboseOpt)
printf(" S=%s",
(group->gr_Flags ? group->gr_Flags : "y"));
}
printf("\n");
}
}
}
}
return(0);
}
void
processLine(char *cmd, char *wild, int *count, int *ok)
{
char *group;
char *gbeg;
char *gend;
char *flags;
Group *grp;
if (strcmp(cmd, ".\r\n") == 0) {
if (ok)
*ok = 1;
return;
}
group = strtok(cmd, " \r\n");
gend = strtok(NULL, " \r\n");
gbeg = strtok(NULL, " \r\n");
flags = strtok(NULL, " \r\n");
/*
* ignore group that does not match the wildcard, even though
* the remote end is supposed to do this for us.
*/
if (wild && WildCmp(wild, group) != 0)
return;
if (*gend == '-' || *gbeg == '-') {
printf("Invalid group begin or end number - skipping : %s\n", group);
return;
}
grp = EnterGroup(
2,
group,
strtol(gbeg, NULL, 10),
strtol(gend, NULL, 10),
strtol(gend, NULL, 10), /* end repeated */
-1,
-1,
flags,
NULL
);
/*
* mark group as coming from remote
*/
if (grp)
grp->gr_State |= GRF_FROMREMOTE;
++*count;
}
char *
allocTmpCopy(const char *buf, int bufLen)
{
static char *SaveAry[8];
static int SaveCnt;
char **pptr;
SaveCnt = (SaveCnt + 1) % arysize(SaveAry);
pptr = &SaveAry[SaveCnt];
if (*pptr)
free(*pptr);
*pptr = malloc(bufLen + 1);
memcpy(*pptr, buf, bufLen);
(*pptr)[bufLen] = 0;
return(*pptr);
}
Group *
EnterGroup(int pass, const char *groupName, int begNo, int endNo, int synNo, int noCTS, int noLMTS, const char *flags, const char *desc)
{
Group **pgroup = &GHash[hash(groupName)];
Group *group;
while ((group = *pgroup) != NULL) {
if (strcmp(groupName, group->gr_GroupName) == 0)
break;
pgroup = &group->gr_Next;
}
if (group == NULL) {
/*
* ignore groups not already in the dactive.kp file if SyncGroupsOpt is not
* set.
*/
if (SyncGroupsOpt == 0)
return(NULL);
*pgroup = group = calloc(sizeof(Group) + strlen(groupName) + 1, 1);
group->gr_State = GRF_NEW | GRF_LMTS | GRF_CTS;
group->gr_GroupName = (char *)(group + 1);
group->gr_NoCTS = 1;
group->gr_NoLMTS = 1;
group->gr_StartNo = 1;
strcpy(group->gr_GroupName, groupName);
}
/*
* update fields
*/
if (synNo >= 0) {
if (pass == 1) {
group->gr_SynNo = synNo;
} else if (SyncArtNumbersSynOpt) {
group->gr_State |= GRF_SYNNO;
if (group->gr_SynNo != synNo) {
if (SyncArtNumbersSynOpt != 2 || synNo > group->gr_SynNo) {
int perc;
if (group->gr_SynNo == 0)
group->gr_SynNo = 1;
group->gr_SynDiff = (synNo + SyncArtNumbersAddition) -
group->gr_SynNo;
perc = group->gr_SynDiff * 100 / group->gr_SynNo;
if (SyncArtNumbersMaxPerc && group->gr_SynNo &&
(group->gr_SynDiff > 0) &&
(perc > SyncArtNumbersMaxPerc))
group->gr_SynDiff = SyncArtNumbersMaxPerc *
group->gr_SynNo / 100;
if (group->gr_SynDiff == 0)
group->gr_SynDiff = 1;
group->gr_SynNo += group->gr_SynDiff;
group->gr_State |= GRF_MODIFIED;
}
}
}
}
if (endNo >= 0) {
if (pass == 1) {
group->gr_EndNo = endNo;
} else if (SyncArtNumbersEndOpt) {
group->gr_State |= GRF_ENDNO;
if (group->gr_EndNo != endNo) {
if (SyncArtNumbersEndOpt != 2 || endNo > group->gr_EndNo) {
int perc;
if (group->gr_EndNo == 0)
group->gr_EndNo = 1;
group->gr_EndDiff = (synNo + SyncArtNumbersAddition) -
group->gr_EndNo;
perc = group->gr_EndDiff * 100 / group->gr_EndNo;
if (SyncArtNumbersMaxPerc && group->gr_EndNo &&
(group->gr_EndDiff > 0) &&
(perc > SyncArtNumbersMaxPerc))
group->gr_EndDiff = SyncArtNumbersMaxPerc *
group->gr_EndNo / 100;
if (group->gr_EndDiff == 0)
group->gr_EndDiff = 1;
group->gr_EndNo += group->gr_EndDiff;
group->gr_NoLMTS = 1;
group->gr_State |= GRF_MODIFIED;
}
}
}
}
if (begNo >= 0) {
if (pass == 1) {
group->gr_StartNo = begNo;
} else if (SyncArtNumbersBegOpt ||
(SyncArtNumbersRange && (group->gr_State & GRF_ENDNO) && endNo > 0)
) {
if (SyncArtNumbersRange) {
/*
* Set beginning based on ending minus the difference
* between the remote ending and beginning.
*/
begNo = group->gr_EndNo - (endNo - begNo);
if (begNo < group->gr_StartNo)
begNo = group->gr_StartNo;
if (begNo > group->gr_EndNo)
begNo = group->gr_EndNo;
}
if (group->gr_StartNo != begNo) {
group->gr_State |= GRF_STARTNO;
group->gr_State |= GRF_MODIFIED;
}
group->gr_StartDiff = begNo - group->gr_StartNo;
group->gr_StartNo = begNo;
}
}
if (flags) {
if (pass == 1) {
SetField(&group->gr_Flags, flags);
} else if ((SyncOverwriteOpt && SyncModStatusOpt) ||
(group->gr_State & GRF_NEW)) {
group->gr_State |= GRF_FLAGS;
if (SetField(&group->gr_Flags,
SyncModStatusFlag ? SyncModStatusFlag : flags))
group->gr_State |= GRF_MODIFIED;
}
}
if (desc) {
if (pass == 1) {
SetField(&group->gr_Description, desc);
} else if ((SyncOverwriteOpt && SyncDescrOpt) ||
(SyncDescrOpt && (group->gr_State & GRF_NEW))) {
group->gr_State |= GRF_DESCRIPTION;
if (SetField(&group->gr_Description, desc))
group->gr_State |= GRF_MODIFIED;
}
}
if (noCTS >= 0 && group->gr_NoCTS != noCTS) {
group->gr_NoCTS = noCTS;
if (pass > 1)
group->gr_State |= GRF_MODIFIED | GRF_CTS;
}
if (noLMTS >= 0 && group->gr_NoLMTS != noLMTS) {
group->gr_NoLMTS = noLMTS;
if (pass > 1)
group->gr_State |= GRF_MODIFIED | GRF_LMTS;
}
return(group);
}
int
ConnectToHost(const char *host, int port)
{
int fd;
struct sockaddr_in lsin;
struct sockaddr_in rsin;
bzero(&lsin, sizeof(lsin));
bzero(&rsin, sizeof(rsin));
lsin.sin_port = 0;
if (BindPort != NULL) {
struct servent *sen;
int port;
if ((port = strtol(BindPort, NULL, 0)) != 0) {
lsin.sin_port = htons(port);
} else {
if ((sen = getservbyname(BindPort, "tcp")) != NULL) {
lsin.sin_port = sen->s_port;
} else {
fprintf(stderr, "Unknown service: %s\n", BindPort);
exit(1);
}
}
}
lsin.sin_family = AF_INET;
if (BindHost == NULL) {
lsin.sin_addr.s_addr = INADDR_ANY;
} else {
if (strtol(BindHost, NULL, 0) > 0) {
lsin.sin_addr.s_addr = inet_addr(BindHost);
} else {
struct hostent *he;
if ((he = gethostbyname(BindHost)) != NULL) {
lsin.sin_addr = *(struct in_addr *)he->h_addr;
} else {
fprintf(stderr, "Unknown bind host: %s\n", BindHost);
exit(1);
}
}
}
errno = 0;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return(-1);
if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) {
close(fd);
return(-1);
}
rsin.sin_port = htons(port);
rsin.sin_family = AF_INET;
{
struct hostent *he;
if ((he = gethostbyname(host)) != NULL) {
memcpy(&rsin.sin_addr, he->h_addr, he->h_length);
} else {
rsin.sin_addr.s_addr = inet_addr(host);
if (rsin.sin_addr.s_addr == INADDR_NONE) {
printf("host %s lookup failure\n", host);
close(fd);
return(-1);
}
}
}
if (DebugOpt) {
fprintf(stderr, "Connecting to %s (%s)\n", host, inet_ntoa(rsin.sin_addr));
fflush(stderr);
}
if (connect(fd, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) {
if (DebugOpt) {
fprintf(stderr, "connection failed: %s\n", strerror(errno));
fflush(stderr);
}
close(fd);
return(-1);
}
if (DebugOpt) {
fprintf(stderr, "connection success\n");
fflush(stderr);
}
return(fd);
}
int
CommandResponse(const char *cmd, char **pres)
{
static char buf[4096];
if (DebugOpt && cmd) {
fprintf(stderr, ">> %s\n", cmd);
fflush(stderr);
}
if (cmd)
fprintf(Fo, "%s\r\n", cmd);
fflush(Fo);
if (fgets(buf, sizeof(buf), Fi) != NULL) {
if (DebugOpt) {
fprintf(stderr, "<< %s", buf);
fflush(stderr);
}
if (pres)
*pres = buf;
return(strtol(buf, NULL, 10));
} else if (DebugOpt) {
fprintf(stderr, "<< (EOF)\n");
fflush(stderr);
}
return(0);
}
int
hash(const char *str)
{
unsigned int hv = 0xA432BCDD;
while (*str) {
hv = (hv << 5) ^ *str ^ (hv >> 23);
++str;
}
hv ^= (hv >> 16);
return(hv & GHMASK);
}
int
SetField(char **pptr, const char *str)
{
if (*pptr && strcmp(*pptr, str) == 0)
return(0);
if (*pptr)
free(*pptr);
*pptr = strcpy(malloc(strlen(str) + 1), str);
return(1);
}
syntax highlighted by Code2HTML, v. 0.9.1