[comp.mail.misc] ListServer software under Unix

QQ11@LIVERPOOL.AC.UK (10/06/90)

In article <1990Oct1.214010.4218@maths.tcd.ie>, tim@maths.tcd.ie (Timothy
Murphy) says:
>
>I wonder if someone could point me to software
>to run an archive or list server under Unix.
>I promised to set up such a thing on our Sun SparcStation,
>and now am being pressed to keep my word!
There are UK sites which run info-servers which may do what you want.
I found the following in the anonymous ftp site list:

elroy.cs.iastate.edu               129.186.3.15    mail servers

This may or may not be any use...

Alan Thew
University of Liverpool Computer Laboratory
Bitnet/Earn: QQ11@LIVERPOOL.AC.UK or QQ11%UK.AC.LIVERPOOL @ UKACRL
UUCP       : ....!mcsun!ukc!liv!qq11        Voice: +44 51 794 3735
Internet   : QQ11@LIVERPOOL.AC.UK or QQ11%LIVERPOOL.AC.UK @ NSFNET-RELAY.AC.UK

tim@maths.tcd.ie (Timothy Murphy) (10/14/90)

In <90278.183340QQ11@LIVERPOOL.AC.UK> QQ11@LIVERPOOL.AC.UK writes:

>In article <1990Oct1.214010.4218@maths.tcd.ie>, tim@maths.tcd.ie (Timothy
>Murphy) says:
>>
>>I wonder if someone could point me to software
>>to run an archive or list server under Unix.

>There are UK sites which run info-servers which may do what you want.
>I found the following in the anonymous ftp site list:

>elroy.cs.iastate.edu               129.186.3.15    mail servers

>This may or may not be any use...

Thanks.
I did in fact try the mail-server at this address
(csdserv@cs.iostate.edu) as described by Dave Shaver
(shaver@elroy.cs.iostate.edu) but had no luck --
the user was unknown at the given address.
Maybe someone can point out the correct user/address.

Nelson Beebe (of TeX and Plot79 fame) kindly sent me
the following list-server software.
I'm posting it 'as-is',
since while I compiled it without problem on a Sun SparcStation,
it did not in fact do what I wanted,
which is perhaps better described as an archive-server --
that is, to reply to appropriate e-mail requests
by mailing back files.

I'm posting the list-server from Beebe
because I received many requests for it,
a couple of whom suggested I should post it.
Incidentally, I don't think Nelson Beebe uses it for his TeX archive --
that runs on an IBM, using the usual LISTSERV software, I believe.

