/*
* Copyright (c) 1998,1999,2000 Kazushi (Jam) Marukawa
* All rights of my changes are reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice in the documentation and/or other materials provided with
* the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* $Orig-Id: nntpd.c,v 1.27 1997/07/21 14:08:40 agulbra Exp $ */
/* Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995
Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47
22646949.
Use, modification and distribution is allowed without limitation,
warranty, or liability of any kind. */
#ifdef SOCKS
#include <socks.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include "leafnode.h"
int write2(int fd, const char* msg);
int hash(const char*);
FILE* fopenart(const char*);
FILE* fopenpseudoart(const char* arg, const int article_num);
void list(struct newsgroup*, int);
void rereadactive(void);
void parser(void);
void error(const char*msg);
void doarticle(const char*, int);
void dostat(const char*);
void dogroup(const char*);
void dohelp(void);
void domove(int);
void domove(int);
void dolist(const char*);
void donewgroups(const char*);
void donewnews(const char*);
void dopost(void);
void doxhdr(char*);
void doxover(const char*);
void dolistgroup(const char*);
void markinterest(void);
struct newsgroup* group; /* current group, initially none */
struct newsgroup* xovergroup;
unsigned long artno = 0; /* current article number, initially 0 and almost unused */
char* cmd; /* current command line */
struct newsgroup* active;
time_t activetime;
static int justaftergroup;
void rereadactive(void)
{
const char* s;
struct stat st;
s = getinfofname();
if ((stat(s, &st) == 0 && st.st_mtime > activetime) ||
active == NULL) {
mysyslog(LOG_DEBUG, "rereading %s", s);
readactive();
activetime = st.st_mtime;
}
}
void error(const char* msg)
{
printf("%s: %s\r\n", msg, strerror(errno));
}
void parser(void)
{
char* arg;
int n;
while(1) {
if (!(cmd = getaline(stdin))) {
error("421 Network error");
return;
}
n = 0;
while (isalpha(cmd[n]) && n < 1000) {
cmd[n] = tolower(cmd[n]);
n++;
}
if (n == 0)
continue; /* outside the spec, but let's do it anyway */
if (n > 999) {
printf("400 Dazed and confused\r\n");
return;
}
while (isspace(cmd[n]) && n < 1000)
cmd[n++] = '\0';
arg = cmd + n;
mysyslog(LOG_DEBUG, "%s %s", cmd, arg);
while (cmd[n] && n < 1000)
n++;
n--;
while (isspace(cmd[n]))
cmd[n--] = '\0';
if (!strcasecmp(cmd, "article")) {
doarticle(arg, 3);
} else if (!strcasecmp(cmd, "head")) {
doarticle(arg, 2);
} else if (!strcasecmp(cmd, "body")) {
doarticle(arg, 1);
} else if (!strcasecmp(cmd, "stat")) {
doarticle(arg, 0);
} else if (!strcasecmp(cmd, "help")) {
dohelp();
} else if (!strcasecmp(cmd, "ihave")) {
printf("500 IHAVE is for big news servers\r\n");
} else if (!strcasecmp(cmd, "last")) {
domove(-1);
} else if (!strcasecmp(cmd, "next")) {
domove(1);
} else if (!strcasecmp(cmd, "list")) {
dolist(arg);
} else if (!strcasecmp(cmd, "mode")) {
printf("200 Modal interfaces are for losers\r\n");
} else if (!strcasecmp(cmd, "newgroups")) {
donewgroups(arg);
} else if (!strcasecmp(cmd, "newnews")) {
donewnews(arg);
} else if (!strcasecmp(cmd, "post")) {
dopost();
} else if (!strcasecmp(cmd, "quit")) {
printf("205 Always happy to serve!\r\n");
return;
} else if (!strcasecmp(cmd, "slave")) {
printf("202 Cool - I always wanted a slave\r\n");
} else if (!strcasecmp(cmd, "xhdr")) {
doxhdr(arg);
} else if (!strcasecmp(cmd, "xover")) {
doxover(arg);
} else if (!strcasecmp(cmd, "listgroup")) {
dolistgroup(arg);
} else if (!strcasecmp(cmd, "group")) {
dogroup(arg);
} else
printf("500 Unknown command\r\n");
fflush(stdout);
}
}
/* open a pseudo art */
FILE* fopenpseudoart(const char* arg, const int article_num)
{
FILE* f = NULL;
char msgidbuf[128];
char* c;
struct newsgroup* g;
if (article_num > 0 && article_num < group->first) {
f = buildpseudoart(group->name);
} else if (!article_num) {
if (!strncmp(arg, "<leafnode:placeholder:", 22)) {
strncpy(msgidbuf, arg + 22, 128);
msgidbuf[127] = '\0';
if ((c = strchr(msgidbuf, '@')) != NULL) {
*c = '\0';
g = findgroup(msgidbuf);
if (g) {
f = buildpseudoart(g->name);
}
}
}
}
return f;
}
/* open an article by number or message-id */
FILE* fopenart(const char* arg)
{
unsigned long int a;
FILE* f;
char* t;
t = NULL;
a = strtoul(arg, &t, 10);
if (a && t && !*t && group) {
f = fopen(arg, "r");
if (f)
artno = a;
else
f = fopenpseudoart(arg, a);
markinterest();
/* else try message-id lookup */
} else if (arg && *arg=='<') {
f = fopen(getmsgidfname(arg), "r");
if (!f)
f = fopenpseudoart(arg, a);
} else if (group && artno) {
char s[256];
sprintf(s, "%lu", artno);
f = fopen(s, "r");
if (!f)
f = fopenpseudoart(s, a);
markinterest();
} else {
f = NULL;
}
return f;
}
/* display an article or somesuch */
void doarticle(const char* arg, int what)
{
FILE* f;
char* p;
unsigned long yuck;
char s[1024];
if (!group) {
printf("412 No newsgroup selected\r\n");
return;
}
f = fopenart(arg);
if (!f) {
if (strlen(arg))
printf("430 No such article: %s\r\n", arg);
else
printf("430 No such article: %lu\r\n", artno);
return;
}
yuck = strtoul(arg, &p, 10);
if (!p || *p) {
/* parse an article to get artno. */
char* xref = getaheader(f, "Xref");
if (xref && (xref = strstr(xref, group->name)) != NULL) {
xref += strlen(group->name) + 1;
yuck = strtoul(xref, &p, 10);
if (!p || *p)
yuck = 0;
} else {
yuck = 0;
}
}
printf("%3d %lu %s Text follows, then a line consisting of a single '.'\r\n",
223 - what, yuck, getaheader(f, "Message-ID"));
while (fgets(s, 1024, f) && *s && *s != '\n') {
if (what & 2) {
p = s;
if ((p = strchr(p, '\n')))
*p = '\0';
printf("%s%s\r\n", *s=='.' ? "." : "", s); /* . on headers :( */
}
}
if (what==3)
printf("\r\n"); /* empty separator line */
while ((what & 1) && fgets(s, 1024, f) && *s) {
p = s;
if ((p = strchr(p, '\n')))
*p = '\0';
printf("%s%s\r\n", *s=='.' ? "." : "", s);
}
if (what)
printf(".\r\n");
fclose(f);
return; /* OF COURSE there were no errors */
}
/* note bug.. need not be _immediately after_ GROUP */
void markinterest(void)
{
int f;
const char* s = getinterestingngfname(group);
if (!justaftergroup)
return;
if ((f = open(s, O_RDONLY, 0)) >= 0) {
/* if there is file, changed access time by reading it */
char a;
(void)read(f, &a, 1);
close(f);
} else {
/* Otherwise, create it */
if ((f = open(s, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0) {
(void)write(f, "*", 1);
close(f);
}
}
justaftergroup = FALSE;
}
/* change to group - note no checks on group name */
void dogroup(const char* arg)
{
struct newsgroup* g;
rereadactive();
g = findgroup(arg);
if (g) {
group = g;
chdirgroup(g, 1);
if (g->last < g->first)
printf("211 %lu %lu %lu %s group selected (pseudo article)\r\n",
1LU, g->last, g->last, g->name);
else
printf("211 %lu %lu %lu %s group selected\r\n",
g->last >= g->first ? g->last-g->first+1 : 0,
g->first, g->last, g->name);
artno = g->first;
fflush(stdout);
justaftergroup = TRUE;
#if DOTNGFILE
{
int f;
const char* s = getinterestingngdotfname(group);
if ((f = open(s, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
close(f);
}
#endif
} else {
printf("411 No such group\r\n");
}
}
void dohelp(void)
{
printf("500 Read RFC 977 and 1036 for elucidation\r\n");
}
void domove(int by)
{
if (group) {
if (artno) {
unsigned long art = artno;
FILE* f = NULL;
char buffer[256];
while (f == NULL) {
art += by;
sprintf(buffer, "%lu", art);
f = fopenart(buffer);
/* hit boundaries */
if (art > group->last) {
printf("421 There is no next article\r\n");
return;
}
if (art < group->first) {
printf("422 There is no previous article\r\n");
return;
}
}
printf("223 %lu %s Article number is now %lu\r\n",
artno, getaheader(f, "Message-ID"), artno);
fclose(f);
} else {
printf("420 There is no current article\r\n");
}
} else {
printf("412 No newsgroup selected\r\n");
}
}
/* LIST ACTIVE if what==0, else LIST NEWSGROUPS */
void list(struct newsgroup* g, int what)
{
if (g) {
list(g->right, what);
if (what) {
printf("%s\t%s\r\n", g->name, g->desc ? g->desc : "");
} else {
/* If the group is empty, but has server arts, fudge a
dummy article in... */
if (g->last < g->first)
printf("%s %010lu %010lu y\r\n", g->name, g->last, g->last);
else
printf("%s %010lu %010lu y\r\n", g->name, g->last, g->first);
}
list (g->left, what);
}
}
void dolist(const char* arg)
{
rereadactive();
initconfig();
if (chdir(spooldir)) {
printf("503 News spool directory does not exist!\r\n");
} else if (!active) {
printf("503 Group information file does not exist!\r\n");
} else {
if (!*arg || !strcasecmp(arg, "active")) {
printf("215 Newsgroups in form \"group high low flags\".\r\n");
list (active, 0);
printf(".\r\n");
} else if (!strcasecmp(arg, "newsgroups")) {
printf("215 Descriptions in form \"group description\".\r\n");
list (active, 1);
printf(".\r\n");
} else if (!strcasecmp(arg, "extensions")) {
printf("501 No extensions available.\r\n");
} else if (!strcasecmp(arg, "overview.fmt")) {
printf("215 Order of fields in overview database.\r\n"
"Subject:\r\nFrom:\r\nDate:\r\nMessage-ID:\r\n"
"References:\r\nBytes:\r\nLines:\r\n"
"Xref:full\r\n.\r\n");
} else if (!strcasecmp(arg, "active.times")) {
printf("215 Placeholder - Leafnode will fetch groups on demand\r\n"
"news.announce.newusers 42 tale@uunet.uu.net\r\n"
"news.answers 42 tale@uunet.uu.net\r\n"
".\r\n");
#if 0
} else if (!strcasecmp(arg, "xactive")) {
} else if (!strcasecmp(arg, "distributions")) {
} else if (!strcasecmp(arg, "searches")) {
} else if (!strcasecmp(arg, "searchable")) {
} else if (!strcasecmp(arg, "srchfields")) {
} else if (!strcasecmp(arg, "motd")) {
} else if (!strcasecmp(arg, "prettynames")) {
} else if (!strcasecmp(arg, "subscriptions")) {
#endif
} else {
printf("501 Syntax error\r\n");
}
}
}
void donewgroups(const char* arg)
{
printf("231 Command not supported\r\n.\r\n");
}
void donewnews(const char* arg)
{
printf("500 NEWNEWS is meaningless for this server\r\n");
}
/* next bit is copied from INN 1.4 and modified ("broken") by agulbra
mail to Rich $alz <rsalz@uunet.uu.net> bounced */
/* Scale time back a bit, for shorter Message-ID's. */
#define OFFSET 673416000L
static char ALPHABET[] = "0123456789abcdefghijklmnopqrstuv";
char* generateMessageID(void);
char* generateMessageID(void)
{
static char buff[80];
static time_t then;
static unsigned int fudge;
time_t now;
char* p;
int n;
if (fqdn == NULL) {
return NULL; /* this must be not called if fqdn is NULL. */
}
now = time(0); /* might be 0, in which case fudge will almost fix it */
if (now != then)
fudge = 0;
else
fudge++;
then = now;
p = buff;
*p++ = '<';
n = (unsigned int)now - OFFSET;
while (n) {
*p++ = ALPHABET[(int)(n & 31)];
n >>= 5;
}
*p++ = '.';
n = fudge * 32768 + (unsigned long)getpid();
while (n) {
*p++ = ALPHABET[(int)(n & 31)];
n >>= 5;
}
sprintf(p, ".ln@%s>", fqdn);
return buff;
}
/* the end of what I stole from rsalz and then mangled */
void dopost(void)
{
char* line;
int havefrom = 0;
int havepath = 0;
int havedate = 0;
int havenewsgroups = 0;
int havemessageid = 0;
int havesubject = 0;
int err = 0;
int len;
int out;
char filename[80];
const char* outname;
static int postingno; /* starts as 0 */
sprintf(filename, "%d-%d-%d", (int)getpid(), (int)time(NULL), ++postingno);
outname = getoutgoingfname(filename);
out = open(outname, O_WRONLY|O_EXCL|O_CREAT, 0444);
if (out < 0) {
char dir[80];
sprintf(dir, "%s/out.going", spooldir);
mkdir(dir, 0755);
out = open(outname, O_WRONLY|O_EXCL|O_CREAT, 0444);
if (out < 0) {
printf("440 Unable to open spool file %s\r\n", outname);
return;
}
}
printf("340 Go ahead.\r\n");
fflush(stdout);
do {
int len;
line = getaline(stdin);
if (!line) {
unlink(outname);
exit(0);
}
if (!strncasecmp(line, "From: ", 6)) {
if (havefrom)
err = TRUE;
else
havefrom = TRUE;
}
if (!strncasecmp(line, "Path: ", 6)) {
if (havepath)
err = TRUE;
else
havepath = TRUE;
}
if (!strncasecmp(line, "Message-ID: ", 12)) {
if (havemessageid)
err = TRUE;
else
havemessageid = TRUE;
}
if (!strncasecmp(line, "Subject: ", 9)) {
if (havesubject)
err = TRUE;
else
havesubject = TRUE;
}
if (!strncasecmp(line, "Newsgroups: ", 12)) {
if (havenewsgroups)
err = TRUE;
else
havenewsgroups = TRUE;
}
if (!strncasecmp(line, "Date: ", 6)) {
if (havedate)
err = TRUE;
else
havedate = TRUE;
}
len = strlen(line);
if (len && line[len - 1] == '\n')
line[--len] = '\0';
if (len && line[len - 1] == '\r')
line[--len] = '\0';
if (len && line[len - 1] == '\r')
line[--len] = '\0';
if (len)
write(out, line, len);
else {
if (!havepath) {
write(out, "Path: ", 6);
if (fqdn != NULL) {
write(out, fqdn, strlen(fqdn));
write(out, "!nobody\r\n", 9);
} else {
write(out, "nobody\r\n", 8);
}
}
if (!havedate) {
const char* l = rfctime();
write(out, "Date: ", 6);
write(out, l, strlen(l));
write(out, "\r\n", 2);
}
#ifndef NOMSGID
if (!havemessageid && fqdn != NULL) {
char tmp[80];
sprintf(tmp, "Message-ID: %s\r\n",
generateMessageID());
write(out, tmp, strlen(tmp));
}
#endif
}
write(out, "\r\n", 2);
} while (*line);
do {
line = getaline(stdin);
if (!line) {
unlink(outname);
exit(1);
}
len = strlen(line);
if (len && line[len - 1] == '\n')
line[--len] = '\0';
if (len && line[len - 1] == '\r')
line[--len] = '\0';
if (len && line[len - 1] == '\r')
line[--len] = '\0';
if (len)
write(out, line, len);
write(out, "\r\n", 2);
} while (line[0] != '.' || line[1] != '\0');
close(out);
if (havefrom && havesubject && havenewsgroups && !err) {
printf("240 Article posted, now be patient\r\n");
return;
}
unlink(outname);
if (!havefrom) {
printf("440 No From field, article not posted\r\n");
} else if (!havesubject) {
printf("440 No Subject field, article not posted\r\n");
} else if (!havenewsgroups) {
printf("440 No Newsgroups field, article not posted\r\n");
} else {
printf("440 Formatting error, article not posted\r\n");
}
}
void doxhdr(char* arg)
{
int arglen = strlen(arg);
char* h[] = { "Subject", "From", "Date", "Message-ID", "References",
"Bytes", "Lines", "Xref" };
int n = 8;
char* l;
unsigned long int a,b,c;
FILE* f;
/* have to keep arg since it is a part of a buffer of getaline(). */
arg = strdup(arg);
l = skipnonspaces(arg);
if (l && *l)
*l++ = '\0';
l = skipspaces(l);
if (l && *l == '<') { /* handle message-id form (well) */
FILE* f;
f = fopenart(l);
if (!f) {
printf("430 No such article\r\n");
free(arg);
return;
}
do {
l = getaline(f);
} while (l && *l &&
/* uh, space before : allowed? */
(l[arglen] != ':' || strncasecmp(arg, l, arglen)));
l = skipspaces(skipnonspaces(l));
printf("221 First line of %s header follows:\r\n%s\r\n.\r\n",
arg, l ? l : ""); /* dubious - if not found, "" */
fclose(f);
free(arg);
return;
} else if (l && isdigit(*l)) {
b = a = strtoul(l, &l, 10);
if (a && l && *l) {
l = skipspaces(l);
if (*l == '-') {
l++;
if (l && *l)
b = strtoul(l, &l, 10);
else
b = xlast;
}
l = skipspaces(l);
if (l && *l) {
printf("502 Usage: XHDR header first[-last] or XHDR header message-id\r\n");
free(arg);
return;
}
if (b == 0)
b = xlast;
}
} else {
a = b = artno;
}
if (!group) {
printf("412 Use the GROUP command first\r\n");
free(arg);
return;
}
if (!arg || !*arg) {
printf("502 Usage: XHDR header first[-last] or XHDR header message-id\r\n");
free(arg);
return;
}
do {
n--;
} while (n > -1 && strncasecmp(arg, h[n], strlen(h[n])));
markinterest();
if (a < group->first)
a = group->first;
else if (a > group->last)
a = group->last;
if (b < a)
b = a;
else if (b > group->last)
b = group->last;
if (n >= 0) {
printf("221 %s header (from overview) for postings %lu-%lu:\r\n",
h[n], a, b);
if (xovergroup != group) {
getxover();
xovergroup = group;
}
for(c = a; c <= b; c++) {
if (xoverinfo &&
c >= xfirst && c <= xlast &&
xoverinfo[c - xfirst].text) {
char* l = xoverinfo[c - xfirst].text;
int d;
for(d = 0; l && d <= n; d++)
l = strchr(l + 1, '\t');
if (l) {
if (n == 7) /* dirty Xref: hack */
l = l + 6 + 1;
else
l = l + 1;
}
printf("%lu ", c);
if (l) {
while (*l && *l != '\t')
putchar(*l++);
}
printf("\r\n");
}
}
} else {
printf("221 %s header (from article files) for postings %lu-%lu:\r\n",
arg, a, b);
n = strlen(arg);
for(c = a; c <= b; c++) {
char s[256];
sprintf(s, "%lu", c);
f = fopen(s, "r");
while (f) {
l = getaline(f);
if (!l || !*l || *l == '\r' || *l == '\n') {
fclose(f);
f = 0;
} else if (l[n] == ':' && strncasecmp(arg, l, n) == 0) {
printf("%lu %s\r\n", c, l + n + 2);
}
}
}
}
printf(".\r\n");
free(arg);
return;
}
void doxover(const char* arg)
{
char* l;
unsigned long int a,b, art;
if (!group) {
printf("412 Use the GROUP command first\r\n");
return;
}
markinterest();
l = NULL;
b = a = strtoul(arg, &l, 10);
if (a && l && *l) {
l = skipspaces(l);
if (*l=='-')
b = strtoul(++l, &l, 10);
l = skipspaces(l);
if (l && *l) {
printf("502 Usage: XOVER first[-last]\r\n");
return;
}
}
if (xovergroup != group && !getxover()) {
printf("224 Overview information not available\r\n.\r\n");
return;
}
xovergroup = group;
if (b == 0)
b = xlast;
if (a > xlast)
b = xlast;
if (b > xlast)
b = xlast;
if (a < xfirst)
a = xfirst;
if (b < xfirst)
b = xfirst;
printf("224 Overview information for postings %lu-%lu:\r\n", a, b);
for (art = a; art <= b; art++) {
if (xoverinfo[art - xfirst].text)
printf("%s\r\n", xoverinfo[art-xfirst].text);
}
printf(".\r\n");
}
void dolistgroup(const char* arg)
{
struct newsgroup* g;
unsigned long int art;
if (justaftergroup && group && group->name) {
#if DOTNGFILE
int f;
const char* s = getinterestingngdotfname(group);
/* mark the previous group as _possibly_ interesting */
if ((f = open(s, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
close(f);
#endif
}
rereadactive();
if (arg && strlen(arg)) {
g = findgroup(arg);
if (!g) {
printf("481 No such group: %s\r\n", arg);
return;
} else {
group = g;
artno = g->first;
justaftergroup = TRUE;
}
} else if (group) {
g = group;
} else {
printf("481 No group specified\r\n");
return;
}
markinterest();
group = g;
chdirgroup(g, 1);
if ((xovergroup != group || xovergroup == NULL) && !getxover()) {
printf("481 Overview information not available\r\n");
return;
}
xovergroup = group;
printf("211 Article list for %s follows\r\n", g->name);
for(art = xfirst; art <= xlast; art++) {
if (xoverinfo[art - xfirst].text)
printf("%lu \r\n", art);
}
printf(".\r\n");
if (group)
chdirgroup(group, 1);
}
int main(int argc, char** argv)
{
int fodder;
#ifdef INET6
struct sockaddr_storage sa;
#else
struct hostent* he;
struct sockaddr_in sa;
#endif
#ifdef NI_MAXHOST
char name[NI_MAXHOST];
#else
char name[1025];
#endif
/* initialize FQDN. */
fodder = sizeof(sa);
if (getsockname(0, (struct sockaddr *)&sa, &fodder)) {
strcpy(name, "localhost");
} else {
#ifdef INET6
name[0] = '\0';
getnameinfo((struct sockaddr *)&sa, fodder,
name, sizeof(name), NULL, 0, 0);
#else
he = gethostbyaddr((char *)&sa.sin_addr.s_addr,
sizeof(sa.sin_addr.s_addr),
AF_INET);
strncpy(name,
he && he->h_name ? he->h_name : inet_ntoa(sa.sin_addr),
sizeof(name));
#endif
name[sizeof(name)-1] = '\0';
}
if (strncasecmp(name, "localhost", 9) == 0) {
whoami(); /* initialize FQDN by general way. */
} else {
fqdn = strdup(name);
}
umask(2);
openlog("leafnode", LOG_PID|LOG_CONS, LOG_NEWS);
printf("200 Leafnode+ NNTP Daemon, version %s running at %s\r\n",
version, fqdn ? fqdn : "nowhere");
fflush(stdout);
readconfig();
rereadactive();
parser();
fflush(stdout);
if (nntpout)
fprintf(nntpout, "QUIT\r\n");
exit(0);
}
syntax highlighted by Code2HTML, v. 0.9.1