root / active.c

View | Annotate | Download

1 1.15 tommy
/*
2 1.15 tommy
 * active.c - Active file, newsgroups file and overview.fmt functions
3 1.15 tommy
 *
4 1.28 tommy
 * $Id: active.c,v 1.27 2006/08/30 15:21:03 mjo Exp $
5 1.15 tommy
 */
6 1.1 tommy
7 1.1 tommy
#include "aconfig.h"
8 1.1 tommy
#include "nntpd.h"
9 1.1 tommy
#include "memory.h"
10 1.4 tommy
#include "aprotos.h"
11 1.1 tommy
12 1.26 tommy
ACTIVE *newsgroups = NULL;
13 1.15 tommy
char *overviewfmt[MAX_OVERVIEWFMT];
14 1.15 tommy
15 1.15 tommy
16 1.28 tommy
PROTO void loadoverviewfmt(void)
17 1.28 tommy
{
18 1.28 tommy
        FILE *f;
19 1.28 tommy
        char buf[128];
20 1.28 tommy
        int i=0;
21 1.28 tommy
22 1.28 tommy
        if ( (f=fopen(cfg.OverviewFmtFile,"r")) == NULL )
23 1.28 tommy
                die("Can't open %s", cfg.OverviewFmtFile);
24 1.28 tommy
25 1.28 tommy
        while( fgets(buf,128,f) )
26 1.28 tommy
                overviewfmt[i++] = strdup(buf);
27 1.28 tommy
28 1.28 tommy
        fclose(f);
29 1.28 tommy
        info("Loaded %d overview.fmt headers", i);
30 1.28 tommy
        overviewfmt[i++] = NULL;
31 1.28 tommy
}
32 1.28 tommy
33 1.28 tommy
34 1.28 tommy
PROTO int isinoverviewfmt(const char *hdr)
35 1.28 tommy
{
36 1.28 tommy
        int i=0;
37 1.15 tommy
38 1.28 tommy
        while(overviewfmt[i] != NULL)
39 1.28 tommy
        {
40 1.28 tommy
                if ( strncasecmp(hdr, overviewfmt[i], strlen(hdr)) == 0 )
41 1.28 tommy
                        return 1;
42 1.28 tommy
                i++;
43 1.28 tommy
        }
44 1.28 tommy
        return 0;
45 1.15 tommy
}
46 1.15 tommy
47 1.15 tommy
48 1.28 tommy
PROTO int listoverviewfmt(CLIENT *client)
49 1.28 tommy
{
50 1.28 tommy
        int i=0;
51 1.15 tommy
52 1.28 tommy
        swriteclient(client, MSG_OVERVIEWFMT);
53 1.15 tommy
54 1.28 tommy
        while(overviewfmt[i] != NULL)
55 1.28 tommy
        {
56 1.28 tommy
                swriteclient(client, overviewfmt[i]);
57 1.28 tommy
                i++;
58 1.28 tommy
        }
59 1.15 tommy
60 1.28 tommy
        swriteclient(client, ".\n");
61 1.28 tommy
        return 0;
62 1.15 tommy
}
63 1.4 tommy
64 1.1 tommy
65 1.28 tommy
PROTO int reloadactive(void)
66 1.28 tommy
{
67 1.28 tommy
        struct stat _stat;
68 1.28 tommy
69 1.28 tommy
        if ( stat(cfg.ActiveFile,&_stat) == -1 )
70 1.28 tommy
                die("Can't stat active file %s", cfg.ActiveFile);
71 1.1 tommy
72 1.28 tommy
        if ( master->laststatactive < _stat.st_mtime )
73 1.28 tommy
        {
74 1.28 tommy
                clearactive();
75 1.28 tommy
                return loadactive();
76 1.28 tommy
        }
77 1.28 tommy
        return 0;
78 1.1 tommy
}
79 1.1 tommy
80 1.28 tommy
81 1.21 tommy
/*
82 1.21 tommy
 * Read the nntpswitch active file into memory.
83 1.21 tommy
 * Make sure the active file is sorted, but updategroups should take care of that
84 1.21 tommy
 */
