/* Convert a St Louis nodelist new style into a list with all the line that have an -Unpublished- phone number into Pvt entries, as rquired in teh old style list. */ /* (c) 2007, Michiel van der Vlist */ /* This programme is copyright by Michiel van der Vlist. It is distributed as freeware for noncommercial use. Please do not distribute modified versions of either the source or the object code. For commercial use, please contact the author */ #include #include #include #include #include #include #include #include #define MYNAMEANDNUMBER "(c) 2007, Michiel van der Vlist, PA0MMV (2:280/5555)" #define TRUE (1==1) #define FALSE !TRUE #define NAMELENG 37 #define VERSION "1.00 beta 2007.04.23" //#define VERSION "1.01" #define DEFINPUT "NODELIST" #define DEFOUTEXT ".999" #define DEFPREFIX "000-" #define CONFIGEXT ".CFG" #define USERTYPE 0 #define REGULARTYPE 1 #define IPTYPE 2 #define EMAILTYPE 3 #define MAXFLAGLENGTH 65 #define NONE 0 #define PORTNR 1 #define IPQUAD 2 #define FQDN 3 #define IPV6 4 typedef unsigned char boolean; typedef unsigned char byte; typedef char string[NAMELENG]; typedef char longstring[80]; typedef char verylongstring[255]; typedef char megalongstring[512]; typedef char hyperlongstring[1000]; longstring nodelist,outlist; longstring ipflags={"INA,IP,IBN,IFC,IFT"}; string telnetflags={"ITN,IVM"}; string progname; verylongstring pstr; string prefix; FILE *infile,*outfile; unsigned int crc; char ipv6sep='#'; boolean dofqdn=TRUE,noprefix=FALSE,doportnr=TRUE,onlypvt=FALSE,unpubonly=TRUE; long int nodesread=0, nodesconvert=0; #include "rmainder.h" int getcommands(int argc, char *argv[]); int scanoption(char *st); int readconfig(char *s, int maxl); boolean substenvirons(char *s, int max); int directory(char *match, char *fname); void force_ext(char *buf, char *ext); boolean wildcards(char *s); boolean forbiddenext(char *f); void findlist(char *fbuf, char *inlist, char *defname, char *defext); void help(void); unsigned int chcrc(unsigned char ch, unsigned int crc); unsigned int Writeline(char *b, FILE *f, unsigned int ch); char *Fgets(char *s,int n, FILE *fp); int removeletter(char *s, int pos); int cmp_file_age(char *f1, char *f2); boolean isemptyline(char *s); int copyfield(char *line, char *field, int siz, int pos); void substunder(char *s); void substspace(char *s); int Findfirst(const char *pathname, struct ffblk *ff_blk,int attrib); int Findnext(char *patname,struct ffblk *ff_blk); boolean supermatch(char *s, char *d); int isip(char *s); int isip2(char *s, boolean alsofqdn); boolean isportnumber(char *s); boolean isipquad(char *s); boolean isipv6(char *s); boolean isfqdn(char *s); boolean isemailaddress(char *s); boolean Convertline(char *in, char *out, int size); boolean flagmatch(char *f1, char *f2); int nextflag(char *s, int pos); boolean getflagparam(char *s, char *p, int size, boolean all); boolean isendflag(char c); void substdash(char *s); /************************** Main ********************/ int main(int argc, char *argv[]) { int i,l,oflags; char ofdrv[MAXDRIVE], ofpath[MAXPATH], ofname[MAXFILE], ofext[MAXEXT]; char ifdrv[MAXDRIVE], ifpath[MAXPATH], ifname[MAXFILE], ifext[MAXEXT]; longstring version; megalongstring fbuf, buffer; fpos_t bpos; strcpy(version,VERSION); printf("\nMakePvt %s, Nodelist convert utility\n",version); printf(MYNAMEANDNUMBER); printf("\nNoncommercial use allowed.\n"); nodelist[0]=0; outlist[0]=0; prefix[0]=0; fnsplit(argv[0],NULL,NULL,progname,NULL); if (argc==2 && (argv[1][0]=='?' || toupper(argv[1][0])=='H')) { help(); exit(0); } if ((i=readconfig(buffer,sizeof(buffer)-1))!=0) { printf("Error reading config file, line %d.\n",abs(i),NULL,0); help(); exit(1); } if (argc>1) { if ((i=getcommands(argc, argv))!=0) { printf("Unknown command argument %s\n",argv[abs(i)]); help(); exit(2); } } if (prefix[0]==0 && !noprefix) strcpy(prefix,DEFPREFIX); if (telnetflags[0]==0) strcpy(telnetflags,ipflags); findlist(fbuf,nodelist,DEFINPUT,".???"); strcpy(nodelist,fbuf); if ((infile=fopen(nodelist,"rt"))==NULL) { printf("Can't find nodelist or failed to open: %s\n",nodelist); exit(3); } fnsplit(nodelist,ifdrv,ifpath,ifname,ifext); oflags=fnsplit(outlist,ofdrv,ofpath,ofname,ofext); if (!(oflags & EXTENSION)) strcpy(ofext,DEFOUTEXT); if (!(oflags & FILENAME)) strcpy(ofname,ifname); if (!(oflags & DIRECTORY)) strcpy(ofpath,ifpath); if (!(oflags & DRIVE)) strcpy(ofdrv,ifdrv); fnmerge(outlist,ofdrv,ofpath,ofname,ofext); outfile=fopen(outlist,"w+t"); if (outfile==NULL) { printf("Can not open %s for write.\n",outlist); exit(4); } printf("Reading input from: %s\n",nodelist); printf("Writing output to: %s\n",outlist); crc=0; if (Fgets(pstr,sizeof(pstr)-1,infile)==NULL) { printf("%s appears to be empty.\n",nodelist); exit(5); } /* Read the first line, see if it contains a checksum, if so hunt for the checksum position. */ if (pstr[0]!=';' || pstr[1]!='A') /* nodelist does not start with the standard comment line */ { /* Make our own header line. */ fprintf(outfile,";A Converted nodelist for some day. Checksum : "); fgetpos(outfile,&bpos); /* remember position of checksum */ fprintf(outfile,"00000\n"); } else { l=strlen(pstr); for (i=l-1;i>=0;i--) if (pstr[i]==':') break; if (i<0) /* no ':' found */ { strcpy(buffer,pstr); strcat(buffer," : "); fprintf(outfile,"%s",buffer); } else { pstr[i+1]=0; strcat(pstr," "); fprintf(outfile,"%s",pstr); } fgetpos(outfile,&bpos); /* remember position of checksum */ fprintf(outfile,"00000\n"); Fgets(pstr,sizeof(pstr)-1,infile); /* read the second line */ } /* write our custom line */ sprintf(buffer,";S Converted to old Pvt,-Unpublished- format by %s %s",progname,version); crc=Writeline(buffer,outfile,crc); sprintf(buffer,";"); crc=Writeline(buffer,outfile,crc); /* ok, now the real fun starts */ /* */ /* M A I N L O O P */ /* */ /*********************************/ do { if (pstr[0]==';') /* skip lines starting with ;X , copy other comments */ { if (pstr[1]=='X') continue; else crc=Writeline(pstr,outfile,crc); } else { nodesread++; if (Convertline(pstr,buffer,sizeof(buffer))) nodesconvert++;; crc=Writeline(buffer,outfile,crc); } } while (Fgets(pstr,sizeof(pstr)-1,infile)!=NULL); /* we appear to be done */ fclose(infile); fputc(26,outfile); /* terminating EOF(^z) */ fsetpos(outfile,&bpos); fprintf(outfile,"%05u",crc); fclose(outfile); printf("All done! %ld nodes read, %ld converted.\n",nodesread,nodesconvert); return(0); } /* Convert the line. Returns TRUE if a conversion was done, FALSE if not. */ boolean Convertline(char *in, char *out, int size) { int n=0,k=0; char key[10],nmbr[30],sys[65],loc[65],name[37],phone[100],baud[10],flgs[128]; char phon[15],portnumber[15]; boolean converted=FALSE; key[0]=sys[0]=loc[0]=name[0]=phone[0]=baud[0]=flgs[0]=phon[0]=portnumber[0]=0; k=copyfield(in,key,sizeof(key),k); k=copyfield(in,nmbr,sizeof(nmbr),k); k=copyfield(in,sys,sizeof(sys),k); k=copyfield(in,loc,sizeof(loc),k); k=copyfield(in,name,sizeof(name),k); k=copyfield(in,phone,sizeof(phone),k); k=copyfield(in,baud,sizeof(baud),k); strncpy(flgs,&in[k],sizeof(flgs)-1); flgs[sizeof(flgs)-1]=0; if (strcmp(phone,"-Unpublished-")==0) { if (key[0]==0 || stricmp(key,"Hub")==0) { strcpy(key,"Pvt"); converted=TRUE; } } n=sprintf(out,"%s,%s,%s,%s,%s,%s,%s",key,nmbr,sys,loc,name,phone,baud); if (flgs[0]) { strcat(out,","); strcat(out,flgs); } if (n>size) { printf("Fatal error, buffer size exceeded!\n"); exit(6); } return(converted); } /* skip to the next flag in a comma delimited flag list. Return the position of the first character of the next flag in the string containing the comma delimited flag list. Return -1 if there is no next flag. */ int nextflag(char *s, int pos) { if (s[pos]==0 || (s[pos+1]==',' && s[pos+1]==0)) return(-1); while (s[pos]!=',' && s[pos]!=0 && !isspace(s[pos])) pos++; if (s[pos]==',') pos++; return(pos); } /* Get the parameter of a flag if present. Return FALSE if no parameters If all is set to FALSE copy only the first parameter, If TRUE get them all */ boolean getflagparam(char *s, char *p, int size, boolean all) { int i=0, j=0; /* First hunt for the colon */ while (!isendflag(s[i])) i++; if (s[i]!=':') return(FALSE); i++; if (isendflag(s[i])) return(FALSE); if (all) while (s[i]!=0 && s[i]!=',' && !isspace(s[i])) p[j++]=s[i++]; else while (!isendflag(s[i]) && jfiletime2) return(1); return(0); } /* force the extension of a file name */ void force_ext(char *buf, char *ext) { char drive[MAXDRIVE]; char dir[MAXDIR]; char file[MAXFILE]; fnsplit(buf,drive,dir,file,NULL); fnmerge(buf,drive,dir,file,ext); } /* directory searching */ /* This one is called just before opening the input file. Hunt for all matching files and if the extension is nummeric select the latest one */ int directory(char *match, char *fname) { struct ffblk infoblk; char far *dtasave; char namef[MAXFILE],extf[MAXEXT],extf1[MAXEXT]; int i,j,ret=-1; unsigned ffdate0=0, ffdate1=0; dtasave = getdta(); /* Save het org. disk transfer adres. */ if (Findfirst(match,&infoblk,0)==0) { strcpy(fname,infoblk.ff_name); fnsplit(fname,NULL,NULL,namef,extf); strcpy(extf1,extf); if (isdigit(extf[1]) && isdigit(extf[2]) && isdigit(extf[3])) { sscanf(&extf[1],"%d",&i); ffdate0=infoblk.ff_fdate; } else i=0; while (Findnext(match,&infoblk)==0) { fnsplit(infoblk.ff_name,NULL,NULL,namef,extf); if (forbiddenext(extf)) continue; if (forbiddenext(extf1)) strcpy(fname,infoblk.ff_name); strcpy(extf1,extf); if (isdigit(extf[1]) && isdigit(extf[2]) && isdigit(extf[3])) { sscanf(&extf[1],"%d",&j); ffdate1=infoblk.ff_fdate; if (ffdate1>ffdate0 || (ffdate1==ffdate0 && j>i)) { /* select the latest */ strcpy(fname,infoblk.ff_name); i=j; ffdate0=ffdate1; } } } fnsplit(fname,NULL,NULL,NULL,extf); if (forbiddenext(extf)) ret=-1; else ret=0; } setdta(dtasave); /* org disk transfer adres herstellen */ return(ret); } /* see if a name contains wildcards */ boolean wildcards(char *s) { int i=0; while (s[i]) { if (s[i]=='?' || s[i]=='#' || s[i]=='@' || s[i]=='*') return(TRUE); i++; } return(FALSE); } /* test if extension is forbidden forbidden extensions are 999,BAK,BAT,COM,EXE,FON,H,T,Ann,Jnn,Lnn,Rnn,Snn and Znn */ boolean forbiddenext(char *f) { char c; if (f[0]!='.') return(TRUE); c=toupper(f[1]); if ( stricmp(f,".BAK")==0 || stricmp(f,".BAT")==0 || stricmp(f,".EXE")==0 || stricmp(f,".COM")==0 || stricmp(f,".FON")==0 || stricmp(f,".T")==0 || stricmp(f,".H")==0 || stricmp(f,".999")==0 || (isdigit(f[2]) && isdigit(f[3]) && (c=='A'||c=='J'||c=='L'|| c=='R' ||c=='S' || c=='Z'))) return(TRUE); return(FALSE); } /* same as fgets except that it advances pointer to EOL after coping as many chars as possible and it substitutes tabs by two spaces. */ char *Fgets(char *s,int n, FILE *fp) { int cc; int ii,jj=0; for (ii=0;ii4) return(FALSE); i++; } return(TRUE); } /* See if a string qualifies as an ip quad */ /* four nummeric values in the range 0-254,0-254,0-254,0-255 separated by dots. The following ranges are reserved for private networks and hence invalid: 192.168.0.1 through and up to 192.168.255.254 10.0.0.1 through and up to 10.255.255.254 172.16.0.1 through and up to 172.31.255.254 Also the local hosts: 127.0.0.* and 0.0.0.0 are invalid */ boolean isipquad(char *s) { int n1,n2,n3,n4,dots; long unsigned int ipadr; dots=sscanf(s,"%d.%d.%d.%d",&n1,&n2,&n3,&n4); if (dots<4) return (FALSE); /* too few fields */ if (n1<0 || n2<0 || n3<0 || n4<0) return (FALSE); if (n1>254 || n2>254 || n3>254 || n4>255) return (FALSE); ipadr=(((unsigned long)n1)<<24)+(((unsigned long)n2)<<16)+ (((unsigned long)n3)<<8)+(unsigned long)n4; if (ipadr==0) return(FALSE); if (ipadr>=(192L<<24)+(168L<<16)+1L && ipadr<=(192L<<24)+(168L<<16)+(255L<<8)+254L) return(FALSE); if (ipadr>=(10L<<24)+1 && ipadr<=(10L<<24)+(255L<<16)+(255L<<8)+254L) return(FALSE); if (ipadr>=(172L<<24)+(16L<<16)+1L && ipadr<=(172L<<24)+(31L<<16)+(255L<<8)+254L) return(FALSE); if ((ipadr&0xFFFFFF00L)==(127L<<24)) return(FALSE); return (TRUE); } /* See if a string qualifies as an ipv6 address */ /* The separator character (colon in the IP world) is defined in the global variable ipv6sep, default a poind signe ( # ) in this program. Eight hexadecimal values in the range 0-FFFF separated by a SEP char. One or more successive zero values may once be represented by two successive separators. F.e. 1234::6789:abcd expands to 1234:0:0:0:0:0:6789:abcd. All zeros is invalid. */ boolean isipv6(char *s) { int i=0,n1,n2,n3,n4,n5,n6,n7,n8,seps=0,nrseps=0,doubleseppos=0; char c,t[40],tt[40]; /* first substitute the separator character by a comma, count them and note the position of two successive separators on the fly */ while (s[i] && i0) { if (ampersand) dot=TRUE; if (s[i-1]=='.' || s[i-1]=='@') return(FALSE); } if (!(isalnum(c)||c=='-'||c=='.'||c=='_'||c=='@')) return(FALSE); i++; } if (s[0]=='.' || s[i-1]=='.') return(FALSE); if (s[0]=='@' || s[i-1]=='@') return(FALSE); return (dot && (ampersand==1)); } /* remove a letter from a string */ int removeletter(char *s, int pos) { int i; i=pos; do { s[i]=s[i+1]; } while (s[i++]); return(i-pos); } /* Calculate the CRC. On entry a character is in ch. This is a cumulative process, all chars CRC's are taken as a running total. To start a new sequence, first clear crc. - Inspired by PA0MMV's REMOTE! - */ unsigned int chcrc(unsigned char ch, unsigned int crc) { unsigned char b,crch; b=(crc>>8)^ch; crch=(crc&0xFF)^CRC1[b]; return((crch<<8)+CRC2[b]); } /* Custum replacements of findfirst and findnext */ int Findfirst(const char *pathname, struct ffblk *ff_blk,int attrib) { int n=-1,result; longstring mat; char namef[MAXFILE],extf[MAXEXT],fname[13]; strcpy(mat,pathname); while (mat[++n]) if (mat[n]=='#' || mat[n]=='@') mat[n]='?'; fnsplit(mat,NULL,NULL,namef,extf); if ((result=findfirst(mat,ff_blk,attrib))==0) { fnsplit(pathname,NULL,NULL,namef,extf); strcpy(fname,namef); strcat(fname,extf); while (result==0 && !supermatch(fname,ff_blk->ff_name)) { result=findnext(ff_blk); } } return(result); } int Findnext(char *pathname,struct ffblk *ff_blk) { int result; char namef[MAXFILE],extf[MAXEXT],fname[13]; fnsplit(pathname,NULL,NULL,namef,extf); strcpy(fname,namef); strcat(fname,extf); do { result=findnext(ff_blk); } while (result==0 && !supermatch(fname,ff_blk->ff_name)); return(result); } boolean supermatch(char *s, char *d) { int n=0, m=0; while (s[n]) { switch (s[n]) { case '?': if (d[m]==0 || d[m]=='.') return(FALSE); break; case '@': if (!isalpha(d[m])) return(FALSE); break; case '#': if (!isdigit(d[m])) return(FALSE); break; case '*': while (s[++n]=='*') ; /* skip multple * */ if (s[n]=='.') { while (d[m] && d[m]!='.') m++; if (d[m]=='.') continue; } return(TRUE); default : if (toupper(s[n])!=toupper(d[m])) return(FALSE); break; } n++; m++; } return(TRUE); }