Msg Shar.part.6
sources-request at panda.UUCP
sources-request at panda.UUCP
Mon Mar 3 11:17:40 AEST 1986
Mod.sources: Volume 4, Issue 10
Submitted by: decvax!hplabs!hpcnou!dat (Dave Taylor)
# Msg Shar part 6 of 7
# Shell Archive created by hpcnou!dat at Wed Feb 26 15:56:49 1986
# To unpack the enclosed files, please use this file as input to the
# Bourne (sh) shell. This can be most easily done by the command;
# sh < thisfilename
# This archive contains;
# src/newmbox.c src/strings.c src/syscall.c src/utils.c
# src/validname.c src/Makefile utils/answer.c utils/arepdaemon.c
# utils/autoreply.c
if [ ! -d src ]
then
echo creating directory src
mkdir src
fi
# ---------- file src/newmbox.c ----------
if [ -f src/newmbox.c ]
then
echo File 'src/newmbox.c' already exists\!
exit 1
fi
echo extracting file src/newmbox.c...
cat << 'END-OF-FILE' > src/newmbox.c
/** newmbox.c **/
/** read new mbox file
(C) Copyright 1986 Dave Taylor
**/
#include <ctype.h>
#ifdef BSD
#undef tolower
#endif
#include "headers.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef BSD
# include <sys/time.h>
#else
# include <time.h>
#endif
int
newmbox(stat, resync)
int stat, resync;
{
/** Read a new mailbox file or resync on current file.
Values of stat and what they mean;
stat = 0 - changing mailboxes from within program
stat = 1 - read default mailbox for the first time
stat = 2 - read existing mailbox, new mail arrived
resync is TRUE iff we know the current mailbox has changed. If
it's set to true this means that we MUST READ SOMETHING, even
if it's the current mailbox again!!
**/
int switching_to_default = 0;
char buff[SLEN];
dprint2("newmbox(stat=%d, resync=%d)\n", stat, resync);
dprint1("\tfile-changed = %s\n\n", onoff(file_changed));
if (stat > 0) {
if (strlen(infile) == 0) /* no filename yet?? */
sprintf(infile,"%s%s",mailhome, username);
}
else { /* get name of new mailbox! */
MoveCursor(LINES-3, 30);
CleartoEOS();
show_last_error();
if (mbox_specified != 2) {
PutLine(LINES-2,0,"Name of new mailbox: ");
buff[0] = '\0';
(void) optionally_enter(buff, LINES-2, 21, FALSE);
ClearLine(LINES-2);
if (strlen(buff) == 0) {
if (resync && file_changed)
strcpy(buff, infile);
else
return(FALSE);
}
if (strcmp(buff, infile) == 0 && ! resync) {
error("already reading that mailbox!");
return(FALSE);
}
if (first_word(buff, mailhome) && ! resync) {
mbox_specified = 0; /* fake program to think that */
stat = 1; /* we're the default file */
switching_to_default++; /* remember this act! */
}
else if (strcmp(buff, "!") == 0) { /* go to mailbox */
sprintf(buff,"%s%s", mailhome, username);
if (! resync || (resync && ! file_changed)) {
if (strcmp(buff, infile) == 0) { /* are we reading it? */
error("already reading your incoming mailbox!");
return(FALSE);
}
}
if (! resync || (resync && ! file_changed)) {
mbox_specified = 0; /* fake program to think that */
stat = 1; /* we're the default file */
switching_to_default++; /* remember this act! */
}
}
if (! expand_filename(buff)) {
error1("cannot expand file %s", buff);
if (resync && file_changed)
strcpy(buff, infile);
else
return(FALSE);
}
if (! can_access(buff,"r")) {
error1("cannot open file %s", buff);
if (resync && file_changed)
strcpy(buff, infile);
else
return(FALSE);
}
if (resync && file_changed && strcmp(buff, infile) == 0)
PutLine(20,40,"Resynchronizing file");
else
PutLine(20,40,"Mailbox: %s", buff);
CleartoEOLN();
strcpy(infile,buff);
if (! switching_to_default) mbox_specified = 1;
}
else { /* starting filename given to routine */
if (! can_access(infile,"r"))
exit(PutLine(LINES, 0, "Could not open file %s!\n", infile));
mbox_specified = 1;
}
}
clear_error();
clear_central_message();
if ((mailfile = fopen(infile,"r")) == NULL)
message_count = 0;
else if (stat < 2) { /* new mail file! */
if (notesfile)
message_count = read_notesfile(); /* can't get new notes! */
else
message_count = read_headers(FALSE);
}
else /* resync with current mail file */
message_count = read_headers(TRUE);
if (message_count && stat < 2) current = 1;
header_page = 0;
return(TRUE);
}
int
read_headers(stat)
int stat;
{
/** Reads the headers into the header_table structure and leaves
the file rewound for further I/O requests. If the file being
read is the default mailbox (ie incoming) then it is copied to
a temp file and closed, to allow more mail to arrive during
the msg session. If stat is set, the program will then copy
the delete flag from the previous data structure value to the
new one if possible. This is for re-reading the mailfile!
Added: reads and formats the date from the first 'From' line
**/
FILE *temp;
char buffer[LONG_STRING], temp_filename[SLEN];
register int line = 0, count = 0, subj = 0, copyit = 0, in_header = 1;
long bytes = 0L, line_bytes = 0L;
static int first_read = 0;
int count_x, count_y = 17;
dprint1("read_headers(stat=%d)\n", stat);
if (! first_read++) {
MoveCursor(LINES-2, 0);
CleartoEOS();
PutLine(LINES-1, 0, "Reading in %s, message: 0", infile);
count_x = LINES-1;
count_y = 22 + strlen(infile);
}
else {
PutLine(LINES-2, 0, "Reading message: 0");
count_x = LINES-2;
}
if (mbox_specified == 0) {
lock(INCOMING); /* ensure no mail arrives while we do this! */
sprintf(temp_filename,"%s%s",temp_mbox, username);
if ((temp = fopen(temp_filename,"w")) == NULL) {
unlock(); /* remove lock file! */
Raw(OFF);
printf("Could not open file %s for writing (uid=%d)...\n",
temp_filename, getuid());
system_call("/bin/ls -l /tmp/*", SH);
leave(error1("could not open file %s for writing!",
temp_filename));
}
get_mailtime();
copyit++;
chown(temp_filename, userid, getgid());
}
while (fgets(buffer, LONG_STRING, mailfile) != NULL) {
if (line == 0) { /* first line of file... */
if (! mbox_specified) {
if (first_word(buffer, "Forward to "))
set_central_message("Mail being forwarded to %s",
(char *) (buffer + 11));
}
/* Are we reading in a notesfile file without the flag
turned on??? */
if (first_word(buffer, NOTES_HEADER)) { /* if so... */
rewind(mailfile);
notesfile++; /* set da flag, boss-man */
return(read_notesfile()); /* hop over to notes */
}
}
if (copyit) fputs(buffer, temp);
line_bytes = (long) strlen(buffer);
line++;
if (first_word(buffer,"From ")) {
if (real_from(buffer, &header_table[count])) {
header_table[count].offset = (long) bytes;
if (! stat || count > message_count)
header_table[count].delete = 0; /* clear flag! */
strcpy(header_table[count].subject, ""); /* clear subj */
header_table[count++].lines = line;
header_table[count].priority = 0;
subj = 0;
in_header = 1;
PutLine(count_x, count_y, "%d", count);
if (count > 1)
header_table[count-2].lines = header_table[count-1].lines -
header_table[count-2].lines;
}
}
else if (in_header) {
if (first_word(buffer,">From"))
forwarded(buffer, &header_table[count-1]); /* return address */
else if (first_word(buffer,"Subject:") ||
first_word(buffer,"Subj:") ||
first_word(buffer,"Re:")) {
if (! subj++) {
remove_first_word(buffer);
strncpy(header_table[count-1].subject, buffer, SLEN);
}
}
else if (first_word(buffer,"From:"))
parse_arpa_from(buffer, header_table[count-1].from);
else if (first_word(buffer, "Date:"))
parse_arpa_date(buffer, &header_table[count-1]);
else if (first_word(buffer, "Priority:"))
header_table[count-1].priority++;
else if (buffer[0] == LINE_FEED || buffer[0] == '\0') {
if (in_header) {
in_header = 0; /* in body of message! */
fix_date(&header_table[count-1]);
}
}
}
bytes += (long) line_bytes;
}
total_lines_in_file = line;
header_table[count-1].lines = line - header_table[count-1].lines + 1;
if (mbox_specified == 0) {
unlock(); /* remove lock file! */
fclose(mailfile);
fclose(temp);
if ((mailfile = fopen(temp_filename,"r")) == NULL) {
MoveCursor(LINES,0);
Raw(OFF);
printf("Fatal error: could not reopen %s as temp mail file!\n",
temp_filename);
leave();
}
}
else
rewind(mailfile);
return(count);
}
END-OF-FILE
size=`wc -c < src/newmbox.c`
if [ $size != 8124 ]
then
echo Warning: src/newmbox.c changed - should be 8124 bytes, not $size bytes
fi
chmod 644 src/newmbox.c
# ---------- file src/strings.c ----------
if [ -f src/strings.c ]
then
echo File 'src/strings.c' already exists\!
exit 1
fi
echo extracting file src/strings.c...
cat << 'END-OF-FILE' > src/strings.c
/** strings.c **/
/** This file contains all the string oriented functions for the
MSG Mailer, and lots of other generally useful string functions!
For BSD systems, this file also includes the function "tolower"
to translate the given character from upper case to lower case.
(C) Copyright 1985, Dave Taylor
**/
#include <stdio.h>
#include "headers.h"
#include <ctype.h>
#ifdef BSD
#undef tolower
#undef toupper
#endif
/** forward declarations **/
char *format_long(), *strip_commas(), *tail_of_string(), *shift_lower(),
*get_token(), *strip_parens(), *argv_zero();
#ifdef BSD
int
tolower(ch)
char ch;
{
/** This should be a macro call, but if you use this as a macro
calls to 'tolower' where the argument is a function call will
cause the function to be called TWICE which is obviously the
wrong behaviour. On the other hand, to just blindly translate
assuming the character is always uppercase can cause BIG
problems, so...
**/
return ( isupper(ch) ? ch - 'A' + 'a' : ch );
}
int
toupper(ch)
char ch;
{
/** see comment for above routine - tolower() **/
return ( islower(ch) ? ch - 'a' + 'A' : ch );
}
#endif
int
in_string(buffer, pattern)
char *buffer, *pattern;
{
/** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/
register int i = 0, j = 0;
while (buffer[i] != '\0') {
while (buffer[i++] == pattern[j++])
if (pattern[j] == '\0')
return(TRUE);
i = i - j + 1;
j = 0;
}
return(FALSE);
}
tail_of(from, buffer, header_line)
char *from, *buffer;
int header_line;
{
/** Return last two words of 'from'. This is to allow
painless display of long return addresses as simply the
machine!username. Alternatively, if the first three
characters of the 'from' address are 'To:' and 'header_line'
is TRUE, then return the buffer value prepended with 'To '.
**/
/** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes,
':' delimits CSNet & Bitnet nodes, and '%' delimits
multiple stage ARPA hops... **/
register int loc, i = 0, cnt = 0;
char tempbuffer[SLEN];
for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) {
if (from[loc] == '!' || from[loc] == '@' ||
from[loc] == ':') cnt++;
if (cnt < 2) buffer[i++] = from[loc];
}
buffer[i] = '\0';
reverse(buffer);
if ((strncmp(buffer,"To:", 3) == 0) && header_line)
buffer[2] = ' ';
else if ((strncmp(from, "To:", 3) == 0) && header_line) {
sprintf(tempbuffer,"To %s", buffer);
strcpy(buffer, tempbuffer);
}
else if (strncmp(buffer, "To:", 3) == 0) {
for (i=3; i < strlen(buffer); i++)
tempbuffer[i-3] = buffer[i];
tempbuffer[i-3] = '\0';
strcpy(buffer, tempbuffer);
}
}
char *format_long(inbuff, init_len)
char *inbuff;
int init_len;
{
/** Return buffer with \n\t sequences added at each point
where it would be more than 80 chars long. It only
allows the breaks at legal points (ie white spaces).
init-len is the characters already on the first line...
Changed so that if this is called while mailing without
the overhead of "msg", it'll include "\r\n\t" instead.
**/
static char ret_buffer[VERY_LONG_STRING];
register int index = 0, current_length = 0, depth=15, i;
char buffer[VERY_LONG_STRING];
char *word, *bufptr;
strcpy(buffer, inbuff);
bufptr = (char *) buffer;
current_length = init_len + 2; /* for luck */
while ((word = get_token(bufptr," ", depth)) != NULL) {
if (strlen(word) + current_length > 80) {
if (index > 0) {
if (mail_only)
ret_buffer[index++] = '\r';
ret_buffer[index++] = '\n';
ret_buffer[index++] = '\t';
}
for (i=0; i<strlen(word); i++)
ret_buffer[index++] = word[i];
current_length = strlen(word) + 8; /* 8 = TAB */
}
else {
if (index > 0)
ret_buffer[index++] = ' ';
for (i=0; i<strlen(word); i++)
ret_buffer[index++] = word[i];
current_length += strlen(word) + 1;
}
bufptr = NULL;
}
ret_buffer[index] = '\0';
return( (char *) ret_buffer);
}
char *strip_commas(string)
char *string;
{
/** return string with all commas changed to spaces. This IS
destructive and will permanently change the input string.. **/
register int i;
for (i=0; i < strlen(string); i++)
if (string[i] == COMMA)
string[i] = SPACE;
return( (char *) string);
}
char *strip_parens(string)
char *string;
{
/** Return string with all parenthesized information removed.
This is a non-destructive algorithm... **/
static char buffer[VERY_LONG_STRING];
register int i, depth = 0, buffer_index = 0;
for (i=0; i < strlen(string); i++) {
if (string[i] == '(')
depth++;
else if (string[i] == ')')
depth--;
else if (depth == 0)
buffer[buffer_index++] = string[i];
}
buffer[buffer_index] = '\0';
return( (char *) buffer);
}
move_left(string, chars)
char string[];
int chars;
{
/** moves string chars characters to the left DESTRUCTIVELY **/
register int i;
chars--; /* index starting at zero! */
for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
string[i-chars] = string[i];
string[i-chars] = '\0';
}
remove_first_word(string)
char *string;
{ /** removes first word of string, ie up to first non-white space
following a white space! **/
register int loc;
for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++)
;
while (string[loc] == ' ' || string[loc] == '\t')
loc++;
move_left(string, ++loc);
}
char *tail_of_string(string, maxchars)
char *string;
int maxchars;
{
/** Return a string that is the last 'maxchars' characters of the
given string. This is only used if the first word of the string
is longer than maxchars, else it will return what is given to
it...
**/
static char buffer[SLEN];
register int index, i;
for (index=0;! whitespace(string[index]) && index < strlen(string);
index++)
;
if (index < maxchars) {
strncpy(buffer, string, maxchars-2); /* word too short */
buffer[maxchars-2] = '.';
buffer[maxchars-1] = '.';
buffer[maxchars] = '.';
buffer[maxchars+1] = '\0';
}
else {
i = maxchars;
buffer[i--] = '\0';
while (i > 1)
buffer[i--] = string[index--];
buffer[2] = '.';
buffer[1] = '.';
buffer[0] = '.';
}
return( (char *) buffer);
}
reverse(string)
char *string;
{
/** reverse string... pretty trivial routine, actually! **/
char buffer[SLEN];
register int i, j = 0;
for (i = strlen(string)-1; i >= 0; i--)
buffer[j++] = string[i];
buffer[j] = '\0';
strcpy(string, buffer);
}
int
get_word(buffer, start, word)
char *buffer, *word;
int start;
{
/** return next word in buffer, starting at 'start'.
delimiter is space or end-of-line. Returns the
location of the next word, or -1 if returning
the last word in the buffer. -2 indicates empty
buffer! **/
register int loc = 0;
while (buffer[start] == ' ' && buffer[start] != '\0')
start++;
if (buffer[start] == '\0') return(-2); /* nothing IN buffer! */
while (buffer[start] != ' ' && buffer[start] != '\0')
word[loc++] = buffer[start++];
word[loc] = '\0';
return(start);
}
int
chloc(string, ch)
char *string, ch;
{
/** returns the index of ch in string, or -1 if not in string **/
register int i;
for (i=0; i<strlen(string); i++)
if (string[i] == ch) return(i);
return(-1);
}
int
two_words(string)
char *string;
{
/** is 'string' exactly two words? Return TRUE or FALSE **/
return( words_in_string(string) == 2 );
}
char *shift_lower(string)
char *string;
{
/** return 'string' shifted to lower case. Do NOT touch the
actual string handed to us! **/
static char buffer[LONG_SLEN];
register int i;
for (i=0; i < strlen(string); i++)
if (isupper(string[i]))
buffer[i] = tolower(string[i]);
else
buffer[i] = string[i];
buffer[strlen(string)] = 0;
return( (char *) buffer);
}
int
words_in_string(buffer)
char *buffer;
{
/** This routine returns the number of words in the given line.
A word is defined as a series of characters surrounded by
either the beginning of the string, the end of the string,
or white space.
For example, the following line has 8 words:
"This is a test of the program, okay?"
**/
register int count = 0, i = 0;
while (buffer[i] != '\0') {
while (whitespace(buffer[i])) i++;
if (buffer[i] != '\0')
count++;
while (! whitespace(buffer[i]) && buffer[i] != '\0') i++;
}
return(count);
}
clean_up(buffer)
char *buffer;
{
/** This routine takes a string of the form "a:b" and returns it
as just "b"... **/
char mybuffer[SLEN];
register int loc, myloc = 0;
for (loc=0; buffer[loc] != ':'; loc++)
;
while (buffer[++loc] != '\0')
mybuffer[myloc++] = buffer[loc];
mybuffer[myloc] = '\0';
strcpy(buffer, mybuffer);
}
Centerline(line, string)
int line;
char *string;
{
/** Output 'string' on the given line, centered. **/
register int length, col;
length = strlen(string);
if (length > COLUMNS)
col = 0;
else
col = (COLUMNS - length) / 2;
PutLine(line, col, string);
}
char *argv_zero(string)
char *string;
{
/** given a string of the form "/something/name" return a
string of the form "name"... **/
static char buffer[NLEN];
register int i, j=0;
for (i=strlen(string)-1; string[i] != '/'; i--)
buffer[j++] = string[i];
buffer[j] = '\0';
reverse(buffer);
return( (char *) buffer);
}
#define MAX_RECURSION 20 /* up to 20 deep recursion */
char *get_token(source, keys, depth)
char *source, *keys;
int depth;
{
/** This function is similar to strtok() (see "opt_utils")
but allows nesting of calls via pointers...
**/
register int last_ch;
static char *buffers[MAX_RECURSION];
char *return_value, *sourceptr;
if (depth > MAX_RECURSION) {
error1("get_token calls nested greater than %d deep!",
MAX_RECURSION);
emergency_exit();
}
if (source != NULL)
buffers[depth] = source;
sourceptr = buffers[depth];
if (*sourceptr == '\0')
return(NULL); /* we hit end-of-string last time!? */
sourceptr += strspn(sourceptr, keys); /* skip the bad.. */
if (*sourceptr == '\0') {
buffers[depth] = sourceptr;
return(NULL); /* we've hit end-of-string */
}
last_ch = strcspn(sourceptr, keys); /* end of good stuff */
return_value = sourceptr; /* and get the ret */
sourceptr += last_ch; /* ...value */
if (*sourceptr != '\0') /** don't forget if we're at end! **/
sourceptr++;
return_value[last_ch] = '\0'; /* ..ending right */
buffers[depth] = sourceptr; /* save this, mate! */
return((char *) return_value); /* and we're outta here! */
}
END-OF-FILE
size=`wc -c < src/strings.c`
if [ $size != 10790 ]
then
echo Warning: src/strings.c changed - should be 10790 bytes, not $size bytes
fi
chmod 644 src/strings.c
# ---------- file src/syscall.c ----------
if [ -f src/syscall.c ]
then
echo File 'src/syscall.c' already exists\!
exit 1
fi
echo extracting file src/syscall.c...
cat << 'END-OF-FILE' > src/syscall.c
/** syscall.c **/
/** These routines are used for user-level system calls, including the
'!' command and the '|' commands...
(C) Copyright 1986 Dave Taylor
**/
#include "headers.h"
#include <signal.h>
char *argv_zero();
int
subshell()
{
/** spawn a subshell with either the specified command
returns non-zero if screen rewrite needed
**/
char command[SLEN];
int ret;
PutLine(LINES-3,COLUMNS-40,"(use 'sh' or 'csh' for a shell)");
PutLine(LINES-2,0,"Shell Command: ");
command[0] = '\0';
(void) optionally_enter(command, LINES-2, 15, FALSE);
if (strlen(command) == 0) {
MoveCursor(LINES-2,0); CleartoEOLN();
return(0);
}
MoveCursor(LINES,0); CleartoEOLN();
Raw(OFF);
if (cursor_control) transmit_functions(OFF);
ret = system_call(command, USER_SHELL);
printf("\nPress <return> to return to MSG: ");
Raw(ON);
(void) getchar();
if (cursor_control) transmit_functions(ON);
if (ret != 0) error1("Return code was %d", ret);
return(1);
}
system_call(string, shell_type)
char *string;
int shell_type;
{
/** execute 'string', setting uid to userid... **/
/** if shell-type is "SH" /bin/sh is used regardless of the
users shell setting. Otherwise, "USER_SHELL" is sent **/
int status, pid, w;
register int (*istat)(), (*qstat)();
dprint2("system_call('%s', %s)\n", string,
shell_type == SH? "SH" : "USER-SHELL");
if ((pid = fork()) == 0) {
setuid(userid); /* back to the normal user! */
if (strlen(shell) > 0 && shell_type == USER_SHELL) {
execl(shell, argv_zero(shell), "-c", string, 0);
}
else
execl("/bin/sh", "sh", "-c", string, 0);
_exit(127);
}
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
while ((w = wait(&status)) != pid && w != -1)
;
if (w == -1) status = -1;
signal(SIGINT, istat);
signal(SIGQUIT, qstat);
return(status);
}
int
pipe()
{
/** pipe the current message to the specified sequence.. **/
char command[SLEN], buffer[LONG_SLEN];
int ret, lines;
PutLine(LINES-2,0,"Pipe current msg to: ");
command[0] = '\0';
(void) optionally_enter(command, LINES-2, 21, FALSE);
if (strlen(command) == 0) {
MoveCursor(LINES-2,0); CleartoEOLN();
return(0);
}
MoveCursor(LINES,0); CleartoEOLN();
Raw(OFF);
lines = header_table[current-1].lines;
if (cursor_control) transmit_functions(OFF);
sprintf(buffer, "%s %s %d %d - | %s", cutfile,
infile, header_table[current-1].offset,
lines, command);
ret = system_call(buffer, USER_SHELL);
printf("\nPress <return> to return to MSG: ");
Raw(ON);
(void) getchar();
if (cursor_control) transmit_functions(ON);
if (ret != 0) error1("Return code was %d", ret);
return(1);
}
printmsg()
{
/** print specified message using 'printout' variable.
Error message iff printout not defined! **/
FILE *temp;
char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN];
int retcode;
dprint1("printmsg()\n\tprintout = %s\n", printout);
dprint1("\tcurrent message = %d\n", current);
if (strlen(printout) == 0) {
error("PRINTMAIL not defined! Don't know how to print message");
return;
}
if (current == 0) {
error("No mail to print!");
return;
}
sprintf(filename,"%s%d", temp_print, getpid());
if ((temp = fopen(filename,"w")) == NULL) {
error1("Could not open file %s as a temporary file", filename);
return;
}
copy_message("", temp, FALSE);
fclose(temp);
if (in_string(printout, "%s"))
sprintf(printbuffer, printout, filename);
else
sprintf(printbuffer, "%s %s", printout, filename);
sprintf(buffer,"(%s 2>&1 ) > /dev/null",
printbuffer, filename);
error("working...");
if ((retcode = system_call(buffer, SH)) == 0)
error("Message queued up to print");
else
error1("Printout failed with return code %d", retcode);
unlink(filename); /* remove da temp file! */
}
END-OF-FILE
size=`wc -c < src/syscall.c`
if [ $size != 3869 ]
then
echo Warning: src/syscall.c changed - should be 3869 bytes, not $size bytes
fi
chmod 644 src/syscall.c
# ---------- file src/utils.c ----------
if [ -f src/utils.c ]
then
echo File 'src/utils.c' already exists\!
exit 1
fi
echo extracting file src/utils.c...
cat << 'END-OF-FILE' > src/utils.c
/** utils.c **/
/** Utility routines for MSG
All routines herein: (C) Copyright 1985 Dave Taylor
**/
#include "headers.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#ifdef BSD
#undef tolower
#endif
#include <signal.h>
#include <errno.h>
emergency_exit()
{
/** used in dramatic cases when we must leave without altering
ANYTHING about the system... **/
Raw(OFF);
if (cursor_control) transmit_functions(OFF);
if (hp_terminal) softkeys_off();
if (cursor_control)
MoveCursor(LINES, 0);
printf("\n\rEmergency Exit taken! All temp files intact!\n\r\n\r");
exit(1);
}
leave(val)
int val; /* not used, placeholder for signal catching! */
{
char buffer[SLEN];
dprint1("leave(%d)\n", val);
Raw(OFF);
if (cursor_control) transmit_functions(OFF);
if (hp_terminal) softkeys_off();
sprintf(buffer,"%s%d",temp_file, getpid()); /* editor buffer */
(void) unlink(buffer);
if (! mail_only) {
sprintf(buffer,"%s%d",temp_file, getpid()+1); /* editor buffer */
(void) unlink(buffer);
}
sprintf(buffer,"%s%s",temp_mbox, username); /* temp mailbox */
(void) unlink(buffer);
sprintf(buffer,"%s%s.lock",mailhome, username); /* lock file */
(void) unlink(buffer);
if (! mail_only)
MoveCursor(LINES-1,0);
putchar('\n');
exit(0);
}
leave_locked(val)
int val; /* not used, placeholder for signal catching! */
{
/** same as leave routine, but don't disturb lock file **/
char buffer[SLEN];
dprint1("leave_locked(%d)\n", val);
Raw(OFF);
if (cursor_control) transmit_functions(OFF);
if (hp_terminal) softkeys_off();
sprintf(buffer,"%s%d",temp_file, getpid()); /* editor buffer */
(void) unlink(buffer);
sprintf(buffer,"%s%d",temp_file, getpid()+1); /* editor buffer */
(void) unlink(buffer);
sprintf(buffer,"%s%s",temp_mbox, username); /* temp mailbox */
(void) unlink(buffer);
MoveCursor(LINES-1,0);
putchar('\n');
exit(0);
}
int
get_page(current)
int current;
{
/** ensure that 'current' is on the displayed page,
returning non-zero iff the page changed! **/
register int first_on_page, last_on_page;
first_on_page = (header_page * headers_per_page) + 1;
last_on_page = first_on_page + headers_per_page - 1;
if (current > last_on_page) {
header_page = (int) (current-1) / headers_per_page;
return(1);
}
else if (current < first_on_page) {
header_page = (int) (current-1) / headers_per_page;
return(1);
}
else
return(0);
}
int
copy_to_self(buffer)
char *buffer;
{
/** returns true iff buffer = 'Cc: username' where username
is the account name of the person sending the message.
Used for weeding out 'Cc:' lines from the messages if
'weed' is turned on. **/
/** note: tail_of() is located in file "strings.c" **/
char name[SLEN], buf[SLEN];
register int i=0, j=0;
dprint1("copy_to_self(%s)\n", buffer);
tail_of(header_table[current-1].from, name, FALSE);
while (name[i] != '!' && i < strlen(name))
i++;
if (name[i] == '!') {
for (i++; i < strlen(name); i++)
name[j++] = name[i];
name[j] = 0;
}
sprintf(buf, "Cc: %s\n", name);
return( strcmp(buf, buffer) == 0 );
}
END-OF-FILE
size=`wc -c < src/utils.c`
if [ $size != 3154 ]
then
echo Warning: src/utils.c changed - should be 3154 bytes, not $size bytes
fi
chmod 644 src/utils.c
# ---------- file src/validname.c ----------
if [ -f src/validname.c ]
then
echo File 'src/validname.c' already exists\!
exit 1
fi
echo extracting file src/validname.c...
cat << 'END-OF-FILE' > src/validname.c
/** validname.c **/
/** This routine takes a single address, no machine hops or
anything, and returns 1 if it's valid and 0 if not. The
algorithm it uses is the same one that uux uses, namely:
1. Is there a file '/usr/mail/%s'?
2. Is there a password entry for %s?
(C) Copyright 1986 Dave Taylor
**/
#include <stdio.h>
#include "defs.h"
int
valid_name(name)
char *name;
{
/** does what it says above, boss! **/
char filebuf[SLEN];
#ifdef NOCHECK_VALIDNAME
return(1); /* always say it's okay! */
#else
sprintf(filebuf,"%s/%s", mailhome, name);
if (access(filebuf, ACCESS_EXISTS) == 0)
return(1);
if (getpwnam(name) != NULL)
return(1);
return(0);
#endif
}
END-OF-FILE
size=`wc -c < src/validname.c`
if [ $size != 707 ]
then
echo Warning: src/validname.c changed - should be 707 bytes, not $size bytes
fi
chmod 644 src/validname.c
# ---------- file src/Makefile ----------
if [ -f src/Makefile ]
then
echo File 'src/Makefile' already exists\!
exit 1
fi
echo extracting file src/Makefile...
cat << 'END-OF-FILE' > src/Makefile
#
# Makefile for the MSG mail program.
#
# (C) Copyright 1986, Dave Taylor
#
# Last modification: January 23rd, 1986
CFILES= addr_utils.c alias.c aliasdb.c aliaslib.c args.c curses.c date.c \
delete.c encode.c file.c file_utils.c fileio.c hdrconfg.c help.c \
initialize.c input_utils.c mailout.c mailtime.c mkhdrs.c msg.c \
newmbox.c notesfile.c output_utils.c pattern.c quit.c savecopy.c \
read_rc.c reply.c return_addr.c screen.c showmsg.c strings.c \
syscall.c utils.c validname.c softkeys.c opt_utils.c leavembox.c
HEADERS=../hdrs/curses.h ../hdrs/defs.h ../hdrs/headers.h ../hdrs/msg.h
OBJS= addr_utils.o alias.o aliasdb.o aliaslib.o args.o curses.o date.o \
delete.o encode.o file.o file_utils.o fileio.o hdrconfg.o help.o \
initialize.o input_utils.o mailout.o mailtime.o mkhdrs.o msg.o \
newmbox.o notesfile.o output_utils.o pattern.o quit.o savecopy.o \
read_rc.o reply.o return_addr.o screen.o showmsg.o strings.o \
syscall.o utils.o validname.o softkeys.o opt_utils.o leavembox.o
# if on BSD use
# DEFINE=-DBSD
# else if on UTS use
# DEFINE=-DUTS
# else
DEFINE=
BIN= ../bin
LIBS= -ltermcap
CFLAGS= -O -I../hdrs
CC= /bin/cc
RM= /bin/rm -f
.c.o: ${HEADERS}
${CC} -c ${CFLAGS} ${DEFINE} $*.c
../bin/msg: ${OBJS} ${EXTRA} ${HEADERS} ../hdrs/msg.h
${CC} -o ${BIN}/msg -n ${OBJS} ${LIBS}
curses.o: curses.c ../hdrs/curses.h
${CC} -c -O -DRAWMODE ${DEFINE} -I../hdrs curses.c
clean:
${RM} ${OBJS} LINT.OUT
lint: LINT.OUT
LINT.OUT: ${CFILES}
lint -p -I../hdrs ${CFILES} > LINT.OUT
listing:
@../bin/makelisting Makefile ${HEADERS} ${CFILES}
@echo LISTING generated.
END-OF-FILE
size=`wc -c < src/Makefile`
if [ $size != 1647 ]
then
echo Warning: src/Makefile changed - should be 1647 bytes, not $size bytes
fi
chmod 644 src/Makefile
if [ ! -d utils ]
then
echo creating directory utils
mkdir utils
fi
# ---------- file utils/answer.c ----------
if [ -f utils/answer.c ]
then
echo File 'utils/answer.c' already exists\!
exit 1
fi
echo extracting file utils/answer.c...
cat << 'END-OF-FILE' > utils/answer.c
/** answer.c **/
/** This program is a phone message transcription system, and
is designed for secretaries and the like, to allow them to
painlessly generate electronic mail instead of paper forms.
Note: this program ONLY uses the local alias file, and does not
even read in the system alias file at all.
(C) Copyright 1986, Dave Taylor
**/
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include "defs.h" /* MSG system definitions */
struct alias_rec user_hash_table [MAX_UALIASES];
int user_data; /* fileno of user data file */
char *expand_group(), *get_alias_address(), *get_token();
main()
{
FILE *fd;
char *address, buffer[LONG_STRING], tempfile[SLEN];
char name[SLEN], user_name[SLEN];
int msgnum = 0, eof;
read_alias_files();
while (1) {
if (msgnum > 9999) msgnum = 0;
printf("\n-------------------------------------------------------------------------------\n");
prompt: printf("\nMessage to: ");
gets(user_name, SLEN);
if ((strcmp(user_name,"quit") == 0) ||
(strcmp(user_name,"exit") == 0) ||
(strcmp(user_name,"done") == 0) ||
(strcmp(user_name,"bye") == 0))
exit(0);
if (translate(user_name, name) == 0)
goto prompt;
address = get_alias_address(name, 1, 0);
if (strlen(address) == 0) {
printf("Sorry, could not find '%s' [%s] in list!\n", user_name,
name);
goto prompt;
}
sprintf(tempfile, "%s%d", temp_file, msgnum++);
if ((fd = fopen(tempfile,"w")) == NULL)
exit(printf("** Fatal Error: could not open %s to write\n",
tempfile));
printf("\nEnter message for %s ending with a blank line.\n\n",
user_name);
fprintf(fd,"\n\n");
do {
printf("> ");
if (! (eof = (gets(buffer, SLEN) == NULL)))
fprintf(fd, "%s\n", buffer);
} while (! eof && strlen(buffer) > 0);
fclose(fd);
sprintf(buffer, "(%s -s \"While You Were Out\" %s < %s ; %s %s) &",
mailx, address, tempfile, remove, tempfile);
system(buffer);
}
}
int
translate(fullname, name)
char *fullname, *name;
{
/** translate fullname into name..
'first last' translated to first_initial - underline - last
'initial last' translated to initial - underline - last
Return 0 if error.
**/
register int i, lastname = 0;
for (i=0; i < strlen(fullname); i++) {
if (isupper(fullname[i]))
fullname[i] = fullname[i] - 'A' + 'a';
if (fullname[i] == ' ')
if (lastname) {
printf(
"** Can't have more than 'FirstName LastName' as address!\n");
return(0);
}
else
lastname = i+1;
}
if (lastname)
sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
else
strcpy(name, fullname);
return(1);
}
read_alias_files()
{
/** read the user alias file **/
char fname[SLEN];
int hash;
sprintf(fname, "%s/.alias_hash", getenv("HOME"));
if ((hash = open(fname, O_RDONLY)) == -1)
exit(printf("** Fatal Error: Could not open %s!\n", fname));
read(hash, user_hash_table, sizeof user_hash_table);
close(hash);
sprintf(fname, "%s/.alias_data", getenv("HOME"));
if ((user_data = open(fname, O_RDONLY)) == -1)
return;
}
char *get_alias_address(name, mailing, depth)
char *name;
int mailing, depth;
{
/** return the line from either datafile that corresponds
to the specified name. If 'mailing' specified, then
fully expand group names. Returns NULL if not found.
Depth is the nesting depth, and varies according to the
nesting level of the routine. **/
static char buffer[VERY_LONG_STRING];
int loc;
if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
lseek(user_data, user_hash_table[loc].byte, 0L);
get_line(user_data, buffer, LONG_STRING);
if (buffer[0] == '!' && mailing)
return( (char *) expand_group(buffer, depth));
else
return( (char *) buffer);
}
return( (char *) NULL);
}
char *expand_group(members, depth)
char *members;
int depth;
{
/** given a group of names separated by commas, this routine
will return a string that is the full addresses of each
member separated by spaces. Depth is the current recursion
depth of the expansion (for the 'get_token' routine) **/
char buffer[VERY_LONG_STRING];
char buf[LONG_STRING], *word, *address, *bufptr;
strcpy(buf, members); /* parameter safety! */
buffer[0] = '\0'; /* nothing in yet! */
bufptr = (char *) buf; /* grab the address */
depth++; /* one more deeply into stack */
while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
fprintf(stderr, "Alias %s not found for group expansion!", word);
return( (char *) NULL);
}
else if (strcmp(buffer,address) != 0) {
sprintf(buffer,"%s %s", buffer, address);
}
bufptr = NULL;
}
return( (char *) buffer);
}
int
find(word, table, size)
char *word;
struct alias_rec table[];
int size;
{
/** find word and return loc, or -1 **/
register int loc;
if (strlen(word) > 20)
exit(printf("Bad alias name: %s. Too long.\n", word));
loc = hash_it(word, size);
while (strcmp(word, table[loc].name) != 0) {
if (table[loc].name[0] == '\0')
return(-1);
loc = (loc + 1) % size;
}
return(loc);
}
int
hash_it(string, table_size)
char *string;
int table_size;
{
/** compute the hash function of the string, returning
it (mod table_size) **/
register int i, sum = 0;
for (i=0; string[i] != '\0'; i++)
sum += (int) string[i];
return(sum % table_size);
}
get_line(fd, buffer)
int fd;
char *buffer;
{
/* read from file fd. End read upon reading either
EOF or '\n' character (this is where it differs
from a straight 'read' command!) */
register int i= 0;
char ch;
while (read(fd, &ch, 1) > 0)
if (ch == '\n' || ch == '\r') {
buffer[i] = 0;
return;
}
else
buffer[i++] = ch;
}
print_long(buffer, init_len)
char *buffer;
int init_len;
{
/** print buffer out, 80 characters (or less) per line, for
as many lines as needed. If 'init_len' is specified,
it is the length that the first line can be.
**/
register int i, loc=0, space, length;
/* In general, go to 80 characters beyond current character
being processed, and then work backwards until space found! */
length = init_len;
do {
if (strlen(buffer) > loc + length) {
space = loc + length;
while (buffer[space] != ' ' && space > loc + 50) space--;
for (i=loc;i <= space;i++)
putchar(buffer[i]);
putchar('\n');
loc = space;
}
else {
for (i=loc;i < strlen(buffer);i++)
putchar(buffer[i]);
putchar('\n');
loc = strlen(buffer);
}
length = 80;
} while (loc < strlen(buffer));
}
/****
The following is a newly chopped version of the 'strtok' routine
that can work in a recursive way (up to 20 levels of recursion) by
changing the character buffer to an array of character buffers....
****/
#define MAX_RECURSION 20 /* up to 20 deep recursion */
#undef NULL
#define NULL (char *) 0 /* for this routine only */
extern int strspn();
extern char *strpbrk();
char *get_token(string, sepset, depth)
char *string, *sepset;
int depth;
{
/** string is the string pointer to break up, sepstr are the
list of characters that can break the line up and depth
is the current nesting/recursion depth of the call **/
register char *p, *q, *r;
static char *savept[MAX_RECURSION];
/** is there space on the recursion stack? **/
if (depth >= MAX_RECURSION) {
fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n",
MAX_RECURSION);
exit(1);
}
/* set up the pointer for the first or subsequent call */
p = (string == NULL)? savept[depth]: string;
if(p == 0) /* return if no tokens remaining */
return(NULL);
q = p + strspn(p, sepset); /* skip leading separators */
if (*q == '\0') /* return if no tokens remaining */
return(NULL);
if ((r = strpbrk(q, sepset)) == NULL) /* move past token */
savept[depth] = 0; /* indicate this is last token */
else {
*r = '\0';
savept[depth] = ++r;
}
return(q);
}
END-OF-FILE
size=`wc -c < utils/answer.c`
if [ $size != 8207 ]
then
echo Warning: utils/answer.c changed - should be 8207 bytes, not $size bytes
fi
chmod 644 utils/answer.c
# ---------- file utils/arepdaemon.c ----------
if [ -f utils/arepdaemon.c ]
then
echo File 'utils/arepdaemon.c' already exists\!
exit 1
fi
echo extracting file utils/arepdaemon.c...
cat << 'END-OF-FILE' > utils/arepdaemon.c
/** arepdaemon.c **/
/** (C) Copyright 1986 Dave Taylor **/
/** Keep track of mail as it arrives, and respond by sending a 'recording'
file to the sender as new mail is received.
Note: the user program that interacts with this program is the
'autoreply' program and that should be consulted for further
usage information.
This program is part of the 'autoreply' system, and is designed
to run every hour and check all mailboxes listed in the file
"/etc/autoreply.data", where the data is in the form:
username replyfile current-mailfile-size
To avoid a flood of autoreplies, this program will NOT reply to mail
that contains header "X-Mailer: fastmail". Further, each time the
program responds to mail, the 'mailfile size' entry is updated in
the file /etc/autoreply.data to allow the system to be brought
down and rebooted without any loss of data or duplicate messages.
This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep,
to ensure that more than one copy of itself is never running. For this
reason, it is recommended that this daemon be started up each morning
from cron, since it will either start since it's needed or simply see
that the file is there and disappear.
Since this particular program is the main daemon answering any
number of different users, it must be run with uid root.
(C) 1985, Dave Taylor, HP Colorado Networks Operation
**/
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "defs.h"
#define arep_lock_file "/usr/spool/uucp/LCK..arep"
#define autoreply_file "/etc/autoreply.data"
#define fastmail "/usr/local/bin/fastmail"
#define logfile "/etc/autoreply.log" /* first choice */
#define logfile2 "/tmp/autoreply.log" /* second choice */
#define BEGINNING 0 /* see fseek(3S) for info */
#define SLEEP_TIME 3600 /* run once an hour */
#define MAX_PEOPLE 20 /* max number in program */
#define EXISTS 00 /* lock file exists?? */
#define MODE 0777 /* lockfile creation mode */
#define NLEN 20
#define remove_return(s) if (strlen(s) > 0) { \
if (s[strlen(s)-1] == '\n') \
s[strlen(s)-1] = '\0'; \
}
struct replyrec {
char username[NLEN]; /* login name of user */
char mailfile[SLEN]; /* name of mail file */
char replyfile[SLEN]; /* name of reply file */
long mailsize; /* mail file size */
int in_list; /* for new replies */
} reply_table[MAX_PEOPLE];
FILE *logfd; /* logfile (log action) */
long autoreply_size = 0L; /* size of autoreply file */
int active = 0; /* # of people 'enrolled' */
FILE *open_logfile(); /* forward declaration */
long bytes(); /* ditto */
main()
{
long size;
int person, data_changed;
if (! lock())
exit(0); /* already running! */
while (1) {
logfd = open_logfile(); /* open the log */
/* 1. check to see if autoreply table has changed.. */
if ((size = bytes(autoreply_file)) != autoreply_size) {
read_autoreply_file();
autoreply_size = size;
}
/* 2. now for each active person... */
data_changed = 0;
for (person = 0; person < active; person++) {
if ((size = bytes(reply_table[person].mailfile)) !=
reply_table[person].mailsize) {
if (size > reply_table[person].mailsize)
read_newmail(person);
/* else mail removed - resync */
reply_table[person].mailsize = size;
data_changed++;
}
}
/* 3. if data changed, update autoreply file */
if (data_changed)
update_autoreply_file();
close_logfile(); /* close the logfile again */
/* 4. Go to sleep... */
sleep(SLEEP_TIME);
}
}
int
read_autoreply_file()
{
/** We're here because the autoreply file has changed size!! It
could either be because someone has been added or because
someone has been removed...since the list will always be in
order (nice, eh?) we should have a pretty easy time of it...
**/
FILE *file;
char username[SLEN], replyfile[SLEN];
int person;
long size;
log("Autoreply data file has changed! Reading...");
if ((file = fopen(autoreply_file,"r")) == NULL) {
log("No-one is using autoreply...");
return(0);
}
for (person = 0; person < active; person++)
reply_table[person].in_list = 0;
while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) {
/* check to see if this person is already in the list */
if ((person = in_list(username)) != -1) {
reply_table[person].in_list = 1;
reply_table[person].mailsize = size; /* sync */
}
else { /* if not, add them */
if (active == MAX_PEOPLE) {
unlock();
exit(log("Couldn't add %s - already at max people!",
username));
}
log("adding %s to the active list", username);
strcpy(reply_table[active].username, username);
sprintf(reply_table[active].mailfile, "/usr/mail/%s", username);
strcpy(reply_table[active].replyfile, replyfile);
reply_table[active].mailsize = size;
reply_table[active].in_list = 1; /* obviously! */
active++;
}
}
/** now check to see if anyone has been removed... **/
for (person = 0; person < active; person++)
if (reply_table[person].in_list == 0) {
log("removing %s from the active list",
reply_table[person].username);
strcpy(reply_table[person].username,
reply_table[active-1].username);
strcpy(reply_table[person].mailfile,
reply_table[active-1].mailfile);
strcpy(reply_table[person].replyfile,
reply_table[active-1].replyfile);
reply_table[person].mailsize = reply_table[active-1].mailsize;
active--;
}
}
update_autoreply_file()
{
/** update the entries in the autoreply file... **/
FILE *file;
register int person;
if ((file = fopen(autoreply_file,"w")) == NULL) {
log("Couldn't update autoreply file!");
return;
}
for (person = 0; person < active; person++)
fprintf(file, "%s %s %ld\n",
reply_table[person].username,
reply_table[person].replyfile,
reply_table[person].mailsize);
fclose(file);
printf("updated autoreply file\n");
autoreply_size = bytes(autoreply_file);
}
int
in_list(name)
char *name;
{
/** search the current active reply list for the specified username.
return the index if found, or '-1' if not. **/
register int index;
for (index = 0; index < active; index++)
if (strcmp(name, reply_table[index].username) == 0)
return(index);
return(-1);
}
read_newmail(person)
int person;
{
/** Read the new mail for the specified person. **/
FILE *mailfile;
char from_whom[LONG_SLEN], subject[SLEN];
int sendit;
log("New mail for %s", reply_table[person].username);
if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL)
return(log("can't open mailfile for user %s",
reply_table[person].username));
if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1)
return(log("couldn't seek to %ld in mail file!",
reply_table[person].mailsize));
while (get_return(mailfile, person, from_whom, subject, &sendit) != -1)
if (sendit)
reply_to_mail(person, from_whom, subject);
return;
}
int
get_return(file, person, from, subject, sendit)
FILE *file;
int person, *sendit;
char *from, *subject;
{
/** Reads the new message and return the from and subject lines.
sendit is set to true iff it isn't a machine generated msg
**/
char name1[SLEN], name2[SLEN], lastname[SLEN];
char buffer[LONG_SLEN], hold_return[NLEN];
int done = 0, in_header = 0;
from[0] = '\0';
*sendit = 1;
while (! done) {
if (fgets(buffer, LONG_SLEN, file) == NULL)
return(-1);
if (first_word(buffer, "From ")) {
in_header++;
sscanf(buffer, "%*s %s", hold_return);
}
else if (in_header) {
if (first_word(buffer, ">From")) {
sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2);
add_site(from, name2, lastname);
}
else if (first_word(buffer,"Subject:")) {
remove_return(buffer);
strcpy(subject, (char *) (buffer + 8));
}
else if (first_word(buffer,"X-Mailer: fastmail"))
*sendit = 0;
else if (strlen(buffer) == 1)
done = 1;
}
}
if (from[0] == '\0')
strcpy(from, hold_return); /* default address! */
else
add_site(from, name1, lastname); /* get the user name too! */
return(0);
}
add_site(buffer, site, lastsite)
char *buffer, *site, *lastsite;
{
/** add site to buffer, unless site is 'uucp', or the same as
lastsite. If not, set lastsite to site.
**/
char local_buffer[LONG_SLEN], *strip_parens();
if (strcmp(site, "uucp") != 0)
if (strcmp(site, lastsite) != 0) {
if (buffer[0] == '\0')
strcpy(buffer, strip_parens(site)); /* first in list! */
else {
sprintf(local_buffer,"%s!%s", buffer, strip_parens(site));
strcpy(buffer, local_buffer);
}
strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */
}
}
remove_first_word(string)
char *string;
{ /** removes first word of string, ie up to first non-white space
following a white space! **/
register int loc;
for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++)
;
while (string[loc] == ' ' || string[loc] == '\t')
loc++;
move_left(string, loc);
}
move_left(string, chars)
char string[];
int chars;
{
/** moves string chars characters to the left DESTRUCTIVELY **/
register int i;
chars--; /* index starting at zero! */
for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
string[i-chars] = string[i];
string[i-chars] = '\0';
}
reply_to_mail(person, from, subject)
int person;
char *from, *subject;
{
/** Respond to the message from the specified person with the
specified subject... **/
char buffer[SLEN];
if (strlen(subject) == 0)
strcpy(subject, "Auto-reply Mail");
else if (! first_word(subject,"Auto-reply")) {
sprintf(buffer, "Auto-reply to:%s", subject);
strcpy(subject, buffer);
}
log("auto-replying to '%s'", from);
mail(from, subject, reply_table[person].replyfile, person);
}
reverse(string)
char *string;
{
/** reverse string... pretty trivial routine, actually! **/
char buffer[SLEN];
register int i, j = 0;
for (i = strlen(string)-1; i >= 0; i--)
buffer[j++] = string[i];
buffer[j] = '\0';
strcpy(string, buffer);
}
long
bytes(name)
char *name;
{
/** return the number of bytes in the specified file. This
is to check to see if new mail has arrived.... **/
int ok = 1;
extern int errno; /* system error number! */
struct stat buffer;
if (stat(name, &buffer) != 0)
if (errno != 2) {
unlock();
exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
}
else
ok = 0;
return(ok ? buffer.st_size : 0);
}
mail(to, subject, filename, person)
char *to, *subject, *filename;
int person;
{
/** Mail 'file' to the user from person... **/
char buffer[VERY_LONG_STRING];
sprintf(buffer, "%s -f '%s [autoreply]' -s '%s' %s %s",
fastmail, reply_table[person].username,
subject, filename, to);
system(buffer);
}
log(message, arg)
char *message;
char *arg;
{
/** Put log entry into log file. Use the format:
date-time: <message>
**/
struct tm *localtime(), *thetime;
long time(), clock;
char buffer[SLEN];
/** first off, get the time and date **/
clock = time((long *) 0); /* seconds since ??? */
thetime = localtime(&clock); /* and NOW the time... */
/** then put the message out! **/
sprintf(buffer, message, arg);
fprintf(logfd,"%d/%d-%d:%02d: %s\n",
thetime->tm_mon+1, thetime->tm_mday,
thetime->tm_hour, thetime->tm_min,
buffer);
}
FILE *open_logfile()
{
/** open the logfile. returns a valid file descriptor **/
FILE *fd;
if ((fd = fopen(logfile, "a")) == 0)
if ((fd = fopen(logfile2, "a")) == 0) {
unlock();
exit(1); /* give up! */
}
return( (FILE *) fd);
}
close_logfile()
{
/** Close the logfile until needed again. **/
fclose(logfd);
}
char *strip_parens(string)
char *string;
{
/** Return string with all parenthesized information removed.
This is a non-destructive algorithm... **/
static char buffer[LONG_SLEN];
register int i, depth = 0, buffer_index = 0;
for (i=0; i < strlen(string); i++) {
if (string[i] == '(')
depth++;
else if (string[i] == ')')
depth--;
else if (depth == 0)
buffer[buffer_index++] = string[i];
}
buffer[buffer_index] = '\0';
return( (char *) buffer);
}
/*** LOCK and UNLOCK - ensure only one copy of this daemon running at any
given time by using a file existance semaphore (wonderful stuff!) ***/
lock()
{
/** Try to create the lock file. If it's there, or we can't
create it for some stupid reason, return zero, otherwise,
a non-zero return code indicates success in locking this
process in. **/
if (access(arep_lock_file, EXISTS) == 0)
return(0); /* file already exists!! */
if (creat(arep_lock_file, MODE) == -1)
return(0); /* can't create file!! */
return(1);
}
unlock()
{
/** remove lock file if it's there! **/
(void) unlink(arep_lock_file);
}
END-OF-FILE
size=`wc -c < utils/arepdaemon.c`
if [ $size != 13340 ]
then
echo Warning: utils/arepdaemon.c changed - should be 13340 bytes, not $size bytes
fi
chmod 644 utils/arepdaemon.c
# ---------- file utils/autoreply.c ----------
if [ -f utils/autoreply.c ]
then
echo File 'utils/autoreply.c' already exists\!
exit 1
fi
echo extracting file utils/autoreply.c...
cat << 'END-OF-FILE' > utils/autoreply.c
/** autoreply.c **/
/** This is the front-end for the autoreply system, and performs two
functions: it either adds the user to the list of people using the
autoreply function (starting the daemon if no-one else) or removes
a user from the list of people.
Usage: autoreply filename
autoreply "off"
or autoreply [to find current status]
(C) 1986, Dave Taylor
**/
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#define SLEN 80 /* a normal string */
#define NLEN 20 /* a short string */
#define READ_ACCESS 04 /* is file readable? */
#define mailhome "/usr/mail" /* where new mail lives */
#define tempdir "/tmp/arep" /* file prefix */
#define autoreply_file "/etc/autoreply.data" /* autoreply data file */
extern int errno; /* system error code */
char username[NLEN]; /* login name of user */
main(argc, argv)
int argc;
char *argv[];
{
char filename[SLEN];
if (argc > 2) {
printf("Usage: %s <filename>\tto start autoreply,\n", argv[0]);
printf(" %s off\t\tto turn off autoreply\n", argv[0]);
printf(" or %s \t\tto check current status\n", argv[0]);
exit(1);
}
(void) cuserid(username);
if (strcmp(argv[1], "off") == 0 || argc == 1)
remove_user((argc == 1));
else {
strcpy(filename, argv[1]);
if (access(filename,READ_ACCESS) != 0) {
printf("Error: Can't read file '%s'\n", filename);
exit(1);
}
if (filename[0] != '/') /* prefix home directory */
sprintf(filename,"%s/%s", getenv("HOME"), argv[1]);
add_user(filename);
}
exit(0);
}
remove_user(stat_only)
int stat_only;
{
/** Remove the user from the list of currently active autoreply
people. If 'stat_only' is set, then just list the name of
the file being used to autoreply with, if any. **/
FILE *temp, *repfile;
char tempfile[SLEN], user[SLEN], filename[SLEN];
int c, copied = 0, found = 0;
long filesize, bytes();
if (! stat_only) {
sprintf(tempfile, "%s.%06d", tempdir, getpid());
if ((temp = fopen(tempfile, "w")) == NULL) {
printf("Error: couldn't open tempfile '%s'. Not removed\n",
tempfile);
exit(1);
}
}
if ((repfile = fopen(autoreply_file, "r")) == NULL) {
if (stat_only) {
printf("You're not currently autoreplying to mail.\n");
exit(0);
}
printf("No-one is autoreplying to their mail!\n");
exit(0);
}
/** copy out of real replyfile... **/
while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF)
if (strcmp(user, username) != 0) {
if (! stat_only) {
copied++;
fprintf(tempfile, "%s %s %ld\n", user, filename, filesize);
}
}
else {
if (stat_only) {
printf("You're currently autoreplying to mail with the file %s\n", filename);
exit(0);
}
found++;
}
fclose(temp);
fclose(repfile);
if (! found) {
printf("You're not currently autoreplying to mail%s\n",
stat_only? "." : "!");
if (! stat_only)
unlink(tempfile);
exit(! stat_only);
}
/** now copy tempfile back into replyfile **/
if (copied == 0) { /* removed the only person! */
unlink(autoreply_file);
}
else { /* save everyone else */
if ((temp = fopen(tempfile,"r")) == NULL) {
printf("Error: couldn't reopen tempfile '%s'. Not removed.\n",
tempfile);
unlink(tempfile);
exit(1);
}
if ((repfile = fopen(autoreply_file, "w")) == NULL) {
printf(
"Error: couldn't reopen autoreply file for writing! Not removed.\n");
unlink(tempfile);
exit(1);
}
while ((c = getc(temp)) != EOF)
putc(c, repfile);
fclose(temp);
fclose(repfile);
}
unlink(tempfile);
if (found > 1)
printf("Warning: your username appeared %d times!! Removed all\n",
found);
else
printf("You've been removed from the autoreply table.\n");
}
add_user(filename)
char *filename;
{
/** add the user to the autoreply file... **/
FILE *repfile;
char mailfile[SLEN];
long bytes();
if ((repfile = fopen(autoreply_file, "a")) == NULL) {
printf("Error: couldn't open the autoreply file! Not added\n");
exit(1);
}
sprintf(mailfile,"%s/%s", mailhome, username);
fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile));
fclose(repfile);
printf("You've been added to the autoreply system.\n");
}
long
bytes(name)
char *name;
{
/** return the number of bytes in the specified file. This
is to check to see if new mail has arrived.... **/
int ok = 1;
extern int errno; /* system error number! */
struct stat buffer;
if (stat(name, &buffer) != 0)
if (errno != 2)
exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
else
ok = 0;
return(ok ? buffer.st_size : 0L);
}
END-OF-FILE
size=`wc -c < utils/autoreply.c`
if [ $size != 4840 ]
then
echo Warning: utils/autoreply.c changed - should be 4840 bytes, not $size bytes
fi
chmod 644 utils/autoreply.c
echo done
exit 0
More information about the Mod.sources
mailing list