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