home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume6
/
elm
/
part08
< prev
next >
Wrap
Text File
|
1986-11-30
|
60KB
|
2,420 lines
Subject: v06i033: Elm mail system (elm), Part08/14
Newsgroups: mod.sources
Approved: rs@mirror.UUCP
Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor>
Mod.sources: Volume 6, Issue 33
Archive-name: elm/Part08
# Continuation of Shell Archive, created by hpldat!taylor
# This is part 8
# 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
if [ ! -d src ]
then
echo creating directory src
mkdir src
fi
# ---------- file src/utils.c ----------
filename="src/utils.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/utils.c...
fi
cat << 'END-OF-FILE' > $filename
/** utils.c **/
/** Utility routines for ELM
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>
emergency_exit()
{
/** used in dramatic cases when we must leave without altering
ANYTHING about the system... **/
dprint0(1,
"\nERROR: Something dreadful is happening! Taking emergency exit!!\n\n");
dprint0(1," possibly leaving behind the following files;\n");
dprint2(1," The mailbox tempfile : %s%s\n", temp_mbox, username);
dprint2(1," The mailbox lock file: %s%s.lock\n", mailhome, username);
dprint2(1," The composition file : %s%d\n", temp_file, getpid());
dprint2(1," The header comp file : %s%d\n", temp_file, getpid()+1);
dprint2(1," The readmsg data file: %s/%s\n", home, readmsg_file);
Raw(OFF);
if (cursor_control) transmit_functions(OFF);
if (hp_terminal) softkeys_off();
if (cursor_control)
MoveCursor(LINES, 0);
PutLine0(LINES,0, "\nEmergency Exit taken! All temp files intact!\n\n");
exit(1);
}
leave(val)
int val; /* not used, placeholder for signal catching! */
{
char buffer[SLEN];
dprint0(2,"\nLeaving mailer normally (leave)\n");
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);
sprintf(buffer,"%s/%s", home, readmsg_file); /* readmsg temp */
(void) unlink(buffer);
sprintf(buffer,"%s%s.lock",mailhome, username); /* lock file */
(void) unlink(buffer);
if (! mail_only) {
MoveCursor(LINES,0);
Writechar('\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];
dprint0(3,
"\nLeaving mailer due to presence of lock file (leave_locked)\n");
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,0);
Writechar('\n');
exit(0);
}
int
get_page(msg_pointer)
int msg_pointer;
{
/** 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 (msg_pointer > last_on_page) {
header_page = (int) (msg_pointer-1) / headers_per_page;
return(1);
}
else if (msg_pointer < first_on_page) {
header_page = (int) (msg_pointer-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;
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
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 3786 ]
then
echo $filename changed - should be 3786 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/validname.c ----------
filename="src/validname.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/validname.c...
fi
cat << 'END-OF-FILE' > $filename
/** 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! **/
#ifdef NOCHECK_VALIDNAME
return(1); /* always say it's okay! */
#else
char filebuf[SLEN];
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
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 706 ]
then
echo $filename changed - should be 706 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/syscall.c ----------
filename="src/syscall.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/syscall.c...
fi
cat << 'END-OF-FILE' > $filename
/** 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;
PutLine0(LINES-3,COLUMNS-40,"(use the shell name for a shell)");
PutLine0(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);
PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
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(2,"System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell,
string);
#ifdef NO_VM /* machine without virtual memory! */
if ((pid = fork()) == 0) {
#else
if ((pid = vfork()) == 0) {
#endif
setuid(userid); /* back to the normal user! */
setgid(groupid); /* and group id */
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
do_pipe()
{
/** pipe the tagged messages to the specified sequence.. **/
char command[SLEN], buffer[LONG_SLEN], message_list[SLEN];
register int ret, tagged = 0, oldstat, i;
message_list[0] = '\0'; /* NULL string to start... */
for (i=0; i < message_count; i++)
if (ison(header_table[i].status, TAGGED)) {
sprintf(message_list,"%s %d", message_list,
header_table[i].index_number);
tagged++;
}
if (tagged > 1)
PutLine0(LINES-2,0,"Pipe tagged msgs to: ");
else if (tagged)
PutLine0(LINES-2,0,"Pipe tagged msg to : ");
else {
PutLine0(LINES-2,0,"Pipe current msg to: ");
sprintf(message_list,"%d", header_table[current-1].index_number);
}
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);
if (cursor_control) transmit_functions(OFF);
sprintf(buffer, "%s -f %s -h %s | %s",
readmsg,
infile,
message_list,
command);
ret = system_call(buffer, USER_SHELL);
PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
Raw(ON);
(void) getchar();
if (cursor_control) transmit_functions(ON);
if (ret != 0) error1("Return code was %d", ret);
return(1);
}
printmsg()
{
/** Print current message or tagged messages using 'printout'
variable. Error message iff printout not defined! **/
char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN];
char message_list[SLEN];
register int retcode, tagged = 0, oldstat, i;
if (strlen(printout) == 0) {
error("Don't know how to print - option \"printmail\" undefined!");
return;
}
message_list[0] = '\0'; /* reset to null... */
for (i=0; i < message_count; i++)
if (header_table[i].status & TAGGED) {
sprintf(message_list, "%s %d", message_list,
header_table[i].index_number);
tagged++;
}
if (! tagged)
sprintf(message_list," %d", header_table[current-1].index_number);
sprintf(filename,"%s%d", temp_print, getpid());
if (in_string(printout, "%s"))
sprintf(printbuffer, printout, filename);
else
sprintf(printbuffer, "%s %s", printout, filename);
sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
readmsg, infile, message_list,
filename,
printbuffer);
dprint0(2,"Printing system call...\n");
Centerline(LINES, "queueing...");
if ((retcode = system_call(buffer, SH)) == 0) {
sprintf(buffer, "Message%s queued up to print", plural(tagged));
Centerline(LINES, buffer);
}
else
error1("Printout failed with return code %d", retcode);
unlink(filename); /* remove da temp file! */
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 4692 ]
then
echo $filename changed - should be 4692 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/aliaslib.c ----------
filename="src/aliaslib.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/aliaslib.c...
fi
cat << 'END-OF-FILE' > $filename
/** aliaslib.c **/
/** Library of functions dealing with the alias system...
(C) Copyright 1986 Dave Taylor
**/
#include "headers.h"
char *expand_group(), *get_alias_address(), *expand_system();
char *get_token(), *strpbrk();
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. Depth specifies the nesting
depth - the routine should always initially be called
with this equal 0. Returns NULL if not found **/
static char buffer[VERY_LONG_STRING];
int loc;
if (strlen(name) == 0)
return( (char *) NULL);
if (user_files)
if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
lseek(user_data, user_hash_table[loc].byte, 0L);
get_line(user_data, buffer);
if (buffer[0] == '!' && mailing)
return(expand_group(buffer, depth));
else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */
return(expand_system(buffer, TRUE));
else
return((char *) buffer);
}
if (system_files)
if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
lseek(system_data, system_hash_table[loc].byte, 0L);
get_line(system_data, buffer);
if (buffer[0] == '!' && mailing)
return(expand_group(buffer, depth));
else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */
return(expand_system(buffer, TRUE));
else
return((char *) buffer);
}
return( (char *) NULL);
}
char *expand_system(buffer, show_errors)
char *buffer;
int show_errors;
{
/** This routine will check the first machine name in the given path
(if any) and expand it out if it is an alias...if not, it will
return what it was given. If show_errors is false, it won't
display errors encountered...
**/
dprint2(6, "expand_system(%s, show-errors=%s)\n", buffer,
onoff(show_errors));
findnode(buffer, show_errors);
return( (char *) buffer);
}
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 an internal counter
that keeps track of the depth of nesting that the routine
is in...it's for the get_token routine! **/
static char buffer[VERY_LONG_STRING];
char buf[LONG_STRING], *word, *address, *bufptr;
strcpy(buf, members); /* parameter safety! */
if (depth == 0) buffer[0] = '\0'; /* nothing in yet! */
bufptr = (char *) buf; /* grab the address */
depth++; /* one deeper! */
while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
if ((address = get_alias_address(word, 1, depth)) == NULL) {
if (! valid_name(word)) {
dprint2(3, "Encountered illegal address %s (%s)\n",
word, "expand_group");
error1("%s is an illegal address!", word);
return( (char *) NULL);
}
else if (strcmp(buffer, word) != 0)
sprintf(buffer, "%s%s%s", buffer,
(strlen(buffer) > 0)? ", ":"", word);
}
else if (strcmp(buffer, address) != 0)
sprintf(buffer,"%s%s%s", buffer,
(strlen(buffer) > 0)? ", ":"", 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) {
dprint2(3, "Too long alias name entered [%s] (%s)\n", word, "find");
error1("Bad alias name: %s. Too long.\n", word);
return(-1);
}
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;
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 4476 ]
then
echo $filename changed - should be 4476 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/domains.c ----------
filename="src/domains.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/domains.c...
fi
cat << 'END-OF-FILE' > $filename
/** domains.c **/
/** This file contains all the code dealing with the expansion of
domain based addresses in Elm. It uses the file "domains" as
defined in the sysdefs.h file.
(C) Copyright 1986 Dave Taylor
From a file format and idea in "uumail" - designed by Stan Barber.
**/
#include <stdio.h>
#include <ctype.h>
#include "headers.h"
/** define the various characters that we can encounter after a "%" sign
in the template file...
**/
#define USERNAME 'U' /* %U = the name of the remote user */
#define HOSTNAME 'N' /* %N = the remote machine name */
#define FULLNAME 'D' /* %D = %N + domain info given */
#define NPATH 'R' /* %R = path to %N from pathalias */
#define PPATH 'P' /* %P = path to 'P' from pathalias */
#define OBSOLETE 'S' /* %S = (used to be suffix string) */
/** and finally some characters that are allowed in user/machine names **/
#define okay_others(c) (c == '-' || c == '^' || c == '$' || c == '_')
/** and some allowed ONLY in the username field **/
#define special_chars(c) (c == '%' || c == ':')
char *find_path_to(), *expand_domain(), *match_and_expand_domain();
open_domain_file()
{
if ((domainfd = fopen(domains, "r")) == NULL) {
dprint1(1, "Can't open file %s as domains file (open_domain_file)\n",
domains);
}
else {
dprint1(2,
"\nOpened '%s' as the domain database. (open_domain_file)\n\n",
domains);
}
/* if it fails it'll instantiate domainfd to NULL which is
exactly what we want to have happen!! */
}
char *expand_domain(buffer)
char *buffer;
{
/** Expand the address 'buffer' based on the domain information,
if any. Returns NULL if it can't expand it for any reason.
**/
char name[2*NLEN], address[2*NLEN], domain[2*NLEN];
char *match_and_expand_domain();
if (domainfd == NULL) return(NULL); /* no file present! */
if (explode(buffer, name, address, domain))
return( match_and_expand_domain(domain, name, address) );
else { /* invalid format - not "user@host.domain" */
dprint1(3,
"Invalid format for domain expansion: %s (expand_domain)\n",
buffer);
return(NULL);
}
}
int
explode(buffer, name, address, domain)
char *buffer, *name, *address, *domain;
{
/** Break buffer, if in format name@machine.domain, into the
component parts, otherwise return ZERO and don't worry
about the values of the parameters!
**/
register int i, j = 0;
/** First get the name... **/
for (i=0; buffer[i] != '@'; i++) {
if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && !
special_chars(buffer[i]))
return(0); /* invalid character in string! */
name[i] = buffer[i];
}
name[i++] = '\0';
/** now let's get the machinename **/
while (buffer[i] != '.') {
if (! isalnum(buffer[i]) && ! okay_others(buffer[i]))
return(0); /* invalid character in string! */
address[j++] = buffer[i++];
}
address[j] = '\0';
j = 0;
/** finally let's get the domain information (there better be some!) **/
while (buffer[i] != '\0') {
if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) &&
buffer[i] != '.')
return(0); /* an you fail again, bozo! */
domain[j++] = toupper(buffer[i]);
i++;
}
domain[j] = '\0';
return(j); /* if j == 0 there's no domain info! */
}
char *match_and_expand_domain(domain, name, machine)
char *domain, *name, *machine;
{
/** Given the domain, try to find it in the domain file and
if found expand the entry and return the result as a
character string...
**/
static char address[SLEN];
char buffer[SLEN], domainbuff[NLEN];
char field1[2*NLEN], field2[2*NLEN], field3[2*NLEN];
char *path, *template, *expanded, *mydomain;
int matched = 0, in_percent = 0;
register int i, j = 0;
address[j] = '\0';
domainbuff[0] = '\0';
mydomain = (char *) domainbuff; /* set up buffer etc */
do {
rewind(domainfd); /* back to ground zero! */
if (strlen(mydomain) > 0) { /* already in a domain! */
mydomain++; /* skip leading '.' */
while (*mydomain != '.' && *mydomain != ',')
mydomain++; /* next character */
if (*mydomain == ',')
return (NULL); /* didn't find domain! */
}
else
sprintf(mydomain, "%s,", domain); /* match ENTIRELY! */
/* whip through file looking for the entry, please... */
while (fgets(buffer, SLEN, domainfd) != NULL) {
if (buffer[0] == '#') /* skip comments */
continue;
if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */
matched++; /* Gotcha! Remember this momentous event! */
break;
}
}
if (! matched)
continue; /* Nothing. Not a sausage! Step through! */
/** We've matched the domain! **/
no_ret(buffer);
(void) strtok(buffer, ","); /* skip the domain info */
strcpy(field1, strtok(NULL, ",")); /* fun */
strcpy(field2, strtok(NULL, ",")); /* stuff */
strcpy(field3, strtok(NULL, ",")); /* eh? */
path = (char *) NULL;
/* now we merely need to figure out what permutation this is! */
if (field3 == NULL || strlen(field3) == 0)
if (field2 == NULL || strlen(field2) == 0)
template = (char *) field1;
else {
path = (char *) field1;
template = (char *) field2;
}
else {
dprint1(2,"Domain info for %s from file broken into THREE fields!!\n",
domain);
dprint3(2, "-> %s\n-> %s\n-> %s\n", field1, field2, field3);
error1("Warning: domain %s uses a defunct field!!", domain);
sleep(2);
path = (char *) field1;
template = (char *) field3;
}
if (strlen(path) > 0 && path[0] == '>')
path++; /* skip the '>' character, okay? */
j = 0; /* address is zero, right now, right?? */
address[j] = '\0'; /* make sure string is too! */
for (i=0; i < strlen(template); i++) {
if (template[i] == '%') {
if (! in_percent) /* just hit a NEW percent! */
in_percent = 1;
else { /* just another percent sign on the wall... */
address[j++] = '%';
address[j] = '\0'; /* ALWAYS NULL terminate */
in_percent = 0;
}
}
else if (in_percent) { /* Hey! a real command string */
in_percent = 0;
switch (template[i]) {
case USERNAME: strcat(address, name); break;
case HOSTNAME: strcat(address, machine); break;
case FULLNAME: strcat(address, machine);
strcat(address, domain); break;
case NPATH :
if ((expanded = find_path_to(machine, FALSE)) == NULL) {
dprint2(3,"\nCouldn't expand system path '%s' (%s)\n\n",
machine, "domains");
error1("Couldn't find a path to %s!", machine);
sleep(2);
return(NULL); /* failed!! */
}
strcat(address, expanded); /* isn't this fun??? */
break;
case PPATH :
if ((expanded = find_path_to(path, FALSE)) == NULL) {
dprint2(3,"\nCouldn't expand system path '%s' (%s)\n\n",
path, "domains");
error1("I Couldn't find a path to %s!", path);
sleep(2);
return(NULL); /* failed!! */
}
strcat(address, expanded); /* isn't this fun??? */
break;
case OBSOLETE: /* fall through.. */
default : dprint2(1,
"\nError: Bad sequence in template file for domain '%s': %%%c\n\n",
domain, template[i]);
}
j = strlen(address);
}
else {
address[j++] = template[i];
address[j] = '\0'; /* null terminate */
}
}
address[j] = '\0';
} while (strlen(address) < 1);
return( (char *) address);
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 7635 ]
then
echo $filename changed - should be 7635 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/fileio.c ----------
filename="src/fileio.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/fileio.c...
fi
cat << 'END-OF-FILE' > $filename
/** fileio.c **/
/** File I/O routines, including deletion from the mailbox!
(C) Copyright 1986 Dave Taylor
**/
#include "headers.h"
#include <ctype.h>
#ifdef BSD
#undef tolower
#endif
copy_message(prefix, dest_file, remove_header, remote)
char *prefix;
FILE *dest_file;
int remove_header, remote;
{
/** Copy current message to destination file, with optional 'prefix'
as the prefix for each line. If remove_header is true, it will
skip lines in the message until it finds the end of header line...
then it will start copying into the file... If remote is true
then it will append "remote from <hostname>" at the end of the
very first line of the file (for remailing) **/
char buffer[LONG_SLEN];
register int ok = 1, lines, in_header = 1, first_line = TRUE;
/** get to the first line of the message desired **/
if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
dprint2(1,"ERROR: Attempt to seek %d bytes into file failed (%s)",
header_table[current-1].offset, "copy_message");
error1("ELM [seek] failed trying to read %d bytes into file",
header_table[current-1].offset);
return;
}
/* how many lines in message? */
lines = header_table[current-1].lines;
/* now while not EOF & still in message... copy it! */
while (ok && lines--) {
ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL);
if (strlen(buffer) < 2) in_header = 0;
if (ok)
if (! (remove_header && in_header))
if (first_line && remote) {
no_ret(buffer);
fprintf(dest_file, "%s%s remote from %s\n",
prefix, buffer, hostname);
first_line = FALSE;
}
else if (! in_header && first_word(buffer, "From ")) {
dprint0(1,"\n*** Internal Problem...Tried to add the following;\n");
dprint1(1," '%s'\nto output file (copy_message) ***\n", buffer);
}
else
fprintf(dest_file, "%s%s", prefix, buffer);
}
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 1967 ]
then
echo $filename changed - should be 1967 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/return_addr.c ----------
filename="src/return_addr.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/return_addr.c...
fi
cat << 'END-OF-FILE' > $filename
/** return_addr.c **/
/** This set of routines is used to generate real return addresses
and also return addresses suitable for inclusion in a users
alias files (ie optimized based on the pathalias database).
Added: the ability to respond to messages that were originally
sent by the user (That is, the "savemail" file format messages)
by reading the return address, seeing the "To:" prefix and then
calling the "get_existing_return()" routine. Currently this does
NOT include any "Cc" lines in the message, just the "To:" line(s).
Also added the PREFER_UUCP stuff for listing reasonable addresses
and such...*sigh*
These routines (C) Copyright 1986 Dave Taylor
**/
#include "headers.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
char *shift_lower(), *notes_machine(), *expand_address();
extern int errno;
char *error_name();
optimize_return(address)
char *address;
{
/** This routine tries to create an optimized address, that is,
an address that has the minimal information needed to
route a message to this person given the current path
database...
**/
#ifdef PREFER_UUCP
/** first off, let's see if we need to strip off the localhost
address crap... **/
/** if we have a uucp part (e.g.a!b) AND the bogus address...**/
if (chloc(address,'!') != -1 && in_string(address, BOGUS_INTERNET))
address[strlen(address)-strlen(BOGUS_INTERNET)] = '\0';
#endif
/** next step is to figure out what sort of address we have... **/
if (chloc(address, '%') != -1)
optimize_cmplx_arpa(address);
else if (chloc(address, '@') != -1)
optimize_arpa(address);
else
optimize_usenet(address);
}
optimize_cmplx_arpa(address)
char *address;
{
/** Try to optimize a complex ARPA address. A Complex address is one
that contains '%' (deferred '@'). For example:
veeger!hpcnof!hplabs!joe%sytech@syte
is a complex address (no kidding, right?). The algorithm for
trying to resolve it is to move all the way to the right, then
back up left until the first '!' then from there to the SECOND
metacharacter on the right is the name@host address...(in this
example, it would be "joe%sytech"). Check this in the routing
table. If not present, keep backing out to the right until we
find a host that is present, or we hit the '@' sign. Once we
have a 'normal' ARPA address, hand it to optimize_arpa().
**/
char name[SHORT_SLEN], buffer[SLEN], junk[SLEN];
char host[SHORT_SLEN], old_host[SHORT_SLEN];
register int i, loc, nloc = 0, hloc = 0, passes = 1;
/** first off, get the name%host... **/
for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--)
;
while (address[loc] != '\0') {
if (passes == 1) {
loc++;
while (address[loc] != '%' && address[loc] != '@')
name[nloc++] = address[loc++];
}
else {
for (i=0; old_host[i] != '\0'; i++)
name[nloc++] = old_host[i];
}
loc++;
while (address[loc] != '%' && address[loc] != '@')
host[hloc++] = address[loc++];
host[hloc] = name[nloc] = '\0';
strcpy(old_host, host);
remove_domains(host);
sprintf(buffer, "%s@%s", name, shift_lower(host));
if (expand_site(buffer, junk) == 0) {
strcpy(address, buffer);
return;
}
else if (address[loc] == '@') {
optimize_arpa(address);
return;
}
else
name[nloc++] = '%'; /* for next pass through */
}
}
optimize_arpa(address)
char *address;
{
/** Get an arpa address and simplify it to the minimal
route needed to get mail to this person... **/
char name[SHORT_SLEN], buffer[SLEN], junk[SLEN];
char host[SHORT_SLEN];
register int loc, nloc = 0, hloc = 0, at_sign = 0;
for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) {
if (address[loc] == '@')
at_sign++; /* remember this spot! */
else if (at_sign)
name[nloc++] = address[loc];
else
host[hloc++] = address[loc];
}
name[nloc] = host[hloc] = '\0';
reverse(name);
reverse(host);
remove_domains(host);
sprintf(buffer,"%s@%s", name, shift_lower(host));
if (expand_site(buffer, junk) == 0) {
strcpy(address, buffer);
return;
}
optimize_usenet(address); /* that didn't work... */
}
optimize_usenet(address)
char *address;
{
/** optimize the return address IFF it's a standard usenet
address...
**/
char name[SHORT_SLEN], new_address[SLEN], buffer[SLEN], junk[SLEN];
register int loc, nloc = 0, aloc = 0, passes = 1;
for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--)
name[nloc++] = address[loc];
name[nloc] = '\0';
reverse(name);
new_address[0] = '\0';
/* got name, now get machine until we can get outta here */
while (loc > -1) {
new_address[aloc++] = address[loc--]; /* the '!' char */
while (address[loc] != '!' && loc > -1)
new_address[aloc++] = address[loc--];
new_address[aloc] = '\0';
strcpy(buffer, new_address);
reverse(buffer);
if (expand_site(buffer, junk) == 0) {
if (passes == 1 && chloc(name, '@') == -1) {
buffer[strlen(buffer) - 1] = '\0'; /* remove '!' */
sprintf(address, "%s@%s", name, buffer);
}
else
sprintf(address, "%s%s", buffer, name);
return; /* success! */
}
passes++;
}
return; /* nothing to do! */
}
get_return(buffer)
char *buffer;
{
/** reads 'current' message again, building up the full return
address including all machines that might have forwarded
the message. **/
char buf[LONG_SLEN], name1[SLEN], name2[SLEN], lastname[SLEN];
char hold_return[LONG_SLEN], alt_name2[SLEN];
int ok = 1, lines;
/** are we reading a notesfile file?? **/
if (notesfile) {
strcpy(buf, header_table[current-1].from);
if (chloc(buf, '!') == -1)
sprintf(buf, "%s!%s", notes_machine(), header_table[current-1].from);
strcpy(buffer, expand_system(buf, TRUE));
return;
}
/** get to the first line of the message desired **/
if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
dprint3(1,"Error: seek %ld bytes into file hit errno %s (%s)",
header_table[current-1].offset, error_name(errno),
"get_return");
error2("couldn't seek %d bytes into file (%s)",
header_table[current-1].offset, error_name(errno));
return;
}
/** okay! Now we're there! **/
lines = header_table[current-1].lines;
buffer[0] = '\0';
while (ok && lines--) {
ok = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
if (first_word(buf, "From ")) {
sscanf(buf, "%*s %s", hold_return);
}
else if (first_word(buf, ">From")) {
sscanf(buf,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s %s",
name1, name2, alt_name2);
if (strcmp(name2, "from") == 0)
strcpy(name2, alt_name2);
add_site(buffer, name2, lastname);
}
#ifdef USE_EMBEDDED_ADDRESSES
else if (first_word(buf, "From:")) {
get_address_from("From:", buf, hold_return);
}
else if (first_word(buf, "Reply-To:")) {
get_address_from("Reply-To:", buf, buffer);
return;
}
#endif
else if (strlen(buf) < 2) /* done with header */
lines = 0; /* let's get outta here! We're done!!! */
}
if (buffer[0] == '\0')
strcpy(buffer, hold_return); /* default address! */
else
add_site(buffer, name1, lastname); /* get the user name too! */
if (first_word(buffer, "To:")) /* response to savecopy! */
get_existing_address(buffer);
}
get_existing_address(buffer)
char *buffer;
{
/** This routine is called when the message being responded to has
"To:xyz" as the return address, signifying that this message is
an automatically saved copy of a message previously sent. The
correct to address can be obtained fairly simply by reading the
To: header from the message itself and (blindly) copying it to
the given buffer. Note that this header can be either a normal
"To:" line (Elm) or "Originally-To:" (previous versions e.g.Msg)
**/
char mybuf[LONG_STRING];
register char ok = 1, in_to = 0;
buffer[0] = '\0';
/** first off, let's get to the beginning of the message... **/
if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
dprint3(1,"Error: seek %ld bytes into file hit errno %s (%s)",
header_table[current-1].offset, error_name(errno),
"get_existing_address");
error2("couldn't seek %d bytes into the file (%s)",
header_table[current-1].offset, error_name(errno));
return;
}
/** okay! Now we're there! **/
while (ok) {
ok = (int) (fgets(mybuf, LONG_STRING, mailfile) != NULL);
no_ret(mybuf); /* remove return character */
if (first_word(mybuf, "To: ")) {
in_to = TRUE;
strcpy(buffer, (char *) mybuf + strlen("To: "));
}
else if (first_word(mybuf, "Original-To:")) {
in_to = TRUE;
strcpy(buffer, (char *) mybuf + strlen("Original-To:"));
}
else if (in_to && whitespace(mybuf[0])) {
strcat(buffer, " "); /* tag a space in */
strcat(buffer, (char *) mybuf + 1); /* skip 1 whitespace */
}
else if (strlen(mybuf) < 2)
return; /* we're done for! */
else
in_to = 0;
}
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 9321 ]
then
echo $filename changed - should be 9321 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/addr_utils.c ----------
filename="src/addr_utils.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/addr_utils.c...
fi
cat << 'END-OF-FILE' > $filename
/** addr_utils.c **/
/** This file contains addressing utilities
(C) Copyright 1986 Dave Taylor
**/
#include "headers.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#ifdef BSD
#undef tolower
#endif
char *shift_lower(), *get_alias_address(), *get_token(), *strtok();
int
talk_to(sitename)
char *sitename;
{
/** If we talk to the specified site, return true, else
we're going to have to expand this baby out, so
return false! **/
struct lsys_rec *sysname;
sysname = talk_to_sys;
if (sysname == NULL) {
dprint0(2,
"Warning - talk_to_sys is currently set to NULL! (talk_to)\n");
return(0);
}
while (sysname != NULL) {
if (strcmp(sysname->name, sitename) == 0)
return(1);
else
sysname = sysname->next;
}
return(0);
}
remove_domains(host)
char *host;
{
/** Remove all entries following the first '.' to ensure that
entries like "MIT.ARPA" will match "MIT" in the database
**/
register int loc = 0;
while (host[loc] != '.' && host[loc] != '\0')
loc++;
if (host[loc] == '.') host[loc] = '\0';
}
add_site(buffer, site, lastsite)
char *buffer, *site, *lastsite;
{
/** add site to buffer, unless site is 'uucp', current machine, or
site is the same as lastsite. If not, set lastsite to
site.
**/
char local_buffer[LONG_SLEN];
if (strcmp(site, "uucp") != 0)
if (strcmp(site, lastsite) != 0)
if (strcmp(site, hostname) != 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! */
}
}
#ifdef USE_EMBEDDED_ADDRESSES
get_address_from(prefix, line, buffer)
char *prefix, *line, *buffer;
{
/** This routine extracts the address from either a 'From:' line
or a 'Reply-To:' line...the algorithm is quite simple, too:
increment 'line' past header, then check last character of
line. If it's a '>' then the address is contained within '<>'
and if it's a ')' then the address is in the 'clear'... **/
register int i, j = 0;
no_ret(line);
line = (char *) (line + strlen(prefix) + 1);
if (line[strlen(line)-1] == '>') {
for (i=strlen(line)-2; i > -1 && line[i] != '<'; i--)
buffer[j++] = line[i];
buffer[j] = 0;
reverse(buffer);
}
else { /* either ')' or address in the clear... */
for (i=0; i < strlen(line) && line[i] != '('; i++)
buffer[j++] = line[i];
if (buffer[j-1] == '(') j--;
buffer[j] = 0;
}
}
#endif
translate_return(addr, ret_addr)
char *addr, *ret_addr;
{
/** Return ret_addr to be the same as addr, but with the login
of the person sending the message replaced by '%s' for
future processing...
Fixed to make "%xx" "%%xx" (dumb 'C' system!)
**/
register int loc, loc2, index = 0;
loc2 = chloc(addr,'@');
if ((loc = chloc(addr, '%')) < loc2)
loc2 = loc;
if (loc2 != -1) { /* ARPA address. */
/* algorithm is to get to '@' sign and move backwards until
we've hit the beginning of the word or another metachar.
*/
for (loc = loc2 - 1; loc > -1 && addr[loc] != '!'; loc--)
;
}
else { /* usenet address */
/* simple algorithm - find last '!' */
loc2 = strlen(addr); /* need it anyway! */
for (loc = loc2; loc > -1 && addr[loc] != '!'; loc--)
;
}
/** now copy up to 'loc' into destination... **/
while (index <= loc) {
ret_addr[index] = addr[index];
index++;
}
/** now append the '%s'... **/
ret_addr[index++] = '%';
ret_addr[index++] = 's';
/** and, finally, if anything left, add that **/
while (loc2 < strlen(addr)) {
ret_addr[index++] = addr[loc2++];
if (addr[loc2-1] == '%') /* tweak for "printf" */
ret_addr[index++] = '%';
}
ret_addr[index] = '\0';
}
build_address(to, full_to)
char *to, *full_to;
{
/** loop on all words in 'to' line...append to full_to as
we go along, until done or length > len **/
register int i, changed = 0;
char word[SLEN], *ptr, buffer[SLEN];
char new_to_list[LONG_SLEN];
new_to_list[0] = '\0';
i = get_word(to, 0, word);
full_to[0] = '\0';
while (i > 0) {
if (strpbrk(word,"!@:") != NULL)
sprintf(full_to, "%s%s%s", full_to,
full_to[0] != '\0'? ", " : "", expand_system(word, 1));
else if ((ptr = get_alias_address(word, 1, 0)) != NULL)
sprintf(full_to, "%s%s%s", full_to,
full_to[0] != '\0'? ", " : "", ptr);
else if (strlen(word) > 0) {
if (valid_name(word))
sprintf(full_to, "%s%s%s", full_to,
full_to[0] != '\0'? ", " : "", word);
else if (check_only) {
printf("(alias \"%s\" is unknown)\n\r",
word);
changed++;
}
else if (! isatty(fileno(stdin)) ) { /* batch mode error! */
fprintf(stderr,"Cannot expand alias '%s'!\n\r", word);
fprintf(stderr,"Use \"checkalias\" to find valid addresses!\n\r");
dprint1(1,
"Can't expand alias %s - bailing out! (build_address)\n",
word);
emergency_exit();
}
else {
dprint1(2,"Entered unknown address %s (build_address)\n", word);
sprintf(buffer, "'%s' is an unknown address. Replace with: ",
word);
word[0] = '\0';
if (! mail_only)
PutLine0(LINES, 0, buffer);
(void) optionally_enter(word, LINES, strlen(buffer), FALSE);
if (strlen(word) > 0) {
sprintf(new_to_list, "%s%s%s", new_to_list,
strlen(new_to_list) > 0? " ":"", word);
dprint1(3,"Replaced with %s (build_address)\n", word);
}
else
dprint0(3,"Address removed from to list (build_address)\n");
if (mail_only) printf("\n\r");
changed++;
clear_error();
continue;
}
}
i = get_word(to, i, word);
}
if (changed)
strcpy(to, new_to_list);
}
int
real_from(buffer, entry)
char *buffer;
struct header_rec *entry;
{
/***** Returns true iff 's' has the seven 'from' fields, (or
8 - some machines include the TIME ZONE!!!)
Initializing the date and from entries in the record
and also the message received date/time. *****/
char junk[STRING], timebuff[STRING], holding_from[SLEN];
int eight_fields = 0;
entry->year[0] = '\0';
junk[0] = '\0';
/* From <user> <day> <month> <day> <hr:min:sec> <year> */
sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %s", timebuff, junk);
if (timebuff[1] != ':' && timebuff[2] != ':') {
dprint1(3,"real_from returns FAIL [bad time field] on\n-> %s\n",
buffer);
return(FALSE);
}
if (junk[0] != '\0') { /* try for 8 field entry */
junk[0] = '\0';
sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %*s %s", timebuff, junk);
if (junk[0] != '\0') {
dprint1(3,"real_from returns FAIL [too many fields] on\n-> %s\n",
buffer);
return(FALSE);
}
eight_fields++;
}
/** now get the info out of the record! **/
if (eight_fields)
sscanf(buffer, "%s %s %s %s %s %s %*s %s",
junk, holding_from, entry->dayname, entry->month,
entry->day, entry->time, entry->year);
else
sscanf(buffer, "%s %s %s %s %s %s %s",
junk, holding_from, entry->dayname, entry->month,
entry->day, entry->time, entry->year);
strncpy(entry->from, holding_from, STRING);
resolve_received(entry);
return(entry->year[0] != '\0');
}
forwarded(buffer, entry)
char *buffer;
struct header_rec *entry;
{
/** Change 'from' and date fields to reflect the ORIGINATOR of
the message by iteratively parsing the >From fields...
Modified to deal with headers that include the time zone
of the originating machine... **/
char machine[SLEN], buff[SLEN], holding_from[SLEN];
machine[0] = '\0';
sscanf(buffer, "%*s %s %s %s %s %s %s %*s %*s %s",
holding_from, entry->dayname, entry->month,
entry->day, entry->time, entry->year, machine);
if (isdigit(entry->month[0])) { /* try for veeger address */
sscanf(buffer, "%*s %s %s%*c %s %s %s %s %*s %*s %s",
holding_from, entry->dayname, entry->day, entry->month,
entry->year, entry->time, machine);
}
if (isalpha(entry->year[0])) { /* try for address including tz */
sscanf(buffer, "%*s %s %s %s %s %s %*s %s %*s %*s %s",
holding_from, entry->dayname, entry->month,
entry->day, entry->time, entry->year, machine);
}
if (machine[0] == '\0')
sprintf(buff,"anonymous");
else
sprintf(buff,"%s!%s", machine, holding_from);
strncpy(entry->from, buff, STRING);
}
parse_arpa_from(buffer, newfrom)
char *buffer, *newfrom;
{
/** try to parse the 'From:' line given... It can be in one of
two formats:
From: Dave Taylor <hplabs!dat>
or From: hplabs!dat (Dave Taylor)
Change 'newfrom' ONLY if sucessfully parsed this entry and
the resulting name is non-null!
Added: removes quotes if name is quoted (12/12)
Added: only copies STRING characters...
**/
char temp_buffer[SLEN], *temp;
register int i, j = 0;
temp = (char *) temp_buffer;
temp[0] = '\0';
no_ret(buffer); /* blow away '\n' char! */
if (lastch(buffer) == '>') {
for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
buffer[i] != '('; i++)
temp[j++] = buffer[i];
temp[j] = '\0';
}
else if (lastch(buffer) == ')') {
for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
buffer[i] != '<'; i--)
temp[j++] = buffer[i];
temp[j] = '\0';
reverse(temp);
}
if (strlen(temp) > 0) { /* mess with buffer... */
/* remove leading spaces and quotes... */
while (whitespace(temp[0]) || quote(temp[0]))
temp = (char *) (temp + 1); /* increment address! */
/* remove trailing spaces and quotes... */
i = strlen(temp) - 1;
while (whitespace(temp[i]) || quote(temp[i]))
temp[i--] = '\0';
/* if anything is left, let's change 'from' value! */
if (strlen(temp) > 0)
strncpy(newfrom, temp, STRING);
}
}
parse_arpa_date(string, entry)
char *string;
struct header_rec *entry;
{
/** Parse and figure out the given date format... return
the entry fields changed iff it turns out we have a
valid parse of the date! **/
char word[15][NLEN], buffer[SLEN], *bufptr;
char *aword;
int words = 0;
strcpy(buffer, string);
bufptr = (char *) buffer;
/** break the line down into words... **/
while ((aword = strtok(bufptr," \t '\"-/(),.")) != NULL) {
strcpy(word[words++], aword);
bufptr = NULL;
}
if (words < 6) { /* strange format. We're outta here! */
dprint1(3,"parse_arpa_date failed [less than six fields] on\n-> %s\n",
string);
return;
}
/* There are now five possible combinations that we could have:
Date: day_number month_name year_number time timezone
Date: day_name day_number month_name year_number ...
Date: day_name month_name day_number time year_number
Date: day_name month_name day_number year_number time
Date: day_number month_name year_number time timezone day_name
Note that they are distinguishable by checking the first
character of the second, third and fourth words...
*/
if (isdigit(word[1][0])) { /*** type one! ***/
if (! valid_date(word[1], word[2], word[3])) {
dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
word[1], word[2], word[3], string);
return; /* strange date! */
}
strncpy(entry->day, word[1], 3);
strncpy(entry->month, word[2], 3);
strncpy(entry->year, word[3], 4);
strncpy(entry->time, word[4], 10);
}
else if (isdigit(word[2][0])) { /*** type two! ***/
if (! valid_date(word[2], word[3], word[4])) {
dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
word[2], word[3], word[4], string);
return; /* strange date! */
}
strncpy(entry->day, word[2], 3);
strncpy(entry->month, word[3], 3);
strncpy(entry->year, word[4], 4);
strncpy(entry->time, word[5], 10);
}
else if (isdigit(word[3][0])) {
if (word[4][1] == ':' ||
word[4][2] == ':') { /*** type three! ***/
if (! valid_date(word[3], word[2], word[5])) {
dprint4(3,
"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
word[3], word[2], word[5], string);
return; /* strange date! */
}
strncpy(entry->year, word[5], 4);
strncpy(entry->time, word[4], 10);
}
else { /*** type four! ***/
if (! valid_date(word[3], word[2], word[4])) {
dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
word[3], word[2], word[4], string);
return; /* strange date! */
}
strncpy(entry->year, word[4], 4);
strncpy(entry->time, word[5], 10);
}
strncpy(entry->day, word[3], 3);
strncpy(entry->month, word[2], 3);
}
}
fix_arpa_address(address)
char *address;
{
/** Given a pure ARPA address, try to make it reasonable.
This means that if you have something of the form a@b@b make
it a@b. If you have something like a%b%c%b@x make it a%b@x...
**/
register int host_count = 0, i;
char hosts[MAX_HOPS][2*NLEN]; /* array of machine names */
char *host, *addrptr;
/* break down into a list of machine names, checking as we go along */
addrptr = (char *) address;
while ((host = get_token(addrptr, "%@", 2)) != NULL) {
for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
;
if (i == host_count) {
strcpy(hosts[host_count++], host);
if (host_count == MAX_HOPS) {
dprint0(2,
"Can't build return address - hit MAX_HOPS (fix_arpa_address)\n");
error("Can't build return address - hit MAX_HOPS limit!");
return(1);
}
}
else
host_count = i + 1;
addrptr = NULL;
}
/** rebuild the address.. **/
address[0] = '\0';
for (i = 0; i < host_count; i++)
sprintf(address, "%s%s%s", address,
address[0] == '\0'? "" :
(i == host_count - 1 ? "@" : "%"),
hosts[i]);
return(0);
}
figure_out_addressee(buffer, mail_to)
char *buffer;
char *mail_to;
{
/** This routine steps through all the addresses in the "To:"
list, initially setting it to the first entry (if mail_to
is NULL) or, if the user is found (eg "alternatives") to
the current "username".
Modified to know how to read quoted names...
**/
char *address, *bufptr, *strchr();
register int index = 0, index2 = 0;
if (equal(mail_to, username)) return; /* can't be better! */
bufptr = (char *) buffer; /* use the string directly */
if (strchr(buffer,'"') != NULL) { /* we have a quoted string */
while (buffer[index] != '"')
index++;
index++; /* skip the leading quote */
while (buffer[index] != '"' && index < strlen(buffer))
mail_to[index2++] = buffer[index++];
mail_to[index2] = '\0';
}
else while ((address = strtok(bufptr, " ,\t\n\r")) != NULL) {
if (! okay_address(address, "don't match me!")) {
strcpy(mail_to, username); /* it's to YOU! */
return;
}
else if (strlen(mail_to) == 0) /* it's SOMEthing! */
get_return_name(address, mail_to, FALSE);
bufptr = (char *) NULL; /* set to null */
}
return;
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 15408 ]
then
echo $filename changed - should be 15408 bytes, not $size bytes
fi
chmod 644 $filename
fi
# ---------- file src/input_utils.c ----------
filename="src/input_utils.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file src/input_utils.c...
fi
cat << 'END-OF-FILE' > $filename
/** input_utils.c **/
/** Mindless I/O routines for ELM
(C) Copyright 1985 Dave Taylor
**/
#include "headers.h"
#include <errno.h>
extern int errno; /* system error number */
int
want_to(question, dflt, echo_answer)
char *question, dflt;
int echo_answer;
{
/** Ask 'question' at LINES-2, COLUMNS-40, returning the answer in
lower case. If 'echo_answer', then echo answer. 'dflt' is the
default answer if <return> is pressed. (Note: 'dflt' is also what
will be returned if <return> is pressed!)
**/
register char ch, cols;
cols = (strlen(question) < 30)? COLUMNS-40 : COLUMNS-50;
PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
fflush(stdout);
fflush(stdin);
ch = tolower(ReadCh());
if (echo_answer && ch > (char) ' ') {
Writechar(ch);
fflush(stdout);
}
return(ch == '\n' || ch == '\r' ? dflt : ch);
}
int
read_number(ch, max)
char ch;
int max;
{
/** read a number, where 'ch' is the leading digit!
If max < 10 then just return 'ch' **/
char buff[SHORT_SLEN];
int num;
if (max < 10)
return( (int) ch - '0' );
buff[0] = ch;
buff[1] = '\0';
PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE) == -1)
return(current);
sscanf(buff,"%d", &num);
return(num);
}
int
optionally_enter(string, x, y, append_current)
char *string;
int x,y, append_current;
{
/** Display the string on the screen and if RETURN is pressed, return
it. Otherwise, allow standard text input, including backspaces
and such until RETURN is hit.
If "append_current" is set, then leave the default string in
place and edit AFTER it...assume 'x,y' is placing us at the
beginning of the string...
This routine returns zero unless INTERRUPT hit, then it returns
-1 and must be treated accordingly.
**/
char ch;
register index = 0;
PutLine1(x,y, "%s", string);
CleartoEOLN();
if (! append_current)
MoveCursor(x,y);
if (cursor_control)
transmit_functions(OFF);
ch = getchar();
if (ch == '\n' || ch == '\r') {
if (cursor_control)
transmit_functions(ON);
return(0); /* we're done. No change needed */
}
CleartoEOLN();
index = (append_current? strlen(string) : 0);
if (ch == kill_line) {
if (! mail_only)
MoveCursor(x,y);
CleartoEOLN();
index = 0;
}
else if (ch != backspace) {
Writechar(ch);
string[index++] = ch;
}
else if (index > 0) {
index--;
Writechar(BACKSPACE);
Writechar(' ');
Writechar(BACKSPACE);
fflush(stdout);
}
else {
Writechar(' ');
Writechar(BACKSPACE);
fflush(stdout);
}
do {
ch = getchar();
/* the following is converted from a case statement to
allow the variable characters (backspace, kill_line
and break) to be processed. Case statements in
C require constants as labels, so it failed ...
*/
if (ch == backspace) {
if (index > 0) {
index--;
Writechar(BACKSPACE);
Writechar(' ');
Writechar(BACKSPACE);
fflush(stdout);
}
else {
Writechar(' ');
Writechar(BACKSPACE);
fflush(stdout);
}
}
else if (ch == '\n' || ch == '\r') {
string[index] = '\0';
if (cursor_control)
transmit_functions(ON);
return(0);
}
else if (ch == kill_line) {
if (mail_only)
back_up(index+1);
else
MoveCursor(x,y);
CleartoEOLN();
index = 0;
}
else if (ch == NULL) {
if (cursor_control)
transmit_functions(ON);
fflush(stdin); /* remove extraneous chars, if any */
string[0] = '\0'; /* clean up string, and... */
return(-1);
}
else { /* default case */
string[index++] = ch;
Writechar(ch);
}
} while (index < SLEN);
string[index] = '\0';
if (cursor_control)
transmit_functions(ON);
return(0);
}
int
pattern_enter(string, alt_string, x, y, alternate_prompt)
char *string, *alt_string, *alternate_prompt;
int x,y;
{
/** This function is functionally similar to the routine
optionally-enter, but if the first character pressed
is a '/' character, then the alternate prompt and string
are used rather than the normal one. This routine
returns 1 if alternate was used, 0 if not
**/
char ch;
register index = 0;
PutLine1(x, y, "%s", string);
CleartoEOLN();
MoveCursor(x,y);
if (cursor_control)
transmit_functions(OFF);
ch = getchar();
if (ch == '\n' || ch == '\r') {
if (cursor_control)
transmit_functions(ON);
return(0); /* we're done. No change needed */
}
if (ch == '/') {
PutLine1(x, 0, "%s", alternate_prompt);
CleartoEOLN();
(void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
FALSE);
return(1);
}
CleartoEOLN();
index = 0;
if (ch == kill_line) {
MoveCursor(x,y);
CleartoEOLN();
index = 0;
}
else if (ch != backspace) {
Writechar(ch);
string[index++] = ch;
}
else if (index > 0) {
index--;
Writechar(BACKSPACE);
Writechar(' ');
Writechar(BACKSPACE);
}
else {
Writechar(' ');
Writechar(BACKSPACE);
}
do {
fflush(stdout);
ch = getchar();
/* the following is converted from a case statement to
allow the variable characters (backspace, kill_line
and break) to be processed. Case statements in
C require constants as labels, so it failed ...
*/
if (ch == backspace) {
if (index > 0) {
index--;
Writechar(BACKSPACE);
Writechar(' ');
Writechar(BACKSPACE);
}
else {
Writechar(' ');
Writechar(BACKSPACE);
}
}
else if (ch == '\n' || ch == '\r') {
string[index] = '\0';
if (cursor_control)
transmit_functions(ON);
return(0);
}
else if (ch == kill_line) {
MoveCursor(x,y);
CleartoEOLN();
index = 0;
}
else if (ch == NULL) {
if (cursor_control)
transmit_functions(ON);
fflush(stdin); /* remove extraneous chars, if any */
string[0] = '\0'; /* clean up string, and... */
return(-1);
}
else { /* default case */
string[index++] = ch;
Writechar(ch);
}
} while (index < SLEN);
string[index] = '\0';
if (cursor_control)
transmit_functions(ON);
return(0);
}
back_up(spaces)
int spaces;
{
/** this routine is to replace the goto x,y call for when sending
mail without starting the entire "elm" system up... **/
while (spaces--) {
Writechar(BACKSPACE);
Writechar(' ');
Writechar(BACKSPACE);
}
fflush(stdout);
}
int
GetPrompt()
{
/** This routine does a read/timeout for a single character.
The way that this is determined is that the routine to
read a character is called, then the "errno" is checked
against EINTR (interrupted call). If they match, this
returns NO_OP_COMMAND otherwise it returns the normal
command.
**/
int ch;
if (timeout > 0) {
alarm(timeout);
errno = 0; /* we actually have to do this. *sigh* */
ch = ReadCh();
if (errno == EINTR) ch = NO_OP_COMMAND;
alarm(0);
}
else
ch = ReadCh();
return(ch);
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 7235 ]
then
echo $filename changed - should be 7235 bytes, not $size bytes
fi
chmod 644 $filename
fi
echo end of this archive file....
exit 0