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