1 /*****************************************************************************
2 * AreaFix for HPT (FTN NetMail/EchoMail Tosser)
3 *****************************************************************************
4 * Copyright (C) 2000
5 *
6 * Lev Serebryakov
7 *
8 * Fido: 2:5030/661
9 * Internet: lev@serebryakov.spb.ru
10 * St.Petersburg, Russia
11 *
12 * This file is part of HPT.
13 *
14 * HPT is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2, or (at your option) any
17 * later version.
18 *
19 * HPT is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with HPT; see the file COPYING. If not, write to the Free
26 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27 *****************************************************************************
28 * $Id$
29 */
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <ctype.h>
36
37
38 #include <huskylib/compiler.h>
39
40 #ifdef HAS_UNISTD_H
41 # include <unistd.h>
42 #endif
43
44
45 /* export functions from DLL */
46 #define DLLEXPORT
47 #include <huskylib/huskyext.h>
48
49 #include "arealist.h"
50 #include "common.h"
51
52 #define LIST_PAGE_SIZE 256
53
54 static s_fidoconfig *config; /* extern? see fidoconf.c */
55
newAreaList(s_fidoconfig * cfg)56 ps_arealist newAreaList(s_fidoconfig *cfg)
57 {
58 ps_arealist al;
59
60 config = cfg; /* This may cause problem if somewhere release memory... */
61 if(NULL == (al = malloc(sizeof(s_arealist))))
62 return NULL;
63 al->areas = NULL;
64 al->count = 0;
65 al->maxcount = LIST_PAGE_SIZE;
66 if(NULL == (al->areas = malloc(al->maxcount*sizeof(s_arealistitem))) )
67 {
68 nfree(al);
69 return NULL;
70 }
71 return al;
72 }
73
freeAreaList(ps_arealist al)74 void freeAreaList(ps_arealist al)
75 {
76 int i;
77
78 if(al) {
79 if(al->areas && al->maxcount) {
80 for(i = 0; i < al->count; i++) {
81 nfree(al->areas[i].tag);
82 nfree(al->areas[i].desc);
83 nfree(al->areas[i].grp);
84 }
85 nfree(al->areas);
86 }
87 nfree(al);
88 }
89 return;
90 }
91
addAreaListItem(ps_arealist al,int active,int rescanable,int import,int aexport,int mandatory,char * tag,char * desc,char * grp)92 int addAreaListItem(ps_arealist al, int active, int rescanable, int import, int aexport, int mandatory, char *tag, char *desc, char *grp)
93 {
94 ps_arealistitem areas;
95 int l;
96
97 if(al->count == al->maxcount) {
98 if(NULL == (areas = realloc(al->areas,(al->maxcount+LIST_PAGE_SIZE)*sizeof(s_arealistitem)))) return 1;
99 al->areas = areas;
100 al->maxcount += LIST_PAGE_SIZE;
101 }
102 al->areas[al->count].active = active;
103 al->areas[al->count].rescanable = rescanable ? 2 : 0;
104 al->areas[al->count].readonly = import ? 0 : 3;
105 al->areas[al->count].writeonly = aexport ? 0 : 4;
106 al->areas[al->count].fullaccess = (aexport && import) ? 5 : 0;
107 al->areas[al->count].mandatory = mandatory ? 6 : 0;
108 al->areas[al->count].tag = sstrdup(tag);
109 al->areas[al->count].grp = sstrdup(grp ? grp : "");
110 if(desc) {
111 l = strlen(desc);
112 al->areas[al->count].desc = smalloc(l+3);
113 if('"' == desc[0] && '"' == desc[l-1]) {
114 strcpy(al->areas[al->count].desc,desc);
115 } else {
116 al->areas[al->count].desc[0] = '"';
117 strcpy(&al->areas[al->count].desc[1],desc);
118 al->areas[al->count].desc[l+1] = '"';
119 al->areas[al->count].desc[l+2] = '\x00';
120 }
121 }
122 else al->areas[al->count].desc = NULL;
123 al->count++;
124
125 return 0;
126 }
127
compare_bytag(const void * a,const void * b)128 static int compare_bytag(const void *a, const void *b) {
129 return sstricmp(((ps_arealistitem)a)->tag,((ps_arealistitem)b)->tag);
130 }
131
compare_bygrp(const void * a,const void * b)132 static int compare_bygrp(const void *a, const void *b) {
133 return strcmp(((ps_arealistitem)a)->grp,((ps_arealistitem)b)->grp);
134 }
135
compare_bygrptag(const void * a,const void * b)136 static int compare_bygrptag(const void *a, const void *b) {
137 register int r = strcmp(((ps_arealistitem)a)->grp,((ps_arealistitem)b)->grp);
138 return r ? r : sstricmp(((ps_arealistitem)a)->tag,((ps_arealistitem)b)->tag);
139 }
140
sortAreaList(ps_arealist al)141 HUSKYEXT void sortAreaList(ps_arealist al)
142 {
143 if (config && al && al->count && al->areas)
144 switch (config->listEcho) {
145 case lemGroupName:
146 qsort(al->areas, al->count, sizeof(s_arealistitem), compare_bygrptag);
147 break;
148 case lemGroup:
149 qsort(al->areas, al->count, sizeof(s_arealistitem), compare_bygrp);
150 break;
151 case lemUnsorted:
152 break;
153 case lemName:
154 default:
155 qsort(al->areas, al->count, sizeof(s_arealistitem), compare_bytag);
156 break;
157 }
158 }
159
compare_arealistitems_and_desc(const void * a,const void * b)160 static int compare_arealistitems_and_desc(const void *a, const void *b)
161 {
162 register int r;
163
164 /* compare areatags */
165 r = sstricmp(((ps_arealistitem)a)->tag,((ps_arealistitem)b)->tag);
166 if (r!=0)
167 return r;
168 /* comapre descriptions: if both presents it's eq; if both absence then eq also;
169 else NULL'ed is little */
170 r = (((ps_arealistitem)b)->desc != NULL) - (((ps_arealistitem)a)->desc != NULL);
171 return r;
172
173 /* Don't compare descriptions text
174 if ((r!=0)||(((ps_arealistitem)a)->desc == NULL))
175 return r;
176
177 return strcmp(((ps_arealistitem)a)->desc, ((ps_arealistitem)b)->desc);
178 */
179 }
180
sortAreaListNoDupes(unsigned int halcnt,ps_arealist * hal,int nodupes)181 HUSKYEXT void sortAreaListNoDupes(unsigned int halcnt, ps_arealist *hal, int nodupes)
182 {
183 int i,j;
184 unsigned int k;
185 char *prev;
186 ps_arealist al;
187 ps_arealistitem ali;
188
189 if (!hal)
190 return;
191
192 al = hal[halcnt-1];
193
194 if(!(al && al->count && al->areas))
195 return;
196
197 if (!nodupes)
198 {
199 sortAreaList(al);
200 return;
201 }
202
203 qsort(al->areas,al->count,sizeof(s_arealistitem),compare_arealistitems_and_desc);
204
205 j=0;
206 prev = NULL;
207
208 for(i=0; i<al->count; i++)
209 {
210 if (prev&&(sstricmp(prev, al->areas[i].tag)==0))
211 {
212 nfree(al->areas[i].tag);
213 nfree(al->areas[i].desc);
214 continue;
215 }
216 prev = al->areas[i].tag;
217
218 ali = NULL;
219 for(k=1; k<halcnt; k++)
220 {
221 ali = bsearch(&(al->areas[i]), hal[k-1]->areas, hal[k-1]->count, sizeof(s_arealistitem), compare_bytag);
222 if (ali)
223 break;
224 }
225 if (ali)
226 {
227 prev = NULL;
228 nfree(al->areas[i].tag);
229 nfree(al->areas[i].desc);
230 continue;
231 }
232
233 if (i!=j) memcpy(&(al->areas[j]), &(al->areas[i]), sizeof(s_arealistitem));
234 j++;
235 }
236
237 if (j!=(al->maxcount))
238 {
239 al->areas = realloc(al->areas, j*sizeof(s_arealistitem));
240 al->maxcount = j;
241 }
242 al->count = j;
243 }
244
245
addline(char * text,char * line,int * pos,int * tlen)246 static char *addline(char *text, char *line, int *pos, int *tlen)
247 {
248 int ll;
249
250 if(!text) return NULL;
251 if(!line) return text;
252
253 ll = strlen(line);
254
255 if(*pos+ll+1 > *tlen) {
256 *tlen += 1024;
257 if(NULL == (text = realloc(text,*tlen))) return NULL;
258 }
259 strcpy(&text[*pos],line);
260 *pos += ll;
261 return text;
262 }
263
addchars(char * text,char c,int count,int * pos,int * tlen)264 static char *addchars(char *text, char c, int count, int *pos, int *tlen)
265 {
266 int i;
267 if(!text) return NULL;
268 if(*pos+count+1 > *tlen) {
269 *tlen += count+1024;
270 if(NULL == (text = realloc(text,*tlen))) return NULL;
271 }
272 for(i = *pos; i < *pos+count; i++) text[i] = c;
273 text[i] = '\x00';
274 *pos += count;
275 return text;
276 }
277
find_grpdesc(char * grp)278 static char *find_grpdesc(char *grp) {
279 register unsigned int i;
280 char *ddef=NULL;
281 if (*grp == 0) return NULL;
282
283 if(config) for (i = 0; i < config->groupCount; i++) {
284 if ( strcmp(grp, config->group[i].name) == 0 ) return config->group[i].desc;
285 else if (*config->group[i].name == '*') ddef = config->group[i].desc;
286 }
287 if (ddef) return ddef;
288 else return "*** Other areas"/* NULL*/;
289 }
290
formatAreaList(ps_arealist al,int maxlen,char * activechars,int grps)291 HUSKYEXT char *formatAreaList(ps_arealist al, int maxlen, char *activechars, int grps)
292 {
293 char *text;
294 char *p;
295 char *cgrp = NULL, *cgrpdesc = NULL;
296 int i;
297 int clen,wlen;
298 int tlen;
299 int tpos = 0;
300
301 if(!al || !al->count || !al->areas) return NULL;
302
303 tlen = al->count * (maxlen+5);
304
305 if(NULL == (text = malloc(tlen))) return NULL;
306 text[tpos] = '\x00';
307
308 for(i = 0; i < al->count; i++) {
309 clen = 0;
310 if(tpos >= tlen) {
311 tlen += (maxlen+5) * 32;
312 if(NULL == (text = realloc(text,tlen))) return NULL;
313 }
314
315 /* val: add group description */
316 if ( grps && (!cgrp || strcmp(cgrp, al->areas[i].grp) != 0) ) {
317 char *dgrp = find_grpdesc(al->areas[i].grp);
318 if (dgrp && dgrp != cgrpdesc) {
319 if (cgrp) { text[tpos++] = '\r'; text[tpos] = 0; }
320 if ( (text = addline(text, dgrp, &tpos, &tlen)) == NULL ) return NULL;
321 text[tpos++] = '\r'; text[tpos++] = '\r'; text[tpos] = 0;
322 cgrpdesc = dgrp;
323 }
324 cgrp = al->areas[i].grp;
325 }
326
327 if(activechars) {
328 text[tpos++] = activechars[al->areas[i].active];
329 text[tpos++] = activechars[al->areas[i].rescanable];
330 if (al->areas[i].fullaccess) {
331 text[tpos++] = activechars[al->areas[i].fullaccess];
332 } else {
333 if (al->areas[i].readonly)
334 text[tpos++] = activechars[al->areas[i].readonly];
335 else
336 text[tpos++] = activechars[al->areas[i].writeonly];
337 }
338 text[tpos++] = activechars[al->areas[i].mandatory];
339 clen++;
340 }
341 text[tpos++] = ' ';
342 clen++;
343 text[tpos] = '\x00';
344
345 if(NULL == (text = addline(text,al->areas[i].tag,&tpos,&tlen))) return NULL;
346
347 /* Not add description */
348 if(!al->areas[i].desc) {
349 text[tpos++] = '\r';
350 text[tpos] = '\x00';
351 continue;
352 }
353
354 clen += strlen(al->areas[i].tag);
355 wlen = strlen(al->areas[i].desc);
356 if(clen + 5 + wlen <= maxlen) {
357 text[tpos++] = ' ';
358 text[tpos] = '\x00';
359 if(NULL == (text = addchars(text,'.',maxlen-(clen+4+wlen),&tpos,&tlen))) return NULL;
360 text[tpos++] = ' ';
361 text[tpos] = '\x00';
362 if(NULL == (text = addline(text,al->areas[i].desc,&tpos,&tlen))) return NULL;
363 } else {
364 p = strchr(al->areas[i].desc,' ');
365 if(p && (p - al->areas[i].desc) + clen + 5 <= maxlen) {
366 wlen = p - al->areas[i].desc;
367 *p = '\x00';
368
369 text[tpos++] = ' ';
370 text[tpos] = '\x00';
371 if(NULL == (text = addchars(text,'.',maxlen-(clen+4+wlen),&tpos,&tlen))) {
372 *p = ' ';
373 return NULL;
374 }
375 text[tpos++] = ' ';
376 text[tpos] = '\x00';
377 if(NULL == (text = addline(text,al->areas[i].desc,&tpos,&tlen))) {
378 *p = ' ';
379 return NULL;
380 }
381 wlen = strlen(p+1);
382 text[tpos++] = '\r';
383 text[tpos] = '\x00';
384 if(NULL == (text = addline(addchars(text,' ',maxlen-wlen,&tpos,&tlen),p+1,&tpos,&tlen))) {
385 *p = ' ';
386 return NULL;
387 }
388 *p = ' ';
389 } else {
390 text[tpos++] = '\r';
391 text[tpos] = '\x00';
392 if(NULL == (text = addline(addchars(text,' ',maxlen-wlen,&tpos,&tlen),al->areas[i].desc,&tpos,&tlen))) return NULL;
393 }
394 }
395 text[tpos++] = '\r';
396 text[tpos] = '\x00';
397 }
398 return text;
399 }
400