Beispiel #1
0
int rw_init_courier(const char *name)
{
unsigned	i;
int	err=0;

	if (rw_init_verbose_flag)
	{
		clog_msg_start_info();
		clog_msg_str("Loading STATIC transport module libraries.");
		clog_msg_send();
	}
	if (rw_install_start())	return (-1);
	for (i=0; rw_static[i].name; i++)
		/* name != 0 really meaningless for static libs, but,
		** what the heck...
		*/
		if ((name == 0 || strcmp(name,
			rw_static[i].name) == 0) &&
			rw_install(rw_static[i].name,
				rw_static[i].rw_install,
				rw_static[i].rw_init))
			err=1;

	if (err || rw_install_init())
	{
		clog_msg_start_err();
		clog_msg_str("Transport module installation has FAILED.");
		clog_msg_send();
		return (-1);
	}
	return (0);
}
Beispiel #2
0
static void kill1filter(struct filterinfo **p)
{
int	waitstat;
pid_t	pid;
struct	filterinfo *pp= *p;

	*p=pp->next;

	clog_msg_start_info();
	clog_msg_str("Stopping ");
	clog_msg_str(pp->filtername);
	clog_msg_send();
	close(pp->fd0);
	while ((pid=wait(&waitstat)) >= 0 && pid != pp->p)
		;
	free(pp->filtername);
	free(pp);
}
Beispiel #3
0
static void purgedir(const char *dirname)
{
    std::string	buf;
    DIR	*p;
    struct dirent *de;

    clog_msg_start_info();
    clog_msg_str("Purging ");
    clog_msg_str(dirname);
    clog_msg_send();

    p=opendir(dirname);
    if (!p)	return;
    while ((de=readdir(p)) != NULL)
    {
        if (de->d_name[0] == '.')	continue;
        buf=dirname;
        buf += '/';
        buf += de->d_name;
        rmdir(buf.c_str());		// Just for the hell of it
    }
    closedir(p);
}
Beispiel #4
0
static int faxsend_cleanup(int errcode, char *errmsg, void *vp)
{
	struct faxconv_err_args *args=(struct faxconv_err_args *)vp;
	unsigned pages_sent=0;
	char *p, *q;

	int i;
	time_t now_time;

	unsigned coverpage_cnt=0;
	unsigned page_cnt=0;

	/* Check how many files sendfax renamed (were succesfully sent) */

	while (args->file_list)
	{
		if (access(args->file_list->filename, 0) == 0)
			break;

		if (coverpage_cnt < args->n_cover_pages)
			++coverpage_cnt;
		else
			++pages_sent;
		args->file_list=args->file_list->next;
	}

	/* Strip out any blank lines in captured output from sendfax */

	for (p=q=errmsg; *p; p++)
	{
		if (*p == '\n' && (p[1] == '\n' || p[1] == 0))
			continue;

		*q++=*p;
	}
	*q=0;

	/* Find the last message from sendfax */

	for (p=q=errmsg; *p; p++)
	{
		if (*p != '\n')
			continue;

		*p=0;

		/* Dump sendfax's output to the log */

		if (*q)
		{
			clog_msg_start_info();
			clog_msg_str("courierfax: " SENDFAX ": ");
			clog_msg_str(q);
			clog_msg_send();
		}
		q=p+1;
	}

	if (*q)	/* Last line of the error message */
	{
		clog_msg_start_info();
		clog_msg_str("courierfax: " SENDFAX ": ");
		clog_msg_str(q);
		clog_msg_send();
	}
	else	/* Default message */
	{
		q=SENDFAX ": completed.";
	}

	/*
	** Ugly hack: capture the following message from sendfax:
	**
	** /usr/sbin/sendfax: cannot access fax device(s) (locked?)
	*/

#if 0
	lockflag=0;
	p=strchr(q, ':');
	if (p)
	{
		static const char msg1[]="cannot access fax device";
		static const char msg2[]="locked";

		++p;
		while (*p && isspace((int)(unsigned char)*p))
			p++;

		if (*p && strncasecmp(p, msg1, sizeof(msg1)-1) == 0)
		{
			p += sizeof(msg1);
			while (*p && !isspace((int)(unsigned char)*p))
				++p;

			p=strchr(p, '(');

			if (p && strncmp(p+1, msg2, sizeof(msg2)-1) == 0)
			{
				args->is_locked=1;
				clog_msg_start_info();
				clog_msg_str("courierfax: detected locked"
					     " modem line, sleeping...");
				clog_msg_send();
				sleep(60);
				return (-1);
			}
		}
	}
#else

	if (errcode == 2)
	{
		args->is_locked=1;
		clog_msg_start_info();
		clog_msg_str("courierfax: detected locked"
			     " modem line, sleeping...");
		clog_msg_send();
		sleep(60);
		return (-1);
	}
#endif

	ctlfile_append_connectioninfo(args->ctf, args->nreceip,
				      COMCTLFILE_DELINFO_REPLY, q);

	sprintf(errmsg, "%u cover pages, %u document pages sent.",
		coverpage_cnt, page_cnt);

	i=ctlfile_searchfirst(args->ctf, COMCTLFILE_FAXEXPIRES);

	time(&now_time);
	ctlfile_append_reply(args->ctf, args->nreceip,
			     errmsg,
			     (pages_sent == 0 &&
			      i >= 0 &&
			      errcode < 10 &&
			      now_time < strtotime(args->ctf->lines[i]+1)
			      ? COMCTLFILE_DELDEFERRED:
			      COMCTLFILE_DELFAIL_NOTRACK), 0);
	return (-1);
}
Beispiel #5
0
/*
**	sighup attempts to synchronize everything.
*/
static void sighup()
{
struct filterinfo **pp;
DIR	*dirp;
struct dirent *de;

	/* Start any new filters */

	dirp=opendir(FILTERACTIVEDIR);
	while (dirp && (de=readdir(dirp)) != 0)
	{
	char	*n;
	int	pipefd[2];
	struct filterinfo *newp;

		if (de->d_name[0] == '.')
			continue;

		for (pp= &filterlist; *pp; pp= &(*pp)->next)
			if (strcmp( (*pp)->filtername, de->d_name) == 0)
				break;

		if (*pp)	continue;

		n=malloc(sizeof(FILTERACTIVEDIR "/")+strlen(de->d_name));
		if (!n)
		{
			perror("malloc");
			exit(1);
		}
		strcat(strcpy(n, FILTERACTIVEDIR "/"), de->d_name);

		if ( (newp=(struct filterinfo *)
				malloc(sizeof(struct filterinfo))) == 0 ||
			(newp->filtername=malloc(strlen(de->d_name)+1)) == 0)
		{
			perror("malloc");
			exit(1);
		}
		strcpy(newp->filtername, de->d_name);
		newp->next=filterlist;
		filterlist=newp;

		if (pipe(pipefd) < 0)
		{
			perror("pipe");
			exit(1);
		}

		newp->fd0=pipefd[1];

		while ((newp->p=fork()) < 0)
		{
			perror("fork");
			sleep(3);
		}

		if ( newp->p == 0)
		{
			dup2(pipefd[0], 0);
			close(pipefd[0]);
			close(pipefd[1]);
			execl(n, de->d_name, (char *)0);
			perror("exec");
			exit(1);
		}
		free(n);
		close(pipefd[0]);
		if (fcntl(newp->fd0, F_SETFD, FD_CLOEXEC) < 0)
		{
			perror("fcntl");
			exit(1);
		}
		clog_msg_start_info();
		clog_msg_str("Starting ");
		clog_msg_str(newp->filtername);
		clog_msg_send();
	}
	if (dirp)	closedir(dirp);

	/* Then, kill any filters that should not be running any more */

	for (pp= &filterlist; *pp; )
	{
	char	*n=activename( (*pp)->filtername );

		if (access(n, 0) == 0)
		{
			free(n);
			pp= &(*pp)->next;
			continue;
		}
		free(n);
		kill1filter(pp);
	}

	/* Finally, remove any sockets for filters that don't run any more */

  {
  static const char *dirs[2]={FILTERSOCKETDIR, ALLFILTERSOCKETDIR};
  int i;

    for (i=0; i<2; i++)
    {
	dirp=opendir(dirs[i]);
	while (dirp && (de=readdir(dirp)) != 0)
	{
	char	*n;

		if (de->d_name[0] == '.')
			continue;

		for (pp= &filterlist; *pp; pp= &(*pp)->next)
			if (strcmp( (*pp)->filtername, de->d_name) == 0)
				break;

		if (*pp)	continue;

		n=malloc(strlen(dirs[i])+strlen(de->d_name)+2);
		if (!n)
		{
			perror("malloc");
			exit(1);
		}
		strcat(strcat(strcpy(n, dirs[i]), "/"), de->d_name);
		unlink(n);
		free(n);
	}
	if (dirp)	closedir(dirp);
    }
  }
}
Beispiel #6
0
void drvinfo::init()
{
unsigned	cnt, i;
struct	rw_transport *p;

	module_dsn=0;
	queuelo=0;
	for (cnt=0, p=rw_transport_first; p; p=p->next)
		++cnt;
	if ((modules=new drvinfo[cnt]) == 0)	clog_msg_errno();
	cnt=0;

	for (p=rw_transport_first; p; p=p->next)
	{
	char	*namebuf=(char *)courier_malloc(
		sizeof( SYSCONFDIR "/module.")+strlen(p->name));

		strcat(strcpy(namebuf, SYSCONFDIR "/module."),
				p->name);

	FILE	*config=fopen(namebuf, "r");

		if (!config)
		{
			clog_msg_start_err();
			clog_msg_str("Cannot open ");
			clog_msg_str(namebuf);
			clog_msg_send();
			exit(1);
		}
		free(namebuf);
		
	unsigned maxdels=1;
	unsigned maxhost=1;
	unsigned maxrcpt=1;
	char	*prog=0;
	char	buf[BUFSIZ];

		while (fgets(buf, sizeof(buf), config) != 0)
		{
		char	*p;

			if ((p=strchr(buf, '#')) != 0)	*p=0;
			p=strtok(buf, " \t\r\n=");
			if (strcmp(p, "MAXDELS") == 0)
			{
				p=strtok(NULL, " \t\r\n=");
				if (p)	maxdels=atoi(p);
			}
			else if (strcmp(p, "MAXHOST") == 0)
			{
				p=strtok(NULL, " \t\r\n=");
				if (p)	maxhost=atoi(p);
			}
			else if (strcmp(p, "MAXRCPT") == 0)
			{
				p=strtok(NULL, " \t\r\n=");
				if (p)	maxrcpt=atoi(p);
			}
			else if (strcmp(p, "PROG") == 0 && !prog)
			{
				p=strtok(NULL, "\t\r\n=");
				if (p)
				{
					prog=(char *)
						courier_malloc(strlen(p)+1);
					strcpy(prog, p);
				}
			}
		}
		fclose(config);
		if (!prog)	continue;	// Input only module

		modules[cnt].module=p;
		p->udata=(void *)&modules[cnt];
		modules[cnt].delinfo_list.resize(maxdels);
		modules[cnt].hosts_list.resize(maxdels);
		queuelo += maxdels;
		modules[cnt].maxhost=maxhost;
		modules[cnt].maxrcpt=maxrcpt;
		modules[cnt].delpfreefirst=0;

		if (strcmp(p->name, DSN) == 0)
			module_dsn= &modules[cnt];

		for (i=0; i<maxdels; i++)
		{
			modules[cnt].delinfo_list[i].delid=i;
			modules[cnt].delinfo_list[i].freenext=
				modules[cnt].delpfreefirst;
			modules[cnt].delpfreefirst=
				&modules[cnt].delinfo_list[i];
		}

		modules[cnt].hdlvrpfree=0;
		for (i=0; i<maxdels; i++)
		{
			modules[cnt].hosts_list[i].next=
				modules[cnt].hdlvrpfree;
			modules[cnt].hdlvrpfree=&modules[cnt].hosts_list[i];
		}
		modules[cnt].hdlvrpfirst=0;
		modules[cnt].hdlvrplast=0;

	int	pipe0[2], pipe1[2];

		if (pipe(pipe0) || pipe(pipe1))
			clog_msg_errno();

		switch (modules[cnt].module_pid=fork())	{
		case 0:
#if 0
// replaced by close-on-exec, below

			for (i=cnt; i; )
			{
				--i;
				fclose(modules[i].module_to);
				close(modules[i].module_from.fd);
			}
#endif
			close(pipe0[1]);
			close(pipe1[0]);
			dup2(pipe0[0], 0);
			dup2(pipe1[1], 1);
			close(pipe0[0]);
			close(pipe1[1]);
			signal(SIGCHLD, SIG_DFL);

			if (chdir(MODULEDIR) ||
				chdir(modules[cnt].module->name))
			{
				clog_msg_start_err();
				clog_msg_str(MODULEDIR "/");
				clog_msg_str(modules[cnt].module->name);
				clog_msg_str(" does not exist.");
				clog_msg_send();
				clog_msg_errno();
			}

			{
			char maxdels_buf[MAXLONGSIZE+15];
			char maxhost_buf[MAXLONGSIZE+15];
			char maxrcpt_buf[MAXLONGSIZE+15];
			const char *sh=getenv("SHELL");

				sprintf(maxdels_buf, "MAXDELS=%ld",
					(long)maxdels);
				sprintf(maxhost_buf, "MAXHOST=%ld",
					(long)maxhost);
				sprintf(maxrcpt_buf, "MAXRCPT=%ld",
					(long)maxrcpt);

				putenv(maxdels_buf);
				putenv(maxhost_buf);
				putenv(maxrcpt_buf);

			const char *ch=courierdir();
			char	*p=(char *)courier_malloc(strlen(ch)+
					sizeof("COURIER_HOME="));

				strcat(strcpy(p,"COURIER_HOME="), ch);
				putenv(p);

				if (!sh)	sh="/bin/sh";
				execl(sh, sh, "-c", prog, (char *)0);
				clog_msg_start_err();
				clog_msg_str(MODULEDIR "/");
				clog_msg_str(modules[cnt].module->name);
				clog_msg_str(": ");
				clog_msg_str(prog);
				clog_msg_send();
				clog_msg_errno();
			}
		case -1:
			clog_msg_errno();
			break;
		}

		close(pipe0[0]);
		close(pipe1[1]);

		if (fcntl(pipe0[1], F_SETFD, FD_CLOEXEC) ||
			fcntl(pipe1[0], F_SETFD, FD_CLOEXEC))
			clog_msg_errno();

		if ((modules[cnt].module_to=fdopen(pipe0[1], "w")) == NULL)
			clog_msg_errno();

		mybuf_init( &modules[cnt].module_from, pipe1[0] );

		clog_msg_start_info();
		clog_msg_str("Started ");
		clog_msg_str(prog);
		clog_msg_str(", pid=");
		clog_msg_int(modules[cnt].module_pid);
		clog_msg_str(", maxdels=");
		clog_msg_int(maxdels);
		clog_msg_str(", maxhost=");
		clog_msg_int(maxhost);
		clog_msg_str(", maxrcpt=");
		clog_msg_int(maxrcpt);
		clog_msg_send();
		free(prog);
		cnt++;
	}
	nmodules=cnt;

	if (queuelo < 200)	queuelo=200;

char	*cfname=config_localfilename("queuelo");
char	*conf=config_read1l(cfname);

	if (conf)
	{
		queuelo=atoi(conf);
		free(conf);
	}
	free(cfname);
	if (queuelo < 20)	queuelo=20;

	cfname=config_localfilename("queuehi");
	conf=config_read1l(cfname);
	if (conf)
	{
		queuehi=atoi(conf);
		free(conf);
	}
	else
		queuehi=queuelo < 500 ? queuelo * 2:queuelo+1000;
	if (queuehi < queuelo)	queuehi=queuelo;
	free(cfname);

	clog_msg_start_info();
	clog_msg_str("queuelo=");
	clog_msg_int(queuelo);
	clog_msg_str(", queuehi=");
	clog_msg_int(queuehi);
	clog_msg_send();

	if (module_dsn == 0)
	{
		clog_msg_start_err();
		clog_msg_str("Driver dsn not found.");
		clog_msg_send();
		exit(1);
	}
}
Beispiel #7
0
int courierbmain()
{
    fd_set	fds, fdc;
    struct	mybuf trigger_buf;

    clog_open_syslog("courierd");
    rw_init_verbose(1);
    if (rw_init_courier(0))	return (1);
    drvinfo::init();

    libmail_changeuidgid(MAILUID, MAILGID);
    signal(SIGPIPE, SIG_IGN);

    respawnlo=config_time_respawnlo();
    respawnhi=config_time_respawnhi();

    retryalpha=config_time_retryalpha();
    retrybeta=config_retrybeta();
    retrygamma=config_time_retrygamma();
    retrymaxdelta=config_retrymaxdelta();
    flushtime=0;
    delaytime=config_time_submitdelay();

    queuefill=config_time_queuefill();
    nextqueuefill=0;

    purgedir(MSGQDIR);
    purgedir(MSGSDIR);
    rmdir(MSGQDIR);
    mkdir(MSGQDIR, 0755);
    trackpurge();

    if ((triggerw=open(triggername, O_WRONLY, 0)) < 0 ||
            (triggerr=open(triggername, O_RDONLY, 0)) < 0)
        clog_msg_errno();

    time(&start_time);

    courierbstart=start_time;

    msgq::init(queuehi);

    shutdown_flag=0;
    FD_ZERO(&fds);

    unsigned nd;
    int	maxfd=triggerr;

    FD_SET(maxfd, &fds);
    mybuf_init(&trigger_buf, triggerr);

    for (nd=0; nd<drvinfo::nmodules; nd++)
    {
        int	fd=drvinfo::modules[nd].module_from.fd;

        if (fd > maxfd)	maxfd=fd;
        FD_SET(fd, &fds);
    }

    ++maxfd;

    time_t	current_time, next_time, shutdown_time;

    current_time=start_time;

    shutdown_time=0;

    msgq::queuescan();	// Initial queue scan

    int	doscantmp=1;

////////////////////////////////////////////////////////////////////////////
//
// Main loop:
//
// A) Scan tmp for new messages.
//
// B) Schedule messages for delivery, when their time comes.
//
// C) Update statistics.
//
// D) Stop scheduling messages when restart signal received.
//
// E) Restart if there's no activity for 5 mins after we've been running
//    for respawnlo amount of times.
//
// F) When we've been running for respawnhi amount of time, stop scheduling
//    messages, restart when all deliveries have been completed.
//
// G) Receive delivery completion messages from modules.
//
////////////////////////////////////////////////////////////////////////////
    for (;;)
    {
        msgq	*mp;

        if (shutdown_flag)
            doscantmp=0;

        if (doscantmp)
            doscantmp=msgq::tmpscan();

        if (shutdown_flag && msgq::inprogress == 0)
            break;

        if (current_time >= start_time + respawnhi && !shutdown_flag)
        {
            clog_msg_start_info();
            clog_msg_str("SHUTDOWN: respawnhi limit reached.");
            clog_msg_send();
            shutdown_flag=1;
            continue;
        }

        if (diskspacelow() && msgq::queuehead &&
                msgq::queuehead->nextsenddel <= current_time)
        {
            clog_msg_start_err();
            clog_msg_str("Low on disk space.");
            clog_msg_send();
            for (mp=msgq::queuehead; mp &&
                    mp->nextsenddel <= current_time + 300;
                    mp=mp->next)
                mp->nextsenddel=current_time+300;
        }

        if (!shutdown_flag)
        {
            while ((mp=msgq::queuehead) != 0 &&
                    mp->nextsenddel <= current_time)
            {
                mp->removewq();
                mp->start_message();
            }
        }

        if (nextqueuefill && nextqueuefill <= current_time)
        {
            nextqueuefill=0;
            if (!shutdown_flag)
            {
                msgq::queuescan();
            }

        }

        next_time=0;
        if ( msgq::queuehead && msgq::queuehead->nextsenddel
                > current_time)
            next_time=msgq::queuehead->nextsenddel;
        if (!shutdown_flag && msgq::inprogress == 0 &&
                shutdown_time == 0)
        {
            shutdown_time=current_time + 5 * 60;
            if (shutdown_time < start_time + respawnlo)
                shutdown_time=start_time + respawnlo;
        }

        if (shutdown_time && (next_time == 0 ||
                              shutdown_time < next_time))
            next_time=shutdown_time;

        if (nextqueuefill)
        {
            /* Or, wake up next time we need to refill the queue */

            if (next_time == 0 || nextqueuefill < next_time)
            {
                next_time=nextqueuefill;
            }
        }

        fdc=fds;

        struct	timeval	tv;

        if (next_time)
        {
            tv.tv_sec= next_time > current_time ?
                       next_time - current_time:0;
            tv.tv_usec=0;
        }

#if 1
        {
            char buf[40];

            clog_msg_start_info();
            clog_msg_str("Waiting.  shutdown time=");
            strcpy(buf, shutdown_time ? ctime(&shutdown_time):"none\n");
            *strchr(buf, '\n')=0;
            clog_msg_str(buf);

            clog_msg_str(", wakeup time=");
            strcpy(buf, next_time ? ctime(&next_time):"none\n");
            *strchr(buf, '\n')=0;
            clog_msg_str(buf);
            clog_msg_str(", queuedelivering=");
            clog_msg_int(msgq::queuedelivering);
            clog_msg_str(", inprogress=");
            clog_msg_int(msgq::inprogress);
            clog_msg_send();
        }
#endif

        while (select(maxfd, &fdc, (fd_set *)0, (fd_set *)0,
                      (next_time && doscantmp == 0 ?
                       &tv:(struct timeval *)0)) < 0)
        {
            if (errno != EINTR)	clog_msg_errno();
        }
        time(&current_time);
        if (shutdown_time)
        {
            if (current_time >= shutdown_time &&
                    msgq::inprogress == 0)
            {
                clog_msg_start_info();
                clog_msg_str("SHUTDOWN: respawnlo limit reached, system inactive.");
                clog_msg_send();
                shutdown_flag=1;
            }
            shutdown_time=0;
        }

        /* Handle commands sent via the trigger pipe */

        if (FD_ISSET(triggerr, &fdc))
        {
            unsigned	l;
            char	cmdbuf[256];
            int	c;

            do
            {
                l=0;
                do
                {
                    c=mybuf_get(&trigger_buf);
                    if (l < sizeof(cmdbuf)-1)
                        cmdbuf[l++]=c;
                } while (c != '\n');
                cmdbuf[l]=0;

                if (strcmp(cmdbuf, TRIGGER_NEWMSG) == 0)
                    doscantmp=1;
                else if (strcmp(cmdbuf, TRIGGER_RESTART) == 0)
                {
                    shutdown_flag=1;
                    clog_msg_start_info();
                    clog_msg_str("SHUTDOWN: Restarting...");
                    clog_msg_send();
                }
                else if (strcmp(cmdbuf, TRIGGER_STOP) == 0)
                {
                    clog_msg_start_info();
                    clog_msg_str("SHUTDOWN: Stopping...");
                    clog_msg_send();
                    _exit(99);
                }
                else if (strcmp(cmdbuf, TRIGGER_FLUSH) == 0)
                {
                    flushtime=current_time;
                    for (mp=msgq::queuehead; mp;
                            mp=mp->next)
                        mp->nextsenddel=current_time;
                }
                else if (strncmp(cmdbuf, TRIGGER_FLUSHMSG,
                                 sizeof(TRIGGER_FLUSHMSG)-1) == 0)
                {
                    char *p;
                    ino_t	n;

                    if ((p=strchr(cmdbuf, '\n')) != 0)
                        *p=0;

                    p=cmdbuf+sizeof(TRIGGER_FLUSHMSG)-1;
                    while (*p == ' ')	++p;
                    if (comparseqid(p, &n) == 0 &&
                            !shutdown_flag)
                        msgq::flushmsg(n, p);
                }
            } while (mybuf_more(&trigger_buf));
        }

        for (nd=0; nd<drvinfo::nmodules; nd++)
        {
            struct mybuf *p= &drvinfo::modules[nd].module_from;
            size_t	delnum;
            int	c;

            if (!FD_ISSET(p->fd, &fdc))	continue;
            do
            {
                delnum=0;
                while (errno=0, ((c=mybuf_get(p)) != '\n'))
                {
                    if (c < 0)
                    {
                        if (errno == EINTR)
                            continue;

                        clog_msg_start_err();
                        clog_msg_str("MODULE ");
                        clog_msg_str(
                            drvinfo::modules[nd]
                            .module->name);
                        clog_msg_str(" ABORTED.");
                        clog_msg_send();
                        _exit(1);
                    }
                    if (c >= '0' && c <= '9')
                        delnum=delnum * 10 + (c-'0');
                }
                msgq::completed(drvinfo::modules[nd], delnum);
            } while (mybuf_more(p));
            if (!shutdown_flag)	shutdown_time=0;
        }
    }

    close(triggerr);
    close(triggerw);

    drvinfo::cleanup();
    return (0);
}
Beispiel #8
0
void msgq::start_message()
{
//
// Schedule deliveries for this message.
//

#if 0
clog_msg_start_info();
clog_msg_str("Start message ");
logmsgid(this);
clog_msg_send();
#endif

	size_t n=rcptinfo_list.size();

	if (n == 0)
	{
		done(this, 0);
		return;
	}

	size_t i;

	for (i=0; i<n; i++)
	{
		rcptinfo &ri=rcptinfo_list[i];

	drvinfo *drvp=ri.delmodule;
	dlvrhost *hostp, *freehostp=0;

//
// Check if the same host has any deliveries in progress, or pending.
// Search the hdlvrpfree/hdlvrplast link list for this host.
//
		for (hostp=drvp->hdlvrplast; hostp; hostp=hostp->prev)
		{
			if (hostp->hostname == ri.delhost)
{
#if 0
clog_msg_start_info();
clog_msg_str("Found host ");
clog_msg_str(ri.delhost);
clog_msg_str(", # of deliveries=");
clog_msg_uint(hostp->dlvrcount);
clog_msg_send();
#endif
				break;
}

//
// Just in case we don't find it, remember the last host at the end of the
// MRU list which does not have any deliveries in progress.
//
			if (!freehostp &&
				drvp->hdlvrpfree == 0 && hostp->dlvrcount == 0)
				freehostp=hostp;
				// Recycle a host struct used longest ago
		}
		if (!hostp)
		{
//
// Did not find this host.
//
			if (drvp->hdlvrpfree)
			{
//
// There's an unused host structure, take it.
//
				hostp=drvp->hdlvrpfree;
				drvp->hdlvrpfree=hostp->next;
			}
			else if (freehostp)
			{
//
// Recycle a host structure for a host without any current deliveries,
// remove it from the MRU list.
//
				hostp=freehostp;
				if (hostp->next)
					hostp->next->prev=hostp->prev;
				else
					drvp->hdlvrplast=hostp->prev;
				if (hostp->prev)
					hostp->prev->next=hostp->next;
				else
					drvp->hdlvrpfirst=hostp->next;
			}

			if (hostp)
			{
//
// Ok, initialize this host, and stick it at the end of the MRU list.
//
				hostp->hostname=ri.delhost;
				hostp->dlvrcount=0;
				hostp->next=0;
				if ((hostp->prev=drvp->hdlvrplast) != 0)
					drvp->hdlvrplast->next=hostp;
				else
					drvp->hdlvrpfirst=hostp;
				drvp->hdlvrplast=hostp;
				if (hostp->pending_list)
					hostp->pending_list->hostp=0;
				hostp->pending_list=0;
			}
		}
//
// Determine if we can start a new delivery.  The conditions are:
// A) We found an unused host structure, and the number of deliveries in
// progress to this host is less than the maximum set for the module,
//
// AND
//
// B) The total number of current deliveries to this host is less than
// the maximum set for this module (there's an available delivery slot
// structure)
//
		if (hostp && hostp->dlvrcount < drvp->maxhost &&
			drvp->delpfreefirst)
		{
		delinfo *newdi=drvp->delpfreefirst;

			drvp->delpfreefirst=newdi->freenext;
			newdi->dlvrphost=hostp;
			newdi->rcptlist=&ri;

			ri.pending=0;
			hostp->dlvrcount++;
			startdelivery(drvp, newdi);
			continue;
		}
//
// We are unable to start the delivery at this time.  At the recipient list
// to the list of pending deliveries for this host.
//
// The first thing is to make sure that this host structure has the pending
// list structure allocated.
//

	pendelinfo *pi;

		if (hostp)
		{
			if ((pi=hostp->pending_list) == 0)
			{
				drvp->pendelinfo_list.push_back(pendelinfo());

				std::list<pendelinfo>::iterator pos=
					--drvp->pendelinfo_list.end();

				pi=& *pos;
				pi->pos=pos;
				pi->drvp=drvp;
				pi->hostname=ri.delhost;
				pi->hostp=hostp;
				hostp->pending_list=pi;
			}
		}
		else
		{
			std::list<pendelinfo>::iterator pos;

//
// We don't even have a host structure.
// That's ok, search the pendelinfo_list of this module anyway.
//
			pi=0;

			for (pos=drvp->pendelinfo_list.begin();
			     pos != drvp->pendelinfo_list.end();
			     ++pos)
			{
				pi=& *pos;
				if (pi->hostname == ri.delhost) break;
				pi=0;
			}
			if (!pi)
			{
				drvp->pendelinfo_list.push_back(pendelinfo());
				pos= --drvp->pendelinfo_list.end();

				pi=& *pos;
				pi->pos=pos;
				pi->drvp=drvp;
				pi->hostname=ri.delhost;
				pi->hostp=0;
			}
		}

		ri.pending=pi;
		pi->receipient_list.push_back(&ri);

		ri.pendingpos= --pi->receipient_list.end();
	}
}
Beispiel #9
0
int msgq::queuescan3(std::string subdir, std::string name,
		     const char *isnewmsg)
{
	struct ctlfile	ctlinfo;
	ino_t	inum;
	time_t	deltime, delsendtime;
	const char *p=name.c_str();
	struct	stat	stat_buf;

	++p;
	inum=strtoino(p);
	while (isdigit(*p))	p++;
	++p;
	deltime=strtotime(p);
	name= subdir + '/' + name;
	if (ctlfile_openfn(name.c_str(), &ctlinfo, 0, 1))
	{
		if (errno)
		{
			clog_msg_start_err();
			clog_msg_str("Cannot read ");
			clog_msg_str(name.c_str());
			clog_msg_send();
			clog_msg_prerrno();
		}
		return (0);
	}
	delsendtime=deltime;
	if (flushtime && ctlinfo.mtime < flushtime && flushtime < deltime)
		delsendtime=flushtime;

	if (!queuefree)
	{
	msgq	*p;

//
// msgq array is full.  See if we can remove the last message from the
// pending queue.

		p=queuetail;
		if (p && p->nextsenddel > delsendtime)
		{

#if 0
clog_msg_start_info();
clog_msg_str("Removing ");
clog_msg_uint(p->msgnum);
clog_msg_str(" to make room for this message.");
clog_msg_send();
#endif

			p->removewq();
			p->removeq();
		}
	}

msgq	*newq=queuefree;

	if (!newq)
	{
		ctlfile_close(&ctlinfo);

		if (queuefill && nextqueuefill == 0)
		{
			nextqueuefill=current_time + queuefill;
		}
		return (1);
	}

	const char *cn=qmsgsctlname(inum);

	if ( stat(cn, &stat_buf) == -1 )
	{
		unlink(name.c_str());
		unlink(qmsgsdatname(inum));
		unlink(cn);
		ctlfile_close(&ctlinfo);
		return (0);
	}


#if 0
clog_msg_start_info();
clog_msg_str("Adding ");
clog_msg_uint(inum);
clog_msg_str(" to queue.");
clog_msg_send();
#endif

	queuefree=newq->next;
	++queuedelivering;

	ino_t	hashbucket=inum % queuehashfirst.size();

	if (queuehashfirst[hashbucket])
		queuehashfirst[hashbucket]->prevhash=newq;
	else
		queuehashlast[hashbucket]=newq;

	newq->nexthash=queuehashfirst[hashbucket];
	newq->prevhash=0;
	queuehashfirst[hashbucket]=newq;

	newq->nksize= (unsigned long)stat_buf.st_size;
	ctlinfo.starttime=stat_buf.st_mtime;

int	k=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_MSGID);

	newq->msgid= k < 0 ? "": ctlinfo.lines[k]+1;

	newq->msgnum=inum;
	newq->nextdel=deltime;
	newq->nextsenddel=delsendtime;
	newq->rcptinfo_list.resize(0);
	newq->rcptcount=0;
	newq->cancelled=ctlinfo.cancelled;

	if (isnewmsg)
	{
		int auth;

		clog_msg_start_info();
		clog_msg_str("newmsg,id=");
		logmsgid(newq);

		auth=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_AUTHNAME);

		if (auth >= 0)
		{
			clog_msg_str(", auth=");
			clog_msg_str(ctlinfo.lines[auth]+1);
		}

		int m=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_FROMMTA);

		if (m >= 0)
		{
			clog_msg_str(": ");
			clog_msg_str(ctlinfo.lines[m]+1);
		}

		clog_msg_send();
	}

	unsigned	i, j;
	std::string host, addr;

	k=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_SENDER);

	struct rfc822t *sendert=rw_rewrite_tokenize(k < 0 ? "":ctlinfo.lines[k]+1);
	std::string	errmsg;

	for (i=0; i<ctlinfo.nreceipients; i++)
	{
		for (j=0; ctlinfo.lines[j]; j++)
		{
			switch (ctlinfo.lines[j][0])	{
			case COMCTLFILE_DELSUCCESS:
			case COMCTLFILE_DELFAIL:
				if ((unsigned)atoi(ctlinfo.lines[j]+1) == i)
					break;
				// This one has been delivered
			default:
				continue;
			}
			break;
		}
		if (ctlinfo.lines[j])	continue;

	drvinfo *module=getdelinfo(sendert->tokens,
			ctlinfo.receipients[i], host, addr, errmsg);

		if (!module)
		{
			ctlfile_append_reply(&ctlinfo, i, errmsg.c_str(),
					     SMTPREPLY_TYPE(errmsg.c_str()),
					     0);
			continue;
		}

		/* Check if it's time to move the message to a backup relay */

		if (backup_relay_driver &&
			ctlfile_searchfirst(&ctlinfo, COMCTLFILE_WARNINGSENT)
			>= 0 &&
		    strcmp(module->module->name,
			   backup_relay_driver->module->name) == 0)
		{
			// module=backup_relay_driver;
			host=backup_relay;
		}

		/* Group all recipients for the same driver and host together */

		for (j=0; j<newq->rcptcount; j++)
			if (strcmp(module->module->name,
				   newq->rcptinfo_list[j].delmodule->
				   module->name) == 0 &&
			    newq->rcptinfo_list[j].delhost == host &&
			    newq->rcptinfo_list[j].addresses.size()
			    < module->maxrcpt )
				break;
		if (j == newq->rcptcount)
		{
#if 0
clog_msg_start_info();
clog_msg_str("id=");
logmsgid(newq);
clog_msg_str(",new rcpt list - module=");
clog_msg_str(module->module->name);
clog_msg_str(", host=");
clog_msg_str(host);
clog_msg_send();
#endif
			newq->rcptinfo_list.resize(++newq->rcptcount);

		struct	rw_info_rewrite rwir;
		struct	rw_info	rwi;

			rwir.buf=0;
			rwir.errmsg=0;
			rw_info_init(&rwi, sendert->tokens, rw_err_func);
			rwi.sender=0;
			rwi.mode=RW_OUTPUT|RW_ENVSENDER;
			rwi.udata= (void *)&rwir;
			rw_rewrite_module(module->module, &rwi,
				rw_rewrite_chksyn_print);

		char *address=((struct rw_info_rewrite *)rwi.udata)->buf;
		char *errmsg= ((struct rw_info_rewrite *)rwi.udata)->errmsg;

			if (!address)
			{
				ctlfile_append_reply(&ctlinfo, i, errmsg,
					SMTPREPLY_TYPE(errmsg), 0);
				newq->rcptinfo_list.resize(--newq->rcptcount);
				free(errmsg);
				continue;
			}

			if (errmsg)	free(errmsg);
			newq->rcptinfo_list[j].init(newq, module, host, address);
			free(address);
		}
#if 0
clog_msg_start_info();
clog_msg_str("id=");
logmsgid(newq);
clog_msg_str(",module=");
clog_msg_str(module->module->name);
clog_msg_str(", host=");
clog_msg_str(host);
clog_msg_str(", addr=<");
clog_msg_str(addr);
clog_msg_str(">");
clog_msg_send();
#endif

		newq->rcptinfo_list[j].addresses.push_back(addr);
		newq->rcptinfo_list[j].addressesidx.push_back(i);
	}
	rfc822t_free(sendert);
	ctlfile_close(&ctlinfo);

	if (newq->nextsenddel <= current_time ||

/*
** If there are no more recipients, we want to call done() via
** start_message.  HOWEVER, if DSN injection FAILED, we want to respect
** the rescheduled delivery attempt time.  We can detect that if isnewmsg == 0
*/
		(newq->rcptinfo_list.size() == 0 && isnewmsg))
	{
		newq->start_message();
		return (0);
	}