I think this list-server could easily be modified to do
what I want.
If I don't get an appropriate program from Iowa (iostate, as above),
I'll try that.
But there are some 6 list-server programs available at iostate
so hopefully at least one of these will do the trick:


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile commands.c listserv.h main.c str.c subscribe.c
# Wrapped by tim@lanczos on Sat Oct 13 19:14:54 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(473 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XRM = rm -f
X
XCFLAGS = -g
X
Xall:	listserv
X
Xinstall:	all
X	install -c -m 2711 -g mail listserv /usr/mail
X
Xlistserv:	main.o commands.o subscribe.o str.o
X	cc -O -o listserv main.o commands.o subscribe.o str.o
X
Xmain.o:	main.c listserv.h
X	cc -c $(CFLAGS) main.c
X
Xcommands.o:	commands.c listserv.h
X	cc -c $(CFLAGS) commands.c
X
Xsubscribe.o:	subscribe.c listserv.h
X	cc -c $(CFLAGS) subscribe.c
X
Xstr.o:	str.c
X	cc -c $(CFLAGS) str.c
X
Xclean:
X	$(RM) *.o
X
Xveryclean:	clean
X	$(RM) listserv
X
END_OF_FILE
if test 473 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'commands.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'commands.c'\"
else
echo shar: Extracting \"'commands.c'\" \(1638 characters\)
sed "s/^X//" >'commands.c' <<'END_OF_FILE'
X#include "listserv.h"
X
Xextern FILE *msg;
Xextern FILE *mailer;
X
Xsendhelp(from,request)
Xchar *from, *request;
X	{
X	printf("called sendhelp with %s %s\n", from, request);
X	callmailer("", from, request);
X	mailcat(HELPFILE,"");
X	pclose(mailer);
X	return;
X	}
X
Xlisthelp(from,grp,request)
Xchar *from,*grp,*request;
X	{
X	char tmp[128];
X	printf("called listhelp with %s %s %s\n", from,grp,request);
X
X	sprintf(tmp,"%s/%s.info", SERVDIR, grp);
X	if (access(tmp,R_OK) != 0)
X		{
X		callmailer("", from, request);
X		fprintf(mailer,"The mailing list \"%s\" could not be found.\n",
X			grp);
X		fprintf(mailer,"You may use the INDEX command to get a listing\n");
X		fprintf(mailer,"of available mailing lists.\n");
X		fflush(mailer);
X		pclose(mailer);
X		return;
X		}
X
X	callmailer("", from, request);
X	fprintf(mailer,"Mailing list \"%s\":\n", grp);
X	mailcat(tmp,"\t");
X	pclose(mailer);
X	return;
X	}
X
Xsendindex(from,request,l)
Xchar *from,*request;
Xint l;
X	{
X	FILE *ls;
X	char tmp[128];
X	char buf[128];
X	int i;
X	printf("called sendindex with %s %s %d\n", from,request,l);
X
X	sprintf(tmp,"cd %s; ls *.info | sed -e 's/.info//", SERVDIR);
X	ls = popen(tmp,"r");
X	if (ls == NULL)
X		{
X		perror(tmp);
X		exit(1);
X		}
X	callmailer("", from, request);
X	fprintf(mailer,"Index of mailing lists\n");
X
X	/* read the result of the ls */
X	while (fgets(tmp, sizeof(tmp), ls))
X		{
X		while (tmp[(i=strlen(tmp)-1)] == '\n')
X			tmp[i] = '\0';
X		fprintf(mailer, "%s\n", tmp);
X
X		/* if he wanted the long listing, cat the .info file */
X		if (l)
X			{
X			sprintf(buf, "%s/%s.info", SERVDIR, tmp);
X			mailcat(buf,"\t");
X			fprintf(mailer, "\n");
X			}
X		}
X	pclose(ls);
X	pclose(mailer);
X	return;
X	}
X
END_OF_FILE
if test 1638 -ne `wc -c <'commands.c'`; then
    echo shar: \"'commands.c'\" unpacked with wrong size!
fi
# end of 'commands.c'
fi
if test -f 'listserv.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'listserv.h'\"
else
echo shar: Extracting \"'listserv.h'\" \(236 characters\)
sed "s/^X//" >'listserv.h' <<'END_OF_FILE'
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X#include <sys/file.h>
X
X#define MAILER	"/usr/lib/sendmail"
X#define HELPFILE	"/usr/mail/maillists/HELP"
X#define SERVDIR	"/usr/mail/maillists"
X#define LOGFILE	"/var/log/listserv"
X
END_OF_FILE
if test 236 -ne `wc -c <'listserv.h'`; then
    echo shar: \"'listserv.h'\" unpacked with wrong size!
