1 /*****************************************************************************/
2 /*                                                                           */
3 /*                 (C) Copyright 1992-1997  Alberto Pasquale                 */
4 /*                 Portions (C) Copyright 1999 Per Lundberg                  */
5 /*                                                                           */
6 /*                   A L L   R I G H T S   R E S E R V E D                   */
7 /*                                                                           */
8 /*****************************************************************************/
9 /*                                                                           */
10 /* How to contact the author:  Alberto Pasquale of 2:332/504@fidonet         */
11 /*                             Viale Verdi 106                               */
12 /*                             41100 Modena                                  */
13 /*                             Italy                                         */
14 /*                                                                           */
15 /*****************************************************************************/
16 
17 #include "bbsgenlb.hpp"
18 #include "daydir.hpp"
19 #include "cfgdata.hpp"
20 #include "misc.hpp"
21 #include "parse.hpp"
22 #include "filesbbs.hpp"
23 
24 #include <string.h>
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <glob.h>
28 #include <unistd.h>
29 
30 #define DMOD 367
31 
32 static int
cmp_dd_data(const dd_data * s1,const dd_data * s2)33 cmp_dd_data (const dd_data * s1, const dd_data * s2)
34 {
35   if (s1->day < s2->day)
36     return -1;
37   else if (s1->day == s2->day)
38     return 0;
39   else
40     return +1;
41 }
42 
43 			 // for GetExtDay
44 #define dir_none   -1		// none of the search types
45 #define dir_arc    -2		//  .arc
46 
47 
48 int
day3(int day2,int fday)49 day3 (int day2, int fday)
50 {
51   int fde = (fday + 10) % DMOD;	// we cannot accept after this
52   int fde1 = fde - fde % 100;	// hundreds
53 
54   int ret = fde1 + day2;	// try this
55 
56   if (day2 > (fde % 100))
57     {
58       if (fde1 == 0)
59 	{			// 0?? -> 3??
60 	  ret += 300;
61 	  if (ret > 366)
62 	    ret -= 100;
63 	}
64       else
65 	ret -= 100;
66     }
67 
68   return ret;
69 }
70 
71 
72 static int
GetExtDay(char * & ext,int fileday=0)73 GetExtDay (char *&ext, int fileday = 0)		// returns day or error from extension
74 {
75   if (fileday == 0)
76     {				// .<ddd>
77       if (IsDigit (*ext) && IsDigit (*(ext + 1)) && IsDigit (*(ext + 2)))
78 	{
79 	  int day = atoi (ext);
80 	  if (day < DMOD)
81 	    return day;
82 	}
83     }
84   else
85     {				// .<a><dd>
86       if (!IsDigit (*ext) && IsDigit (*(ext + 1)) && IsDigit (*(ext + 2)))
87 	return day3 (atoi (ext + 1), fileday);
88       const AH_Archiver *a;
89       if ((a = Compr->ExtDefined (ext)) != NULL)
90 	{
91 	  ext = a->ext;
92 	  return dir_arc;
93 	}
94     }
95 
96   return dir_none;
97 }
98 
99 
100 void
CommInit(int Latest)101 DAYDIR::CommInit (int Latest)
102 {
103   fname = new char[PATH_MAX];
104 
105   switch (Select)
106     {
107     case NODELIST:
108       arc = FALSE;
109       break;
110     case ARCLIST:
111       arc = TRUE;
112       break;
113     case NODEDIFF:
114       arc = FALSE;
115       break;
116     case ARCDIFF:
117       arc = TRUE;
118       break;
119     }
120 
121   firstnew = 0;
122   nfound = 0;
123 
124   if (!mask)			// name not used in cfg, nfound = 0;
125     return;
126 
127   char name[PATH_MAX], *q = NULL;
128   char path[PATH_MAX];
129   char oldpath[PATH_MAX];
130 
131   getcwd (oldpath, PATH_MAX);
132 
133   q = strrchr (mask, '/');	// mask could contain dir or part of dir
134   if (q == NULL)		// point to first char of file name
135     strcpy (name, mask);
136   else
137     strcpy (name, q + 1);
138   int
139   namelen = strlen (name);	// length of filename (no path)
140 
141   strcpy (path, mask);
142   path[strlen (path) - namelen] = 0;
143 
144   chdir (path);
145 
146   // search for ff_name with letters and/or figures in the place of ?
147 
148   glob_t g;
149   int done;
150 
151   int today = dayn (time (NULL));  //tomorrow?!
152 
153   dir = new dd_data[DD_SIZE];	// alloc memory for directory data
154 
155   int day;
156   int fflen;
157   int ncount = 0;    /* Note from Gerrit (2:2411/12):
158   			This counter is neccessary because not every globbed
159 			filename may be usable. When e.g. fastlst looks for a
160 			unarced list (arc=FALSE) it globs for nodelist.??? and
161 			gets gl_pathc matches. There may be arced lists among
162 			these (nodelist.a??) that produce day=-1 and no valid
163 			entry in dir.day. So there have to be two independent
164 			counters: ncount for counting though the globbed
165 			filenames and nfound for the number of matching lists
166 			found. I hope that this patch corrects the usage of
167 			archived nodelists and nodediffs.*/
168 
169   done = glob (name, 0, NULL, &g);
170   if (!g.gl_pathc) done=1;
171 
172   while (!done)
173     {
174       fflen = strlen (g.gl_pathv[nfound]);
175 
176       if (fflen == namelen)
177 	{			// one char for every '?'
178             q = g.gl_pathv[nfound] + fflen - 3;     // point to first char of ext
179             day = GetExtDay (q, arc ? dayn (arcfiletime (g.gl_pathv[nfound])) : 0); // if dir_arc, p points to Archive->ext
180 	  switch (day)
181 	    {
182 	    case dir_none:
183 	      break;
184 	    case dir_arc:	// fixed archive extension
185 	      {
186                       long newtime = arcfiletime (g.gl_pathv[nfound]);
187                       if (newtime >= fixtime) {
188                         fixtime = newtime;
189                         fixext = q;
190                       }
191 	      }
192 	      break;
193 	    default:		// day number
194 	      if (nfound == DD_SIZE)
195 		{
196 		  vprintlog ("Error: too many files \"%s\"\n", name);
197 		  myexit (ERR_TOO_MANY_FILES);
198 		}
199 	      if (day > (today + 10) % DMOD)
200 		day -= DMOD;	// for sorting
201 	      if (arc)
202 		dir[nfound].first = q[0];	// get first char of ext
203 	      dir[nfound].day = (short) day;
204 	      nfound++;
205 	    }
206 	}
207         ncount++;
208 
209 	/* Double typecasting is neccessary because glibc2 (newer versions of
210 	   Linux) have gl_pathc defined as type size_t, while libc5 (older
211 	   versions of Linux) and FreeBSD have gl_pathc defined as type int. */
212         if ((size_t)g.gl_pathc == (size_t)ncount) done = 1;
213     }
214 
215   chdir (oldpath);
216 
217   if (nfound == 0)
218     return;
219 
220 
221   qsort (dir, nfound, sizeof (dd_data), (QSF) cmp_dd_data);
222 
223   int i;
224 
225   if (Latest >= 0)
226     {				// find first new
227       day = Latest;
228       if (day > (today + 10) % DMOD)
229 	day -= DMOD;
230       for (i = 0; (i < nfound) && (dir[i].day <= day); i++);
231       firstnew = i;
232     }
233 
234   for (i = 0; (i < nfound) && (dir[i].day < 0); i++)
235     dir[i].day += (short) DMOD;	// restore positive numbers
236 
237   if (arc)
238     latestime = arcfiletime (Name (nfound - 1));
239   else
240     latestime = DosFileTime (Name (nfound - 1));
241 }
242 
243 
DAYDIR(int Select,char * List,int nKeep)244 DAYDIR::DAYDIR (int Select, char *List, int nKeep)
245 {
246   memset (this, 0, sizeof (*this));
247   // VarList, FutDiff, OldTime not applicable
248   DAYDIR::Select = Select;
249   SrcNodeMissing = TRUE;
250 
251   mask = List;
252   keep = nKeep;
253 
254   CommInit ();
255 }
256 
257 
DAYDIR(int Select,InpncBlk * cib,int Latest,int FutDiff)258 DAYDIR::DAYDIR (int Select, InpncBlk * cib, int Latest, int FutDiff)	// Latest = -1: no NodeList avail
259 {				//          -2: fixed NodeList avail
260   memset (this, 0, sizeof (*this));	//       1-366: Var NodeList avail
261   // FutDiff != 0 is day of first not applicable nodediff
262   DAYDIR::Select = Select;
263   DAYDIR::FutDiff = FutDiff;
264   VarList = cib->l->VarNodeList;
265 
266   SrcNodeMissing = (Latest == -1);
267 
268   switch (Select)
269     {
270     case NODELIST:
271       mask = cib->l->NodeList;
272       OldTime = cib->s->NodeTime;
273       break;
274     case ARCLIST:
275       keep = cib->l->ArcListKeep;
276       mask = cib->l->ArcList;
277       OldTime = cib->s->ArcTime;
278       break;
279     case NODEDIFF:
280       mask = cib->l->NodeDiff;
281       OldTime = cib->s->NodeTime;
282       break;
283     case ARCDIFF:
284       keep = cib->l->ArcDiffKeep;
285       mask = cib->l->ArcDiff;
286       OldTime = cib->s->ArcTime;
287       break;
288     }
289 
290   CommInit (Latest);
291 }
292 
293 
~DAYDIR(void)294 DAYDIR::~DAYDIR (void)
295 {
296   delete[]dir;
297   delete[]fname;
298 }
299 
300 
301 char *
Name(int dd_idx)302 DAYDIR::Name (int dd_idx)
303 {
304   if (dd_idx == -1)
305     {				// return fixed extension !
306       if (fixext == NULL)
307 	return NULL;
308       sprintf (fname, "%.*s%s", (int)strlen (mask) - 3, mask, fixext);
309     }
310   else
311     {				// return day extension
312       if (dd_idx >= nfound)
313 	return NULL;
314       if (arc)
315 	sprintf (fname, "%.*s%c%02hd", (int)strlen (mask) - 3, mask,
316 		 dir[dd_idx].first, dir[dd_idx].day % 100);
317       else
318 	sprintf (fname, "%.*s%03hd", (int)strlen (mask) - 3, mask, dir[dd_idx].day);
319     }
320   return fname;
321 }
322 
323 
324 void
KillOld(void)325 DAYDIR::KillOld (void)
326 {
327   int
328   NotKill;			// first not killed
329 
330   switch (Select)
331     {
332     case NODELIST:
333       NotKill = nfound - 1;
334       break;
335     case ARCLIST:
336       NotKill = FirstKeep (keep);
337       break;
338     case NODEDIFF:
339       NotKill = firstnew;
340       break;
341     case ARCDIFF:
342       NotKill = FirstKeep (keep);
343       break;
344     default:
345       return;
346     }
347 
348   for (int i = 0; i < NotKill; i++)
349     if (arc)
350       KillFile (Name (i));
351     else
352       DeleteFile (Name (i));
353 }
354 
355 
356 void
KillAll(void)357 DAYDIR::KillAll (void)
358 {
359   for (int i = 0; i < nfound; i++)
360     if (arc)
361       KillFile (Name (i));
362     else
363       DeleteFile (Name (i));
364 }
365 
366 
367 int
FirstKeep(int keep)368 DAYDIR::FirstKeep (int keep)
369 {
370   int lastday = -1;
371   int i;
372   keep++;
373   for (i = nfound - 1; i > -1; i--)
374     {
375       if (lastday != dir[i].day)
376 	{
377 	  lastday = dir[i].day;
378 	  keep--;
379 	  if (keep == 0)
380 	    break;
381 	}
382     }
383   return i + 1;			// i points to last item to be killed
384 }
385 
386 
387 BOOL
NewAvail(void)388 DAYDIR::NewAvail (void)
389 {
390   if ((fixtime != 0) || !VarList)
391     {
392       time_t
393       max = __max (fixtime, latestime);
394       if (max == 0)
395 	return FALSE;
396       if (SrcNodeMissing)
397 	return TRUE;
398       return (max != OldTime);
399     }
400   else
401     {				// variable extension only
402       if (FindNewDay (TRUE) == -1)
403 	return FALSE;
404       else
405 	return TRUE;
406     }
407 }
408 
409 
410 char *
LatestName()411 DAYDIR::LatestName ()
412 {
413   if ((fixtime == 0) || (latestime > fixtime))	// no fixed extension ARChives or var is latest
414     return Name (nfound - 1);
415   else				// fixed extension ARChives only
416     return Name ();
417 }
418 
419 
420 int
LatestDay(void)421 DAYDIR::LatestDay (void)
422 {
423   if (nfound == 0)
424     return -1;
425   return dir[nfound - 1].day;
426 }
427 
428 
429 int
FindNew(BOOL first)430 DAYDIR::FindNew (BOOL first)
431 {
432   static int
433   cur;
434 
435   if (first)
436     cur = firstnew;
437 
438   if (arc)
439     while ((cur < (nfound - 1)) && (dir[cur + 1].day == dir[cur].day))
440       cur++;			// skip files of same day
441 
442   if (cur >= nfound)
443     return -1;
444 
445   if (first)
446     if ((Select == NODEDIFF) || (Select == ARCDIFF))
447       if (dir[cur].day == FutDiff)
448 	return -1;
449 
450   return cur++;
451 }
452 
453 
454 char *
FindNewName(BOOL first)455 DAYDIR::FindNewName (BOOL first)
456 {
457   int
458   idx = FindNew (first);
459 
460   if (idx == -1)
461     return NULL;
462 
463   return Name (idx);
464 }
465 
466 
467 int
FindNewDay(BOOL first)468 DAYDIR::FindNewDay (BOOL first)
469 {
470   int
471   idx = FindNew (first);
472 
473   if (idx == -1)
474     return -1;
475 
476   return dir[idx].day;
477 }
478