1 /*
2 * USERLIST.C
3 *
4 * Written by Paul Edwards and modified by Bill Bond.
5 * Modified to make it do a binary search by Bill Bond.
6 * Modfied by Tobias Ernst (based on code by Kim Lykkegaard) to support
7 * multiple results for a single lookup.
8 * Released to the public domain.
9 *
10 * Look up user name in a Fido userlist.
11 *
12 * Note: The Fido userlist consists of fixed length records sorted
13 * alphabetically. A record is in the format:
14 *
15 * Bloggs, Joe 3:666/666
16 */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <time.h>
22 #include "addr.h"
23 #include "nedit.h"
24 #include "winsys.h"
25 #include "keys.h"
26 #include "menu.h"
27 #include "msged.h"
28 #include "memextra.h"
29 #include "strextra.h"
30 #include "nshow.h"
31 #include "userlist.h"
32 #include "screen.h"
33 #include "mctype.h"
34
35 #define SELBOX_WRTOVER 7
36 #if defined(MSDOS) && (!defined(__FLAT__))
37 #define LOOKUPMAX 200 /* prevent memory exhaustage */
38 #else
39 #define LOOKUPMAX 200000L
40 #endif
41 #define LOOKUPSTEP 50
42
filelen(FILE * fp)43 static long filelen(FILE * fp)
44 {
45 long ret;
46
47 ret = fseek(fp, 0, SEEK_END);
48 if (ret != 0L)
49 {
50 return (0L);
51 }
52 ret = ftell(fp);
53 if (ret < 0)
54 {
55 ret = 0;
56 }
57 return ret;
58 }
59
lookup(char * name,char * fn)60 FIDO_ADDRESS lookup(char *name, char *fn)
61 {
62 FILE *fp;
63 FIDO_ADDRESS tmpAddr;
64 char buf[200];
65 char revName[200];
66 char **nodeinfo = NULL;
67 int lenRev, result, fureclen = 1, done = 0;
68 int i, j, k;
69 long found = 0, lookupmax = 0L;
70 long low, mid, high;
71 char *p;
72
73 tmpAddr = CurArea.addr;
74 if (tmpAddr.domain != NULL)
75 {
76 tmpAddr.domain = xstrdup(tmpAddr.domain);
77 }
78 tmpAddr.notfound = 1;
79 fp = fopen(fn, "r");
80 if (fp == NULL)
81 {
82 return (tmpAddr);
83 }
84 makeReverse(revName, name);
85 strlwr(revName);
86 lenRev = strlen(revName);
87 if (fgets(buf, sizeof buf, fp) != NULL)
88 {
89 fureclen = strlen(buf);
90 #ifndef UNIX
91 fureclen++; /* take the \r character into account */
92 /* i++; */
93 #endif
94 }
95 high = filelen(fp) / fureclen;
96 low = 0;
97 while (low <= high && !done)
98 {
99 mid = low + (high - low) / 2;
100 fseek(fp, (long)mid * fureclen, SEEK_SET);
101 if (fgets(buf, sizeof buf, fp) != NULL)
102 {
103 strlwr(buf);
104 result = strncmp(buf, revName, lenRev);
105 if (result > 0)
106 {
107 high = mid - 1;
108 }
109 else if (result < 0)
110 {
111 low = mid + 1;
112 }
113 else
114 {
115 if (!OpenMsgWnd(50, 6, " Scanning Fido User List ",
116 NULL, 0, 0))
117 {
118 return tmpAddr;
119 }
120 SendMsgWnd("Press Esc to stop", 1);
121
122 /* seek backwards to find the first match */
123 while (result == 0)
124 {
125 mid=mid-10;
126 if (mid<0)
127 {
128 fseek(fp, 0L, SEEK_SET);
129 mid = 0;
130 break;
131 }
132 fseek(fp, (long)mid * fureclen, SEEK_SET);
133 fgets(buf, sizeof buf, fp);
134 strlwr(buf);
135 result = strncmp(buf, revName, lenRev);
136 if (KeyHit() && GetKey() == Key_Esc)
137 {
138 CloseMsgWnd();
139 return tmpAddr;
140 }
141 }
142
143 /* we seeked backwards too far, now find the first match. */
144 while (result != 0)
145 {
146 fgets(buf, sizeof buf, fp);
147 strlwr(buf);
148 result = strncmp(buf, revName, lenRev);
149 if (KeyHit() && GetKey() == Key_Esc)
150 {
151 CloseMsgWnd();
152 return tmpAddr;
153 }
154 }
155
156 /* Now we have found the first match. Implement a lookup
157 window */
158 while (result == 0)
159 {
160 /* kill trailing LFs and CRs */
161 if (buf[strlen(buf)-1]=='\n')
162 {
163 buf[strlen(buf)-1]='\0';
164 }
165 if (buf[strlen(buf)-1]=='\r')
166 {
167 buf[strlen(buf)-1]='\0';
168 }
169
170 /* uppercase the first letters of the name */
171 buf[0] = toupper(buf[0]);
172 for(i = 1; *buf && i < strlen(buf) - 1; i++)
173 {
174 if ((buf[i] == ' ') && (buf[i+1] != ' '))
175 {
176 buf[i + 1] = toupper(buf[i + 1]);
177 }
178 }
179
180 if (found + 1 >= lookupmax)
181 {
182 if (lookupmax + LOOKUPSTEP > LOOKUPMAX)
183 {
184 break;
185 }
186 if (lookupmax == 0)
187 {
188 lookupmax = LOOKUPSTEP;
189 nodeinfo = xmalloc(sizeof(char *) * lookupmax);
190 }
191 else
192 {
193 lookupmax += LOOKUPSTEP;
194 nodeinfo = xrealloc(nodeinfo,
195 sizeof(char *) * lookupmax);
196 }
197 }
198
199 nodeinfo[found++] = xstrdup(buf);
200 if (fgets(buf, sizeof buf, fp) == NULL)
201 {
202 break;
203 }
204 strlwr(buf);
205 result = strncmp(buf, revName, lenRev);
206 if (KeyHit() && GetKey() == Key_Esc)
207 {
208 CloseMsgWnd();
209 return tmpAddr;
210 }
211 }
212 nodeinfo[found++] = NULL;
213
214 CloseMsgWnd();
215
216
217 result = DoMenu(8, 7, 8+61,
218 (5 + found > maxy - 4) ? maxy - 4 : 5 + found,
219 nodeinfo, 0,
220 SELBOX_WRTOVER, " Nodelist Lookup ");
221 if (result == (unsigned long) - 1)
222 {
223 fclose(fp);
224 return tmpAddr;
225 }
226 strcpy(buf, nodeinfo[result]);
227
228 /* Use the name as it was found in the userlist */
229 i = strlen(buf) - 1;
230 while (i > 0 && m_isspace(buf[i]))
231 {
232 i--;
233 }
234 while (i > 0 && !m_isspace(buf[i]))
235 {
236 i--;
237 }
238 while (i > 0 && m_isspace(buf[i]))
239 {
240 i--;
241 }
242 j = i;
243 while (i > 0 && buf[i] != ',')
244 {
245 i--;
246 }
247 if (buf[i] == ',')
248 {
249 if (buf[i + 1] == ' ')
250 {
251 i++;
252 }
253 if (j - i + 1 > 0)
254 {
255 memmove(name, buf + i + 1, j - i);
256 }
257 k = i;
258 if (buf[i] == ' ')
259 {
260 i--;
261 }
262 if (i > 0)
263 {
264 name[j - k] = ' ';
265 memmove(name + j - k + 1, buf, k);
266 name[j] = '\0';
267 }
268 }
269 else
270 {
271 if (j != 0)
272 {
273 memcpy(name, buf, j + 1);
274 name[j+2] = '\0';
275 }
276 else
277 {
278 name[0] = '\0';
279 }
280 }
281
282 for(i = 0; i < found; i++)
283 {
284 if (nodeinfo[i] == NULL)
285 {
286 break;
287 }
288 xfree(nodeinfo[i]);
289 }
290
291 p = buf + strlen(buf) - 1;
292 while ((p >= buf) && (m_isspace(*p)))
293 {
294 *p = '\0';
295 p--;
296 }
297 while ((p >= buf) && (!m_isspace(*p)))
298 {
299 p--;
300 }
301 if ((p >= buf) && (m_isspace(*p)))
302 {
303 p++;
304 }
305 if (tmpAddr.domain != NULL)
306 {
307 xfree(tmpAddr.domain);
308 }
309 fclose(fp);
310 return parsenode(p);
311 }
312 }
313 else
314 {
315 done = 0; /* force end of loop */
316 }
317 }
318 fclose(fp);
319 return tmpAddr;
320 }
321
makeReverse(char * revName,char * name)322 void makeReverse(char *revName, char *name)
323 {
324 char *lastSpace;
325 int len;
326
327 lastSpace = strrchr(name, ' ');
328 if (lastSpace == NULL)
329 {
330 strcpy(revName, name);
331 return;
332 }
333 len = strlen(lastSpace + 1);
334 memcpy(revName, lastSpace + 1, len);
335 memcpy(revName + len, ", ", 2);
336 memcpy(revName + len + 2, name, (size_t) (lastSpace - name));
337 *(revName + len + 2 + (size_t) (lastSpace - name)) = '\0';
338 }
339