1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25   #include "config.h"
26 #endif  // HAVE_CONFIG_H
27 
28 #include "snprintf.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 
35 #if TIME_WITH_SYS_TIME
36   #include <sys/time.h>
37   #include <time.h>
38 #else   // TIME_WITH_SYS_TIME
39   #if HAVE_SYS_TIME_H
40     #include <sys/time.h>
41   #else  // HAVE_SYS_TIME_H
42     #include <time.h>
43   #endif // HAVE_SYS_TIME_H
44 #endif  // TIME_WITH_SYS_TIME
45 
46 #include <Xm/XmAll.h>
47 
48 #include "xastir.h"
49 #include "fcc_data.h"
50 #include "xa_config.h"
51 #include "main.h"
52 
53 // Must be last include file
54 #include "leak_detection.h"
55 
56 
57 
58 
59 
call_only(char * callsign)60 char *call_only(char *callsign)
61 {
62   int i, len;
63 
64   len = strlen(callsign);
65   for (i = 0; i < len; i++)
66   {
67     if (!isalnum((int)callsign[i]))
68     {
69       callsign[i]='\0';
70       i=len;
71     }
72   }
73   return(callsign);
74 }
75 
76 
77 
78 
79 
80 /* ====================================================================  */
81 /*    build a new (or newer if I check the file date) index file     */
82 /*    check for current ic index file                     */
83 /*    FG: added a date check in case the FCC file has been updated.    */
84 /*      appl.dat must have a time stamp newer than the index file time  */
85 /*      stamp. Use the touch command on the appl.dat file to make the   */
86 /*      time current if necessary.                                      */
87 //    How this works:  The index file contains a few callsigns and their
88 //    offsets into the large database file.  The code uses these as
89 //    jump-off points to look for a particular call, to speed things up.
90 /* ******************************************************************** */
build_fcc_index(int type)91 int build_fcc_index(int type)
92 {
93   FILE *fdb;
94   FILE *fndx;
95   unsigned long call_offset = 0;
96   unsigned long x = 0;
97   char fccdata[FCC_DATA_LEN+8];
98   char database_name[100];
99   int found,i,num;
100   char appl_file_path[MAX_VALUE];
101 
102   if (type==1)
103   {
104     xastir_snprintf(database_name, sizeof(database_name), "fcc/appl.dat");
105   }
106   else
107   {
108     xastir_snprintf(database_name, sizeof(database_name), "fcc/EN.dat");
109   }
110 
111   /* ====================================================================    */
112   /*    If the index file is there, exit                */
113   /*                                    */
114   get_user_base_dir("data/appl.ndx", appl_file_path,
115                     sizeof(appl_file_path));
116   if (filethere(appl_file_path))
117   {
118     /* if file is there make sure the index date is newer */
119     if (file_time(get_data_base_dir(database_name))<=file_time(appl_file_path))
120     {
121       return(1);
122     }
123     else
124     {
125       // FCC index old, rebuilding
126       statusline(langcode("STIFCC0100"),1);
127 
128       fprintf(stderr,"FCC index is old.  Rebuilding index.\n");
129 //            XmTextFieldSetString(text,"FCC index old, rebuilding");
130 //            XtManageChild(text);
131 //            XmUpdateDisplay(XtParent(text));     // DK7IN: do we need this ???
132     }
133   }
134 
135   /* ====================================================================    */
136   /*    Open the database and index file                */
137   /*                                    */
138   fdb=fopen(get_data_base_dir(database_name),"rb");
139   if (fdb==NULL)
140   {
141     fprintf(stderr,"Build:Could not open FCC data base: %s\n", get_data_base_dir(database_name) );
142     return(0);
143   }
144 
145   fndx=fopen(appl_file_path,"w");
146   if (fndx==NULL)
147   {
148     fprintf(stderr,"Build:Could not open/create FCC data base index: %s\n", appl_file_path );
149     (void)fclose(fdb);
150     return(0);
151   }
152 
153   /* ====================================================================    */
154   /*    write out the current callsign and RBA of the db file         */
155   /*    skip (index_skip) records and do it again until no more        */
156   /*                                    */
157   xastir_snprintf(fccdata,sizeof(fccdata)," ");
158   while(!feof(fdb))
159   {
160     call_offset = (unsigned long)ftell(fdb);
161     if (fgets(fccdata, (int)sizeof(fccdata), fdb) == NULL)
162     {
163       // error occurred
164       fprintf(stderr,"Build: Could not read fcc data base: %s \n", appl_file_path);
165       (void)fclose(fdb);
166       return(0);
167     }
168     found=0;
169     num=0;
170     if (type==2)
171     {
172       for(i=0; i<14 && !found; i++)
173       {
174         if(fccdata[i]=='|')
175         {
176           num++;
177           if(num==4)
178           {
179             found=i+1;
180           }
181         }
182       }
183     }
184     (void)call_only(fccdata+found);
185     fprintf(fndx,"%-6.6s%li\n",fccdata+found,call_offset+found);
186     for (x=0; x<=500 && !feof(fdb); x++)
187     {
188       if (fgets(fccdata, (int)sizeof(fccdata), fdb)==NULL)
189       {
190         break;
191       }
192     }
193   }
194   (void)fclose(fdb);
195   (void)fclose(fndx);
196 
197 //    XmTextFieldSetString(text,"");
198 //    XtManageChild(text);
199 
200   return(1);
201 }
202 
203 
204 
205 
206 
207 /* ====================================================================    */
208 /*    Check for ic data base file                    */
209 /*    Check/build the index                        */
210 /*                                    */
211 /* ******************************************************************** */
check_fcc_data(void)212 int check_fcc_data(void)
213 {
214   int fcc_data_available = 0;
215   if (filethere(get_data_base_dir("fcc/EN.dat")) && filethere(get_data_base_dir("fcc/appl.dat")))
216   {
217     if(file_time(get_data_base_dir("fcc/appl.dat"))<=file_time(get_data_base_dir("fcc/EN.dat")))
218     {
219       /*fprintf(stderr,"NEW FORMAT FCC DATA FILE is NEWER THAN OLD FCC FORMAT\n");*/
220       if (build_fcc_index(2))
221       {
222         fcc_data_available=2;
223       }
224       else
225       {
226         fprintf(stderr,"Check:Could not build fcc data base index\n");
227         fcc_data_available=0;
228       }
229     }
230     else
231     {
232       /*fprintf(stderr,"OLD FORMAT FCC DATA FILE is NEWER THAN NEW FCC FORMAT\n");*/
233       if (build_fcc_index(1))
234       {
235         fcc_data_available=1;
236       }
237       else
238       {
239         fprintf(stderr,"Check:Could not build fcc data base index\n");
240         fcc_data_available=0;
241       }
242     }
243   }
244   else
245   {
246     if (filethere(get_data_base_dir("fcc/EN.dat")))
247     {
248       /*fprintf(stderr,"NO OLD FCC, BUT NEW FORMAT FCC DATA AVAILABLE\n");*/
249       if (build_fcc_index(2))
250       {
251         fcc_data_available=2;
252       }
253       else
254       {
255         fprintf(stderr,"Check:Could not build fcc data base index\n");
256         fcc_data_available=0;
257       }
258     }
259     else
260     {
261       if (filethere(get_data_base_dir("fcc/appl.dat")))
262       {
263         /*fprintf(stderr,"NO NEW FCC, BUT OLD FORMAT FCC DATA AVAILABLE\n");*/
264         if (build_fcc_index(1))
265         {
266           fcc_data_available=1;
267         }
268         else
269         {
270           fprintf(stderr,"Check:Could not build fcc data base index\n");
271           fcc_data_available=0;
272         }
273       }
274     }
275   }
276   return(fcc_data_available);
277 }
278 
279 
280 
281 
282 
search_fcc_data_appl(char * callsign,FccAppl * data)283 int search_fcc_data_appl(char *callsign, FccAppl *data)
284 {
285   FILE *f;
286   char line[200];
287   int line_pos;
288   char data_in[16385];
289   int found, xx, bytes_read;
290   char temp[15];
291   int len;
292   int which;
293   int i,ii;
294   int pos_it;
295   int llen;
296   char calltemp[8];
297   int pos,ix,num;
298   FILE *fndx;
299   long call_offset = 0;
300   char char_offset[16];
301   char index[32];
302   char appl_file_path[MAX_VALUE];
303 
304   data->id_file_num[0] = '\0';
305   data->type_purpose[0] = '\0';
306   data->type_applicant=' ';
307   data->name_licensee[0] = '\0';
308   data->text_street[0] = '\0';
309   data->text_pobox[0] = '\0';
310   data->city[0] = '\0';
311   data->state[0] = '\0';
312   data->zipcode[0] = '\0';
313   data->date_issue[0] = '\0';
314   data->date_expire[0] = '\0';
315   data->date_last_change[0] = '\0';
316   data->id_examiner[0] = '\0';
317   data->renewal_notice=' ';
318   xastir_snprintf(temp,
319                   sizeof(temp),
320                   "%s",
321                   callsign);
322   (void)call_only(temp);
323 
324   xastir_snprintf(calltemp, sizeof(calltemp), "%-6.6s", temp);
325 // calltemp doesn't appear to get used anywhere...
326 
327   /* add end of field data */
328   strncat(temp, "|", sizeof(temp) - 1 - strlen(temp));
329   len=(int)strlen(temp);
330   found=0;
331   line_pos=0;
332   /* check the database again */
333   which = check_fcc_data();
334 
335   // Check for first letter of a U.S. callsign
336   if (! (callsign[0] == 'A' || callsign[0] == 'K' || callsign[0] == 'N' || callsign[0] == 'W') )
337   {
338     return(0);  // Not found
339   }
340 
341   // ====================================================================
342   // Search thru the index, get the RBA
343   //
344   // This gives us a jumping-off point to start looking in the right
345   // neighborhood for the callsign of interest.
346   //
347   get_user_base_dir("data/appl.ndx", appl_file_path, sizeof(appl_file_path));
348   fndx=fopen(appl_file_path,"r");
349   if (fndx!=NULL)
350   {
351     if (fgets(index,(int)sizeof(index),fndx) == NULL)
352     {
353       // Error occurred
354       fprintf(stderr,"Search:Could not read FCC database index(1): %s\n",appl_file_path);
355       return(0);
356     }
357 
358     memcpy(char_offset, &index[6], sizeof(char_offset));
359     char_offset[sizeof(char_offset)-1] = '\0';  // Terminate string
360 
361     // Search through the indexes looking for a callsign which is
362     // close to the callsign of interest.  If callsign is later in
363     // the alphabet than the current index, snag the next index.
364     while (!feof(fndx) && strncmp(callsign,index,6) > 0)
365     {
366       memcpy(char_offset, &index[6], sizeof(char_offset));
367       char_offset[sizeof(char_offset)-1] = '\0';  // Terminate string
368       if (fgets(index,(int)sizeof(index),fndx) == NULL)
369       {
370         // Error occurred
371         fprintf(stderr,"Search:Could not read FCC database index(2): %s\n", appl_file_path );
372         return(0);
373       }
374     }
375   }
376   else
377   {
378     fprintf(stderr,"Search:Could not open FCC data base index: %s\n", appl_file_path );
379     return (0);
380   }
381   call_offset = atol(char_offset);
382 
383   (void)fclose(fndx);
384 
385   /* ====================================================================    */
386   /*    Continue with the original search                */
387   /*                                                                */
388 
389   f=NULL;
390   switch (which)
391   {
392     case(1):
393       f=fopen(get_data_base_dir("fcc/appl.dat"),"r");
394       break;
395 
396     case(2):
397       f=fopen(get_data_base_dir("fcc/EN.dat"),"r");
398       break;
399 
400     default:
401       break;
402   }
403   if (f!=NULL)
404   {
405     (void)fseek(f, call_offset,SEEK_SET);
406     while (!feof(f) && !found)
407     {
408       bytes_read=(int)fread(data_in,1,16384,f);
409       if (bytes_read>0)
410       {
411         for (xx=0; (xx<bytes_read) && !found; xx++)
412         {
413           if(data_in[xx]!='\n' && data_in[xx]!='\r')
414           {
415             if (line_pos<199)
416             {
417               line[line_pos++]=data_in[xx];
418               line[line_pos]='\0';
419             }
420           }
421           else
422           {
423             line_pos=0;
424             /*fprintf(stderr,"line:%s\n",line);*/
425             pos=0;
426             num=0;
427             if (which==2)
428             {
429               for (ix=0; ix<14 && !pos; ix++)
430               {
431                 if (line[ix]=='|')
432                 {
433                   num++;
434                   if (num==4)
435                   {
436                     pos=ix+1;
437                   }
438                 }
439               }
440             }
441             if (strncmp(line+pos,temp,(size_t)len)==0)
442             {
443               found=1;
444               /*fprintf(stderr,"line:%s\n",line);*/
445               llen=(int)strlen(line);
446               /* replace "|" with 0 */
447               for (ii=pos; ii<llen; ii++)
448               {
449                 if (line[ii]=='|')
450                 {
451                   line[ii]='\0';
452                 }
453               }
454               pos_it=pos;
455               for (i=0; i<15; i++)
456               {
457                 for (ii=pos_it; ii<llen; ii++)
458                 {
459                   if (line[ii]=='\0')
460                   {
461                     pos_it=ii;
462                     ii=llen+1;
463                   }
464                 }
465                 pos_it++;
466                 if (line[pos_it]!='\0')
467                 {
468                   /*fprintf(stderr,"DATA %d %d:%s\n",i,pos_it,line+pos_it);*/
469                   switch (which)
470                   {
471                     case(1):
472                       switch(i)
473                       {
474                         case(0):
475                           xastir_snprintf(data->id_file_num,sizeof(data->id_file_num),"%s",line+pos_it);
476                           break;
477 
478                         case(1):
479                           xastir_snprintf(data->type_purpose,sizeof(data->type_purpose),"%s",line+pos_it);
480                           break;
481 
482                         case(2):
483                           data->type_applicant=line[pos_it];
484                           break;
485 
486                         case(3):
487                           xastir_snprintf(data->name_licensee,sizeof(data->name_licensee),"%s",line+pos_it);
488                           break;
489 
490                         case(4):
491                           xastir_snprintf(data->text_street,sizeof(data->text_street),"%s",line+pos_it);
492                           break;
493 
494                         case(5):
495                           xastir_snprintf(data->text_pobox,sizeof(data->text_pobox),"%s",line+pos_it);
496                           break;
497 
498                         case(6):
499                           xastir_snprintf(data->city,sizeof(data->city),"%s",line+pos_it);
500                           break;
501 
502                         case(7):
503                           xastir_snprintf(data->state,sizeof(data->state),"%s",line+pos_it);
504                           break;
505 
506                         case(8):
507                           xastir_snprintf(data->zipcode,sizeof(data->zipcode),"%s",line+pos_it);
508                           break;
509 
510                         case(9):
511                           xastir_snprintf(data->date_issue,sizeof(data->date_issue),"%s",line+pos_it);
512                           break;
513 
514                         case(11):
515                           xastir_snprintf(data->date_expire,sizeof(data->date_expire),"%s",line+pos_it);
516                           break;
517 
518                         case(12):
519                           xastir_snprintf(data->date_last_change,sizeof(data->date_last_change),"%s",line+pos_it);
520                           break;
521 
522                         case(13):
523                           xastir_snprintf(data->id_examiner,sizeof(data->id_examiner),"%s",line+pos_it);
524                           break;
525 
526                         case(14):
527                           data->renewal_notice=line[pos_it];
528                           break;
529 
530                         default:
531                           break;
532                       }
533                       break;
534 
535                     case(2):
536                       switch (i)
537                       {
538                         case(0):
539                           xastir_snprintf(data->id_file_num,sizeof(data->id_file_num),"%s",line+pos_it);
540                           break;
541 
542                         case(2):
543                           xastir_snprintf(data->name_licensee,sizeof(data->name_licensee),"%s",line+pos_it);
544                           break;
545 
546                         case(10):
547                           xastir_snprintf(data->text_street,sizeof(data->text_street),"%s",line+pos_it);
548                           break;
549 
550                         case(11):
551                           xastir_snprintf(data->city,sizeof(data->city),"%s",line+pos_it);
552                           break;
553 
554                         case(12):
555                           xastir_snprintf(data->state,sizeof(data->state),"%s",line+pos_it);
556                           break;
557 
558                         case(13):
559                           xastir_snprintf(data->zipcode,sizeof(data->zipcode),"%s",line+pos_it);
560                           break;
561 
562                         default:
563                           break;
564                       }
565                       break;
566 
567                     default:
568                       break;
569                   }
570                 }
571               }
572             }
573             else
574             {
575               // Check whether we passed the alphabetic
576               // location for the callsign.  Return if so.
577               if ( (temp[0] < line[pos]) ||
578                    ( (temp[0] == line[pos]) && (temp[1] < line[pos+1]) ) )
579               {
580 
581                 // "Callsign Search", "Callsign Not Found!"
582                 popup_message_always(langcode("STIFCC0101"),
583                                      langcode("STIFCC0102") );
584 
585                 //fprintf(stderr,"%c%c\t%c%c\n",temp[0],temp[1],line[pos],line[pos+1]);
586                 (void)fclose(f);
587                 return(0);
588               }
589             }
590           }
591         }
592       }
593     }
594     (void)fclose(f);
595   }
596   else
597   {
598     fprintf(stderr,"Could not open FCC appl data base at: %s\n", get_data_base_dir("fcc/") );
599   }
600   return(found);
601 }
602 
603 
604