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