DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T f

⟦85aa41bed⟧ TextFile

    Length: 16867 (0x41e3)
    Types: TextFile
    Names: »filtercont.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Chans/filtercontrol/filtercont.c« 

TextFile

/* filtercont.c: filter control channel */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/filtercontrol/RCS/filtercont.c,v 5.0 90/09/20 15:48:12 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/filtercontrol/RCS/filtercont.c,v 5.0 90/09/20 15:48:12 pp Exp Locker: pp $
 *
 * $Log:	filtercont.c,v $
 * Revision 5.0  90/09/20  15:48:12  pp
 * rcsforce : 5.0 public release
 * 
 */



#include "util.h"
#include "retcode.h"
#include "expand.h"
#include "qmgr.h"
#include "q.h"
#include "prm.h"
#include	<sys/stat.h>
#include	<sys/file.h>
#include	<sys/wait.h>
#include	<signal.h>

extern char	*mquedir;
extern char 	*quedfldir;
extern char	*formdfldir;
extern char	*logdfldir;
extern CHAN 	*ch_nm2struct();
extern char	*expand_dyn ();
extern void	err_abrt(), rd_end(), sys_init(), arg2vstr();
CHAN 		*mychan;
char		*this_msg = NULL, *this_chan = NULL;
char		*none_str = "none";

static struct type_Qmgr_DeliveryStatus *process ();
static int processMsg ();
static int doFormat ();
static int is_mychan_file ();
static int hdrinlist ();
static int in_BPT ();
static int file_create ();
static int do_child_logging ();
static int file_link ();
static int initialise ();
static int security_check ();
static void dirinit ();
static struct type_Qmgr_DeliveryStatus *new_DeliveryStatus();
static ADDR *getnthrecip ();
int	first_failureDR;
int	value;
char	*error, buf[BUFSIZ];

/* \f

 */
/* main routine */
 
main (argc, argv)
int 	argc;
char	**argv;
{
	sys_init(argv[0]);
	dirinit ();
#ifdef PP_DEBUG
	if (argc>1 && (strcmp(argv[1],"debug") == 0))
		debug_channel_control(argc,argv,initialise,process, NULLIFP);
	else
#endif
		channel_control (argc, argv, initialise, process, NULLIFP);
}

/* \f

 */
/* routine to move to correct place in file system */

static void dirinit ()
{
	if (chdir (quedfldir) < 0)
		err_abrt (RP_LIO, " Unable to change directory to '%s'",
			  quedfldir);
}

/* \f

 */
/* channel initialise routine */

static int initialise (arg)
struct type_Qmgr_Channel *arg;
{
	char *name;
	
	name = qb2str(arg);

	if ((mychan = ch_nm2struct(name)) == NULLCHAN) {
		PP_OPER(NULLCP, ("Chan/filtercont : Channel '%s' not known",name));
		if (name != NULL) free(name);
		return NOTOK;
	}

	(void) signal (SIGCHLD, SIG_DFL);
	/* check if a filter channel */
	if (name != NULL) free(name);
	return OK;
}

/* \f

 */
/* routine to check if allowed to filter this message through this channel */
static int security_check (msg)
struct type_Qmgr_ProcMsg *msg;
{
 	char 		*msg_file = NULL, *msg_chan = NULL;
	int		result;

	result = TRUE;
	msg_file = qb2str (msg->qid);	
	msg_chan = qb2str (msg->channel);

	if ((mychan == NULLCHAN) || (strcmp(msg_chan,mychan->ch_name) != 0)) {
		PP_LOG(LLOG_EXCEPTIONS,
		       ("Chans/fcontrol channel err: '%s'",msg_chan));
		result = FALSE;
	}

	/* free all storage used */
	if (msg_file != NULL) free(msg_file);
	if (msg_chan != NULL) free(msg_chan);
	return result;
}

/* \f

 */
/* routine called to do filter */

Expand expand_macros[] = {
	"sender", NULLCP,
	"822sender", NULLCP,
	"400sender", NULLCP,
	"qid", NULLCP,
	"ua-id", NULLCP,
	"p1-id", NULLCP,
	"recip", NULLCP,
	"822recip", NULLCP,
	"400recip", NULLCP,
	"table", NULLCP,
	"outmta", NULLCP,
	NULLCP, NULLCP};

