/*****************************************************************************
* HPT --- FTN NetMail/EchoMail Tosser
*****************************************************************************
* Copyright (C) 1997-1999
*
* Matthias Tichy
*
* Fido: 2:2433/1245 2:2433/1247 2:2432/605.14
* Internet: mtt@tichy.de
*
* Grimmestr. 12 Buchholzer Weg 4
* 33098 Paderborn 40472 Duesseldorf
* Germany Germany
*
* This file is part of HPT.
*
* HPT is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* HPT is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HPT; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************
* $Id: seenby.c,v 1.29.2.10 2004/11/28 16:19:06 d_sergienko Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <fcommon.h>
#include <global.h>
#include <seenby.h>
#include <fidoconf/xstr.h>
#include <fidoconf/common.h>
s_seenByZone seenBysZone[MAX_ZONE];
int compare(const void *first, const void *second)
{
if ( ((s_seenBy*) first)->net < ((s_seenBy*) second)->net) return -1;
else
if ( ((s_seenBy*) first)->net > ((s_seenBy*) second)->net) return 1;
else if ( ((s_seenBy*) first)->node < ((s_seenBy*) second)->node) return -1;
else if ( ((s_seenBy*) first)->node > ((s_seenBy*) second)->node) return 1;
return 0;
}
void sortSeenBys(s_seenBy *seenBys, UINT16 count)
{
qsort(seenBys, count, sizeof(s_seenBy), compare);
}
void cleanDupesFromSeenBys(s_seenBy **seenBys, UINT16 *count)
{
UINT16 i;
s_seenBy seenBy;
if (seenBys == NULL || *seenBys == NULL || count == NULL || *count < 2)
return;
sortSeenBys(*seenBys, *count);
seenBy.net = (*seenBys)[0].net;
seenBy.node = (*seenBys)[0].node;
for (i=1;i<*count;i++) {
if ((*seenBys)[i].net == seenBy.net &&
(*seenBys)[i].node == seenBy.node)
{ /* seenby[i-1] == seenby[i] - overwrite it */
(*seenBys)[i].net = (*seenBys)[--*count].net;
(*seenBys)[i].node = (*seenBys)[--*count].node;
sortSeenBys((*seenBys), *count);
}
seenBy.net = (*seenBys)[i].net;
seenBy.node = (*seenBys)[i].node;
}
}
void cleanDupes_seenByZone()
{
UINT16 i;
for (i=0;i<MAX_ZONE;i++)
cleanDupesFromSeenBys(&(seenBysZone[i].seenByArray), (UINT16 *) &(seenBysZone[i].seenByCount));
}
void zero_seenBysZone()
{
UINT16 i;
for (i=0;i<MAX_ZONE;i++)
{
seenBysZone[i].seenByArray = NULL;
seenBysZone[i].seenByCount = 0;
}
}
void print_seenBysZone()
{
UINT16 i;
char *text;
w_log(LL_DEBUGS, "printing seen-bys...");
for (i=0;i<MAX_ZONE;i++)
{
if (seenBysZone[i].seenByCount) {
w_log(LL_DEBUGS, "printing %u seenbys of zone %u", seenBysZone[i].seenByCount, i);
text = createControlText(seenBysZone[i].seenByArray, seenBysZone[i].seenByCount, "");
w_log(LL_DEBUGS, "SEEN-BY: %s", text);
nfree(text);
}
}
}
void free_seenBysZone()
{
UINT16 i;
for (i=0;i<MAX_ZONE;i++)
nfree(seenBysZone[i].seenByArray);
zero_seenBysZone();
}
void attachTo_seenBysZone(UINT16 zone, s_seenBy **seenBys, UINT16 count)
{
seenBysZone[zone].seenByArray = *seenBys;
seenBysZone[zone].seenByCount = count;
}
void addTo_seenByZone(UINT16 zone, UINT16 net, UINT16 node)
{
UINT16 i;
s_seenBy *tmp=NULL, *tmp2=NULL;
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "adding %u:%u/%u to seen-by chain", zone, net, node);
print_seenBysZone();
#endif
if (seenBysZone[zone].seenByArray == NULL) {
i=0;
seenBysZone[zone].seenByArray = (s_seenBy *) safe_calloc(sizeof(s_seenBy), 1);
seenBysZone[zone].seenByCount++;
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "created seen-by array for zone %u", zone);
#endif
} else {
for (i=0;i<seenBysZone[zone].seenByCount;i++)
{
if (seenBysZone[zone].seenByArray[i].net == net &&
seenBysZone[zone].seenByArray[i].node == node) {
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "already found this address in sb array");
#endif
return; /* already found this address in sb array */
}
}
seenBysZone[zone].seenByCount++;
tmp = (s_seenBy *) safe_malloc(seenBysZone[zone].seenByCount * sizeof(s_seenBy));
memset(tmp, 0, sizeof(s_seenBy) * seenBysZone[zone].seenByCount);
memcpy(tmp, seenBysZone[zone].seenByArray, sizeof(s_seenBy) * (seenBysZone[zone].seenByCount-1));
tmp2 = seenBysZone[zone].seenByArray;
seenBysZone[zone].seenByArray = tmp;
nfree(tmp2);
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "enlarge sb array to 1 element, %u bytes of memory", sizeof(s_seenBy));
print_seenBysZone();
#endif
}
seenBysZone[zone].seenByArray[seenBysZone[zone].seenByCount-1].net = net;
seenBysZone[zone].seenByArray[seenBysZone[zone].seenByCount-1].node = node;
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "seenBysZone[%u].seenByCount = %u", zone, seenBysZone[zone].seenByCount);
print_seenBysZone();
#endif
}
void deleteFrom_seenByZone(UINT16 zone, UINT16 net, UINT16 node)
{
UINT16 i;
if (seenBysZone[zone].seenByArray == NULL) return;
for (i=0;i<seenBysZone[zone].seenByCount;i++)
{
if (seenBysZone[zone].seenByArray[i].net == net &&
seenBysZone[zone].seenByArray[i].node == node)
break; /* already found this address in sb array */
}
seenBysZone[zone].seenByArray[i].net = 0;
seenBysZone[zone].seenByArray[i].net = 0;
}
char *createControlText(s_seenBy seenBys[], UINT16 seenByCount, char *lineHeading)
{
#define size 81
#define addr2dSize 13
UINT16 i;
char *text=NULL, *line = NULL, addr2d[addr2dSize];
if (seenByCount==0) { /* return empty control line */
xstrcat(&text, lineHeading);
/* reserve one byte for \r */
text = (char *) safe_realloc(text, strlen(text)+2);
} else {
line = safe_malloc ((size_t) size);
sprintf(addr2d, "%u/%u", seenBys[0].net, seenBys[0].node);
text = (char *) safe_malloc((size_t) size);
text[0]='\0';
strncpy(line, lineHeading, size);
strncat(line, addr2d, size);
for (i=1; i < seenByCount; i++) {
/* fix for double seen-by's (may be after ignoreSeen) */
/* NOTE! fixed seen-by's hides shitty tossers! */
/* it is not recommended to uncomment this. */
/* if (config->ignoreSeenCount && */
/* seenBys[i-1].net == seenBys[i].net && */
/* seenBys[i-1].node == seenBys[i].node) continue; */
if (seenBys[i-1].net == seenBys[i].net)
sprintf(addr2d, " %u", seenBys[i].node);
else
sprintf(addr2d, " %u/%u", seenBys[i].net, seenBys[i].node);
if (strlen(line)+strlen(addr2d) > size-3) {
/* if line would be greater than 79 characters, make new line */
strcat(text, line);
strncat(text, "\r", size);
text = (char *) safe_realloc(text,strlen(text)+size);
strncpy(line, lineHeading, size);
/* start new line with full 2d information */
sprintf(addr2d, "%u/%u", seenBys[i].net, seenBys[i].node);
}
strcat(line, addr2d);
}
/* reserve only needed space + ending \r */
text = (char *) safe_realloc(text, strlen(text)+strlen(line)+2);
strcat(text,line);
nfree(line);
}
strncat(text, "\r", size);
return text;
}
void createSeenByArrayFromMsg(s_message *msg, s_seenBy **seenBys, UINT16 *seenByCount)
{
char *seenByText=NULL, *start = NULL, *token = NULL;
unsigned long temp;
char *endptr = NULL;
UINT16 seenByAlloced;
#ifdef DEBUG_HPT
int i;
#endif
*seenByCount = seenByAlloced = 0;
start = strrstr(msg->text, " * Origin:"); /* jump over Origin */
if (start == NULL) start = msg->text;
/* find beginning of seen-by lines */
do {
start = strstr(start, "SEEN-BY:");
if (start == NULL) return;
start += 8; /* jump over SEEN-BY: */
while (*start == ' ') start++; /* find first word after SEEN-BY: */
} while (!isdigit(*start));
/* now that we have the start of the SEEN-BY's we can tokenize the lines and read them in */
xstrcat(&seenByText, start);
token = strtok(seenByText, " \r\t\376");
for (; token != NULL; token = strtok(NULL, " \r\t\376")) {
if (isdigit(*token)) {
/* parse token */
temp = strtoul(token, &endptr, 10);
if (*endptr==':') {
token = endptr+1;
temp = strtoul(token, &endptr, 10);
}
if (*endptr && *endptr != '/')
continue;
/* get new memory */
if ((*seenByCount)++ >= seenByAlloced)
(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (seenByAlloced+=32));
if ((*endptr) == '\0') {
/* only node aka */
(*seenBys)[*seenByCount-1].node = (UINT16) temp;
/* use net aka of last seenBy */
(*seenBys)[*seenByCount-1].net = (*seenBys)[*seenByCount-2].net;
} else {
/* net and node aka */
(*seenBys)[*seenByCount-1].net = (UINT16) temp;
/* eat up '/' */
endptr++;
(*seenBys)[*seenByCount-1].node = (UINT16) atol(endptr);
}
} else if (strcmp(token,"SEEN-BY:")!=0) break; /* not digit and not SEEN-BY */
} /* end while */
if (*seenByCount != seenByAlloced)
(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (*seenByCount));
/* test output for reading of seenBys... */
#ifdef DEBUG_HPT
for (i=0; i < *seenByCount; i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
#endif
/* exit(2); */
nfree(seenByText);
}
void createPathArrayFromMsg(s_message *msg, s_seenBy **seenBys, UINT16 *seenByCount)
{
/* DON'T GET MESSED UP WITH THE VARIABLES NAMED SEENBY... */
/* THIS FUNCTION READS PATH!!! */
char *seenByText=NULL, *start = NULL, *token = NULL;
char *endptr = NULL;
unsigned long temp;
UINT16 seenByAlloced;
#ifdef DEBUG_HPT
UINT16 i;
#endif
*seenByCount = seenByAlloced = 0;
start = strrstr(msg->text, " * Origin:"); /* jump over Origin */
if (start == NULL) start = msg->text;
/* find beginning of path lines */
do {
start = strstr(start, "\001PATH:");
if (start == NULL) return;
for (endptr = strchr(start, '\r'); endptr; endptr = strchr(endptr, '\r')) {
while (*endptr == '\r' || *endptr == '\n') endptr++;
if (strncmp(endptr, "\001PATH:", 6)) break; /* not path line */
}
if (endptr && strstr(endptr, "\001PATH:")) {
start = endptr;
continue; /* only last path lines are valid */
}
start += 7; /* jump over PATH: */
while (*start == ' ') start++; /* find first word after PATH: */
} while (!isdigit(*start));
/* now that we have the start of the PATH' so we can tokenize the lines and read them in */
xstrcat(&seenByText, start);
token = strtok(seenByText, " \r\t\376");
for (; token != NULL; token = strtok(NULL, " \r\t\376")) {
if (isdigit(*token)) {
/* parse token */
temp = strtoul(token, &endptr, 10);
if (*endptr==':') {
token = endptr+1;
temp = strtoul(token, &endptr, 10);
}
if (*endptr && *endptr != '/')
continue;
/* get new memory */
if ((*seenByCount)++ >= seenByAlloced)
(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (seenByAlloced+=32));
if ((*endptr) == '\0') {
/* only node aka */
(*seenBys)[*seenByCount-1].node = (UINT16) temp;
/* use net aka of last seenBy */
(*seenBys)[*seenByCount-1].net = (*seenBys)[*seenByCount-2].net;
} else {
/* net and node aka */
(*seenBys)[*seenByCount-1].net = (UINT16) temp;
/* eat up '/' */
endptr++;
(*seenBys)[*seenByCount-1].node = (UINT16) atol(endptr);
}
} else if (strcmp(token, "\001PATH:")!=0) break; /* not digit and not PATH */
}
if (*seenByCount != seenByAlloced)
(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (*seenByCount));
/* test output for reading of paths... */
#ifdef DEBUG_HPT
for (i=0; i < *seenByCount; i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
#endif
/* exit(2); */
nfree(seenByText);
}
/**
* This function returns 0 if the link is not in seenBy else it returns 1.
*/
UINT16 checkLink(s_seenBy *seenBys, UINT16 seenByCount, s_link *link,
s_area *echo, hs_addr pktOrigAddr)
{
UINT16 i,j;
/* the link where we got the mail from */
if (addrComp(pktOrigAddr, link->hisAka) == 0) return 1;
if (seenBys==NULL) return 0;
/* skip our address in seen-by and allow to
send the mail to links within our node-system */
for (i=0; i < config->addrCount; i++)
if ((link->hisAka.zone == config->addr[i].zone) &&
(link->hisAka.net == config->addr[i].net) &&
(link->hisAka.node == config->addr[i].node))
return 0;
for (i=0; i < seenByCount; i++) {
if ((link->hisAka.net==seenBys[i].net) &&
(link->hisAka.node==seenBys[i].node)) {
return 1;
}
for (j=0; j < config->ignoreSeenCount; j++) {
if (config->ignoreSeen[j].net == seenBys[i].net &&
config->ignoreSeen[j].node == seenBys[i].node) {
link->sb = 1; /* fix for double seen-bys */
return 0;
}
}
for (j=0; j < echo->sbignCount; j++) {
if (echo->sbign[j].net == seenBys[i].net &&
echo->sbign[j].node == seenBys[i].node) {
link->sb = 1; /* fix for double seen-bys */
return 0;
}
}
}
return 0;
}
/* helper function, just for debugging */
void printNewLinks(s_arealink **newLinks, int count)
{
char *str;
int i;
str=strdup("");
for (i=0;i<count;i++)
if (newLinks[i] != NULL)
xscatprintf(&str, " %s", aka2str(newLinks[i]->link->hisAka));
w_log(LL_DEBUGS, "newLinks: %s", str);
nfree(str);
}
/*
* This function builds an array of links who is subscribed to this echo
* except ones listed in seenbys.
*/
void createNewLinksArray(s_area *echo, s_arealink ***newLinks,
hs_addr pktOrigAddr, UINT16 rsb)
{
UINT16 i, lFound = 0;
*newLinks = (s_arealink **)safe_calloc(echo->downlinkCount,sizeof(s_arealink*));
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "echo->downlinkCount = %u", echo->downlinkCount);
printNewLinks(*newLinks, echo->downlinkCount);
#endif
for (i=0; i < echo->downlinkCount; i++) {
/* link with "export off" */
if (echo->downlinks[i]->export == 0) continue;
if (echo->downlinks[i]->link->reducedSeenBy != rsb) continue;
/* don't send to link if it is in seen-bys */
if (checkLink(seenBysZone[echo->downlinks[i]->link->hisAka.zone].seenByArray,
seenBysZone[echo->downlinks[i]->link->hisAka.zone].seenByCount,
echo->downlinks[i]->link, echo, pktOrigAddr))
continue;
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "i=%u, lFound=%u", i, lFound);
#endif
(*newLinks)[lFound++] = echo->downlinks[i];
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "adding link %s to newLinks chain", aka2str(echo->downlinks[i]->link->hisAka));
printNewLinks(*newLinks, echo->downlinkCount);
w_log(LL_DEBUGS, "i=%u, lFound=%u --", i, lFound);
#endif
}
#ifdef DEBUG_HPT
w_log(LL_DEBUGS, "created %u links in newLinks chain", lFound);
printNewLinks(*newLinks, echo->downlinkCount);
#endif
if(lFound == 0)
nfree(*newLinks);
}
void addLinksTo_seenByZone(s_arealink **newLinks, UINT16 count)
{
UINT16 i;
hs_addr *addr;
if (newLinks == NULL) return;
for (i=0; i < count; i++) {
if (newLinks[i] == NULL) continue;
addr = &newLinks[i]->link->hisAka;
if (addr->point != 0) continue; /* don't include points */
addTo_seenByZone(addr->zone, addr->net, addr->node);
}
}
void addAkasTo_seenByZone()
{
UINT16 i;
for (i=0; i < config->addrCount; i++) {
if (config->addr[i].point != 0) continue; /* don't include point addresses */
addTo_seenByZone(config->addr[i].zone, config->addr[i].net, config->addr[i].node);
}
}
void processAutoAdd_seenByZone(s_area *echo)
{
UINT16 i, zone;
for (zone=0;zone<MAX_ZONE;zone++) {
for (i=0; i<config->addToSeenCount; i++)
addTo_seenByZone(zone, config->addToSeen[i].net, config->addToSeen[i].node);
for (i=0; i<echo->sbaddCount; i++)
addTo_seenByZone(zone, echo->sbadd[i].net, echo->sbadd[i].node);
/* for (i=0; i<config->ignoreSeenCount; i++)
deleteFrom_seenByZone(zone, config->ignoreSeen[i].net, config->ignoreSeen[i].node);
for (i=0; i<echo->sbignCount; i++)
deleteFrom_seenByZone(zone, echo->sbign[i].net, echo->sbign[i].node); */
}
}
syntax highlighted by Code2HTML, v. 0.9.1