85 1.28 tommy
PROTO int loadactive(void)
86 1.28 tommy
{
87 1.28 tommy
        FILE *actf;
88 1.28 tommy
        struct stat _stat;
89 1.28 tommy
        char group[MAX_GROUP], hi[11], lo[11], mode[2], svr[MAX_SERVER];
90 1.28 tommy
        char searchstr[100];
91 1.28 tommy
        int groups=0;
92 1.28 tommy
        unsigned int tim;
93 1.28 tommy
        int n;
94 1.28 tommy
        int linenr=0;
95 1.28 tommy
96 1.28 tommy
        if ( (newsgroups=memmap(sizeof(ACTIVE) * MAX_GROUPS)) == NULL )
97 1.28 tommy
                die("Cant mmap room for newsgroups");
98 1.1 tommy
99 1.28 tommy
        memset(newsgroups, '\0', sizeof(ACTIVE) * MAX_GROUPS);
100 1.1 tommy
101 1.28 tommy
        if ( (actf=fopen(cfg.ActiveFile,"r")) == NULL )
102 1.28 tommy
                die("Can't open active file %s", cfg.ActiveFile);
103 1.1 tommy
104 1.28 tommy
        sprintf(searchstr, "%%%ds %%10s %%10s %%1s %%%ds %%d", MAX_GROUP-1, MAX_SERVER-1);
105 1.28 tommy
        while( (n = fscanf(actf, searchstr, group, hi, lo, mode, svr, &tim)) > 0 )
106 1.28 tommy
        {
107 1.28 tommy
                linenr++;
108 1.28 tommy
                if ( n != 6 )
109 1.28 tommy
                            info("Skipping invalid active entry on line %d, read %d fields", linenr, n);
110 1.28 tommy
                else {
111 1.28 tommy
                        strncpy((newsgroups+groups)->newsgroup, group, MAX_GROUP);
112 1.28 tommy
                        strncpy((newsgroups+groups)->server, svr, MAX_SERVER);
113 1.28 tommy
                        (newsgroups+groups)->hi = atol(hi);
114 1.28 tommy
                        (newsgroups+groups)->lo = atol(lo);
115 1.28 tommy
                        (newsgroups+groups)->mode = mode[0];
116 1.28 tommy
                        (newsgroups+groups)->times = tim;
117 1.28 tommy
                        (newsgroups+groups)->id = groups;
118 1.28 tommy
119 1.28 tommy
                        if ( getserver(svr) == NULL )
120 1.28 tommy
                                die("Inconsistency detected, server %s (group %s) is in active:%d but not in servers.conf, run updategroups",
121 1.28 tommy
                                        svr, group, linenr);
122 1.28 tommy
123 1.28 tommy
                        groups++;
124 1.28 tommy
                        if ( groups >= MAX_GROUPS )
125 1.28 tommy
                                die("Too many newsgroups (%d) increase MAX_GROUPS in nntpd.h", groups);
126 1.28 tommy
                }
127 1.21 tommy
        }
128 1.1 tommy
129 1.28 tommy
        fclose(actf);
130 1.28 tommy
        master->numgroups = groups;
131 1.1 tommy
132 1.28 tommy
        stat(cfg.ActiveFile,&_stat);
133 1.28 tommy
        master->laststatactive = _stat.st_mtime;
134 1.1 tommy
135 1.28 tommy
        info("Loaded %d newsgroups", groups);
136 1.28 tommy
        return groups;
137 1.1 tommy
}
138 1.1 tommy
139 1.20 tommy
140 1.28 tommy
PROTO void clearactive(void)
141 1.28 tommy
{
142 1.1 tommy
143 1.28 tommy
        memunmap(newsgroups, sizeof(ACTIVE) * MAX_GROUPS);
144 1.1 tommy
145 1.28 tommy
        master->numgroups = 0;
146 1.28 tommy
        info("Active file freed");
147 1.1 tommy
}
148 1.1 tommy
149 1.20 tommy
150 1.28 tommy
PROTO int cmp_getgroup(const void *a, const void *b)
151 1.28 tommy
{
152 1.20 tommy
153 1.28 tommy
        const ACTIVE *s1 = (const ACTIVE *) a;
154 1.28 tommy
        const ACTIVE *s2 = (const ACTIVE *) b;
155 1.20 tommy
156 1.28 tommy
        return strcmp(s1->newsgroup, s2->newsgroup);
157 1.20 tommy
}
158 1.20 tommy
159 1.20 tommy
160 1.28 tommy
PROTO ACTIVE* getgroup(const char *groupname)
161 1.28 tommy
{
162 1.28 tommy
        ACTIVE ng;
163 1.28 tommy
164 1.28 tommy
        memset(&ng, 0, sizeof(ACTIVE));
165 1.28 tommy
        strncpy(ng.newsgroup, groupname, MAX_GROUP);
166 1.1 tommy
167 1.28 tommy
        return bsearch(&ng, newsgroups, master->numgroups, sizeof(ACTIVE), cmp_getgroup);
168 1.1 tommy
}
169 1.20 tommy
170 1.1 tommy
171 1.28 tommy
PROTO int listactive(CLIENT *client, char *pattern)
172 1.28 tommy
{
173 1.28 tommy
        int i;
174 1.28 tommy
175 1.28 tommy
        swriteclient(client, "215 Active file follows\r\n");
176 1.1 tommy
177 1.28 tommy
        for (i=0; i<master->numgroups; i++)
178 1.28 tommy
        {
179 1.28 tommy
                if ( match_expression( (unsigned char *)(newsgroups+i)->newsgroup
180 1.27 mjo
                                        , (unsigned char *)getwildmat(client->profile->ReadPat)
181 1.28 tommy
                                        , 0) )
182 1.28 tommy
183 1.28 tommy
                        if ( uwildmat_simple( (newsgroups+i)->newsgroup, pattern) )
184 1.28 tommy
185 1.27 mjo
                                if ( writeclient(client, "%s %10.10ld %10.10ld %c\r\n"
186 1.27 mjo
                                                , (newsgroups+i)->newsgroup, (newsgroups+i)->hi
187 1.28 tommy
                                                , (newsgroups+i)->lo, (newsgroups+i)->mode) )
188 1.27 mjo
                                        return -1;
189 1.28 tommy
        }
190 1.1 tommy
191 1.28 tommy
        return swriteclient(client,".\r\n");
192 1.1 tommy
}
193 1.1 tommy
194 1.10 tommy
195 1.28 tommy
PROTO int listactivetimes(CLIENT *client)
196 1.28 tommy
{
197 1.28 tommy
        int i;
198 1.28 tommy
199 1.28 tommy
        swriteclient(client,"215 Active.times follows\r\n");
200 1.10 tommy
201 1.28 tommy
        for (i=0; i<master->numgroups; i++)
202 1.28 tommy
                if ( (newsgroups+i)->times > 0 )
203 1.27 mjo
                        if ( writeclient(client, "%s %ld usenet\r\n"
204 1.27 mjo
                                                , (newsgroups+i)->newsgroup
205 1.27 mjo
                                                , (newsgroups+i)->times) )
206 1.27 mjo
                                return -1;
207 1.28 tommy
208 1.28 tommy
        return swriteclient(client,".\r\n");
209 1.10 tommy
}
210 1.10 tommy
211 1.28 tommy
212 1.28 tommy
PROTO int listnewsgroups(CLIENT *client, char *pattern)
213 1.28 tommy
{
214 1.28 tommy
        return listfile(client,
215 1.28 tommy
                        (char *)cfg.NewsgroupsFile,
216 1.28 tommy
                        "Newsgroups follows",
217 1.28 tommy
                        pattern,
218 1.28 tommy
                        215, 503);
219 1.7 tommy
}
220 1.7 tommy
221 1.28 tommy
222 1.28 tommy
PROTO int listxgtitle(CLIENT *client, char *pattern)
223 1.28 tommy
{
224 1.28 tommy
        return listfile(client,
225 1.28 tommy
                        (char *)cfg.NewsgroupsFile,
226 1.28 tommy
                        "Newsgroups follows",
227 1.28 tommy
                        pattern,
228 1.28 tommy
                        282, 481);
229 1.1 tommy
}
230 1.1 tommy
231 1.1 tommy
232 1.28 tommy
PROTO int listfile(CLIENT *client, char *filename, char *descr, char *pattern, int ok, int fail)
233 1.28 tommy
{
234 1.28 tommy
        char buffer[512];
235 1.28 tommy
        FILE *ngfile;
236 1.28 tommy
237 1.28 tommy
        if ( (ngfile=fopen(filename,"r")) == NULL )
238 1.28 tommy
        {
239 1.28 tommy
                syslog(LOG_INFO,"error opening %s %m",filename);
240 1.28 tommy
                return writeclient(client,"%d Error opening %s\r\n", fail, filename);
241 1.28 tommy
        }
242 1.1 tommy
243 1.28 tommy
        writeclient(client,"%d %s\r\n",ok, descr);
244 1.1 tommy
245 1.28 tommy
        while( fgets(buffer, 511, ngfile) )
246 1.28 tommy
                if ( uwildmat_simple( buffer, pattern) )
247 1.28 tommy
                        if ( swriteclient(client, buffer) )
248 1.28 tommy
                                return -1;
249 1.1 tommy
250 1.28 tommy
        swriteclient(client, ".\r\n");
251 1.28 tommy
        fclose(ngfile);
252 1.28 tommy
        return 0;
253 1.1 tommy
}
254 1.1 tommy
255 1.24 tommy
256 1.28 tommy
void newgroups_error(CLIENT *client, char *error)
257 1.24 tommy
{
258 1.28 tommy
        syslog(LOG_NOTICE, "Invalid date format in newgroup command, %s", error);
259 1.28 tommy
        writeclient(client, "501 Wrong command use %s\r\n", error);
260 1.1 tommy
}
261 1.1 tommy
262 1.24 tommy
263 1.28 tommy
PROTO int newgroups(CLIENT *client, char *args)
264 1.24 tommy
{
265 1.28 tommy
        struct tm tm;
266 1.28 tommy
        int i;
267 1.28 tommy
        char timebuf[40];
268 1.28 tommy
        ulong since;
269 1.28 tommy
        char datbuf[9];
270 1.28 tommy
        int y,m;
271 1.28 tommy
272 1.28 tommy
        memset(&tm, 0, sizeof(tm));
273 1.28 tommy
274 1.28 tommy
        if ( sscanf(args,"%8s %2d%2d%2d", datbuf, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) < 1 )
275 1.28 tommy
        {
276 1.28 tommy
                newgroups_error(client, "yyyymmdd hhmmss");
277 1.28 tommy
                return 1;
278 1.28 tommy
        }
279 1.1 tommy
280 1.28 tommy
        if ( strlen(datbuf) == 8 )
281 1.28 tommy
        {
282 1.28 tommy
                if ( sscanf(datbuf,"%4d%2d%2d",&y,&m,&tm.tm_mday) != 3 )
283 1.28 tommy
                {
284 1.28 tommy
                        newgroups_error(client,"yyyymmdd");
285 1.28 tommy
                        return 1;
286 1.28 tommy
                } else
287 1.28 tommy
                        tm.tm_year = y-1900;
288 1.28 tommy
        }
289 1.28 tommy
        else if ( strlen(datbuf) == 7 )
290 1.28 tommy
        {
291 1.28 tommy
                if ( sscanf(datbuf,"%3d%2d%2d",&y,&m,&tm.tm_mday) != 3 )
292 1.28 tommy
                {
293 1.28 tommy
                        newgroups_error(client,"yyymmdd");
294 1.28 tommy
                        return 1;
295 1.28 tommy
                }
296 1.28 tommy
        }
297 1.28 tommy
        else if ( strlen(datbuf) == 6 )
298 1.28 tommy
        {
299 1.28 tommy
                if ( sscanf(datbuf,"%2d%2d%2d",&y,&m,&tm.tm_mday) != 3 )
300 1.28 tommy
                {
301 1.28 tommy
                        newgroups_error(client,"yymmdd");
302 1.28 tommy
                        return 1;
303 1.28 tommy
                } else
304 1.28 tommy
                        tm.tm_year = y < 70 ? y+100 : y;
305 1.28 tommy
        }
306 1.28 tommy
        else if ( strlen(datbuf) == 5 )
307 1.28 tommy
        {
308 1.28 tommy
                if ( sscanf(datbuf,"%1d%2d%2d",&y,&m,&tm.tm_mday) != 3 )
309 1.28 tommy
                {
310 1.28 tommy
                        newgroups_error(client,"ymmdd");
311 1.28 tommy
                        return 1;
312 1.28 tommy
                } else
313 1.28 tommy
                        tm.tm_year = y + 100;
314 1.28 tommy
        }
315 1.28 tommy
        else
316 1.28 tommy
        {
317 1.28 tommy
                newgroups_error(client, "Couldn't parse date");
318 1.28 tommy
                return 1;
319 1.28 tommy
        }
320 1.1 tommy
321 1.28 tommy
        tm.tm_mon  = m - 1;
322 1.24 tommy
323 1.28 tommy
        strftime(timebuf, sizeof(timebuf), "%s",&tm);
324 1.28 tommy
        since = atoi(timebuf);
325 1.1 tommy
326 1.28 tommy
        swriteclient(client, "231 List of newgroups follow\r\n");
327 1.1 tommy
328 1.28 tommy
        for (i=0; i<master->numgroups; i++)
329 1.28 tommy
                if ( (newsgroups+i)->times >= since )
330 1.28 tommy
                        if ( writeclient(client,
331 1.28 tommy
                                        "%s %10.10ld %10.10ld %c\r\n",
332 1.28 tommy
                                        (newsgroups+i)->newsgroup,
333 1.28 tommy
                                        (newsgroups+i)->hi,
334 1.28 tommy
                                        (newsgroups+i)->lo,
335 1.28 tommy
                                        (newsgroups+i)->mode) )
336 1.28 tommy
                                return -1;
337 1.1 tommy
338 1.28 tommy
        return swriteclient(client, ".\r\n");
339 1.1 tommy
}