/*
* hpttree - area tree builder for Highly Portable Tosser (hpt)
* by Serguei Revtov 2:5021/11.10 || 2:5021/19.1
*
* 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: hpttree.c,v 1.26.2.1 2004/01/23 04:29:16 andr_lukyanov Exp $
*/
#include <ctype.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <smapi/compiler.h>
#ifdef HAS_IO_H
#include <io.h>
#endif
#ifdef HAS_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAS_SHARE_H
#include <share.h>
#endif
#ifdef HAS_SYS_SYSEXITS_H
#include <sys/sysexits.h>
#endif
#ifdef HAS_SYSEXITS_H
#include <sysexits.h>
#endif
#include <smapi/prog.h>
#include <smapi/progprot.h>
#include <smapi/msgapi.h>
#include <fidoconf/fidoconf.h>
#include <fidoconf/common.h>
#include <version.h>
#include "cvsdate.h"
s_fidoconfig *cfg;
struct nodepath {
unsigned int zone, net, node;
int exportto;
int printed;
};
typedef struct nodepath s_nodepath;
s_nodepath *allNodes = NULL;
int nodeCount = 0;
FILE *outlog;
char *versionStr = NULL;
int *linksOnLevel = NULL;
int linksInArray = 0;
#ifdef __UNIX__
int charsPG = 0;
#else
int charsPG = 1;
#endif
#define LLCORNER allCharsPG[charsPG][0]
#define VLINE allCharsPG[charsPG][1]
#define LTEE allCharsPG[charsPG][2]
char *allCharsPG[2] = { "L|+", "\300\263\303" };
int tperiod;
void printTree (int level, int nodeNum)
{
int i;
s_nodepath *cnode;
int linech;
cnode = &allNodes [nodeNum];
if ( linksInArray <= level ) { /* Allocate place for link counter in current level */
linksInArray = level + 1;
linksOnLevel = srealloc ( linksOnLevel, sizeof(int) * linksInArray);
}
linksOnLevel[level] = 0;
for (i=0; i < nodeCount; i++) {
if ((allNodes[i]).exportto == nodeNum) {
linksOnLevel[level]++;
}
}
if ( level > 0 ) linksOnLevel[level-1]--; /* current node is already printed */
for (i=0; i<level; i++) {
linech = ' ';
if ( linksOnLevel[i] ) linech = VLINE;
if ( i == (level-1) ) {
linech = LTEE;
if (linksOnLevel[level-1] == 0) linech = LLCORNER;
}
printf ( " %c ", linech);
}
printf ("%d:%d/%d\n", cnode->zone, cnode->net, cnode->node);
if (cnode->printed) {
printf("WARNING: Loop at %d:%d/%d, escaping thread\n", cnode->zone, cnode->net, cnode->node);
return;
}
cnode->printed = 1; /* for checking for lost nodes */
for (i=0; i < nodeCount; i++) {
if ((allNodes[i]).exportto == nodeNum) {
printTree (level+1, i);
}
}
}
void buildAreaTree(s_area *area)
{
HAREA harea;
dword highMsg;
HMSG hmsg;
XMSG xmsg;
int i = -1;
int nmsg;
char *text;
dword textLength;
s_nodepath node;
s_nodepath *cnode;
int prevNode;
char *token;
char *start;
char *endptr;
unsigned long temp;
int found;
int done;
int root = -1;
/* for time period */
struct tm tmTime;
time_t ttime, actualTime = time(NULL);
fprintf(outlog, "Distribution tree of area %s", area->areaName);
if (tperiod) {
fprintf(outlog, " for last %d %s\n\n", tperiod, tperiod ==1 ? "day" : "days");
}
else fprintf(outlog, "\n\n");
if ((area->msgbType & MSGTYPE_PASSTHROUGH) == MSGTYPE_PASSTHROUGH) {
fprintf(outlog, "PASSTHROUGH, ignoring\n");
return;
}
if((area->useAka)!=NULL)
node.zone = (area->useAka)->zone;
else
node.zone = 2;
nodeCount = linksInArray = 0;
linksOnLevel = NULL;
allNodes = NULL;
harea = MsgOpenArea((byte *) area->fileName, MSGAREA_NORMAL, (word)area->msgbType);
if (harea)
{
highMsg = MsgGetHighMsg(harea);
if ( highMsg < 1 ) {
fprintf(outlog, "nothing to build (%ld messages)\n", (long)highMsg);
MsgCloseArea(harea);
return;
}
/* Pass 1: fill nodes array and buld links */
for (nmsg = 1; nmsg <= highMsg; nmsg++) {
hmsg = MsgOpenMsg(harea, MOPEN_READ, nmsg);
if (hmsg){
/*
* NOTE: text would be destructed by strtoc() !!!
* Do not use it for anything else
*/
textLength = MsgGetTextLen(hmsg);
text = (char *) scalloc(textLength+1,sizeof(char));
if (text == NULL) return;
ttime = mktime(&tmTime);
MsgReadMsg(hmsg, &xmsg, 0, textLength, (unsigned char *) text, 0, NULL);
/* check time period */
if (xmsg.attr & MSGLOCAL) {
DosDate_to_TmDate((SCOMBO*)&(xmsg.date_written), &tmTime);
} else {
DosDate_to_TmDate((SCOMBO*)&(xmsg.date_arrived), &tmTime);
}
MsgCloseMsg(hmsg);
/* check time period */
if ( (tperiod) && ( abs(actualTime - ttime) >= ( tperiod * 24 *60 * 60)) )
continue;
start = text;
prevNode = -1;
node.exportto = -1;
node.printed = 0;
done = 0;
/* find beginning of path lines */
do {
start = strstr(start, "\001PATH: ");
if (start == NULL) done++;
if (!done) {
start += 7; /* jump over PATH: */
while (*start == ' ') start++; /* find first word after PATH: */
}
} while (!done && !isdigit( (int) *start));
if (!done) {
token = strtok(start, " \r\t\376");
while (token != NULL && !done) {
if (isdigit( (int) *token)) {
/* parse token */
temp = strtoul(token, &endptr, 10);
if ((*endptr) == ':') { /* zone */
node.zone = temp;
endptr++;
temp = strtoul(endptr, &endptr, 10);
}
if ((*endptr) == '/') { /* net */
node.net = temp;
endptr++;
temp = strtoul(endptr, &endptr, 10);
}
if (*endptr) fprintf (outlog, "POINT or bad address in PATH: in message %d\n", nmsg);
/* only node aka */
node.node = temp;
/* find if there where that node in array */
for ( found=0, i=0, cnode=allNodes; i < nodeCount && !found; i++, cnode++) {
if ( cnode->node == node.node &&
cnode->net == node.net &&
cnode->zone == node.zone
) found++;
}
if (!found) {
nodeCount++;
i = nodeCount;
allNodes = (s_nodepath *) srealloc (allNodes, sizeof(s_nodepath) * nodeCount);
cnode = &allNodes[i-1];
*cnode = node;
}
i--; /* was incremented in 'for' & in prev. 'if' */
if (prevNode >= 0 && prevNode != i) (allNodes[prevNode]).exportto = i;
prevNode = i;
} else
if (strchr(" \r\t\376", *token)==NULL && strncmp(token, "\001PATH:", 6)!=0) done++; /* something's wrong */
token = strtok(NULL, " \r\t\376");
}
if (root < 0) root = i;
}
nfree(text);
}
}
MsgCloseArea(harea);
/* printing tree */
if (nodeCount > 0)
printTree (0, root);
else
printf("Not distributed\n");
for (i=0; i < nodeCount; i++) {
if (!((allNodes[i]).printed)) {
fprintf(outlog, "Lost Node: %d:%d/%d\n", (allNodes[i]).zone, (allNodes[i]).net, (allNodes[i]).node);
}
}
nfree(allNodes);
nfree(linksOnLevel);
fprintf(outlog, "\nGenerated by %s\n", versionStr);
} else {
fprintf(outlog,"\nCould not open area %s\n", area->areaName);
}
}
void usage(void) {
fprintf(outlog, "Usage: hpttree [options] ][areaname ...]\n");
fprintf(outlog, "Options: -p\t\t- toggle pseudographics mode\n");
fprintf(outlog, "\t -d <num>\t- for last <num>> days\n");
}
int main(int argc, char **argv) {
int i, j;
struct _minf m;
char **argareas=NULL;
int nareas=0;
int found;
versionStr = GenVersionStr( "hptTree", VER_MAJOR, VER_MINOR, VER_PATCH,
VER_BRANCH, cvs_date );
printf( "%s\n\n", versionStr);
outlog=stdout;
setbuf(outlog, NULL);
for (i=1; i<argc; i++) {
if ( argv[i][0] == '-' ) {
switch (argv[i][1])
{
case 'p': /* Toggle pseudographics */
case 'P':
charsPG = (charsPG) ? 0 : 1;
break;
case 'd': /* Last NUM days */
case 'D':
i++;
if ( !argv[i] ) {
usage();
exit(EX_USAGE);
}
tperiod = atoi(argv[i]);
if ( tperiod <=0 ) {
usage();
exit(EX_USAGE);
}
break;
default:
usage();
exit(EX_USAGE);
}
} else {
/* AreaName(s) specified by args */
nareas++;
argareas = (char **)srealloc ( argareas, nareas*sizeof(char *));
argareas[nareas-1] = argv[i];
}
}
cfg = readConfig(NULL);
if (!cfg) {
fprintf(outlog, "Could not read fido config\n");
return (1);
}
m.req_version = 0;
m.def_zone = (UINT16) cfg->addr[0].zone;
if (MsgOpenApi(&m)!= 0) {
fprintf(outlog, "MsgOpenApi Error.\n");
exit(EX_SOFTWARE);
}
if ( argareas )
{
/* link only specified areas */
for ( j=0; j<nareas; j++) {
found=0;
/* EchoAreas */
for (i=0; i < cfg->echoAreaCount && !found; i++) {
if (stricmp(cfg->echoAreas[i].areaName, argareas[j])==0){
buildAreaTree(&(cfg->echoAreas[i]));
found++;
}
}
if (!found) fprintf(outlog, "Couldn't find area \"%s\"\n", argareas[j]);
}
} else {
/* EchoAreas */
for (i=0; i < cfg->echoAreaCount; i++) buildAreaTree(&(cfg->echoAreas[i]));
}
disposeConfig(cfg);
return (0);
}
syntax highlighted by Code2HTML, v. 0.9.1