/* * binkleyforce -- unix FTN mailer project * * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 * * This program 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 of the License, or * (at your option) any later version. * * $Id: nodelist.c,v 1.1.1.1 2004/09/09 09:52:38 kstepanenkov Exp $ */ #include "includes.h" #include "confread.h" #include "logger.h" #include "util.h" #include "nodelist.h" #define NODELIST_LOCK_TRIES 3 #define NODELIST_LOCK_DELAY 1 /* seconds */ struct keyword { const char *keystr; const int keyval; } keywords[] = { { "", KEYWORD_EMPTY }, { "Zone", KEYWORD_ZONE }, { "Region", KEYWORD_REGION }, { "Host", KEYWORD_HOST }, { "Hub", KEYWORD_HUB }, { "Pvt", KEYWORD_PVT }, { "Hold", KEYWORD_HOLD }, { "Down", KEYWORD_DOWN }, { "Boss", KEYWORD_BOSS }, { "Point", KEYWORD_POINT }, { NULL, 0 } }; /***************************************************************************** * Check flag for existing in nodelist flags string * * Arguments: * nodeflags pointer to the node's nodelist flags string * flag pointer to the flag that we want to check * * Return value: * zero value if flag is presented in flags, and non-zero if not */ int nodelist_checkflag(const char *nodeflags, const char *flag) { char *p, *q; if( (p = strstr(nodeflags, flag)) ) { if( p == nodeflags || *(p-1) == ',' ) { if( (q = strchr(p, ',')) == NULL || (q - p) == strlen(flag) ) return 0; } } return 1; } /***************************************************************************** * Get nodelist keyword (e.g. Host, Hub, Point, etc.) value * (e.g. KEYWORD_HOST, KEYWORD_HUB, etc.) * * Arguments: * keywordval pointer to the keyword string * * Return value: * One of KEYWORD_* values, and -1 for unknown keywords */ int nodelist_keywordval(const char *keyword) { int i; for( i = 0; keywords[i].keystr; i++ ) { if( strcmp(keyword, keywords[i].keystr) == 0 ) { return keywords[i].keyval; } } return -1; } int nodelist_parse_Txy(s_node *node, const char *xy) { long beg; long end; long tz; if( xy[0] >= 'A' && xy[0] <= 'X' ) beg = (xy[0] - 'A') * 60; else if( xy[0] >= 'a' && xy[0] <= 'x' ) beg = (xy[0] - 'a') * 60 + 30; else return -1; if( xy[1] >= 'A' && xy[1] <= 'X' ) end = (xy[1] - 'A') * 60; else if( xy[1] >= 'a' && xy[1] <= 'x' ) end = (xy[1] - 'a') * 60 + 30; else return -1; if( beg == end ) return -1; /* Convert it to local time */ if( (tz = time_gmtoffset()) ) { beg -= tz; if( beg > 1440 ) beg = beg - 1440; else if( beg < 0 ) beg = beg + 1440; else if( beg == 1440 ) beg = 0; end -= tz; if( end > 1440 ) end = end - 1440; else if( end < 0 ) end = end + 1440; else if( end == 1440 ) end = 0; } timevec_add(&node->worktime, DAY_MONDAY, DAY_SUNDAY, beg, end); return 0; } /***************************************************************************** * Nodelist string parser * * Arguments: * node put here all obtained information * str pointer to the nodelist string * * Return value: * zero value if string was parsed successfuly, and non-zero if wasn't */ int nodelist_parsestring(s_node *node, char *str) { char *argv[NODELIST_POSFLAGS+1]; char *p; if( string_parse(argv, NODELIST_POSFLAGS+1, str, ',') != NODELIST_POSFLAGS+1 ) return -1; if( !ISDEC(argv[NODELIST_POSNUMBER]) || !ISDEC(argv[NODELIST_POSSPEED]) ) return -1; if( (node->keyword = nodelist_keywordval(argv[NODELIST_POSKEYWORD])) == -1 ) return -1; if( node->addr.zone ) { int number = atoi(argv[NODELIST_POSNUMBER]); bool goodstr = FALSE; switch(node->keyword) { case KEYWORD_ZONE: goodstr = (node->addr.zone == number); break; case KEYWORD_REGION: case KEYWORD_HOST: goodstr = (node->addr.net == number); break; case KEYWORD_POINT: goodstr = (node->addr.point == number); break; default: goodstr = (node->addr.node == number); break; } if( !goodstr ) return -1; } strnxcpy(node->name, argv[NODELIST_POSNAME], sizeof(node->name)); strnxcpy(node->location, argv[NODELIST_POSLOCATION], sizeof(node->location)); strnxcpy(node->sysop, argv[NODELIST_POSSYSOP], sizeof(node->sysop)); strnxcpy(node->phone, argv[NODELIST_POSPHONE], sizeof(node->phone)); strnxcpy(node->flags, argv[NODELIST_POSFLAGS], sizeof(node->flags)); node->speed = atoi(argv[NODELIST_POSSPEED]); /* * Replace all '_' by space character */ string_replchar(node->name, '_', ' '); string_replchar(node->location, '_', ' '); string_replchar(node->sysop, '_', ' '); /* * Get system work time (usefull flags: CM,Txy) */ if( nodelist_checkflag(node->flags, "CM") == 0 ) { timevec_add(&node->worktime, DAY_MONDAY, DAY_SUNDAY, 0, 1440); } else { for( p = node->flags; p && *p; p = strchr(p, ',') ) { if( p[1] == 'T' && p[2] && p[3] && (p[4] == ',' || p[4] == '\0') ) { if( nodelist_parse_Txy(node, p+2) == -1 ) bf_log("invalid nodelist Txy flag in \"%s\"", node->flags); break; } p++; } /* * Set default work time according to ZMH */ if( node->addr.point == 0 ) { switch(node->addr.zone) { case 1: nodelist_parse_Txy(node, "JK"); break; case 2: nodelist_parse_Txy(node, "cd"); break; case 3: nodelist_parse_Txy(node, "ST"); break; case 4: nodelist_parse_Txy(node, "IJ"); break; case 5: nodelist_parse_Txy(node, "BC"); break; case 6: nodelist_parse_Txy(node, "UV"); break; } } } return 0; } /***************************************************************************** * Open nodelist, nodelist index, do some checks * * Arguments: * dir pointer to the nodelist's directory * name pointer to the nodelist file name * mode are we going to read nodelist index? Or write? * * Return value: * pointer to the allocated nodelist structure (will be used with all * nodelist operations), and NULL to indicate errors. */ s_nodelist *nodelist_open(const char *dir, const char *name, int mode) { s_nodelist tmp; const char *openmode; int lockmode; memset(&tmp, '\0', sizeof(s_nodelist)); /* * Select nodelist index open mode */ if( mode == NODELIST_READ ) { openmode = "r"; lockmode = FILELOCK_READ; } else if( mode == NODELIST_WRITE ) { openmode = "w"; lockmode = FILELOCK_WRITE; } else ASSERT(0); /* * Get nodelist and nodelist index file names */ if( *name == DIRSEPCHR ) { strnxcpy(tmp.name_nodelist, name, sizeof(tmp.name_nodelist)); strnxcpy(tmp.name_index, name, sizeof(tmp.name_index)); } else { strnxcpy(tmp.name_nodelist, dir, sizeof(tmp.name_nodelist)); strnxcat(tmp.name_nodelist, name, sizeof(tmp.name_nodelist)); strnxcpy(tmp.name_index, tmp.name_nodelist, sizeof(tmp.name_index)); } strnxcat(tmp.name_index, ".index", sizeof(tmp.name_index)); DEB((D_NODELIST, "nodelist_open: nodelist name = \"%s\"", tmp.name_nodelist)); DEB((D_NODELIST, "nodelist_open: nodelist index = \"%s\"", tmp.name_index)); DEB((D_NODELIST, "nodelist_open: open mode = \"%s\"", openmode)); /* * Try to open and lock nodelist */ if( (tmp.fp_nodelist = file_open(tmp.name_nodelist, "r")) == NULL ) { logerr("cannot open nodelist \"%s\"", tmp.name_nodelist); return NULL; } /* * Try to open and lock nodelist index */ if( (tmp.fp_index = file_open(tmp.name_index, openmode)) == NULL ) { logerr("cannot open nodelist index \"%s\"", tmp.name_index); fclose(tmp.fp_nodelist); return NULL; } /* * If we open nodelist for reading then we should check that * nodelist index has correct header and up to date */ if( mode == NODELIST_READ ) { if( nodelist_checkheader(&tmp) == -1 ) { file_close(tmp.fp_nodelist); file_close(tmp.fp_index); return NULL; } } return xmemcpy(&tmp, sizeof(s_nodelist)); } /***************************************************************************** * Check nodelist index header for valid nodelist date and size * * Arguments: * nlp opened nodelist * * Return value: * zero value if header is correct, and -1 if not */ int nodelist_checkheader(s_nodelist *nlp) { unsigned long nltime; unsigned long nlsize; struct stat nlstat; char buffer[NODELIST_HDRSIZE]; if( fread(buffer, sizeof(buffer), 1, nlp->fp_index) != 1 ) { logerr("cannot read header from nodelist index \"%s\"", nlp->name_index); return -1; } if( fstat(fileno(nlp->fp_nodelist), &nlstat) == -1 ) { logerr("cannot stat nodelist \"%s\"", nlp->name_nodelist); return -1; } nltime = buffer_getlong(buffer + 0); nlsize = buffer_getlong(buffer + 4); if( (unsigned long)nlstat.st_mtime != nltime ) { bf_log("invalid nodelist index: incorrect nodelist date %ld (expected %ld)", (long)nlstat.st_mtime, (long)nltime); return -1; } if( (unsigned long)nlstat.st_size != nlsize ) { bf_log("invalid nodelist index: incorrect nodelist size %ld (expected %ld)", (long)nlstat.st_size, (long)nlsize); return -1; } return 0; } /***************************************************************************** * Create/update nodelist index header. Nodelist must be opened for * writing. Now nodelist index header contain nodelist modification * time and nodelist size. * * Arguments: * nlp opened nodelist * * Return value: * zero value on success, and -1 at errors */ int nodelist_createheader(s_nodelist *nlp) { struct stat nlstat; char hdrbuf[NODELIST_HDRSIZE]; memset(&hdrbuf, '\0', sizeof(hdrbuf)); if( fstat(fileno(nlp->fp_nodelist), &nlstat) == -1 ) { logerr("cannot stat nodelist \"%s\"", nlp->name_nodelist); return -1; } buffer_putlong(hdrbuf + 0, nlstat.st_mtime); buffer_putlong(hdrbuf + 4, nlstat.st_size); if( fseek(nlp->fp_index, 0L, SEEK_SET) == -1 ) { logerr("cannot seek to zero offset of index"); return -1; } if( fwrite(hdrbuf, sizeof(hdrbuf), 1, nlp->fp_index) != 1 ) { logerr("cannot write nodelist index header"); return -1; } return 0; } /***************************************************************************** * Close nodelist and nodelist index files * * Arguments: * nlp pointer to the opened nodelist * * Return value: * Zero value if close was successful, and non-zero if not */ int nodelist_close(s_nodelist *nlp) { int rc = 0; ASSERT(nlp && nlp->fp_nodelist && nlp->fp_index); if( nlp->fp_nodelist && file_close(nlp->fp_nodelist) ) logerr("cannot close nodelist \"%s\"", nlp->name_nodelist); if( nlp->fp_index && file_close(nlp->fp_index) ) { logerr("cannot close nodelist index \"%s\"", nlp->name_index); rc = 1; } free(nlp); return rc; } int nodelist_putindex(s_nodelist *nlp, const s_bni *bni) { char buffer[NODELIST_ENTRYSIZE]; ASSERT(nlp && nlp->fp_index); buffer_putint(buffer + 0, bni->zone); buffer_putint(buffer + 2, bni->net); buffer_putint(buffer + 4, bni->node); buffer_putint(buffer + 6, bni->point); buffer_putint(buffer + 8, bni->hub); buffer_putlong(buffer + 10, bni->offset); if( fwrite(buffer, sizeof(buffer), 1, nlp->fp_index) != 1 ) { logerr("error writing nodelist index file \"%s\"", nlp->name_index); return -1; } return 0; } int nodelist_findindex(s_nodelist *nlp, s_bni *bni, s_faddr addr) { long readitems; char buffer[NODELIST_ENTRYSIZE * NODELIST_READAHEAD]; char *p; if( fseek(nlp->fp_index, NODELIST_HDRSIZE, SEEK_SET) ) return -1; while(1) { if( (readitems = fread(buffer, NODELIST_ENTRYSIZE, NODELIST_READAHEAD, nlp->fp_index)) > 0 ) { for( p = buffer; readitems > 0; readitems-- ) { if( buffer_getint(p + 0) == addr.zone && buffer_getint(p + 2) == addr.net && buffer_getint(p + 4) == addr.node && buffer_getint(p + 6) == addr.point ) { bni->zone = buffer_getint(p + 0); bni->net = buffer_getint(p + 2); bni->node = buffer_getint(p + 4); bni->point = buffer_getint(p + 6); bni->hub = buffer_getint(p + 8); bni->offset = buffer_getlong(p + 10); return 0; } p += NODELIST_ENTRYSIZE; } } else return -1; } return -1; } int nodelist_getstr(s_nodelist *nlp, size_t offset, char *buffer, size_t buflen) { ASSERT(nlp && nlp->fp_nodelist); if( fseek(nlp->fp_nodelist, offset, SEEK_SET) == 0 && fgets(buffer, buflen, nlp->fp_nodelist) ) { string_chomp(buffer); return 0; } return -1; } int nodelist_lookup_string(char *buffer, size_t buflen, s_faddr addr) { s_bni bni; s_cval_entry *ptrl; s_nodelist *nlp; const char *ndldir = NULL; ndldir = conf_string(cf_nodelist_directory); /* * Try all nodelists with matching address mask */ for( ptrl = conf_first(cf_nodelist); ptrl; ptrl = conf_next(ptrl) ) { if( ftn_addrcomp_mask(addr, ptrl->d.falist.addr) == 0 ) { if( (nlp = nodelist_open(ndldir, ptrl->d.falist.what, NODELIST_READ)) ) { int rc = nodelist_findindex(nlp, &bni, addr); if( !rc ) rc = nodelist_getstr(nlp, bni.offset, buffer, buflen); nodelist_close(nlp); if( !rc ) return 0; } } } return -1; } int nodelist_lookup(s_node *node, s_faddr addr) { char buf[512]; char abuf[BF_MAXADDRSTR+1]; nodelist_initnode(node, addr); if( nodelist_lookup_string(buf, sizeof(buf), addr) == 0 ) { node->listed = TRUE; if( nodelist_parsestring(node, buf) == -1 ) { bf_log("invalid nodelist string for address %s", ftn_addrstr(abuf, addr)); } return 0; } return -1; } void nodelist_initnode(s_node *node, s_faddr addr) { memset(node, '\0', sizeof(s_node)); node->addr = addr; strcpy(node->name, ""); strcpy(node->sysop, ""); strcpy(node->location, ""); strcpy(node->phone, ""); }