home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume22
/
elm2.3
/
part13
< prev
next >
Wrap
Text File
|
1990-06-07
|
51KB
|
1,962 lines
Subject: v22i072: ELM mail syste, release 2.3, Part13/26
Newsgroups: comp.sources.unix
Approved: rsalz@uunet.UU.NET
X-Checksum-Snefru: f2273946 5ecd860c 7944d294 aa7f34b7
Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
Posting-number: Volume 22, Issue 72
Archive-name: elm2.3/part13
---- Cut Here and unpack ----
#!/bin/sh
# this is part 13 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/curses.c continued
#
CurArch=13
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/curses.c"
sed 's/^X//' << 'SHAR_EOF' >> src/curses.c
X
X if (strcpy(termname, getenv("TERM")) == NULL)
X return(-1);
X
X if ((err = tgetent(_terminal, termname)) != 1)
X return(err-2);
X
X _line = 0; /* where are we right now?? */
X _col = 0; /* assume zero, zero... */
X
X /* load in all those pesky values */
X _clearscreen = tgetstr("cl", &ptr);
X _moveto = tgetstr("cm", &ptr);
X _up = tgetstr("up", &ptr);
X _down = tgetstr("do", &ptr);
X _right = tgetstr("nd", &ptr);
X _left = tgetstr("bs", &ptr);
X _setbold = tgetstr("so", &ptr);
X _clearbold = tgetstr("se", &ptr);
X _setunderline = tgetstr("us", &ptr);
X _clearunderline = tgetstr("ue", &ptr);
X _setinverse = tgetstr("so", &ptr);
X _clearinverse = tgetstr("se", &ptr);
X _sethalfbright = tgetstr("hs", &ptr);
X _clearhalfbright = tgetstr("he", &ptr);
X _cleartoeoln = tgetstr("ce", &ptr);
X _cleartoeos = tgetstr("cd", &ptr);
X _lines = tgetnum("li");
X _columns = tgetnum("co");
X tabspacing = ((tabspacing=tgetnum("it"))==-1 ? 8 : tabspacing);
X _automargin = tgetflag("am");
X _eatnewlineglitch = tgetflag("xn");
X _transmit_on = tgetstr("ks", &ptr);
X _transmit_off = tgetstr("ke", &ptr);
X _set_memlock = tgetstr("ml", &ptr);
X _clear_memlock = tgetstr("mu", &ptr);
X
X
X if (!_left) {
X _left = "\b";
X }
X
X return(0);
X}
X
Xchar *return_value_of(termcap_label)
Xchar *termcap_label;
X{
X /** This will return the string kept by termcap for the
X specified capability. Modified to ensure that if
X tgetstr returns a pointer to a transient address
X that we won't bomb out with a later segmentation
X fault (thanks to Dave@Infopro for this one!)
X
X Tweaked to remove padding sequences.
X **/
X
X static char escape_sequence[20];
X register int i=0,j=0;
X char buffer[20];
X char *myptr, *tgetstr(); /* Get termcap capability */
X
X if (strlen(termcap_label) < 2)
X return(NULL);
X
X if (termcap_label[0] == 's' && termcap_label[1] == 'o')
X {
X if (_setinverse)
X strcpy(escape_sequence, _setinverse);
X else
X return( (char *) NULL );
X }
X else if (termcap_label[0] == 's' && termcap_label[1] == 'e')
X {
X if (_clearinverse)
X strcpy(escape_sequence, _clearinverse);
X else
X return( (char *) NULL );
X }
X else if ((myptr = tgetstr(termcap_label, &ptr)) == NULL)
X return( (char *) NULL );
X else
X strcpy(escape_sequence, myptr);
X
X if (chloc(escape_sequence, '$') != -1) {
X while (escape_sequence[i] != '\0') {
X while (escape_sequence[i] != '$' && escape_sequence[i] != '\0')
X buffer[j++] = escape_sequence[i++];
X if (escape_sequence[i] == '$') {
X while (escape_sequence[i] != '>') i++;
X i++;
X }
X }
X buffer[j] = '\0';
X strcpy(escape_sequence, buffer);
X }
X
X return( (char *) escape_sequence);
X}
X
Xtransmit_functions(newstate)
Xint newstate;
X{
X /** turn function key transmission to ON | OFF **/
X
X if (newstate != _intransmit) {
X _intransmit = ! _intransmit;
X if (newstate == ON)
X tputs(_transmit_on, 1, outchar);
X else
X tputs(_transmit_off, 1, outchar);
X fflush(stdout); /* clear the output buffer */
X }
X}
X
X/****** now into the 'meat' of the routines...the cursor stuff ******/
X
XScreenSize(lines, columns)
Xint *lines, *columns;
X{
X /** returns the number of lines and columns on the display. **/
X
X#ifdef TIOCGWINSZ
X struct winsize w;
X
X if (ioctl(1,TIOCGWINSZ,&w) != -1) {
X _lines = w.ws_row;
X _columns = w.ws_col;
X }
X#endif
X
X if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
X if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
X
X *lines = _lines - 1; /* assume index from zero */
X *columns = _columns;
X}
X
XSetXYLocation(x,y)
Xint x,y;
X{
X /* declare where the cursor is on the screen - useful after using
X * a function that moves cursor in predictable fasion but doesn't
X * set the static x and y variables used in this source file -
X * e.g. getpass().
X */
X
X _line = x;
X _col = y;
X}
X
XGetXYLocation(x,y)
Xint *x,*y;
X{
X /* return the current cursor location on the screen */
X
X *x = _line;
X *y = _col;
X}
X
XClearScreen()
X{
X /* clear the screen: returns -1 if not capable */
X
X _line = 0; /* clear leaves us at top... */
X _col = 0;
X
X if (!_clearscreen)
X return(-1);
X
X tputs(_clearscreen, 1, outchar);
X fflush(stdout); /* clear the output buffer */
X return(0);
X}
X
Xstatic
XCursorUp(n)
Xint n;
X{
X /** move the cursor up 'n' lines **/
X /** Calling function must check that _up is not null before calling **/
X
X _line = (_line-n > 0? _line - n: 0); /* up 'n' lines... */
X
X while (n-- > 0)
X tputs(_up, 1, outchar);
X
X fflush(stdout);
X return(0);
X}
X
X
Xstatic
XCursorDown(n)
Xint n;
X{
X /** move the cursor down 'n' lines **/
X /** Caller must check that _down is not null before calling **/
X
X _line = (_line+n <= LINES? _line + n: LINES); /* down 'n' lines... */
X
X while (n-- > 0)
X tputs(_down, 1, outchar);
X
X fflush(stdout);
X return(0);
X}
X
X
Xstatic
XCursorLeft(n)
Xint n;
X{
X /** move the cursor 'n' characters to the left **/
X /** Caller must check that _left is not null before calling **/
X
X _col = (_col - n> 0? _col - n: 0); /* left 'n' chars... */
X
X while (n-- > 0)
X tputs(_left, 1, outchar);
X
X fflush(stdout);
X return(0);
X}
X
X
Xstatic
XCursorRight(n)
Xint n;
X{
X /** move the cursor 'n' characters to the right (nondestructive) **/
X /** Caller must check that _right is not null before calling **/
X
X _col = (_col+n < COLUMNS? _col + n: COLUMNS); /* right 'n' chars... */
X
X while (n-- > 0)
X tputs(_right, 1, outchar);
X
X fflush(stdout);
X return(0);
X}
X
Xstatic
Xmoveabsolute(col, row)
X{
X
X char *stuff, *tgoto();
X
X stuff = tgoto(_moveto, col, row);
X tputs(stuff, 1, outchar);
X fflush(stdout);
X}
X
XMoveCursor(row, col)
Xint row, col;
X{
X /** move cursor to the specified row column on the screen.
X 0,0 is the top left! **/
X
X int scrollafter = 0;
X
X /* we don't want to change "rows" or we'll mangle scrolling... */
X
X if (col < 0)
X col = 0;
X if (col >= COLUMNS)
X col = COLUMNS - 1;
X if (row < 0)
X row = 0;
X if (row > LINES) {
X if (col == 0)
X scrollafter = row - LINES;
X row = LINES;
X }
X
X if (!_moveto)
X return(-1);
X
X if (row == _line) {
X if (col == _col)
X return(0); /* already there! */
X
X else if (abs(col - _col) < 5) { /* within 5 spaces... */
X if (col > _col && _right)
X CursorRight(col - _col);
X else if (col < _col && _left)
X CursorLeft(_col - col);
X else
X moveabsolute(col, row);
X }
X else /* move along to the new x,y loc */
X moveabsolute(col, row);
X }
X else if (_line == row-1 && col == 0) {
X if (_col != 0)
X putchar('\r');
X putchar('\n');
X fflush(stdout);
X }
X else if (col == _col && abs(row - _line) < 5) {
X if (row < _line && _up)
X CursorUp(_line - row);
X else if (row > _line && _down)
X CursorDown(row - _line);
X else
X moveabsolute(col, row);
X }
X else
X moveabsolute(col, row);
X
X _line = row; /* to ensure we're really there... */
X _col = col;
X
X if (scrollafter) {
X putchar('\r');
X while (scrollafter--)
X putchar('\n');
X }
X
X return(0);
X}
X
XCarriageReturn()
X{
X /** move the cursor to the beginning of the current line **/
X Writechar('\r');
X}
X
XNewLine()
X{
X /** move the cursor to the beginning of the next line **/
X
X Writechar('\r');
X Writechar('\n');
X}
X
XStartBold()
X{
X /** start boldface/standout mode **/
X
X if (!_setbold)
X return(-1);
X
X tputs(_setbold, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
X
XEndBold()
X{
X /** compliment of startbold **/
X
X if (!_clearbold)
X return(-1);
X
X tputs(_clearbold, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
X#ifndef ELM
X
XStartUnderline()
X{
X /** start underline mode **/
X
X if (!_setunderline)
X return(-1);
X
X tputs(_setunderline, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
X
XEndUnderline()
X{
X /** the compliment of start underline mode **/
X
X if (!_clearunderline)
X return(-1);
X
X tputs(_clearunderline, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
X
XStartHalfbright()
X{
X /** start half intensity mode **/
X
X if (!_sethalfbright)
X return(-1);
X
X tputs(_sethalfbright, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
XEndHalfbright()
X{
X /** compliment of starthalfbright **/
X
X if (!_clearhalfbright)
X return(-1);
X
X tputs(_clearhalfbright, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
XStartInverse()
X{
X /** set inverse video mode **/
X
X if (!_setinverse)
X return(-1);
X
X tputs(_setinverse, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
X
XEndInverse()
X{
X /** compliment of startinverse **/
X
X if (!_clearinverse)
X return(-1);
X
X tputs(_clearinverse, 1, outchar);
X fflush(stdout);
X return(0);
X}
X
Xint
XHasMemlock()
X{
X /** returns TRUE iff memory locking is available (a terminal
X feature that allows a specified portion of the screen to
X be "locked" & not cleared/scrolled... **/
X
X return ( _set_memlock && _clear_memlock );
X}
X
Xstatic int _old_LINES;
X
Xint
XStartMemlock()
X{
X /** mark the current line as the "last" line of the portion to
X be memory locked (always relative to the top line of the
X screen) Note that this will alter LINES so that it knows
X the top is locked. This means that (plus) the program
X will scroll nicely but (minus) End memlock MUST be called
X whenever we leave the locked-memory part of the program! **/
X
X if (! _set_memlock)
X return(-1);
X
X if (! _memory_locked) {
X
X _old_LINES = LINES;
X LINES -= _line; /* we can't use this for scrolling */
X
X tputs(_set_memlock, 1, outchar);
X fflush(stdout);
X _memory_locked = TRUE;
X }
X
X return(0);
X}
X
Xint
XEndMemlock()
X{
X /** Clear the locked memory condition... **/
X
X if (! _set_memlock)
X return(-1);
X
X if (_memory_locked) {
X LINES = _old_LINES; /* back to old setting */
X
X tputs(_clear_memlock, 1, outchar);
X fflush(stdout);
X _memory_locked = FALSE;
X }
X return(0);
X}
X
X#endif /* ndef ELM */
X
XWritechar(ch)
Xregister int ch;
X{
X /** write a character to the current screen location. **/
X
X static int wrappedlastchar = 0;
X int justwrapped, nt;
X
X justwrapped = 0;
X
X /* if return, just go to left column. */
X if(ch == '\r') {
X if (wrappedlastchar)
X justwrapped = 1; /* preserve wrap flag */
X else {
X putchar('\r');
X _col = 0;
X }
X }
X
X /* if newline and terminal just did a newline without our asking,
X * do nothing, else output a newline and increment the line count */
X else if (ch == '\n') {
X if (!wrappedlastchar) {
X putchar('\n');
X if (_line < LINES)
X ++_line;
X }
X }
X
X /* if backspace, move back one space if not already in column 0 */
X else if (ch == BACKSPACE) {
X if(_col != 0) {
X putchar('\b');
X _col--;
X } /* else BACKSPACE does nothing */
X }
X
X /* if bell, ring the bell but don't advance the column */
X else if (ch == '\007') {
X putchar(ch);
X }
X
X /* if a tab, output it */
X else if (ch == '\t') {
X putchar(ch);
X if((nt=next_tab(_col+1)) > prev_tab(COLUMNS))
X _col = COLUMNS-1;
X else
X _col = nt-1;
X }
X
X else {
X /* if some kind of non-printable character change to a '?' */
X if(!isascii(ch) || !isprint(ch))
X ch = '?';
X
X /* if we only have one column left, simulate automargins if
X * the terminal doesn't have them */
X if (_col == COLUMNS - 1) {
X putchar(ch);
X if (!_automargin || _eatnewlineglitch) {
X putchar('\r');
X putchar('\n');
X }
X if (_line < LINES)
X ++_line;
X _col = 0;
X justwrapped = 1;
X }
X
X /* if we are here this means we have no interference from the
X * right margin - just output the character and increment the
X * column position. */
X else {
X putchar(ch);
X _col++;
X }
X }
X
X wrappedlastchar = justwrapped;
X
X return(0);
X}
X
X/*VARARGS2*/
X
XWrite_to_screen(line, argcount, arg1, arg2, arg3)
Xchar *line;
Xint argcount;
Xchar *arg1, *arg2, *arg3;
X{
X /** This routine writes to the screen at the current location.
X when done, it increments lines & columns accordingly by
X looking for "\n" sequences... **/
X
X switch (argcount) {
X case 0 :
X PutLine0(_line, _col, line);
X break;
X case 1 :
X PutLine1(_line, _col, line, arg1);
X break;
X case 2 :
X PutLine2(_line, _col, line, arg1, arg2);
X break;
X case 3 :
X PutLine3(_line, _col, line, arg1, arg2, arg3);
X break;
X }
X}
X
XPutLine0(x, y, line)
Xint x,y;
Xregister char *line;
X{
X /** Write a zero argument line at location x,y **/
X
X MoveCursor(x,y);
X while(*line)
X Writechar(*line++);
X fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine1(x,y, line, arg1)
Xint x,y;
Xchar *line;
Xchar *arg1;
X{
X /** write line at location x,y - one argument... **/
X
X char buffer[VERY_LONG_STRING];
X
X sprintf(buffer, line, arg1);
X
X PutLine0(x, y, buffer);
X fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine2(x,y, line, arg1, arg2)
Xint x,y;
Xchar *line;
Xchar *arg1, *arg2;
X{
X /** write line at location x,y - one argument... **/
X
X char buffer[VERY_LONG_STRING];
X
X sprintf(buffer, line, arg1, arg2);
X
X PutLine0(x, y, buffer);
X fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine3(x,y, line, arg1, arg2, arg3)
Xint x,y;
Xchar *line;
Xchar *arg1, *arg2, *arg3;
X{
X /** write line at location x,y - one argument... **/
X
X char buffer[VERY_LONG_STRING];
X
X sprintf(buffer, line, arg1, arg2, arg3);
X
X PutLine0(x, y, buffer);
X fflush(stdout);
X}
X
XCleartoEOLN()
X{
X /** clear to end of line **/
X
X if (!_cleartoeoln)
X return(-1);
X
X tputs(_cleartoeoln, 1, outchar);
X fflush(stdout); /* clear the output buffer */
X return(0);
X}
X
XCleartoEOS()
X{
X /** clear to end of screen **/
X
X if (!_cleartoeos)
X return(-1);
X
X tputs(_cleartoeos, 1, outchar);
X fflush(stdout); /* clear the output buffer */
X return(0);
X}
X
X
XRawState()
X{
X /** returns either 1 or 0, for ON or OFF **/
X
X return( _inraw );
X}
X
XRaw(state)
Xint state;
X{
X /** state is either ON or OFF, as indicated by call **/
X
X if (state == OFF && _inraw) {
X (void) ttsetattr(TTYIN,&_original_tty);
X _inraw = 0;
X }
X else if (state == ON && ! _inraw) {
X
X (void) ttgetattr(TTYIN, &_original_tty);
X (void) ttgetattr(TTYIN, &_raw_tty); /** again! **/
X
X#if !defined(TERMIO) && !defined(TERMIOS)
X _raw_tty.sg_flags &= ~(ECHO); /* echo off */
X _raw_tty.sg_flags |= CBREAK; /* raw on */
X#else
X _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */
X
X _raw_tty.c_cc[VMIN] = '\01'; /* minimum # of chars to queue */
X _raw_tty.c_cc[VTIME] = '\0'; /* minimum time to wait for input */
X
X#endif
X (void) ttsetattr(TTYIN, &_raw_tty);
X _inraw = 1;
X }
X}
X
Xint
XReadCh()
X{
X /** read a character with Raw mode set! **/
X
X register int result;
X char ch;
X result = read(0, &ch, 1);
X return((result <= 0 ) ? EOF : ch);
X}
X
Xoutchar(c)
Xchar c;
X{
X /** output the given character. From tputs... **/
X /** Note: this CANNOT be a macro! **/
X
X putc(c, stdout);
X}
X
SHAR_EOF
echo "File src/curses.c is complete"
chmod 0444 src/curses.c || echo "restore of src/curses.c fails"
echo "x - extracting src/date.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/date.c &&
X
Xstatic char rcsid[] = "@(#)$Id: date.c,v 4.1 90/04/28 22:42:41 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: date.c,v $
X * Revision 4.1 90/04/28 22:42:41 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** return the current date and time in a readable format! **/
X/** also returns an ARPA RFC-822 format date... **/
X
X
X#include "headers.h"
X
X#ifdef I_TIME
X# include <time.h>
X#endif
X#ifdef I_SYSTIME
X# include <sys/time.h>
X#endif
X#ifdef BSD
X# include <sys/types.h>
X# include <sys/timeb.h>
X#endif
X
X#include <ctype.h>
X
X#ifndef _POSIX_SOURCE
Xextern struct tm *localtime();
Xextern long time();
X#endif
X
X#ifdef BSD
X#undef toupper
X#undef tolower
X#endif
X
X#define MONTHS_IN_YEAR 11 /* 0-11 equals 12 months! */
X#define FEB 1 /* 0 = January */
X#define DAYS_IN_LEAP_FEB 29 /* leap year only */
X
X#define ampm(n) (n > 12? n - 12 : n)
X#define am_or_pm(n) (n > 11? (n > 23? "am" : "pm") : "am")
X#define leapyear(year) ((year % 4 == 0) && (year % 100 != 0))
X
Xchar *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
X "Fri", "Sat", "" };
X
Xchar *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
X
Xint days_in_month[] = { 31, 28, 31, 30, 31, 30,
X 31, 31, 30, 31, 30, 31, -1};
X
X#ifdef BSD
X char *timezone();
X#else
X extern char *tzname[];
X#endif
X
Xchar *get_arpa_date()
X{
X /** returns an ARPA standard date. The format for the date
X according to DARPA document RFC-822 is exemplified by;
X
X Mon, 12 Aug 85 6:29:08 MST
X
X **/
X
X static char buffer[SLEN]; /* static character buffer */
X struct tm *the_time; /* Time structure, see CTIME(3C) */
X long junk; /* time in seconds.... */
X
X#ifdef BSD
X# ifndef TZ_MINUTESWEST
X struct timeb loc_time;
X
X junk = time((long *) 0);
X ftime(&loc_time);
X# else
X struct timeval time_val;
X struct timezone time_zone;
X
X gettimeofday(&time_val, &time_zone);
X junk = time_val.tv_sec;
X# endif
X
X#else
X junk = time((long *) 0); /* this must be here for it to work! */
X#endif
X
X the_time = localtime(&junk);
X
X sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
X arpa_dayname[the_time->tm_wday],
X the_time->tm_mday % 32,
X arpa_monname[the_time->tm_mon],
X the_time->tm_year % 100,
X the_time->tm_hour % 24,
X the_time->tm_min % 61,
X the_time->tm_sec % 61,
X#ifdef BSD
X#ifdef TZ_MINUTESWEST
X# ifdef GOULD_NP1
X the_time->tm_zone);
X# else
X timezone(time_zone.tz_minuteswest, the_time->tm_isdst));
X# endif
X#else
X timezone(loc_time.timezone, the_time->tm_isdst));
X#endif
X#else
X tzname[the_time->tm_isdst]);
X#endif
X
X return( (char *) buffer);
X}
X
Xdays_ahead(days, buffer)
Xint days;
Xchar *buffer;
X{
X /** return in buffer the date (Day, Mon Day, Year) of the date
X 'days' days after today.
X **/
X
X struct tm *the_time; /* Time structure, see CTIME(3C) */
X long junk; /* time in seconds.... */
X
X junk = time((long *) 0); /* this must be here for it to work! */
X the_time = localtime(&junk);
X
X /* increment the day of the week */
X
X the_time->tm_wday = (the_time->tm_wday + days) % 7;
X
X /* the day of the month... */
X the_time->tm_mday += days;
X
X while (the_time->tm_mday > days_in_month[the_time->tm_mon]) {
X if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) {
X if (the_time->tm_mday > DAYS_IN_LEAP_FEB) {
X the_time->tm_mday -= DAYS_IN_LEAP_FEB;
X the_time->tm_mon += 1;
X }
X else
X break; /* Is Feb 29, so leave */
X }
X else {
X the_time->tm_mday -= days_in_month[the_time->tm_mon];
X the_time->tm_mon += 1;
X }
X
X /* check the month of the year */
X if (the_time->tm_mon > MONTHS_IN_YEAR) {
X the_time->tm_mon -= (MONTHS_IN_YEAR + 1);
X the_time->tm_year += 1;
X }
X }
X
X /* now, finally, build the actual date string */
X
X sprintf(buffer, "%s, %d %s %d",
X arpa_dayname[the_time->tm_wday],
X the_time->tm_mday % 32,
X arpa_monname[the_time->tm_mon],
X the_time->tm_year % 100);
X}
X
Xfix_date(entry)
Xstruct header_rec *entry;
X{
X /** This routine will 'fix' the date entry for the specified
X message. This consists of 1) adjusting the year to 0-99
X and 2) altering time from HH:MM:SS to HH:MM am|pm **/
X
X if (atoi(entry->year) > 99)
X sprintf(entry->year,"%d", atoi(entry->year) - 1900);
X
X fix_time(entry->time);
X}
X
Xfix_time(timestring)
Xchar *timestring;
X{
X /** Timestring in format HH:MM:SS (24 hour time). This routine
X will fix it to display as: HH:MM [am|pm] **/
X
X int hour, minute;
X
X sscanf(timestring, "%d:%d", &hour, &minute);
X
X if (hour < 1 || hour == 24)
X sprintf(timestring, "12:%02d am", minute);
X else if (hour < 12)
X sprintf(timestring, "%d:%02d am", hour, minute);
X else if (hour == 12)
X sprintf(timestring, "12:%02d pm", minute);
X else if (hour < 24)
X sprintf(timestring, "%d:%02d pm", hour-12, minute);
X}
X
Xint
Xcompare_parsed_dates(rec1, rec2)
Xstruct date_rec rec1, rec2;
X{
X /** This function is very similar to the compare_dates
X function but assumes that the two record structures
X are already parsed and stored in "date_rec" format.
X **/
X
X if (rec1.year != rec2.year)
X return( rec1.year - rec2.year );
X
X if (rec1.month != rec2.month)
X return( rec1.month - rec2.month );
X
X if (rec1.day != rec2.day)
X return( rec1.day - rec2.day );
X
X if (rec1.hour != rec2.hour)
X return( rec1.hour - rec2.hour );
X
X return( rec1.minute - rec2.minute ); /* ignore seconds... */
X}
X
Xint
Xmonth_number(name)
Xchar *name;
X{
X /** return the month number given the month name... **/
X
X char ch;
X
X switch (tolower(name[0])) {
X case 'a' : if ((ch = tolower(name[1])) == 'p') return(APRIL);
X else if (ch == 'u') return(AUGUST);
X else return(-1); /* error! */
X
X case 'd' : return(DECEMBER);
X case 'f' : return(FEBRUARY);
X case 'j' : if ((ch = tolower(name[1])) == 'a') return(JANUARY);
X else if (ch == 'u') {
X if ((ch = tolower(name[2])) == 'n') return(JUNE);
X else if (ch == 'l') return(JULY);
X else return(-1); /* error! */
X }
X else return(-1); /* error */
X case 'm' : if ((ch = tolower(name[2])) == 'r') return(MARCH);
X else if (ch == 'y') return(MAY);
X else return(-1); /* error! */
X case 'n' : return(NOVEMBER);
X case 'o' : return(OCTOBER);
X case 's' : return(SEPTEMBER);
X default : return(-1);
X }
X}
X
X#ifdef SITE_HIDING
X
Xchar *get_ctime_date()
X{
X /** returns a ctime() format date, but a few minutes in the
X past...(more cunningness to implement hidden sites) **/
X
X static char buffer[SLEN]; /* static character buffer */
X struct tm *the_time; /* Time structure, see CTIME(3C) */
X long junk; /* time in seconds.... */
X
X#ifdef BSD
X struct timeval time_val;
X struct timezone time_zone;
X#endif
X
X#ifdef BSD
X gettimeofday(&time_val, &time_zone);
X junk = time_val.tv_sec;
X#else
X junk = time((long *) 0); /* this must be here for it to work! */
X#endif
X the_time = localtime(&junk);
X
X sprintf(buffer, "%s %s %d %02d:%02d:%02d %d",
X arpa_dayname[the_time->tm_wday],
X arpa_monname[the_time->tm_mon],
X the_time->tm_mday % 32,
X min(the_time->tm_hour % 24, (rand() % 24)),
X min(abs(the_time->tm_min % 61 - (rand() % 60)), (rand() % 60)),
X min(abs(the_time->tm_sec % 61 - (rand() % 60)), (rand() % 60)),
X the_time->tm_year % 100 + 1900);
X
X return( (char *) buffer);
X}
X
X#endif
SHAR_EOF
chmod 0444 src/date.c || echo "restore of src/date.c fails"
echo "x - extracting src/delete.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/delete.c &&
X
Xstatic char rcsid[] = "@(#)$Id: delete.c,v 4.1 90/04/28 22:42:43 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: delete.c,v $
X * Revision 4.1 90/04/28 22:42:43 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** Delete or undelete files: just set flag in header record!
X Also tags specified message(s)...
X
X**/
X
X#include "headers.h"
X
Xchar *show_status();
X
Xdelete_msg(real_del, update_screen)
Xint real_del, update_screen;
X{
X /** Delete current message. If real-del is false, then we're
X actually requested to toggle the state of the current
X message... **/
X
X if (real_del)
X headers[current-1]->status |= DELETED;
X else if (ison(headers[current-1]->status, DELETED))
X clearit(headers[current-1]->status, DELETED);
X else
X setit(headers[current-1]->status, DELETED);
X
X if (update_screen)
X show_msg_status(current-1);
X}
X
Xundelete_msg(update_screen)
Xint update_screen;
X{
X /** clear the deleted message flag **/
X
X clearit(headers[current-1]->status, DELETED);
X
X if (update_screen)
X show_msg_status(current-1);
X}
X
Xshow_msg_status(msg)
Xint msg;
X{
X /** show the status of the current message only. **/
X
X char tempbuf[3];
X
X strcpy(tempbuf, show_status(headers[msg]->status));
X
X if (on_page(msg)) {
X MoveCursor(((compute_visible(msg+1)-1) % headers_per_page) + 4, 2);
X if (msg+1 == current && !arrow_cursor) {
X StartBold();
X Writechar( tempbuf[0] );
X EndBold();
X }
X else
X Writechar( tempbuf[0] );
X }
X}
X
Xint
Xtag_message(update_screen)
Xint update_screen;
X{
X /** Tag current message and return TRUE.
X If already tagged, untag it and return FALSE. **/
X
X int istagged;
X
X if (ison(headers[current-1]->status, TAGGED)) {
X clearit(headers[current-1]->status, TAGGED);
X istagged = FALSE;
X } else {
X setit(headers[current-1]->status, TAGGED);
X istagged = TRUE;
X }
X
X if(update_screen)
X show_msg_tag(current-1);
X return(istagged);
X}
X
Xshow_msg_tag(msg)
Xint msg;
X{
X /** show the tag status of the current message only. **/
X
X if (on_page(msg)) {
X MoveCursor(((compute_visible(msg+1)-1) % headers_per_page) + 4, 4);
X if (msg+1 == current && !arrow_cursor) {
X StartBold();
X Writechar( ison(headers[msg]->status, TAGGED)? '+' : ' ');
X EndBold();
X }
X else
X Writechar( ison(headers[msg]->status, TAGGED)? '+' : ' ');
X }
X}
X
Xshow_new_status(msg)
Xint msg;
X{
X /** If the specified message is on this screen, show
X the new status (could be marked for deletion now,
X and could have tag removed...)
X **/
X
X if (on_page(msg))
X if (msg+1 == current && !arrow_cursor) {
X StartBold();
X PutLine2(((compute_visible(msg+1)-1) % headers_per_page) + 4,
X 2, "%s%c", show_status(headers[msg]->status),
X ison(headers[msg]->status, TAGGED )? '+' : ' ');
X EndBold();
X }
X else
X PutLine2(((compute_visible(msg+1)-1) % headers_per_page) + 4,
X 2, "%s%c", show_status(headers[msg]->status),
X ison(headers[msg]->status, TAGGED )? '+' : ' ');
X}
SHAR_EOF
chmod 0444 src/delete.c || echo "restore of src/delete.c fails"
echo "x - extracting src/domains.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/domains.c &&
X
Xstatic char rcsid[] = "@(#)$Id: domains.c,v 4.1 90/04/28 22:42:44 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: domains.c,v $
X * Revision 4.1 90/04/28 22:42:44 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** This file contains all the code dealing with the expansion of
X domain based addresses in Elm. It uses the file "domains" as
X defined in the sysdefs.h file.
X
X From a file format and idea in "uumail" - designed by Stan Barber.
X**/
X
X#if defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES)
X
X#include <ctype.h>
X
X#include "headers.h"
X
X#ifdef BSD
X# undef toupper
X# undef tolower
X#endif
X
X/** define the various characters that we can encounter after a "%" sign
X in the template file...
X**/
X
X#define USERNAME 'U' /* %U = the name of the remote user */
X#define RMTMNAME 'N' /* %N = the remote machine name */
X#define FULLNAME 'D' /* %D = %N + domain info given */
X#define NPATH 'R' /* %R = path to %N from pathalias */
X#define PPATH 'P' /* %P = path to 'P' from pathalias */
X#define OBSOLETE 'S' /* %S = (used to be suffix string) */
X
X/** and finally some characters that are allowed in user/machine names **/
X
X#define okay_others(c) (c == '-' || c == '^' || c == '$' || c == '_')
X
X/** and some allowed ONLY in the username field **/
X
X#define special_chars(c) (c == '%' || c == ':')
X
Xchar *find_path_to(), *expand_domain(), *match_and_expand_domain();
Xchar *strcpy(), *strcat(), *strtok();
Xvoid rewind();
X
Xopen_domain_file()
X{
X if ((domainfd = fopen(domains, "r")) == NULL) {
X dprint(2, (debugfile,"Warning: can't open file %s as domains file\n",
X domains));
X }
X else {
X dprint(3, (debugfile,
X "Opened '%s' as the domain database\n\n", domains));
X }
X
X /* if it fails it'll instantiate domainfd to NULL which is
X exactly what we want to have happen!! */
X}
X
Xchar *expand_domain(buffer)
Xchar *buffer;
X{
X /** Expand the address 'buffer' based on the domain information,
X if any. Returns NULL if it can't expand it for any reason.
X **/
X
X char name[NLEN], address[NLEN], domain[NLEN];
X char *match_and_expand_domain();
X
X if (domainfd == NULL) return(NULL); /* no file present! */
X
X if (explode(buffer, name, address, domain))
X return( match_and_expand_domain(domain, name, address) );
X else { /* invalid format - not "user@host.domain" */
X dprint(2, (debugfile,
X "Invalid format for domain expansion: %s (expand_domain)\n",
X buffer));
X return(NULL);
X }
X}
X
Xint
Xexplode(buffer, name, address, domain)
Xchar *buffer, *name, *address, *domain;
X{
X /** Break buffer, if in format name@machine.domain, into the
X component parts, otherwise return ZERO and don't worry
X about the values of the parameters!
X **/
X
X register int i, j = 0;
X
X /** First get the name... **/
X
X for (i=0; buffer[i] != '@'; i++) {
X if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && !
X special_chars(buffer[i]))
X return(0); /* invalid character in string! */
X name[i] = buffer[i];
X }
X
X name[i++] = '\0';
X
X /** now let's get the machinename **/
X
X while (buffer[i] != '.') {
X if (! isalnum(buffer[i]) && ! okay_others(buffer[i]))
X return(0); /* invalid character in string! */
X address[j++] = buffer[i++];
X }
X address[j] = '\0';
X
X j = 0;
X
X /** finally let's get the domain information (there better be some!) **/
X
X while (buffer[i] != '\0') {
X if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) &&
X buffer[i] != '.')
X return(0); /* an you fail again, bozo! */
X domain[j++] = toupper(buffer[i]);
X i++;
X }
X
X domain[j] = '\0';
X
X return(j); /* if j == 0 there's no domain info! */
X}
X
Xchar *match_and_expand_domain(domain, name, machine)
Xchar *domain, *name, *machine;
X{
X /** Given the domain, try to find it in the domain file and
X if found expand the entry and return the result as a
X character string...
X **/
X
X static char address[SLEN];
X char buffer[SLEN], domainbuff[NLEN];
X char field1[NLEN], field2[NLEN], field3[NLEN];
X char *path, *template, *expanded, *mydomain;
X int matched = 0, in_percent = 0;
X register int j = 0;
X
X address[j] = '\0';
X
X domainbuff[0] = '\0';
X mydomain = (char *) domainbuff; /* set up buffer etc */
X
X do {
X rewind(domainfd); /* back to ground zero! */
X
X if (strlen(mydomain) > 0) { /* already in a domain! */
X mydomain++; /* skip leading '.' */
X while (*mydomain != '.' && *mydomain != ',')
X mydomain++; /* next character */
X if (*mydomain == ',')
X return (NULL); /* didn't find domain! */
X }
X else
X sprintf(mydomain, "%s,", domain); /* match ENTIRELY! */
X
X /* whip through file looking for the entry, please... */
X
X while (fgets(buffer, SLEN, domainfd) != NULL) {
X if (buffer[0] == '#') /* skip comments */
X continue;
X if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */
X matched++; /* Gotcha! Remember this momentous event! */
X break;
X }
X }
X
X if (! matched)
X continue; /* Nothing. Not a sausage! Step through! */
X
X /** We've matched the domain! **/
X
X no_ret(buffer);
X
X (void) strtok(buffer, ","); /* skip the domain info */
X
X strcpy(field1, strtok(NULL, ",")); /* fun */
X strcpy(field2, strtok(NULL, ",")); /* stuff */
X strcpy(field3, strtok(NULL, ",")); /* eh? */
X
X path = (char *) NULL;
X
X /* now we merely need to figure out what permutation this is!
X
X Fields are null if they have only a blank in them or are null.
X If fields 2 and 3 are null, use field 1 as the template.
X --else--
X If field 3 is null and 2 is not, use field 2 as the template.
X --else--
X Field 3 is the template. */
X
X
X if (strcmp(field3," ") == 0 || field3[0] == '\0'){
X if (strcmp(field2," ") == 0 || field2[0] == '\0')
X template = (char *) field1;
X else {
X path = (char *) field1;
X template = (char *) field2;
X }
X }
X else {
X path = (char *) field1;
X template = (char *) field3;
X }
X dprint(1, (debugfile,
X "-> %s\n-> %s\n-> %s\n", field1, field2, field3));
X dprint(1, (debugfile,
X "Path-> %s\nTemplate-> %s\n", path, template));
X
X if (strlen(path) > 0 && path[0] == '>')
X path++; /* skip the '>' character, okay? */
X
X j = 0; /* address is zero, right now, right?? */
X address[j] = '\0'; /* make sure string is too! */
X
X for (; *template; template++) {
X if (*template == '%') {
X if (! in_percent) /* just hit a NEW percent! */
X in_percent = 1;
X else { /* just another percent sign on the wall... */
X address[j++] = '%';
X address[j] = '\0'; /* ALWAYS NULL terminate */
X in_percent = 0;
X }
X }
X else if (in_percent) { /* Hey! a real command string */
X in_percent = 0;
X switch (*template) {
X case USERNAME: strcat(address, name); break;
X case RMTMNAME: strcat(address, machine); break;
X case FULLNAME: strcat(address, machine);
X strcat(address, domain); break;
X case NPATH :
X
X if ((expanded = find_path_to(machine, FALSE)) == NULL) {
X dprint(3, (debugfile,
X "\nCouldn't expand system path '%s' (%s)\n\n",
X machine, "domains"));
X error1("Couldn't find a path to %s!", machine);
X sleep(2);
X return(NULL); /* failed!! */
X }
X strcat(address, expanded); /* isn't this fun??? */
X
X break;
X
X case PPATH :
X
X if ((expanded = find_path_to(path, FALSE)) == NULL) {
X dprint(3, (debugfile,
X "\nCouldn't expand system path '%s' (%s)\n\n",
X path, "domains"));
X error1("Couldn't find a path to %s!", path);
X sleep(2);
X return(NULL); /* failed!! */
X }
X strcat(address, expanded); /* isn't this fun??? */
X
X break;
X
X case OBSOLETE: /* fall through.. */
X default : dprint(1, (debugfile,
X "\nError: Bad sequence in template file for domain '%s': %%%c\n\n",
X domain, *template));
X }
X j = strlen(address);
X }
X else {
X address[j++] = *template;
X address[j] = '\0'; /* null terminate */
X }
X }
X
X address[j] = '\0';
X
X } while (strlen(address) < 1);
X
X return( (char *) address);
X}
X#endif
SHAR_EOF
chmod 0444 src/domains.c || echo "restore of src/domains.c fails"
echo "x - extracting src/edit.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/edit.c &&
X
Xstatic char rcsid[] = "@(#)$Id: edit.c,v 4.1 90/04/28 22:42:46 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: edit.c,v $
X * Revision 4.1 90/04/28 22:42:46 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** This routine is for allowing the user to edit their current folder
X as they wish.
X
X**/
X
X#include "headers.h"
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy();
Xlong bytes();
Xunsigned long sleep();
X
X#ifdef ALLOW_MAILBOX_EDITING
X
Xedit_mailbox()
X{
X /** Allow the user to edit their folder, always resynchronizing
X afterwards. Due to intense laziness on the part of the
X programmer, this routine will invoke $EDITOR on the entire
X file. The mailer will ALWAYS resync on the folder
X even if nothing has changed since, not unreasonably, it's
X hard to figure out what occurred in the edit session...
X
X Also note that if the user wants to edit their incoming
X mailbox they'll actually be editing the tempfile that is
X an exact copy. More on how we resync in that case later
X in this code.
X **/
X
X FILE *real_folder, *temp_folder;
X char edited_file[SLEN], buffer[SLEN];
X
X if(folder_type == SPOOL) {
X if(save_file_stats(cur_folder) != 0) {
X error1("Problems saving permissions of folder %s!", cur_folder);
X Raw(ON);
X sleep(2);
X return(0);
X }
X }
X
X PutLine0(LINES-1,0,"Invoking editor...");
X
X strcpy(edited_file, (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder));
X sprintf(buffer, "%s %s", alternative_editor, edited_file);
X
X Raw(OFF);
X
X if (system_call(buffer, SH, TRUE, FALSE) != 0) {
X error1("Problems invoking editor %s!", alternative_editor);
X Raw(ON);
X sleep(2);
X return(0);
X }
X
X Raw(ON);
X
X if (folder_type == SPOOL) { /* uh oh... now the toughie... */
X
X if (bytes(cur_folder) != mailfile_size) {
X
X /* SIGH. We've received mail since we invoked the editor
X on the folder. We'll have to do some strange stuff to
X remedy the problem... */
X
X PutLine0(LINES, 0, "Warning: new mail received...");
X CleartoEOLN();
X
X if ((temp_folder = fopen(edited_file, "a")) == NULL) {
X dprint(1, (debugfile,
X "Attempt to open \"%s\" to append failed in %s\n",
X edited_file, "edit_mailbox"));
X set_error("Couldn't reopen tempfile. Edit LOST!");
X return(1);
X }
X /** Now let's lock the folder up and stream the new stuff
X into the temp file... **/
X
X lock(OUTGOING);
X if ((real_folder = fopen(cur_folder, "r")) == NULL) {
X dprint(1, (debugfile,
X "Attempt to open \"%s\" for reading new mail failed in %s\n",
X cur_folder, "edit_mailbox"));
X sprintf(buffer, "Couldn't open %s for reading! Edit LOST!",
X cur_folder);
X set_error(buffer);
X unlock();
X return(1);
X }
X if (fseek(real_folder, mailfile_size, 0) == -1) {
X dprint(1, (debugfile,
X "Couldn't seek to end of cur_folder (offset %ld) (%s)\n",
X mailfile_size, "edit_mailbox"));
X set_error("Couldn't seek to end of folder. Edit LOST!");
X unlock();
X return(1);
X }
X
X /** Now we can finally stream the new mail into the tempfile **/
X
X while (fgets(buffer, SLEN, real_folder) != NULL)
X fprintf(temp_folder, "%s", buffer);
X
X fclose(real_folder);
X fclose(temp_folder);
X
X } else lock(OUTGOING);
X
X /* remove real mail_file and then
X * link or copy the edited mailfile to real mail_file */
X
X (void)unlink(cur_folder);
X
X if (link(edited_file, cur_folder) != 0) {
X if (errno == EXDEV || errno == EEXIST) {
X /* attempt to link across file systems */
X if (copy(edited_file, cur_folder) != 0) {
X Write_to_screen(
X "\n\rCouldn't copy %s to mailfile %s!\n\r",
X 2, edited_file, cur_folder);
X Write_to_screen(
X "\n\rYou'll need to check out %s for your mail.\n\r",
X 1, edited_file);
X Write_to_screen("** %s - %s. **\n\r", 2,
X error_name(errno), error_description(errno));
X unlock(); /* ciao!*/
X emergency_exit();
X }
X } else {
X Write_to_screen("\n\rCouldn't link %s to mailfile %s!\n\r",2,
X edited_file, cur_folder);
X Write_to_screen(
X "\n\rYou'll need to check out %s for your mail.\n\r",
X 1, edited_file);
X Write_to_screen("** %s - %s. **\n\r", 2,
X error_name(errno), error_description(errno));
X unlock(); /* ciao!*/
X emergency_exit();
X }
X }
X
X /* restore file permissions before removing lock */
X
X if(restore_file_stats(cur_folder) != 1) {
X error1("Problems restoring permissions of folder %s!", cur_folder);
X Raw(ON);
X sleep(2);
X }
X
X unlock();
X unlink(edited_file); /* remove the edited mailfile */
X error("Changes incorporated into new mail...");
X
X } else
X error("Resynchronizing with new version of folder...");
X
X sleep(2);
X ClearScreen();
X newmbox(cur_folder, FALSE);
X showscreen();
X return(1);
X}
X
X#endif
SHAR_EOF
chmod 0444 src/edit.c || echo "restore of src/edit.c fails"
echo "x - extracting src/editmsg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/editmsg.c &&
X
Xstatic char rcsid[] = "@(#)$Id: editmsg.c,v 4.1 90/04/28 22:42:47 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: editmsg.c,v $
X * Revision 4.1 90/04/28 22:42:47 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** This contains routines to do with starting up and using an editor (or two)
X from within Elm. This stuff used to be in mailmsg2.c...
X**/
X
X#include "headers.h"
X#include <errno.h>
X#ifndef BSD
X/* BSD has already included setjmp.h in headers.h */
X#include <setjmp.h>
X#endif /* BSD */
X#include <signal.h>
X#include <ctype.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy(), *format_long();
Xunsigned long sleep();
X
Xint
Xedit_the_message(filename, already_has_text)
Xchar *filename;
Xint already_has_text;
X{
X /** Invoke the users editor on the filename. Return when done.
X If 'already has text' then we can't use the no-editor option
X and must use 'alternative editor' (e.g. $EDITOR or default_editor)
X instead... **/
X
X char buffer[SLEN];
X register int stat, return_value = 0, old_raw;
X
X buffer[0] = '\0';
X
X if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) {
X if (already_has_text)
X sprintf(buffer, "%s %s", alternative_editor, filename);
X else
X return(no_editor_edit_the_message(filename));
X }
X
X PutLine0(LINES, 0, "Invoking editor..."); fflush(stdout);
X if (strlen(buffer) == 0)
X sprintf(buffer,"%s %s", editor, filename);
X
X chown(filename, userid, groupid); /* file was owned by root! */
X
X if (( old_raw = RawState()) == ON)
X Raw(OFF);
X
X if (cursor_control)
X transmit_functions(OFF); /* function keys are local */
X
X if ((stat = system_call(buffer, SH, TRUE, FALSE)) != 0) {
X dprint(1,(debugfile,
X "System call failed with stat %d (edit_the_message)\n",
X stat));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X ClearLine(LINES-1);
X error1("Can't invoke editor '%s' for composition.", editor);
X sleep(2);
X return_value = 1;
X }
X
X if (old_raw == ON)
X Raw(ON);
X
X if (cursor_control)
X transmit_functions(ON); /* function keys are local */
X
X return(return_value);
X}
X
Xstatic char simple_continue[] = "(Continue.)\n\r";
Xstatic char post_ed_continue[] =
X"(Continue entering message. Type ^D or '.' on a line by itself to end.)\n\r";
X
Xextern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING],
X expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING],
X bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING],
X subject[SLEN];
X
Xint interrupts_while_editing; /* keep track 'o dis stuff */
Xjmp_buf edit_location; /* for getting back from interrupt */
X
Xchar *strip_commas();
Xlong fsize();
X
Xint
Xno_editor_edit_the_message(filename)
Xchar *filename;
X{
X /** If the current editor is set to either "builtin" or "none", then
X invoke this program instead. As it turns out, this and the
X routine above have a pretty incestuous relationship (!)...
X **/
X
X FILE *edit_fd;
X char buffer[SLEN], editor_name[SLEN], buf[SLEN];
X int edit_interrupt(), old_raw;
X#ifdef VOIDSIG
X void (*oldint)(), (*oldquit)();
X#else
X int (*oldint)(), (*oldquit)();
X#endif
X
X if ((edit_fd = fopen(filename, "a")) == NULL) {
X error2("Couldn't open %s for appending [%s].", filename,
X error_name(errno));
X sleep (2);
X dprint(1, (debugfile,
X "Error encountered trying to open file %s;\n", filename));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X return(1);
X }
X
X /** is there already text in this file? **/
X
X if (fsize(edit_fd) > 0L)
X strcpy(buf, "\n\rContinue entering message.");
X else
X strcpy(buf, "\n\rEnter message.");
X strcat(buf, " Type Elm commands on lines by themselves.\n\r");
X sprintf(buf + strlen(buf),
X "Commands include: ^D or '.' to end, %cp to list, %c? for help.\n\r\n\r",
X escape_char, escape_char);
X CleartoEOS();
X Write_to_screen(buf, 0);
X
X oldint = signal(SIGINT, edit_interrupt);
X oldquit = signal(SIGQUIT, edit_interrupt);
X
X interrupts_while_editing = 0;
X
X if (setjmp(edit_location) != 0) {
X if (interrupts_while_editing > 1) {
X
X (void) signal(SIGINT, oldint);
X (void) signal(SIGQUIT, oldquit);
X
X if (edit_fd != NULL) /* insurance... */
X fclose(edit_fd);
X return(1);
X }
X goto more_input; /* read input again, please! */
X }
X
Xmore_input: buffer[0] = '\0';
X
X while (optionally_enter(buffer, -1,-1, FALSE, FALSE) == 0) {
X
X interrupts_while_editing = 0; /* reset to zero... */
X
X if (strcmp(buffer, ".") == 0)
X break; /* '.' is as good as a ^D to us dumb programs :-) */
X if (buffer[0] == escape_char) {
X switch (tolower(buffer[1])) {
X case '?' : tilde_help();
X goto more_input;
X
X case TILDE_ESCAPE: move_left(buffer, 1);
X goto tilde_input; /*!!*/
X
X case 't' : get_with_expansion("\n\rTo: ",
X to, expanded_to, buffer);
X goto more_input;
X case 'b' : get_with_expansion("\n\rBcc: ",
X bcc, expanded_bcc, buffer);
X goto more_input;
X case 'c' : get_with_expansion("\n\rCc: ",
X cc, expanded_cc, buffer);
X goto more_input;
X case 's' : get_with_expansion("\n\rSubject: ",
X subject,NULL,buffer);
X goto more_input;
X
X case 'h' : get_with_expansion("\n\rTo: ", to, expanded_to, NULL);
X get_with_expansion("Cc: ", cc, expanded_cc, NULL);
X get_with_expansion("Bcc: ", bcc,expanded_bcc, NULL);
X get_with_expansion("Subject: ", subject, NULL, NULL);
X goto more_input;
X
X case 'r' : read_in_file(edit_fd, (char *) buffer + 2, 1);
X goto more_input;
X case 'e' : if (strlen(emacs_editor) > 0)
X if (access(emacs_editor, ACCESS_EXISTS) == 0) {
X strcpy(buffer, editor);
SHAR_EOF
echo "End of part 13"
echo "File src/editmsg.c is continued in part 14"
echo "14" > s2_seq_.tmp
exit 0
exit 0 # Just in case...