static struct type_Qmgr_DeliveryStatus *process (arg)
struct type_Qmgr_ProcMsg *arg;
{
	struct prm_vars	prm;
	Q_struct	que;
	ADDR		*sender = NULL;
	ADDR		*recips = NULL;
	int 		rcount;
	struct type_Qmgr_UserList 	*ix;
	ADDR				*adr;

	bzero((char *) &que,sizeof(que));
	bzero((char *) &prm,sizeof(prm));

	delivery_init(arg->users);
	delivery_setall(int_Qmgr_status_messageFailure);
	first_failureDR = TRUE;

	if (security_check(arg) != TRUE)
		return deliverystate;

	if (this_msg != NULL) free(this_msg);
	if (this_chan != NULL) free(this_chan);

	this_msg = qb2str(arg->qid);
	this_chan = qb2str(arg->channel);

	PP_LOG(LLOG_NOTICE,
	       ("%s formatting msg '%s'",mychan->ch_name,this_msg));

	if (rp_isbad(rd_msg(this_msg,&prm,&que,&sender,&recips,&rcount))) {
		PP_LOG(LLOG_EXCEPTIONS,
		       ("%s rd_msg err: '%s'",mychan->ch_name,this_msg));
		rd_end();
		return delivery_setallstate(int_Qmgr_status_messageFailure,
					    "Can't read message");
	}

	expand_macros[0].expansion = que.Oaddress->ad_value;
	expand_macros[1].expansion = que.Oaddress->ad_r822adr;
	expand_macros[2].expansion = que.Oaddress->ad_r400adr;
	expand_macros[3].expansion = this_msg;
	expand_macros[4].expansion = que.ua_id;
	expand_macros[5].expansion = que.msgid.mpduid_string;
	if (mychan->ch_table != NULLTBL)
		expand_macros[9].expansion = mychan->ch_table->tb_name;
	else
		expand_macros[9].expansion = none_str;
	if (arg->users == NULL)
		PP_LOG(LLOG_NOTICE,
			("%s : passed a NULL user list for message '%s'",
			mychan->ch_name,
			this_msg));

	/* check each recipient for processing */
	for (ix = arg->users; ix; ix = ix->next) {
		error = NULLCP;
		if ((adr = getnthrecip(&que,ix->RecipientId->parm)) == NULL) {
			PP_LOG(LLOG_EXCEPTIONS,
			       ("%s : failed to find recipient %d of msg '%s'",mychan->ch_name,ix->RecipientId->parm, this_msg));
			delivery_setstate(ix->RecipientId->parm, 
					  int_Qmgr_status_messageFailure,
					  "Unable to find specified recipient");
			continue;
		}

		switch(chan_acheck (adr, mychan, 1, (char **)NULL)) {
		    case OK:
			expand_macros[6].expansion = adr -> ad_value;
			expand_macros[7].expansion = adr -> ad_r822adr;
			expand_macros[8].expansion = adr -> ad_r400adr;
			if (adr -> ad_outchan
			    && adr -> ad_outchan -> li_mta)
				expand_macros[10].expansion = adr -> ad_outchan -> li_mta;
			else 
				expand_macros[10].expansion = none_str;
			    
			value = int_Qmgr_status_messageFailure;
			if (processMsg(this_msg,adr) == NOTOK) {
				PP_LOG(LLOG_EXCEPTIONS,
				       ("%s : failed to process msg '%s' for recip '%d' on channel '%s'",mychan->ch_name,this_msg, adr->ad_no, this_chan));
				delivery_setstate(adr->ad_no, 
						  value,
						  (error == NULLCP) ? "Problems with filtering" : error);
			} else {
				/* CHANGE update adr->ad_rcnt in struct and in file */
				PP_LOG(LLOG_NOTICE,
					("%s : processed '%s' for recipient %d",mychan->ch_name,this_msg,adr->ad_no));
				adr->ad_rcnt++; 
				wr_ad_rcntno(adr,adr->ad_rcnt);
				delivery_set(adr->ad_no,int_Qmgr_status_success);
			}
			break;
		    default:
			break;
		}
		if (error != NULLCP)
			free(error);
	}
	rd_end();
	return deliverystate;
}

/* \f

 */
