// June 15, 1994 - KF5MG - Jack Snodgrass // // This code was adapted/copied from the SAM.C code. The code to process // the QRZ disk was taken from the QRZ CD-ROM. This code could work // with the name and zipcode versions of the Callbook data, but as-is, it // only processes callsigns. // #include #include #include #include #include #include #define reclen 160 #include "global.h" #ifdef QRZCALLB #include "mbuf.h" #include "socket.h" #include "session.h" #include "proc.h" #include "netuser.h" #include "commands.h" #include "tty.h" #include "config.h" extern char *Callserver; /* buckbook.c */ int cb_lookup __ARGS((int s,char *,FILE *)); /* does the actual lookup. */ int qrzfind(char *,int s, FILE *); /* Parse QRZ data record. */ void parse_record(char *, int s); /* Format QRZ Database Date. */ void formatdate(char *); /* Gobal variables. */ char pretty_date[12]; char prettycall[7]; char *qrzdir; char *qrzdrv; /* Taken from the QRZ CD-ROM disk. * This block is located at the start of each index */ /* * New Index Header Block Definition */ typedef struct { char dataname[16]; /* Name of the data file */ char bytesperkey[8]; /* Data Bytes per Index Item */ char numkeys[8]; /* Number of items in this index */ char keylen[8]; /* Length of each key item in bytes */ char version[8]; /* Database Version ID */ } index_header; /* * Old Index Header Block Definition */ typedef struct { char dataname[13]; /* Name of the data file */ long bytesperkey; /* Data Bytes per Index Item */ int numkeys; /* Number of items in this index */ int keylen; /* Length of each key item in bytes */ } old_index_header ; /* return values - 2= Callbook Error 1= not found, 0= okay */ int cb_lookup(s, str, fp) int s; char *str; FILE *fp; { if(qrzfind(str,s,fp)) return 0; else return 1; } int qrzfind(char *call_in, int s, FILE *fpout) { index_header idxhdr; old_index_header oldidxhdr; FILE *fp; char *buf; char *bufptr; char IndexFile[] = "callbkc.idx"; int size; int bytesperkey; /* Data Bytes per Index Item */ int numkeys; /* Number of items in this index */ int keylen; /* Length of each key item in bytes */ int slots; int i,j,k,found,slotcnt; long fpos; long frc; char temp[255]; char *cp; char *cp2; char call[8]; /* call needs to be blank filled. */ strcpy(call," "); /* Pretty call holds the original, un-qrz-formatted callsign. */ strcpy(prettycall, call_in); strupr(prettycall); k = strlen(call_in); if (k>6) { usprintf(s,"Callsign too long.\n"); return 0; } /* Callsigns in the QRZ Index are stored in a weird format. They are */ /* 6 characters in length ( padded with spaces ), in the format of */ /* ccdccc where the digit is always in the 3rd posistion. If the */ /* callsign is a 1-by-something callsign, the 2nd posistion will be */ /* blank. KF5MG will be stored as KF5MGb. N5VGC will be stored as */ /* Nb5VGC. ( the b are spaces ) */ /* */ i = 1; j = 1; call[0] = call_in[0]; if(!isdigit(call_in[j])) call[i++] = call_in[j++]; else call[i++] = ' '; if(isdigit(call_in[j])) { call[i++] = call_in[j++]; } else { /* No digit found in posistion 2 or 3. */ usprintf(s,"Error parsing callsign... %s\n", call_in); return 0; } if(isalpha(call_in[j])) call[i++] = call_in[j]; else call[i++] = ' '; j++; if(isalpha(call_in[j])) call[i++] = call_in[j]; else call[i++] = ' '; j++; if(isalpha(call_in[j])) call[i++] = call_in[j]; else call[i++] = ' '; call[6] = 0; strupr(call); qrzdir = strdup(getenv("QRZPATH")); qrzdrv = strdup(getenv("QRZDRV")); if(qrzdir == NULLCHAR) qrzdir = strdup("\\callbk"); if(qrzdrv == NULLCHAR) qrzdrv = strdup("C:"); /* Open the index file. We'll use it to tell us the name of the */ /* database file. We'll also find the database version and some */ /* other useful info. */ /* */ sprintf(temp,"%s%s\\%s",qrzdrv,qrzdir,IndexFile); if((fp = fopen(temp,"rt"))==NULL) { usprintf(s,"Error opening Index: %s\n",temp); free(qrzdir); free(qrzdrv); return 0; } size = fread(&idxhdr,sizeof(idxhdr),1,fp); if(size != 1) { usprintf(s,"Error reading Index Header.\n"); free(qrzdir); free(qrzdrv); return 0; } // Old Style Index has a '0' at pos 16 and 17. if((int)idxhdr.dataname[16] != 0) { // This is a 'new' style index bytesperkey = atoi(idxhdr.bytesperkey); /* size of data area. */ numkeys = atoi(idxhdr.numkeys); /* # of keys in file. */ keylen = atoi(idxhdr.keylen); /* length of each key. */ } else { // This is an 'old' style index. // rewind the file and read the header using the old_index_header struct. rewind(fp); size = fread(&oldidxhdr,sizeof(oldidxhdr),1,fp); if(size != 1) { usprintf(s,"Error reading Index Header.\n"); free(qrzdir); free(qrzdrv); return 0; } bytesperkey = oldidxhdr.bytesperkey; /* size of data area. */ numkeys = oldidxhdr.numkeys; /* # of keys in file. */ keylen = oldidxhdr.keylen; /* length of each key. */ } /* This is a 10K ish buffer. Each 'key' in the index covers almost */ /* 10K of data. Once you find the correct key, you have to read the */ /* 10K chunk of data from the data file. You then start searching */ /* for the correct callsign. This code uses the same 10k buffer to */ /* scan the index file ( typically 40K so you might do 4 reads ) to */ /* save memory. Once you've found the correct key, you calculate the */ /* offset into the database. You then read the data base into your */ /* 10K buffer. /* */ bufptr = malloc(bytesperkey+400); /* Get space for buffer */ slots = bytesperkey / keylen; /* Calculate # of slots */ found = 0; slotcnt = 0; do { /* Point floating buf pointer to start of big buffer. */ buf = bufptr; /* Read slots number of entries that are keylen in size */ size = fread(buf,keylen,slots,fp); if(size == 0) { usprintf(s,"Error reading Index file.\n"); found = 2; } /* Start scanning Index buffer. If the data is less than your search */ /* Value... keep going. If the Data is greater, then your done. You */ /* then subtract one from your slotcnt (unless it's an exact match) */ /* and that's the closet record to your data. */ /* */ for(i=0;i= 0) { if(strncmp(&temp[3],&call[3],3) > 0) { found = 1; slotcnt--; } else if(strncmp(&temp[2],&call[2],4) > 0) { slotcnt--; found = 1; } } if(found) break; /* *buf++; *buf++; *buf++; *buf++; *buf++; *buf++; */ buf += 6; } } while(!found); /* enddo */ slotcnt--; /* We're done with the Index so we can close it. */ fclose(fp); /* If we found a match, the calculate the offset and read the data. */ if(found == 1) { buf = bufptr; sprintf(temp,"%s%s\\%s",qrzdrv,qrzdir,idxhdr.dataname); if((fp = fopen(temp,"rt"))==NULL) { usprintf(s,"Error opening Database: %s\n",temp); free(bufptr); free(qrzdir); free(qrzdrv); return 0; } /* Just to to be save, we read 200 bytes before and after so we */ /* don't miss anything. */ /* seek to correct posistion in file . */ fpos = (long) bytesperkey*slotcnt; fpos -= 200; frc = lseek(fileno(fp),(long) fpos,SEEK_SET); if(frc < 1) { usprintf(s,"Error seeking Database file.\n"); free(bufptr); free(qrzdir); free(qrzdrv); return 0; } /* Read slot from callbk file. */ size = fread(buf,bytesperkey+400,1,fp); if(size < 1) { usprintf(s,"Error reading Database file.\n"); free(bufptr); free(qrzdir); free(qrzdrv); return 0; } /* Done with data file. Now we can close it too. Our users is either */ /* in our buffer or doesn't exist. */ fclose(fp); i = 0; for(;;) { if(i>bytesperkey+400) break; k = strcspn(buf,"\n"); strncpy(temp,buf,k); temp[k] = 0; for(j=0;j<=k;j++) /* *buf++; */ buf += 1; /* Find our user. */ if(strncmp(temp,call,6) == 0) { /* Found it. Now read and format the data. */ parse_record(temp,s); break; } i+=k; } } /* Done with the buffer. */ free(bufptr); free(qrzdir); free(qrzdrv); return found; } void parse_record(char *record, int s) { /* * Standard Record Format */ char callsign[7]; /* Call Sign Decoded */ char lastname[33]; /* Last Name */ char namesuffix[3]; /* Name Suffix */ char frstname[33]; /* First Name */ char middleinit[3]; /* Middle Initial */ char datelicensed[6]; /* Date Licensed mm/dd/yy */ char dateborn[6]; /* Date Born */ char dateexpires[6]; /* Date Born */ char streetaddr[33]; /* Street Address */ char city[33]; /* City */ char state[3]; /* State Code */ char zipcode[6]; /* Zip Code */ char license_class[3]; /* License Class */ char prevcall[7]; /* Previous Call */ char prevclass[3]; /* Previous Class */ char *cp; char fullname[80]; char address[80]; char temp[255]; char temp2[255]; int i,j,k; strcpy(temp2,record); cp = temp2; k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(callsign,temp); if(strlen(record) < 16) { usprintf(s,"%s is an old call for %s\n", prettycall, cp); return; } k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(lastname,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(namesuffix,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(frstname,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(middleinit,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(dateborn,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(datelicensed, temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(dateexpires,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(streetaddr,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(city,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(state,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(zipcode,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(license_class,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(prevcall,temp); k = strcspn(cp,","); strncpy(temp,cp,k); temp[k] = 0; for(j=0;j<=k;j++) cp += 1; strcpy(prevclass,temp); sprintf(fullname,"%s %s. %s, %s",frstname, middleinit, lastname, namesuffix); sprintf(address, "%s, %s, %s", city, state, zipcode); usprintf(s,"\n%-8s", prettycall); usprintf(s,"%-45s", fullname); formatdate(dateborn); usprintf(s,"Born: %s\n", pretty_date); usprintf(s,"%-8s%-45s","", streetaddr); formatdate(datelicensed); usprintf(s,"Class: %s %s\n", license_class, pretty_date); usprintf(s,"%-8s%-45s", "", address); usprintf(s,"Prev: %s %s\n", prevclass, prevcall); formatdate(dateexpires); usprintf(s,"%52s Expir: %s\n", "", pretty_date); return; } void formatdate(char *date){ char year[5]; char rest[4]; int mon; int day; int days; int years; int i; int dayarray[12] = { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; strncpy(year,date,2); year[2] = 0; years = atoi(year); if(years < 20) years += 2000; else years += 1900; strncpy(rest,&date[2],3); rest[3] = 0; days = atoi(rest); if((years % 4) != 0) if(days > 59) days++; for(i=0;i<12;i++){ if(days <= dayarray[i]) { mon = i; day = days - dayarray[i-1]; break; } } sprintf(pretty_date, "%02d/%02d/%04d", mon+1,day,years); } #endif