fi
# end of 'listserv.h'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(4607 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X#include "listserv.h"
X
XFILE *mailer;
XFILE *logfile;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X	{
X	char from[256];
X	char buf[BUFSIZ];
X	char grp[64];
X	char dat[64];
X	char *p;
X	int i;
X	int gotcommand = 0;
X	int inheader;
X
X	/* gotta have some default if the From: line is missing */
X	strcpy(from, "Postmaster");
X
X	inheader = 1;
X	while (fgets(buf,BUFSIZ,stdin) != NULL)
X		{
X		/* drop trailing newline */
X		while (buf[(i=strlen(buf)-1)] == '\n')
X			buf[i] = '\0';
X
X		/* drop trailing blanks */
X		p = buf + (strlen(buf) - 1);
X		while (p && *p && p >= buf && isspace(*p))
X			*p-- = '\0';
X
X		/* deblank beginning of line */
X		p = buf;
X		while (p && *p && isspace(*p))
X			p++;
X		if (p != buf)
X			strcpy(buf, p);
X
X		if (strlen(buf) == 0)	/* blank line ends header */
X			{
X			inheader = 0;
X			continue;
X			}
X		
X		/*
X		get the From: line so we can return the answer
X
X		Note that we DON'T check that we're in the header when
X		picking up the From: line; that's so that we'll take the
X		last from line we encounter which makes it handle
X		forwarded messages correctly.
X		*/
X		if (strncasecmp(buf,"From: ",6) == 0)
X			{
X			strcpy(from, &buf[6]);
X			cleanup(from);
X			continue;
X			}
X		
X		/* 
X		don't look for commands in the header 
X		*/
X		if (inheader)
X			continue;
X		
X		/* avoid mail loops - ignore requests from ourself! */
X		if (!strncasecmp(from, "listserv", 8))
X			{
X			printf("I refuse to talk to myself.\n");
X			exit(0);
X			}
X
X		/* force to lower case and scan for commands */
X		p = buf;
X		while (p && *p)
X			{
X			if (isupper(*p))
X				*p = tolower(*p);
X			p++;
X			}
X		
X		/* log the request */
X		logfile = fopen(LOGFILE,"a");
X		if (logfile != NULL)
X			{
X			long clock = time(0);
X			strcpy(dat,ctime(&clock));
X			/* drop trailing newline */
X			while (dat[(i=strlen(dat)-1)] == '\n')
X				dat[i] = '\0';
X			printf("logfile: %s|%s|%s\n", dat, from, buf);
X			fprintf(logfile,"%s|%s|%s\n", dat, from, buf);
X			fflush(logfile);
X			fclose(logfile);
X			}
X		else
X			perror(LOGFILE);
X		
X		if (!strncasecmp(buf,"add ", 4)
X		|| !strncasecmp(buf,"subscribe ", 10))
X			{
X			gotcommand++;
X			subscription(from,buf,1);
X			continue;
X			}
X		
X		if (!strncasecmp(buf,"delete ", 7)
X		|| !strncasecmp(buf,"unsubscribe ", 12))
X			{
X			gotcommand++;
X			subscription(from,buf,0);
X			continue;
X			}
X		
X		if (!strcasecmp(buf,"index")
X		|| !strcasecmp(buf,"longindex"))
X			{
X			gotcommand++;
X			sendindex(from,buf,!strcasecmp(buf,"longindex"));
X			continue;
X			}
X		
X		if (!strcasecmp(buf,"help"))
X			{
X			gotcommand++;
X			sendhelp(from,buf);
X			continue;
X			}
X		
X		if (!strncasecmp(buf,"help ",5))
X			{
X			gotcommand++;
X			sscanf(buf,"%*s%s", grp);
X			listhelp(from,grp,buf);
X			continue;
X			}
X		}
X	if (gotcommand == 0)
X		sendhelp(from, "indecipherable");
X	}
X
Xcallmailer(redirect, toaddr, request)
Xchar *redirect, *toaddr, *request;
X	{
X	char cbuf[BUFSIZ];
X
X	printf("callmailer \"%s\",\"%s\",\"%s\"\n", redirect, toaddr, request);
X
X	strcpy(cbuf, MAILER);
X	strcat(cbuf, " -fPostmaster@ucsd.edu");
X	strcat(cbuf, " -F\"Mailing List Processor\"");
X	strcat(cbuf, " -t -oi"); 
X	strcat(cbuf, " "); strcat(cbuf, redirect);
X	mailer = popen(cbuf,"w");
X	printf("mailer popen '%s'\n", cbuf);
X	if (mailer == NULL)
X		{
X		perror(cbuf);
X		exit(1);
X		}
X	fprintf(mailer,"From: postmaster@ucsd.edu (Mailing List Processor)\n");
X	fprintf(mailer,"To: %s\n", toaddr);
X	fprintf(mailer,"Subject: Re: your LISTSERVE request \"%s\"\n", request);
X	fprintf(mailer,"\n");
X	}
X
Xmailcat(mfname,prefix)
Xchar *mfname, *prefix;
X	{
X	FILE *mf;
X	char buf[BUFSIZ];
X
X	printf("mailcat \"%s\", \"%s\"\n", mfname, prefix);
X
X	mf = fopen(mfname,"r");
X	if (mf == NULL)
X		{
X		perror(mfname);
X		fprintf(mailer,"This should have been the contents of\n");
X		fprintf(mailer,"file '%s' but it's missing!\n",mfname);
X		return;
X		}
X
X	/* copy the message file into the mailer */
X	while (fgets(buf,BUFSIZ,mf) != NULL)
X		{
X		fputs(prefix,mailer);
X		fputs(buf,mailer);
X		}
X	fclose(mf);
X	return;
X	}
X
Xcleanup(from)
Xchar *from;
X	{
X	char *p, *q;
X
X	printf("cleanup \"%s\"\n", from);
X
X	while (p = index(from,'~'))
X		*p = 'X';
X
X	while (p = index(from,'/'))
X		*p = 'X';
X
X	while (p = index(from,'|'))
X		*p = 'X';
X
X	/* elide stuff in parenthesis */
X	if (p = index(from,'('))
X		{
X		if ( (q=index(from,')')) == NULL)
X			{
X			/* zap the from line; it's invalid */
X			*p = '\0';
X			return;
X			}
X		strcpy(p, q+1);
X		}
X
X	if (p = index(from,'<'))
X		{
X		if ( (q=index(from,'>')) == NULL)
X			{
X			/* zap the from line; it's invalid */
X			*p = '\0';
X			return;
X			}
X		*q = '\0';
X		strcpy(from, p+1);
X		}
X
X	/* drop trailing blanks */
X	p = from + (strlen(from) - 1);
X	while (p && *p && p >= from && isspace(*p))
X		*p-- = '\0';
X	}
END_OF_FILE
if test 4607 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'str.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'str.c'\"
else
echo shar: Extracting \"'str.c'\" \(487 characters\)
sed "s/^X//" >'str.c' <<'END_OF_FILE'
X#include <ctype.h>
X
Xstrcasecmp(a,b)
Xchar *a, *b;
X	{
X	char *p;
X	p = a;
X	while (p && *p)
X		{
X		if (isupper(*p))
X			*p = tolower(*p);
X		p++;
X		}
X	p = b;
X	while (p && *p)
X		{
X		if (isupper(*p))
X			*p = tolower(*p);
X		p++;
X		}
X	return(strcmp(a,b));
X	}
Xstrncasecmp(a,b,n)
Xchar *a, *b;
Xint n;
X	{
X	char *p;
X	p = a;
X	while (p && *p)
X		{
X		if (isupper(*p))
X			*p = tolower(*p);
X		p++;
X		}
X	p = b;
X	while (p && *p)
X		{
X		if (isupper(*p))
X			*p = tolower(*p);
X		p++;
X		}
X	return(strncmp(a,b,n));
X	}
END_OF_FILE
if test 487 -ne `wc -c <'str.c'`; then
    echo shar: \"'str.c'\" unpacked with wrong size!
