home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / EXPIRE.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  23KB  |  847 lines

  1. /* Expire old messages.
  2.  * Inspired by 'expire.c' by Bernie Roehl.
  3.  * Substantially rewritten for integration into KA9Q NOS,
  4.  * WG7J v1.01 and later
  5.  * by Johan. K. Reinalda, WG7J/PA3DIS, March/April 92
  6.  *
  7.  * Old bid expiry by WG7J, March 92
  8.  * Index file support for jnos 1.10x3 and later added. WG7J Summer 1993
  9.  * Error checking/logging added by N5KNX 14Jun94
  10.  * NNTPS expiry written by VK5XXX, added 28Jun94 and extended for NNTP
  11.  *  for jnos 1.10f -- n5knx
  12.  */
  13.  
  14. /* 'expire #' sets the expire interval for n hours.
  15.  * Each time the timer goes off, a new process is started,
  16.  * that expires the old messages...
  17.  *
  18.  * The control file '~/spool/expire.dat' contains lists of
  19.  * filename age
  20.  *     -or-
  21.  * !newsgroup age
  22.  *
  23.  * where 'filename' is the name of the .txt file under '~/spool/mail'
  24.  * containing the messages (but specified WITHOUT the ending '.txt').
  25.  * filename can be extended into subdirectories, and can have either
  26.  * '/', '\' or '.' to indicate subdirectories.
  27.  *
  28.  * and where 'newsgroup' is the NNTP newsgroup name whose articles are
  29.  * to be expired.  The active and history files are also updated when
  30.  * necessary.
  31.  *
  32.  * 'age' is an integer giving the maximum age of a message or newsgroup
  33.  * article, in days, after which expiry is performed.
  34.  * If no age is given, the default age is 21 days.
  35.  */
  36. #ifdef MSDOS
  37. #include <dir.h>
  38. #include <dos.h>
  39. #endif
  40. #include <alloc.h>
  41. #include <fcntl.h>
  42. #include <sys/stat.h>
  43. #include <sys/timeb.h>
  44. #include <ctype.h>
  45. #include <time.h>
  46. #include "global.h"
  47. #include "timer.h"
  48. #include "proc.h"
  49. #include "bm.h"
  50. #include "files.h"
  51. #include "smtp.h"
  52. #include "socket.h"
  53. #include "index.h"
  54. #ifdef NNTPS
  55. #include "dirutil.h"
  56. #include <limits.h>
  57. #endif
  58.  
  59. #if defined(NNTPS) || defined(NNTP)
  60. #define NN_EITHER
  61. #endif
  62.  
  63. #ifdef LINUX
  64. extern int unlink __ARGS((char *));
  65. #endif
  66.   
  67. #ifndef __BORLANDC__
  68. #ifndef UNIX
  69. time_t mktime(struct tm *);
  70.   
  71. /* If you're using BC++ 2.0 or higher, you don't need this,
  72.  * but TCC 2.0 doesn't have it... (But, TC++ v1.01 does)
  73.  */
  74. /* Simple emulation of the mktime() call (sort-of works :-) )
  75.  * doesn't do any error checking,
  76.  * no timezone adjustments or value adjustments
  77.  * Simply 'sort-a' calculates the number of seconds since 1970 - WG7J
  78.  */
  79. time_t
  80. mktime(t)
  81. struct tm *t;
  82. {
  83.     static int total[12]={0,31,59,90,120,151,181,212,243,273,304,334};
  84.     int years;
  85.     int leapyears;
  86.     int days;
  87.   
  88.     /* time count start at jan 1, 1970, 00:00 hrs */
  89.     years = t->tm_year - 70;
  90.     /* adjust for leap-years */
  91.     leapyears = (years + 2) / 4;
  92.     if (!((years+70) & 3) && (t->tm_mon < 2))
  93.         --leapyears;    /* no extra day until 3/1 or after */
  94.   
  95.     days = years*365L + leapyears + total[t->tm_mon] + (t->tm_mday-1);
  96.   
  97.     return( days*86400L + t->tm_hour*3600L + t->tm_min*60L + t->tm_sec);
  98. }
  99. #endif  /* UNIX */
  100. #endif  /* __BORLANDC__ */
  101.   
  102. /* Include the rest in #ifdef's, so we don't pull in the whole module
  103.  * when we only have AT defined and NOT EXPIRE !
  104.  * (since these are the two modules that needs the surrogate mktime()
  105.  *  if compiling with Turbo C 2.0 )
  106.  */
  107. #ifdef EXPIRY
  108.   
  109. /* Default expiry values: */
  110. #define DEFAULT_AGE 21       /* 21 days from origination date */
  111. #define MSPHOUR (1000L*60L*60L)
  112. #define DAYStoSECS (24L*60L*60L)
  113. static struct timer Expiretimer;
  114. static int Eproc;
  115.   
  116. static char OpenErr[] = "expire: err %d opening %s";
  117. static char RenErr[] = "expire: err %d renaming %s to %s";
  118. static char WriteErr[] = "expire: err %d writing %s";
  119. static char IRMsg[] = "expire: err %d reading index for msg %d of %s";
  120. static char IWMsg[] = "expire: err %d writing index for msg %d of %s";
  121. static char TRMsg[] = "expire: err %d reading msg %d of %s";
  122. static char TWMsg[] = "expire: err %d writing msg %d to %s";
  123.  
  124. static void Expireprocess __ARGS((int a,void *v1,void *v2));
  125. static void Expiretick __ARGS((void *));
  126. static void expire __ARGS((char *,int));
  127. static void Oldbidtick __ARGS((void *p));
  128. /* NNTP Expire stuff */
  129. #ifdef NN_EITHER
  130. static void update_nntp_history __ARGS((int));
  131. static int convert_num __ARGS((char **));
  132. #endif
  133. #ifdef NNTPS
  134. static void expire_nntpsrv __ARGS((char *, int));
  135. static void update_nntp_active __ARGS((void));
  136. static void update_newsrc __ARGS((int, int, char *));
  137. static char *newsgroup_to_path __ARGS((char *));
  138. #endif
  139.   
  140. int
  141. doexpire(argc,argv,p)
  142. int argc;
  143. char *argv[];
  144. void *p;
  145. {
  146.     if(argc < 2) {
  147.         tprintf("timer: %lu/%lu hrs\n",
  148.         read_timer(&Expiretimer)/MSPHOUR,
  149.         dur_timer(&Expiretimer)/MSPHOUR);
  150.         return 0;
  151.     }
  152.     if(*argv[1] == 'n') {
  153.         Expiretick(NULL);
  154.         return 0;
  155.     }
  156.     /* set the timer */
  157.     stop_timer(&Expiretimer); /* Just in case */
  158.     Expiretimer.func = (void (*)())Expiretick;/* what to call on timeout */
  159.     Expiretimer.arg = NULL;        /* dummy value */
  160.     set_timer(&Expiretimer,atol(argv[1])*MSPHOUR); /* set timer duration */
  161.     start_timer(&Expiretimer);
  162.     return 0;
  163. }
  164.   
  165. void
  166. Expiretick(p)
  167. void *p;
  168. {
  169.     start_timer(&Expiretimer);
  170.     /* Spawn off the process */
  171.     if(!Eproc)
  172.         newproc("Expiry", 1536, Expireprocess, 0, NULL, NULL, 0);
  173. }
  174.   
  175. static void
  176. Expireprocess(a,v1,v2)
  177. int a;
  178. void *v1, *v2;
  179. {
  180.     char line[80];
  181.     int age;
  182. #ifdef NN_EITHER
  183.     int expire_nntp_history = 0;
  184. #endif
  185.     char *cp;
  186.     FILE *ctl;
  187.   
  188.     Eproc = 1;
  189.     if ((ctl = fopen(Expirefile, "r")) == NULLFILE) {
  190.         Eproc = 0;
  191.         return;
  192.     }
  193.     /* read lines from the control file */
  194.     while(fgets(line, sizeof(line), ctl) != NULLCHAR) {
  195.         pwait(NULL); /* be nice */
  196.         if((*line == '#') || (*line == '\n')
  197. #ifndef NN_EITHER
  198.            || (*line == '!')
  199. #endif
  200.           ) /* comment or blank line */
  201.             continue;
  202.         rip(line);
  203.         /* terminate area name */
  204.         age = DEFAULT_AGE;
  205.         if((cp=strpbrk(line, " \t")) != NULLCHAR) {
  206.             /* there is age info */
  207.             *cp++ = '\0';
  208.             age = atoi(cp);
  209.             if (age <= 0) age = DEFAULT_AGE;
  210.         }
  211. #ifdef NN_EITHER
  212.         if (*line == '!') {  /* Expire NNTP entry if line begins with ! */
  213. #ifdef NNTPS
  214.             expire_nntpsrv(&line[1], age);
  215. #endif
  216. #ifdef NNTP
  217.             expire(&line[1], age);
  218. #endif
  219.             if (expire_nntp_history < age)
  220.                 expire_nntp_history = age;
  221.         }
  222.         else
  223. #endif
  224.         expire(line,age);
  225.     }
  226.     fclose(ctl);
  227. #ifdef NN_EITHER
  228.     if (expire_nntp_history) {
  229.         update_nntp_history(expire_nntp_history);
  230. #ifdef NNTPS
  231.         update_nntp_active();  /* and news.rc */
  232. #endif
  233.     }
  234. #endif
  235.     Eproc = 0;
  236. }
  237.   
  238. #ifdef NN_EITHER
  239. /*
  240.         expire NNTP articles
  241.         coded by brett england (future amateur) and rob vk5xxx.
  242. */
  243. static
  244. int
  245. convert_num( p )
  246. char **p;
  247. {
  248.     int i;
  249.     char *pp = *p;
  250.  
  251.     i = (*pp - '0') * 10 + *(pp+1) - '0';
  252.     (*p)+=2;
  253.     return (i);
  254. }
  255.  
  256. static
  257. void
  258. update_nntp_history(age)
  259. int age;
  260. {
  261.   FILE *old, *new;
  262.   char newfile[FILE_PATH_SIZE];
  263.   char line[LINELEN];
  264.   char *p;
  265.   struct tm tm_time;
  266.   time_t expire_time, file_time, now;
  267.   int i,history_records_expired = 0;
  268.  
  269.   for (i=10; i>0; i--) {
  270.       if(!mlock(History,NULLCHAR)) break;
  271.       pause(2000L);
  272.   }
  273.   if (!i)  return;   /* can't lock, we'll have to wait until next time */
  274.  
  275.  
  276.   expire_time = (long)age * DAYStoSECS;  /* days to seconds */
  277.   time(&now);
  278.  
  279.   sprintf(newfile,"%s.new",History);
  280.   unlink(newfile);
  281.   if((old = fopen(History,READ_TEXT)) == NULLFILE) {
  282.       log(-1,OpenErr, errno, History);
  283.       rmlock(History,NULLCHAR);
  284.       return;
  285.   }
  286.  
  287.   if((new = fopen(newfile,WRITE_TEXT)) == NULLFILE) {
  288.       fclose(old);
  289.       log(-1,OpenErr, errno, newfile);
  290.       rmlock(History,NULLCHAR);
  291.       return;
  292.   }
  293.  
  294.   /* Scan the history file, deleting old article references */
  295.   /* format: <message-id> yymmdd hhmmss ngname/Art# */
  296.   for(;;) {
  297.     pwait(NULL);
  298.     if(fgets(line, LINELEN, old) == NULL)
  299.         break;
  300.  
  301.     p = line;
  302.     while (*p != '\0' && *p != '>')
  303.        p++;
  304.     if (*p != '>')  /* Some sort of corrupt line */
  305.         continue;
  306.     p+=2;
  307.     tm_time.tm_year = convert_num(&p);
  308.     tm_time.tm_mon = convert_num(&p)-1;
  309.     tm_time.tm_mday = convert_num(&p);
  310.     p++;   /* Point to time component */
  311.     tm_time.tm_hour = convert_num(&p);
  312.     tm_time.tm_min = convert_num(&p);
  313.     tm_time.tm_sec = 0;
  314.  
  315.     file_time = mktime(&tm_time);
  316.  
  317.     if (file_time > ( now - expire_time ))
  318.       fputs(line, new);
  319.     else
  320.       history_records_expired++;
  321.   }
  322.   i=ferror(new);
  323.   fclose(new);
  324.   fclose(old);
  325.  
  326.   if(!i) {
  327.       unlink(History);
  328.       if(rename(newfile, History) == -1)
  329.           log(-1, RenErr, errno, newfile, History);
  330.   }
  331.   else log(-1, WriteErr, errno, newfile);
  332.  
  333.   rmlock(History,NULLCHAR);
  334.  
  335.   if(history_records_expired > 0)
  336.     log(-1,"Expired: %d in %s", history_records_expired, History);
  337. }
  338. #endif
  339.  
  340. #ifdef NNTPS
  341. /* Check the news.rc file if the number contained is less than min
  342.    replace the news.rc file contents with min.
  343. */
  344. static
  345. void
  346. update_newsrc( min, max, path )
  347.   int min, max;
  348.   char *path;
  349. {
  350.   FILE *newsrcfd;
  351.   char news_file[FILE_PATH_SIZE], line[LINELEN];
  352.   int no;
  353.  
  354.   sprintf(news_file,"%s/news.rc",path);
  355.   if((newsrcfd = fopen(news_file,"r+")) == NULL) {
  356.       log(-1,OpenErr, errno, news_file);
  357.       return;
  358.   }
  359.  
  360.   fgets(line, LINELEN, newsrcfd);
  361.   rewind(newsrcfd);
  362.  
  363.   no = atoi(line);
  364.   if((no < min) || (no > max))
  365.       fprintf(newsrcfd,"%d",min);
  366.   fclose(newsrcfd);
  367.  
  368. }
  369.  
  370. /* Update the active file and return the lowest news article
  371. */
  372. static
  373. void
  374. update_nntp_active() {
  375.   FILE *old, *new;
  376.   char newfile[FILE_PATH_SIZE];
  377.   char line[LINELEN];
  378.   char *p, *path, *rpath;
  379.   int min, max;
  380.   int command, file_num;
  381.   struct ffblk *file;
  382.  
  383.  
  384.   sprintf(newfile,"%s.new",Active);
  385.   unlink(newfile);
  386.   if((old = fopen(Active,READ_TEXT)) == NULLFILE) {
  387.       log(-1,OpenErr,errno,Active);
  388.       return;
  389.   }
  390.  
  391.   if((new = fopen(newfile,WRITE_TEXT)) == NULLFILE) {
  392.       fclose(old);
  393.       log(-1,OpenErr,newfile);
  394.       return;
  395.   }
  396.  
  397.   file = (struct ffblk *)mallocw(sizeof(struct ffblk));
  398.   /* rewrite the active file, with current max and min article numbers */
  399.   /* format: ngname MaxArt# MinArt# Postflag */
  400.   for(;;) {
  401.     pwait(NULL);
  402.     if(fgets(line, LINELEN, old) == NULL)
  403.        break;
  404.  
  405.     p = line;
  406.     while (*p != '\0' && ! isspace(*p))
  407.       p++;
  408.     if (*p == '\0')
  409.       continue;
  410.     *p = '\0';
  411.  
  412.     p++;
  413.     while(*p != '\0' && (isspace(*p) || isdigit(*p)))
  414.         p++;
  415.  
  416.     rpath = newsgroup_to_path( line );
  417.     path = wildcardize(rpath);
  418.  
  419.     command = 0;
  420.     min = INT_MAX;
  421.     max = INT_MIN;
  422.     for(;;) {
  423.         pwait(NULL);
  424.         if (!nextname(command, path, file))
  425.             break;
  426.         command = 1;   /* Find next */
  427.  
  428.         if (file->ff_name[0] == '.')
  429.             continue;  /* ignore . and .. */
  430.  
  431.         file_num = atoi(file->ff_name);
  432.         if (file_num > 0) {     /* should always be greater than 0 */
  433.             if (file_num < min)
  434.                 min = file_num;
  435.             if (file_num > max)
  436.                 max = file_num;
  437.         } 
  438.     }
  439.     if (min == INT_MAX && max == INT_MIN) { /* No files */
  440.         min = 1;
  441.         max = 0;
  442.     }
  443.     update_newsrc(min, max, rpath);
  444.  
  445.     fprintf(new,"%s %05d %05d %s", line, max, min, p);
  446.   }
  447.  
  448.   command=ferror(new);
  449.   fclose(new);
  450.   fclose(old);
  451.   free(file);
  452.  
  453.   if(!command) {
  454.       unlink(Active);
  455.       if(rename(newfile,Active) == -1)
  456.           log(-1,RenErr,newfile,Active);
  457.   }
  458.   else log(-1, WriteErr, errno, newfile);
  459. }
  460.  
  461. static
  462. char
  463. *newsgroup_to_path( group )
  464. char *group;
  465. {
  466.     FILE *f;
  467.     static char line[LINELEN];
  468.     char *cp;
  469.  
  470.     if((f = fopen(Pointer,"r")) == NULL)
  471.         return((char *)NULL);
  472.  
  473.     for (;;) {
  474.         pwait(NULL);
  475.         if (fgets(line,LINELEN,f) == NULL)
  476.             break;
  477.  
  478.         if (strcspn(line," ") != strlen(group))
  479.             continue;
  480.  
  481.         if (strnicmp(group,line,strlen(group)) == 0) {
  482.             cp = (strchr(line,' ')) + 1;
  483.  
  484.             rip(cp);
  485.             fclose(f);
  486.             return (cp);
  487.         }
  488.     }
  489.     fclose(f);
  490.     return (NULL);
  491. }
  492.  
  493. void
  494. expire_nntpsrv(nntp_name, age)
  495. char *nntp_name;
  496. int age;
  497. {
  498.     char *path;
  499.     int command = 0;
  500.     struct ffblk file;
  501.     struct tm tm_time;
  502.     time_t file_time, expire_time, now;
  503.     char nntp_file[FILE_PATH_SIZE];
  504.     char save_path[FILE_PATH_SIZE];
  505.     int file_num, expired = 0;
  506.  
  507.     /* Resolve nntp name into directory path */
  508.     if ((path = newsgroup_to_path( nntp_name )) == NULL)
  509.         return;
  510.  
  511.     expire_time = (long)age * DAYStoSECS;
  512.     time(&now);
  513.     strcpy(save_path, path);
  514.     path = wildcardize(path);
  515.  
  516.     for(;;) {
  517.         pwait(NULL);
  518.         if (!nextname(command, path, &file))
  519.             break;
  520.         command = 1;   /* Find next */
  521.  
  522.         if (file.ff_name[0] == '.')
  523.             continue;  /* ignore . and .. */
  524.  
  525.         file_num = atoi(file.ff_name);
  526.         if (file_num > 0) {
  527.             /* only expire a file that is numeric :-) */
  528.             tm_time.tm_sec = 0;  /* DOS doesn't store this */
  529.             tm_time.tm_min = (file.ff_ftime >> 5) & 0x3f;
  530.             tm_time.tm_hour = (file.ff_ftime >> 11) & 0x1f;
  531.             tm_time.tm_mday = file.ff_fdate & 0x1f;
  532.             tm_time.tm_mon = ((file.ff_fdate >> 5) & 0xf)-1;
  533.             tm_time.tm_year = (file.ff_fdate >> 9) + 80;
  534.  
  535.             file_time = mktime(&tm_time);
  536.  
  537.             if (( now - expire_time ) > file_time) {
  538.                  sprintf(nntp_file, "%s/%s", save_path, file.ff_name);
  539.                  unlink(nntp_file);
  540.                  expired++;
  541.             }
  542.         }
  543.     }
  544.     if(expired)
  545.         log(-1,"Expired: %d in %s",expired, nntp_name);
  546. }
  547. #endif NNTPS
  548.  
  549. void
  550. expire(filename,age)
  551. char *filename;
  552. int age;
  553. {
  554.     int idx,idxnew,expired,i,err;
  555.     FILE *txt,*new;
  556.     long start,pos,msgsize;
  557.     time_t now;
  558.     struct indexhdr hdr;
  559.     struct mailindex index;
  560.     char file[FILE_PATH_SIZE];
  561.     char newfile[FILE_PATH_SIZE];
  562.     char buf[LINELEN];
  563.  
  564. #define IRERR    -1    /* Index read error */
  565. #define IWERR    -2    /* Index write error */
  566. #define TRERR    -3    /* area text file read error */
  567. #define TWERR    -4    /* area text file write error */
  568. #define TPERR    -5    /* area text file position error */
  569.  
  570.     dirformat(filename);
  571.   
  572.     if(mlock(Mailspool,filename))
  573.         /* can't get a lock */
  574.         return;
  575.   
  576.     sprintf(file,"%s/%s.txt",Mailspool,filename);
  577.     if((txt=fopen(file,READ_BINARY)) == NULLFILE) {
  578.         rmlock(Mailspool, filename);
  579.         return;
  580.     }
  581.  
  582.     sprintf(file,"%s/%s.ind",Mailspool,filename);
  583.     if((idx=open(file,READBINARY)) == -1) {    /* Open the index file */
  584.         fclose(txt);
  585.         log(-1, OpenErr, errno, file);
  586.         rmlock(Mailspool,filename);
  587.         return;
  588.     }
  589.  
  590.     /* Create new text file */
  591.     sprintf(file,"%s/%s.new",Mailspool,filename);
  592.     if((new=fopen(file,WRITE_TEXT)) == NULLFILE) {
  593.         fclose(txt);
  594.         close(idx);
  595.         log(-1, OpenErr, errno, file);
  596.         rmlock(Mailspool, filename);
  597.         return;
  598.     }
  599.   
  600.     /* Create the new index file */
  601.     sprintf(file,"%s/%s.idn",Mailspool,filename);
  602.     if((idxnew=open(file,CREATETRUNCATEBINARY,CREATEMODE)) == -1) {
  603.         fclose(txt);
  604.         close(idx);
  605.         fclose(new);
  606.         rmlock(Mailspool,filename);
  607.         log(-1, OpenErr, errno, file);
  608.         return;
  609.     }
  610.   
  611.     memset(&index,0,sizeof(index));
  612.     time(&now);
  613.     start = pos = 0L;
  614.     expired = err = 0;
  615.   
  616.     /* Write a default header to the new index file */
  617.     default_header(&hdr);
  618.     if (write_header(idxnew,&hdr) == -1) {
  619.         log(-1, IWMsg, errno, -1, filename);
  620.         err=IWERR;
  621.     }
  622.   
  623.     /* Read the header from the index file */
  624.     if (read_header(idx,&hdr) == -1) {
  625.         log(-1, IRMsg, errno, -1, filename);
  626.         err=IRERR;
  627.     }
  628.   
  629.     /* Now read all messages, and expire old ones */
  630.     for(i = 1; i <= hdr.msgs && !err; i++) {
  631.         default_index(filename,&index);
  632.         if (read_index(idx,&index) == -1) {
  633.             log(-1,IRMsg,errno,i,filename);
  634.             err=IRERR;
  635.             break;
  636.         }
  637.         msgsize = index.size;
  638.         if(now - index.date < ((long)age*DAYStoSECS)) {
  639.             /* This one we should keep ! Copy it from txt to new */
  640.             fseek(txt,start,SEEK_SET);
  641.             pos = ftell(new);
  642.             /* Read the first line, should be 'From ' line */
  643.             if (bgets(buf,sizeof(buf),txt) == NULL) {
  644.                 log(-1, TRMsg, errno,i,filename);
  645.                 err=TRERR;
  646.                 break;
  647.             }
  648.         if (strncmp(buf,"From ",5)) {
  649.                 log(-1, "expire: format error in msg %d of %s.txt",i,filename);
  650.                 err=TPERR;
  651.                 break;
  652.             }
  653.  
  654.             /* Now copy to output until we find another 'From ' line or
  655.              * reach end of file.
  656.              */
  657.             do {
  658.                 if (fprintf(new,"%s\n",buf) == -1) {
  659.                     log(-1, TWMsg,errno,i,filename);
  660.                     err=TWERR;
  661.                     break;  /* copy of msg will have shrunk ...  */
  662.                 }
  663.                 if (bgets(buf,sizeof(buf),txt) == NULL) break;
  664.                 pwait(NULL);
  665.             } while (strncmp(buf,"From ",5));
  666.             /* write the index for the new copy of the message */
  667.             index.size = ftell(new) - pos;
  668.             if (index.size < 0 || pos < 0) {
  669.                 log(-1, "expire: ftell err %d for %s", errno, filename);
  670.                 err=TPERR;
  671.                 break;
  672.             }
  673.             if (WriteIndex(idxnew,&index) == -1) {
  674.                 log(-1,IWMsg,errno,i,filename);
  675.                 err=IWERR;
  676.                 break;
  677.             }
  678.         } else
  679.             expired++;
  680.         start += msgsize;    /* starting offset of the next message */
  681.     }
  682.     default_index("",&index);
  683.     close(idx);
  684.     close(idxnew);
  685.     pos=ftell(new);        /* how long is new area */
  686.     fclose(new);
  687.     fclose(txt);
  688.  
  689.     if (!err) {
  690.  
  691.         sprintf(file,"%s/%s.txt",Mailspool,filename);
  692.         sprintf(newfile,"%s/%s.new",Mailspool,filename);
  693.         unlink(file);
  694.         if(pos)
  695.             rename(newfile,file);
  696.         else
  697.             /* remove a zero length file */
  698.             unlink(newfile);
  699.         sprintf(file,"%s/%s.ind",Mailspool,filename);
  700.         sprintf(newfile,"%s/%s.idn",Mailspool,filename);
  701.         unlink(file);
  702.         if(pos)
  703.             rename(newfile,file);
  704.         else {
  705.             /* remove a zero length file */
  706.             unlink(newfile);
  707. #ifdef USERLOG
  708.             sprintf(file,"%s/%s.inf", Mailspool, filename);
  709.             unlink(file);
  710. #endif
  711.         }
  712.     }
  713.     rmlock(Mailspool,filename);
  714.     if(expired)
  715.         log(-1,"Expired: %d in %s",expired,filename);
  716.  
  717. }
  718.   
  719.   
  720. /******************************************************************/
  721. /* This program will deleted old BID's from the history file,
  722.  * after making a backup copy.
  723.  *
  724.  *  Eg. 'oldbids 24 30' will try to delete all bids older then 30 days
  725.  *      every 24 hours.
  726.  *      'oldbids now' will do it now, with set value of age.
  727.  *
  728.  * Copyright 1992, Johan. K. Reinalda, WG7J/PA3DIS
  729.  *      email : johan@ece.orst.edu
  730.  *      packet: wg7j@wg7j.or.usa.na
  731.  *
  732.  * Any part of this source may be freely distributed for none-commercial,
  733.  * amateur radio use only, as long as credit is given to the author.
  734.  *
  735.  * v1.0 920325
  736.  */
  737. static struct timer Oldbidtimer;
  738. static int Oldbid_age = 30;
  739.   
  740. static
  741. void
  742. Oldbidtick(p)
  743. void *p;
  744. {
  745.     int i,expired = 0;
  746.     char *cp;
  747.     FILE *old, *new;
  748.     time_t now;
  749.     time_t age;
  750.     time_t bidtime;
  751.     #define LEN 80
  752.     char newfile[LEN];
  753.     char buf[LEN];
  754.   
  755.     stop_timer(&Oldbidtimer);
  756.   
  757.     /* We will rewrite the msgid history file, renaming it when we are
  758.        done.  Since this is not protected by a lock, we won't call pwait()
  759.        so as to minimize chances we'll lose an update -- N5KNX */
  760.  
  761.     sprintf(newfile,"%s.new",Historyfile);
  762.     unlink(newfile);
  763.     if((old = fopen(Historyfile,READ_TEXT)) == NULLFILE) {
  764.         log(-1, OpenErr, errno, Historyfile);
  765.         return;
  766.     }
  767.     if((new = fopen(newfile,WRITE_TEXT)) == NULLFILE) {
  768.         fclose(old);
  769.         log(-1, OpenErr, errno, newfile);
  770.         return;
  771.     }
  772.  
  773.     now = time(&now);
  774.     age = (time_t)(Oldbid_age*DAYStoSECS);
  775.   
  776.     while(fgets(buf,LEN,old) != NULL) {
  777.         rip(buf);
  778.         if((cp=strchr(buf,' ')) != NULLCHAR) {
  779.             /*found one with timestamp*/
  780.             *cp = '\0';
  781.             cp++;   /* now points to timestamp */
  782.             if((bidtime = atol(cp)) == 0L)
  783.                 /*something wrong, re-stamp */
  784.                 fprintf(new,"%s %ld\n",buf,now);
  785.             else {
  786.                 /* Has this one expired yet ? */
  787.                 if(now - bidtime < age)
  788.                     fprintf(new,"%s %ld\n",buf,bidtime);
  789.                 else
  790.                     expired++;
  791.             }
  792.         } else {
  793.             /* This is an old one without time stamp,
  794.              * add to the new file with current time as timestamp
  795.              */
  796.             fprintf(new,"%s %ld\n",buf,now);
  797.         }
  798.     }
  799.  
  800.     i=ferror(new);
  801.     fclose(old);
  802.     fclose(new);
  803.   
  804.     if(!i) {
  805.         unlink(Historyfile);
  806.         if(rename(newfile,Historyfile) == -1)
  807.             log(-1, RenErr, errno, newfile, Historyfile);
  808.     }
  809.     else log(-1, WriteErr, errno, newfile);
  810.  
  811.     if(expired)
  812.         log(-1,"Oldbids: %d expired",expired);
  813.  
  814.     start_timer(&Oldbidtimer);
  815.     return;
  816. }
  817.   
  818. int
  819. dooldbids(argc,argv,p)
  820. int argc;
  821. char *argv[];
  822. void *p;
  823. {
  824.     if(argc < 2){
  825.         tprintf("timer: %lu/%lu hrs; age: %d days\n",
  826.         read_timer(&Oldbidtimer)/MSPHOUR,
  827.         dur_timer(&Oldbidtimer)/MSPHOUR,
  828.         Oldbid_age);
  829.         return 0;
  830.     }
  831.     if(*argv[1] == 'n') {
  832.         Oldbidtick(NULL);
  833.         return 0;
  834.     }
  835.     /* set the timer */
  836.     stop_timer(&Oldbidtimer); /* Just in case */
  837.     Oldbidtimer.func = (void (*)())Oldbidtick;/* what to call on timeout */
  838.     Oldbidtimer.arg = NULL;        /* dummy value */
  839.     set_timer(&Oldbidtimer,atol(argv[1])*MSPHOUR); /* set timer duration */
  840.     if(argc > 2)
  841.         Oldbid_age = atoi(argv[2]);
  842.     Oldbidtick(NULL); /* Do one now and start it all!*/
  843.     return 0;
  844. }
  845.   
  846. #endif /* EXPIRE */
  847.