Subject: v09i003: ELM Mail System, Part03/19 Newsgroups: mod.sources Approved: rs@mirror.TMC.COM Submitted by: Dave Taylor Mod.sources: Volume 9, Issue 3 Archive-name: elm2/Part03 #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If this archive is complete, you will see the message: # "End of archive 3 (of 19)." # Contents: Instructions MANIFEST filter/summarize.c hdrs/filter.h # hdrs/shortnames.h src/builtin.c src/encode.c src/savecopy.c # utils/Makefile utils/Makefile.mstr utils/autoreply.c PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"Instructions\" \(4676 characters\) if test -f Instructions ; then echo shar: Will not over-write existing file \"Instructions\" else sed "s/^X//" >Instructions <<'END_OF_Instructions' X X Instructions X ------------ X X Last Update: July 17th, 1986 X X X This file contains instructions on how to create and install Xthe entire ELM mail system. It should be read BEFORE any attempts Xare made at actually creating and/or installing any of the software Xcontained herein! X X There is actually really one step needed - unpack all the shar Xfiles and then; X X $ cd X X $ sh Configure.sh X X Answer the questions of that program,, then let it create the localized XMakefiles and system definition files for you. When it's done you can double Xcheck the configuration (or customize it further) by reading the Configuration XGuide + editing the file "hdrs/sysdefs.h". There are lots of neat features Xthat are unique to this mailer - it's worth a quick perusal at least! X X Once you're happy with the localized files, you then need to create Xthe documentation (so there's a bit of a catch-22 that you need to format the XConfiguration guide before you are happy with the localization but can't do Xthat until you're happy with the localization...oh well). X X $ X X $ make documentation X X When that's done, or even if it fails (don't worry too much about it) X X $ (make -i all >& MAKELOG) & X $ tail -f MAKELOG X X (if you're in "sh", you can use "> MAKELOG 2>&1" instead of ">& MAKELOG") X XThis will take a fair while, so it's recommended that you go and eat Xlunch or play a game for a while!! (alternatively, spend lots of money Xon a really FAST machine and blink your eyes a few times...) X XAssuming there are no errors during compilation (we'll have to assume Xthat for the moment) you should now be able to list the directory "bin" Xand find the following files: X X "answer", "arepdaemon", "autoreply", "fastmail", "from", X "elm", "newalias", "newmail", "printmail", and "readmsg". X Xnext, you can install all the software on your system by; X X $ make -i install X XNote: the mailer runs as setgid mail to have the ability to WRITE Xto the /usr/mail directory (for lock files). If you have a different Xscheme at your site, feel free to set it up to use that instead. X XFinally, we're just about done! The final checks can be made Xby the following commands: X X $ /usr/local/bin/elm -z X Xshould say "no mail" if nothing's in your incoming mailbox, and X X $ /usr/local/bin/elm -f test/test.mail X Xshould read in EIGHT messages from various people. While here, try to XA)lias C)urrent message for each of the eight messages to confirm that Xthe reply/address system is working okay. Now try to C)hange mailboxes Xto the file "test/test.note" and use the '%' key to see if the mailer is Xgenerating valid return addresses for the notes (If not, then you might Xneed to install the pathalias database - see "sysdefs.h" for more info) XChange back to "test/test.mail" and Q)uit without having marked anything Xfor deletion...answer the questions accordingly. X XIf you get this far you're in Wonderful shape! In fact, you're done! X XCongratulations! You've just installed one of the best electronic mail Xsystems available today on your machine (if I say so myself!) X XHANDY HINTS: If you want to create a print of the entire set of Xsources, including this file, use the command: X X $ make listing X XIf, on the other hand, you just want to create a listing file of Xjust the ELM sources, try: X X $ make elm-listing X XAlso, if you have a number of machines on a network, you can rlogin Xto the remote machine and then do a remote install (after checking Xto ensure that the networking copy method in the Makefile under the Xtarget "remote-install" is correct) by typing: X X $ make -f REMOTE= rmt-install X X(for example, if we had installed the system on machine "machx" and X wanted to install it on "machy", with the Makefile in /src/Elm on X "machx", we could type from "machy"; X $ make -f machx:/src/Elm/Makefile REMOTE=machx: rmt-install X to have it install the system on machine y!) X XOne final note for non-US distribution - the program might complain Xat link time that it can't find "crypt()". If so, and if you cannot Xobtain a copy, you should merely instruct your users to not use the Xencrypted mail option on outgoing mail. X XThat's it! X---------- X XOh! One final note: if you'd like a nicely typeset copy of the documentation, Xfeel free to drop me a line with your full (overland) mail address!! I'll Xtry to get it back to you within a week or two. X X----------- X X Author's address: taylor@HPLABS X hplabs!taylor X X Mail address: Dave Taylor X Hewlett Packard Laboratories X 1501 Page Mill Road X Palo Alto CA X 94304 X X This document and the entire mail system is X X (C) Copyright 1986, Dave Taylor END_OF_Instructions if test 4676 -ne `wc -c MANIFEST <<'END_OF_MANIFEST' X File Name Archive # Description X----------------------------------------------------------- X Configure.sh 18 X Instructions 3 X MANIFEST 3 X Makefile 9 X Makefile.mstr 9 X NOTICE 2 X Overview 4 X bin 1 X doc 1 X doc/Alias.guide 15 X doc/Config.guide 15 X doc/Elm.coversheet 1 X doc/Filter.guide 14 X doc/Form.guide 10 X doc/Ref.guide 19 X doc/Users.guide 18 X doc/answer.1 1 X doc/autoreply.1 1 X doc/checkalias.1 1 X doc/elm-help.0 1 X doc/elm-help.1 1 X doc/elm-help.2 1 X doc/elm.1 2 X doc/elmrc-info 2 X doc/elmrc.sample 1 X doc/fastmail.1 2 X doc/filter.1 1 X doc/from.1 1 X doc/listalias.1 1 X doc/messages.1 1 X doc/newalias.1 1 X doc/newmail.1 1 X doc/printmail.1 1 X doc/readmsg.1 2 X doc/trim-headers.1 1 X doc/wnewmail.1 1 X filter 1 X filter/Makefile 1 X filter/Makefile.mstr 1 X filter/actions.c 5 X filter/filter.c 4 X filter/parse.c 8 X filter/rules.c 5 X filter/summarize.c 3 X filter/utils.c 2 X filter/utils2.c 4 X hdrs 1 X hdrs/curses.h 1 X hdrs/defs.h 6 X hdrs/elm.h 5 X hdrs/filter.h 3 X hdrs/headers.h 5 X hdrs/save_opts.h 1 X hdrs/shortnames.h 3 X hdrs/sysdefs.h 6 X hdrs/sysdefs.master 6 X hdrs/sysdefs.old 6 X src 1 X src/Makefile 2 X src/Makefile.mstr 2 X src/addr_utils.c 15 X src/alias.c 10 X src/aliasdb.c 7 X src/aliaslib.c 4 X src/args.c 2 X src/bounceback.c 2 X src/builtin.c 3 X src/calendar.c 5 X src/connect_to.c 2 X src/curses.c 16 X src/curses.q 12 X src/date.c 10 X src/delete.c 1 X src/domains.c 7 X src/edit.c 4 X src/editmsg.c 12 X src/elm.c 17 X src/encode.c 3 X src/errno.c 2 X src/file.c 6 X src/file_utils.c 4 X src/fileio.c 2 X src/forms.c 9 X src/getopt.c 1 X src/hdrconfg.c 5 X src/help.c 5 X src/initialize.c 7 X src/initialize.uts 6 X src/input_utils.c 8 X src/leavembox.c 12 X src/limit.c 6 X src/mailmsg1.c 8 X src/mailmsg2.c 17 X src/mailtime.c 4 X src/mkhdrs.c 2 X src/newmbox.c 14 X src/opt_utils.c 4 X src/options.c 8 X src/output_utils.c 1 X src/pattern.c 5 X src/pmalloc.c 1 X src/quit.c 1 X src/read_rc.c 16 X src/remail.c 1 X src/reply.c 14 X src/return_addr.c 9 X src/save_opts.c 9 X src/savecopy.c 3 X src/screen.c 11 X src/screen3270.q 11 X src/showmsg.c 11 X src/showmsg_cmd.c 2 X src/signals.c 1 X src/softkeys.c 2 X src/sort.c 4 X src/string2.c 1 X src/strings.c 11 X src/syscall.c 4 X src/utils.c 5 X src/validname.c 1 X test 1 X test/test.empty 1 X test/test.mail 10 X test/test.notes 13 X utils 1 X utils/Makefile 3 X utils/Makefile.mstr 3 X utils/answer.c 8 X utils/arepdaemon.c 13 X utils/autoreply.c 3 X utils/fastmail.c 7 X utils/from.c 10 X utils/listalias.c 1 X utils/mailrc.awk 1 X utils/newalias.c 13 X utils/newmail.c 7 X utils/printmail.c 2 X utils/readmsg.c 12 X utils/trim-headers 1 X utils/wnewmail.c 7 END_OF_MANIFEST if test 4296 -ne `wc -c filter/summarize.c <<'END_OF_filter/summarize.c' X/** summarize.c **/ X X/** This routine is called from the filter program (or can be called X directly with the correct arguments) and summarizes the users filterlog X file. To be honest, there are two sorts of summaries that are X available - either the '.filterlog' file can be output (filter -S) X or a summary by rule and times acted upon can be output (filter -s). X Either way, this program will delete the two associated files each X time ($HOME/.filterlog and $HOME/.filtersum) *if* the -c option is X used to the program (e.g. clear_logs is set to TRUE). X X (C) Copyright 1986, Dave Taylor X**/ X X#include X X#include "defs.h" X X#include "filter.h" X Xshow_summary() X{ X /* Summarize usage of the program... */ X X FILE *fd; /* for output to temp file! */ X char filename[SLEN], /* name of the temp file */ X buffer[LONG_SLEN]; /* input buffer space */ X int erroneous_rules = 0, X default_rules = 0, X rule, X applied[MAXRULES]; X X if (long_summary) X long_sum(); X else { X X sprintf(filename, "%s/%s", home, filtersum); X X if ((fd = fopen(filename, "r")) == NULL) { X fprintf(stderr,"filter (%s): Can't open filterlog file %s!\n", X username, filename); X exit(1); X } X X for (rule=0;rule < MAXRULES; rule++) X applied[rule] = 0; /* initialize it all! */ X X /** Next we need to read it all in, incrementing by which rule X was used. The format is simple - each line represents a X single application of a rule, or '-1' if the default action X was taken. Simple stuff, eh? But oftentimes the best. X **/ X X while (fgets(buffer, LONG_SLEN, fd) != NULL) { X if ((rule = atoi(buffer)) > total_rules || rule < -1) { X fprintf(stderr, X "%sfilter (%s): Warning - rule #%d is invalid data for short summary!!\n", X BEEP, username, rule); X erroneous_rules++; X } X else if (rule == -1) X default_rules++; X else X applied[rule]++; X } X X fclose(fd); X X /** now let's summarize the data... **/ X X printf("\nSummary of filter activity;\n\n"); X X if (erroneous_rules) X printf("** Warning: %d erroneous rule%s logged and ignored! **\n\n", X erroneous_rules, erroneous_rules > 1? "s were" : " was"); X X if (default_rules) X printf( X "The default rule of putting mail into your mailbox was used %d time%s\n\n", X default_rules, plural(default_rules)); X X /** and now for each rule we used... **/ X X for (rule = 0; rule < total_rules; rule++) { X if (applied[rule]) { X printf("Rule #%d: ", rule+1); X switch (rules[rule].action) { X case LEAVE: printf("(leave mail in mailbox)"); break; X case DELETE: printf("(delete message)"); break; X case SAVE : printf("(save in \"%s\")", X rules[rule].argument2); break; X case SAVECC: printf("(left in mailbox and saved in \"%s\")", X rules[rule].argument2); break; X case FORWARD: printf("(forwarded to \"%s\")", X rules[rule].argument2); break; X case EXEC : printf("(given to command \"%s\")", X rules[rule].argument2); break; X } X printf(" was applied %d time%s.\n\n", applied[rule], X plural(applied[rule])); X } X } X X /* next, after a ^L, include the actual log file... */ X X sprintf(filename, "%s/%s", home, filterlog); X X if ((fd = fopen(filename, "r")) == NULL) { X fprintf(stderr,"filter (%s): Can't open filterlog file %s!\n", X username, filename); X } X else { X printf("\n\n\n%c\n\nExplicit log of each action;\n\n", (char) 12); X while (fgets(buffer, LONG_SLEN, fd) != NULL) X printf("%s", buffer); X printf("\n-----\n"); X fclose(fd); X } X X /* now remove the log files, please! */ X X if (clear_logs) { X unlink(filename); X sprintf(filename, "%s/%s", home, filtersum); X unlink(filename); X } X X return; X } X} X Xlong_sum() X{ X /** summarize by listing the .fitlerlog file. The simplest of the X two possible options this one is indeed rather trivial! **/ X X FILE *fd; /* for output to temp file! */ X char filename[SLEN], /* name of the temp file */ X buffer[LONG_SLEN]; /* input buffer space */ X X sprintf(filename,"%s/%s", home, filterlog); X X if ((fd = fopen(filename, "r")) == NULL) { X fprintf(stderr,"filter (%s): Can't open filterlog file %s!\n", X username, filename); X exit(1); X } X X while (fgets(buffer, SLEN, fd) != NULL) X printf("%s", buffer); /* already has '\n' doesn't it? */ X fclose(fd); X X /** now let's waste the TWO log files and get outta here! **/ X X if (clear_logs) { X unlink(filename); X sprintf(filename, "%s/%s", home, filtersum); X unlink(filename); X } X X return; X} END_OF_filter/summarize.c if test 4658 -ne `wc -c hdrs/filter.h <<'END_OF_hdrs/filter.h' X/** filter.h **/ X X/** Headers for the filter program. X X (C) Copyright 1986, Dave Taylor X**/ X X#ifdef BSD X# undef tolower X# define tolower(c) (isupper(c)? c = c - 'A' + 'a' : c) X#endif X X/** define a few handy macros for later use... **/ X X#define BEEP (audible? "\007" : "") X X#define the_same(a,b) (strncmp(a,b,strlen(b)) == 0) X X#define relationname(x) (x == 1?"<=":x==2?"<":x==3?">=":x==4?">":x==5?"!=":"=") X X#define quoteit(x) (x == LINES? "" : "\"") X X/** some of the files we'll be using, where they are, and so on... **/ X X#define filter_temp "/tmp/filter" X#define filterfile ".filter-rules" X#define filterlog ".filterlog" X#define filtersum ".filtersum" X X#define EMERGENCY_MAILBOX "EMERGENCY_MBOX" X#define EMERG_MBOX "MBOX.EMERGENCY" X X/** and now the hardwired constraint of the program.. **/ X X#define MAXRULES 25 /* can't have more den dis, boss! */ X X/** some random defines for mnemonic stuff in the program... **/ X X#define TO 1 X#define FROM 2 X#define LINES 3 X#define CONTAINS 4 X X#define DELETE 5 X#define SAVE 6 X#define SAVECC 7 X#define FORWARD 8 X#define LEAVE 9 X#define EXEC 10 X X#define FAILED_SAVE 20 X X/** Some conditionals... **/ X X#define LE 1 X#define LT 2 X#define GE 3 X#define GT 4 X#define NE 5 X#define EQ 6 X X/** A funky way to open a file using open() to avoid file locking hassles **/ X X#define FOLDERMODE O_WRONLY | O_APPEND | O_CREAT | O_SYNCIO X X/** cheap but easy way to have two files share the same #include file **/ X X#ifdef MAIN_ROUTINE X# define extern X#endif X Xextern char home[SLEN], /* the users home directory */ X hostname[SLEN], /* the machine name... */ X username[SLEN]; /* the users login name... */ X Xextern char to[VERY_LONG_STRING], X from[SLEN], X subject[SLEN]; /* from current message */ X X#ifdef MAIN_ROUTINE Xint total_rules = 0, /* how many rules to check */ X show_only = FALSE, /* just for show? */ X long_summary = FALSE, /* what sorta summary?? */ X verbose = FALSE, /* spit out lots of stuff */ X audible = FALSE, /* be noisy with output? */ X lines = 0, /* lines in message.. */ X clear_logs = FALSE, /* clear files after sum? */ X already_been_forwarded = FALSE, /* has this been filtered? */ X log_actions_only = FALSE, /* log actions | everything */ X rule_choosen; /* which one we choose */ X#else Xextern int total_rules, /* how many rules to check */ X show_only, /* just for show? */ X long_summary, /* what sorta summary?? */ X verbose, /* spit out lots of stuff */ X audible, /* be noisy with output? */ X lines, /* lines in message.. */ X clear_logs, /* clear files after sum? */ X already_been_forwarded, /* has this been filtered? */ X log_actions_only, /* log actions | everything */ X rule_choosen; /* which one we choose */ X#endif X X/** and our ruleset record structure... **/ X Xstruct condition_rec { X int matchwhat; /* type of 'if' clause */ X int relation; /* type of match (eq, etc) */ X char argument1[SLEN]; /* match against this */ X struct condition_rec *next; /* next condition... */ X }; X Xextern struct ruleset_record { X char printable[SLEN]; /* straight from file... */ X struct condition_rec *condition; X int action; /* what action to take */ X char argument2[SLEN]; /* argument for action */ X } rules[MAXRULES]; X X X/** finally let's keep LINT happy with the return values of all these pups! ***/ X Xunsigned short getuid(); X Xunsigned long sleep(); X Xchar *malloc(), *strcpy(), *strcat(), *itoa(); X Xvoid exit(); X X#ifdef BSD X X FILE *popen(); X X extern char _vbuf[5*BUFSIZ]; /* space for file buffering */ X X# define _IOFBF 0 /* doesn't matter - ignored */ X X# define setvbuf(fd,a,b,c) setbuffer(fd, _vbuf, 5*BUFSIZ) X X#endif END_OF_hdrs/filter.h if test 3994 -ne `wc -c hdrs/shortnames.h <<'END_OF_hdrs/shortnames.h' X/** shortnames.h **/ X X/** This file is from Geoff Kuenning, and will help those poor users that X are stuck using C compilers that don't have flexnames. Too bad. X X This file has no explicit copyright. X X**/ X X#define PutLine0 PLine0 X#define PutLine1 PLine1 X#define PutLine2 PLine2 X#define PutLine3 PLine3 X X#define add_to_table add_2_table X#define address1 addrs1 X#define addressII addrsII X#define addresses addr_s X#define alternate_prompt alt_prompt X#define alternative_addresses alt_addrs X#define always_leave alw_leave X X#define calendar_line cal_line X#define cancelled_msg cncld_msg X#define central_message_buffer cntrl_bfr X#define compare_dates cmp_dates X#define compare_headers cmp_hdrs X#define copy_message_across cpy_msg_across X#define current_record cur_rec X#define current_time cur_time X X#define define_softkeys def_softkeys X#define display_central_message displ_cntrl_msg X#define display_error displ_error X#define display_headers displ_hdrs X#define display_helpfile dspl_helpfile X#define display_options displ_options X#define display_title displ_titles X#define display_to displ_to X X#define encrypted crypted X#define encrypted_key crypt_key X#define expanded_cc xp_cc X#define expanded_to xp_to X#define expand_address xp_addr X#define expand_domain xp_domain X#define expand_env xp_env X#define expand_filename xp_filename X#define expand_group xp_group X#define expand_logname xp_logname X#define expand_site xp_site X#define expand_system xp_system X X#define filename2 fn2 X#define forward forwrd X X#define generate_reply_to gen_reply_to X#define get_return_name g_ret_name X X#define header_line h_line X#define header_page h_page X#define headers_per_page h_per_page X#define header_table h_table X X#define install_aliases ins_aliases X X#define last_line_loc last_ln_loc X X#define machine_group mach_group X#define mailbox_defined mbox_defined X#define mailfile_size mfile_size X#define message_count msg_count X#define message_number msg_number X X#define newaliases nwaliases X#define noptimize_return noret_opt X#define noptimize_usenet nousenet_opt X X#define optimize_and_add opt_and_add X#define optimize_arpa opt_arpa X#define optimize_cmplx_arpa opt_cmplx_arpa X#define optimize_return opt_return X#define optimize_usenet opt_usenet X#define optional_arg opt_arg X#define optionally_enter opt_enter X#define original_cc orig_cc X#define original_msg_num orig_msg_num X#define original_to orig_to X X#define parse_arguments pars_arguments X#define parse_arpa_from prs_arpa_from X#define password_entry pw_entry X#define pattern_enter pat_enter X#define pattern_match pat_match X X#define read_alias_files rd_alias_files X#define read_headers rd_headers X#define read_rc rd_rc X#define read_rc_file rd_rc_file X#define received_on_machine rcvd_on_machine X#define remove_all rem_all X#define remove_first_word rem_1st_word X#define remove_domains rem_domains X#define remove_header rem_hdr X#define remove_user rem_user X#define remove_through_ch rem_thru_ch X#define reply_to_everyone repl_to_everyone X#define resolve_received rslv_received X X#define show_message shw_message X#define show_msg showmsg X#define show_msg_tag sh_msg_tag X#define size_of_pathfd sz_of_pathfd X#define softkeys_off soft_off X#define softkeys_on soft_on X#define subjectbuffer subjbuff X#define subject_matches subj_matches X#define system_call sys_call X#define system_data sys_data X#define system_files sys_files X#define system_hash_table sys_hash_table X#define system_record sys_record X X#define tail_of_string tl_of_string X#define talk_to_sys tlk_to_sys X#define tempfile tmpfile X#define termcap_label tcap_label X#define top_of_screen_left top_left_of_screen X#define top_of_screen_right top_right_of_screen X#define translate_return xlate_return X X#define update_mailtime upd_mailtime X#define update_title upd_title X#define unexpanded_cc unexp_cc X#define unexpanded_to unexp_to X X#define verify_transmission vfy_xmsn X X#define weeding_out wding_out END_OF_hdrs/shortnames.h if test 3969 -ne `wc -c src/builtin.c <<'END_OF_src/builtin.c' X/** builtin.c **/ X X/** This is the built-in pager for displaying messages while in the Elm X program. It's a bare-bones pager with precious few options. The idea X is that those systems that are sufficiently slow that using an external X pager such as 'more' is too slow, then they can use this! X X Added the following functionality; X X s skip lines X f forward a page or pages X /pattern skip forward to pattern X X (C) Copyright 1986, Dave Taylor X**/ X X#include "headers.h" X#include X X#define BEEP 007 /* ASCII Bell character */ X X#ifdef BSD X# undef tolower X#endif X Xint lines_put_on_screen = 0, /* number of lines displayed per screen */ X lines_displayed = 0, /* Total number of lines displayed */ X total_lines_to_display, /* total number of lines in message */ X lines_to_ignore = 0; /* for 'f' and 's' functions... */ X Xstart_builtin(lines_in_message) Xint lines_in_message; X{ X /** clears that screen and resets it's internal counters... **/ X X dprint1(8,"displaying %d lines from message using internal pager\n", X lines_in_message); X X lines_displayed = 0; X lines_put_on_screen = 0; X lines_to_ignore = 0; X X total_lines_to_display = lines_in_message; X} X Xint Xdisplay_line(line) Xchar *line; X{ X /** Display the given line on the screen, taking into account such X dumbness as wraparound and such. If displaying this would put X us at the end of the screen, put out the "MORE" prompt and wait X for some input. Return non-zero if the user terminates the X paging (e.g. 'q') or zero if we should continue... X **/ X X register int lines_needed, okay_char, ch, len = 12, iteration = 0; X char pattern[SLEN]; X X if (lines_to_ignore != 0) { X if (--lines_to_ignore <= 0) { X putchar('\n'); X lines_to_ignore = 0; X } X return(0); X } X X lines_needed = (int) (printable_chars(line)/COLUMNS); /* wraparound */ X X for (ch = 0; ch < strlen(line); ch++) X if (line[ch] == '\n') lines_needed++; X X if (lines_needed + lines_put_on_screen > LINES-1) { X StartBold(); X if (user_level == 0) { X Write_to_screen( X "You've read %d%%: press for more, or 'q' to return", 1, X (int) (100.0 * ( X (float) lines_displayed / (float) total_lines_to_display))); X len = 59; X } X else if (user_level == 1) { X Write_to_screen( X "More (%d%%) Press for more, 'q' to return", 1, X (int) (100.0 * ( X (float) lines_displayed / (float) total_lines_to_display))); X len = 49; X } X else X Write_to_screen(" More (%d%%)", 1, X (int) (100.0 * ( X (float) lines_displayed / (float) total_lines_to_display))); X X EndBold(); X okay_char = FALSE; X do { X Raw(ON); X ch = tolower(ReadCh()); X Raw(OFF); Xloop_top: switch (ch) { X case '\n' : X case '\r' : /* pressed... */ X lines_put_on_screen -= lines_needed; X okay_char = TRUE; X break; X case ' ' : /* pressed... */ X lines_put_on_screen = 0; X okay_char = TRUE; X break; X case '/' : putchar('/');fflush(stdout); X Raw(ON); X optionally_enter(pattern,-1,-1,FALSE); X Raw(OFF); X CursorLeft(len+strlen(pattern)+1); CleartoEOLN(); X printf("...searching for pattern \"%s\"...", X pattern); X fflush(stdout); X break; X case 'f' : lines_to_ignore = ((iteration?iteration:1)*LINES)-5; X CursorLeft(len); CleartoEOLN(); X printf("...skipping %d lines...",lines_to_ignore+2); X fflush(stdout); X lines_put_on_screen = 0; X return(0); X case 's' : lines_to_ignore = (iteration?iteration-1:0); X CursorLeft(len); CleartoEOLN(); X if (lines_to_ignore) X printf("...skipping %d lines...",lines_to_ignore+1); X else X printf("...skipping one line...\n"); X fflush(stdout); X lines_put_on_screen = 0; X return(0); X case 'q' : X case 'Q' : return(TRUE); /* get OUTTA here! */ X default : if (isdigit(ch)) { X Raw(ON); X do { X iteration = 10*iteration + (ch - '0'); X } while (isdigit(ch = ReadCh())); X Raw(OFF); X goto loop_top; X } X putchar(BEEP); X fflush(stdout); X break; X } X } while (! okay_char); X X CursorLeft(len); /* back up to the beginning of line */ X CleartoEOLN(); X } X X Write_to_screen("%s", 1, line); X X lines_displayed += 1; /* tossed on screen */ X lines_put_on_screen += lines_needed; /* read from file */ X X return (FALSE); X} END_OF_src/builtin.c if test 4541 -ne `wc -c src/encode.c <<'END_OF_src/encode.c' X/** encode.c **/ X X/** This is a heavily mangled version of the 'cypher' program written by X person or persons unknown. X X (C) Copyright 1986, Dave Taylor X**/ X X#include X#include "curses.h" X#include "headers.h" X X#define RS 94 X#define RN 4 X#define RMASK 0x7fff /* use only 15 bits */ X Xstatic char r[RS][RN]; /* rotors */ Xstatic char ir[RS][RN]; /* inverse rotors */ Xstatic char h[RS]; /* half rotor */ Xstatic char s[RS]; /* shuffle vector */ Xstatic int p[RN]; /* rotor indices */ X Xstatic char the_key[SLEN]; /* unencrypted key */ Xstatic char *encrypted_key; /* encrypted key */ X Xchar *getpass(), *strncpy(), *strcpy(); Xunsigned long sleep(); X Xgetkey(send) Xint send; X{ X /** this routine prompts for and returns an encode/decode X key for use in the rest of the program. If send == 1 X then need to mess with rawmode. **/ X X char buffer[NLEN]; X int gotkey = 0, x, y; X X GetXYLocation(&x,&y); X X ClearLine(21); X X if (send) Raw(OFF); X X while ( !gotkey ) { X MoveCursor(LINES-1,0); X ClearLine(LINES-1); X if (send) X strcpy( buffer, getpass( "Enter encryption key: ")); X else X strcpy( buffer, getpass( "Enter decryption key: ")); X MoveCursor(LINES-1,0); X if ( strcmp( buffer, getpass( "Please enter it again: "))) { X error("Your keys were not the same!"); X sleep(1); X clear_error(); X continue; X } X strcpy(the_key, buffer); /* save unencrypted key */ X makekey( buffer ); X gotkey = 1; X } X X if (send) Raw(ON); X X setup(); /** initialize the rotors etc. **/ X X ClearLine(LINES-1); X clear_error(); X X MoveCursor(x+1,0); /* move to 'next' line... */ X} X Xget_key_no_prompt() X{ X /** This performs the same action as get_key, but assumes that X the current value of 'the_key' is acceptable. This is used X when a message is encrypted twice... **/ X X char buffer[SLEN]; X X strcpy(buffer, the_key); X X makekey( buffer ); X X setup(); X} X Xencode(line) Xchar *line; X{ X /** encrypt or decrypt the specified line. Uses the previously X entered key... **/ X X register int i, index, j, ph = 0; X X for (index=0; index < strlen(line); index++) { X i = (int) line[index]; X X if ( (i >= ' ') && (i < '~') ) { X i -= ' '; X X for ( j = 0; j < RN; j++ ) /* rotor forwards */ X i = r[(i+p[j])%RS][j]; X X i = ((h[(i+ph)%RS])-ph+RS)%RS; /* half rotor */ X X for ( j-- ; j >= 0; j-- ) /* rotor backwards */ X i = (ir[i][j]+RS-p[j])%RS; X X j = 0; /* rotate rotors */ X p[0]++; X while ( p[j] == RS ) { X p[j] = 0; X j++; X if ( j == RN ) break; X p[j]++; X } X X if ( ++ph == RS ) X ph = 0; X X i += ' '; X } X X line[index] = (char) i; /* replace with altered one */ X } X} X X Xmakekey( rkey) Xchar *rkey; X{ X /** encrypt the key using the system routine 'crypt' **/ X X char key[8], salt[2], *crypt(); X X strncpy( key, rkey, 8); X salt[0] = key[0]; X salt[1] = key[1]; X encrypted_key = crypt( key, salt); X} X X/* X * shuffle rotors. X * shuffle each of the rotors indiscriminately. shuffle the half-rotor X * using a special obvious and not very tricky algorithm which is not as X * sophisticated as the one in crypt(1) and Oh God, I'm so depressed. X * After all this is done build the inverses of the rotors. X */ X Xsetup() X{ X register long i, j, k, temp; X long seed; X X for ( j = 0; j < RN; j++ ) { X p[j] = 0; X for ( i = 0; i < RS; i++ ) X r[i][j] = i; X } X X seed = 123; X for ( i = 0; i < 13; i++) /* now personalize the seed */ X seed = (seed*encrypted_key[i] + i) & RMASK; X X for ( i = 0; i < RS; i++ ) /* initialize shuffle vector */ X h[i] = s[i] = i; X X for ( i = 0; i < RS; i++) { /* shuffle the vector */ X seed = (5 * seed + encrypted_key[i%13]) & RMASK;; X k = ((seed % 65521) & RMASK) % RS; X temp = s[k]; X s[k] = s[i]; X s[i] = temp; X } X X for ( i = 0; i < RS; i += 2 ) { /* scramble the half-rotor */ X temp = h[s[i]]; /* swap rotor elements ONCE */ X h[s[i]] = h[s[i+1]]; X h[s[i+1]] = temp; X } X X for ( j = 0; j < RN; j++) { /* select a rotor */ X X for ( i = 0; i < RS; i++) { /* shuffle the vector */ X seed = (5 * seed + encrypted_key[i%13]) & RMASK;; X k = ((seed % 65521) & RMASK) % RS; X temp = r[i][j]; X r[i][j] = r[k][j]; X r[k][j] = temp; X } X X for ( i = 0; i < RS; i++) /* create inverse rotors */ X ir[r[i][j]][j] = i; X } X} END_OF_src/encode.c if test 4300 -ne `wc -c src/savecopy.c <<'END_OF_src/savecopy.c' X/** savecopy.c **/ X X/** Save a copy of the specified message in the users savemail mailbox. X X (C) Copyright 1986, Dave Taylor X**/ X X#include "headers.h" X#ifdef BSD X# ifdef BSD4.1 X# include X# else X# include X# endif X#else X# include X#endif X X#include X Xchar *format_long(), *get_arpa_date(); Xchar *error_name(), *error_description(); Xchar *ctime(); X Xextern char in_reply_to[SLEN]; /* In-Reply-To: string */ Xextern int gotten_key; /* for encryption */ Xextern int errno; X Xchar *strcat(), *strcpy(); Xunsigned long sleep(); Xlong time(); X Xsave_copy(subject, to, cc, filename, original_to) Xchar *subject, *to, *cc, *filename, *original_to; X{ X /** This routine appends a copy of the outgoing message to the X file specified by the SAVEFILE environment variable. **/ X X FILE *save, /* file id for file to save to */ X *message; /* the actual message body */ X long thetime, /* variable holder for time */ X time(); X char buffer[SLEN], /* read buffer */ X savename[SLEN], /* name of file saving into */ X newbuffer[SLEN]; /* first name in 'to' line */ X register int i; /* for chopping 'to' line up */ X int crypted=0; /* are we encrypting? */ X X savename[0] = '\0'; X X if (save_by_name) { X get_return_name(to, buffer, FALSE); X if (strlen(buffer) == 0) { X dprint1(3,"Warning: get_return_name couldn't break down %s\n", to); X savename[0] = '\0'; X } X else { X sprintf(savename, "%s%s%s", folders, X lastch(folders) == '/'? "" : "/", buffer); X X if (can_access(savename, READ_ACCESS) != 0) X savename[0] = '\0'; X } X } X X if (strlen(savename) == 0) { X if (strlen(savefile) == 0) X return(error("variable 'SAVEFILE' not defined!")); X strcpy(savename, savefile); X } X X if ((errno = can_access(savename, WRITE_ACCESS))) { X dprint0(2,"Error: attempt to autosave to a file that can't...\n"); X dprint1(2,"\tbe appended to: %s (save_copy)\n", savename); X dprint2(2,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error1("permission to append to %s denied!", savename); X sleep(2); X return(FALSE); X } X X if ((save = fopen(savename, "a")) == NULL) { X dprint2(1,"Error: Couldn't append message to file %s (%s)\n", X savename, "save_copy"); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error1("couldn't append to %s", savename); X sleep(2); X return(FALSE); X } X X if ((message = fopen(filename, "r")) == NULL) { X fclose(save); X dprint1(1,"Error: Couldn't read file %s (save_copy)\n", filename); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error1("couldn't read file %s!", filename); X sleep(2); X return(FALSE); X } X X for (i=0; original_to[i] != '\0' && ! whitespace(original_to[i]); i++) X newbuffer[i] = original_to[i]; X X newbuffer[i] = '\0'; X X tail_of(newbuffer, buffer, FALSE); X X thetime = time((long *) 0); /* dumb dumb dumb routine */ X X fprintf(save,"\nFrom To:%s %s", buffer, ctime(&thetime)); X X fprintf(save, "Date: %s\n", get_arpa_date()); X X fprintf(save,"To: %s\nSubject: %s\n", X format_long(to,strlen("To: ")), subject); X X if (strlen(cc) > 0) X fprintf(save,"Cc: %s\n", X format_long(cc, strlen("Cc:"))); X X if (strlen(in_reply_to) > 0) X fprintf(save, "In-Reply-To: %s\n", in_reply_to); X X (void) putc('\n', save); /* put another return, please! */ X X /** now copy over the message... **/ X X while (fgets(buffer, SLEN, message) != NULL) { X if (buffer[0] == '[') { X if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0) X crypted = 1; X else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0) X crypted = 0; X else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0) { X fclose(message); X fclose(save); X chown(savename, userid, groupid); X return(TRUE); X } X } X else if (crypted) { X if (! gotten_key++) X getkey(ON); X encode(buffer); X } X fputs(buffer, save); X } X X fclose(message); X fclose(save); X X /* make sure save file isn't owned by root! */ X chown(savename, userid, groupid); X X return(TRUE); X} END_OF_src/savecopy.c if test 4180 -ne `wc -c utils/Makefile <<'END_OF_utils/Makefile' X# X# Makefile for the Elm system utilities X# X# (C) Copyright 1986, Dave Taylor X# X# Last modification: Sept 15th, 1986 X XSHELL=/bin/sh X XDEFINE= -DBSD XLIB2 = -lcurses X XCFLAGS= -O -I../hdrs XCC= /bin/cc XRM= /bin/rm -f XECHO= /bin/echo X XOBJS= ../bin/newalias ../bin/from ../bin/newmail ../bin/answer \ X ../bin/printmail ../bin/fastmail ../bin/readmsg \ X ../bin/checkalias ../bin/arepdaemon ../bin/autoreply ../bin/wnewmail \ X ../bin/messages ../bin/trim-headers ../bin/listalias X Xall: ${OBJS} X X../bin/newalias: ../hdrs/defs.h newalias.c ../src/validname.o \ X ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} newalias.c ../src/validname.o \ X ../src/opt_utils.o -o ../bin/newalias X X../bin/from: from.c ../src/opt_utils.o ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} from.c ../src/opt_utils.o \ X ../src/string2.o -o ../bin/from X X../bin/newmail: ../src/opt_utils.c newmail.c ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} newmail.c \ X ../src/string2.o -o ../bin/newmail X X../bin/wnewmail: ../src/opt_utils.c wnewmail.c ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} ../src/opt_utils.o \ X ../src/string2.o wnewmail.c -o ../bin/wnewmail X X../bin/listalias: listalias.c X ${CC} ${CFLAGS} ${DEFINE} listalias.c -o ../bin/listalias X X../bin/answer: answer.c ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} answer.c ../src/opt_utils.o -o ../bin/answer X X../bin/printmail: printmail.c ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} printmail.c ../src/opt_utils.o \ X -o ../bin/printmail X X../bin/fastmail: fastmail.c X ${CC} ${CFLAGS} ${DEFINE} fastmail.c ../src/opt_utils.o \ X -o ../bin/fastmail X X../bin/readmsg: readmsg.c ../src/getopt.o ../src/opt_utils.o ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} readmsg.c ../src/getopt.o ../src/string2.o \ X ../src/opt_utils.o -o ../bin/readmsg X X../bin/arepdaemon: arepdaemon.c X ${CC} ${CFLAGS} ${DEFINE} arepdaemon.c -o ../bin/arepdaemon X X../bin/autoreply: autoreply.c ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} autoreply.c ../src/opt_utils.o \ X -o ../bin/autoreply X X../bin/checkalias: X @echo ': Use /bin/sh' > ../bin/checkalias X @echo 'if [ "$$*" = "" ]; then' >> ../bin/checkalias X @echo ' echo Usage: checkalias alias \[or aliases\]' >> \ X ../bin/checkalias X @echo ' exit 1' >> ../bin/checkalias X @echo 'fi' >> ../bin/checkalias X @echo ' ' >> ../bin/checkalias X @echo 'exec elm -c $$*' >> ../bin/checkalias X @chmod +x ../bin/checkalias X X../bin/messages: X @echo ': Use /bin/sh' > ../bin/messages X @echo 'if [ "$$2" != "" ]; then' >> ../bin/messages X @echo ' echo Usage: messages \{folder-name\}' >> ../bin/messages X @echo ' exit 1' >> ../bin/messages X @echo 'fi' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'if [ "$$1" = "" ]; then' >> ../bin/messages X @echo ' fname=$$MAIL' >> ../bin/messages X @echo ' optional="in your mailbox"' >> ../bin/messages X @echo 'else' >> ../bin/messages X @echo ' fname=$$1' >> ../bin/messages X @echo ' optional="in folder $$1"' >> ../bin/messages X @echo 'fi' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'mcount=`egrep "^From " $$fname | wc -l`' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'if [ $$mcount = 1 ];then' >> ../bin/messages X @echo ' echo There is $$mcount message $$optional' >> ../bin/messages X @echo 'else' >> ../bin/messages X @echo ' echo There are $$mcount messages $$optional' >> ../bin/messages X @echo 'fi' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'exit 0' >> ../bin/messages X @chmod +x ../bin/messages X X../bin/trim-headers: X @cp trim-headers ../bin/trim-headers X @chmod +x ../bin/trim-headers X X../src/validname.o: ../src/validname.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} validname.c; cd ../utils) X X../src/opt_utils.o: ../src/opt_utils.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} opt_utils.c; cd ../utils) X X../src/getopt.o: ../src/getopt.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} getopt.c; cd ../utils) X X../src/string2.o: ../src/string2.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} string2.c; cd ../utils) X Xclean: X ${RM} *.o ${OBJS} ../bin/utils X Xlint: X lint -p -I../hdrs *.c > LINT.OUT END_OF_utils/Makefile if test 4197 -ne `wc -c utils/Makefile.mstr <<'END_OF_utils/Makefile.mstr' X# X# Makefile for the Elm system utilities X# X# (C) Copyright 1986, Dave Taylor X# X# Last modification: Sept 15th, 1986 X XSHELL=/bin/sh X XDEFINE= >os-define< XLIB2 = >lib2< X XCFLAGS= -O -I../hdrs XCC= >cc< XRM= >rm< XECHO= /bin/echo X XOBJS= ../bin/newalias ../bin/from ../bin/newmail ../bin/answer \ X ../bin/printmail ../bin/fastmail ../bin/readmsg \ X ../bin/checkalias ../bin/arepdaemon ../bin/autoreply ../bin/wnewmail \ X ../bin/messages ../bin/trim-headers ../bin/listalias X Xall: ${OBJS} X X../bin/newalias: ../hdrs/defs.h newalias.c ../src/validname.o \ X ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} newalias.c ../src/validname.o \ X ../src/opt_utils.o -o ../bin/newalias X X../bin/from: from.c ../src/opt_utils.o ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} from.c ../src/opt_utils.o \ X ../src/string2.o -o ../bin/from X X../bin/newmail: ../src/opt_utils.c newmail.c ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} newmail.c \ X ../src/string2.o -o ../bin/newmail X X../bin/wnewmail: ../src/opt_utils.c wnewmail.c ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} ../src/opt_utils.o \ X ../src/string2.o wnewmail.c -o ../bin/wnewmail X X../bin/listalias: listalias.c X ${CC} ${CFLAGS} ${DEFINE} listalias.c -o ../bin/listalias X X../bin/answer: answer.c ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} answer.c ../src/opt_utils.o -o ../bin/answer X X../bin/printmail: printmail.c ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} printmail.c ../src/opt_utils.o \ X -o ../bin/printmail X X../bin/fastmail: fastmail.c X ${CC} ${CFLAGS} ${DEFINE} fastmail.c ../src/opt_utils.o \ X -o ../bin/fastmail X X../bin/readmsg: readmsg.c ../src/getopt.o ../src/opt_utils.o ../src/string2.o X ${CC} ${CFLAGS} ${DEFINE} readmsg.c ../src/getopt.o ../src/string2.o \ X ../src/opt_utils.o -o ../bin/readmsg X X../bin/arepdaemon: arepdaemon.c X ${CC} ${CFLAGS} ${DEFINE} arepdaemon.c -o ../bin/arepdaemon X X../bin/autoreply: autoreply.c ../src/opt_utils.o X ${CC} ${CFLAGS} ${DEFINE} autoreply.c ../src/opt_utils.o \ X -o ../bin/autoreply X X../bin/checkalias: X @echo ': Use /bin/sh' > ../bin/checkalias X @echo 'if [ "$$*" = "" ]; then' >> ../bin/checkalias X @echo ' echo Usage: checkalias alias \[or aliases\]' >> \ X ../bin/checkalias X @echo ' exit 1' >> ../bin/checkalias X @echo 'fi' >> ../bin/checkalias X @echo ' ' >> ../bin/checkalias X @echo 'exec elm -c $$*' >> ../bin/checkalias X @chmod +x ../bin/checkalias X X../bin/messages: X @echo ': Use /bin/sh' > ../bin/messages X @echo 'if [ "$$2" != "" ]; then' >> ../bin/messages X @echo ' echo Usage: messages \{folder-name\}' >> ../bin/messages X @echo ' exit 1' >> ../bin/messages X @echo 'fi' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'if [ "$$1" = "" ]; then' >> ../bin/messages X @echo ' fname=$$MAIL' >> ../bin/messages X @echo ' optional="in your mailbox"' >> ../bin/messages X @echo 'else' >> ../bin/messages X @echo ' fname=$$1' >> ../bin/messages X @echo ' optional="in folder $$1"' >> ../bin/messages X @echo 'fi' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'mcount=`egrep "^From " $$fname | wc -l`' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'if [ $$mcount = 1 ];then' >> ../bin/messages X @echo ' echo There is $$mcount message $$optional' >> ../bin/messages X @echo 'else' >> ../bin/messages X @echo ' echo There are $$mcount messages $$optional' >> ../bin/messages X @echo 'fi' >> ../bin/messages X @echo ' ' >> ../bin/messages X @echo 'exit 0' >> ../bin/messages X @chmod +x ../bin/messages X X../bin/trim-headers: X @cp trim-headers ../bin/trim-headers X @chmod +x ../bin/trim-headers X X../src/validname.o: ../src/validname.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} validname.c; cd ../utils) X X../src/opt_utils.o: ../src/opt_utils.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} opt_utils.c; cd ../utils) X X../src/getopt.o: ../src/getopt.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} getopt.c; cd ../utils) X X../src/string2.o: ../src/string2.c ../hdrs/defs.h X @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} string2.c; cd ../utils) X Xclean: X ${RM} *.o ${OBJS} ../bin/utils X Xlint: X lint -p -I../hdrs *.c > LINT.OUT END_OF_utils/Makefile.mstr if test 4192 -ne `wc -c utils/autoreply.c <<'END_OF_utils/autoreply.c' X/** autoreply.c **/ X X/** This is the front-end for the autoreply system, and performs two X functions: it either adds the user to the list of people using the X autoreply function (starting the daemon if no-one else) or removes X a user from the list of people. X X Usage: autoreply filename X autoreply "off" X or autoreply [to find current status] X X (C) 1986, Dave Taylor X**/ X X#include X#include X#include X#include X X#include "defs.h" X Xstatic char ident[] = { WHAT_STRING }; X X#define tempdir "/tmp/arep" /* file prefix */ X#define autoreply_file "/etc/autoreply.data" /* autoreply data file */ X Xextern int errno; /* system error code */ Xchar username[NLEN]; /* login name of user */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X char filename[SLEN]; X X if (argc > 2) { X printf("Usage: %s \tto start autoreply,\n", argv[0]); X printf(" %s off\t\tto turn off autoreply\n", argv[0]); X printf(" or %s \t\tto check current status\n", argv[0]); X exit(1); X } X X (void) cuserid(username); X X if (argc == 1 || strcmp(argv[1], "off") == 0) X remove_user((argc == 1)); X else { X strcpy(filename, argv[1]); X if (access(filename,READ_ACCESS) != 0) { X printf("Error: Can't read file '%s'\n", filename); X exit(1); X } X X if (filename[0] != '/') /* prefix home directory */ X sprintf(filename,"%s/%s", getenv("HOME"), argv[1]); X X add_user(filename); X } X X exit(0); X} X Xremove_user(stat_only) Xint stat_only; X{ X /** Remove the user from the list of currently active autoreply X people. If 'stat_only' is set, then just list the name of X the file being used to autoreply with, if any. **/ X X FILE *temp, *repfile; X char tempfile[SLEN], user[SLEN], filename[SLEN]; X int c, copied = 0, found = 0; X long filesize, bytes(); X X if (! stat_only) { X sprintf(tempfile, "%s.%06d", tempdir, getpid()); X X if ((temp = fopen(tempfile, "w")) == NULL) { X printf("Error: couldn't open tempfile '%s'. Not removed\n", X tempfile); X exit(1); X } X } X X if ((repfile = fopen(autoreply_file, "r")) == NULL) { X if (stat_only) { X printf("You're not currently autoreplying to mail.\n"); X exit(0); X } X printf("No-one is autoreplying to their mail!\n"); X exit(0); X } X X /** copy out of real replyfile... **/ X X while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) X X if (strcmp(user, username) != 0) { X if (! stat_only) { X copied++; X fprintf(tempfile, "%s %s %ld\n", user, filename, filesize); X } X } X else { X if (stat_only) { X printf("You're currently autoreplying to mail with the file %s\n", filename); X exit(0); X } X found++; X } X X fclose(temp); X fclose(repfile); X X if (! found) { X printf("You're not currently autoreplying to mail%s\n", X stat_only? "." : "!"); X if (! stat_only) X unlink(tempfile); X exit(! stat_only); X } X X /** now copy tempfile back into replyfile **/ X X if (copied == 0) { /* removed the only person! */ X unlink(autoreply_file); X } X else { /* save everyone else */ X X if ((temp = fopen(tempfile,"r")) == NULL) { X printf("Error: couldn't reopen tempfile '%s'. Not removed.\n", X tempfile); X unlink(tempfile); X exit(1); X } X X if ((repfile = fopen(autoreply_file, "w")) == NULL) { X printf( X "Error: couldn't reopen autoreply file for writing! Not removed.\n"); X unlink(tempfile); X exit(1); X } X X while ((c = getc(temp)) != EOF) X putc(c, repfile); X X fclose(temp); X fclose(repfile); X X } X unlink(tempfile); X X if (found > 1) X printf("Warning: your username appeared %d times!! Removed all\n", X found); X else X printf("You've been removed from the autoreply table.\n"); X} X Xadd_user(filename) Xchar *filename; X{ X /** add the user to the autoreply file... **/ X X FILE *repfile; X char mailfile[SLEN]; X long bytes(); X X if ((repfile = fopen(autoreply_file, "a")) == NULL) { X printf("Error: couldn't open the autoreply file! Not added\n"); X exit(1); X } X X sprintf(mailfile,"%s/%s", mailhome, username); X X fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile)); X X fclose(repfile); X X printf("You've been added to the autoreply system.\n"); X} X X Xlong Xbytes(name) Xchar *name; X{ X /** return the number of bytes in the specified file. This X is to check to see if new mail has arrived.... **/ X X int ok = 1; X extern int errno; /* system error number! */ X struct stat buffer; X X if (stat(name, &buffer) != 0) X if (errno != 2) X exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name)); X else X ok = 0; X X return(ok ? buffer.st_size : 0L); X} END_OF_utils/autoreply.c if test 4689 -ne `wc -c