src/post.c

/* [<][>]
[^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. post_regex_set
  2. postInit
  3. GenMessageID
  4. extractHeader
  5. free_post_cfg
  6. 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;
}

/* [<][>][^][v][top][bottom][index][help] */