chiark / gitweb /
Commit 2.4.5-5 as unpacked
[inn-innduct.git] / innd / wip.c
1 /* $Id: wip.c 6124 2003-01-14 06:03:29Z rra $
2 **
3 ** Routines for keeping track of incoming articles, articles that haven't
4 ** acked from a duplex channel feed, and history caching.
5 **
6 ** WIP stands for work-in-progress
7 */
8
9 #include "config.h"
10 #include "clibrary.h"
11
12 #include "inn/innconf.h"
13 #include "innd.h"
14
15 #define WIPTABLESIZE        1024
16 #define WIP_ARTMAX          300         /* innfeed default max send time */
17
18 static WIP     *WIPtable[WIPTABLESIZE];      /* Top level of the WIP hash table */
19
20 void
21 WIPsetup(void)
22 {
23     memset(WIPtable, '\0', sizeof(WIPtable));
24 }
25
26 /* Add a new entry into the table.  It is the appilications responsiblity to
27    to call WIPinprogress or WIPbyid first. */
28 WIP *
29 WIPnew(const char *messageid, CHANNEL *cp)
30 {
31     HASH hash;
32     unsigned long bucket;
33     WIP *new;
34
35     hash = Hash(messageid, strlen(messageid));
36     memcpy(&bucket, &hash,
37            sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
38     bucket = bucket % WIPTABLESIZE;
39     
40     new = xmalloc(sizeof(WIP));
41     new->MessageID = hash;
42     new->Timestamp = Now.time;
43     new->Chan = cp;
44     /* Link the new entry into the list */
45     new->Next = WIPtable[bucket];
46     WIPtable[bucket] = new;
47     return new; 
48 }
49
50 void
51 WIPprecomfree(CHANNEL *cp)
52 {
53     WIP *cur;
54     int i;
55     if (cp == NULL)
56         return;
57
58     for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
59         cur = cp->PrecommitWIP[i];
60         if (cur != (WIP *)NULL) {
61             WIPfree(cur);
62         }
63     }
64 }
65
66 void
67 WIPfree(WIP *wp)
68 {
69     unsigned long bucket;
70     WIP *cur;
71     WIP *prev = NULL;
72     int i;
73     /* This is good error checking, but also allows us to
74           WIPfree(WIPbymessageid(id))
75        without having to check if id exists first */
76     if (wp == NULL)
77         return;
78
79     memcpy(&bucket, &wp->MessageID,
80            sizeof(bucket) < sizeof(HASH) ? sizeof(bucket) : sizeof(HASH));
81     bucket = bucket % WIPTABLESIZE;
82
83     for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
84         if (wp->Chan->PrecommitWIP[i] == wp) {
85             wp->Chan->PrecommitWIP[i] = (WIP *)NULL;
86             break;
87         }
88     }
89     for (cur = WIPtable[bucket]; (cur != NULL) && (cur != wp); prev = cur, cur = cur->Next);
90
91     if (cur == NULL)
92         return;
93
94     if (prev == NULL)
95         WIPtable[bucket] = cur->Next;
96     else
97         prev->Next = cur->Next;
98
99     /* unlink the entry and free the memory */
100     free(wp);
101 }
102
103 /* Check if the given messageid is being transfered on another channel.  If
104    Add is true then add the given message-id to the current channel */
105 bool
106 WIPinprogress(const char *msgid, CHANNEL *cp, bool Precommit)
107 {
108     WIP *wp;
109     int i;
110     
111     if ((wp = WIPbyid(msgid)) != NULL) {
112         if(wp->Chan->ArtBeg == 0)
113             i = 0;
114         else {
115             i = wp->Chan->ArtMax;
116             if(i > WIP_ARTMAX)
117                 i = WIP_ARTMAX;
118         }
119  
120         if ((Now.time - wp->Timestamp) < (i + innconf->wipcheck))
121             return true;
122         if ((Now.time - wp->Timestamp) > (i + innconf->wipexpire)) {
123             for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
124                 if (wp->Chan->PrecommitWIP[i] == wp) {
125                     wp->Chan->PrecommitWIP[i] = (WIP *)NULL;
126                     break;
127                 }
128             }
129             WIPfree(wp);
130             WIPinprogress(msgid, cp, Precommit);
131             return false;
132         }
133         if (wp->Chan == cp)
134             return true;
135         return false;
136     }
137     wp = WIPnew(msgid, cp);
138     if (Precommit) {
139         if (cp->PrecommitiCachenext == PRECOMMITCACHESIZE)
140             cp->PrecommitiCachenext = 0;
141         if (cp->PrecommitWIP[cp->PrecommitiCachenext])
142             WIPfree(cp->PrecommitWIP[cp->PrecommitiCachenext]);
143         cp->PrecommitWIP[cp->PrecommitiCachenext++] = wp;
144     } else {
145         WIPfree(WIPbyhash(cp->CurrentMessageIDHash));
146         cp->CurrentMessageIDHash = wp->MessageID;
147     }
148     return false;
149 }
150
151 WIP *
152 WIPbyid(const char *messageid)
153 {
154     HASH hash;
155     unsigned long bucket;
156     WIP *wp;
157
158     hash = Hash(messageid, strlen(messageid));
159     memcpy(&bucket, &hash,
160            sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
161     bucket = bucket % WIPTABLESIZE;
162     
163     /* Traverse the list until we find a match or find the head again */
164     for (wp = WIPtable[bucket]; wp != NULL; wp = wp->Next) 
165         if (!memcmp(&hash, &wp->MessageID, sizeof(HASH)))
166             return wp;
167
168     return NULL;
169 }
170
171 WIP *
172 WIPbyhash(const HASH hash)
173 {
174     unsigned long bucket;
175     WIP *wp;
176
177     memcpy(&bucket, &hash,
178            sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
179     bucket = bucket % WIPTABLESIZE;
180     
181     /* Traverse the list until we find a match or find the head again */
182     for (wp = WIPtable[bucket]; wp != NULL; wp = wp->Next) 
183         if (!memcmp(&hash, &wp->MessageID, sizeof(HASH)))
184             return wp;
185
186     return NULL;
187 }