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