fi
# end of 'str.c'
fi
if test -f 'subscribe.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'subscribe.c'\"
else
echo shar: Extracting \"'subscribe.c'\" \(3479 characters\)
sed "s/^X//" >'subscribe.c' <<'END_OF_FILE'
X#include "listserv.h"
X
Xextern FILE *msg;
Xextern FILE *mailer;
X
Xsubscription(from,command,add)
Xchar *from,*command;
Xint add;
X	{
X	FILE *list;
X	FILE *listtmp;
X	char grp[256];
X	char adr[256];
X	char tmp[256];
X	char buf[BUFSIZ];
X	int del = 0;
X	int i;
X
X	printf("subscription %s %s %d\n", from, command, add);
X
X	i = sscanf(command,"%s%s%s", tmp, adr, grp);
X	if (i < 2 || i > 3)
X		{
X		callmailer("", from, command);
X		fprintf(mailer,"Your command\n");
X		fprintf(mailer,"\t%s\n", command);
X		fprintf(mailer,"could not be understood.  Correct syntax is\n");
X		fprintf(mailer,"\tADD listname\n");
X		fprintf(mailer,"\tADD mailbox listname\n");
X		fprintf(mailer,"\tDELETE listname\n");
X		fprintf(mailer,"\tDELETE mailbox listname\n");
X		fflush(mailer);
X		pclose(mailer);
X		return(-1);
X		}
X
X	if (i == 2)
X		{
X		strcpy(grp, adr);
X		strcpy(adr, from);
X		}
X	
X	cleanup(grp);
X	cleanup(adr);
X
X	sprintf(tmp,"%s/%s.info", SERVDIR, grp);
X	if (access(tmp,R_OK) != 0)
X		{
X		callmailer("", from, "");
X		fprintf(mailer,"The mailing list \"%s\" could not be found.\n",
X			grp);
X		fprintf(mailer,"You may use the INDEX command to get a listing\n");
X		fprintf(mailer,"of available mailing lists.\n");
X		fflush(mailer);
X		pclose(mailer);
X		return(-1);
X		}
X
X	strcpy(tmp, SERVDIR);
X	strcat(tmp, "/");
X	strcat(tmp, grp);
X	if (add)
X		{
X		list = fopen(tmp, "a");
X		if (list == NULL)
X			{
X			callmailer("Postmaster", from, "");
X			fprintf(mailer,"Error[1] processing request. Please try later.\n");
X			fprintf(mailer,">%s\n", command);
X			fflush(mailer);
X			pclose(mailer);
X			return(-1);
X			}
X		flock(fileno(list), LOCK_EX);
X		fprintf(list, "%s\n", adr);
X		fflush(list);
X		flock(fileno(list), LOCK_UN);
X		fclose(list);
X		}
X	else
X		{
X		del = 0;
X		list = fopen(tmp, "r");
X		if (list == NULL)
X			{
X			callmailer("Postmaster", from, "");
X			fprintf(mailer,"Error[2] processing request. Please try later.\n");
X			fprintf(mailer,">%s\n", command);
X			fflush(mailer);
X			pclose(mailer);
X			return(-1);
X			}
X		flock(fileno(list), LOCK_EX);
X		fprintf(list, "%s\n", adr);
X
X		strcpy(tmp, SERVDIR);
X		strcat(tmp, "/");
X		strcat(tmp, grp);
X		strcat(tmp, ".tmp");
X		listtmp = fopen(tmp, "w");
X		if (listtmp == NULL)
X			{
X			callmailer("Postmaster", from, "");
X			fprintf(mailer,"Error[3] processing request. Please try later.\n");
X			fprintf(mailer,">%s\n", command);
X			fflush(mailer);
X			pclose(mailer);
X			return(-1);
X			}
X		/* copy the list, omitting the one address */
X		while (fgets(buf, sizeof(buf), list))
X			{
X			buf[strlen(buf)-1] = '\0';
X			if (strcasecmp(buf, adr))
X				{
X				fputs(buf, listtmp);
X				fputs("\n", listtmp);
X				}
X			else
X				del++;
X			}
X		fflush(listtmp);
X		fclose(listtmp);
X
X		/* replace the old list with the shortened one */
X		strcpy(buf, SERVDIR);
X		strcat(buf, "/");
X		strcat(buf, grp);
X		unlink(buf);	/* delete original file */
X		rename(tmp, buf);	/* put updated one in place */
X		flock(fileno(list), LOCK_UN);	/* release lock */
X		}
X
X	if (strcmp(from, adr))
X		{
X		callmailer(adr, from, command);
X		fprintf(mailer,"Per request by %s\n", from);
X		}
X	else
X		{
X		callmailer("", from, command);
X		fprintf(mailer,"Per your request\n");
X		}
X	fprintf(mailer,"\t\"%s\"\n", command);
X	if (add)
X		fprintf(mailer,"'%s' was ADDED to the '%s' mailing list.\n",
X			adr, grp);
X	else
X		if (del)
X			fprintf(mailer,
X			"'%s' was DELETED from the '%s' mailing list.\n",
X				adr, grp);
X		else
X			fprintf(mailer,
X			"'%s' was NOT FOUND on the '%s' mailing list.\n",
X				adr, grp);
X	fflush(mailer);
X	pclose(mailer);
X	}
END_OF_FILE
if test 3479 -ne `wc -c <'subscribe.c'`; then
    echo shar: \"'subscribe.c'\" unpacked with wrong size!
