comparison src/request.c @ 43:2842f50feb55 noffle

[svn] * client.c, client.h, common.h, config.c, config.h, content.c, content.h, control.c, control.h, database.c, database.h, dynamicstring.c, dynamicstring.h, fetch.c, fetch.h, fetchlist.c, fetchlist.h, group.c, group.h, itemlist.c, itemlist.h, lock.c, lock.h, log.c, log.h, noffle.c, online.c, online.h, outgoing.c, outgoing.h, over.c, over.h, post.c, post.h, protocol.c, protocol.h, pseudo.c, pseudo.h, request.c, request.h, server.c, server.h, util.c, util.h, wildmat.c, wildmat.h: Moved files to the subdirectory src/ * Makefile.am, acconfig.h, configure.in, docs/Makefile.am, src/Makefile.am, Makefile.in, aclocal.m4, config.h.in, configure, install-sh, missing, mkinstalldirs, stamp-h.in, docs/Makefile.in, src/Makefile.in: Added files. They are used by aclocal, autoheader, autoconf and automake. * src/config.c, src/config.h: Renamed to configfile.c and configfile.h, because configure will generate a config.h file itself. * src/client.c, src/content.c, src/database.c, src/fetch.c, src/fetchlist.c, src/group.c, src/lock.c, src/noffle.c, src/online.c, src/outgoing.c, src/over.c, src/pseudo.c, src/request.c, src/server.c, src/util.c: Changed '#include "config.h"' to '#include "configfile.h"'. * src/client.c, src/content.c, src/database.c, src/fetch.c, src/fetchlist.c, src/group.c, src/lock.c, src/online.c, src/outgoing.c, src/post.c, src/protocol.c, src/request.c, src/server.c: Files now #include <config.h>. Added missing <stdio.h>. This removes the warnings about snprintf() not being declared. * Makefile: Removed. This is now generated by configure.
author uh1763
date Fri, 05 May 2000 22:45:56 +0100
parents
children 32ba1198c6fa
comparison
equal deleted inserted replaced
42:2467ff423c15 43:2842f50feb55
1 /*
2 request.c
3
4 Collection of articles that are marked for download.
5
6 $Id: request.c 49 2000-05-05 21:45:56Z uh1763 $
7 */
8
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdio.h>
14 #include "request.h"
15 #include <dirent.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <assert.h>
22 #include "configfile.h"
23 #include "log.h"
24 #include "util.h"
25
26
27 /* This struct keeps record of the message IDs that are to be fetched from
28 one particular host. Several of these are chained together via the
29 "next" pointer, if we have several servers.
30 */
31
32 struct Reqserv;
33 typedef struct Reqserv Reqserv;
34
35 struct Reqserv {
36 char* serv; /* Server the messages are to be requested
37 from */
38 char** reql; /* List of message IDs of requested
39 messages. Some entries (that have been
40 deleted) may be NULL */
41 int reql_length; /* Number of string pointers in reql,
42 including NULL entries */
43 int reql_capacity; /* maximum number of string pointers reql
44 can hold */
45 Bool dirty; /* whether the request list needs to be
46 rewritten to disk */
47 Reqserv* next; /* next Reqserv in list */
48 time_t mtime; /* last modification time of request file */
49 };
50
51 /* List of servers */
52 static Reqserv* reqserv = 0;
53
54 /* sanity check */
55 static Bool is_open = FALSE;
56
57 /* for Req_first/Req_next */
58 static char** iterator = 0;
59 static char** iterator_end = 0;
60
61
62 /* local functions */
63 static Reqserv* newReqserv (const char* serv);
64 static Bool getReqserv (const char* serv, Reqserv** rsz);
65 static void fileRequest (Str file, const char *serv);
66 static char** searchMsgId (const Reqserv * rs, const char *msgId);
67 static void storeMsgId (Reqserv* rs, const char* msgId);
68 static Bool readRequestfile (const char* serv, Reqserv** rsz);
69 static time_t get_mtime (const char* serv);
70
71 /* read modification time of request file */
72 static time_t get_mtime(const char* serv)
73 {
74 Str filename;
75 struct stat stat1;
76
77 fileRequest(filename, serv);
78 stat(filename, &stat1);
79 return stat1.st_mtime;
80 }
81
82
83 /* create new Reqserv and queue it */
84 static Reqserv* newReqserv(const char* serv)
85 {
86 Reqserv* rs = (Reqserv*) malloc(sizeof(Reqserv));
87 rs->serv = strcpy(malloc(strlen(serv)+1), serv);
88 rs->reql = 0;
89 rs->reql_length = 0;
90 rs->reql_capacity = 0;
91 rs->next = reqserv;
92 rs->dirty = FALSE;
93 rs->mtime = 0;
94 reqserv = rs;
95 return rs;
96 }
97
98
99 /* get Reqserv for given server, and save it in "rsz". Load from file as
100 necessary. Return TRUE on success. Otherwise log errors and return
101 FALSE. (details in errno)
102 */
103 static Bool getReqserv(const char* serv, Reqserv** rsz)
104 {
105 Reqserv* rs;
106 for (rs = reqserv; rs; rs = rs->next)
107 if (!strcmp(serv, rs->serv)) {
108 *rsz = rs;
109 return TRUE;
110 }
111 return readRequestfile(serv, rsz);
112 }
113
114
115 /* Delete Reqserv from cache, if not up-to-date */
116 static void
117 cleanupReqserv( void )
118 {
119 Reqserv *rs, *prev, *next;
120
121 rs = reqserv;
122 prev = NULL;
123 while ( rs != NULL )
124 {
125 ASSERT( ! rs->dirty );
126 next = rs->next;
127 if ( get_mtime( rs->serv ) != rs->mtime )
128 {
129 if ( prev != NULL )
130 prev->next = next;
131 else
132 reqserv = next;
133 free( rs->serv );
134 rs->serv = NULL;
135 free( rs->reql );
136 rs->reql = NULL;
137 free( rs );
138 }
139 prev = rs;
140 rs = next;
141 }
142 }
143
144 /* Save name of file storing requests from server "serv" in "file" */
145 static void fileRequest( Str file, const char *serv)
146 {
147 snprintf( file, MAXCHAR, "%s/requested/%s", Cfg_spoolDir(), serv);
148 }
149
150
151 /* Search for msgid in Reqserv. Return pointer to list entry. Return 0 if
152 list does not contain msgid. */
153 static char** searchMsgId(const Reqserv * rs, const char *msgId )
154 {
155 char** rz;
156 ASSERT(rs != 0);
157
158 if (!rs->reql)
159 return 0;
160
161 for (rz = rs->reql; rz < rs->reql + rs->reql_length; rz++)
162 if (*rz && !strcmp(*rz, msgId))
163 return rz;
164
165 return 0;
166 }
167
168
169 Bool
170 Req_contains(const char *serv, const char *msgId)
171 {
172 Reqserv* rs;
173 ASSERT( is_open );
174 if (getReqserv(serv, &rs) == FALSE)
175 return FALSE;
176 return searchMsgId(rs, msgId) ? TRUE : FALSE;
177 }
178
179
180 static void storeMsgId(Reqserv* rs, const char* msgId)
181 {
182 char* msgid;
183
184 if (searchMsgId(rs, msgId))
185 /* already recorded */
186 return;
187
188 msgid = strcpy(malloc(strlen(msgId)+1), msgId);
189
190 if (rs->reql_length >= rs->reql_capacity) {
191 int c1 = rs->reql_capacity*2 + 10;
192 rs->reql = (char**) realloc(rs->reql, c1*sizeof(char*));
193 rs->reql_capacity = c1;
194 }
195
196 *(rs->reql + rs->reql_length++) = msgid;
197 rs->dirty = TRUE;
198 }
199
200
201 /* Add request for message "msgIg" from server "serv". Return TRUE iff
202 successful.
203 */
204 Bool Req_add(const char *serv, const char *msgId)
205 {
206 Reqserv* rs;
207 ASSERT( is_open );
208 Log_dbg( "Marking %s on %s for download", msgId, serv );
209
210 if (getReqserv(serv, &rs) == FALSE)
211 return FALSE;
212 storeMsgId(rs, msgId);
213 return TRUE;
214 }
215
216 static Bool
217 readLn( Str line, FILE* f )
218 {
219 size_t len;
220
221 if ( ! fgets( line, MAXCHAR, f ) )
222 return FALSE;
223 len = strlen( line );
224 if ( line[ len - 1 ] == '\n' )
225 line[ len - 1 ] = '\0';
226 return TRUE;
227 }
228
229 /* Read request file into new, non-queued Reqserv. Save new Reqserv in
230 "rsz" and return TRUE on success. Returns FALSE on failure, see errno.
231 If the file doesn't exist, an empty Reqserv is returned.
232 */
233 static Bool readRequestfile(const char* serv, Reqserv** rsz)
234 {
235 Str filename;
236 Str line;
237 FILE* file;
238 Reqserv* rs;
239
240 fileRequest(filename, serv);
241 Log_dbg("reading request file %s", filename);
242
243 file = fopen(filename, "r");
244 if (!file && (errno == ENOENT)) {
245 *rsz = newReqserv(serv);
246 (*rsz)->mtime = get_mtime(serv);
247 return TRUE;
248 }
249 if (Log_check(file != 0,
250 "could not open %s for reading: %s",
251 filename, strerror(errno)))
252 return FALSE;
253
254 rs = *rsz = newReqserv(serv);
255
256 while( readLn(line, file) == TRUE) {
257 char* line1 = Utl_stripWhiteSpace(line);
258 if (*line1)
259 storeMsgId(rs, line1);
260 }
261
262 rs->dirty = FALSE;
263
264 if (Log_check(fclose(file) != EOF,
265 "could not close %s properly: %s\n",
266 filename, strerror(errno)))
267 return FALSE;
268
269 return TRUE;
270 }
271
272
273 /* Write out request file for given Reqserv. Return TRUE on success. If an
274 I/O error occurs, it is logged, and FALSE is returned.
275 */
276 static Bool writeRequestfile(Reqserv* rs)
277 {
278 Str filename;
279 FILE* file;
280 char** z;
281
282 fileRequest(filename, rs->serv);
283 Log_dbg("writing request file %s", filename);
284
285 if (Log_check((file = fopen(filename, "w")) != 0,
286 "could not open %s for writing: %s",
287 filename, strerror(errno)))
288 return FALSE;
289
290 if (rs->reql)
291 for (z = rs->reql; z < rs->reql+rs->reql_length; z++)
292 if (*z) {
293 if (Log_check( fputs(*z, file) != EOF
294 && fputs("\n", file) != EOF,
295 "write error: %s", strerror(errno)))
296 return FALSE;
297 }
298
299 if (Log_check(fclose(file) != EOF,
300 "could not close %s properly: %s\n",
301 filename, strerror(errno)))
302 return FALSE;
303
304 rs->dirty = FALSE;
305 rs->mtime = get_mtime(rs->serv);
306
307 return TRUE;
308 }
309
310
311 void
312 Req_remove( const char *serv, const char *msgId )
313 {
314 Reqserv* rs;
315 char** z;
316
317 ASSERT( is_open );
318 Log_dbg("Req_remove(\"%s\", \"%s\")", serv, msgId);
319
320 if (getReqserv(serv, &rs) == FALSE)
321 return;
322
323 z = searchMsgId(rs, msgId);
324 if ( ! z )
325 return;
326
327 free(*z);
328 *z = 0;
329 rs->dirty = TRUE;
330 }
331
332
333 Bool
334 Req_first( const char *serv, Str msgId )
335 {
336 Reqserv* rs;
337
338 ASSERT( is_open );
339 ASSERT( !iterator && !iterator_end );
340
341 if (getReqserv(serv, &rs) == FALSE)
342 return FALSE;
343
344 if (!rs->reql)
345 return FALSE;
346
347 iterator = rs->reql - 1;
348 iterator_end = rs->reql + rs->reql_length;
349
350 return Req_next(msgId);
351 }
352
353
354 Bool
355 Req_next( Str msgId )
356 {
357 ASSERT( is_open );
358 ASSERT(iterator && iterator_end);
359
360 if (iterator >= iterator_end)
361 return FALSE;
362 iterator++;
363
364 while (iterator < iterator_end) {
365 if (!*iterator)
366 iterator++;
367 else {
368 Utl_cpyStr(msgId, *iterator);
369 return TRUE;
370 }
371 }
372
373 iterator = iterator_end = 0;
374 return FALSE;
375 }
376
377
378 /* Get exclusive access to all request files. Maybe we already have had it,
379 and the cache is outdated. So we delete request files, which have
380 changed recently, from cache. These files will be reread on demand.
381 */
382 Bool
383 Req_open(void)
384 {
385 Log_dbg("opening request database");
386 ASSERT(is_open == FALSE);
387 cleanupReqserv();
388 is_open = TRUE;
389 return TRUE;
390 }
391
392
393 /* Do not occupy the request files any longer. Write any changes to disk.
394 Return TRUE on success, FALSE if an IO error occurs. */
395 void Req_close(void)
396 {
397 Bool ret = TRUE;
398 Reqserv* rs;
399 Log_dbg("closing request database, writing changes to disk");
400 ASSERT(is_open == TRUE);
401
402 for (rs = reqserv; rs; rs = rs->next) {
403 if (rs->dirty == TRUE) {
404 if (!writeRequestfile(rs))
405 ret = FALSE;
406 }
407 }
408
409 is_open = FALSE;
410 }