syd@dsinc.UUCP (Syd Weinstein) (12/13/88)
---- Cut Here and unpack ---- #!/bin/sh # this is part 15 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/mailmsg2.c continued # CurArch=15 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/mailmsg2.c" sed 's/^X//' << 'SHAR_EOF' >> src/mailmsg2.c X X sprintf(fname, "%s/%s", home, dead_letter); X X if ((deadfd = fopen(fname,"a")) == NULL) { X dprint(1, (debugfile, X "\nAttempt to append to deadletter file '%s' failed: %s\n\r", X fname, error_name(errno))); X printf("Message not saved, Sorry.\n\r\n\r"); X return('f'); X } X else if ((messagefd = fopen(filename, "r")) == NULL) { X dprint(1, (debugfile, X "\nAttempt to read reply file '%s' failed: %s\n\r", X filename, error_name(errno))); X printf("Message not saved, Sorry.\n\r\n\r"); X return('f'); X } X X chown (fname, userid, groupid); X X /* if we get here we're okay for everything, right? */ X X while (fgets(buffer, LONG_SLEN, messagefd) != NULL) X fputs(buffer, deadfd); X X fclose(messagefd); X fclose(deadfd); X X printf("Message saved in file \"$HOME/%s\"\n\r\n\r", dead_letter); X X return('f'); /* forget it! */ X } X else switch (ch) { X case '\r': X case '\n': ch = 's'; X case 's' : printf("Send\n\r"); break; X case 'e' : printf("Edit the message\n\r"); break; X case 'h' : printf("Edit the headers\n\r"); break; X default : printf("\n\rI'm afraid I don't understand that - please answer again...\n\r"); X goto batch_reprompt; X } X X return(ch); /* send this baby or whatever! */ X } X else X return('s'); /* SEND! Yow!! */ X } X else if (check_first) { /* used to check strlen(infile) > 0 too? */ Xreprompt: X MoveCursor(LINES,0); X CleartoEOLN(); X ClearLine(LINES-1); X X if (user_level == 0) { X PutLine0(LINES-2,0, "Please choose one of the following options by capitalized letter"); X PutLine1(LINES-1,0, "E)dit the message, edit the H)eaders, S)end it, or F)orget it: s%c", X BACKSPACE); X } X else if (*form_letter == PREFORMATTED) X PutLine1(LINES-1, 0, X "Choose: edit H)eaders, S)end, or F)orget : s%c", X BACKSPACE); X else if (*form_letter == YES) X PutLine1(LINES-1, 0, X "Choose: E)dit form, edit H)eaders, S)end, or F)orget : s%c", X BACKSPACE); X else if (*form_letter == MAYBE) X PutLine1(LINES-1, 0, X "Choose: E)dit msg, edit H)eaders, M)ake form, S)end, or F)orget : s%c", X BACKSPACE); X else X PutLine1(LINES-1, 0, X "Please choose: E)dit msg, edit H)eaders, S)end, or F)orget : s%c", X BACKSPACE); X X fflush(stdin); /* wait for answer! */ X fflush(stdout); X Raw(ON); /* double check... testing only... */ X ch = ReadCh(); X ch = tolower(ch); X X switch (ch) { X case 'f': Write_to_screen("Forget",0); X set_error( X "Message kept - Can be restored at next F)orward, M)ail or R)eply "); X break; X X case '\n' : X case '\r' : X case 's' : Write_to_screen("Send",0); X ch = 's'; /* make sure! */ X break; X X case 'm' : if (*form_letter == MAYBE) { X *form_letter = YES; X switch (check_form_file(filename)) { X case -1 : return('f'); X case 0 : *form_letter = MAYBE; /* check later!*/ X error("No fields in form!"); X return('e'); X default : goto reprompt; X } X } X else { X Write_to_screen("%c??", 1, 07); /* BEEP */ X sleep(1); X goto reprompt; /* yech */ X } X case 'e' : if (*form_letter != PREFORMATTED) { X Write_to_screen("Edit",0); X if (*form_letter == YES) X *form_letter = MAYBE; X } X else { X Write_to_screen("%c??", 1, 07); /* BEEP */ X sleep(1); X goto reprompt; /* yech */ X } X break; X case 'h' : Write_to_screen("Headers",0); X break; X X default : Write_to_screen("%c??", 1, 07); /* BEEP */ X sleep(1); X goto reprompt; /* yech */ X } X X return(ch); X } X else return('s'); X} X XFILE * X#ifdef ALLOW_BCC X write_header_info(filename, long_to, long_cc, long_bcc, form) X char *filename, *long_to, *long_cc, *long_bcc; X#else X write_header_info(filename, long_to, long_cc, form) X char *filename, *long_to, *long_cc; X#endif Xint form; X{ X /** Try to open filedesc as the specified filename. If we can, X then write all the headers into the file. The routine returns X 'filedesc' if it succeeded, NULL otherwise. Added the ability X to have backquoted stuff in the users .elmheaders file! X **/ X X static FILE *filedesc; /* our friendly file descriptor */ X X#ifdef SITE_HIDING X char buffer[SLEN]; X int is_hidden_user; /* someone we should know about? */ X#endif X X char *get_arpa_date(); X X if ((filedesc = fopen(filename, "w")) == NULL) { X dprint(1, (debugfile, X "Attempt to open file %s for writing failed! (write_header_info)\n", X filename)); X dprint(1, (debugfile, "** %s - %s **\n\n", error_name(errno), X error_description(errno))); X error2("Error %s encountered trying to write to %s", X error_name(errno), filename); X sleep(2); X return(NULL); /* couldn't open it!! */ X } X X chown (filename, userid, groupid); X X#ifdef SITE_HIDING X if ((is_hidden_user = is_a_hidden_user(username))) { X /** this is the interesting part of this trick... **/ X sprintf(buffer, "From %s!%s %s\n", HIDDEN_SITE_NAME, X username, get_ctime_date()); X fprintf(filedesc, "%s", buffer); X dprint(1,(debugfile, "\nadded: %s", buffer)); X /** so is this perverted or what? **/ X } X#endif X X X /** Subject moved to top of headers for mail because the X pure System V.3 mailer, in its infinite wisdom, now X assumes that anything the user sends is part of the X message body unless either: X 1. the "-s" flag is used (although it doesn't seem X to be supported on all implementations??) X 2. the first line is "Subject:". If so, then it'll X read until a blank line and assume all are meant X to be headers. X So the gory solution here is to move the Subject: line X up to the top. I assume it won't break anyone elses program X or anything anyway (besides, RFC-822 specifies that the *order* X of headers is irrelevant). Gahhhhh.... X **/ X X fprintf(filedesc, "Subject: %s\n", subject); X X fprintf(filedesc, "To: %s\n", format_long(long_to, strlen("To:"))); X X fprintf(filedesc,"Date: %s\n", get_arpa_date()); X X#ifndef DONT_ADD_FROM X# ifdef SITE_HIDING X if (is_hidden_user) X fprintf(filedesc,"From: %s <%s!%s!%s>\n", full_username, X hostname, HIDDEN_SITE_NAME, username); X else X# endif X# ifdef INTERNET_ADDRESS_FORMAT X# ifdef USE_DOMAIN X fprintf(filedesc,"From: %s <%s@%s%s>\n", full_username, X username, hostname, DOMAIN); X# else X fprintf(filedesc,"From: %s <%s@%s>\n", full_username, X username, hostname); X# endif X# else X fprintf(filedesc,"From: %s <%s!%s>\n", full_username, X hostname, username); X# endif X#endif X X if (cc[0] != '\0') X fprintf(filedesc, "Cc: %s\n", format_long(long_cc, strlen("Cc: "))); X X#ifdef ALLOW_BCC X if (bcc[0] != '\0') X fprintf(filedesc, "Bcc: %s\n", X format_long(long_bcc, strlen("Bcc: "))); X#endif X X if (strlen(action) > 0) X fprintf(filedesc, "Action: %s\n", action); X X if (strlen(priority) > 0) X fprintf(filedesc, "Priority: %s\n", priority); X X if (strlen(expires) > 0) X fprintf(filedesc, "Expires: %s\n", expires); X X if (strlen(reply_to) > 0) X fprintf(filedesc, "Reply-To: %s\n", reply_to); X X if (strlen(in_reply_to) > 0) X fprintf(filedesc, "In-Reply-To: %s\n", in_reply_to); X X if (strlen(user_defined_header) > 0) X fprintf(filedesc, "%s\n", user_defined_header); X X add_mailheaders(filedesc); X X if (form) X fprintf(filedesc, "Content-Type: mailform\n"); X X fprintf(filedesc, "X-Mailer: Elm [version %s]\n\n", version_buff); X X return((FILE *) filedesc); X} X Xcopy_message_across(source, dest) XFILE *source, *dest; X{ X /** copy the message in the file pointed to by source to the X file pointed to by dest. **/ X X int crypted = FALSE; /* are we encrypting? */ X int encoded_lines = 0; /* # lines encoded */ X char buffer[LONG_SLEN]; /* file reading buffer */ X X while (fgets(buffer, LONG_SLEN, source) != NULL) { X if (buffer[0] == '[') { X if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0) X crypted = TRUE; X else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0) X crypted = FALSE; X else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0) X continue; /* next line? */ X } X else if (crypted) { X if (! gotten_key++) X getkey(ON); X else if (! encoded_lines++) X get_key_no_prompt(); /* reinitialize.. */ X X encode(buffer); X } X fputs(buffer, dest); X } X} X Xint Xverify_bounceback() X{ X char ch; X X /** Ensure the user wants to have a bounceback copy too. (This is X only called on messages that are greater than the specified X threshold hops and NEVER for non-uucp addresses.... Returns X TRUE iff the user wants to bounce a copy back.... X **/ X X if (mail_only) { X printf("Would you like a copy \"bounced\" off the remote? (y/n) "); X CleartoEOLN(); X printf("n%c", BACKSPACE); X fflush(stdin); /* wait for answer! */ X fflush(stdout); X ch = ReadCh(); X if (tolower(ch) != 'y') { X printf("No\n\r"); X return(FALSE); X } X else X printf("Yes - Bounceback included\n\r"); X } X else { X MoveCursor(LINES,0); X CleartoEOLN(); X PutLine1(LINES,0, X "\"Bounce\" a copy off the remote machine? (y/n) y%c", X BACKSPACE); X fflush(stdin); /* wait for answer! */ X fflush(stdout); X ch = ReadCh(); X if (tolower(ch) != 'y') { X Write_to_screen("No", 0); X fflush(stdout); X return(FALSE); X } X Write_to_screen("Yes!", 0); X fflush(stdout); X } X X return(TRUE); X} SHAR_EOF echo "File src/mailmsg2.c is complete" chmod 0444 src/mailmsg2.c || echo "restore of src/mailmsg2.c fails" echo "x - extracting src/mailtime.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/mailtime.c && X Xstatic char rcsid[] = "@(#)$Id: mailtime.c,v 2.1 88/07/21 09:58:59 edc 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: mailtime.c,v $ X * Revision 2.1 88/07/21 09:58:59 edc X * checked in with -k by syd at 88.09.15.20.28.59. X * X * Revision 2.1 88/07/21 09:58:59 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:18 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This set of routines is used to figure out when the user last read X their mail and to also figure out if a given message is new or not. X X**/ X X#include "headers.h" X X#include <sys/types.h> X#include <sys/stat.h> X#ifdef BSD X# ifndef BSD4_1 X# include <sys/time.h> X# else X# include <time.h> X# include <sys/timeb.h> X# endif X#else X# include <time.h> X#endif X Xresolve_received(entry) Xstruct header_rec *entry; X{ X /** Entry has the data for computing the time and date the X message was received. Fix it and return **/ X X switch (tolower(entry->month[0])) { X case 'j' : if (tolower(entry->month[1]) == 'a') X entry->received.month = JANUARY; X else if (tolower(entry->month[2]) == 'n') X entry->received.month = JUNE; X else X entry->received.month = JULY; X break; X case 'f' : entry->received.month = FEBRUARY; X break; X case 'm' : if (tolower(entry->month[2]) == 'r') X entry->received.month = MARCH; X else X entry->received.month = MAY; X break; X case 'a' : if (tolower(entry->month[1]) == 'p') X entry->received.month = APRIL; X else X entry->received.month = AUGUST; X break; X case 's' : entry->received.month = SEPTEMBER; X break; X case 'o' : entry->received.month = OCTOBER; X break; X case 'n' : entry->received.month = NOVEMBER; X break; X case 'd' : entry->received.month = DECEMBER; X break; X } X X sscanf(entry->day, "%d", &(entry->received.day)); X X sscanf(entry->year, "%d", &(entry->received.year)); X if (entry->received.year > 100) entry->received.year -= 1900; X X sscanf(entry->time, "%d:%d", &(entry->received.hour), X &(entry->received.minute)); X} X Xget_mailtime() X{ X /** Instantiate the values of the last_read_mail stat X variable based on the file access time/date of the X file mailtime_file. IF the file doesn't exist, X then assume all mail is new. **/ X X struct stat buffer; X struct tm *timebuf; X char filename[SLEN]; X#ifdef BSD X extern struct tm *localtime(); X#endif X X sprintf(filename, "%s/%s", home, mailtime_file); X X if (stat(filename, &buffer) == -1) { X last_read_mail.month = 0; X last_read_mail.day = 0; X last_read_mail.year = 0; X last_read_mail.hour = 0; X last_read_mail.minute = 0; X } X else { /* stat okay... */ X timebuf = (struct tm *) localtime(&(buffer.st_mtime)); X X last_read_mail.month = timebuf->tm_mon; X last_read_mail.day = timebuf->tm_mday; X last_read_mail.year = timebuf->tm_year; X last_read_mail.hour = timebuf->tm_hour; X last_read_mail.minute = timebuf->tm_min; X } X} X Xupdate_mailtime() X{ X /** This routine updates the last modified time of the X .last_read_mail file in the users home directory. X If the file doesn't exist, it creates it!! **/ X X char filename[SLEN]; X X#ifdef BSD X# ifdef BSD4_1 X struct timeb loc_time; X time_t tval; X# else X struct timeval tval[2]; X struct timezone tzone; X# endif X#endif X X sprintf(filename, "%s/%s", home, mailtime_file); X X#ifdef BSD X# ifdef BSD4_1 X tval = (time_t) time((long *) 0); X if (utime(filename, &tval) == -1) X# else X gettimeofday(&tval[0], &tzone); X gettimeofday(&tval[1], &tzone); X X if (utimes(filename, tval) == -1) /* note the "S" */ X# endif X#else X if (utime(filename, (char *) NULL) == -1) /* note no "S" */ X#endif X /** That's what I like about programming for BSD & USG - the easy X portability between 'em. Especially the section 2 calls!! **/ X X (void) creat(filename, 0777); X} X Xnew_msg(entry) Xstruct header_rec entry; X{ X /** Return true if the current message is NEW. This can be X easily tested by seeing 1) if we're reading the incoming X mailbox and then, if so, 2) if the received_on_machine X date is more recent than the last_read_mail date. X **/ X X if (mbox_specified != 0) return(FALSE); /* not incoming */ X X /** Two tests - if received is OLDER than last read mail, then X immediately return FALSE. If received is NEWER than last X read mail then immediately return TRUE **/ X X if (entry.received.year < last_read_mail.year) X return(FALSE); X X if (entry.received.year > last_read_mail.year) X return(TRUE); X X if (entry.received.month < last_read_mail.month) X return(FALSE); X X if (entry.received.month > last_read_mail.month) X return(TRUE); X X if (entry.received.day < last_read_mail.day) X return(FALSE); X X if (entry.received.day > last_read_mail.day) X return(TRUE); X X if (entry.received.hour < last_read_mail.hour) X return(FALSE); X X if (entry.received.hour > last_read_mail.hour) X return(TRUE); X X if (entry.received.minute < last_read_mail.minute) X return(FALSE); X X return(TRUE); X} SHAR_EOF chmod 0444 src/mailtime.c || echo "restore of src/mailtime.c fails" echo "x - extracting src/mkhdrs.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/mkhdrs.c && X Xstatic char rcsid[] = "@(#)$Id: mkhdrs.c,v 2.1 88/07/21 09:59:01 edc 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: mkhdrs.c,v $ X * Revision 2.1 88/07/21 09:59:01 edc X * checked in with -k by syd at 88.09.15.20.29.01. X * X * Revision 2.1 88/07/21 09:59:01 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:20 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This contains all the header generating routines for the ELM X program. X X**/ X X#include <stdio.h> X#include "headers.h" X Xextern char in_reply_to[SLEN]; X Xchar *strcpy(); Xunsigned long sleep(); X Xgenerate_reply_to(msg) Xint msg; X{ X /** Generate an 'in-reply-to' message... **/ X char buffer[SLEN]; X X X if (msg == -1) /* not a reply! */ X in_reply_to[0] = '\0'; X else { X if (chloc(header_table[msg].from, '!') != -1) X tail_of(header_table[msg].from, buffer, FALSE); X else X strcpy(buffer, header_table[msg].from); X sprintf(in_reply_to, "%s; from \"%s\" at %s %s, %s %s", X header_table[msg].messageid, X buffer, X header_table[msg].month, X header_table[msg].day, X header_table[msg].year, X header_table[msg].time); X } X} X Xadd_mailheaders(filedesc) XFILE *filedesc; X{ X /** Add the users .mailheaders file if available. Allow backquoting X in the file, too, for fortunes, etc...*shudder* X **/ X X FILE *fd; X char filename[SLEN], buffer[LONG_SLEN]; X X sprintf(filename, "%s/%s", home, mailheaders); X X if ((fd = fopen(filename, "r")) != NULL) { X while (fgets(buffer, LONG_SLEN, fd) != NULL) X if (strlen(buffer) < 2) { X dprint(2, (debugfile, X "Strlen of line from .elmheaders is < 2 (write_header_info)")); X if (mail_only) X printf("Warning: blank line in %s ignored!\r\n", filename); X else { X error1("Warning: blank line in %s ignored!", filename); X sleep(2); X } X } X else if (occurances_of(BACKQUOTE, buffer) >= 2) X expand_backquote(buffer, filedesc); X else X fprintf(filedesc, "%s", buffer); X X fclose(fd); X } X} X Xexpand_backquote(buffer, filedesc) Xchar *buffer; XFILE *filedesc; X{ X /** This routine is called with a line of the form: X Fieldname: `command` X and is expanded accordingly.. X **/ X X FILE *fd; X char command[SLEN], command_buffer[SLEN], fname[SLEN], X prefix[SLEN]; X register int i, j = 0; X X for (i=0; buffer[i] != BACKQUOTE; i++) X prefix[j++] = buffer[i]; X prefix[j] = '\0'; X X j = 0; X X for (i=chloc(buffer, BACKQUOTE)+1; buffer[i] != BACKQUOTE;i++) X command[j++] = buffer[i]; X command[j] = '\0'; X X sprintf(fname,"%s%d", temp_print, getpid()); X X sprintf(command_buffer, "%s > %s", command, fname); X X system_call(command_buffer, SH); X X if ((fd = fopen(fname, "r")) == NULL) { X if (mail_only) X printf("\nbackquoted command \"%s\" in .elmheaders failed\n", X command); X else X error1("backquoted command \"%s\" in .elmheaders failed", command); X return; X } X X /* If we get a line that is less than 80 - length of prefix then we X can toss it on the same line, otherwise, simply prepend each line X *starting with this line* with a leading tab and cruise along */ X X if (fgets(command_buffer, SLEN, fd) == NULL) X fprintf(filedesc, prefix); X else { X if (strlen(command_buffer) + strlen(prefix) < 80) X fprintf(filedesc, "%s%s", prefix, command_buffer); X else X fprintf(filedesc, "%s\n\t%s", prefix, command_buffer); X X while (fgets(command_buffer, SLEN, fd) != NULL) X fprintf(filedesc, "\t%s", command_buffer); X X fclose(fd); X } X X unlink(fname); /* don't leave the temp file laying around! */ X} SHAR_EOF chmod 0444 src/mkhdrs.c || echo "restore of src/mkhdrs.c fails" echo "x - extracting src/newmbox.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/newmbox.c && X Xstatic char rcsid[] = "@(#)$Id: newmbox.c,v 2.1.1.2 88/09/23 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: newmbox.c,v $ X * Revision 2.1 88/09/15 20:29:04 syd X * checked in with -k by syd at 88.09.15.20.29.04. X * X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob> X * Resend: exiting in cooked mode fix X * fix alignment when new mail arrives in existing and in empty box X * X * 88/08/27 ssw X * add deluth patches X * X * Revision 2.1 88/07/21 09:59:02 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:21 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** read new mailbox file **/ X X#include <ctype.h> X X#ifdef BSD X#undef tolower /* we have our own "tolower" routine instead! */ X#endif X X#include "headers.h" X X#include <sys/types.h> X#include <sys/stat.h> X#include <errno.h> X X#ifdef BSD /* Berkeley has library elsewhere... */ X# ifndef BSD4_1 X# include <sys/time.h> X# else X# include <time.h> X# endif X#else X# include <time.h> X#endif X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(), *strncpy(); Xunsigned long sleep(); Xvoid rewind(); Xvoid exit(); Xlong bytes(); X Xstruct header_rec *realloc(); X Xint Xnewmbox(stat, resync, main_screen) Xint stat, resync, main_screen; X{ X /** Read a new mailbox file or resync on current file. X X Values of stat and what they mean; X X stat = 0 - changing mailboxes from within program X stat = 1 - read default mailbox or infile for the X first time X stat = 2 - read existing mailbox, new mail arrived X stat = 3 - resync on existing mailbox... X X resync is TRUE iff we know the current mailbox has changed. If X it's set to true this means that we MUST READ SOMETHING, even X if it's the current mailbox again!! X X main_screen simply tells where the counting line should be. X X **/ X X int switching_to_default = 0, switching_from_default = 0; X int iterations = 0, redraw = 0; /* for dealing with the '?' answer */ X int old_raw; X char buff[SLEN]; X X if (mbox_specified == 0 && stat == 0) X switching_from_default++; X X if (stat > 0) { X if (stat == 1 && strlen(infile) == 0) { X X /* Subtlety - check to see if there's another instantiation X of Elm (e.g. if the /tmp file is in use). If so, DIE! */ X X sprintf(infile, "%s%s", temp_mbox, username); X if (access(infile, ACCESS_EXISTS) != -1) { X error( X "Hey! An instantiation of Elm is already reading this mail!\n\r"); X fprintf(stderr, X"\n\r [if this is in error then you'll need to remove '%s%s']\n\r", X temp_mbox, username); X Raw(OFF); X exit(1); X } X sprintf(infile, "%s%s", mailhome, username); X } X if (strlen(infile) == 0) /* no filename yet?? */ X sprintf(infile,"%s%s",mailhome, username); X if ((errno = can_access(infile, READ_ACCESS))) { X if (strncmp(infile, mailhome, strlen(mailhome)) == 0) { X /* oh wow. incoming mailbox with no messages... */ X return(1); X } X error2("Can't open mailbox '%s' for reading [%s]", infile, X error_name(errno)); X Raw(OFF); X exit(1); X } X } X else { /* get name of new mailbox! */ X MoveCursor(LINES-3, 30); X CleartoEOS(); X PutLine0(LINES-3, 40, "(Use '?' to list your folders)"); X show_last_error(); Xask_again: X buff[0] = '\0'; X if (iterations++ == 0) { X PutLine0(LINES-2,0,"Name of new mailbox: "); X (void) optionally_enter(buff, LINES-2, 21, FALSE); X ClearLine(LINES-2); X } X else { X printf("\n\rName of new mailbox: "); X (void) optionally_enter(buff, -1, -1, FALSE); X } X if (strlen(buff) == 0) { X if (resync && file_changed) X strcpy(buff, infile); X else X return(redraw); X } X if (strcmp(buff, "?") == 0) { X redraw = 1; /* we'll need to clean the screen */ X if (( old_raw = RawState()) == ON) X Raw(OFF); X list_folders(); X if (old_raw == ON) X Raw(ON); X goto ask_again; X } X if (strcmp(buff, "!") == 0 || X strcmp(buff, "%") == 0) /* go to mailbox */ X sprintf(buff,"%s%s", mailhome, username); X else if (! expand_filename(buff)) { X error1("can't expand file %s", buff); X if (resync && file_changed) X strcpy(buff, infile); X else X return(FALSE); X } X X if (strcmp(buff, infile) == 0 && ! resync) { X error("already reading that mailbox!"); X return(FALSE); X } X X if ((errno = can_access(buff, READ_ACCESS))) { X dprint(2, (debugfile, X "Error: attempt to open %s as mailbox denied (%s)!\n", X buff, "newmbox")); X error1("Permission to open file %s denied", buff); X if (resync && file_changed) X strcpy(buff, infile); X else X return(FALSE); X } X X if (first_word(buff, mailhome)) { /* a mail file! */ X mbox_specified = 0; /* fake program to think that */ X stat = 1; /* we're the default file */ X switching_to_default++; /* remember this act! */ X } X X if (resync && file_changed && strcmp(buff, infile) == 0) X PutLine0(LINES-3,COLUMNS-40,"Resynchronizing file"); X else X PutLine1(LINES-3,COLUMNS-40,"Mailbox: %s", buff); X CleartoEOLN(); X strcpy(infile,buff); X if (! switching_to_default) mbox_specified = 1; X X } X X if (stat == 3) X switching_from_default = TRUE; X X if (switching_from_default) { /* we need to remove the tmp file */ X sprintf(buff, "%s%s", temp_mbox, username); X if (access(buff, ACCESS_EXISTS) != -1) /* is it there at all? */ X if (unlink(buff) != 0) { X error1( X "Sorry, but I can't seem to unlink your temp mail file [%s]\n\r", X error_name(errno)); X silently_exit(); X } X } X X clear_error(); X clear_central_message(); X X header_page = 0; X X if (mailfile != NULL) X (void) fclose(mailfile); /* close it first, to avoid too many open */ X X if ((mailfile = fopen(infile,"r")) == NULL) X message_count = 0; X else if (stat != 2) { /* new mail file! */ X current = 1; X save_file_stats(infile); X message_count = read_headers(FALSE, main_screen); X if (! message_count) current = 0; X } X else { /* resync with current mail file */ X save_file_stats(infile); X message_count = read_headers(TRUE, main_screen); X } X X if (stat != 2) X selected = 0; /* we don't preselect new mailboxes, boss! */ X X return(TRUE); X} X Xint Xread_headers(rereading, main_screen) Xint rereading, main_screen; X{ X /** Reads the headers into the header_table structure and leaves X the file rewound for further I/O requests. If the file being X read is the default mailbox (ie incoming) then it is copied to X a temp file and closed, to allow more mail to arrive during X the elm session. If 'rereading' is set, the program will copy X the status flags from the previous data structure to the new X one if possible. This is (obviously) for re-reading a mailfile! X **/ X X FILE *temp; X struct header_rec *temp_struct; X char buffer[LONG_STRING], temp_filename[SLEN]; X long fbytes = 0L, line_bytes = 0L; X register int line = 0, count = 0, subj = 0, copyit = 0, in_header = 1; X int count_x, count_y = 17, new_messages = 0, err; X int in_to_list = FALSE, forwarding_mail = FALSE, first_line = TRUE; X X static int first_read = 0; X X if (! first_read++) { X ClearLine(LINES-1); X ClearLine(LINES); X if (rereading) X PutLine2(LINES, 0, "Reading in %s, message: %d", infile, X message_count); X else X PutLine1(LINES, 0, "Reading in %s, message: 0", infile); X count_x = LINES; X count_y = 22 + strlen(infile); X } X else { X count_x = LINES-2; X if (main_screen) X PutLine0(LINES-2, 0, "Reading message: 0"); X else { X PutLine0(LINES, 0, "\n"); X PutLine0(LINES, 0, "Reading message: 0"); X count_x = LINES; X } X } X X if (mbox_specified == 0) { X lock(INCOMING); /* ensure no mail arrives while we do this! */ X sprintf(temp_filename,"%s%s",temp_mbox, username); X if (! rereading) { X if (access(temp_filename, ACCESS_EXISTS) != -1) { X /* Hey! What the hell is this? The temp file already exists? */ X /* Looks like a potential clash of processes on the same file! */ X unlock(); /* so remove lock file! */ X error("What's this? The temp mailbox already exists??"); X sleep(2); X error("Ahhhh.....I give up"); X silently_exit(); /* leave without tampering with it! */ X } X if ((temp = fopen(temp_filename,"w")) == NULL) { X err = errno; X unlock(); /* remove lock file! */ X Raw(OFF); X Write_to_screen( X "\nCouldn't open file %s for use as temp mailbox;\n", 1, X temp_filename); X Write_to_screen("** %s - %s **\n", 2, X error_name(err), error_description(err)); X dprint(1, (debugfile, X "Error: Couldn't open file %s as temp mbox. errno %s (%s)\n", X temp_filename, error_name(err), "read_headers")); X leave(); X } X get_mailtime(); X copyit++; X chown(temp_filename, userid, groupid); X chmod(temp_filename, 0700); /* shut off file for other people! */ X } X else { X if ((temp = fopen(temp_filename,"a")) == NULL) { X err = errno; X unlock(); /* remove lock file! */ X Raw(OFF); X Write_to_screen( X "\nCouldn't reopen file %s for use as temp mailbox;\n", 1, X temp_filename); X Write_to_screen("** %s - %s **\n", 2, X error_name(err), error_description(err)); X dprint(1, (debugfile, X "Error: Couldn't reopen file %s as temp mbox. errno %s (%s)\n", X temp_filename, error_name(err), "read_headers")); X emergency_exit(); X } X copyit++; X } X } X X if (rereading) { X if (fseek(mailfile, mailfile_size, 0) == -1) { X err = errno; X Write_to_screen( X "\nCouldn't seek to %ld (end of mailbox) in %s!\n", 2, X mailfile_size, infile); X Write_to_screen("** %s - %s **\n", 2, X error_name(err), error_description(err)); X dprint(1, (debugfile, X "Error: Couldn't seek to end of mailbox %s: (offset %ld) Errno %s (%s)\n", X infile, mailfile_size, error_name(err), "read_headers")); X emergency_exit(); X } X count = message_count; /* next available */ X fbytes = mailfile_size; /* start correctly */ X } X X /** find the size of the mailbox then unlock the file **/ X X mailfile_size = bytes(infile); X unlock(); X X /** now let's copy it all across accordingly... **/ X X while (fbytes < mailfile_size) { X X if (fgets(buffer, LONG_STRING, mailfile) == NULL) break; X X if (fbytes == 0L || first_line) { /* first line of file... */ X if (! mbox_specified) { X if (first_word(buffer, "Forward to ")) { X set_central_message("Mail being forwarded to %s", X (char *) (buffer + 11)); X forwarding_mail = TRUE; X } X } X X /** flush leading blank lines before next test... **/ X if (strlen(buffer) == 1) { X fbytes++; X continue; X } X else X first_line = FALSE; X X if (! first_word(buffer, "From ") && !forwarding_mail) { X PutLine0(LINES, 0, X "\n\rMail file is corrupt!! I can't read it!!\n\r\n\r"); X fflush(stderr); X dprint(1, (debugfile, X "\n\n**** First mail header is corrupt!! ****\n\n")); X dprint(1, (debugfile, "Line is;\n\t%s\n\n", buffer)); X mail_only++; /* to avoid leave() cursor motion */ X leave(); X } X } X X if (copyit) fputs(buffer, temp); X line_bytes = (long) strlen(buffer); X line++; X if (first_word(buffer,"From ")) { X X /** try to allocate new headers, if needed... **/ X X if (count >= max_headers) { X max_headers += KLICK; X if ((temp_struct = realloc(header_table, max_headers * X sizeof(struct header_rec))) == NULL) { X error1( X "\n\r\n\rCouldn't allocate enough memory! Failed on message #%d\n\r\n\r", X count); X leave(); X } X header_table = temp_struct; X } X X if (real_from(buffer, &header_table[count])) { X header_table[count].offset = (long) fbytes; X header_table[count].index_number = count+1; X if (! rereading || count >= message_count) X header_table[count].status = VISIBLE; /* default status! */ X strcpy(header_table[count].subject, ""); /* clear subj */ X strcpy(header_table[count].to, ""); /* clear to */ X X /* Set the number of lines for the _preceding_ message, X * but only if there was a preceding message and X * only if it wasn't calculated already. It would X * have been calculated already if we are only X * reading headers of new messages that have just arrived, X * and the preceding message was one of the old ones. X */ X if ((count) && (!rereading || count > message_count)) X header_table[count-1].lines = line; X if (new_msg(header_table[count])) { X header_table[count].status |= NEW; /* new message! */ X X if (! new_messages++ && point_to_new && ! rereading && X sortby == RECEIVED_DATE) { X current = count+1; X get_page(current); /* make sure we're ON that page! */ X } X X /* Quick comment on that last conditional test... X X We want to move the current pointer to the first new X message IF this is the first of the new messages, the X user requested this feature, we're not rereading the X mailbox (imagine how THAT could screw the user up!), X and we're not in some funky sorting mode (received-date is X the default). As always, I'm open to suggestions on X other ways to have this work intelligently. X */ X X } X count++; X subj = 0; X line = 0; X in_header = 1; X PutLine1(count_x, count_y, "%d", count); X } X } X else if (in_header) { X if (first_word(buffer,">From:")) X parse_arpa_from(buffer, header_table[count-1].from); X else if (first_word(buffer,">From")) X forwarded(buffer, &header_table[count-1]); /* return address */ X else if (first_word(buffer,"Subject:") || X first_word(buffer,"Subj:") || X first_word(buffer,"Re:")) { X if (! subj++) { X remove_first_word(buffer); X copy_sans_escape(header_table[count-1].subject, buffer, STRING); X remove_possible_trailing_spaces(header_table[count-1].subject); X } X } X else if (first_word(buffer,"From:")) X parse_arpa_from(buffer, header_table[count-1].from); X X else if (first_word(buffer, "Message-Id:") || X first_word(buffer, "Message-ID:")) { X buffer[strlen(buffer)-1] = '\0'; X strcpy(header_table[count-1].messageid, X (char *) buffer + 12); X } X X else if (first_word(buffer, "Expires:")) X process_expiration_date((char *) buffer + 9, X &(header_table[count-1].status)); X X /** when it was sent... **/ X X else if (first_word(buffer, "Date:")) X parse_arpa_date(buffer, &header_table[count-1]); X X /** some status things about the message... **/ X X else if (first_word(buffer, "Priority:") || X first_word(buffer, "Importance: 2")) X header_table[count-1].status |= URGENT; X else if (first_word(buffer, "Sensitivity: 2")) X header_table[count-1].status |= PRIVATE; X else if (first_word(buffer, "Sensitivity: 3")) X header_table[count-1].status |= CONFIDENTIAL; X else if (first_word(buffer, "Content-Type: mailform")) X header_table[count-1].status |= FORM_LETTER; X else if (first_word(buffer, "Action:")) X header_table[count-1].status |= ACTION; X X /** next let's see if it's to us or not... **/ X X else if (first_word(buffer, "To:")) { X in_to_list = TRUE; X header_table[count-1].to[0] = '\0'; /* nothing yet */ X figure_out_addressee((char *) buffer +3, X header_table[count-1].to); X } X X else if (buffer[0] == LINE_FEED || buffer[0] == '\0') { X if (in_header) { X in_header = 0; /* in body of message! */ X fix_date(&header_table[count-1]); X } X } X else if (in_to_list == TRUE) { X if (whitespace(buffer[0])) X figure_out_addressee(buffer, header_table[count-1].to); X else in_to_list = FALSE; X } X } X fbytes += (long) line_bytes; X } X X header_table[count > 0? count-1:count].lines = line + 1; X if(count && ! current) current = 1; X X if (mbox_specified == 0) { X unlock(); /* remove lock file! */ X fclose(mailfile); X fclose(temp); X if ((mailfile = fopen(temp_filename,"r")) == NULL) { X err = errno; X MoveCursor(LINES,0); X Raw(OFF); X Write_to_screen("\nAugh! Couldn't reopen %s as temp mail file;\n", X 1, temp_filename); X Write_to_screen("** %s - %s **\n", 2, error_name(err), X error_description(err)); X dprint(1, (debugfile, X "Error: Reopening %s as temp mail file failed! errno %s (%s)\n", X temp_filename, error_name(errno), "read_headers")); X leave(); X } X } X else X rewind(mailfile); X X sort_mailbox(count, 1); /* let's sort this baby now! */ X X return(count); X} SHAR_EOF chmod 0444 src/newmbox.c || echo "restore of src/newmbox.c fails" echo "x - extracting src/opt_utils.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/opt_utils.c && X Xstatic char rcsid[] = "@(#)$Id: opt_utils.c,v 2.1.1.2 88/09/23 edc 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: opt_utils.c,v $ X * Revision 2.1 88/07/21 09:59:07 edc X * checked in with -k by syd at 88.09.15.20.29.07. X * X * Revision 2.1 88/07/21 09:59:07 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:22 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This file contains routines that might be needed for the various X machines that the mailer can run on. Please check the Makefile X for more help and/or information. X X**/ X X#include <stdio.h> X#include "headers.h" X X#ifdef BSD X# include <pwd.h> X#endif X X#ifdef NEED_GETHOSTNAME X# include <sys/types.h> X# include <sys/utsname.h> X#endif X X#ifdef NEED_GETHOSTNAME X Xgethostname(hostname,size) /* get name of current host */ Xint size; Xchar *hostname; X{ X /** Return the name of the current host machine. **/ X X /** This routine compliments of Scott McGregor at the HP X Corporate Computing Center **/ X X int uname(); X struct utsname name; X X (void) uname(&name); X (void) strncpy(hostname,name.nodename,size-1); X hostname[size - 1] = '\0'; X X} X X#endif X X#ifdef NEED_CUSERID X Xchar *cuserid(uname) X char *uname; X{ X /** Added for compatibility with Bell systems, this is the last-ditch X attempt to get the users login name, after getlogin() fails. It X instantiates "uname" to the name of the user...(it also tries X to use "getlogin" again, just for luck) X **/ X /** This wasn't really compatible. According to our man page, X ** It was inconsistent. If the parameter is NULL then you return X ** the name in a static area. Else the ptr is supposed to be a X ** pointer to l_cuserid bytes of memory [probally 9 bytes]... X ** It's not mention what it should return if you copy the name X ** into the array, so I chose NULL. X ** Sept 20, 1988 X ** **WJL** X **/ X X struct passwd *password_entry, *getpwuid(); X char *name, *getlogin(); X static char buf[10]; X register returnonly = 0; X X if (uname == NULL) ++returnonly; X X if ((name = getlogin()) != NULL) { X if (returnonly) { X return(name); X } else { X strcpy(uname, name); X return name; X } X } X else X if (( password_entry = getpwuid(getuid())) != NULL) X { X if (returnonly) X { X return(password_entry->pw_name); X } X else X { X strcpy(uname, password_entry->pw_name); X return name; X } X } X else X { X return NULL; X } X} X X#endif X X#ifdef BSD X X/** some supplementary string functions for Berkeley Unix systems **/ X Xstrspn(source, keys) Xchar *source, *keys; X{ X /** This function returns the length of the substring of X 'source' (starting at zero) that consists ENTIRELY of X characters from 'keys'. This is used to skip over a X defined set of characters with parsing, usually. X **/ X X register int loc = 0, key_index = 0; X X while (source[loc] != '\0') { X key_index = 0; X while (keys[key_index] != source[loc]) X if (keys[key_index++] == '\0') X return(loc); X loc++; X } X X return(loc); X} X Xstrcspn(source, keys) Xchar *source, *keys; X{ X /** This function returns the length of the substring of X 'source' (starting at zero) that consists entirely of X characters NOT from 'keys'. This is used to skip to a X defined set of characters with parsing, usually. X NOTE that this is the opposite of strspn() above X **/ X X register int loc = 0, key_index = 0; X X while (source[loc] != '\0') { X key_index = 0; X while (keys[key_index] != '\0') X if (keys[key_index++] == source[loc]) X return(loc); X loc++; X } X X return(loc); X} X Xchar *strtok(source, keys) Xchar *source, *keys; X{ X /** This function returns a pointer to the next word in source X with the string considered broken up at the characters X contained in 'keys'. Source should be a character pointer X when this routine is first called, then NULL subsequently. X When strtok has exhausted the source string, it will X return NULL as the next word. X X WARNING: This routine will DESTROY the string pointed to X by 'source' when first invoked. If you want to keep the X string, make a copy before using this routine!! X **/ X X register int last_ch; X static char *sourceptr; X char *return_value; X X if (source != NULL) X sourceptr = source; X X if (*sourceptr == '\0') X return(NULL); /* we hit end-of-string last time!? */ X X sourceptr += strspn(sourceptr, keys); /* skip leading crap */ X X if (*sourceptr == '\0') X return(NULL); /* we've hit end-of-string */ X X last_ch = strcspn(sourceptr, keys); /* end of good stuff */ X X return_value = sourceptr; /* and get the ret */ X X sourceptr += last_ch; /* ...value */ X X if (*sourceptr != '\0') /* don't forget if we're at END! */ X sourceptr++; /* and skipping for next time */ X X return_value[last_ch] = '\0'; /* ..ending right */ X X return((char *) return_value); /* and we're outta here! */ X} X Xchar *strpbrk(source, keys) Xchar *source, *keys; X{ X /** Returns a pointer to the first character of source that is any X of the specified keys, or NULL if none of the keys are present X in the source string. X **/ X X register int loc = 0, key_index = 0; X X while (source[loc] != '\0') { X key_index = 0; X while (keys[key_index] != '\0') X if (keys[key_index++] == source[loc]) X return((char *) (source + loc)); X loc++; X } X X return(NULL); X} X Xchar *strchr(buffer, ch) Xchar *buffer, ch; X{ X /** Returns a pointer to the first occurance of the character X 'ch' in the specified string or NULL if it doesn't occur **/ X X char *address; X X address = buffer; X X while (*address != ch) { X if (*address == '\0') X return (NULL); X address++; X } X X return ( (char *) address); X} X X#endif SHAR_EOF chmod 0444 src/opt_utils.c || echo "restore of src/opt_utils.c fails" echo "x - extracting src/options.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/options.c && X Xstatic char rcsid[] = "@(#)$Id: options.c,v 2.1 88/09/15 20:29:10 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: options.c,v $ X * Revision 2.1 88/09/15 20:29:10 syd X * checked in with -k by syd at 88.09.15.20.29.10. X * X * 88/08/27 ssw X * add deluth patches X * X * 88/08/27 ssw X * split tolower and ReadCh due to macro calls X * X * Revision 2.1 88/07/21 09:59:08 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:23 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This set of routines allows the alteration of a number of paramaters X in the Elm mailer, including the following; X X calendar-file <where to put calendar entries> X display pager <how to page messages> X editor <name of composition editor> X folder-dir <folder directory> X sort-by <how to sort mailboxes> X savefile <file to save outbound message copies to> X printmail <how to print messages> X full_username <your full user name for outgoing mail> X X arrow-cursor <on or off> X menu-display <on or off> X X user-level <BEGINNER|INTERMEDIATE|EXPERT> X names-only <on or off> X X And others as they seem useful. X X**/ X X#include "headers.h" X X#ifdef BSD X#undef tolower X#endif X X#undef onoff X#define onoff(n) (n == 1? "ON ":"OFF") X Xchar *one_liner_for(), *level_name(); Xunsigned long sleep(); X Xoptions() X{ X /** change options... **/ X X int ch; X X display_options(); X X clearerr(stdin); X X do { X ClearLine(LINES-4); X X Centerline(LINES-4, X "Select first letter of Option line, '>' to Save, or R)eturn"); X X PutLine0(LINES-2, 0, "Command: "); X X ch = ReadCh(); X ch = tolower(ch); X X clear_error(); /* remove possible "sorting" message etc... */ X X one_liner(one_liner_for(ch)); X X switch (ch) { X case 'c' : optionally_enter(calendar_file, 2, 23, FALSE); break; X case 'd' : optionally_enter(pager, 3, 23, FALSE); X clear_pages = (equal(pager, "builtin+") || X equal(pager, "internal+")); break; X case 'e' : optionally_enter(editor, 4, 23, FALSE); break; X case 'f' : optionally_enter(folders, 5, 23, FALSE); break; X case 's' : change_sort(6,23); break; X case 'o' : optionally_enter(savefile, 7, 23, FALSE); break; X case 'p' : optionally_enter(printout, 8, 23, FALSE); break; X case 'y' : optionally_enter(full_username, 9, 23, FALSE); break; X case 'a' : on_or_off(&arrow_cursor, 12, 23); break; X case 'm' : on_or_off(&mini_menu, 13, 23); X headers_per_page = LINES - (mini_menu ? 13 : 8); break; X X case 'u' : switch_user_level(&user_level,15, 23); break; X case 'n' : on_or_off(&names_only, 16, 23); break; X X case '?' : options_help(); X PutLine0(LINES-2,0,"Command: "); break; X X case '>' : printf("Save options in .elm/elmrc..."); X fflush(stdout); save_options(); break; X X case 'x' : X case 'r' : X case ctrl('D'): X case ctrl('M'): X case ctrl('J'): return; X case ctrl('L'): display_options(); break; X default: error("Command unknown!"); X } X X } while (ch != 'r'); X} X Xdisplay_options() X{ X /** Display all the available options.. **/ X X char *sort_name(); X X ClearScreen(); SHAR_EOF echo "End of part 15" echo "File src/options.c is continued in part 16" echo "16" > 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