syd@dsinc.UUCP (Syd Weinstein) (12/12/88)
---- Cut Here and unpack ----
#!/bin/sh
# this is part 12 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/elm.c continued
#
CurArch=12
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file src/elm.c"
sed 's/^X//' << 'SHAR_EOF' >> src/elm.c
X (header_table[current-1].status & VISIBLE) != 0);
X
X Write_to_screen(buffer, 0);
X
X sprintf(buffer, "\nReceived on: %d/%d/%d at %d:%02d\n",
X header_table[current-1].received.month+1,
X header_table[current-1].received.day,
X header_table[current-1].received.year,
X header_table[current-1].received.hour,
X header_table[current-1].received.minute);
X Write_to_screen(buffer, 0);
X
X sprintf(buffer, "Message sent on: %s, %s %s, %s at %s\n",
X header_table[current-1].dayname,
X header_table[current-1].month,
X header_table[current-1].day,
X header_table[current-1].year,
X header_table[current-1].time);
X Write_to_screen(buffer, 0);
X
X Write_to_screen("From: %s\nSubject: %s", 2,
X header_table[current-1].from,
X header_table[current-1].subject);
X
X Write_to_screen("\nPrimary Recipient: %s\nInternal Index Reference Number = %d\n", 2,
X header_table[current-1].to,
X header_table[current-1].index_number);
X
X Write_to_screen("Message-ID: %s\n", 1,
X strlen(header_table[current-1].messageid) > 0 ?
X header_table[current-1].messageid : "<none>");
X
X Raw(ON);
X
X PutLine0(LINES,0,"Please Press any key to return: ");
X (void) ReadCh();
X}
SHAR_EOF
echo "File src/elm.c is complete"
chmod 0444 src/elm.c || echo "restore of src/elm.c fails"
echo "x - extracting src/encode.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/encode.c &&
X
Xstatic char rcsid[] = "@(#)$Id: encode.c,v 2.1 88/09/15 20:28:08 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: encode.c,v $
X * Revision 2.1 88/09/15 20:28:08 syd
X * checked in with -k by syd at 88.09.15.20.28.08.
X *
X * Revision 2.1 88/07/21 09:58:21 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:00 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** This is a heavily mangled version of the 'cypher' program written by
X person or persons unknown.
X
X**/
X
X#include <stdio.h>
X#include "curses.h"
X#include "headers.h"
X
X#define RS 94
X#define RN 4
X#define RMASK 0x7fff /* use only 15 bits */
X
Xstatic char r[RS][RN]; /* rotors */
Xstatic char ir[RS][RN]; /* inverse rotors */
Xstatic char h[RS]; /* half rotor */
Xstatic char s[RS]; /* shuffle vector */
Xstatic int p[RN]; /* rotor indices */
X
Xstatic char the_key[SLEN]; /* unencrypted key */
Xstatic char *encrypted_key; /* encrypted key */
X
Xchar *getpass(), *strncpy(), *strcpy();
Xunsigned long sleep();
X
Xgetkey(send)
Xint send;
X{
X /** this routine prompts for and returns an encode/decode
X key for use in the rest of the program. If send == 1
X then need to mess with rawmode. **/
X
X char buffer[NLEN];
X int gotkey = 0, x, y;
X
X GetXYLocation(&x,&y);
X
X ClearLine(21);
X
X if (send) Raw(OFF);
X
X while ( !gotkey ) {
X MoveCursor(LINES-1,0);
X ClearLine(LINES-1);
X if (send)
X strcpy( buffer, getpass( "Enter encryption key: "));
X else
X strcpy( buffer, getpass( "Enter decryption key: "));
X MoveCursor(LINES-1,0);
X if ( send && strcmp( buffer, getpass( "Please enter it again: "))) {
X error("Your keys were not the same!");
X sleep(1);
X clear_error();
X continue;
X }
X strcpy(the_key, buffer); /* save unencrypted key */
X makekey( buffer );
X gotkey = 1;
X }
X
X if (send) Raw(ON);
X
X setup(); /** initialize the rotors etc. **/
X
X ClearLine(LINES-1);
X clear_error();
X
X MoveCursor(x+1,0); /* move to 'next' line... */
X}
X
Xget_key_no_prompt()
X{
X /** This performs the same action as get_key, but assumes that
X the current value of 'the_key' is acceptable. This is used
X when a message is encrypted twice... **/
X
X char buffer[SLEN];
X
X strcpy(buffer, the_key);
X
X makekey( buffer );
X
X setup();
X}
X
Xencode(line)
Xchar *line;
X{
X /** encrypt or decrypt the specified line. Uses the previously
X entered key... **/
X
X register int i, index, j, ph = 0;
X
X for (index=0; index < strlen(line); index++) {
X i = (int) line[index];
X
X if ( (i >= ' ') && (i < '~') ) {
X i -= ' ';
X
X for ( j = 0; j < RN; j++ ) /* rotor forwards */
X i = r[(i+p[j])%RS][j];
X
X i = ((h[(i+ph)%RS])-ph+RS)%RS; /* half rotor */
X
X for ( j-- ; j >= 0; j-- ) /* rotor backwards */
X i = (ir[i][j]+RS-p[j])%RS;
X
X j = 0; /* rotate rotors */
X p[0]++;
X while ( p[j] == RS ) {
X p[j] = 0;
X j++;
X if ( j == RN ) break;
X p[j]++;
X }
X
X if ( ++ph == RS )
X ph = 0;
X
X i += ' ';
X }
X
X line[index] = (char) i; /* replace with altered one */
X }
X}
X
X
Xmakekey( rkey)
Xchar *rkey;
X{
X /** encrypt the key using the system routine 'crypt' **/
X
X char key[8], salt[2], *crypt();
X
X strncpy( key, rkey, 8);
X salt[0] = key[0];
X salt[1] = key[1];
X encrypted_key = crypt( key, salt);
X}
X
X/*
X * shuffle rotors.
X * shuffle each of the rotors indiscriminately. shuffle the half-rotor
X * using a special obvious and not very tricky algorithm which is not as
X * sophisticated as the one in crypt(1) and Oh God, I'm so depressed.
X * After all this is done build the inverses of the rotors.
X */
X
Xsetup()
X{
X register long i, j, k, temp;
X long seed;
X
X for ( j = 0; j < RN; j++ ) {
X p[j] = 0;
X for ( i = 0; i < RS; i++ )
X r[i][j] = i;
X }
X
X seed = 123;
X for ( i = 0; i < 13; i++) /* now personalize the seed */
X seed = (seed*encrypted_key[i] + i) & RMASK;
X
X for ( i = 0; i < RS; i++ ) /* initialize shuffle vector */
X h[i] = s[i] = i;
X
X for ( i = 0; i < RS; i++) { /* shuffle the vector */
X seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
X k = ((seed % 65521) & RMASK) % RS;
X temp = s[k];
X s[k] = s[i];
X s[i] = temp;
X }
X
X for ( i = 0; i < RS; i += 2 ) { /* scramble the half-rotor */
X temp = h[s[i]]; /* swap rotor elements ONCE */
X h[s[i]] = h[s[i+1]];
X h[s[i+1]] = temp;
X }
X
X for ( j = 0; j < RN; j++) { /* select a rotor */
X
X for ( i = 0; i < RS; i++) { /* shuffle the vector */
X seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
X k = ((seed % 65521) & RMASK) % RS;
X temp = r[i][j];
X r[i][j] = r[k][j];
X r[k][j] = temp;
X }
X
X for ( i = 0; i < RS; i++) /* create inverse rotors */
X ir[r[i][j]][j] = i;
X }
X}
SHAR_EOF
chmod 0444 src/encode.c || echo "restore of src/encode.c fails"
echo "x - extracting src/errno.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/errno.c &&
X
Xstatic char rcsid[] = "@(#)$Id: errno.c,v 2.1 88/09/15 20:28:11 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: errno.c,v $
X * Revision 2.1 88/09/15 20:28:11 syd
X * checked in with -k by syd at 88.09.15.20.28.11.
X *
X * Revision 2.1 88/07/21 09:58:24 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:01 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** This routine maps error numbers to error names and error messages.
X These are all directly ripped out of the include file errno.h, and
X are HOPEFULLY standardized across the different breeds of Unix!!
X
X If (alas) yours are different, you should be able to use awk to
X mangle your errno.h file quite simply...
X
X**/
X
X#include "headers.h"
X
Xchar *err_name[] = {
X/* 0 */ "NOERROR", "No error status currently",
X/* 1 */ "EPERM", "Not super-user",
X/* 2 */ "ENOENT", "No such file or directory",
X/* 3 */ "ESRCH", "No such process",
X/* 4 */ "EINTR", "Interrupted system call",
X/* 5 */ "EIO", "I/O error",
X/* 6 */ "ENXIO", "No such device or address",
X/* 7 */ "E2BIG", "Arg list too long",
X/* 8 */ "ENOEXEC", "Exec format error",
X/* 9 */ "EBADF", "Bad file number",
X/* 10 */ "ECHILD", "No children",
X/* 11 */ "EAGAIN", "No more processes",
X/* 12 */ "ENOMEM", "Not enough core",
X/* 13 */ "EACCES", "Permission denied",
X/* 14 */ "EFAULT", "Bad address",
X/* 15 */ "ENOTBLK", "Block device required",
X/* 16 */ "EBUSY", "Mount device busy",
X/* 17 */ "EEXIST", "File exists",
X/* 18 */ "EXDEV", "Cross-device link",
X/* 19 */ "ENODEV", "No such device",
X/* 20 */ "ENOTDIR", "Not a directory",
X/* 21 */ "EISDIR", "Is a directory",
X/* 22 */ "EINVAL", "Invalid argument",
X/* 23 */ "ENFILE", "File table overflow",
X/* 24 */ "EMFILE", "Too many open files",
X/* 25 */ "ENOTTY", "Not a typewriter",
X/* 26 */ "ETXTBSY", "Text file busy",
X/* 27 */ "EFBIG", "File too large",
X/* 28 */ "ENOSPC", "No space left on device",
X/* 29 */ "ESPIPE", "Illegal seek",
X/* 30 */ "EROFS", "Read only file system",
X/* 31 */ "EMLINK", "Too many links",
X/* 32 */ "EPIPE", "Broken pipe",
X/* 33 */ "EDOM", "Math arg out of domain of func",
X/* 34 */ "ERANGE", "Math result not representable",
X/* 35 */ "ENOMSG", "No message of desired type",
X/* 36 */ "EIDRM", "Identifier removed"
X };
X
Xchar *strcpy();
X
Xchar *error_name(errnumber)
Xint errnumber;
X{
X static char buffer[50];
X
X if (errnumber < 0 || errnumber > 36)
X sprintf(buffer,"ERR-UNKNOWN (%d)", errnumber);
X else
X strcpy(buffer, err_name[2*errnumber]);
X
X return( (char *) buffer);
X}
X
Xchar *error_description(errnumber)
Xint errnumber;
X{
X static char buffer[50];
X
X if (errnumber < 0 || errnumber > 36)
X sprintf(buffer,"Unknown error - %d - No description", errnumber);
X else
X strcpy(buffer, err_name[2*errnumber + 1]);
X
X return ( (char *) buffer);
X}
SHAR_EOF
chmod 0444 src/errno.c || echo "restore of src/errno.c fails"
echo "x - extracting src/expires.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/expires.c &&
X
Xstatic char rcsid[] = "@(#)$Id: expires.c,v 2.1 88/09/15 20:28:13 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1985 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: expires.c,v $
X * Revision 2.1 88/09/15 20:28:13 syd
X * checked in with -k by syd at 88.09.15.20.28.13.
X *
X * 88/08/27 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X * fix date parsing
X *
X * Revision 2.1 88/07/21 09:58:25 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:02 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** This routine is written to deal with the Expires: header on the
X individual mail coming in. What it does is to look at the date,
X compare it to todays date, then set the EXPIRED flag on the
X current message if it is true...
X**/
X
X#include "headers.h"
X
X#ifdef BSD
X# ifndef BSD4_1
X# include <sys/time.h>
X# else
X# include <time.h>
X# include <sys/types.h>
X# include <sys/timeb.h>
X# endif
X#else
X# include <time.h>
X#endif
X
X#include <ctype.h>
X
X#ifdef BSD
X#undef toupper
X#undef tolower
X#endif
X
Xchar *shift_lower(), *strcpy(), *strncpy();
X
Xprocess_expiration_date(date, message_status)
Xchar *date;
Xint *message_status;
X{
X struct tm *timestruct, *localtime();
X long *thetime, *time();
X char word1[NLEN], word2[NLEN], word3[NLEN], word4[NLEN];
X int month = 0, day = 0, year = 0, hour = 0, minute = 0;
X
X /** first step is to break down the date given into MM DD YY HH MM
X format: The possible formats for this field are, by example:
X
X (1) Mon, Jun 11, 87
X (2) Mon, 11 Jun 87
X (3) Jun 11, 87
X (4) 11 Jun 87
X (5) 11/06/87 <- ambiguous - will be ignored!!
X
X The reason #5 is considered ambiguous will be made clear
X if we consider a message to be expired on Jan 4, 88:
X 01/04/88 in the United States
X 04/01/88 in Europe
X so is the first field the month or the day? Standard prob.
X **/
X
X sscanf(date, "%s %s %s %s", word1, word2, word3, word4);
X
X if (strlen(word2) == 0) { /* we have form #6 or form #5 */
X if (isdigit(word2[1]) && isdigit(word2[2])) /* form #6! */
X sscanf(word1, "%02d%02d%02d%02d%02d%*c",
X &year, &month, &day, &hour, &minute);
X }
X else if (strlen(word4) != 0) { /* form #1 or form #2 */
X if(isdigit(word2[0])) { /* form #2 */
X month = month_number(word3);
X day = atoi(word2);
X year = atoi(word4);
X } else { /* form #1 */
X month = month_number(word2);
X day = atoi(word3);
X year = atoi(word4);
X }
X }
X else if (! isdigit(word1[0])) { /* form #3 */
X month = month_number(word1);
X day = atoi(word2);
X year = atoi(word3);
X }
X else { /* form #4 */
X day = atoi(word2);
X month = month_number(word3);
X year = atoi(word4);
X }
X
X if (day == 0 || year == 0)
X return; /* we didn't get a valid date */
X
X /** next let's get the current time and date, please **/
X
X thetime = time((long *) 0);
X
X timestruct = localtime(&thetime);
X
X /** and compare 'em **/
X
X if (year > timestruct->tm_year)
X return;
X else if (year < timestruct->tm_year)
X goto expire_message;
X
X if (month > timestruct->tm_mon)
X return;
X else if (month < timestruct->tm_mon)
X goto expire_message;
X
X if (day > timestruct->tm_mday)
X return;
X else if (day < timestruct->tm_mday)
X goto expire_message;
X
X if (hour > timestruct->tm_hour)
X return;
X else if (hour < timestruct->tm_hour)
X goto expire_message;
X
X if (minute > timestruct->tm_min)
X return;
X
Xexpire_message:
X
X /** it's EXPIRED! Yow!! **/
X
X (*message_status) |= EXPIRED;
X}
SHAR_EOF
chmod 0444 src/expires.c || echo "restore of src/expires.c fails"
echo "x - extracting src/file.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/file.c &&
X
Xstatic char rcsid[] = "@(#)$Id: file.c,v 2.1 88/09/15 20:28:17 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: file.c,v $
X * Revision 2.1 88/09/15 20:28:17 syd
X * checked in with -k by syd at 88.09.15.20.28.17.
X *
X * 88/09/13 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X * The message that appears if you try to save a mail message to a
X * file that exists that cannot be opened for appending mentioned a
X * permissions problem, but since the problem can be other than one
X * of permissions (e.g. trying to save to a directory instead of a
X * regular file), I have made the message more general.
X *
X * 88/08/27 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X * fix saving to/ apending to messages
X *
X * Revision 2.1 88/07/21 09:58:27 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:03 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** File I/O routines, mostly the save to file command...
X
X**/
X
X#include "headers.h"
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy(), *getenv();
Xunsigned long sleep();
X
Xint
Xsave(redraw, silently)
Xint *redraw, silently;
X{
X /** Save all tagged messages + current in a file. If no messages
X are tagged, save the current message instead! This routine
X will return ZERO if the operation failed.
X 'redraw' is set to TRUE iff we use the '?' and mess up
X the screen. Pretty reasonable, eh? If "silently" is set,
X then don't output the "D" character upon marking for
X deletion...
X **/
X
X register int tagged = 0, i, oldstat, appending = 0;
X register int iterations = 0, continue_looping;
X char filename[SLEN], address[LONG_SLEN], buffer[SLEN];
X FILE *save_file;
X
X oldstat = header_table[current-1].status; /* remember */
X
X for (i=0; i < message_count; i++)
X if (ison(header_table[i].status, TAGGED))
X tagged++;
X
X if (tagged == 0) {
X tagged = 1;
X setit(header_table[current-1].status, TAGGED);
X }
X
X dprint(4, (debugfile, "%d message%s tagged for saving (save)\n", tagged,
X plural(tagged)));
X
X do {
X
X continue_looping = 0; /* clear the flag, ho hum... */
X
X if (iterations++) {
X printf("File message%s in: ", plural(tagged));
X fflush(stdout);
X }
X else
X PutLine1(LINES-2, 0, "File message%s in: ", plural(tagged));
X
X if (save_by_name) {
X /** build default filename to save to **/
X get_return(address);
X get_return_name(address, buffer, TRUE);
X sprintf(filename, "=%s", buffer);
X }
X else
X filename[0] = '\0';
X
X if (iterations > 1) {
X optionally_enter(filename, -1, -1, FALSE);
X }
X else {
X if (tagged > 1)
X optionally_enter(filename, LINES-2, 19, FALSE);
X else
X optionally_enter(filename, LINES-2, 18, FALSE);
X }
X
X if (iterations == 1)
X MoveCursor(LINES-1,0);
X
X if (strlen(filename) == 0) { /** <return> means 'cancel', right? **/
X header_table[current-1].status = oldstat; /* BACK! */
X return(0);
X }
X
X if (strcmp(filename,"?") == 0) {
X *redraw = TRUE; /* set the flag so we know what to do later */
X Raw(OFF);
X list_folders();
X Raw(ON);
X continue_looping++;
X }
X } while (continue_looping);
X
X if (! expand_filename(filename)) {
X dprint(2, (debugfile,
X "Error: Failed on expansion of filename %s (save)\n",
X filename));
X header_table[current-1].status = oldstat; /* BACK! */
X return(0); /* failed expanding name! */
X }
X
X if (access(filename,ACCESS_EXISTS)== 0) /* already there!! */
X appending = 1;
X
X#ifdef BSD4_1
X if ((errno = ((can_open(filename, "a") & ~0x0200) >>8))) {
X#else
X if ((errno = can_open(filename, "a"))) {
X#endif
X error1("Cannot save message to file %s!", filename);
X dprint(2, (debugfile,
X "Error: access permission on file %s denied (%s)! (save)\n",
X filename, error_name(errno)));
X header_table[current-1].status = oldstat; /* BACK! */
X return(0);
X }
X
X dprint(4,(debugfile, "Saving mail to file '%s'...\n", filename));
X
X if ((save_file = fopen(filename,"a")) == NULL) {
X dprint(2, (debugfile,
X "Error: couldn't append to specified file %s (save)\n",
X filename));
X error1("Couldn't append to file %s!", filename);
X header_table[current-1].status = oldstat; /* BACK! */
X return(0);
X }
X
X for (i=0; i < message_count; i++) /* save each tagged msg */
X if (header_table[i].status & TAGGED)
X save_message(i, filename, save_file, (tagged > 1), appending++,
X silently);
X
X fclose(save_file);
X
X chown(filename, userid, groupid); /* owned by user */
X if (tagged > 1)
X error1("Message%s saved", plural(tagged));
X return(1);
X}
X
Xint
Xsave_message(number, filename, fd, pause, appending, silently)
Xint number, pause, appending, silently;
Xchar *filename;
XFILE *fd;
X{
X /** Save an actual message to a file. This is called by
X "save()" only! The parameters are the message number,
X and the name and file descriptor of the file to save to.
X If 'pause' is true, a sleep(2) will be done after the
X saved message appears on the screen...
X 'appending' is only true if the file already exists
X **/
X
X register int save_current;
X
X dprint(4, (debugfile, "\tSaving message %d to file...\n", number));
X
X save_current = current;
X current = number+1;
X copy_message("", fd, FALSE, FALSE);
X current = save_current;
X
X if (resolve_mode)
X setit(header_table[number].status, DELETED); /* deleted, but ... */
X clearit(header_table[number].status, TAGGED); /* not tagged anymore */
X clearit(header_table[number].status, NEW); /* it's not new now! */
X
X if (appending)
X error2("Message %d appended to file %s", number+1, filename);
X else
X error2("Message %d saved to file %s", number+1, filename);
X
X if (! silently)
X show_new_status(number); /* update screen, if needed */
X
X if (pause && ! silently) sleep(2);
X}
X
Xint
Xexpand_filename(filename)
Xchar *filename;
X{
X /** Expands '~' and '=' to specified file names, also will try to
X expand shell variables if encountered.. '+' and '%' are synonymous
X with '=' (folder dir)... **/
X
X char buffer[SLEN], varname[SLEN], env_value[SLEN], *ptr;
X register int i = 1, index = 0;
X char *getenv();
X
X ptr = filename;
X while (*ptr == ' ') ptr++; /* leading spaces GONE! */
X strcpy(filename, ptr);
X
X /** New stuff - make sure no illegal char as last **/
X
X if (lastch(filename) == '\n' || lastch(filename) == '\r')
X lastch(filename) = '\0';
X
X if (filename[0] == '~') {
X sprintf(buffer, "%s%s%s", home,
X (filename[1] != '/' && lastch(folders) != '/')? "/" : "",
X (char *) filename + 1);
X strcpy(filename, buffer);
X }
X else if (filename[0] == '=' || filename[0] == '+' ||
X filename[0] == '%') {
X if (strlen(folders) == 0) {
X dprint(3, (debugfile,
X "Error: maildir not defined - can't expand '%c' (%s)\n",
X filename[0], "expand_filename"));
X error1("MAILDIR not defined. Can't expand '%c'", filename[0]);
X return(0);
X }
X sprintf(buffer, "%s%s%s", folders,
X (filename[1] != '/' && lastch(folders) != '/')? "/" : "",
X (char *) filename + 1);
X strcpy(filename, buffer);
X }
X else if (filename[0] == '$') { /* env variable! */
X while (isalnum(filename[i]))
X varname[index++] = filename[i++];
X varname[index] = '\0';
X
X env_value[0] = '\0'; /* null string for strlen! */
X if (getenv(varname) != NULL)
X strcpy(env_value, getenv(varname));
X
X if (strlen(env_value) == 0) {
X dprint(3,(debugfile,
X "Error: Can't expand environment variable $%s (%s)\n",
X varname, "expand_filename"));
X error1("Don't know what the value of $%s is!", varname);
X return(0);
X }
X
X sprintf(buffer, "%s%s%s", env_value,
X (filename[i] != '/' && lastch(env_value) != '/')? "/" : "",
X (char *) filename + i);
X strcpy(filename, buffer);
X }
X
X return(1);
X}
SHAR_EOF
chmod 0444 src/file.c || echo "restore of src/file.c fails"
echo "x - extracting src/file_util.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/file_util.c &&
X
Xstatic char rcsid[] = "@(#)$Id: file_util.c,v 2.1 88/09/15 20:28:21 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: file_util.c,v $
X * Revision 2.1 88/09/15 20:28:21 syd
X * checked in with -k by syd at 88.09.15.20.28.21.
X *
X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X * 1. It allows the user to use the -z flags and -f [filename] flag
X * 2. Puts elm in raw mode earlier on than before so that any commands
X *
X * 88/08/27 ssw
X * add deluth patches
X *
X * Revision 2.1 88/07/21 09:58:28 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:04 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** File oriented utility routines for ELM
X
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X# undef tolower
X#endif
X
X#include <signal.h>
X#include <errno.h>
X
X#ifdef BSD
X# include <sys/wait.h>
X#endif
X
Xextern int errno; /* system error number */
X
Xchar *error_name(), *error_description(), *strcpy(), *getlogin();
Xlong fsize();
X
Xlong
Xbytes(name)
Xchar *name;
X{
X /** return the number of bytes in the specified file. This
X is to check to see if new mail has arrived.... (also
X see "fsize()" to see how we can get the same information
X on an opened file descriptor slightly more quickly)
X **/
X
X int ok = 1;
X extern int errno; /* system error number! */
X struct stat buffer;
X
X if (stat(name, &buffer) != 0)
X if (errno != 2) {
X dprint(1,(debugfile,
X "Error: errno %s on fstat of file %s (bytes)\n",
X error_name(errno), name));
X Write_to_screen("\n\rError attempting fstat on file %s!\n\r",
X 1, name);
X Write_to_screen("** %s - %s **\n\r", 2, error_name(errno),
X error_description(errno));
X emergency_exit();
X }
X else
X ok = 0;
X
X return(ok ? (long) buffer.st_size : 0L);
X}
X
Xint
Xcan_access(file, mode)
Xchar *file;
Xint mode;
X{
X /** returns ZERO iff user can access file or "errno" otherwise **/
X
X int the_stat = 0, pid, w;
X void _exit(), exit();
X#ifdef BSD
X union wait status;
X#else
X int status;
X#endif
X register int (*istat)(), (*qstat)();
X
X#ifdef NO_VM /* machine without virtual memory!! */
X if ((pid = fork()) == 0) {
X#else
X if ((pid = vfork()) == 0) {
X#endif
X setgid(groupid);
X setuid(userid); /** back to normal userid **/
X
X errno = 0;
X
X if (access(file, mode) == 0)
X _exit(0);
X else
X _exit(errno != 0? errno : 1); /* never return zero! */
X _exit(127);
X }
X
X istat = signal(SIGINT, SIG_IGN);
X qstat = signal(SIGQUIT, SIG_IGN);
X
X while ((w = wait(&status)) != pid && w != -1)
X ;
X
X#ifdef BSD
X the_stat = status.w_retcode;
X#else
X the_stat = status;
X#endif
X
X signal(SIGINT, istat);
X signal(SIGQUIT, qstat);
X
X return(the_stat);
X}
X
Xint
Xcan_open(file, mode)
Xchar *file, *mode;
X{
X /** Returns 0 iff user can open the file. This is not
X the same as can_access - it's used for when the file might
X not exist... **/
X
X FILE *fd;
X int the_stat = 0, pid, w;
X void _exit(), exit();
X#ifdef BSD
X union wait status;
X#else
X int status;
X#endif
X register int (*istat)(), (*qstat)();
X
X#ifdef NO_VM /* machine without virtual memory!! */
X if ((pid = fork()) == 0) {
X#else
X if ((pid = vfork()) == 0) {
X#endif
X setgid(groupid);
X setuid(userid); /** back to normal userid **/
X errno = 0;
X if ((fd = fopen(file, mode)) == NULL)
X _exit(errno);
X else {
X fclose(fd); /* don't just LEAVE it! */
X _exit(0);
X }
X _exit(127);
X }
X
X istat = signal(SIGINT, SIG_IGN);
X qstat = signal(SIGQUIT, SIG_IGN);
X
X while ((w = wait(&status)) != pid && w != -1)
X ;
X
X#ifdef BSD
X the_stat = status.w_retcode;
X#else
X the_stat = status;
X#endif
X
X signal(SIGINT, istat);
X signal(SIGQUIT, qstat);
X
X return(the_stat);
X}
X
Xint
Xcopy(from, to)
Xchar *from, *to;
X{
X /** this routine copies a specified file to the destination
X specified. Non-zero return code indicates that something
X dreadful happened! **/
X
X FILE *from_file, *to_file;
X char buffer[VERY_LONG_STRING];
X
X if ((from_file = fopen(from, "r")) == NULL) {
X dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n",
X from));
X error1("could not open file %s", from);
X return(1);
X }
X
X if ((to_file = fopen(to, "w")) == NULL) {
X dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n",
X to));
X error1("could not open file %s", to);
X return(1);
X }
X
X while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
X fputs(buffer, to_file);
X
X fclose(from_file);
X fclose(to_file);
X chown( to, userid, groupid);
X
X return(0);
X}
X
Xmove(from, to)
Xchar *from, *to;
X{
X /** This routine moves a specified file to the destination
X specified. It starts by trying to it all by link'ing.
X **/
X
X FILE *from_file, *to_file;
X char buffer[VERY_LONG_STRING];
X
X if (access(from, ACCESS_EXISTS) == -1) /* doesn't exist? */
X return;
X
X /** does the dest file exist?? **/
X
X if (access(to, ACCESS_EXISTS) != -1) { /* dest DOES exist! */
X printf("File %s already exists! Overwriting...\n", to);
X (void) unlink(to);
X }
X
X /** first off, let's try to link() it **/
X
X if (link(from, to) != -1) { /* yeah! */
X#ifdef DONT_JUST_LINK_EM_TOGETHER
X (void) unlink(from);
X#endif
X return;
X }
X
X /** nope. Let's open 'em both up and move the data... **/
X
X if ((from_file = fopen(from, "r")) == NULL) {
X dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n",
X from));
X printf("Could not open file %s for reading\n", from);
X return;
X }
X
X if ((to_file = fopen(to, "w")) == NULL) {
X dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n",
X to));
X printf("Could not open file %s for writing\n", to);
X return;
X }
X
X while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
X fputs(buffer, to_file);
X
X fclose(from_file);
X fclose(to_file);
X chown( to, userid, groupid);
X
X#ifdef DONT_JUST_LINK_EM_TOGETHER
X (void) unlink(from);
X#endif
X
X return;
X}
X
X
Xint
Xappend(fd, filename)
XFILE *fd;
Xchar *filename;
X{
X /** This routine appends the specified file to the already
X open file descriptor.. Returns non-zero if fails. **/
X
X FILE *my_fd;
X char buffer[VERY_LONG_STRING];
X
X if ((my_fd = fopen(filename, "r")) == NULL) {
X dprint(1, (debugfile,
X "Error: could not open %s for reading (append)\n", filename));
X return(1);
X }
X
X while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL)
X fputs(buffer, fd);
X
X fclose(my_fd);
X
X return(0);
X}
X
Xint
Xcheck_mailfile_size()
X{
X /** Check to ensure we have mail. Only used with the '-z'
X starting option. **/
X
X char filename[SLEN], *getlogin();
X struct stat buffer;
X
X if (infile[0] != '\0')
X strcpy(filename, infile);
X else {
X strcpy(username,getlogin());
X if (strlen(username) == 0)
X cuserid(username);
X
X sprintf(filename,"%s%s", mailhome, username);
X }
X
X if (stat(filename, &buffer) == -1) {
X printf(" You have no mail.\n");
X return(-1);
X }
X else if (buffer.st_size < 2) { /* maybe one byte??? */
X printf("You have no mail to read.\n");
X return(-1);
X }
X return(0);
X}
X
Xcreate_readmsg_file()
X{
X /** Creates the file ".current" in the users home directory
X for use with the "readmsg" program.
X **/
X
X FILE *fd;
X char buffer[SLEN];
X
X sprintf(buffer,"%s/%s", home, readmsg_file);
X
X if ((fd = fopen (buffer, "w")) == NULL) {
X dprint(1, (debugfile,
X "Error: couldn't create file %s - error %s (%s)\n",
X buffer, error_name(errno), "create_readmsg_file"));
X return; /* no error to user */
X }
X
X if (current)
X fprintf(fd, "%d\n", header_table[current-1].index_number);
X else
X fprintf(fd, "\n");
X
X fclose(fd);
X chown( buffer, userid, groupid);
X}
X
Xlong fsize(fd)
XFILE *fd;
X{
X /** return the size of the current file pointed to by the given
X file descriptor - see "bytes()" for the same function with
X filenames instead of open files...
X **/
X
X struct stat buffer;
X
X (void) fstat(fd, &buffer);
X
X return( (long) buffer.st_size );
X}
SHAR_EOF
chmod 0444 src/file_util.c || echo "restore of src/file_util.c fails"
echo "x - extracting src/fileio.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/fileio.c &&
X
Xstatic char rcsid[] = "@(#)$Id: fileio.c,v 2.1 88/09/15 20:28:24 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: fileio.c,v $
X * Revision 2.1 88/09/15 20:28:24 syd
X * checked in with -k by syd at 88.09.15.20.28.24.
X *
X * Revision 2.1 88/07/21 09:58:30 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:05 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** File I/O routines, including deletion from the mailbox!
X
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name();
X
Xcopy_message(prefix, dest_file, remove_header, remote)
Xchar *prefix;
XFILE *dest_file;
Xint remove_header, remote;
X{
X /** Copy current message to destination file, with optional 'prefix'
X as the prefix for each line. If remove_header is true, it will
X skip lines in the message until it finds the end of header line...
X then it will start copying into the file... If remote is true
X then it will append "remote from <hostname>" at the end of the
X very first line of the file (for remailing)
X
X If "forwarding" is true then it'll do some nice things to
X ensure that the forwarded message looks pleasant (e.g. remove
X stuff like ">From " lines and "Received:" lines, and prefix
X the entire message with "Forwarded message:\n" etc etc)
X **/
X
X char buffer[LONG_SLEN];
X register int ok = 1, lines, in_header = 1, first_line = TRUE,
X ignoring = FALSE;
X
X /** get to the first line of the message desired **/
X
X if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
X dprint(1, (debugfile,
X "ERROR: Attempt to seek %d bytes into file failed (%s)",
X header_table[current-1].offset, "copy_message"));
X error1("ELM [seek] failed trying to read %d bytes into file",
X header_table[current-1].offset);
X return;
X }
X
X /* how many lines in message? */
X
X lines = header_table[current-1].lines;
X
X /* set up for forwarding just in case... */
X
X if (forwarding) remove_header = FALSE;
X
X /* now while not EOF & still in message... copy it! */
X
X while (ok && lines--) {
X ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL);
X if (strlen(buffer) < 2) in_header = 0;
X if (ok)
X if (! (remove_header && in_header))
X if (first_line && remote) {
X no_ret(buffer);
X fprintf(dest_file, "%s%s remote from %s\n",
X prefix, buffer, hostname);
X first_line = FALSE;
X }
X else if (! in_header && first_word(buffer, "From ")) {
X dprint(1, (debugfile,
X "\n*** Internal Problem...Tried to add the following;\n"));
X dprint(1, (debugfile,
X " '%s'\nto output file (copy_message) ***\n", buffer));
X ok = 0; /* STOP NOW! */
X }
X else if (! in_header || ! forwarding)
X fprintf(dest_file, "%s%s", prefix, buffer);
X else if (forwarding) {
X if (first_line) {
X first_line = FALSE;
X fprintf(dest_file, "Forwarded message:\n\n");
X }
X else if (first_word(buffer, "Received:" ) ||
X first_word(buffer, ">From" ) ||
X first_word(buffer, "Return-Path:"))
X ignoring = TRUE;
X else if (ignoring && ! whitespace(buffer[0])) {
X ignoring = FALSE;
X fprintf(dest_file, "%s%s", prefix, buffer);
X }
X else if (! ignoring || ! in_header)
X fprintf(dest_file, "%s%s", prefix, buffer);
X }
X }
X if (strlen(buffer) + strlen(prefix) > 1)
X fprintf(dest_file, "\n"); /* blank line to keep mailx happy *sigh* */
X}
X
X/******** the following routines are for a nice clean way to preserve
X the stats related to the file we're currently reading and all
X*********/
X
Xstatic struct stat statbuff;
X
Xsave_file_stats(fname)
Xchar *fname;
X{
X struct stat *stat();
X
X stat(fname, &statbuff);
X
X dprint(2, (debugfile, "** saved stats for file %s **\n", fname));
X}
X
Xrestore_file_stats(fname)
Xchar *fname;
X{
X /** restore the file mode, but set our umask to 0 first to
X ensure that doesn't get in the way... **/
X
X int old_umask, i;
X
X old_umask = umask(0);
X
X i = chmod(fname, statbuff.st_mode & 0777);
X
X dprint(2, (debugfile, "** chmod(%s, %.3o) returns %d [errno=%d] **\n",
X fname, statbuff.st_mode & 0777, i, errno));
X
X i = chown(fname, statbuff.st_uid, statbuff.st_gid);
X
X dprint(2, (debugfile, "** chown(%s, %d, %d) returns %d [errno=%d] **\n",
X fname, statbuff.st_uid, statbuff.st_gid, i, errno));
X
X (void) umask(old_umask);
X}
X
X/** and finally, here's something for that evil trick: site hiding **/
X
X#ifdef SITE_HIDING
X
Xint
Xis_a_hidden_user(specific_username)
Xchar *specific_username;
X{
X /** Returns true iff the username is present in the list of
X 'hidden users' on the system.
X **/
X
X FILE *hidden_users;
X char buffer[SLEN];
X
X this line is deliberately inserted to ensure that you THINK
X about what you're doing, and perhaps even contact the author
X of Elm before you USE this option...
X
X if ((hidden_users = fopen (HIDDEN_SITE_USERS,"r")) == NULL) {
X dprint(1, (debugfile,
X "Couldn't open hidden site file %s [%s]\n",
X HIDDEN_SITE_USERS, error_name(errno)));
X return(FALSE);
X }
X
X while (fscanf(hidden_users, "%s", buffer) != EOF)
X if (strcmp(buffer, specific_username) == 0) {
X dprint(3, (debugfile, "** Found user '%s' in hidden site file!\n",
X specific_username));
X fclose(hidden_users);
X return(TRUE);
X }
X
X fclose(hidden_users);
X dprint(3, (debugfile,
X "** Couldn't find user '%s' in hidden site file!\n",
X specific_username));
X
X return(FALSE);
X}
X
X#endif
SHAR_EOF
chmod 0444 src/fileio.c || echo "restore of src/fileio.c fails"
echo "x - extracting src/forms.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/forms.c &&
X
Xstatic char rcsid[] = "@(#)$Id: forms.c,v 2.1 88/09/15 20:28:28 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X *
X * Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X * Syd Weinstein, Elm Corrdinator
X * syd@dsinc.UUCP dsinc!syd
X *
X *******************************************************************************
X * $Log: forms.c,v $
X * Revision 2.1 88/09/15 20:28:28 syd
X * checked in with -k by syd at 88.09.15.20.28.28.
X *
X * Revision 2.1 88/07/21 09:58:32 edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X *
X * Revision 2.0 88/06/27 17:25:05 edc
X * The original 2.0 gamma sources as leaked from HP
X *
X *
X *
X ******************************************************************************/
X
X/** This set of files supports the 'forms' options (AT&T Mail Forms) to
X the mail system. The specs are drawn from a document from AT&T entitled
X "Standard for Exchanging Forms on AT&T Mail", version 1.9.
X
X**/
X
X/** Some notes on the format of a FORM;
X
X First off, in AT&T Mail parlance, this program only supports SIMPLE
X forms, currently. This means that while each form must have three
X sections;
X
X [options-section]
X ***
X [form-image]
X ***
X [rules-section]
X
X this program will ignore the first and third sections completely. The
X program will assume that the user merely enteres the form-image section,
X and will append and prepend the triple asterisk sequences that *MUST*
X be part of the message. The messages are also expected to have a
X specific header - "Content-Type: mailform" - which will be added on all
X outbound mail and checked on inbound...
X**/
X
X#include "headers.h"
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
X
Xcheck_form_file(filename)
Xchar *filename;
X{
X /** This routine returns the number of fields in the specified file,
X or -1 if an error is encountered. **/
X
X FILE *form;
X char buffer[SLEN];
X register int field_count = 0;
X
X if ((form = fopen(filename, "r")) == NULL) {
X error2("Error %s trying to open %s to check fields!",
X error_name(errno), filename);
X return(-1);
X }
X
X while (fgets(buffer, SLEN, form) != NULL) {
X field_count += occurances_of(COLON, buffer);
X }
X
X fclose(form);
X
X return(field_count);
X}
X
Xformat_form(filename)
Xchar *filename;
X{
X /** This routine accepts a validated file that is the middle
X section of a form message and prepends and appends the appropriate
X instructions. It's pretty simple.
X This returns the number of forms in the file, or -1 on errors
X **/
X
X FILE *form, *newform;
X char newfname[SLEN], buffer[SLEN];
X register form_count = 0;
X
X dprint(4, (debugfile, "Formatting form file '%s'\n", filename));
X
X /** first off, let's open the files... **/
X
X if ((form = fopen(filename, "r")) == NULL) {
X error("Can't read the message to validate the form!");
X dprint(1, (debugfile,
X "** Error encountered opening file \"%s\" - %s (check_form) **\n",
X filename, error_name(errno)));
X return(-1);
X }
X
X sprintf(newfname, "%s%d", temp_form_file, getpid());
X
X if ((newform = fopen(newfname, "w")) == NULL) {
X error("Couldn't open newform file for form output!");
X dprint(1, (debugfile,
X "** Error encountered opening file \"%s\" - %s (check_form) **\n",
X newfname, error_name(errno)));
X return(-1);
X }
X
X /** the required header... **/
X
X /* these are actually the defaults, but let's be sure, okay? */
X
X fprintf(newform, "WIDTH=78\nTYPE=SIMPLE\nOUTPUT=TEXT\n***\n");
X
X /** and let's have some fun transfering the stuff across... **/
X
X while (fgets(buffer, SLEN, form) != NULL) {
X fputs(buffer, newform);
X form_count += occurances_of(COLON, buffer);
X }
X
X fprintf(newform, "***\n"); /* that closing bit! */
X
X fclose(form);
X fclose(newform);
X
X if (form_count > 0) {
X if (unlink(filename) != 0) {
X error2("Error %s unlinking file %s", error_name(errno), filename);
X return(-1);
X }
X if (link(newfname, filename)) {
X error3("Error %s linking %s to %s", error_name(errno),
X newfname, filename);
X return(-1);
X }
X }
X
X if (unlink(newfname)) {
X error2("Error %s unlinking file %s", error_name(errno), newfname);
X return(-1);
X }
X
X return(form_count);
X}
X
Xint
Xmail_filled_in_form(address, subject)
Xchar *address, *subject;
X{
X /** This is the interesting routine. This one will read the
X message and prompt the user, line by line, for each of
X the fields...returns non-zero if it succeeds
X **/
X
X FILE *fd;
X register int lines = 0, count;
X char buffer[SLEN], *ptr;
X
X dprint(4, (debugfile,
X "replying to form with;\n\taddress=%s and\n\t subject=%s\n",
X address, subject));
X
X if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
X dprint(1, (debugfile,
X "Error: seek %ld resulted in errno %s (%s)\n",
X header_table[current-1].offset, error_name(errno),
X "mail_filled_in_form"));
X error2("ELM [seek] couldn't read %d bytes into file (%s)",
X header_table[current-1].offset, error_name(errno));
X return(0);
X }
X
X /* now we can fly along and get to the message body... */
X
X while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
X if (strlen(buffer) == 1) /* <return> only */
X break;
X else if (strncmp(buffer,"From ", 5) == 0 && lines++ > 0) {
X error("No form in this message!?");
X return(0);
X }
X }
X
X if (ptr == NULL) {
X error("No form in this message!?");
X return(0);
X }
X
X dprint(6, (debugfile, "- past header of form message -\n"));
X
X /* at this point we're at the beginning of the body of the message */
X
X /* now we can skip to the FORM-IMAGE section by reading through a
X line with a triple asterisk... */
X
X while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
X if (strcmp(buffer, "***\n") == 0)
X break; /* we GOT it! It's a miracle! */
X else if (strncmp(buffer, "From ",5) == 0) {
X error("Badly constructed form. Can't reply!");
X return(0);
X }
X }
X
X if (ptr == NULL) {
X error("Badly constructed form. Can't reply!");
X return(0);
X }
X
X dprint(6, (debugfile, "- skipped the non-forms-image stuff -\n"));
X
X /* one last thing - let's open the tempfile for output... */
X
X sprintf(buffer, "%s%d", temp_form_file, getpid());
X
X dprint(2, (debugfile,"-- forms sending using file %s --\n", buffer));
X
X if ((fd = fopen(buffer,"w")) == NULL) {
X error2("Can't open \"%s\" as output file! (%s)", buffer,
X error_name(errno));
X dprint(1, (debugfile,
X "** Error %s encountered trying to open temp file %s;\n",
X error_name(errno), buffer));
X return(0);
X }
X
X /* NOW we're ready to read the form image in and start prompting... */
X
X Raw(OFF);
X ClearScreen();
X
X while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
X dprint(9, (debugfile, "- read %s", buffer));
X if (strcmp(buffer, "***\n") == 0) /* end of form! */
X break;
X
X switch ((count = occurances_of(COLON, buffer))) {
X case 0 : printf("%s", buffer); /* output line */
X fprintf(fd, "%s", buffer);
X break;
X case 1 : if (buffer[0] == COLON) {
X printf(
X"(Enter as many lines as needed, ending with a '.' by itself on a line)\n");
X while (gets(buffer) != NULL)
X if (strcmp(buffer, ".") == 0)
X break;
X else
X fprintf(fd,"%s\n", buffer);
X }
X else
X prompt_for_entry(buffer, fd);
X break;
X default: prompt_for_multiple_entries(buffer, fd, count);
X }
X }
X
X Raw(ON);
X fclose(fd);
X
X /** let's just mail this off now... **/
X
X mail_form(address, subject);
X
X return(1);
X}
X
Xprompt_for_entry(buffer, fd)
Xchar *buffer;
XFILE *fd;
X{
X /** This is called with an entry of the form "prompt:" and will
X display the prompt and save the prompt and the user reply
X in the file "fd"
X **/
X
X char mybuffer[SLEN];
X
X no_ret(buffer);
X
X dprint(7, (debugfile, "prompt-for-entry \"%s\"\n", buffer));
X
X printf("%s ", buffer); fflush(stdout);
X
X gets(mybuffer);
X
X fprintf(fd, "%s: %s\n", buffer, mybuffer);
X}
X
Xprompt_for_multiple_entries(buffer, fd, entries)
Xchar *buffer;
XFILE *fd;
Xint entries;
X{
X /** Almost the same as the above routine, this one deals with lines
X that have multiple colons on them. It must first figure out how
X many spaces to allocate for each field then prompts the user,
X line by line, for the entries...
X **/
X
X char mybuffer[SLEN], prompt[SLEN], spaces[SLEN];
X register int field_size, i, j, offset = 0, extra_tabs = 0;
X
X dprint(7, (debugfile,
X "prompt-for-multiple [%d] -entries \"%s\"\n", entries,
X buffer));
X
X strcpy(prompt, "No Prompt Available:");
X
X while (entries--) {
X j=0;
X i = chloc((char *) buffer + offset, COLON) + 1;
X while (j < i - 1) {
X prompt[j] = buffer[j+offset];
X j++;
X }
X prompt[j] = '\0';
X
X field_size = 0;
X
X while (whitespace(buffer[i+offset])) {
X if (buffer[i+offset] == TAB) {
X field_size += 8 - (i % 8);
X extra_tabs += (8 - (i % 8)) - 1;
X }
X else
X field_size += 1;
X i++;
X }
X
X offset += i;
X
X if (field_size == 0) /* probably last prompt in line... */
X field_size = 80 - (offset + extra_tabs);
X
X prompt_for_sized_entry(prompt, mybuffer, field_size);
X
X spaces[0] = ' '; /* always at least ONE trailing space... */
X spaces[1] = '\0';
X
X for (j = strlen(mybuffer); j < field_size; j++)
X strcat(spaces, " ");
X
X fprintf(fd, "%s: %s%s", prompt, mybuffer, spaces);
X fflush(fd);
X }
X
X fprintf(fd, "\n");
X}
X
Xprompt_for_sized_entry(prompt, buffer, field_size)
Xchar *prompt, *buffer;
Xint field_size;
X{
X /* This routine prompts for an entry of the size specified. */
X
X register int i;
SHAR_EOF
echo "End of part 12"
echo "File src/forms.c is continued in part 13"
echo "13" > s2_seq_.tmp
exit 0
--
=====================================================================
Sydney S. Weinstein, CDP, CCP Elm Coordinator
Datacomp Systems, Inc. Voice: (215) 947-9900
{allegra,bellcore,bpa,vu-vlsi}!dsinc!syd FAX: (215) 938-0235