static int processMsg (msg,recip)
/* returns OK if managed to process msg for recip on mychan */
char	*msg;
ADDR 	*recip;
{
	char 	*origdir = NULL,
	        *newdir = NULL;
	int result = OK;
	struct stat statbuf;

	if (qid2dir(msg, recip, TRUE, &origdir) != OK) {
		PP_LOG(LLOG_EXCEPTIONS,
		       ("%s original directory not found for recipient %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
		error = strdup("Unable to find original directory");
		result = NOTOK;
	}
	
	/* temp change so as to get new directory name */
	recip->ad_rcnt++;
	if ((result == OK) 
	    && (qid2dir(msg, recip, FALSE, &newdir) != OK)) {
		PP_LOG(LLOG_EXCEPTIONS,
		       ("%s couldn't construct new directory for recipient '%d' of message '%s'",mychan->ch_name,recip->ad_no, msg));
		error = strdup ("Unable to construct new directory");
		result = NOTOK;
	}
	recip->ad_rcnt--;

	if ((result == OK) 
	    && (stat(newdir, &statbuf) == OK) 
	    && ((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
		/* directory already exists and so reformatting already done */
		PP_LOG(LLOG_NOTICE,
			("%s : work already done for recipient %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
		if (origdir != NULL) free(origdir);
		if (newdir != NULL) free(newdir);
		return OK;
	}

	if ((result == OK) && (doFormat(origdir,newdir,msg) != OK))
		result = NOTOK;

	if (origdir != NULL) free(origdir);
	if (newdir != NULL) free(newdir);
	return result;
}

/* \f

 */
static int doFormat (orig, new, msg)
/* reformats orig directory contents to new directory through mychan */
char	*orig,	/* original directory */
	*new,	/* new directory */
	*msg;	/* message */
{
	char	tmpdir[FILNSIZE],
		newfile[FILNSIZE],
		*stripped_file,
		*origfile,
		*subdir,
	        file[FILNSIZE];
	int	result = OK;	
	struct stat statbuf;
	(void) sprintf(tmpdir, "%s/%s/tmp.%s", 
		       mquedir, msg, mychan->ch_name);
	
	if (stat(tmpdir, &statbuf) == OK) {
		/* exists so remove it */
		char *cmdline = (char *) malloc((unsigned int) (strlen("rm -rf ") + strlen(tmpdir) +1));
		sprintf(cmdline, "rm -rf %s", tmpdir);
		system(cmdline);
		if (cmdline != NULL) free(cmdline);
	}

	if (mkdir(tmpdir, 0777) != OK) {
		PP_SLOG(LLOG_EXCEPTIONS, tmpdir,
		       ("Can't make directory"));
		(void) sprintf (buf,
				"Unable to make temporary directory '%s'",
				tmpdir);
		error = strdup(buf);
		result = NOTOK;
	}

	if (result == OK) {
		msg_rinit(orig);	
		if (msg_rfile(file) != RP_OK) {
			PP_LOG(LLOG_EXCEPTIONS,
				("%s empty or non exsistant dir %s",mychan->ch_name,orig));
			(void) sprintf (buf,
					"Original directory '%s' is empty",
					orig);
			error = strdup (buf);
			result = NOTOK;
		} else {
			do {
				stripped_file = file + strlen(orig) + 1;
				sprintf(newfile,"%s/%s",tmpdir, stripped_file);
				stripped_file = newfile + strlen(tmpdir) +1;
				/* stripped file now local to tmpdir */
				origfile = rindex(file,'/');
				*origfile = '\0';
				while ((result == OK) 
					&& ((subdir = index(stripped_file,'/')) != NULL)){
					/* check intervening directories */
					*subdir = '\0';
					if (!((stat(newfile, &statbuf) == OK)
						&& ((statbuf.st_mode & S_IFMT) == S_IFDIR))) {
						/* sub dir not there so mkdir */
						if (mkdir(newfile, 0777) != OK) {
							PP_SLOG(LLOG_EXCEPTIONS,
								newfile,
								("Can't make directory"));
							(void) sprintf (buf,
									"Failed to make directory '%s'",
									newfile);
							error = strdup(buf);
							result = NOTOK;
						} else
							PP_TRACE(("%s : made directory %s",mychan->ch_name,newfile));
							
						}
					*subdir = '/';
					stripped_file = subdir+1;
				}
				if ( result == OK) {	
					
					subdir = rindex(newfile,'/');
					*subdir = '\0';
					if (is_mychan_file(stripped_file) == TRUE)
						result = file_create(file,newfile,stripped_file);
					else
						result = file_link(file,newfile,stripped_file);
					*subdir = '/';
			}
			*origfile = '/';
			} while ((result == OK) && (msg_rfile(file) == RP_OK)) ;

		}
		msg_rend();

		if ((result == OK) && (rename(tmpdir, new) == -1)) {
			PP_SLOG(LLOG_EXCEPTIONS, "rename",
				("Can't rename directory '%s' to '%s'",
				tmpdir, new));
			(void) sprintf (buf,
					"Failed to rename %s to %s",
					tmpdir, new);
			error = strdup (buf);
			result = NOTOK;
		}
	}

	return result;
}

static int is_mychan_file(name)
char	*name;
{
	char	*suffix;
	if (hdrinlist(mychan->ch_bpt_in) 
		&& (strncmp(name,"hdr.",4) == 0))
		return TRUE;
	if ((suffix = index(name,'.')) == NULL)
		return FALSE;
	return in_BPT(++suffix,mychan->ch_bpt_in);
}

static int hdrinlist(list)
LIST_BPT	*list;
{
	LIST_BPT *ix = list;

	while ((ix != NULL) 
	       && (strncmp(ix->li_name,"hdr.",4) != 0))
		ix = ix->li_next;
	return (ix == NULL) ? FALSE : TRUE;
}

static int in_BPT(suffix, list)
char 		*suffix;
LIST_BPT	*list;
{
	LIST_BPT *ix = list;

	while ((ix != NULL) 
	       && (strcmp(suffix,ix->li_name) != 0))
		ix = ix->li_next;
	return (ix == NULL) ? FALSE : TRUE;
}

/* \f

 */
static int file_create (orig, tmp, file)
char	*orig,	/* original message directory */
	*tmp, /* where to put new file */
	*file;	/* file to format */
{
	char	filein[FILNSIZE], /* input file */
	fileout[FILNSIZE],	/* output file */
	*name = NULL,		/* base name of file */
	*program = NULL,	/* full name of exec'd program */
	*ix,
	*info_copy,
	*expanded = NULL,
	*margv[100];
	int	fd_in,		/* input file id */
	fd_out,			/* output file id */
	fd_sterr[2],		/* stderr pipe */
	pid,			/* child process id */
	pgmresult,
	margc,
	i, total_len,
	result = OK;
	struct stat statbuf;
	
	(void) sprintf(filein, "%s/%s",orig,file);

	if (strncmp(mychan->ch_bpt_out->li_name,"hdr.",4) == 0) {
		(void) sprintf(fileout, "%s/%s",tmp,mychan->ch_bpt_out->li_name);
	} else {
		name = strdup(file);
		ix = index(name,'.');
		*ix = '\0';

		(void) sprintf(fileout, "%s/%s.%s",
			       tmp,name,mychan->ch_bpt_out->li_name);
	}

	if ((fd_in = open(filein, O_RDONLY, 0666)) == -1) {
		PP_SLOG(LLOG_EXCEPTIONS, filein,
		       ("Can't open file"));
		(void) sprintf(buf,
			       "Unable to open input file '%s'",
			       filein);
		error = strdup(buf);
		return NOTOK;
	}
	if ((fd_out = open(fileout, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
		PP_SLOG(LLOG_EXCEPTIONS, fileout,
		       ("Can't open file"));
		(void) sprintf(buf,
			       "Unable to open output file '%s'",
			       fileout);
		error = strdup(buf);
		return NOTOK;
	}
	if (pipe(fd_sterr) != 0) {
		PP_SLOG(LLOG_EXCEPTIONS, "pipe",
		       ("Can't pipe standard err"));
		error = strdup("Failed to pipe standard error");
		return NOTOK;
	}
		       
	/* get program name */
	if (mychan->ch_info == NULL) {
		PP_OPER(NULLCP,
			("%s cannot find channel info",mychan->ch_name));
		value = int_Qmgr_status_mtaFailure;
		error = strdup("No channel info associated with channel");
		return NOTOK;
	}
	info_copy = strdup (mychan -> ch_info);
	if ((margc = sstr2arg(info_copy, 100, margv, " \t")) < 1) {
		PP_OPER(NULLCP,
			("%s : no arguments in ch_info string",
			 mychan->ch_name));
		value = int_Qmgr_status_mtaFailure;
		(void) sprintf(buf,
			       "No arguments in info string '%s'",
			       mychan -> ch_info);
		error = strdup(buf);
		return NOTOK;
	}
	if (margv[0][0] == '/')
		/* given full path name */
		program = strdup(margv[0]);
	else {
		program = (char *) malloc((unsigned int)
					  (strlen(formdfldir) + 1 +
					   strlen(margv[0]) + 1));
		sprintf(program,"%s/%s",formdfldir,margv[0]);
	}
	
	if (stat(program, &statbuf) != OK) {
		PP_OPER(NULLCP,
			("%s : missing filter '%s'",mychan -> ch_name, program));
		value = int_Qmgr_status_mtaFailure;
		(void) sprintf (buf,
				"Missing filter '%s'",
				program);
		error = strdup(buf);
		return NOTOK;
	}

	total_len = 0;
	for (i = 0; i < margc; i++) {
		if (index (margv[i], '$')) 
			margv[i] = expand_dyn (margv[i],
					   expand_macros);
		else
			margv[i] = strdup (margv[i]);
		total_len += strlen(margv[i]) + 3;
		/* +3 for intervening space and possible quotes */
	}
	total_len += 10;
	/* just in case */

	expanded = malloc((unsigned)(total_len * sizeof(char)));
	arg2vstr (0, total_len, expanded, margv);
	if ((ix = index (expanded, ' ')) == NULLCP)
		ix = expanded;
	PP_NOTICE (("%s %s < %s > %s", program, ix,
		    filein, fileout));
		
#ifdef BSD42
	if ((pid = vfork ()) == 0) {
#else
	if ((pid = tryfork()) == 0) {
#endif
		/* in child so redirect in- and out-put */
		dup2 (fd_in, 0);
		dup2 (fd_out, 1);
		dup2 (fd_sterr[1], 2);
		close(fd_in);
		close(fd_out);
		close(fd_sterr[0]);
		close(fd_sterr[1]);

		execv(program,margv);
		_exit (1);
	} else if (pid == -1) {
		PP_SLOG(LLOG_EXCEPTIONS, this_msg,
		       ("tryfork failed"));
		error = strdup("Tryfork tailed");
		result = NOTOK;
	} else {
		union wait w;

		while ((pgmresult = wait(&w)) != pid && pgmresult != -1)
			PP_TRACE(("process %d returned", pgmresult));

		if ((pgmresult == pid) && !WIFSIGNALED(w) &&
		    w.w_retcode == 0)
			result = OK;
		else 
			result = NOTOK;
	}
	close(fd_sterr[1]);
	do_child_logging(fd_sterr[0]);
 	close(fd_in);
	close(fd_out);
	if (program != NULL) free(program);

	for (i = 0; i < margc; i++) 
		free(margv[i]);
	if (expanded) free(expanded);
	free (info_copy);

	return result;
}

static int do_child_logging(ifd)
int	ifd;
{
	/* log stuff child puts out on stderr */
	char	line[LINESIZE];
	int	len;
	FILE	*fd = fdopen(ifd, "r");

	while (fgets(line, LINESIZE, fd) != NULL) {
		len = strlen(line);
		if (line[len-1] == '\n')
			line[len-1] = '\0';
		PP_LOG(LLOG_NOTICE,
		       ("%s : %s",mychan->ch_name,line));
	}
	fclose(fd);
}

static int file_link(orig,tmp,file)
char	*orig,	/* original message directory */
	*tmp,	/* new temporary directory */
	*file;	/* file to link across */
{
	char	old[FILNSIZE],	/* old file */
	        new[FILNSIZE];	/* new link */
	struct stat statbuf;
	int	result = OK;

	(void) sprintf(old, "%s/%s",orig,file);

	(void) sprintf(new, "%s/%s",tmp,file);

	if ((stat(old, &statbuf) == OK)
	    && (stat(new, &statbuf) != OK)
	    && (link(old, new) != -1)) {
		result = OK;
	} else {
		(void) sprintf(buf,
			       "Failed to link '%s' to '%s'",
			       new, old);
		error = strdup(buf);
		result = NOTOK;
	}

	return result;
}
		
static ADDR *getnthrecip(que, num)
Q_struct	*que;
int		num;
{
	ADDR *ix = que->Raddress;
	int icount = 1;
	if (num == 0)
		return que->Oaddress;
	while ((ix != NULL) && (icount++ < num))
		ix = ix->ad_next;
	return ix;
}