msgq	*qp, *qprev;

	for (qprev=queuetail, qp=0; qprev; qp=qprev, qprev=qp->prev)
		if (qprev->nextsenddel < newq->nextsenddel)
			break;

	newq->next=qp;
	newq->prev=qprev;

	if (qprev)	qprev->next=newq;
	else		queuehead=newq;

	if (qp)	qp->prev=newq;
	else	queuetail=newq;
	++queuewaiting;
	return (0);
}
Beispiel #10
0
void msgq::queuescan()
{
static	int queuescan_flag=0;

	if (queuescan_flag)	return;
		// Recursive invocation if message just pulled into queue
		// has been delivered to all of its recipients.

	nextqueuefill=0;

#if 0
clog_msg_start_info();
clog_msg_str("queue scan");
clog_msg_send();
#endif

	try
	{
		std::list<std::string> subdirlist;
		DIR *tmpdir=opendir(MSGQDIR);
		struct dirent *de;
		std::string	s;

		queuescan_flag=1;
		if (!tmpdir)	clog_msg_errno();

		time(&current_time);

		while ((de=readdir(tmpdir)) != 0)
		{
			const char *p;

			for (p=de->d_name; *p; p++)
				if (!isdigit((int)(unsigned char)*p))	break;

			if (*p)	continue;	// Subdirs must be named all digits

			p=de->d_name;
			time_t n=strtotime(p);

			std::list<std::string>::iterator sb, se;

			sb=subdirlist.begin();
			se=subdirlist.end();

			while (sb != se)
			{
				if (strtotime(sb->c_str()) > n)
					break;
				++sb;
			}

			subdirlist.insert(sb, de->d_name);
		}
		closedir(tmpdir);

		while (!subdirlist.empty())
		{
			s=MSGQDIR "/";
			s += subdirlist.front();
			subdirlist.pop_front();

			if (queuescan2(s) <= 0)	break;
				// Stop if we can't add any more msgs
		}
		queuescan_flag=0;
	}
	catch (...)
	{
		queuescan_flag=0;
		throw;
	}
}