Example #1
0
void qmsgunlink(ino_t n, time_t rightnow)
{
	const char *bigbrother=getenv("ARCHIVEDIR");

	if (bigbrother && *bigbrother)
	{
		struct tm *tmptr=localtime(&rightnow);

		/* Archive this message */

		if (tmptr)
		{
			const char *dname=qmsgsdatname(n);
			const char *tname=strrchr(dname, '/');

			char *p=courier_malloc(strlen(bigbrother)+
					       strlen(tname)+40);

			sprintf(p, "%s/%04d.%02d.%02d%s",
				bigbrother, tmptr->tm_year + 1900,
				tmptr->tm_mon+1,
				tmptr->tm_mday, tname);

			if (bigbrother_create_rename(dname, p) == 0)
			{
				dname=qmsgsctlname(n);

				strcpy(strrchr(p, '/'), strrchr(dname, '/'));

				if (rename(dname, p) == 0)
				{
					free(p);
					return;
				}
			}

			clog_msg_start_err();
			clog_msg_str("Unable to move ");
			clog_msg_str(dname);
			clog_msg_str(" to ");
			clog_msg_str(p);
			clog_msg_send();
			clog_msg_prerrno();

			free(p);
		}
	}

	unlink(qmsgsdatname(n));
	unlink(qmsgsctlname(n));
}
Example #2
0
static void fax(struct moduledel *p)
{
	struct	ctlfile ctf;
	unsigned nreceipients=p->nreceipients;
	const char *host=p->host;
	const char *receipient;
	unsigned nrecipient=(unsigned)atol(p->receipients[0]);
	int pipefd[2];
	pid_t child_proc;
	int faxopts;
	int n_cover_pages;
	FILE *fp;

	struct faxconv_err_args err_args;

	struct sort_file_list *page_list, *pp;


#if     HAVE_SETPGRP
#if     SETPGRP_VOID
        setpgrp();
#else
        setpgrp(0, 0);
#endif
#else
#if     HAVE_SETPGID
        setpgid(0, 0);
#endif
#endif

	if (comgetfaxopts(host, &faxopts))
	{
		clog_msg_start_err();
		clog_msg_str("courierfax: FATAL: invalid host");
		clog_msg_send();
		exit(1);
	}

	putenv(faxopts & FAX_LOWRES ? "FAXRES=lo":"FAXRES=hi");

	if (nreceipients != 1)
	{
		clog_msg_start_err();
		clog_msg_str("courierfax: FATAL: # receipients must be 1");
		clog_msg_send();
		exit(1);
	}

	receipient=p->receipients[1];
	nrecipient=(unsigned)atol(p->receipients[0]);

	if (ctlfile_openi(p->inum, &ctf, 0))
		clog_msg_errno();

	/* Convert message to fax format, use a child process */

	signal(SIGTERM, faxabort);

	if (pipe(pipefd) < 0)
	{
		clog_msg_errno();
	}

	child_proc=fork();
	if (child_proc < 0)
	{
		clog_msg_errno();
		return;
	}

	if (child_proc == 0)
	{
		const char *fn;

		close(0);
		if (open("/dev/null", O_RDONLY) != 0)
			clog_msg_errno();

		close(pipefd[0]);
		close(1);
		if (dup(pipefd[1]) != 1)
		{
			perror("dup");
			exit(1);
		}
		close(2);
		if (dup(pipefd[1]) != 2)
		{
			fprintf(stderr, "ERROR: dup failed\n");
			exit(1);
		}
		close(pipefd[1]);

		libmail_changeuidgid(MAILUID, MAILGID);

		fn=qmsgsdatname(p->inum);

		if (faxconvert(fn, faxopts, &n_cover_pages))
			exit (1);

		if ((fp=fopen(FAXTMPDIR "/.ncoverpages", "w")) == NULL ||
		    fprintf(fp, "%d\n", n_cover_pages) < 0 ||
		    fflush(fp) < 0)
			exit(1);
		fclose(fp);
		exit(0);
	}

	close(pipefd[1]);

	err_args.ctf= &ctf;
	err_args.nreceip=nrecipient;

	if (read_childerrmsg(child_proc, pipefd[0],
			     &faxconvert_cleanup, &err_args))
	{
		ctlfile_close(&ctf);
		return;
	}

	/* Hit it */

	if ((fp=fopen(FAXTMPDIR "/.ncoverpages", "r")) == NULL ||
	    fscanf(fp, "%d", &n_cover_pages) != 1)
	{
		if (fp)
			fclose(fp);

		ctlfile_append_reply(err_args.ctf,
				     err_args.nreceip,
				     "Internal error: cannot read number of cover pages",
				     COMCTLFILE_DELFAIL, 0);
		ctlfile_close(&ctf);
		exit(0);
	}

	page_list=read_dir_sort_filenames(FAXTMPDIR, FAXTMPDIR "/");

	if (!page_list)
	{
		clog_msg_start_err();
		clog_msg_str("courierfax: INTERNAL ERROR - no pages to xmit.");
		clog_msg_send();
		exit(1);
	}

	/* Keep trying until the modem line is unlocked */

	do
	{
		if (pipe(pipefd) < 0)
		{
			clog_msg_errno();
		}

		child_proc=fork();
		if (child_proc < 0)
		{
			clog_msg_errno();
			return;
		}

		if (child_proc == 0)
		{
			unsigned page_cnt=0;
			char **argvec;

			close(pipefd[0]);
			close(0);
			if (open("/dev/null", O_RDONLY) != 0)
			{
				perror("/dev/null");
				exit(1);
			}
			close(1);
			if (dup(pipefd[1]) != 1)
			{
				perror("dup");
				exit(1);
			}
			close(2);
			if (dup(pipefd[1]) != 2)
			{
				fprintf(stderr, "ERROR: dup failed\n");
				exit(1);
			}
			close(pipefd[1]);

			for (pp=page_list; pp; pp=pp->next)
				++page_cnt;

#if 0
			while (page_list)
			{
				unlink(page_list->filename);
				page_list=page_list->next;
			}

			exit(0);
#endif

			argvec=(char **)courier_malloc(sizeof(char *)*
						       (page_cnt+10));

			argvec[0]=SENDFAX;
			argvec[1]="-v";
			argvec[2]="-r";

			page_cnt=3;

			if (faxopts & FAX_LOWRES)
				argvec[page_cnt++]="-n";

			argvec[page_cnt++]=(char *)receipient;

			while (page_list)
			{
				argvec[page_cnt++]=page_list->filename;
				page_list=page_list->next;
			}
			argvec[page_cnt]=0;
			execv(SENDFAX, argvec);
			perror(SENDFAX);
			exit(1);
		}
		close(pipefd[1]);

		err_args.ctf= &ctf;
		err_args.nreceip=nrecipient;
		err_args.file_list=page_list;
		err_args.is_locked=0;
		err_args.n_cover_pages=n_cover_pages;

		if (read_childerrmsg(child_proc, pipefd[0],
				     &faxsend_cleanup, &err_args) == 0)
		{
			size_t npages=0;
			char fmtbuf[NUMBUFSIZE];
			char fmtbuf1[NUMBUFSIZE];
			char fmtbuf2[NUMBUFSIZE+100];

			for (pp=page_list; pp; pp=pp->next)
				++npages;

			libmail_str_size_t(npages, fmtbuf);
			libmail_str_size_t(n_cover_pages, fmtbuf1);

			sprintf(fmtbuf2,
				"%s pages - including %s cover page(s)"
				" - sent by fax.", fmtbuf, fmtbuf1);

			ctlfile_append_reply(&ctf, (unsigned)
					     nrecipient,
					     fmtbuf2,
					     COMCTLFILE_DELSUCCESS, " l");
			break;
		}
	} while (err_args.is_locked);

	ctlfile_close(&ctf);
	rmdir_contents(FAXTMPDIR);
}
Example #3
0
int main(int argc, char **argv)
{
struct moduledel *p;

	clog_open_syslog("courierlocal");

	if (chdir(courier_home=getenv("COURIER_HOME")))
		clog_msg_errno();

	if (atol(getenv("MAXRCPT")) > 1)
	{
		clog_msg_start_err();
		clog_msg_str("Invalid configuration in config, set MAXRCPT=1");
		clog_msg_send();
		exit(1);
	}

	module_init(0);

	module_delivery_timeout(config_readtime("localtimeout", 15*60));

	while ((p=module_getdel()) != NULL)
	{
	unsigned delid=atol(p->delid);
	unsigned rcptnum;
	struct ctlfile ctf;
	int	pipe1[2], pipe2[2];
	pid_t	pid;
	int datfd;
	struct stat stat_buf;

		pid=module_fork(delid, 0);
		if (pid < 0)
		{
			clog_msg_prerrno();
			module_completed(delid, delid);
			continue;
		}

		if (pid)	continue;

#if     HAVE_SETPGRP
#if     SETPGRP_VOID
		setpgrp();
#else
		setpgrp(0, 0);
#endif
#endif

		if (p->nreceipients != 1)
		{
			clog_msg_start_err();
			clog_msg_str("Invalid message from courierd.");
			clog_msg_send();
			_exit(0);
		}

		rcptnum=atol(p->receipients[0]);
		if (ctlfile_openi(p->inum, &ctf, 0))
		{
			clog_msg_errno();
			_exit(0);
		}

		if (pipe(pipe1) < 0 || pipe(pipe2) < 0
		    || (pid=fork()) < 0)
		{
			clog_msg_prerrno();
			ctlfile_append_reply(&ctf, rcptnum,
				"Can't run courierdeliver.",
				COMCTLFILE_DELDEFERRED, 0);
			ctlfile_close(&ctf);
			_exit(0);
			return (0);
		}

		if ((datfd=open(qmsgsdatname(p->inum), O_RDONLY)) < 0)
		{
			clog_msg_prerrno();
			ctlfile_append_reply(&ctf, rcptnum,
					     "Unable to read message file.",
					     COMCTLFILE_DELDEFERRED, 0);
			ctlfile_close(&ctf);
			_exit(0);
			return (0);
		}

		if (pid == 0)
		{
		const char *host, *homedir, *maildir, *quota;
		char	*buf, *s;

		char	*username, *ext;
		uid_t	u;
		gid_t	g;

			close(pipe1[0]);
			close(pipe2[0]);
			dup2(pipe2[1], 2);
			close(pipe2[1]);
			dup2(pipe1[1], 1);
			close(pipe1[1]);
			close(0);
			if (dup(datfd) != 0)
			{
				clog_msg_start_err();
				clog_msg_str("Unable to read message file.");
				clog_msg_send();
				_exit(EX_TEMPFAIL);
			}
			close(ctf.fd);
			close(datfd);

			/* Contents of host: */
			/* acct!ext!uid!gid!homedir!maildir!quota */

			host=p->host;

			buf=strdup(host);
			if (!buf)
			{
				clog_msg_prerrno();
				_exit(EX_TEMPFAIL);
			}

			s=strchr(buf, '!');
			username=buf;
			if (s)	*s++=0;
			ext=s;
			if (s)	s=strchr(s, '!');
			if (s)	*s++=0;

			u=0;
			while (s && *s != '!')
			{
				if (isdigit((int)(unsigned char)*s))
					u=u*10 + (*s - '0');
				++s;
			}
			if (s)	*s++=0;
			g=0;
			while (s && *s != '!')
			{
				if (isdigit((int)(unsigned char)*s))
					g=g*10 + (*s - '0');
				++s;
			}

			if (s)	*s++=0;

			homedir=s;

			if (s)	s=strchr(s, '!');
			if (s)	*s++=0;

			maildir=s;

			if (s)	s=strchr(s, '!');
			if (s)	*s++=0;

			quota=s;
			
			if (!s)
			{
				clog_msg_start_err();
				clog_msg_str("Invalid local recipient address.");
				clog_msg_send();
				_exit(EX_TEMPFAIL);
			}

			if (chdir(homedir))
			{
				clog_msg_str(homedir);
				clog_msg_str(": ");
				clog_msg_prerrno();
				_exit(EX_TEMPFAIL);
			}

			libmail_changeuidgid(u, g);

			execl( MODULEDIR "/local/courierdeliver",
				"courierdeliver",
				username,
				homedir,
				ext,
				ctf.receipients[rcptnum],
				verp_getsender(&ctf, ctf.receipients[rcptnum]),
				quota,
				maildir,
				(const char *)0);

			clog_msg_start_err();
			clog_msg_prerrno();
			clog_msg_send();
			_exit(EX_TEMPFAIL);
		}

		close(pipe1[1]);
		close(pipe2[1]);

		libmail_changeuidgid(MAILUID, MAILGID);
		if (fstat(datfd, &stat_buf) == 0)
			ctf.msgsize=stat_buf.st_size;

		close(datfd);
		wait_delivery(pid, &ctf, rcptnum, pipe2[0], pipe1[0],
				p->host, p->receipients[1]);
		ctlfile_close(&ctf);
		_exit(0);
	}
	return (0);
}
Example #4
0
static void wait_delivery(pid_t pid,
	struct ctlfile *ctf, unsigned rcptnum, int msgpipe, int fwdpipe,
	const char *user, const char *ext)
{
fd_set	fds;
int	maxfd= msgpipe > fwdpipe ? msgpipe:fwdpipe;
char	buf[BUFSIZ];
int	waitstat;
char	*sender=verp_getsender(ctf, ctf->receipients[rcptnum]);

const	char *oreceipient;
char	*oreceipients=0;

	if ( ctf->oreceipients[rcptnum] == 0 ||
			ctf->oreceipients[rcptnum][0])
	{
		oreceipient=ctf->oreceipients[rcptnum];
	}
	else
	{
		oreceipient=oreceipients=dsnencodeorigaddr(
			ctf->receipients[rcptnum]);
	}

	++maxfd;
	msglen=0;
	fwdlen=0;
	while (msgpipe >= 0 && fwdpipe >= 0)
	{
	int	l;

		FD_ZERO(&fds);
		if (msgpipe >= 0)
			FD_SET(msgpipe, &fds);
		if (fwdpipe >= 0)
			FD_SET(fwdpipe, &fds);

		if (select(maxfd, &fds, 0, 0, 0) < 0)
		{
			clog_msg_prerrno();
			continue;
		}

		if (msgpipe >= 0 && FD_ISSET(msgpipe, &fds))
		{
			if ( (l=read(msgpipe, buf, sizeof(buf))) <= 0)
			{
				close(msgpipe);
				msgpipe=-1;
			}
			else
				savemsg(buf, l);
		}
		if (fwdpipe >= 0 && FD_ISSET(fwdpipe, &fds))
		{
			if ( (l=read(fwdpipe, buf, sizeof(buf))) <= 0)
			{
				close(fwdpipe);
				fwdpipe=-1;
			}
			else
				fwdmsg(buf, l, sender,
					ctf->receipients[rcptnum],
					oreceipient);
		}
	}

	free(sender);
	while ( wait(&waitstat) != pid)
		;

	if (msglen)
	{
	char	*p, *q;

		msgbuf[msglen]=0;
		for (p=msgbuf; *p; )
		{
			for (q=p; *q; )
			{
				if (*q == '\n')
				{
					*q++=0;
					break;
				}
				q++;
			}
			ctlfile_append_info(ctf, rcptnum, p);
			p=q;
		}
	}

	if (submit_started && !submit_err)
	{
	FILE	*f=fopen(qmsgsdatname(ctf->n), "r");

		if (!f)
			submit_err=1;
		else
		{
		int	c;

			fprintf(submit_to, "\nDelivered-To: %s\n",
				ctf->receipients[rcptnum]);
			while ((c=getc(f)) != EOF)
				putc(c, submit_to);
			if (ferror(f) || fflush(submit_to) || fclose(submit_to))
			{
				submit_cancel();
				submit_err=1;
			}
			else if (submit_readrcprinterr())
			{
				submit_wait();
				submit_err=1;
			}
			else if (submit_wait())
				submit_err=1;
		}
	}

	if (WIFEXITED(waitstat))
		switch (WEXITSTATUS(waitstat))	{
		case 0:
		case 99:
			if (submit_err)
			{
				ctlfile_append_reply(ctf, rcptnum,
						     errbuf,
						     COMCTLFILE_DELFAIL, 0);
			}
			else
			{
				ctlfile_append_reply(ctf, rcptnum,
					"Message delivered.",
					COMCTLFILE_DELSUCCESS, " l");
			}
			if (oreceipients)
				free (oreceipients);
			return;
		case EX_SOFTWARE:
			ctlfile_append_reply(ctf, rcptnum,
					"", COMCTLFILE_DELFAIL_NOTRACK, 0);
			if (oreceipients)
				free (oreceipients);
			return;


		case 64:
		case 65:
		case 67:
		case 68:
		case 69:
		case 76:
		case 77:
		case 78:
		case 100:
		case 112:
			break;
		default:
			ctlfile_append_reply(ctf, rcptnum,
					"", COMCTLFILE_DELDEFERRED, 0);
			if (oreceipients)
				free (oreceipients);
			return;
		}

	ctlfile_append_reply(ctf, rcptnum, "", COMCTLFILE_DELFAIL, 0);
	if (oreceipients)
		free (oreceipients);
}
Example #5
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);
}
Example #6
0
int msgq::tmpscan()
{
	int	found=0;

	time(&current_time);

	DIR *tmpdir=opendir(TMPDIR);

	if (!tmpdir)	clog_msg_errno();

	struct dirent *de;
	std::string	subdir;
	std::string	ctlfile, datfile, newctlfile, newdatfile;
	struct	stat stat_buf;
	std::string	qdir, qname;

	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

		subdir=TMPDIR "/";
		subdir += de->d_name;

		DIR *subde=opendir(subdir.c_str());

		while ((de=readdir(subde)) != 0 && found < 100)
		{
			if (strcmp(de->d_name, ".") == 0 ||
				strcmp(de->d_name, "..") == 0)	continue;

			ctlfile=subdir;
			ctlfile += '/';
			ctlfile += de->d_name;

			int	i=-1;

			if (stat(ctlfile.c_str(), &stat_buf))	continue;

			size_t j=ctlfile.size();

			while (j)
			{
				if (ctlfile[--j] == '/')
					break;

				if (ctlfile[j] == '.')
				{
					i=j;
					break;
				}
			}

		ino_t	inum=stat_buf.st_ino;

		// Cleanup timeout. Should always be sufficiently longer than
		// the submit timeout set in submit.C via alarm_timeout.

			if (stat_buf.st_mtime < current_time - 48 * 60 * 60)
			{
				if (de->d_name[0] == 'D')
				{
					datfile=subdir + "/C" +
						(de->d_name+1);

					if (stat(datfile.c_str(), &stat_buf)
					    == 0)
						continue;
						// Wait until the C file is
						// purged

				// Be carefull with Cnnnn.x files, because
				// Cnnnn.1 is used to hold submission of all
				// of them.  A race condition can leave
				// Cnnnn.1 in a submittable state, so if it
				// is removed, other copies of this message
				// can become submittable, during a very small
				// window.

				} else if (de->d_name[0] == 'C' && i >= 0)
				{

				// This race condition is handled simply
				// by not removing Cxxxxx.n if Cxxxxx.n+1
				// exists.

					char	nbuf[NUMBUFSIZE];

					datfile=ctlfile.substr(0, i);

					size_t	n=atoi( ctlfile.c_str()+i+1);

					++n;

					datfile += '.';
					datfile += libmail_str_size_t(n, nbuf);

					if (stat(datfile.c_str(), &stat_buf)
					    == 0)
						continue;
						// Wait until the C.1 file is
						// purged

					unlink(ctlfile.c_str());

					ctlfile=subdir + "/D" +
						(de->d_name+1);
					/* FALLTHRU */
				}
				unlink(ctlfile.c_str());
				continue;
			}

			if (de->d_name[0] != 'C')	continue;
			if (i >= 0)
			{
				datfile=ctlfile.substr(0, i);
				datfile += ".1";

				if (ctlfile == datfile ||
				    stat(datfile.c_str(), &stat_buf) == 0)
					continue;
			}


			datfile=subdir + "/D" + (de->d_name+1);

			newdatfile=qmsgsdatname(inum);
			newctlfile=qmsgsctlname(inum);

			struct	ctlfile ctf;

			if ((access(datfile.c_str(), 0) == 0 &&
			     access(newdatfile.c_str(), 0) == 0) ||
			    access(newctlfile.c_str(), 0) == 0 ||
			    ctlfile_openfn(ctlfile.c_str(), &ctf, 0, 0))
			{
				clog_msg_start_err();
				clog_msg_str("QUEUE FILE CORRUPTION: inode ");
				clog_msg_uint(inum);
				clog_msg_send();
				utime(ctlfile.c_str(), 0);
				// Keep it around
				continue;
			}

		time_t	nextattempt=current_time+delaytime;

			if ((i=ctlfile_searchfirst(&ctf,
				COMCTLFILE_SUBMITDELAY)) >= 0)
				nextattempt=current_time+
					atoi(ctf.lines[i]+1);

			qname=qmsgqname(inum, nextattempt);

			ctlfile_nextattempt(&ctf, nextattempt);

			if (link(ctlfile.c_str(), qname.c_str()))
			{
				mkdir(qmsgqdir(current_time),0755);
				if (link(ctlfile.c_str(), qname.c_str())
				    && errno != EEXIST)
					clog_msg_errno();
			}

			if (rename(datfile.c_str(), newdatfile.c_str()))
			{
				mkdir(qmsgsdir(inum), 0755);
					// We may need to create this dir
				rename(datfile.c_str(), newdatfile.c_str());
			}

			if (rename(ctlfile.c_str(), newctlfile.c_str()))
				clog_msg_errno();

			for (i=qname.size(); i; )
			{
				if (qname[--i] == '/')
					break;
			}

			qdir=qname.substr(0, i);
			qname=qname.substr(i+1);
			++found;
			ctlfile_close(&ctf);

			queuescan3(qdir, qname, de->d_name);
		}
		closedir(subde);

		if (stat(subdir.c_str(), &stat_buf) == 0 &&
			stat_buf.st_mtime < current_time - 2 * 60 * 60)
			rmdir(subdir.c_str());	// Just give it a try
	}
	closedir(tmpdir);
	return (found);
}