1 /* $Id: list.c 7731 2008-04-06 08:40:29Z iulius $
11 #include "inn/innconf.h"
12 #include "inn/messages.h"
14 typedef struct _LISTINFO {
17 void (*impl)(struct _LISTINFO *);
23 static void cmd_list_schema(LISTINFO *lp);
24 static void cmd_list_extensions(LISTINFO *lp);
26 static LISTINFO INFOactive = {
27 "active", _PATH_ACTIVE, NULL, true, "active newsgroups",
28 "Newsgroups in form \"group high low flags\""
30 static LISTINFO INFOactivetimes = {
31 "active.times", _PATH_ACTIVETIMES, NULL, false, "creation times",
32 "Group creations in form \"name time who\""
34 static LISTINFO INFOdistribs = {
35 "distributions", _PATH_NNRPDIST, NULL, false, "newsgroup distributions",
36 "Distributions in form \"area description\""
38 static LISTINFO INFOsubs = {
39 "subscriptions", _PATH_NNRPSUBS, NULL, false, "automatic group subscriptions",
40 "Subscriptions in form \"group\""
42 static LISTINFO INFOdistribpats = {
43 "distrib.pats", _PATH_DISTPATS, NULL, false, "distribution patterns",
44 "Default distributions in form \"weight:pattern:value\""
46 static LISTINFO INFOextensions = {
47 "extensions", NULL, cmd_list_extensions, false, "supported extensions",
48 "Supported NNTP extensions"
50 static LISTINFO INFOgroups = {
51 "newsgroups", _PATH_NEWSGROUPS, NULL, false, "newsgroup descriptions",
52 "Descriptions in form \"group description\""
54 static LISTINFO INFOmoderators = {
55 "moderators", _PATH_MODERATORS, NULL, false, "moderator patterns",
56 "Newsgroup moderators in form \"group-pattern:mail-address-pattern\""
58 static LISTINFO INFOschema = {
59 "overview.fmt", NULL, cmd_list_schema, true, "overview format",
60 "Order of fields in overview database"
62 static LISTINFO INFOmotd = {
63 "motd", _PATH_MOTD, NULL, false, "motd",
64 "Message of the day text"
67 static LISTINFO *info[] = {
82 ** List the overview schema
85 cmd_list_schema(LISTINFO *lp)
87 const struct cvector *standard;
90 Reply("%d %s.\r\n", NNTP_LIST_FOLLOWS_VAL, lp->Format);
91 standard = overview_fields();
92 for (i = 0; i < standard->count; ++i) {
93 Printf("%s:\r\n", standard->strings[i]);
95 for (i = 0; i < OVextra->count; ++i) {
96 Printf("%s:full\r\n", OVextra->strings[i]);
103 ** List supported extensions
106 cmd_list_extensions(LISTINFO *lp)
108 Reply("%d %s.\r\n", NNTP_SLAVEOK_VAL, lp->Format);
109 if (PERMauthorized != true)
110 Printf("AUTHINFO USER\r\n");
111 Printf("LISTGROUP\r\n");
117 ** List a single newsgroup. Called by LIST ACTIVE with a single argument.
118 ** This is quicker than parsing the whole active file, but only works with
119 ** single groups. It also doesn't work for aliased groups, since overview
120 ** doesn't know what group the group is aliased to (yet). Returns whether we
121 ** were able to answer the command.
124 CMD_list_single(char *group)
126 char *grplist[2] = { NULL, NULL };
131 if (!PERMmatch(PERMreadlist, grplist))
134 if (OVgroupstats(group, &lo, &hi, NULL, &flag) && flag != '=') {
135 Reply("%d %s.\r\n", NNTP_LIST_FOLLOWS_VAL, INFOactive.Format);
136 Printf("%s %010u %010u %c\r\n.\r\n", group, hi, lo, flag);
144 ** List active newsgroups, newsgroup descriptions, and distributions.
147 CMDlist(int ac, char *av[])
156 char *wildarg = NULL;
165 for (i = 0; i < ARRAY_SIZE(info); ++i) {
166 if (strcasecmp(p, info[i]->method) == 0) {
173 Reply("%s\r\n", NNTP_SYNTAX_USE);
176 if (lp == &INFOactive) {
179 if (CMD_list_single(wildarg))
182 } else if (lp == &INFOgroups || lp == &INFOactivetimes) {
187 if (ac > 2 && !wildarg) {
188 Reply("%s\r\n", NNTP_SYNTAX_USE);
192 if (lp->impl != NULL) {
197 path = innconf->pathetc;
198 if ((strstr(lp->File, "active") != NULL) ||
199 (strstr(lp->File, "newsgroups") != NULL))
200 path = innconf->pathdb;
201 if (strchr(lp->File, '/') != NULL)
203 path = concatpath(path, lp->File);
207 Reply("%d No list of %s available.\r\n",
208 NNTP_TEMPERR_VAL, lp->Items);
209 if (lp->Required || errno != ENOENT) {
210 syslog(L_ERROR, "%s cant fopen %s %m", ClientHost, lp->File);
215 Reply("%d %s.\r\n", NNTP_LIST_FOLLOWS_VAL, lp->Format);
216 if (!PERMspecified) {
217 /* Optmize for unlikely case of no permissions and false default. */
223 /* Set up group list terminator. */
226 /* Read lines, ignore long ones. */
227 while ((p = QIOread(qp)) != NULL) {
228 if (lp == &INFOmotd) {
232 if (p[0] == '.' && p[1] == '\0') {
233 syslog(L_ERROR, "%s single dot in %s", ClientHost, lp->File);
236 /* matching patterns against patterns is not that
237 good but it's better than nothing ... */
238 if (lp == &INFOdistribpats) {
239 if (*p == '\0' || *p == '#' || *p == ';' || *p == ' ')
242 if ((q = strchr(p, ':')) == NULL)
245 if ((save = strchr(q, ':')) == NULL)
249 if (!PERMmatch(PERMreadlist, grplist))
256 if (lp == &INFOdistribs || lp == &INFOmoderators) {
257 if (*p != '\0' && *p != '#' && *p != ';' && *p != ' ')
262 for (save = p; *save != '\0'; save++) {
263 if (*save == ' ' || *save == '\t') {
272 if (!PERMmatch(PERMreadlist, grplist))
275 if (wildarg && !uwildmat(p, wildarg))