home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.wwiv.com
/
ftp.wwiv.com.zip
/
ftp.wwiv.com
/
pub
/
BBS
/
GIGO0209.ZIP
/
LISTSERV.ZIP
/
LISTSERV.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-20
|
14KB
|
460 lines
/*
* LISTSERV
*
* Sample program that takes a GIGO function request file (FUNCTION.REQ),
* checks it, and then modifies the appropriate .ML files (for mailing lists).
*
* Jason Fesler December, 1990 jfesler@wmeonlin.sacbbx.com
*/
/* For simplicity sake, I include everything, so that I don't have
* any problems with the compiler knowing what I am talking about.
*/
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <conio.h>
#include <ctype.h>
#include <direct.h>
#include <dos.h>
#include <dirent.h>
#include <stdarg.h>
/*
* Global variables are usually a bad programming practice.
* However, I don't give a damn.. :-)
*
*/
extern unsigned int _stklen = 10000; // Borland style stack declaration,
// ymmv
struct headers {
char Apparently_To[256];
char Apparently_From[256];
char To[256];
char From[256];
char Subject[256];
} header;
FILE *infile,
*outfile,
*file;
int amihere = 0;
int amiheremsg = 1;
/*
* cmpcopy looks to see if string at <source> compares to
* the string at <token>. If it does, the parameters after
* <token> are going to be copied to <dest>.
*/
void cmpcopy(char *token, char *source, char *dest)
{
if (!strncmp(source, token, strlen(token))) {
source += strlen(token);// get past the token itself
while (*source == ' ')
source++; // get past the spaces
strcpy(dest, source);
}
}
/*
* readheaders reads in the top part of the file until it reaches
* a newline character.
*
*/
void readheaders(void)
{
char line[1024] = " ";
memset(&header, 0, sizeof(headers));
while ((*line) && (!feof(infile))) {
/* remember, GIGO stands for garbage in, garbage out. */
memset(line, 0, sizeof(line));
fgets(line, sizeof(line) - 1, infile);
/* fgets includes the line terminator; we need to remove it. */
if (*line)
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = 0;
if (*line)
if (line[strlen(line) - 1] == '\r')
line[strlen(line) - 1] = 0;
if (!*line)
continue; /* We got a blank line, or an eof */
cmpcopy("Apparently-To:", line, header.Apparently_To);
cmpcopy("Apparently-From:", line, header.Apparently_From);
cmpcopy("To:", line, header.To);
cmpcopy("From:", line, header.From);
cmpcopy("Subject:", line, header.Subject);
}
}
void show_internal_help()
{
fprintf(outfile,
"Simple help instructions for the GIGO listserv processor..\n"
"----------------------------------------------------------\n"
"HELP (or ?) This help information\n"
"INDEX Shows the list of available lists\n"
"FAQ listname Shows the FAQ (info) file for listname\n"
"SUBSCRIBE listname Subscribes to listname\n"
"UNSUBSCRIBE listname Unsubscribes to listname\n"
"QUERY Query the various lists to see which you are on\n"
"\n"
"DISCONNECT Disconnects from ALL lists on this server\n"
"\n"
"Commands may be abbreviated down to a single character.\n"
"\n"
);
}
/* show_file dumps the file to the reply. If it does not exist, returns a 1. */
int show_file(char *filename)
{ // 1=error, 0=noerror
FILE *hfile;
int c;
hfile = fopen(filename, "rt");
if (!hfile)
return 1;
while (!feof(hfile)) {
c = fgetc(hfile);
fputc(c, outfile);
}
fclose(file);
return 0;
}
/* Shows the faq file for filename (filename.FAQ). If it does not
exist, it will print a message to that effect. */
void show_faq(char *filename)
{
char buf[256];
sprintf(buf, "%s.faq", filename);
if (show_file(buf))
fprintf(outfile, "Sorry, no FAQ file for %s.\n", filename);
}
/* Attempts to dump LISTSERV.HLP to the reply; if that doesn't work,
then shows the internal help file instead. */
void process_help(void)
{
if (show_file("LISTSERV.HLP"))
show_internal_help();
}
/* Subscribes to filename.ML... (routine should only specify the 8 character
name, and not the extension). If UNSUB==1, then the user is
unsubscribing instead. We get to reuse most of the code this way. */
void subscribe(char *filename, int unsub)
{
char buf[256];
char line[512];
FILE *oldfile,
*newfile;
int found = 0;
errno = 0;
unlink("LISTSERV.$$$");
errno = 0;
sprintf(buf, "%s.ml", filename);
rename(buf, "LISTSERV.$$$");
errno = 0;
oldfile = fopen("LISTSERV.$$$", "rt");
if (!oldfile) {
fprintf(outfile, "Could not access mailing list \"%s\".\n", filename);
return;
}
newfile = fopen(buf, "wt");
if (!newfile) {
fprintf(outfile, "Could not access mailing list \"%s\".\n", filename);
return;
}
if (!unsub)
fprintf(newfile, "%s\n", header.Apparently_From);
while (!feof(oldfile)) {
memset(line, 0, sizeof(line));
fgets(line, sizeof(line), oldfile);
if (line[0])
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = 0;
if (line[0])
if (line[strlen(line) - 1] == '\r')
line[strlen(line) - 1] = 0;
if (!line[0])
continue;
if (strcmp(header.Apparently_From, line) != NULL)
fprintf(newfile, "%s\n", line);
else
found = 1;
}
if (unsub) {
if (found)
fprintf(outfile, "List %s: Unsubscribed.\n", filename);
else
fprintf(outfile, "List %s: Already unsubscribed.\n", filename);
} else {
if (found)
fprintf(outfile, "List %s: Already subscribed.\n", filename);
else
fprintf(outfile, "List %s: Subscribed.\n", filename);
show_faq(filename);
}
fclose(oldfile);
fclose(newfile);
unlink("LISTSERV.$$$");
}
/* All of the answer_*() functions are used with the
check_multiple(function pointer) command. check_multiple scans
the directory for all .ML files, and runs the routine specified
passing the parameter of the list name in question.
*/
/* answer_unsubscribe works with check_multiple to globally unsubscribe. */
void answer_unsubscribe(char *filename)
{
subscribe(filename, 1);
}
/* answer_amihere works with check_multiple to globally find out if
a person is in each list. A message is displayed for each area that
the user is in; a global integer "amihere" is also updated. */
void answer_amihere(char *filename)
{
char buf[256];
char line[512];
sprintf(buf, "%s.ml", filename);
file = fopen(buf, "rt");
if (!file)
return;
while (!feof(file)) {
memset(line, 0, sizeof(line));
fgets(line, sizeof(line), file);
if (line[0])
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = 0;
if (line[0])
if (line[strlen(line) - 1] == '\r')
line[strlen(line) - 1] = 0;
if (!line[0])
continue;
if (strcmp(header.Apparently_From, line) == NULL) {
if (amiheremsg)
fprintf(outfile, "You are in the %s list.\n", filename);
amihere++;
break;
}
}
fclose(file);
}
/* answer_index works with check_multiple to tell the user what
mailing lists there are. This is only used if the file
LISTSERV.IDX is not available (hence the manual check). */
void answer_index(char *name)
{
fprintf(outfile, " %s\n", name);
}
/* check_multiple is a special function..
It takes as it's parameter the address to another function(char*).
All answer_*(char*) functions use this procedure.
check_multiple will run that function once for every mailing list
in the current directory. It has multiple uses; it can make
an index of the lists, globally desubscribe, and check to see which
lists a user is in. This method of handling it means that I don't
have to have 3-4 (maybe more in the future) copies of the
directory-reading code.
*/
void check_multiple(void func(char *))
{
DIR *dir;
struct dirent *ent;
char buf[256];
errno = 0;
if ((dir = opendir("")) == NULL) {
fprintf(stdout, "Unable to open directory\n");
return;
}
while ((ent = readdir(dir)) != NULL) {
strcpy(buf, ent->d_name);
if (strstr(buf, ".ML")) {
if (strchr(buf, '.'))
*strchr(buf, '.') = 0;
func(buf);
}
}
}
void process_query(void)
{
amiheremsg = 1;
amihere = 0;
fprintf(outfile, "Checking to see which mailing lists you are in...\n");
check_multiple(answer_amihere);
if (amihere)
fprintf(outfile, "-----\n"
"Total of %u lists.\n\n", amihere);
else
fprintf(outfile, "You are in no lists with your present email address.\n");
}
void process_index(void)
{
if (!show_file("LISTSERV.IDX"))
return; // we had an ascii one handy
fprintf(outfile, "Checking to see which mailing lists are available...\n");
check_multiple(answer_index);
fprintf(outfile, "End of lists.\n");
}
void processline(char *cmd, char *parm)
{
strupr(cmd);
strupr(parm);
switch (cmd[0]) {
case '?':
case 'H':
process_help();
break;
case 'I':
process_index();
break;
case 'F':
show_faq(parm);
break;
case 'S':
subscribe(parm, 0);
break;
case 'U':
subscribe(parm, 1);
break;
case 'Q':
process_query();
break;
case 'D':
fprintf(outfile, "Disconnecting you from all lists.\n");
check_multiple(answer_unsubscribe);
break;
case '-':
fprintf(outfile, "Signature or tearline detected, end of process.\n");
return;
default:
fprintf(outfile, "I don't recognize that command. HELP will give you more information.\n");
}
}
void processlines(void)
{
char line[256];
char *cmd;
char *parm;
char *genpurpose;
while (!feof(infile)) {
memset(line, 0, sizeof(line));
fgets(line, sizeof(line), infile);
if (line[0])
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = 0;
if (line[0])
if (line[strlen(line) - 1] == '\r')
line[strlen(line) - 1] = 0;
if (!line[0])
continue;
fprintf(outfile, "\n>%s\n", line);
printf(">%s\n", line);
cmd = strtok(line, " \x09");
parm = strtok(NULL, " \x09");
if (!cmd)
cmd = "";
if (!parm)
parm = "";
while (genpurpose = strpbrk(parm, ":/\\"))
parm = genpurpose + 1;
while (genpurpose = strpbrk(parm, "?*"))
*genpurpose = '_';
if (genpurpose = strchr(parm, '.'))
*genpurpose = 0; // truncate
processline(cmd, parm);
}
}
void needhelp(char *errmsg)
{
fprintf(stderr, "Error! %s\n", errmsg);
fprintf(stderr, "LISTSERV is meant to be run as a function request under GIGO.\n"
"Please see the LISTSERV documentation for proper usage.\n\n\n(Pausing 2 seconds)\n");
delay(2000);
exit(1);
}
void main(void)
{
int i;
fprintf(stderr, "LISTSERV processor for GIGO compile " __DATE__ ".\n");
infile = fopen("FUNCTION.REQ", "rt");
if (!infile)
needhelp("FUNCTION.REQ not available for input.");
outfile = fopen("FUNCTION.REP", "wt");
if (!outfile)
needhelp("FUNCTION.REP not available for output.");
readheaders();
if (header.Apparently_From[0] == 0)
needhelp("Apparently-From: line missing from FUNCTION.REQ file");
printf("Function request for: %s\n", header.Apparently_From);
if (show_file("LISTSERV.TXT"))
fprintf(outfile,
"Thank you for using GIGO's listserv processor. Your commands are being quoted\n"
"below, followed by the processor's responses. For this process, we are using\n"
"your email address of \"%s\".\n\n", header.Apparently_From);
else
fprintf(outfile, "\nFor this process, we are using\n"
"your email address of \"%s\".\n\n", header.Apparently_From);
// if there are command line parameters..
if (_argc > 2) {
if (toupper(_argv[1][0]) == 'S') {
for (i = 2; i < _argc; i++)
processline("S", _argv[i]);
} else if (toupper(_argv[1][0]) == 'U') {
for (i = 2; i < _argc; i++)
processline("U", _argv[i]);
} else
needhelp("Invalid command line option (rtfm).");
} else if (_argc == 2)
needhelp("Not enough parameters or invalid command line option.");
else
processlines();
fclose(infile);
fclose(outfile);
}