syd@dsinc.UUCP (Syd Weinstein) (12/12/88)
---- Cut Here and unpack ---- #!/bin/sh # this is part 10 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/conn_to.c continued # CurArch=10 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/conn_to.c" sed 's/^X//' << 'SHAR_EOF' >> src/conn_to.c X out what machines the current machine can talk to. This can be X done in one of two ways - either the program can read the L.sys X file, or (if it fails or "UUNAME" define is present) will invoke X uuname to a file, then read the file in! X X**/ X X#include "headers.h" X Xchar *strcpy(); X Xget_connections() X{ X X /** get the direct connections that this machine has, by hook X or by crook (so to speak) X **/ X X#ifndef USE_UUNAME X FILE *lsysfile; X char buffer[SLEN], sysname[NLEN]; X struct lsys_rec *system_record, *previous_record; X int loc_on_line; X#endif X X if (! warnings) { /* skip this - they don't care! */ X talk_to_sys = NULL; X return; X } X X#ifndef USE_UUNAME X X previous_record = NULL; X if ((lsysfile = fopen(Lsys,"r")) == NULL) { X dprint(1, (debugfile, X "Warning: Can't open L.sys file %s (read_lsys)\n", Lsys)); X#endif X X if (read_uuname() == -1) { X error("Warning: couldn't figure out system connections..."); X talk_to_sys = NULL; X } X X#ifndef USE_UUNAME X /** ELSE: already read in uuname() output if we're here!! **/ X return; X } X X while (fgets(buffer, SLEN, lsysfile) != NULL) { X sscanf(buffer,"%s", sysname); X X if (previous_record == NULL) { X dprint(2, (debugfile, X "L.sys\tdirect connection to %s, ", sysname)); X loc_on_line = 30 + strlen(sysname); X previous_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys); X X strcpy(previous_record->name, sysname); X previous_record->next = NULL; X talk_to_sys = previous_record; X } X else if (! talk_to(sysname) && sysname[0] != '#') { X if (loc_on_line + strlen(sysname) > 80) { X dprint(2, (debugfile, "\n\t")); X loc_on_line = 8; X } X dprint(2, (debugfile, "%s, ", sysname)); X loc_on_line += (strlen(sysname) + 2); X system_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys); X X strcpy(system_record->name, sysname); X system_record->next = NULL; X previous_record->next = system_record; X previous_record = system_record; X } X } X X fclose(lsysfile); X X if (loc_on_line != 8) X dprint(2, (debugfile, "\n")); X X dprint(2, (debugfile, "\n")); /* for an even nicer format... */ X#endif X} X Xint Xread_uuname() X{ X /** This routine trys to use the uuname routine to get the names of X all the machines that this machine connects to...it returns X -1 on failure. X **/ X X FILE *fd; X char buffer[SLEN], filename[SLEN]; X struct lsys_rec *system_record, *previous_record; X int loc_on_line; X X sprintf(filename, "%s%d", temp_uuname, getpid()); X sprintf(buffer,"%s > %s", uuname, filename); X X if (system_call(buffer, SH) != 0) { X dprint(1, (debugfile, "Can't get uuname info - system() failed!\n")); X unlink(filename); /* insurance */ X return(-1); X } X X if ((fd = fopen(filename, "r")) == NULL) { X dprint(1, (debugfile, X "Can't get uuname info - can't open file %s for reading\n", X filename)); X unlink(filename); /* insurance */ X return(-1); X } X X previous_record = NULL; X X while (fgets(buffer, SLEN, fd) != NULL) { X no_ret(buffer); X if (previous_record == NULL) { X dprint(2, (debugfile, "uuname\tdirect connection to %s, ", buffer)); X loc_on_line = 30 + strlen(buffer); X previous_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys); X X strcpy(previous_record->name, buffer); X previous_record->next = NULL; X talk_to_sys = previous_record; X } X else { /* don't have to check uniqueness - uuname does that! */ X if (loc_on_line + strlen(buffer) > 80) { X dprint(2, (debugfile, "\n\t")); X loc_on_line = 8; X } X dprint(2, (debugfile, "%s, ", buffer)); X loc_on_line += (strlen(buffer) + 2); X system_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys); X X strcpy(system_record->name, buffer); X system_record->next = NULL; X previous_record->next = system_record; X previous_record = system_record; X } X } X X fclose(fd); X X (void) unlink(filename); /* kill da temp file!! */ X X dprint(2, (debugfile, "\n")); /* for a nice format! Yeah! */ X X return(0); /* it all went okay... */ X} SHAR_EOF echo "File src/conn_to.c is complete" chmod 0444 src/conn_to.c || echo "restore of src/conn_to.c fails" echo "x - extracting src/curses.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/curses.c && X Xstatic char rcsid[] = "@(#)$Id: curses.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: curses.c,v $ X * Revision 2.1 88/09/15 20:27:44 syd X * checked in with -k by syd at 88.09.15.20.27.44. X * X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob> X * There were *two* bugs causing the "command:" prompt to appear X * on the wrong line under a limited set of circumstances. X * X * 88/08/27 ssw X * add deluth patches X * X * 88/08/27 BLA X * count backspaces X * X * Revision 2.1 88/07/21 09:58:05 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:53 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This library gives programs the ability to easily access the X termcap information and write screen oriented and raw input X programs. The routines can be called as needed, except that X to use the cursor / screen routines there must be a call to X InitScreen() first. The 'Raw' input routine can be used X independently, however. X X Modified 2/86 to work (hopefully) on Berkeley systems. If X there are any problems with BSD Unix, please report them to X the author at taylor@hplabs (fixed, if possible!) X X Modified 5/86 to add memory lock support, thanks to the X suggested code by Steve Wolf. X X Modified (as if I'm keeping track) to add 24,80 defaults X X**/ X X/** NOTE THE ADDITION OF: the #ifndef ELM stuff around routines that X we don't use. This is for code size and compile time speed... X**/ X X#include "headers.h" X X#ifdef RAWMODE X# ifdef BSD X# ifndef BSD4_1 X# include <sgtty.h> X# else X# include <termio.h> X# endif X# else X# include <termio.h> X# endif X#endif X X#include <ctype.h> X X#ifdef BSD X#undef tolower X#endif X#include "curses.h" X X#ifdef RAWMODE X# define TTYIN 0 X#endif X X#ifdef SHORTNAMES X# define _clearinverse _clrinv X# define _cleartoeoln _clrtoeoln X# define _cleartoeos _clr2eos X# define _transmit_off xmit_off X# define _transmit_on xmit_on X#endif X X#ifdef RAWMODE X# ifndef BSD Xstruct termio _raw_tty, X _original_tty; X# else X# define TCGETA TIOCGETP X# define TCSETAW TIOCSETP X Xstruct sgttyb _raw_tty, X _original_tty; X# endif X Xstatic int _inraw = 0; /* are we IN rawmode? */ X X#endif X X#define DEFAULT_LINES_ON_TERMINAL 24 X#define DEFAULT_COLUMNS_ON_TERMINAL 80 X Xstatic int _memory_locked = 0; /* are we IN memlock?? */ Xstatic int _line = -1, /* initialize to "trash" */ X _col = -1; X Xstatic int _intransmit; /* are we transmitting keys? */ X Xstatic Xchar *_clearscreen, *_moveto, *_up, *_down, *_right, *_left, X *_setbold, *_clearbold, *_setunderline, *_clearunderline, X *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse, X *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off, X *_set_memlock, *_clear_memlock; X Xstatic Xint _lines, _columns; X Xstatic char _terminal[1024]; /* Storage for terminal entry */ Xstatic char _capabilities[1024]; /* String for cursor motion */ X Xstatic char *ptr = _capabilities; /* for buffering */ X Xint outchar(); /* char output for tputs */ Xchar *tgetstr(), /* Get termcap capability */ X *tgoto(); /* and the goto stuff */ X XInitScreen() X{ X /* Set up all this fun stuff: returns zero if all okay, or; X -1 indicating no terminal name associated with this shell, X -2..-n No termcap for this terminal type known X */ X X int tgetent(), /* get termcap entry */ X err; X char termname[40]; X char *strcpy(), *getenv(); X X if (getenv("TERM") == NULL) return(-1); 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 _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 = ptr; X *ptr++ = '\b'; X *ptr++ = '\0'; 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 strcpy(escape_sequence, _setinverse); X else if (termcap_label[0] == 's' && termcap_label[1] == 'e') X strcpy(escape_sequence, _clearinverse); 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 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 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 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 char *stuff, *tgoto(); 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) X CursorRight(col - _col); X else X CursorLeft(_col - col); X } X else { /* move along to the new x,y loc */ X stuff = tgoto(_moveto, col, row); X tputs(stuff, 1, outchar); X fflush(stdout); X } X } X else if (col == _col && abs(row - _line) < 5) { X if (row < _line) X CursorUp(_line - row); X else X CursorDown(row - _line); X } X else if (_line == row-1 && col == 0) { X putchar('\n'); /* that's */ X putchar('\r'); /* easy! */ X fflush(stdout); X } X else { X stuff = tgoto(_moveto, col, row); X tputs(stuff, 1, outchar); X fflush(stdout); X } X X _line = row; /* to ensure we're really there... */ X _col = col; X X if (scrollafter) { X while (scrollafter--) X putchar('\n'); X putchar('\r'); X } X X return(0); X} X XCarriageReturn() X{ X /** move the cursor to the beginning of the current line **/ X X _col = 0; X X putchar('\r'); X} X XNewLine() X{ X /** move the cursor to the beginning of the next line **/ X X _col = 0; X if (_line < LINES) X _line++; X X putchar('\r'); X putchar('\n'); X} X XCursorUp(n) Xint n; X{ X /** move the cursor up 'n' lines **/ X X _line = (_line-n > 0? _line - n: 0); /* up 'n' lines... */ X X if (!_up) X return(-1); X X while (n-- > 0) X tputs(_up, 1, outchar); X X fflush(stdout); X return(0); X} X X XCursorDown(n) Xint n; X{ X /** move the cursor down 'n' lines **/ X X _line = (_line+n < LINES? _line + n: LINES); /* down 'n' lines... */ X X if (!_down) X return(-1); X X while (n-- > 0) X tputs(_down, 1, outchar); X X fflush(stdout); X return(0); X} X X XCursorLeft(n) Xint n; X{ X /** move the cursor 'n' characters to the left **/ X X _col = (_col - n> 0? _col - n: 0); /* left 'n' chars... */ X X if (!_left) X return(-1); X X while (n-- > 0) X tputs(_left, 1, outchar); X X fflush(stdout); X return(0); X} X X XCursorRight(n) Xint n; X{ X /** move the cursor 'n' characters to the right (nondestructive) **/ X X _col = (_col+n < COLUMNS? _col + n: COLUMNS); /* right 'n' chars... */ X X if (!_right) X return(-1); X X while (n-- > 0) X tputs(_right, 1, outchar); X X fflush(stdout); X return(0); X} 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) Xchar ch; X{ X /** write a character to the current screen location. **/ X X putchar(ch); X X if (ch == BACKSPACE) /* moved BACK one! */ X _col--; X else if (ch == '\r') /* moved BACK to col 0! */ X _col = 0; X else if (ch == '\n') /* moved DOWN one! */ X _line++; X else if (ch >= ' ') /* moved FORWARD one! */ X _col++; 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; Xchar *line; X{ X /** Write a zero argument line at location x,y **/ X X char *p, *pend; X X MoveCursor(x,y); X printf("%s", line); /* to avoid '%' problems */ X fflush(stdout); X _col += printable_chars(line); X X while (_col > COLUMNS) { /* line wrapped around?? */ X _col -= COLUMNS; X (_line < LINES) ? _line++: _line; X } X X /** now let's figure out if we're supposed to do a "<return>" **/ X X pend = line + strlen(line); X for (p = line; p < pend; ) { X if (*p == '\b') X _col--; X if (*p++ == '\n') { X (_line < LINES) ? _line++: _line; X _col = 0; /* on new line! */ X } X } 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#ifdef RAWMODE 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) ioctl(TTYIN, TCSETAW, &_original_tty); X _inraw = 0; X } X else if (state == ON && ! _inraw) { X X (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/ X X (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/ X#ifdef BSD X _raw_tty.sg_flags &= ~(ECHO | CRMOD); /* 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) ioctl(TTYIN, TCSETAW, &_raw_tty); X 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 X#endif 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} SHAR_EOF 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 2.1 88/09/15 20:27:47 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1985 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: date.c,v $ X * Revision 2.1 88/09/15 20:27:47 syd X * checked in with -k by syd at 88.09.15.20.27.47. X * X * 88/08/27 ssw X * Bug fixes from alpha test at dsinc X * fix bug with compares of 12pm vs 12am, old code added 12 for pm X * but 12:01pm is 12 pm not 24 pm. needs to check if == 12, if X * so, for pm leave alone for am subtract 12. X * X * Revision 2.1 88/07/21 09:58:08 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:54 edc X * The original 2.0 gamma sources as leaked from HP X * 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 BSD X# ifndef BSD4_1 X# include <sys/time.h> X# else X# include <time.h> X# include <sys/types.h> X# include <sys/timeb.h> X# endif X#else X# include <time.h> X#endif X X#include <ctype.h> X X#ifdef BSD X#undef toupper X#undef tolower X#endif X 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 *shift_lower(), *strcpy(), *strncpy(); 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 *localtime(); X long junk, /* time in seconds.... */ X time(); X X#ifdef BSD X# ifdef BSD4_1 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 BSD4_1 X timezone(time_zone.timezone, the_time->tm_isdst)); X# else X timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime)); 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 *localtime(); X long junk, /* time in seconds.... */ X time(); 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 if (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_month[the_time->tm_mon]; X the_time->tm_mon += 1; X } X } X else { X the_time->tm_mday -= days_in_month[the_time->tm_mon]; X the_time->tm_mon += 1; X } 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; X the_time->tm_year += 1; 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 Xint Xvalid_date(day, mon, year) Xchar *day, *mon, *year; X{ X /** Validate the given date - returns TRUE iff the date X handed is reasonable and valid. X Ignore month param, okay? X **/ X X register int daynum, yearnum; X X daynum = atoi(day); X yearnum = atoi(year); X X if (daynum < 1 || daynum > 31) { X dprint(3, (debugfile, X "Error: day %d is obviously wrong! (valid_date)\n", X daynum)); X return(0); X } X X if (yearnum < 1 || (yearnum > 100 && yearnum < 1900) || X yearnum > 2000) { X dprint(3, (debugfile, X "Error: year %d is obviously wrong! (valid_date)\n", X yearnum)); X return(0); X } X X return(1); 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 (midnight)", minute); X else if (hour < 12) X sprintf(timestring, "%d:%02d am", hour, minute); X else if (hour == 12) X sprintf(timestring, "%d:%02d (noon)", hour, minute); X else if (hour < 24) X sprintf(timestring, "%d:%02d pm", hour-12, minute); X} X Xint Xcompare_dates(rec1, rec2) Xstruct header_rec *rec1, *rec2; X{ X /** This function works similarly to the "strcmp" function, but X has lots of knowledge about the internal date format... X Apologies to those who "know a better way"... X **/ X X int month1, day1, year1, hour1, minute1, X month2, day2, year2, hour2, minute2; X X year1 = atoi(rec1->year); X year2 = atoi(rec2->year); X X if (year1 != year2) X return( year1 - year2 ); X X /* And HERE's where the performance of this sort dies... */ X X month1 = month_number(rec1->month); /* retch... gag.... */ X month2 = month_number(rec2->month); /* puke... */ X X if (month1 == -1) X dprint(2, (debugfile, X "month_number failed on month '%s'\n", rec1->month)); X X if (month2 == -1) X dprint(2, (debugfile, X "month_number failed on month '%s'\n", rec2->month)); X X if (month1 != month2) X return( month1 - month2 ); X X /* back and cruisin' now, though... */ X X day1 = atoi(rec1->day); /* unfortunately, 2 is greater than 19 */ X day2 = atoi(rec2->day); /* on a dump string-only compare... */ X X if (day1 != day2) X return( day1 - day2 ); X X /* we're really slowing down now... */ X X minute1 = minute2 = -1; X X sscanf(rec1->time, "%d:%d", &hour1, &minute1); X sscanf(rec2->time, "%d:%d", &hour2, &minute2); X X /* did we get the time? If not, try again */ X X if (minute1 < 0) X sscanf(rec1->time, "%2d%2d", &hour1, &minute1); X X if (minute2 < 0) X sscanf(rec2->time, "%2d%2d", &hour2, &minute2); X X /** deal with am/pm, if present... **/ X X if (strlen(rec1->time) > 3) X if (rec1->time[strlen(rec1->time)-2] == 'p') { X if (hour1 != 12) X hour1 += 12; X } X else { X if (hour1 == 12) X hour1 = 0; X } X X if (strlen(rec2->time) > 3) X if (rec2->time[strlen(rec2->time)-2] == 'p') { X if (hour2 != 12) X hour2 += 12; X } X else { X if (hour2 == 12) X hour2 = 0; X } X X if (hour1 != hour2) X return( hour1 - hour2 ); X X return( minute1 - minute2 ); /* ignore seconds... */ 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 *localtime(); X long junk, /* time in seconds.... */ X time(); 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 2.1 88/09/15 20:27:51 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1985 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: delete.c,v $ X * Revision 2.1 88/09/15 20:27:51 syd X * checked in with -k by syd at 88.09.15.20.27.51. X * X * 88/08/27 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob> X * fix inverse video bar X * X * Revision 2.1 88/07/21 09:58:10 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:55 edc X * The original 2.0 gamma sources as leaked from HP X * 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 header_table[current-1].status |= DELETED; X else if (ison(header_table[current-1].status, DELETED)) X clearit(header_table[current-1].status, DELETED); X else X setit(header_table[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(header_table[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(header_table[msg].status)); X X if (on_page(msg)) { X MoveCursor((msg % 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 Xtag_message() X{ X /** Tag current message. If already tagged, untag it. **/ X X if (ison(header_table[current-1].status, TAGGED)) X clearit(header_table[current-1].status, TAGGED); X else X setit(header_table[current-1].status, TAGGED); X X show_msg_tag(current-1); 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((msg % headers_per_page) + 4, 4); X if (msg+1 == current && !arrow_cursor) { X StartBold(); X Writechar( ison(header_table[msg].status, TAGGED)? '+' : ' '); X EndBold(); X } X else X Writechar( ison(header_table[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((msg % headers_per_page) + 4, 2, "%s%c", X show_status(header_table[msg].status), X ison(header_table[msg].status, TAGGED )? '+' : ' '); X EndBold(); X } X else X PutLine2((msg % headers_per_page) + 4, 2, "%s%c", X show_status(header_table[msg].status), X ison(header_table[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 2.1 88/07/21 09:58:11 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: domains.c,v $ X * Revision 2.1 88/07/21 09:58:11 edc X * checked in with -k by syd at 88.09.15.20.27.54. X * X * Revision 2.1 88/07/21 09:58:11 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:56 edc X * The original 2.0 gamma sources as leaked from HP X * 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#include <stdio.h> 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 HOSTNAME '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(); Xunsigned long sleep(); 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[2*NLEN], address[2*NLEN], domain[2*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[2*NLEN], field2[2*NLEN], field3[2*NLEN]; X char *path, *template, *expanded, *mydomain, *strtok(); X int matched = 0, in_percent = 0; X register int i, 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 if (field3 == NULL || strlen(field3) == 0) X if (field2 == NULL || strlen(field2) == 0) X template = (char *) field1; X else { X path = (char *) field1; X template = (char *) field2; X } X else { X dprint(1, (debugfile, X "Domain info for %s from file broken into THREE fields!!\n", X domain)); X dprint(1, (debugfile, X "-> %s\n-> %s\n-> %s\n", field1, field2, field3)); X dprint(1, (debugfile, "(this means it's using a defunct field)\n")); X error1("Warning: domain %s uses a defunct field!!", domain); X sleep(2); X path = (char *) field1; X template = (char *) field3; X } 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 (i=0; i < strlen(template); i++) { X if (template[i] == '%') { 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[i]) { X case USERNAME: strcat(address, name); break; X case HOSTNAME: 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("I 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[i])); X } X j = strlen(address); X } X else { X address[j++] = template[i]; 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} 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 2.1 88/09/15 20:27:57 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: edit.c,v $ X * Revision 2.1 88/09/15 20:27:57 syd X * checked in with -k by syd at 88.09.15.20.27.57. X * X * 88/09/01 Rob Bernardo <rob@pbhyf.PacBell.COM> X * fix resync after edit X * X * 88/08/27 ssw X * add deluth patches X * X * 88/08/27 ssw X * Bug fixes from alpha test at dsinc X * problems with linking across file systems fixed. X * X * Revision 2.1 88/07/21 09:58:13 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:57 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This routine is for allowing the user to edit their current mailbox X as they wish. X X**/ X X#include "headers.h" X#include <errno.h> X#include <sys/types.h> X#include <sys/stat.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 mailbox, 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 mailbox file 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_mailbox, *temp_mailbox; X char filename[SLEN], buffer[LONG_SLEN], temp_infile[SLEN]; X struct stat stat_buffer; X int loaded_stat_buffer = FALSE; X X PutLine0(LINES-1,0,"invoking editor..."); X X if (mbox_specified == 0) { X sprintf(filename, "%s%s", temp_mbox, username); X chown(filename, userid, groupid); /* make sure we can! */ X } X else X strcpy(filename, infile); X X /** now get and save the ownership and permissions... **/ X X if (stat(infile, &stat_buffer)) { X error("Warning: couldn't 'stat' file, perms might get mangled"); X sleep(2); X } X else X loaded_stat_buffer = TRUE; X X sprintf(buffer, "%s %s", alternative_editor, filename); X X Raw(OFF); X X if (system_call(buffer, SH) != 0) { X error1("Problems invoking editor %s!", alternative_editor); SHAR_EOF echo "End of part 10" echo "File src/edit.c is continued in part 11" echo "11" > 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