1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 //              David Freese, W1HKJ
4 //
5 // This file is part of fldigi
6 //
7 // fldigi is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // fldigi 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, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20 
21 #ifndef QRZHEADER
22 
23 // To include the email code remove the comment specifier from the following line
24 #define HAVE_EMAIL
25 
26 // QRZ CDROM data structures
27 
28 /*
29 **     Index Header Block Definition (Version 2)
30 **     (applies to all QRZ CDROMS from Version 2 onward)
31 **
32 **     This block is located at the start of each index
33 */
34 
35 typedef struct {
36   char  dataname[16];    /* Name of the data file            */
37   char  bytesperkey[8];  /* Data Bytes per Index Item        */
38   char  numkeys[8];      /* Number of items in this index    */
39   char  keylen[8];       /* Length of each key item in bytes */
40   char  version[8];      /* Database Version ID              */
41 } index_header;
42 
43 /*
44 
45 Index Usage
46 
47 The name index is set to a maximum of 16 characters with longer names
48 being truncated.   Names are stored in last-first format with a space
49 between the names.  The city/state index uses 12 characters per entry,
50 the callsign index 6 characters and the zip code index 5 characters.
51 
52 The data which follows the header is simply a long list of single field
53 records. The records are tightly packed on 'bytesperkey' boundaries
54 without separators.  There is no guarantee of a null terminator on any
55 index record entry.
56 
57 When the program qrz.exe is run it first searches for a drive
58 containing the base directory \CALLBK .  Next, it loads all four index
59 files (callbkc.idx, callbkn.idx, callbks.idx and callbkz.idx) into
60 tables in memory.  These tables were kept small so as not to place an
61 undue RAM requirement on the user's system.
62 
63 Next, when a user specifies a field and key to search, the program
64 searches the relevant index table and returns the closest match lower
65 (or equal to) the supplied key.  The table position of this key is then
66 taken and multiplied by the 'bytesperkey' value to arrive at a database
67 file offset.  This offset is then used to perform the first and only
68 seek into the database.  Once on position within the file, a sequential
69 search is performed to return the match.  The search terminates at the
70 next index key value if the field is not found.
71 
72 The database files all have the same format.  The records each consist
73 of comma separated fields which end with a single newline '\n'  (ASCII
74 0xa) character.  Blank fields are simply stored as a comma.  Every
75 record has the same number of commas in it.  Actual comma's in the data
76 field are stored as a semi-colon ';' which should be replaced by a
77 comma in the user's output formatting routine.
78 
79 
80 Example:
81 
82 AA7BQ ,LLOYD,,FRED L,,53340,90009,00009,8215 E WOOD DR,SCOTTSDALE,AZ,
83 85260,E,KJ6RK,A
84 
85 The callsign database is sorted by SUFFIX, AREA, PREFIX.
86 
87 For example, the following order would be observed:
88 
89 QE24AA
90 ...
91 ZZ99ZZ
92 ...
93 A 0A
94 ...
95 AA0AAA
96 ...
97 ZZ9ZZZ
98 
99 This ordering also pertains to the index file since it is just a snaphot of
100 every nth record in the database.
101 
102 */
103 
104 /*
105 **    Standard Record Field Offsets
106 */
107 #define QRZLIB_CALL            0
108 #define QRZLIB_LNAME           1
109 #define QRZLIB_JR              2
110 #define QRZLIB_FNAME           3
111 #define QRZLIB_MI              4
112 #define QRZLIB_DOB             5
113 #define QRZLIB_EFDATE          6
114 #define QRZLIB_EXPDATE         7
115 #define QRZLIB_MAIL_STR        8
116 #define QRZLIB_MAIL_CITY       9
117 #define QRZLIB_MAIL_ST         10
118 #define QRZLIB_MAIL_ZIP        11
119 #define QRZLIB_CLASS           12
120 #define QRZLIB_P_CALL          13
121 #define QRZLIB_P_CLASS         14
122 
123 /*
124 
125 The fields JR and MI were obsoleted by the FCC in July 1994.
126 
127 The callsign fields are arranged in a strict "ccdccc" columnar format
128 where 'c' represents a letter and 'd' a digit. Callsigns which do not
129 conform to the "ccdccc" format are space filled in the relevant
130 positions.  This field is rearranged to the proper layout by the user
131 program's output formatting routines.
132 
133 All dates are stored in 5 character Julian format, e.g. 93003 equals
134 January 3, 1993.  Dates before 1900 or after year 2000 must be
135 determined by their context usage.  In other words, if the resultant
136 age does not make sense, then it's wrong.  For example, all licenses
137 expire in the future so 02 is 2002.  Birthdays are more difficult
138 but most can be determined to be greater than 10 years old.  This is
139 not a perfect method, but it does yield satisfactory results.
140 
141 Some folks may notice that the database no longer contains station
142 location information.  This information is no longer supplied nor
143 available from the FCC since it is no longer a part of their record
144 keeping (See the May 1993 QST for more info).
145 
146 
147 Cross Reference Information
148 
149 Callsigns in the database are now cross-referenced to both the current
150 and the previous call sign for each entry in which they are available.
151 A cross reference record takes the form of 'old,new' with no other
152 information in the record.  A record can be identified as a cross
153 reference either one of two ways:
154 
155     First, if the record length is less than 15 characters, then
156     it is a cross reference record.
157 
158     Secondly, if the record contains only one comma "," , then
159     it is a cross reference record.
160 
161 It is not necessary to test for both cases, either will do.
162 
163 When a cross reference record is encountered, you must fetch the second
164 field and restart the search to return the primary reference.
165 
166 */
167 
168 #include <stdlib.h>
169 #include <stdio.h>
170 #include <string.h>
171 
172 extern char *Composite( char * );
173 
174 class QRZ
175 {
176   private:
177     char          criteria;
178     index_header  idxhdr;
179     char          *data;
180     char          *index;
181     char          *top;
182     FILE          *idxfile;
183     long          idxsize;
184     FILE          *datafile;
185     long          dataoffset;
186     long          databytesread;
187     char          *dfptr;
188     char          *endofline;
189     char          *idxptr;
190     int           found;
191     char          recbuffer[512];
192     unsigned int  datarecsize;
193     long          numkeys;
194     int           keylen;
195     void          OpenQRZFiles( const char * );
196     int           FindCallsign( char * );
197     int           FindName( char * );
198     int           FindState( char * );
199     int           FindZip( char * );
200     int           ReadDataBlock( long );
201     int           nextrec();
202 	bool		  hasImage;
203 
204     char *Qcall;
205     char *Qlname;
206     char *Qfname;
207     char *Qdob;
208     char *Qefdate;
209     char *Qexpdate;
210     char *Qmail_str;
211     char *Qmail_city;
212     char *Qmail_st;
213     char *Qmail_zip;
214     char *Qopclass;
215     char *Qp_call;
216     char *Qimagefname;
217     char *Qp_class;
218 
219     int  QRZvalid;
220 
221   public:
222     QRZ( const char * );
223     QRZ( const char *, char );
224     ~QRZ();
225 
226     int  CallComp( char *, char * );
227     int  CompState( const char *, const char *, const char * );
228 
229     int  getQRZvalid();
230     void NewDBpath( const char * );
231 
232     int  FindRecord( char * );
233     int  NextRecord();
234     int  ReadRec();
235     int  GetCount( char * );
236     char *GetCall();
237     const char *GetLname();
238     const char *GetFname();
239     const char *GetDOB();
240     const char *GetEFdate();
241     const char *GetEXPdate();
242     const char *GetStreet();
243     const char *GetCity();
244     const char *GetState();
245     const char *GetZIP();
246     const char *GetOPclass();
247     const char *GetPriorCall();
248     const char *GetPriorClass();
249     const char *GetImageFileName();
250     char *CSV_Record();
251     char *Fmt_Record();
252 	bool ImageExists();
ImageFileName()253 	const char *ImageFileName() {return Qimagefname;};
254 };
255 
256 extern void SetQRZdirectory(char *dir);
257 extern int  filename_expand(char *to,int tolen, const char *from);
258 
259 #define QRZHEADER
260 
261 #endif
262