leafnode  1.12.0
About: Leafnode is a store & forward NNTP proxy for small (dialup) sites.
  Fossies Dox: leafnode-1.12.0.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

miscutil.c
Go to the documentation of this file.
1/*
2libutil -- miscellaneous stuff
3
4Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995
5Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47
622646949.
7Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>
8and Randolf Skerka <Randolf.Skerka@gmx.de>.
9Copyright of the modifications 1997.
10Modified by Kent Robotti <robotti@erols.com>. Copyright of the
11modifications 1998.
12Modified by Markus Enzenberger <enz@cip.physik.uni-muenchen.de>.
13Copyright of the modifications 1998.
14Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
15Copyright of the modifications 1998, 1999.
16Modified and copyright of the modifications 2002 by Ralf Wildenhues
17<ralf.wildenhues@gmx.de>.
18Modified by Matthias Andree <matthias.andree@gmx.de>.
19Copyright of the modifications 1999 - 2021.
20
21See file COPYING for restrictions on the use of this software.
22*/
23
24#include "leafnode.h"
25#include "validatefqdn.h"
26#include "strlcpy.h"
27#include "mastring.h"
28#include "ln_log.h"
29
30#include <fcntl.h>
31#include <sys/uio.h>
32#include <sys/param.h>
33#include <ctype.h>
34#include <errno.h>
35#include <limits.h>
36#include <stdlib.h>
37#include <netdb.h>
38#include <stdio.h>
39#include <string.h>
40#include <syslog.h>
41#include <pwd.h>
42#include <sys/stat.h>
43#include <sys/types.h>
44#include <unistd.h>
45#include "system.h"
46#include <signal.h>
47#include <stdarg.h>
48
49static void whoami(void);
50
51static void suicide(void) {
52 /* just in case */
53 fflush(stdout);
54 fflush(stderr);
55 raise(SIGKILL);
56}
57
58char fqdn[FQDNLEN + 1] = "";
59
60static const mode_t default_umask = 0002;
61
62/* xoverutil global vars */
64unsigned long xfirst, xlast;
65
66/* kludge around C89 const not being a compile-time constant */
67enum { hashsize = 1000 };
68
69static int
71 mastr *dir = mastr_new(1024);
72 mastr *mid = mastr_new(1024);
73 DIR *d;
74 int rc = 0;
75 int havedir[hashsize] = {0};
76
77 mastr_vcat(dir, spooldir, "/message.id", NULL);
78 d = opendir(mastr_str(dir));
79 if (d) {
80 struct dirent *de;
81 unsigned long u;
82 const char *t;
83 char *e;
84
85 /* read directory - should be faster than stat */
86 while(errno = 0, de = readdir(d)) {
87 t = de->d_name;
88 if (isdigit((unsigned char)*t)) {
89 u = strtoul(t, &e, 10);
90 if (e > t && u < hashsize)
91 havedir[u] = 1;
92 }
93 }
94
95 if (errno)
96 ln_log(LNLOG_SERR, LNLOG_CTOP, "error reading directory %s: %m",
97 mastr_str(dir));
98
99 closedir(d);
100
101 /* create missing */
102 for(u = 0; u < hashsize; u++) {
103 char b[4];
104
105 snprintf(b, sizeof(b), "%03lu", u);
106 mastr_clear(mid);
107 if (!havedir[u]) {
108 mastr_vcat(mid, spooldir, "/message.id/", b, NULL);
109 if (mkdir(mastr_str(mid), 02755)) {
110 ln_log(LNLOG_SERR, LNLOG_CTOP, "error creating directory %s: %m",
111 mastr_str(mid));
112 break;
113 }
114 }
115 }
116 } else {
117 ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot read %s: %m", mastr_str(dir));
118 rc = -1;
119 }
120
121 mastr_delete(mid);
122 mastr_delete(dir);
123 return rc;
124}
125
126static struct { const char* name; mode_t mode; } dirs[] = {
127 {"", 04755 },
128 {"interesting.groups", 02775 },
129 {"leaf.node", 0755 },
130 {"failed.postings", 02775 },
131 {"message.id", 0755 },
132 {"out.going", 0755 },
133 {"temp.files", 0755 },
135
136static const int dirs_count = sizeof(dirs)/sizeof(dirs[0]);
137
138/*
139 * initialize all global variables
140 */
141/*@-globstate@*/
142int
143initvars(char *progname)
144{
145#ifndef TESTMODE
146 struct passwd *pw;
147#endif
148 char s[SIZE_s+1];
149 int i;
150 char *t;
151
152 active = NULL;
153 xoverinfo = NULL;
154 xfirst = 0;
155 xlast = 0;
156
157 /* config.c stuff does not have to be initialized */
158
159 expire_base = NULL;
160 servers = NULL;
161
162 t = getenv("LN_DEBUG");
163 if (t)
164 debugmode = atoi(t);
165
166 (void)umask(default_umask);
167 if (strlen(spooldir) != strspn(spooldir, PORTFILENAMECSET "/")) {
168 /* verrecke! */
169 syslog(LOG_CRIT, "Fatal: spooldir contains illegal characters. "
170 "Recompile leafnode with a proper spooldir setting.");
171 suicide();
172 }
173
174#ifndef TESTMODE
175 pw = getpwnam(NEWS_USER);
176 if (!pw) {
177 fprintf(stderr, "no such user: %s\n", NEWS_USER);
178 return FALSE;
179 }
180#endif
181
182 /* These directories should exist anyway */
183 for (i = 0 ; i < dirs_count ; i++) {
184 xsnprintf(s, SIZE_s, "%s/%s", spooldir, dirs[i].name);
185 if ((mkdir(s, dirs[i].mode) && errno != EEXIST)
186 || chmod(s, dirs[i].mode)
187#ifndef TESTMODE
188 || chown(s, pw->pw_uid, pw->pw_gid)
189#endif
190 ) {
191 int e = errno;
192 struct stat st;
193 if (stat(s, &st)
194#ifndef TESTMODE
195 || st.st_uid != pw->pw_uid
196#endif
197 ) {
198 fprintf(stderr, "Warning: cannot create %s with proper ownership: %s\nMake sure you run this program as user root or %s.\n", s, strerror(e),
199 NEWS_USER);
200 syslog(LOG_WARNING, "Warning: cannot create %s with proper ownership: %s", s, strerror(e));
201 suicide();
202 }
203 }
204 }
205
206 whoami();
207
208#ifndef TESTMODE
209 if (progname) {
210 int e;
211
212#ifdef HAVE_SETGID
213 e = setgid(pw->pw_gid);
214#else
215 e = setregid(pw->pw_gid, pw->pw_gid);
216#endif
217
218 if (e) {
219 syslog(LOG_ERR, "%s: setting group id to %ld failed: %s",
220 progname, (long)pw->pw_gid, strerror(errno));
221 fprintf(stderr, "%s: setting group id to %ld failed: %s\n",
222 progname, (long)pw->pw_gid, strerror(errno));
223 }
224
225#ifdef HAVE_SETUID
226 e = setuid(pw->pw_uid);
227#else
228 e = setreuid(pw->pw_uid, pw->pw_uid);
229#endif
230 if (e) {
231 syslog(LOG_ERR, "%s: setting user id to %ld failed: %s. (Real uid is %ld, effective %ld)",
232 progname, (long)pw->pw_uid, strerror(errno), (long)getuid(), (long)geteuid());
233 fprintf(stderr, "%s: setting user id to %ld failed: %s. (Real uid is %ld, effective %ld)\n",
234 progname, (long)pw->pw_uid, strerror(errno), (long)getuid(), (long)geteuid());
235 }
236
237 /* extra sanity check - read back the new values */
238 if (getuid() != pw->pw_uid || getgid() != pw->pw_gid) {
239 syslog(LOG_ERR, "%s: must be run as %s or root", progname, NEWS_USER);
240 fprintf(stderr, "%s: must be run as %s or root\n", progname, NEWS_USER);
241 endpwent();
242 return FALSE;
243 }
244 }
245#endif /* not TESTMODE */
246 endpwent();
247
248 if (chdir(spooldir) || (i = open(".", O_RDONLY)) < 0) {
249 int e = errno;
250 syslog(LOG_CRIT, "Fatal: cannot change to or open spooldir: %m");
251 fprintf(stderr, "Fatal: cannot change or open spooldir: %s\n",
252 strerror(e));
253 suicide();
254 }
255 (void)close(i);
256
257 /* create missing message.id directories */
258 if (createmsgiddir())
259 return FALSE;
260
261 return TRUE;
262}
263
264/*@=globstate@*/
265
266/*
267 * check whether "groupname" is represented in interesting.groups without
268 * touching the file
269 */
270int
271isinteresting(const char *groupname)
272{
273 DIR *d;
274 struct dirent *de;
275 char s[SIZE_s+1];
276
277 xsnprintf(s, SIZE_s, "%s/interesting.groups", spooldir);
278 d = opendir(s);
279 if (!d) {
280 syslog(LOG_ERR, "Unable to open directory %s: %m", s);
281 printf("Unable to open directory %s\n", s);
282 return FALSE;
283 }
284
285 while ((de = readdir(d)) != NULL) {
286 if (strcasecmp(de->d_name, groupname) == 0) {
287 closedir(d);
288 return TRUE;
289 }
290 }
291 closedir(d);
292 return FALSE;
293}
294
295void
297/* report buffer overrun */
298{
299 syslog(LOG_CRIT, "buffer size too small, cannot continue, aborting program");
300 abort();
301 kill(getpid(), SIGKILL); /* really die! */
302}
303
304/** construct file name for message.id/NNN/ in spooldir from message ID */
305const char *
306lookup(const char *msgid /** if LOOKUP_FREE, release static resources */)
307{
308 static char *name = NULL;
309 static size_t namelen = 0;
310 unsigned int r;
311 size_t i;
312
313 if (msgid == LOOKUP_FREE) {
314 namelen = 0;
315 if (name)
316 free(name);
317 return NULL;
318 }
319
320 if (!msgid || !*msgid)
321 return NULL;
322
323 i = strlen(msgid) + strlen(spooldir) + 30;
324
325 if (!name) {
326 name = (char *)critmalloc(i, "lookup");
327 namelen = i;
328 } else if (i > namelen) {
329 free(name);
330 name = (char *)critmalloc(i, "lookup");
331 namelen = i;
332 }
333
334 strcpy(name, spooldir); /* RATS: ignore */
335 strcat(name, "/message.id/000/"); /* RATS: ignore */
336 i = strlen(name);
337 strcat(name, msgid); /* RATS: ignore */
338
339 r = 0;
340 do {
341 if (name[i] == '/')
342 name[i] = '@';
343 else if (name[i] == '>')
344 name[i + 1] = '\0';
345 r += (int)(name[i]);
346 r += ++i;
347 } while (name[i]);
348
349 i = strlen(spooldir) + 14; /* to the last digit */
350 r = (r % 999) + 1;
351 name[i--] = '0' + (char)(r % 10);
352 r /= 10;
353 name[i--] = '0' + (char)(r % 10);
354 r /= 10;
355 name[i] = '0' + (char)(r);
356 return name;
357}
358
359#define LM_SIZE 65536
360
361static int
362makedir(char *d)
363{
364 char *p;
365 char *q;
366
367 if (verbose > 3)
368 printf("makedir(%s)\n", d);
369 if (!d || *d != '/' || chdir("/"))
370 return 0;
371 q = d;
372 do {
373 *q = '/';
374 p = q;
375 q = strchr(++p, '/');
376 if (q)
377 *q = '\0';
378 if (!chdir(p))
379 continue; /* ok, I do use it sometimes :) */
380 if (errno == ENOENT)
381 if (mkdir(p, 0775)) {
382 syslog(LOG_ERR, "mkdir %s: %m", d);
383 exit(1);
384 }
385 if (chdir(p)) {
386 syslog(LOG_ERR, "chdir %s: %m", d);
387 exit(1);
388 }
389 } while (q);
390 return 1;
391}
392
393/* prefix numeric group name components with a minus */
394static int migrate(const char *name) {
395 char *p = critstrdup(name, "dogroup"), *q, *t = NULL;
396
397 /* shortcut: don't call into chdir() excessively */
398 for(q = strtok(p, "."); q; q = strtok(NULL, ".")) {
399 if (strspn(q, "0123456789") == strlen(q)) break;
400 }
401 if (!q) {
402 free(p);
403 return 0;
404 }
405
406 if (chdir(spooldir)) goto barf;
407
408 for(q = strtok(p, "."); q; q = strtok(NULL, ".")) {
409 t = critmalloc(strlen(q)+2, "dogroup");
410 t[0] = '-';
411 strcpy(t+1, q);
412 if (strspn(q, "0123456789") == strlen(q)) {
413 struct stat st;
414 if (0 == chdir(t)) {
415 free(t);
416 continue;
417 }
418 if (0 == stat(q, &st) && S_ISDIR(st.st_mode)) {
419 if (rename(q, t)) {
420 ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot rename %s to %s: %m",
421 q, t);
422 goto barf;
423 }
424 if (0 == chdir(t)) {
425 free(t);
426 continue;
427 }
428 }
429 goto barf;
430 }
431 if (chdir(q)) {
432 goto barf;
433 }
434 free(t);
435 }
436 free(p);
437 return 0;
438barf:
439 free(p);
440 free(t);
441 return -1;
442}
443
444/* chdir to the directory of the argument if it's a valid group */
445int
446chdirgroup(const char *group, int creatdir)
447{
448 char *p;
449 const char *c;
450
451 if (group && *group) {
452 int dots = 0;
453 char *nam, *q;
454 mastr *d = mastr_new(1024);
455
456 migrate(group);
457 mastr_vcat(d, spooldir, "/", group, NULL);
458 p = mastr_modifyable_str(d) + strlen(spooldir) + 1;
459 while (*p) {
460 if (*p == '.') {
461 *p = '/';
462 } else
463 *p = tolower((unsigned char)*p);
464 p++;
465 }
466 for (c = mastr_str(d);*c;c++) {
467 if (*c == '/' && c[1] && strspn(c+1, "0123456789") == strcspn(c+1, "/"))
468 dots++;
469 }
470 nam = critmalloc(mastr_len(d) + dots + 1, "chdirgroup");
471 for (c = mastr_str(d), q=nam;*c;c++) {
472 *(q++) = *c;
473 if (*c == '/' && c[1] && strspn(c+1, "0123456789") == strcspn(c+1, "/"))
474 *(q++) = '-';
475 }
476 *q = 0;
477 mastr_delete(d);
478
479 if (!chdir(nam)) {
480 free(nam);
481 return 1; /* chdir successful */
482 }
483 if (creatdir) {
484 int r = makedir(nam);
485 free(nam);
486 return r;
487 }
488 free(nam);
489 }
490 return 0;
491}
492
493#ifdef HAVE_IPV6
494/* get the fully qualified domain name of this box into fqdn */
495/* IPv6-capable version by Boris Manojlovic <boris@steki.net> */
496static void
497whoami(void)
498{
499 struct addrinfo hints, *res;
500 int debugqual = 0;
501 char *x;
502
503 if ((x = getenv("LN_DEBUG_QUALIFICATION")) != NULL
504 && *x)
505 debugqual = 1;
506 memset(&hints, 0, sizeof hints);
507 hints.ai_flags = AI_CANONNAME;
508
509 if (!gethostname(fqdn, sizeof(fqdn)) && !getaddrinfo(fqdn, NULL, &hints, &res)) {
510 if (res->ai_canonname != NULL) {
511 xstrlcpy(fqdn,res->ai_canonname, sizeof(fqdn));
512 if (debugqual) syslog(LOG_DEBUG, "canonical hostname: %s", fqdn);
513 }
514 freeaddrinfo(res);
515 }
516}
517#else
518/* get the fully qualified domain name of this box into fqdn */
519/* legacy version, uses legacy (IPv4) gethostby*() interfaces */
520static void
522{
523 struct hostent *he;
524 int debugqual = 0;
525 char *x;
526
527 if ((x = getenv("LN_DEBUG_QUALIFICATION")) != NULL
528 && *x)
529 debugqual = 1;
530
531 if (!gethostname(fqdn, sizeof(fqdn)) && (he = gethostbyname(fqdn)) != NULL) {
532 xstrlcpy(fqdn, he->h_name, sizeof(fqdn));
533 if (debugqual) syslog(LOG_DEBUG, "canonical hostname: %s", fqdn);
534 if (!is_validfqdn(fqdn)) {
535 char **alias;
536 alias = he->h_aliases;
537 while (alias && *alias) {
538 if (debugqual) {
539 syslog(LOG_DEBUG, "alias for my hostname: %s", *alias);
540 }
541 if (is_validfqdn(*alias)) {
542 xstrlcpy(fqdn, *alias, sizeof(fqdn));
543 break;
544 } else {
545 alias++;
546 }
547 }
548 }
549 endhostent();
550 }
551}
552#endif
553
554/*
555 * prepend string "newentry" to stringlist "list".
556 */
557void
558prependtolist(struct stringlist **list, /*@unique@*/ const char *newentry)
559{
560
561 struct stringlist *ptr;
562
563 ptr = (struct stringlist *)critmalloc(sizeof(struct stringlist) +
564 strlen(newentry),
565 "Allocating space in stringlist");
566 strcpy(ptr->string, newentry); /* RATS: ignore */
567 ptr->next = *list;
568 *list = ptr;
569}
570
571/*
572 * find a string in a stringlist
573 * return pointer to string if found, NULL otherwise
574 */
575char *
576findinlist(struct stringlist *haystack, char *needle)
577{
578 struct stringlist *a;
579
580 a = haystack;
581 while (a && *a->string) {
582 if (strncmp(needle, a->string, strlen(needle)) == 0)
583 return a->string;
584 a = a->next;
585 }
586 return NULL;
587}
588
589/*
590 * find a string in a stringlist
591 * return pointer to string if found, NULL otherwise
592 */
593struct stringlist **
594lfindinlist(struct stringlist **haystack, char *needle, size_t len)
595{
596 struct stringlist **a;
597
598 a = haystack;
599 while (a && *a && *(*a)->string) {
600 if (strncmp(needle, (*a)->string, len) == 0)
601 return a;
602 a = &(*a)->next;
603 }
604 return NULL;
605}
606
607void replaceinlist(struct stringlist **haystack, char *needle, size_t len)
608{
609 struct stringlist **f = lfindinlist(haystack, needle, len);
610 struct stringlist *n;
611 if (!f) prependtolist(haystack, needle);
612 else {
613 n = (*f)->next;
614 free(*f);
615 *f = (struct stringlist *)critmalloc(sizeof(struct stringlist) +
616 strlen(needle), "Allocating space in stringlist");
617 strcpy((*f)->string, needle); /* RATS: ignore */
618 (*f)->next = n;
619 }
620}
621
622/*
623 * free a list
624 */
625void
626freelist( /*@only@*/ struct stringlist *list)
627{
628 struct stringlist *a;
629
630 while (list) {
631 a = list->next;
632 free(list);
633 list = a;
634 }
635}
636
637/* next few routines implement a mapping from message-id to article
638 number, and clearing the entire space */
639
640struct msgidtree {
643 char msgid[1]; /* RATS: ignore */
644};
645
646static struct msgidtree *head; /* starts as NULL */
647
648static int
649comparemsgid(const char *id1, const char *id2)
650{
651 int c;
652
653 /* comparing only by msgid is uncool because the tree becomes
654 very unbalanced */
655 c = strcmp(strchr(id1, '@'), strchr(id2, '@'));
656 if (!c)
657 c = strcmp(id1, id2);
658 return c;
659}
660
661void
662insertmsgid( /*@unique@*/ const char *msgid)
663{
664 struct msgidtree **a;
665 int c;
666
667 if (strchr(msgid, '@') == 0)
668 return;
669
670 a = &head;
671 while (a) {
672 if (*a) {
673 c = comparemsgid((*a)->msgid, msgid);
674 if (c < 0)
675 a = &((*a)->left);
676 else if (c > 0)
677 a = &((*a)->right);
678 else {
679 return;
680 }
681 } else {
682 *a = (struct msgidtree *)
683 critmalloc(sizeof(struct msgidtree) + strlen(msgid),
684 "Building expiry database");
685 (*a)->left = NULL;
686 (*a)->right = NULL;
687 strcpy((*a)->msgid, msgid); /* RATS: ignore */
688 return;
689 }
690 }
691}
692
693/* returns 0 if not found, 1 otherwise */
694int
695findmsgid(const char *msgid)
696{
697 struct msgidtree *a;
698 int c;
699
700 /* domain part differs more than local-part, so try it first */
701
702 if (NULL == strchr(msgid, '@'))
703 return 0;
704
705 a = head;
706 while (a) {
707 c = comparemsgid(a->msgid, msgid);
708 if (c < 0)
709 a = a->left;
710 else if (c > 0)
711 a = a->right;
712 else
713 return 1;
714 }
715 return 0;
716}
717
718static void
719begone( /*@null@*//*@only@*/ struct msgidtree *m)
720{
721 if (m) {
722 begone(m->right);
723 begone(m->left);
724 free((char *)m);
725 }
726}
727
728void
730{
731 begone(head);
732 head = NULL;
733}
734
735static int
737{
738 int e = 0;
739 if (!m) return 0;
740 e |= xtraverseidtree(m->left, h);
741 e |= h(m->msgid);
742 e |= xtraverseidtree(m->right, h);
743 return e;
744}
745
746int
748 return xtraverseidtree(head, h);
749}
750
751/*@dependent@*/ const char *
753{
754 static char date[128]; /* RATS: ignore */
755 const char *months[] = { "Jan", "Feb", "Mar", "Apr",
756 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
757 };
758 const char *days[] = { "Sun", "Mon", "Tue", "Wed",
759 "Thu", "Fri", "Sat"
760 };
761 time_t now;
762 struct tm gm;
763
764 now = time(NULL);
765#ifdef HAVE_STRUCT_TM_TM_GMTOFF
766 {
767 char sign;
768 long off;
769
770 gm = *(localtime(&now));
771 /* fiddle a bit to make sure we don't get negative a%b results:
772 * make sure operands are non-negative */
773 off = gm.tm_gmtoff/60;
774 sign = off < 0 ? '-' : '+';
775 off = labs(off);
776 xsnprintf(date, sizeof(date), "%3s, %d %3s %4d %02d:%02d:%02d %c%02ld%02ld",
777 days[gm.tm_wday], gm.tm_mday, months[gm.tm_mon],
778 gm.tm_year + 1900, gm.tm_hour, gm.tm_min, gm.tm_sec,
779 sign, off / 60, off % 60);
780 }
781#else
782 gm = *(gmtime(&now));
783 xsnprintf(date, sizeof(date), "%3s, %d %3s %4d %02d:%02d:%02d -0000",
784 days[gm.tm_wday], gm.tm_mday, months[gm.tm_mon],
785 gm.tm_year + 1900, gm.tm_hour, gm.tm_min, gm.tm_sec);
786#endif
787
788 return (date);
789}
790
791int
792ngmatch(const char *pattern, const char *str)
793{
794 return !wildmat(str, pattern);
795}
796
797int
798xsnprintf(char *str, size_t n, const char *format, ...)
799{
800 int r;
801 va_list ap;
802
803 va_start(ap, format);
804 r = vsnprintf(str, n, format, ap);
805 va_end(ap);
806
807 if ((size_t) r >= n || r < 0)
808 overrun();
809 return r;
810}
811
812size_t xstrlcpy(char *dst, const char *src, size_t size)
813{
814 size_t s;
815 s = strlcpy(dst, src, size);
816 if (s >= size)
817 overrun();
818 return s;
819}
struct newsgroup * active
Definition: activutil.c:40
int verbose
Definition: applyfilter.c:31
int debugmode
Definition: configutil.c:67
struct server * servers
Definition: configutil.c:89
struct expire_entry * expire_base
Definition: configutil.c:60
char * critstrdup(const char *source, const char *message)
Definition: critmem.c:92
char * critmalloc(size_t size, const char *message)
Definition: critmem.c:61
static void barf(const char *func, size_t size, const char *message)
Definition: critmem.c:47
static time_t now
Definition: fetchnews.c:58
#define vsnprintf
Definition: leafnode.h:75
const char * spooldir
int(* tmihook)(const char *)
Definition: leafnode.h:157
#define LOOKUP_FREE
Definition: leafnode.h:104
#define SIZE_s
Definition: leafnode.h:287
#define PORTFILENAMECSET
Definition: leafnode.h:46
#define snprintf
Definition: leafnode.h:74
#define TRUE
Definition: leafnode.h:29
#define FALSE
Definition: leafnode.h:32
int wildmat(const char *, const char *)
Definition: wildmat.c:126
#define FQDNLEN
Definition: leafnode.h:288
void ln_log(int sev, int ctx, const char *format,...)
Definition: ln_log.c:103
#define LNLOG_SERR
Definition: ln_log.h:13
#define LNLOG_CTOP
Definition: ln_log.h:22
size_t mastr_len(mastr *m)
Definition: mastring.c:328
void mastr_delete(mastr *m)
Definition: mastring.c:223
mastr * mastr_new(size_t size)
Definition: mastring.c:62
int mastr_vcat(mastr *m,...)
Definition: mastring.c:147
#define len
Definition: mastring.c:31
void mastr_clear(mastr *m)
Definition: mastring.c:138
#define mastr_modifyable_str(m)
Definition: mastring.h:58
#define mastr_str(m)
Definition: mastring.h:57
static struct msgidtree * head
Definition: miscutil.c:646
@ hashsize
Definition: miscutil.c:67
struct stringlist ** lfindinlist(struct stringlist **haystack, char *needle, size_t len)
Definition: miscutil.c:594
unsigned long xlast
Definition: miscutil.c:64
static int createmsgiddir(void)
Definition: miscutil.c:70
void freelist(struct stringlist *list)
Definition: miscutil.c:626
int initvars(char *progname)
Definition: miscutil.c:143
unsigned long xfirst
Definition: miscutil.c:64
void overrun(void)
Definition: miscutil.c:296
static void begone(struct msgidtree *m)
Definition: miscutil.c:719
int findmsgid(const char *msgid)
Definition: miscutil.c:695
const char * rfctime(void)
Definition: miscutil.c:752
char fqdn[255+1]
Definition: miscutil.c:58
int traverseidtree(tmihook h)
Definition: miscutil.c:747
struct xoverinfo * xoverinfo
Definition: miscutil.c:63
static int xtraverseidtree(struct msgidtree *m, tmihook h)
Definition: miscutil.c:736
const char * lookup(const char *msgid)
Definition: miscutil.c:306
static int migrate(const char *name)
Definition: miscutil.c:394
void prependtolist(struct stringlist **list, const char *newentry)
Definition: miscutil.c:558
void replaceinlist(struct stringlist **haystack, char *needle, size_t len)
Definition: miscutil.c:607
const char * name
Definition: miscutil.c:126
void clearidtree(void)
Definition: miscutil.c:729
static struct @1 dirs[]
static void whoami(void)
Definition: miscutil.c:521
static void suicide(void)
Definition: miscutil.c:51
char * findinlist(struct stringlist *haystack, char *needle)
Definition: miscutil.c:576
int ngmatch(const char *pattern, const char *str)
Definition: miscutil.c:792
static const mode_t default_umask
Definition: miscutil.c:60
void insertmsgid(const char *msgid)
Definition: miscutil.c:662
static int makedir(char *d)
Definition: miscutil.c:362
int isinteresting(const char *groupname)
Definition: miscutil.c:271
int xsnprintf(char *str, size_t n, const char *format,...)
Definition: miscutil.c:798
mode_t mode
Definition: miscutil.c:126
static const int dirs_count
Definition: miscutil.c:136
int chdirgroup(const char *group, int creatdir)
Definition: miscutil.c:446
size_t xstrlcpy(char *dst, const char *src, size_t size)
Definition: miscutil.c:812
static int comparemsgid(const char *id1, const char *id2)
Definition: miscutil.c:649
static struct newsgroup * group
Definition: nntpd.c:73
static void list(struct newsgroup *g, const int what, const char *pattern)
Definition: nntpd.c:800
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:47
Definition: mastring.h:28
struct msgidtree * left
Definition: miscutil.c:641
char msgid[1]
Definition: miscutil.c:643
struct msgidtree * right
Definition: miscutil.c:642
struct stringlist * next
Definition: leafnode.h:166
char string[1]
Definition: leafnode.h:167
#define dirent
Definition: system.h:21
int is_validfqdn(const char *f)
Definition: validatefqdn.c:66
static int rc
Definition: xsnprintf.c:11