Ejemplo n.º 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));
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
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);
}