sources-request@mirror.UUCP (06/30/86)
Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor> Mod.sources: Volume 6, Issue 30 Archive-name: elm/Part05 # Continuation of Shell Archive, created by hpldat!taylor # This is part 5 # To unpack the enclosed files, please use this file as input to the # Bourne (sh) shell. This can be most easily done by the command; # sh < thisfilename if [ ! -d src ] then echo creating directory src mkdir src fi # ---------- file src/Makefile ---------- filename="src/Makefile" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/Makefile... fi cat << 'END-OF-FILE' > $filename # # Makefile for the ELM mail program. # # (C) Copyright 1986, Dave Taylor # # Last modification: March 7th, 1986 SHELL=/bin/sh ############################## # # if on a BSD system; # DEFINE=-DBSD # LIB2 = -lcurses # else if on a UTS system; # DEFINE=-DUTS # LIB2 = -la -lq # else if on a SUN system; # DEFINE=-DBSD -DSUN # LIB2 = -lcurses # else if on a Pyramid system; # DEFINE=-DBSD -DNO_VAR_ARGS # LIB2 = -lcurses # else DEFINE= LIB2 = # IF you're on an ACSnet system (Australia) then # you'll want to uncomment the following; # DEFINE= ${DEFINE} -DACSNET ############################## CFILES= addr_utils.c alias.c aliasdb.c aliaslib.c args.c bounceback.c \ calendar.c connect_to.c curses.c date.c delete.c domains.c edit.c \ encode.c errno.c file.c file_utils.c fileio.c hdrconfg.c help.c \ initialize.c input_utils.c leavembox.c mailmsg1.c mailmsg2.c \ mailtime.c mkhdrs.c elm.c newmbox.c notesfile.c options.c opt_utils.c \ output_utils.c pattern.c quit.c read_rc.c remail.c reply.c \ return_addr.c savecopy.c screen.c showmsg.c signals.c softkeys.c \ sort.c strings.c syscall.c utils.c validname.c getopt.c string2.c HEADERS=../hdrs/curses.h ../hdrs/defs.h ../hdrs/headers.h ../hdrs/sysdefs.h OBJS= addr_utils.o alias.o aliasdb.o aliaslib.o args.o bounceback.o \ calendar.o connect_to.o curses.o date.o delete.o domains.o edit.o \ encode.o errno.o file.o file_utils.o fileio.o hdrconfg.o help.o \ initialize.o input_utils.o leavembox.o mailmsg1.o mailmsg2.o \ mailtime.o mkhdrs.o elm.o newmbox.o notesfile.o options.o opt_utils.o \ output_utils.o pattern.o quit.o read_rc.o remail.o reply.o \ return_addr.o savecopy.o screen.o showmsg.o signals.o softkeys.o \ sort.o strings.o syscall.o utils.o validname.o getopt.o string2.o BIN= ../bin LIBS= -ltermcap CFLAGS= -O -I../hdrs CC= /bin/cc RM= /bin/rm -f ../bin/elm: ${OBJS} ${EXTRA} ${HEADERS} ../hdrs/elm.h ${CC} -o ${BIN}/elm -n ${OBJS} ${LIBS} ${LIB2} .c.o: ${HEADERS} ${CC} -c ${CFLAGS} ${DEFINE} $*.c curses.o: curses.c ../hdrs/curses.h ${CC} -c ${CFLAGS} -DRAWMODE ${DEFINE} curses.c # curses.c : curses.q # @../bin/quickscreen curses.q # # curses.q : # @cp curses.c curses.q clean: ${RM} ${OBJS} LINT.OUT lint: LINT.OUT LINT.OUT: ${CFILES} lint -p -I../hdrs ${CFILES} > LINT.OUT listing: LISTING LISTING: Makefile INDEX ${HEADERS} ${CFILES} @echo adding file 'Makefile'... @/bin/echo \\f > LISTING @cat Makefile >> LISTING @echo adding file 'INDEX'... @/bin/echo \\f >> LISTING @cat INDEX >> LISTING @../bin/makelisting ${HEADERS} ${CFILES} @echo LISTING generated. index: INDEX INDEX: ${CFILES} ${HEADERS} @echo Creating function definition index @index *.c | sort > INDEX @echo File INDEX generated END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 2822 ] then echo $filename changed - should be 2822 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/alias.c ---------- filename="src/alias.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/alias.c... fi cat << 'END-OF-FILE' > $filename /** alias.c **/ /** This file contains alias stuff (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include <errno.h> char *expand_group(), *get_alias_address(), *expand_system(), *get_token(); char *error_name(), *error_description(); extern int errno; read_alias_files() { /** read the system and user alias files, if present. Set the flags 'systemfiles' and 'userfiles' accordingly. **/ char fname[SLEN]; int hash; if ((hash = open(system_hash_file, O_RDONLY)) == -1) { dprint1(1, "Warning: Can't read system hash file %s (read_alias_files)\n", system_hash_file); goto user; } read(hash, system_hash_table, sizeof system_hash_table); close(hash); /* and data file opened.. */ if ((system_data = open(system_data_file, O_RDONLY)) == -1) { dprint1(1, "Warning: Can't read system data file %s (read_alias_files)\n", system_data_file); goto user; } system_files++; /* got the system files! */ user: sprintf(fname, "%s/.alias_hash", home); if ((hash = open(fname, O_RDONLY)) == -1) { dprint1(1,"Warning: Can't read user hash file %s (read_alias_files)\n", fname); return; } read(hash, user_hash_table, sizeof user_hash_table); close(hash); sprintf(fname, "%s/.alias_data", home); if ((user_data = open(fname, O_RDONLY)) == -1) { dprint1(1, "Warning: can't read user data file %s (read_alias_files)\n", fname); return; } user_files++; /* got user files too! */ } int add_alias() { /** add an alias to the user alias text file. Return zero if alias not added in actuality **/ char name[SLEN], *address, address1[LONG_STRING]; char comment[SLEN]; PutLine0(LINES-2,0,"Enter alias name: "); CleartoEOLN(); Raw(OFF); gets(name, 20); Raw(ON); if (strlen(name) == 0) return(0); if ((address = get_alias_address(name, 0, 0)) != NULL) { dprint1(2, "Attempt to add a duplicate alias [%s] (add_alias)\n", address); if (address[0] == '!') { address[0] = ' '; error1("already a group with that name:%s", address); } else error1("already an alias for that: %s", address); return(0); } PutLine1(LINES-2,0,"Full name for %s: ", name); CleartoEOLN(); Raw(OFF); gets(comment,SLEN); Raw(ON); if (strlen(comment) == 0) strcpy(comment, name); PutLine1(LINES-2,0,"Enter address for %s: ",name); CleartoEOLN(); Raw(OFF); gets(address1,LONG_SLEN); Raw(ON); if (strlen(address1) == 0) { error("No address specified!"); return(0); } add_to_alias_text(name, comment, address1); return(1); } int add_current_alias() { /** alias the current message to the specified name and add it to the alias text file, for processing as the user leaves the program. Returns non-zero iff alias actually added to file **/ char name[SLEN], address1[LONG_STRING], *address; char comment[SLEN]; if (current == 0) { dprint0(3,"Add current alias called without any current message!\n"); error("No message to alias to!"); return(0); } PutLine0(LINES-2,0,"Current message address aliased to: "); CleartoEOLN(); Raw(OFF); gets(name, 20); Raw(ON); if (strlen(name) == 0) /* cancelled... */ return(0); if ((address = get_alias_address(name, 0, 0)) != NULL) { dprint1(3, "Attempt to add a duplicate alias [%s] (add_current_alias)\n", address); if (address[1] == '!') { address[0] = ' '; error1("already a group with that name:%s", address); } else error1("already an alias for that: %s", address); return(0); } PutLine1(LINES-2,0,"Full name of %s: ", name); CleartoEOLN(); Raw(OFF); gets(comment, 40); Raw(ON); get_return(address1); /* grab the return address of this message */ optimize_return(address1); PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1); CleartoEOLN(); add_to_alias_text(name, comment, address1); return(1); } add_to_alias_text(name, comment, address) char *name, *comment, *address; { /** Add the data to the user alias text file. Return zero if we succeeded, 1 if not **/ FILE *file; char fname[SLEN]; sprintf(fname,"%s/.alias_text", home); if ((file = fopen(fname, "a")) == NULL) { dprint2(2, "FILE Failure attempting to add alias to file %s (%s)", fname, "add_to_alias_text"); dprint2(2, "** %s - %s **\n", error_name(errno), error_description(errno)); error1("couldn't open %s to add new alias!", fname); return(1); } fprintf(file,"%s : %s : %s\n", name, comment, address); fclose(file); chown(fname, userid, groupid); return(0); } show_alias_menu() { MoveCursor(LINES-7,0); CleartoEOLN(); MoveCursor(LINES-6,0); CleartoEOLN(); MoveCursor(LINES-5,0); CleartoEOLN(); PutLine0(LINES-7,COLUMNS-45, "Alias commands"); Centerline(LINES-5, "A)lias current msg, Check a P)erson or S)ystem, M)ake new alias, or R)eturn" ); } alias() { /** work with alias commands... **/ char name[NLEN], *address, ch, buffer[SLEN]; int newaliases = 0; if (mini_menu) show_alias_menu(); define_softkeys(ALIAS); while (1) { PutLine0(LINES-3,0,"Alias: "); CleartoEOLN(); ch = ReadCh(); MoveCursor(LINES-1,0); CleartoEOLN(); switch (tolower(ch)) { case 'a': newaliases += add_current_alias(); break; case 'm': newaliases += add_alias(); break; case RETURN: case 'q': case 'x': case 'r': if (newaliases) install_aliases(); return; case 'p': if (newaliases) error("Warning: new aliases not installed yet!"); PutLine0(LINES-2,0,"Check for person: "); CleartoEOLN(); Raw(OFF); gets(name,NLEN); Raw(ON); if ((address = get_alias_address(name, 0, 0))!=NULL) { if (address[0] == '!') { address[0] = ' '; PutLine1(LINES-1,0,"Group alias:%-65.65s", address); CleartoEOLN(); } else PutLine1(LINES-1,0,"Aliased addresss: %-65.65s", address); } else error("not found"); break; case 's': PutLine0(LINES-2,0,"Check for system: "); CleartoEOS(); Raw(OFF); gets(name,NLEN); Raw(ON); if (talk_to(name)) #ifdef INTERNET_ADDRESS_FORMAT PutLine1(LINES-1,0, "You have a direct connection - the address is (user)@%s", name); #else PutLine1(LINES-1,0, "You have a direct connection - the address is %s!(user)", name); #endif else { sprintf(buffer, "(user)@%s", name); address = expand_system(buffer, FALSE); if (strlen(address) > strlen(name) + 7) PutLine1(LINES-1,0,"Address is: %.65s", address); else error1("couldn't expand system '%s'", name); } break; case '@': PutLine0(LINES-2,0,"Fully expand alias: "); CleartoEOS(); Raw(OFF); gets(name,NLEN); Raw(ON); if ((address = get_alias_address(name, 1, 0)) != NULL) { ClearScreen(); PutLine1(3,0,"Aliased address:\n\r%s", address); PutLine0(LINES-1,0,"Press <return> to continue: "); (void) getchar(); } else error("not found"); break; default : error("Invalid input!"); } } } install_aliases() { /** run the 'newalias' program and install the newly added aliases before going back to the main program! **/ error("Adding new aliases..."); sleep(2); if (system_call(newalias, SH) == 0) { error("Re-reading the database in..."); sleep(2); read_alias_files(); set_error("New aliases installed successfully"); } else set_error("'newalias' failed. Please check alias_text"); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 7725 ] then echo $filename changed - should be 7725 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/curses.c ---------- filename="src/curses.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/curses.c... fi cat << 'END-OF-FILE' > $filename /** curses.c **/ /** This library gives programs the ability to easily access the termcap information and write screen oriented and raw input programs. The routines can be called as needed, except that to use the cursor / screen routines there must be a call to InitScreen() first. The 'Raw' input routine can be used independently, however. Modified 2/86 to work (hopefully) on Berkeley systems. If there are any problems with BSD Unix, please report them to the author at taylor@hplabs (fixed, if possible!) Modified 5/86 to add memory lock support, thanks to the suggested code by Steve Wolf. (C) Copyright 1985 Dave Taylor, HP Colorado Networks **/ #ifdef BSD # include "/usr/include/curses.h" /* don't ask! */ #endif #include "headers.h" #ifdef RAWMODE # ifdef BSD # include <sgtty.h> # else # include <termio.h> # endif #endif #include <ctype.h> #ifdef BSD #undef tolower #endif #include "curses.h" #ifdef RAWMODE # define TTYIN 0 #endif extern int debug; #ifdef RAWMODE # ifndef BSD struct termio _raw_tty, _original_tty; # endif static int _inraw = 0; /* are we IN rawmode? */ static int _memory_locked = 0; /* are we IN memlock?? */ static int _line = -1, /* initialize to "trash" */ _col = -1; #ifdef UTS static int _clear_screen = 0; /* Next i/o clear screen? */ static char _null_string[SLEN]; /* a string of nulls... */ #endif #endif static int _intransmit; /* are we transmitting keys? */ static char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left, *_setbold, *_clearbold, *_setunderline, *_clearunderline, *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse, *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off, *_set_memlock, *_clear_memlock; static int _lines, _columns; static char _terminal[1024]; /* Storage for terminal entry */ static char _capabilities[1024]; /* String for cursor motion */ static char *ptr = _capabilities; /* for buffering */ int outchar(); /* char output for tputs */ char *tgetstr(), /* Get termcap capability */ *tgoto(); /* and the goto stuff */ InitScreen() { /* Set up all this fun stuff: returns zero if all okay, or; -1 indicating no terminal name associated with this shell, -2..-n No termcap for this terminal type known */ int tgetent(), /* get termcap entry */ error; char termname[40]; dprint0(8,"InitScreen()\n"); #ifdef SUN if (getenv("TERM") == NULL) return(-1); #endif #ifdef UTS /* use _line for lack of a better variable, what the heck! */ for (_line = 0; _line < SLEN; _line++) _null_string[_line] = '\0'; #endif if (strcpy(termname, getenv("TERM")) == NULL) return(-1); if ((error = tgetent(_terminal, termname)) != 1) return(error-2); _line = 0; /* where are we right now?? */ _col = 0; /* assume zero, zero... */ /* load in all those pesky values */ _clearscreen = tgetstr("cl", &ptr); _moveto = tgetstr("cm", &ptr); _up = tgetstr("up", &ptr); _down = tgetstr("do", &ptr); _right = tgetstr("nd", &ptr); _left = tgetstr("bs", &ptr); _setbold = tgetstr("so", &ptr); _clearbold = tgetstr("se", &ptr); _setunderline = tgetstr("us", &ptr); _clearunderline = tgetstr("ue", &ptr); _setinverse = tgetstr("so", &ptr); _clearinverse = tgetstr("se", &ptr); _sethalfbright = tgetstr("hs", &ptr); _clearhalfbright = tgetstr("he", &ptr); _cleartoeoln = tgetstr("ce", &ptr); _cleartoeos = tgetstr("cd", &ptr); _lines = tgetnum("li"); _columns = tgetnum("co"); _transmit_on = tgetstr("ks", &ptr); _transmit_off = tgetstr("ke", &ptr); _set_memlock = tgetstr("ml", &ptr); _clear_memlock = tgetstr("mu", &ptr); if (!_left) { _left = ptr; *ptr++ = '\b'; *ptr++ = '\0'; } #ifdef BSD initscr(); /* initalize curses too! */ #endif return(0); } char *return_value_of(termcap_label) char *termcap_label; { /** This will return the string kept by termcap for the specified capability. Modified to ensure that if tgetstr returns a pointer to a transient address that we won't bomb out with a later segmentation fault (thanks to Dave@Infopro for this one!) **/ static char escape_sequence[20]; char *tgetstr(); /* Get termcap capability */ dprint1(9,"return_value_of(%s)\n", termcap_label); strcpy(escape_sequence, tgetstr(termcap_label, &ptr)); return( (char *) escape_sequence); } transmit_functions(newstate) int newstate; { /** turn function key transmission to ON | OFF **/ dprint1(9,"transmit_functions(%s)\n", onoff(newstate)); if (newstate != _intransmit) { _intransmit = ! _intransmit; if (newstate == ON) tputs(_transmit_on, 1, outchar); else tputs(_transmit_off, 1, outchar); fflush(stdout); /* clear the output buffer */ } } /****** now into the 'meat' of the routines...the cursor stuff ******/ ScreenSize(lines, columns) int *lines, *columns; { /** returns the number of lines and columns on the display. **/ dprint2(9,"ScreenSize(_,_) returning %d, %d\n", _lines-1, _columns); *lines = _lines - 1; /* assume index from zero */ *columns = _columns; } ClearScreen() { /* clear the screen: returns -1 if not capable */ dprint0(9,"ClearScreen()\n"); _line = 0; /* clear leaves us at top... */ _col = 0; #ifdef UTS if (isatube) { _clear_screen++; /* queue up for clearing... */ return(0); } #endif if (!_clearscreen) return(-1); tputs(_clearscreen, 1, outchar); fflush(stdout); /* clear the output buffer */ return(0); } MoveCursor(row, col) int row, col; { /** move cursor to the specified row column on the screen. 0,0 is the top left! **/ char *stuff; /* we don't want to change "rows" or we'll mangle scrolling... */ if (col > COLUMNS) col = COLUMNS; if (col < 0) col = 0; #ifdef UTS if (isatube) { at row+1, col+1; _line = row; _col = col; return(0); } #endif if (!_moveto) return(-1); if (row == _line) { if (col == _col) return(0); else if (abs(col - _col) < 5) { if (col > _col) CursorRight(col - _col); else CursorLeft(_col - col); } else { stuff = tgoto(_moveto, col, row); tputs(stuff, 1, outchar); fflush(stdout); } } else if (col == _col && abs(row - _line) < 5) { if (row < _line) CursorUp(_line - row); else CursorDown(row - _line); } else if (_line == row-1 && col == 0) { putchar('\n'); /* that's */ putchar('\r'); /* easy! */ fflush(stdout); } else { stuff = tgoto(_moveto, col, row); tputs(stuff, 1, outchar); fflush(stdout); } _line = row; /* to ensure we're really there... */ _col = col; return(0); } CursorUp(n) int n; { /** move the cursor up 'n' lines **/ dprint1(9,"CursorUp(%d)\n", n); _line = (_line-n > 0? _line - n: 0); /* up 'n' lines... */ #ifdef UTS if (isatube) { at _line+1, _col+1; return(0); } #endif if (!_up) return(-1); while (n-- > 0) tputs(_up, 1, outchar); fflush(stdout); return(0); } CursorDown(n) int n; { /** move the cursor down 'n' lines **/ dprint1(9,"CursorDown(%d)\n", n); _line = (_line+n < LINES? _line + n: LINES); /* down 'n' lines... */ #ifdef UTS if (isatube) { at _line+1, _col+1 ; return(0); } #endif if (!_down) return(-1); while (n-- > 0) tputs(_down, 1, outchar); fflush(stdout); return(0); } CursorLeft(n) int n; { /** move the cursor 'n' characters to the left **/ dprint1(9,"CursorLeft(%d)\n", n); _col = (_col - n> 0? _col - n: 0); /* left 'n' chars... */ #ifdef UTS if (isatube) { at _line+1, _col+1; return(0); } #endif if (!_left) return(-1); while (n-- > 0) tputs(_left, 1, outchar); fflush(stdout); return(0); } CursorRight(n) int n; { /** move the cursor 'n' characters to the right (nondestructive) **/ dprint1(9,"CursorRight(%d)\n", n); _col = (_col+n < COLUMNS? _col + n: COLUMNS); /* right 'n' chars... */ #ifdef UTS if (isatube) { at _line+1, _col+1; return(0); } #endif if (!_right) return(-1); while (n-- > 0) tputs(_right, 1, outchar); fflush(stdout); return(0); } StartBold() { /** start boldface/standout mode **/ if (!_setbold) return(-1); tputs(_setbold, 1, outchar); fflush(stdout); return(0); } EndBold() { /** compliment of startbold **/ if (!_clearbold) return(-1); tputs(_clearbold, 1, outchar); fflush(stdout); return(0); } StartUnderline() { /** start underline mode **/ if (!_setunderline) return(-1); tputs(_setunderline, 1, outchar); fflush(stdout); return(0); } EndUnderline() { /** the compliment of start underline mode **/ if (!_clearunderline) return(-1); tputs(_clearunderline, 1, outchar); fflush(stdout); return(0); } StartHalfbright() { /** start half intensity mode **/ if (!_sethalfbright) return(-1); tputs(_sethalfbright, 1, outchar); fflush(stdout); return(0); } EndHalfbright() { /** compliment of starthalfbright **/ if (!_clearhalfbright) return(-1); tputs(_clearhalfbright, 1, outchar); fflush(stdout); return(0); } StartInverse() { /** set inverse video mode **/ if (!_setinverse) return(-1); tputs(_setinverse, 1, outchar); fflush(stdout); return(0); } EndInverse() { /** compliment of startinverse **/ if (!_clearinverse) return(-1); tputs(_clearinverse, 1, outchar); fflush(stdout); return(0); } int HasMemlock() { /** returns TRUE iff memory locking is available (a terminal feature that allows a specified portion of the screen to be "locked" & not cleared/scrolled... **/ return ( _set_memlock && _clear_memlock ); } static int _old_LINES; int StartMemlock() { /** mark the current line as the "last" line of the portion to be memory locked (always relative to the top line of the screen) Note that this will alter LINES so that it knows the top is locked. This means that (plus) the program will scroll nicely but (minus) End memlock MUST be called whenever we leave the locked-memory part of the program! **/ if (! _set_memlock) return(-1); if (! _memory_locked) { _old_LINES = LINES; LINES -= _line; /* we can't use this for scrolling */ tputs(_set_memlock, 1, outchar); fflush(stdout); _memory_locked = TRUE; } return(0); } int EndMemlock() { /** Clear the locked memory condition... **/ if (! _set_memlock) return(-1); if (_memory_locked) { LINES = _old_LINES; /* back to old setting */ tputs(_clear_memlock, 1, outchar); fflush(stdout); _memory_locked = FALSE; } return(0); } Writechar(ch) char ch; { /** write a character to the current screen location. **/ #ifdef UTS char buffer[2]; /* can't output characters! */ #endif dprint1(9,ch >= ' ' ? "Writechar(%c)\n" : "Writechar(^%c)\n", ch >= ' ' ? ch : ch + 'A' - 1); #ifdef UTS if (isatube) { buffer[0] = ch; buffer[1] = '\0'; at _line+1, _col+1; panel (noerase, noinit, noread) { #ON, buffer, 1# } } else #endif putchar(ch); if (ch == BACKSPACE) /* moved BACK one! */ _col--; else if (ch >= ' ') /* moved FORWARD one! */ _col++; } Write_to_screen(line, argcount, arg1, arg2, arg3) char *line; int argcount, arg1, arg2, arg3; { /** This routine writes to the screen at the current location. when done, it increments lines & columns accordingly by looking for "\n" sequences... **/ dprint2(9,"Write_to_screen(%s) [%d args]\n", line, argcount); switch (argcount) { case 0 : PutLine0(_line, _col, line); break; case 1 : PutLine1(_line, _col, line, arg1); break; case 2 : PutLine2(_line, _col, line, arg1, arg2); break; case 3 : PutLine3(_line, _col, line, arg1, arg2, arg3); break; } } PutLine0(x, y, line) int x,y; char *line; { /** Write a zero argument line at location x,y **/ register int i; dprint3(8,"PutLine0(%d, %d, %s.30...)\n", x, y, line); #ifdef UTS if (isatube) { at x+1, y+1; panel (init=_clear_screen, noread, erase=_clear_screen) { #ON, line, strlen(line)-1# } _clear_screen = 0; _col += printable_chars(line); /* line wrapped around?? */ while (_col > COLUMNS) { _col -= COLUMNS; _line += 1; } /* now let's figure out if we're supposed to do a "<return>" */ for (i=0; i < strlen(line); i++) if (line[i] == '\n') { _line++; _col = 0; /* on new line! */ } return(0); } #endif MoveCursor(x,y); printf("%s", line); /* to avoid '%' problems */ fflush(stdout); _col += printable_chars(line); while (_col > COLUMNS) { /* line wrapped around?? */ _col -= COLUMNS; _line += 1; } /** now let's figure out if we're supposed to do a "<return>" **/ for (i=0; i < strlen(line); i++) if (line[i] == '\n') { _line++; _col = 0; /* on new line! */ } } PutLine1(x,y, line, arg1) int x,y; char *line; char *arg1; { /** write line at location x,y - one argument... **/ char buffer[SLEN]; dprint0(9, "PutLine1(...)\n"); sprintf(buffer, line, arg1); PutLine0(x, y, buffer); } PutLine2(x,y, line, arg1, arg2) int x,y; char *line; char *arg1, *arg2; { /** write line at location x,y - one argument... **/ char buffer[SLEN]; dprint0(9, "PutLine2(...)\n"); sprintf(buffer, line, arg1, arg2); PutLine0(x, y, buffer); } PutLine3(x,y, line, arg1, arg2, arg3) int x,y; char *line; char *arg1, *arg2, *arg3; { /** write line at location x,y - one argument... **/ char buffer[SLEN]; dprint0(9, "PutLine3(...)\n"); sprintf(buffer, line, arg1, arg2, arg3); PutLine0(x, y, buffer); } CleartoEOLN() { /** clear to end of line **/ #ifdef UTS char buffer[SLEN]; register int cols, i = 0; if (isatube) { dprint0(9, "CleartoEOLN()\n"); for (cols = _col; cols < COLUMNS; cols++) buffer[i++] = ' '; buffer[i] = '\0'; at _line+1, _col+1; panel (noerase, noinit, noread) { #ON, buffer, strlen(buffer)-1# } return(0); } #endif dprint0(9, "CleartoEOLN()\n"); if (!_cleartoeoln) return(-1); tputs(_cleartoeoln, 1, outchar); fflush(stdout); /* clear the output buffer */ return(0); } CleartoEOS() { /** clear to end of screen **/ #ifdef UTS register int line_at; if (isatube) { dprint0(9,"CleartoEOS()\n"); for (line_at = _line; line_at < LINES-1; line_at++) { panel (noread, noinit, noread) { #@ line_at, 1# #ON, _null_string, COLUMNS# } } return(0); } #endif dprint0(9,"CleartoEOS()\n"); if (!_cleartoeos) return(-1); tputs(_cleartoeos, 1, outchar); fflush(stdout); /* clear the output buffer */ return(0); } #ifdef RAWMODE Raw(state) int state; { /** state is either ON or OFF, as indicated by call **/ dprint1(8,"Raw(%s)\n", onoff(state)); if (state == OFF && _inraw) { #ifdef BSD echo(); nocrmode(); #else (void) ioctl(TTYIN, TCSETAW, &_original_tty); #endif _inraw = 0; } else if (state == ON && ! _inraw) { #ifdef BSD noecho(); crmode(); #else (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/ (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/ _raw_tty.c_iflag &= ~(INLCR | ICRNL |BRKINT); _raw_tty.c_iflag |= IXON; _raw_tty.c_oflag |= OPOST; _raw_tty.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET); _raw_tty.c_lflag &= ~(ICANON | ECHO); _raw_tty.c_cc[VMIN] = '\01'; _raw_tty.c_cc[VTIME] = '\0'; (void) ioctl(TTYIN, TCSETAW, &_raw_tty); #endif _inraw = 1; } } int ReadCh() { /** read a character with Raw mode set! **/ register int result; char ch; dprint0(9,"ReadCh()\n"); result = read(0, &ch, 1); return(result == 0? EOF : ch); } #endif outchar(c) char c; { /** output the given character. From tputs... **/ /** Note: this CANNOT be a macro! **/ putc(c, stdout); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 15951 ] then echo $filename changed - should be 15951 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file src/date.c ---------- filename="src/date.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/date.c... fi cat << 'END-OF-FILE' > $filename /** date.c **/ /** return the current date and time in a readable format! **/ /** also returns an ARPA RFC-822 format date... **/ /** (C) Copyright 1985, Dave Taylor **/ #include "headers.h" #ifdef BSD # include <sys/time.h> #else # include <time.h> #endif #include <ctype.h> #ifdef BSD #undef toupper #endif #define MONTHS_IN_YEAR 11 /* 0-11 equals 12 months! */ #define FEB 1 /* 0 = January */ #define DAYS_IN_LEAP_FEB 29 /* leap year only */ #define ampm(n) (n > 12? n - 12 : n) #define am_or_pm(n) (n > 11? (n > 23? "am" : "pm") : "am") #define leapyear(year) ((year % 4 == 0) && (year % 100 != 0)) char *dayname[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "" }; char *monname[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""}; char *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "" }; char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""}; int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1}; #ifdef BSD char *timezone(); #else extern char *tzname[]; #endif char *get_date() { /** Return the date in the format exemplified by; Thursday, April 18th 1985 at 8:35 pm ************************************* ** This routine is not used by ELM ** ************************************* **/ static char buffer[SLEN]; /* static character buffer */ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); char *suffix(); /* digit suffix for date */ long junk; /* time in seconds.... */ junk = (long) time(0); /* this must be here for it to work! */ the_time = localtime(&junk); sprintf(buffer, "%s, %s %d%s %d at %d:%02d %s", dayname[the_time->tm_wday], /* weekday */ monname[the_time->tm_mon], /* month */ the_time->tm_mday, /* day */ suffix(the_time->tm_mday), /* suffix */ the_time->tm_year + 1900, /* year */ ampm(the_time->tm_hour), /* hour */ the_time->tm_min, /* minute */ ((the_time->tm_hour == 12 || the_time->tm_hour == 24) && the_time->tm_min == 0) ? (the_time->tm_hour == 12? "noon" : "midnight") : am_or_pm(the_time->tm_hour)); /* am | pm */ return( (char *) buffer); } char *suffix(day) int day; { /** this routine returns the suffix appropriate for the specified number to make it an ordinal number. ie, if given '1' it would return 'st', and '2' => 'nd' **/ static char buffer[10]; register int digit; digit = day % 10; if (digit == 0 || digit > 3) strcpy(buffer,"th"); else if (digit == 1) strcpy(buffer,"st"); else if (digit == 2) strcpy(buffer, "nd"); else strcpy(buffer, "rd"); return( (char *) buffer); } char *get_arpa_date() { /** returns an ARPA standard date. The format for the date according to DARPA document RFC-822 is exemplified by; Mon, 12 Aug 85 6:29:08 MST **/ static char buffer[SLEN]; /* static character buffer */ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); long junk; /* time in seconds.... */ #ifdef BSD struct timeval time_val; struct timezone time_zone; #endif #ifdef BSD gettimeofday(&time_val, &time_zone); junk = time_val.tv_sec; #else junk = (long) time(0); /* this must be here for it to work! */ #endif the_time = localtime(&junk); sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s", arpa_dayname[the_time->tm_wday], the_time->tm_mday % 32, arpa_monname[the_time->tm_mon], the_time->tm_year % 100, the_time->tm_hour % 24, the_time->tm_min % 61, the_time->tm_sec % 61, #ifdef BSD timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime)); #else tzname[the_time->tm_isdst]); #endif return( (char *) buffer); } char *full_month(month) char *month; { /** Given a three letter month abbreviation, return the full name of the month. If can't figure it out, just return the given argument. **/ char name[4]; register int i; /** ensure name in correct case... **/ strncpy(name, shift_lower(month), 3); name[0] = toupper(name[0]); /** now simply step through arpa_monname table to find a match **/ for (i=0; i < 12; i++) if (strncmp(name, arpa_monname[i], 3) == 0) return((char *) monname[i]); dprint1(2, "Warning: Couldn't expand monthname %s (full_month)\n", month); return( (char *) month); } days_ahead(days, buffer) int days; char *buffer; { /** return in buffer the date (Day, Mon Day, Year) of the date 'days' days after today. **/ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); long junk; /* time in seconds.... */ junk = (long) time(0); /* this must be here for it to work! */ the_time = localtime(&junk); /* increment the day of the week */ the_time->tm_wday = (the_time->tm_wday + days) % 7; /* the day of the month... */ the_time->tm_mday += days; if (the_time->tm_mday > days_in_month[the_time->tm_mon]) { if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) { if (the_time->tm_mday > DAYS_IN_LEAP_FEB) { the_time->tm_mday -= days_in_month[the_time->tm_mon]; the_time->tm_mon += 1; } } else { the_time->tm_mday -= days_in_month[the_time->tm_mon]; the_time->tm_mon += 1; } } /* check the month of the year */ if (the_time->tm_mon > MONTHS_IN_YEAR) { the_time->tm_mon -= MONTHS_IN_YEAR; the_time->tm_year += 1; } /* now, finally, build the actual date string */ sprintf(buffer, "%s, %d %s %d", arpa_dayname[the_time->tm_wday], the_time->tm_mday % 32, arpa_monname[the_time->tm_mon], the_time->tm_year % 100); } int valid_date(day, mon, year) char *day, *mon, *year; { /** validate the given date - returns TRUE iff the date handed is reasonable and valid. **/ register int daynum, yearnum; daynum = atoi(day); yearnum = atoi(year); if (daynum < 1 || daynum > 31) { dprint1(3, "Error: day %d is obviously wrong! (valid_date)\n", daynum); return(0); } if (yearnum < 1 || (yearnum > 100 && yearnum < 1900) || yearnum > 2000) { dprint1(3, "Error: year %d is obviously wrong! (valid_date)\n", yearnum); return(0); } return(1); } fix_date(entry) struct header_rec *entry; { /** This routine will 'fix' the date entry for the specified message. This consists of 1) adjusting the year to 0-99 and 2) altering time from HH:MM:SS to HH:MM am|pm **/ if (atoi(entry->year) > 99) sprintf(entry->year,"%d", atoi(entry->year) - 1900); fix_time(entry->time); } fix_time(timestring) char *timestring; { /** Timestring in format HH:MM:SS (24 hour time). This routine will fix it to display as: HH:MM [am|pm] **/ int hour, minute; sscanf(timestring, "%d:%d", &hour, &minute); if (hour < 1 || hour == 24) sprintf(timestring, "12:%2d (midnight)", minute); else if (hour < 12) sprintf(timestring, "%d:%2.2d am", hour, minute); else if (hour == 12) sprintf(timestring, "%d:%2.2d (noon)", hour, minute); else if (hour < 24) sprintf(timestring, "%d:%2.2d pm", hour-12, minute); } int compare_dates(rec1, rec2) struct header_rec *rec1, *rec2; { /** This function works similarly to the "strcmp" function, but has lots of knowledge about the internal date format... Apologies to those who "know a better way"... **/ int month1, day1, year1, hour1, minute1, month2, day2, year2, hour2, minute2; year1 = atoi(rec1->year); year2 = atoi(rec2->year); if (year1 != year2) return( year1 - year2 ); /* And HERE's where the performance of this sort dies... */ month1 = month_number(rec1->month); /* retch... gag.... */ month2 = month_number(rec2->month); /* puke... */ if (month1 == -1) dprint1(2,"month_number failed on month '%s'\n", rec1->month); if (month2 == -1) dprint1(2,"month_number failed on month '%s'\n", rec2->month); if (month1 != month2) return( month1 - month2 ); /* back and cruisin' now, though... */ day1 = atoi(rec1->day); /* unfortunately, 2 is greater than 19 */ day2 = atoi(rec2->day); /* on a dump string-only compare... */ if (day1 != day2) return( day1 - day2 ); /* we're really slowing down now... */ sscanf(rec1->time, "%d:%d", &hour1, &minute1); sscanf(rec2->time, "%d:%d", &hour2, &minute2); if (hour1 != hour2) return( hour1 - hour2 ); return( day1 - day2 ); /* ignore seconds... */ } int month_number(name) char *name; { /** return the month number given the month name... **/ char ch; switch (tolower(name[0])) { case 'a' : if ((ch = tolower(name[1])) == 'p') return(APRIL); else if (ch == 'u') return(AUGUST); else return(-1); /* error! */ case 'd' : return(DECEMBER); case 'f' : return(FEBRUARY); case 'j' : if ((ch = tolower(name[1])) == 'a') return(JANUARY); else if (ch == 'u') { if ((ch = tolower(name[2])) == 'n') return(JUNE); else if (ch == 'l') return(JULY); else return(-1); /* error! */ } else return(-1); /* error */ case 'm' : if ((ch = tolower(name[2])) == 'r') return(MARCH); else if (ch == 'y') return(MAY); else return(-1); /* error! */ case 'n' : return(NOVEMBER); case 'o' : return(OCTOBER); case 's' : return(SEPTEMBER); default : return(-1); } } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 9538 ] then echo $filename changed - should be 9538 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/delete.c ---------- filename="src/delete.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/delete.c... fi cat << 'END-OF-FILE' > $filename /** delete.c **/ /** Delete or undelete files: just set flag in header record! Also tags specified message(s)... (C) Copyright 1985 Dave Taylor **/ #include "headers.h" delete(real_del) int real_del; { /** Delete current message. If real-del is false, then we're actually requested to toggle the state of the current message... **/ if (real_del) header_table[current-1].status |= DELETED; else if (ison(header_table[current-1].status, DELETED)) clearit(header_table[current-1].status, DELETED); else setit(header_table[current-1].status, DELETED); show_msg_status(current-1); } undelete() { /** clear the deleted message flag **/ clearit(header_table[current-1].status, DELETED); show_msg_status(current-1); } show_msg_status(msg) int msg; { /** show the status of the current message only. **/ if (on_page(msg)) { MoveCursor((msg % headers_per_page) + 4, 3); Writechar( ison(header_table[msg].status, DELETED)? 'D' : ' '); } } tag_message() { /** Tag current message. If already tagged, untag it. **/ if (ison(header_table[current-1].status, TAGGED)) clearit(header_table[current-1].status, TAGGED); else setit(header_table[current-1].status, TAGGED); show_msg_tag(current-1); } show_msg_tag(msg) int msg; { /** show the tag status of the current message only. **/ if (on_page(msg)) { MoveCursor((msg % headers_per_page) + 4, 4); Writechar( ison(header_table[msg].status, TAGGED)? '+' : ' '); } } show_new_status(msg) int msg; { /** If the specified message is on this screen, show the new status (could be marked for deletion now, and could have tag removed...) **/ if (on_page(msg)) PutLine2((msg % headers_per_page) + 4, 3, "%c%c", ison(header_table[msg].status, DELETED)? 'D' : ' ', ison(header_table[msg].status, TAGGED )? '+' : ' '); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 1863 ] then echo $filename changed - should be 1863 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/aliasdb.c ---------- filename="src/aliasdb.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/aliasdb.c... fi cat << 'END-OF-FILE' > $filename /** aliasdb.c **/ /** Alias database files... (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include <sys/types.h> #include <sys/stat.h> char *shift_lower(), *find_path_to(); findnode(name, display_error) char *name; int display_error; { /** break 'name' into machine!user or user@machine and then see if you can find 'machine' in the path database.. If so, return name as the expanded address. If not, return what was given to us! If display_error, then do so... **/ char old_name[SLEN]; char address[SLEN]; if (strlen(name) == 0) return; strcpy(old_name, name); /* save what we were given */ if (expand_site(name, address) == -1) { if (display_error && name[0] != '!') { dprint2(2,"Couldn't expand host %s in address. (%s)\n", name, "findnode"); if (! check_only) { /* be silent if just checking */ error1("Warning: couldn't expand %s...", name); sleep(1); } } strcpy(name, old_name); /* and restore... */ } else strcpy(name, address); return; } int expand_site(cryptic, expanded) char *cryptic, *expanded; { /** Given an address of the form 'xyz@site' or 'site!xyz' return an address of the form <expanded address for site> with 'xyz' embedded according to the path database entry. Note that 'xyz' can be eiher a simple address (as in "joe") or a complex address (as in "joe%xerox.parc@Xerox.ARPA")! 0 = found, -1 return means unknown site code **/ #ifdef ACSNET strcpy(expanded, cryptic); /* fast and simple */ return(0); #else char name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING]; char *expand_domain(), *addr; register int i = 0, j = 0, domain_name; strcpy(old_name, cryptic); /* remember what we were given */ /** break down **/ while (cryptic[i] != AT_SIGN && cryptic[i] != BANG && cryptic[i] != '\0') sitename[j++] = cryptic[i++]; sitename[j++] = '\0'; j = 0; if (cryptic[i] == '\0') return(-1); /* nothing to expand! */ domain_name = (cryptic[i] == AT_SIGN); i++; while (cryptic[i] != '\0') name[j++] = cryptic[i++]; name[j] = '\0'; if (domain_name) { strcpy(temp, name); strcpy(name, sitename); strcpy(sitename, temp); } #ifndef LOOK_CLOSE_AFTER_SEARCH if (talk_to(sitename)) { strcpy(expanded, old_name); /* restore! */ return(0); } #endif if ((addr = find_path_to(sitename, TRUE)) == NULL) { #ifdef LOOK_CLOSE_AFTER_SEARCH if (talk_to(sitename)) { strcpy(expanded, old_name); /* restore! */ return(0); } else #endif if ((addr = expand_domain(cryptic)) != NULL) { strcpy(expanded, addr); /* into THIS buffer */ return(0); } else if (size_of_pathfd == 0) { /* no path database! */ strcpy(expanded, old_name); /* restore! */ return(0); } else /* We just can't get there! */ return(-1); } else { /* search succeeded */ sprintf(expanded, addr, name); return(0); } #endif } int binary_search(name, address) char *name, *address; { /* binary search file for name. Return 0 if found, -1 if not */ char machine[40]; register long first = 0, last, middle; register int compare; address[0] = '\0'; last = size_of_pathfd; do { middle = (long) ((first+last) / 2); get_entry(machine, address, pathfd, middle); compare = strcmp(name, machine); if (compare < 0) last = middle - 1; else if (compare == 0) return(0); else /* greater */ first = middle + 1; } while (abs(last) - abs(first) > FIND_DELTA); return(-1); } get_entry(machine, address, fileid, offset) char *machine, *address; FILE *fileid; long offset; { /** get entry...return machine and address immediately following given offset in fileid. **/ fseek(fileid, offset, 0); /* read until we hit an end-of-line */ while (getc(fileid) != '\n') ; fscanf(fileid, "%s\t%s", machine, address); } init_findnode() { /** Initialize the FILE and 'size_of_file' values for the findnode procedure **/ struct stat buffer; if (stat(pathfile, &buffer) == -1) { dprint2(1, "Warning: No pathalias file [filename %s] found! (%s)\n", pathfile, "init_findnode"); size_of_pathfd = 0; return; } size_of_pathfd = (long) buffer.st_size; if ((pathfd = fopen(pathfile,"r")) == NULL) { dprint2(1, "Warning: Can't read pathalias file [filename %s] (%s)\n", pathfile, "init_findnode"); size_of_pathfd = 0; } else dprint2(2, "\nOpened file '%s' as path alias database. (%s)\n\n", pathfile, "init_findnode"); } char *find_path_to(machine, printf_format) char *machine; int printf_format; { /** Returns either the path to the specified machine or NULL if not found. If "printf_format" is TRUE, then it leaves the '%s' intact, otherwise it assumes that the address is a uucp address for the domain expansion program and removes the last three characters of the expanded name ("!%s") since they're redundant with the expansion! **/ static char buffer[LONG_SLEN]; /* space for path */ if (size_of_pathfd > 0) if (binary_search(machine, buffer) != -1) { /* found it! */ if (! printf_format && strlen(buffer) > 3) buffer[strlen(buffer)-3] = '\0'; return( (char *) buffer); } return(NULL); /* failed if it's here! */ } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 5484 ] then echo $filename changed - should be 5484 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/file.c ---------- filename="src/file.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/file.c... fi cat << 'END-OF-FILE' > $filename /** file.c **/ /** File I/O routines, mostly the save to file command... (C) Copyright 1986, Dave Taylor **/ #include "headers.h" #include <ctype.h> #include <errno.h> #ifdef BSD #undef tolower #endif extern int errno; char *error_name(), *error_description(); int save() { /** Save all tagged messages + current in a file. If no messages are tagged, save the current message instead! This routine will return ZERO if the operation failed. **/ register int tagged = 0, i, oldstat, appending = 0; char filename[SLEN], address[LONG_SLEN], buffer[SLEN]; FILE *save_file; oldstat = header_table[current-1].status; /* remember */ for (i=0; i < message_count; i++) if (ison(header_table[i].status, TAGGED)) tagged++; if (tagged == 0) { tagged = 1; setit(header_table[current-1].status, TAGGED); } dprint2(4,"%d message%s tagged for saving (save)\n", tagged, plural(tagged)); PutLine1(LINES-2, 0, "File message%s in: ", plural(tagged)); if (save_by_name) { /** build default filename to save to **/ get_return(address); get_return_name(address, buffer, FALSE); sprintf(filename, "=%s", buffer); } else filename[0] = '\0'; if (tagged > 1) optionally_enter(filename, LINES-2, 19, FALSE); else optionally_enter(filename, LINES-2, 18, FALSE); MoveCursor(LINES-1,0); if (strlen(filename) == 0) { /** <return> means 'cancel', right? **/ header_table[current-1].status = oldstat; /* BACK! */ return(0); } if (! expand_filename(filename)) { dprint1(2,"Error: Failed on expansion of filename %s (save)\n", filename); header_table[current-1].status = oldstat; /* BACK! */ return(0); /* failed expanding name! */ } if (access(filename,ACCESS_EXISTS)) /* already there!! */ appending = 1; if ((errno = can_open(filename, "a"))) { error1("Wrong permissions to save message to file %s!", filename); dprint2(2,"Error: access permission on file %s denied (%s)! (save)\n", filename, error_name(errno)); header_table[current-1].status = oldstat; /* BACK! */ return(0); } dprint1(4,"Saving mail to file '%s'...\n", filename); if ((save_file = fopen(filename,"a")) == NULL) { dprint1(2, "Error: couldn't append to specified file %s (save)\n", filename); error1("Couldn't append to file %s!", filename); header_table[current-1].status = oldstat; /* BACK! */ return(0); } for (i=0; i < message_count; i++) /* save each tagged msg */ if (header_table[i].status & TAGGED) save_message(i, filename, save_file, (tagged > 1), appending++); fclose(save_file); chown(filename, userid, groupid); /* owned by user */ if (tagged > 1) error1("Message%s saved", plural(tagged)); return(1); } int save_message(number, filename, fd, pause, appending) int number, pause, appending; char *filename; FILE *fd; { /** Save an actual message to a file. This is called by "save()" only! The parameters are the message number, and the name and file descriptor of the file to save to. If 'pause' is true, a sleep(2) will be done after the saved message appears on the screen... 'appending' is only true if the file already exists **/ register int save_current; dprint1(4, "\tSaving message %d to file...\n", number); save_current = current; current = number+1; copy_message("", fd, FALSE, FALSE); current = save_current; if (resolve_mode) setit(header_table[number].status, DELETED); /* deleted, but ... */ clearit(header_table[number].status, TAGGED); /* not tagged anymore */ clearit(header_table[number].status, NEW); /* it's not new now! */ if (! appending) /* don't ask */ error2("Message %d appended to file %s", number+1, filename); else error2("Message %d saved to file %s", number+1, filename); show_new_status(number); /* update screen, if needed */ if (pause) sleep(2); } int expand_filename(filename) char *filename; { /** Expands '~' and '=' to specified file names, also will try to expand shell variables if encountered.. '+' and '%' are synonymous with '=' (folder dir)... **/ char buffer[SLEN], varname[SLEN], env_value[SLEN]; register int i = 1, index = 0; /** new stuff - make sure no illegal char as last **/ if (lastch(filename) == '\n' || lastch(filename) == '\r') lastch(filename) = '\0'; if (filename[0] == '~') { sprintf(buffer, "%s%s%s", home, (filename[1] != '/' && lastch(folders) != '/')? "/" : "", (char *) filename + 1); strcpy(filename, buffer); } else if (filename[0] == '=' || filename[0] == '+' || filename[0] == '%') { if (strlen(folders) == 0) { dprint2(3,"Error: maildir not defined - can't expand '%c' (%s)\n", filename[0], "expand_filename"); error1("MAILDIR not defined. Can't expand '%c'", filename[0]); return(0); } sprintf(buffer, "%s%s%s", folders, (filename[1] != '/' && lastch(folders) != '/')? "/" : "", (char *) filename + 1); strcpy(filename, buffer); } else if (filename[0] == '$') { /* env variable! */ while (isalnum(filename[i])) varname[index++] = filename[i++]; varname[index] = '\0'; #ifdef SUN env_value[0] = '\0'; /* null string for strlen! */ if (getenv(varname) != NULL) #endif strcpy(env_value, getenv(varname)); if (strlen(env_value) == 0) { dprint2(3,"Error: Can't expand environment variable $%s (%s)\n", varname, "expand_filename"); error1("Don't know what the value of $%s is!", varname); return(0); } sprintf(buffer, "%s%s%s", env_value, (filename[i] != '/' && lastch(env_value) != '/')? "/" : "", (char *) filename + i); strcpy(filename, buffer); } return(1); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 5704 ] then echo $filename changed - should be 5704 bytes, not $size bytes fi chmod 644 $filename fi echo end of this archive file.... exit 0