Mercurial > noffle
comparison src/expire.c @ 255:52f467c7213b noffle
[svn] * docs/noffle.1,src/Makefile.am,src/Makefile.in,src/content.c,
src/content.h,src/database.c,src/database.h,src/expire.c,
src/expire.h,src/noffle.c: Split out expire code from database.c,
change to remove articles in place (rather than rebuild article
database) and add separate command to rebuild article database
from articles listed in overviews. This may help if the article
database gets corrupted.
author | bears |
---|---|
date | Wed, 26 Jun 2002 14:15:44 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
254:4c0f54d51591 | 255:52f467c7213b |
---|---|
1 /* | |
2 expire.c | |
3 | |
4 $Id: expire.c 387 2002-06-26 13:15:44Z bears $ | |
5 | |
6 Handle expiring articles from the article base. | |
7 */ | |
8 | |
9 #if HAVE_CONFIG_H | |
10 #include <config.h> | |
11 #endif | |
12 | |
13 #include <stdio.h> | |
14 #include <errno.h> | |
15 #include <unistd.h> | |
16 #include <sys/types.h> | |
17 #include <sys/stat.h> | |
18 #include "configfile.h" | |
19 #include "content.h" | |
20 #include "database.h" | |
21 #include "expire.h" | |
22 #include "fetchlist.h" | |
23 #include "group.h" | |
24 #include "itemlist.h" | |
25 #include "log.h" | |
26 #include "protocol.h" | |
27 #include "pseudo.h" | |
28 #include "util.h" | |
29 #include "portable.h" | |
30 | |
31 /* | |
32 * Find the maximum expire time in days for this article. | |
33 * Different groups may have different limits, so we need to | |
34 * check the limit for each group. | |
35 */ | |
36 static int | |
37 calcExpireDays( const char *msgId ) | |
38 { | |
39 const char *xref; | |
40 ItemList *refs; | |
41 const char *ref; | |
42 int res; | |
43 | |
44 xref = Db_xref( msgId ); | |
45 if ( xref[ 0 ] == '\0' ) | |
46 return -1; | |
47 | |
48 res = -1; | |
49 refs = new_Itl( xref, " :" ); | |
50 for ( ref = Itl_first( refs ); ref != NULL; ref = Itl_next( refs ) ) | |
51 { | |
52 int days; | |
53 | |
54 days = Cfg_expire( ref ); | |
55 if ( days == 0 | |
56 || ( days > res && res != 0 ) ) | |
57 res = days; | |
58 | |
59 Itl_next( refs ); /* Throw away group number */ | |
60 } | |
61 del_Itl( refs ); | |
62 | |
63 return res; | |
64 } | |
65 | |
66 /* Does this article need to be expired? */ | |
67 static Bool | |
68 articleExpired( const char *msgId, time_t now ) | |
69 { | |
70 int expDays; | |
71 time_t lastAccess; | |
72 Str expires; | |
73 time_t texpires; | |
74 | |
75 expDays = calcExpireDays( msgId ); | |
76 if ( expDays == -1 ) | |
77 { | |
78 Log_err( "Internal error: Failed expiry calculation on %s", | |
79 msgId ); | |
80 return TRUE; | |
81 } | |
82 | |
83 lastAccess = Db_lastAccess( msgId ); | |
84 if ( lastAccess == -1 ) | |
85 { | |
86 Log_err( "Internal error: Getting lastAccess of %s failed", | |
87 msgId ); | |
88 return TRUE; | |
89 } | |
90 | |
91 if ( Prt_searchHeader( Db_header( msgId ), "Expires", expires ) ) | |
92 texpires = Utl_parseNewsDate( expires ); | |
93 else | |
94 texpires = (time_t) -1; | |
95 | |
96 if ( expDays > 0 && | |
97 difftime( now, lastAccess ) > ( (double) expDays * 24 * 3600 ) ) | |
98 { | |
99 #ifdef DEBUG | |
100 Str lastStr, nowStr; | |
101 | |
102 Utl_cpyStr( lastStr, ctime( &lastAccess ) ); | |
103 lastStr[ strlen( lastStr ) - 1 ] = '\0'; | |
104 Utl_cpyStr( nowStr, ctime( &now ) ); | |
105 nowStr[ strlen( nowStr ) - 1 ] = '\0'; | |
106 Log_dbg( LOG_DBG_EXPIRE, | |
107 "Expiring %s: last access %s, time now %s", | |
108 msgId, lastStr, nowStr ); | |
109 #endif | |
110 } | |
111 else if ( ( texpires != (time_t) -1 ) && now > texpires ) | |
112 { | |
113 Log_dbg( LOG_DBG_EXPIRE, | |
114 "Expiring %s: Expires header activated", msgId ); | |
115 } | |
116 else | |
117 return FALSE; | |
118 | |
119 return TRUE; | |
120 } | |
121 | |
122 /* Work though all overviews looking for articles to expire. */ | |
123 void | |
124 Exp_expire( void ) | |
125 { | |
126 const Over *ov; | |
127 int i; | |
128 int cntDel, cntLeft; | |
129 Str grp; | |
130 Bool autoUnsubscribe; | |
131 int autoUnsubscribeDays; | |
132 time_t now, maxAge = 0; | |
133 const char *msgId; | |
134 | |
135 autoUnsubscribe = Cfg_autoUnsubscribe(); | |
136 autoUnsubscribeDays = Cfg_autoUnsubscribeDays(); | |
137 maxAge = Cfg_autoUnsubscribeDays() * 24 * 3600; | |
138 if ( ! Cont_firstGrp( grp ) ) | |
139 return; | |
140 Log_inf( "Expiring articles" ); | |
141 Fetchlist_read(); | |
142 now = time( NULL ); | |
143 do | |
144 { | |
145 if ( ! Grp_exists( grp ) ) | |
146 Log_err( "Overview file for unknown group %s exists", grp ); | |
147 else | |
148 { | |
149 cntDel = cntLeft = 0; | |
150 Cont_read( grp ); | |
151 for ( i = Cont_first(); i <= Cont_last(); ++i ) | |
152 { | |
153 if ( ! Cont_validNumb( i ) ) | |
154 continue; | |
155 | |
156 if ( ( ov = Cont_get( i ) ) ) | |
157 { | |
158 msgId = Ov_msgId( ov ); | |
159 /* Crossposted articles may have already been deleted. */ | |
160 if ( ! Db_contains( msgId ) ) | |
161 { | |
162 Cont_delete( i ); | |
163 ++cntDel; | |
164 } else if ( articleExpired( msgId, now ) ) | |
165 { | |
166 Cont_delete( i ); | |
167 Db_delete( msgId ); | |
168 ++cntDel; | |
169 } | |
170 else | |
171 ++cntLeft; | |
172 } | |
173 } | |
174 | |
175 /* | |
176 * Auto unsubscribe where applicable if last article arrival | |
177 * time is maxAge newer than the last access time. This ensures | |
178 * the low traffic groups don't get expired simply because | |
179 * there's been nothing to read. | |
180 */ | |
181 if ( ! Grp_local( grp ) | |
182 && Fetchlist_contains( grp, NULL ) | |
183 && autoUnsubscribe | |
184 && difftime( Grp_lastPostTime(grp), | |
185 Grp_lastAccess( grp ) ) > maxAge ) | |
186 { | |
187 Log_ntc( "Auto-unsubscribing from %s after %d " | |
188 "days without access", | |
189 grp, autoUnsubscribeDays ); | |
190 Pseudo_autoUnsubscribed( grp, autoUnsubscribeDays ); | |
191 Fetchlist_remove( grp ); | |
192 Grp_setRmtNext( grp, GRP_RMT_NEXT_NOT_SUBSCRIBED ); | |
193 } | |
194 if ( Cont_write() ) | |
195 Grp_setFirstLast( grp, Cont_first(), Cont_last() ); | |
196 Log_inf( "%ld overviews deleted from group %s, %ld left (%ld-%ld)", | |
197 cntDel, grp, cntLeft, Grp_first( grp ), Grp_last( grp ) ); | |
198 } | |
199 } | |
200 while ( Cont_nextGrp( grp ) ); | |
201 Fetchlist_write(); | |
202 Db_compact(); | |
203 } |