src/post.c
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- post_regex_set
- postInit
- GenMessageID
- extractHeader
- free_post_cfg
- CMDpost
/* $Id: post.c,v 1.52 1997/07/12 13:49:25 proff Exp
* $Copyright$
*/
#include "nglobal.h"
#include "acc.h"
#include "reg.h"
#include "post.h"
static regex_t postStripHeaderPreg;
static bool post_regex_set(regex_t *preg, char *pat)
/* [<][>][^][v][top][bottom][index][help] */
{
int err_code;
if ((err_code = nn_regcomp(preg, pat, REG_EXTENDED|REG_NOSUB|REG_ICASE))!=0)
{
char errbuf[MAX_LINE];
regerror(err_code, preg, errbuf, sizeof errbuf);
logen (("bad postStripHeader regular expression: %s", errbuf));
return FALSE;
}
return TRUE;
}
EXPORT bool postInit()
/* [<][>][^][v][top][bottom][index][help] */
{
if (!post_regex_set(&postStripHeaderPreg, con->postStripHeader))
return FALSE;
return TRUE;
}
static void GenMessageID (char *messageid)
/* [<][>][^][v][top][bottom][index][help] */
{
struct timeval t;
struct timeval *tv;
tv = &t;
gettimeofday (tv, NULL);
sprintf (messageid, "<%lu.%lu@%.127s>", (unsigned long) tv->tv_sec, (unsigned long) tv->tv_usec, Host);
}
EXPORT char *extractHeader (char *s, char *h, int n)
/* [<][>][^][v][top][bottom][index][help] */
{
char *p = strchr (h, ':');
if (!p)
return NULL;
for (p++; *p && (*p == ' ' || *p == '\t'); p++) ;
strncpy (s, p, n - 1);
return s;
}
struct a_post_cfg
{
struct a_post_cfg *next;
struct a_post_cfg *head;
struct server_cfg *server;
};
static void free_post_cfg(struct a_post_cfg *post_cfg)
/* [<][>][^][v][top][bottom][index][help] */
{
struct a_post_cfg *free_cfg;
while (post_cfg)
{
free_cfg = post_cfg;
post_cfg = post_cfg->next;
free(free_cfg);
}
}
EXPORT bool CMDpost ()
/* [<][>][^][v][top][bottom][index][help] */
{
char messageid[MAX_MSGID] = "";
char newsgroups[MAX_HEADER] = "";
bool addmsgid = FALSE;
struct a_post_cfg *post_head = NULL, *post_cfg;
int posted = 0;
struct strList *msg = NULL;
char bfr[MAX_LINE];
bool body = FALSE;
char *group;
char *post_err = NULL;
int bytes = 0;
int numGroups = 0;
bool f_have_organization=FALSE;
emitrn ("340 Ok");
flush ();
do
{
int cc=Get(bfr, sizeof bfr);
if (cc<1)
retire_vm_proc(1);
bytes += cc;
if (!body)
{
if (strEq (bfr, "\r\n") || strEq (bfr, "\n"))
{
body = TRUE;
if (!f_have_organization)
{
sprintf (bfr, "Organization: %.127s\r\n", con->Organization);
msg = strListAdd (msg, bfr);
strcpy (bfr, "\r\n");
}
}
else if (strnCaseEq (bfr, "message-id:", 11))
extractHeader (messageid, bfr, MAX_MSGID);
else if (strnCaseEq (bfr, "newsgroups:", 11))
extractHeader (newsgroups, bfr, MAX_HEADER);
else if (strnCaseEq (bfr, "organization:", 13))
{
if (con->replaceOrganization)
sprintf (bfr, "Organization: %.127s\r\n", con->Organization);
f_have_organization = TRUE;
}
else if (nn_regexec(&postStripHeaderPreg, bfr, cc, 0, 0, 0) == 0)
continue;
}
msg = strListAdd (msg, bfr);
} while (!EL (bfr));
if (!msg || *newsgroups == '\0')
{
emitf ("%d No newsgroups specified.\r\n", NNTP_POSTFAIL_VAL);
loginn (("%s post failed no newsgroups specified.", ClientHostNormal));
Stats->postsFailed++;
PostsRejected++;
if (msg)
strListFree (msg);
return FALSE;
}
PostsReceived++;
if (!*messageid)
{
addmsgid = 1;
GenMessageID (messageid);
}
for (post_cfg = NULL, group = strtok (newsgroups, ","); group; group = strtok (NULL, ","))
{
struct group_cfg *gcf;
struct server_cfg *last_cfg = NULL;
struct authent *gp;
numGroups++;
strStripLeftRight (group);
gp = authorise(RemoteHosts, group);
if (!gp || !gp->post)
continue;
for (gcf = GroupList; gcf; gcf = gcf->next)
{
if (matchExp (gcf->group_pat, group, 1, 0))
last_cfg = gcf->server_cfg;
}
if (!last_cfg)
continue;
if (!post_cfg)
{
post_cfg = post_head = Smalloc (sizeof *post_cfg);
} else
{
struct a_post_cfg *cf;
for (cf = post_head; cf; cf = cf->next)
{
if (strCaseEq(cf->server->host, last_cfg->host))
goto duplicate_server;
}
post_cfg->next = Smalloc (sizeof *post_cfg);
post_cfg = post_cfg->next;
}
post_cfg->server = last_cfg;
post_cfg->head = post_head;
post_cfg->next = NULL;
duplicate_server:
continue; /* solaris cc dumbness */
}
if (!post_head)
{
emitf ("%d permission denied.\r\n", NNTP_PERM_VAL);
loginn (("%s noperm post without permission.", ClientHostNormal));
Stats->postsFailed++;
PostsRejected++;
if (msg)
strListFree (msg);
return FALSE;
}
for (posted = 0, post_cfg = post_head; post_cfg; post_cfg = post_cfg->next)
{
struct strList *art;
bool body = FALSE;
struct server_cfg *cf;
logd (("posting %s to %s", messageid, post_cfg->server->host));
if (!(cf = attachServer (post_cfg->server)))
{
loginnw (("%s post failed couldn't post article to %s (server down)", ClientHostNormal, post_cfg->server->host));
continue;
}
Cfemitrn (cf, "post");
Cfflush (cf);
if (!Cfget (cf, bfr, sizeof (bfr)))
{
dropped:
loginnw (("%s post failed couldn't post to server %s (server dropped connection)", ClientHostNormal, post_cfg->server->host));
continue;
}
if (strToi (bfr) != NNTP_START_POST_VAL)
{
strStripEOL (bfr);
loginnw (("%s post failed couldn't post to server %s (%s)", ClientHostNormal, post_cfg->server->host, bfr));
Stats->postsFailed++;
continue;
}
for (art = msg->head; art; art = art->next)
{
if (!body && (strEq (art->data, "\n") || strEq (art->data, "\r\n")))
{
body = TRUE;
if (addmsgid)
Cfemitf (cf, "Message-ID: %s\r\n", messageid);
Cfemitf (cf, "Cache-Post-Path: %s!%s\r\n", Host, ClientHost);
Cfemitf (cf, "X-Cache: nntpcache " VERSION " (see http://www.nntpcache.com/)\r\n");
}
Cfemit (cf, art->data);
}
Cfflush (cf);
if (!Cfget (cf, bfr, sizeof bfr))
goto dropped;
strStripEOL (bfr);
if (strToi (bfr) == NNTP_POSTEDOK_VAL)
posted++;
else
{
if (post_err)
free (post_err);
post_err = Sstrdup (bfr);
loginnw (("%s post failed couldn't post to %s (%s)", ClientHostNormal, post_cfg->server->host, bfr));
Stats->postsFailed++;
}
}
strListFree (msg);
free_post_cfg(post_head);
if (posted)
{
emitrn (NNTP_POSTEDOK);
if (post_err)
free (post_err);
GroupNextNoCache = TRUE; /* let the reader see it */
} else
{
if (post_err)
{
emitrn (post_err);
free (post_err);
} else
emitf ("%d No servers accepted article\r\n", NNTP_POSTFAIL_VAL);
PostsRejected++;
return FALSE;
}
Stats->posts++;
Stats->postsBytes += bytes;
if (numGroups > 1)
Stats->postsCross++;
return TRUE;
}