fi
# end of 'subscribe.c'
fi
echo shar: End of shell archive.
exit 0


-- 

Timothy Murphy  

e-mail: tim@maths.tcd.ie

shaver@convex.com (Dave Shaver) (10/15/90)

>QQ11@LIVERPOOL.AC.UK writes:
>elroy.cs.iastate.edu               129.186.3.15    mail servers

Timothy Murphy responds:
>I did in fact try the mail-server at this address
>(csdserv@cs.iostate.edu) as described by Dave Shaver
>(shaver@elroy.cs.iostate.edu) but had no luck --
>the user was unknown at the given address.
>Maybe someone can point out the correct user/address.

Take a look at the addresses: The Iowa State University Computer
Science Department is at cs.iastate.edu, not cs.iostate.edu.  My server
was running at csdserv@cs.iastate.edu for a long time, but has been
turned off for now.  However, you can still ftp the servers---including
mine written in Perl---from elroy at the address listed above.  I'm
also willing to mail a btoa'ed, compressed tar file to anyone who asks
for it.

>But there are some 6 list-server programs available at iostate
>so hopefully at least one of these will do the trick:

All of archive servers at ISU are for sending files.  Of course I think
mine has the best features and is the easiest to configure.  ;-)

Once again: Via FTP, look on elroy.cs.iastate.edu (129.186.3.15) in
/pub/servers/csdserv.TZ (it's a compressed tar file).  The other
servers in that directory were written by other people.  My server is
based in great part on the Multihouse Mail Server written by jv@mh.nl
(Johan Vromans).  Thanks go to Johan for sharing his work!

/\  Dave Shaver
\\  CONVEX Computer Corporation
\/  Internet: shaver@convex.com    UUCP:  uunet!convex!shaver