Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: Msg Shar.part.6 Message-ID: <1464@panda.UUCP> Date: 3 Mar 86 01:17:40 GMT Sender: jpn@panda.UUCP Organization: Hewlett-Packard, Colorado Networks Division Lines: 2504 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 10 Submitted by: decvax!hplabs!hpcnou!dat (Dave Taylor) # Msg Shar part 6 of 7 # Shell Archive created by hpcnou!dat at Wed Feb 26 15:56:49 1986 # 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 # This archive contains; # src/newmbox.c src/strings.c src/syscall.c src/utils.c # src/validname.c src/Makefile utils/answer.c utils/arepdaemon.c # utils/autoreply.c if [ ! -d src ] then echo creating directory src mkdir src fi # ---------- file src/newmbox.c ---------- if [ -f src/newmbox.c ] then echo File 'src/newmbox.c' already exists\! exit 1 fi echo extracting file src/newmbox.c... cat << 'END-OF-FILE' > src/newmbox.c /** newmbox.c **/ /** read new mbox file (C) Copyright 1986 Dave Taylor **/ #include #ifdef BSD #undef tolower #endif #include "headers.h" #include #include #ifdef BSD # include #else # include #endif int newmbox(stat, resync) int stat, resync; { /** Read a new mailbox file or resync on current file. Values of stat and what they mean; stat = 0 - changing mailboxes from within program stat = 1 - read default mailbox for the first time stat = 2 - read existing mailbox, new mail arrived resync is TRUE iff we know the current mailbox has changed. If it's set to true this means that we MUST READ SOMETHING, even if it's the current mailbox again!! **/ int switching_to_default = 0; char buff[SLEN]; dprint2("newmbox(stat=%d, resync=%d)\n", stat, resync); dprint1("\tfile-changed = %s\n\n", onoff(file_changed)); if (stat > 0) { if (strlen(infile) == 0) /* no filename yet?? */ sprintf(infile,"%s%s",mailhome, username); } else { /* get name of new mailbox! */ MoveCursor(LINES-3, 30); CleartoEOS(); show_last_error(); if (mbox_specified != 2) { PutLine(LINES-2,0,"Name of new mailbox: "); buff[0] = '\0'; (void) optionally_enter(buff, LINES-2, 21, FALSE); ClearLine(LINES-2); if (strlen(buff) == 0) { if (resync && file_changed) strcpy(buff, infile); else return(FALSE); } if (strcmp(buff, infile) == 0 && ! resync) { error("already reading that mailbox!"); return(FALSE); } if (first_word(buff, mailhome) && ! resync) { mbox_specified = 0; /* fake program to think that */ stat = 1; /* we're the default file */ switching_to_default++; /* remember this act! */ } else if (strcmp(buff, "!") == 0) { /* go to mailbox */ sprintf(buff,"%s%s", mailhome, username); if (! resync || (resync && ! file_changed)) { if (strcmp(buff, infile) == 0) { /* are we reading it? */ error("already reading your incoming mailbox!"); return(FALSE); } } if (! resync || (resync && ! file_changed)) { mbox_specified = 0; /* fake program to think that */ stat = 1; /* we're the default file */ switching_to_default++; /* remember this act! */ } } if (! expand_filename(buff)) { error1("cannot expand file %s", buff); if (resync && file_changed) strcpy(buff, infile); else return(FALSE); } if (! can_access(buff,"r")) { error1("cannot open file %s", buff); if (resync && file_changed) strcpy(buff, infile); else return(FALSE); } if (resync && file_changed && strcmp(buff, infile) == 0) PutLine(20,40,"Resynchronizing file"); else PutLine(20,40,"Mailbox: %s", buff); CleartoEOLN(); strcpy(infile,buff); if (! switching_to_default) mbox_specified = 1; } else { /* starting filename given to routine */ if (! can_access(infile,"r")) exit(PutLine(LINES, 0, "Could not open file %s!\n", infile)); mbox_specified = 1; } } clear_error(); clear_central_message(); if ((mailfile = fopen(infile,"r")) == NULL) message_count = 0; else if (stat < 2) { /* new mail file! */ if (notesfile) message_count = read_notesfile(); /* can't get new notes! */ else message_count = read_headers(FALSE); } else /* resync with current mail file */ message_count = read_headers(TRUE); if (message_count && stat < 2) current = 1; header_page = 0; return(TRUE); } int read_headers(stat) int stat; { /** Reads the headers into the header_table structure and leaves the file rewound for further I/O requests. If the file being read is the default mailbox (ie incoming) then it is copied to a temp file and closed, to allow more mail to arrive during the msg session. If stat is set, the program will then copy the delete flag from the previous data structure value to the new one if possible. This is for re-reading the mailfile! Added: reads and formats the date from the first 'From' line **/ FILE *temp; char buffer[LONG_STRING], temp_filename[SLEN]; register int line = 0, count = 0, subj = 0, copyit = 0, in_header = 1; long bytes = 0L, line_bytes = 0L; static int first_read = 0; int count_x, count_y = 17; dprint1("read_headers(stat=%d)\n", stat); if (! first_read++) { MoveCursor(LINES-2, 0); CleartoEOS(); PutLine(LINES-1, 0, "Reading in %s, message: 0", infile); count_x = LINES-1; count_y = 22 + strlen(infile); } else { PutLine(LINES-2, 0, "Reading message: 0"); count_x = LINES-2; } if (mbox_specified == 0) { lock(INCOMING); /* ensure no mail arrives while we do this! */ sprintf(temp_filename,"%s%s",temp_mbox, username); if ((temp = fopen(temp_filename,"w")) == NULL) { unlock(); /* remove lock file! */ Raw(OFF); printf("Could not open file %s for writing (uid=%d)...\n", temp_filename, getuid()); system_call("/bin/ls -l /tmp/*", SH); leave(error1("could not open file %s for writing!", temp_filename)); } get_mailtime(); copyit++; chown(temp_filename, userid, getgid()); } while (fgets(buffer, LONG_STRING, mailfile) != NULL) { if (line == 0) { /* first line of file... */ if (! mbox_specified) { if (first_word(buffer, "Forward to ")) set_central_message("Mail being forwarded to %s", (char *) (buffer + 11)); } /* Are we reading in a notesfile file without the flag turned on??? */ if (first_word(buffer, NOTES_HEADER)) { /* if so... */ rewind(mailfile); notesfile++; /* set da flag, boss-man */ return(read_notesfile()); /* hop over to notes */ } } if (copyit) fputs(buffer, temp); line_bytes = (long) strlen(buffer); line++; if (first_word(buffer,"From ")) { if (real_from(buffer, &header_table[count])) { header_table[count].offset = (long) bytes; if (! stat || count > message_count) header_table[count].delete = 0; /* clear flag! */ strcpy(header_table[count].subject, ""); /* clear subj */ header_table[count++].lines = line; header_table[count].priority = 0; subj = 0; in_header = 1; PutLine(count_x, count_y, "%d", count); if (count > 1) header_table[count-2].lines = header_table[count-1].lines - header_table[count-2].lines; } } else if (in_header) { if (first_word(buffer,">From")) forwarded(buffer, &header_table[count-1]); /* return address */ else if (first_word(buffer,"Subject:") || first_word(buffer,"Subj:") || first_word(buffer,"Re:")) { if (! subj++) { remove_first_word(buffer); strncpy(header_table[count-1].subject, buffer, SLEN); } } else if (first_word(buffer,"From:")) parse_arpa_from(buffer, header_table[count-1].from); else if (first_word(buffer, "Date:")) parse_arpa_date(buffer, &header_table[count-1]); else if (first_word(buffer, "Priority:")) header_table[count-1].priority++; else if (buffer[0] == LINE_FEED || buffer[0] == '\0') { if (in_header) { in_header = 0; /* in body of message! */ fix_date(&header_table[count-1]); } } } bytes += (long) line_bytes; } total_lines_in_file = line; header_table[count-1].lines = line - header_table[count-1].lines + 1; if (mbox_specified == 0) { unlock(); /* remove lock file! */ fclose(mailfile); fclose(temp); if ((mailfile = fopen(temp_filename,"r")) == NULL) { MoveCursor(LINES,0); Raw(OFF); printf("Fatal error: could not reopen %s as temp mail file!\n", temp_filename); leave(); } } else rewind(mailfile); return(count); } END-OF-FILE size=`wc -c < src/newmbox.c` if [ $size != 8124 ] then echo Warning: src/newmbox.c changed - should be 8124 bytes, not $size bytes fi chmod 644 src/newmbox.c # ---------- file src/strings.c ---------- if [ -f src/strings.c ] then echo File 'src/strings.c' already exists\! exit 1 fi echo extracting file src/strings.c... cat << 'END-OF-FILE' > src/strings.c /** strings.c **/ /** This file contains all the string oriented functions for the MSG Mailer, and lots of other generally useful string functions! For BSD systems, this file also includes the function "tolower" to translate the given character from upper case to lower case. (C) Copyright 1985, Dave Taylor **/ #include #include "headers.h" #include #ifdef BSD #undef tolower #undef toupper #endif /** forward declarations **/ char *format_long(), *strip_commas(), *tail_of_string(), *shift_lower(), *get_token(), *strip_parens(), *argv_zero(); #ifdef BSD int tolower(ch) char ch; { /** This should be a macro call, but if you use this as a macro calls to 'tolower' where the argument is a function call will cause the function to be called TWICE which is obviously the wrong behaviour. On the other hand, to just blindly translate assuming the character is always uppercase can cause BIG problems, so... **/ return ( isupper(ch) ? ch - 'A' + 'a' : ch ); } int toupper(ch) char ch; { /** see comment for above routine - tolower() **/ return ( islower(ch) ? ch - 'a' + 'A' : ch ); } #endif int in_string(buffer, pattern) char *buffer, *pattern; { /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ register int i = 0, j = 0; while (buffer[i] != '\0') { while (buffer[i++] == pattern[j++]) if (pattern[j] == '\0') return(TRUE); i = i - j + 1; j = 0; } return(FALSE); } tail_of(from, buffer, header_line) char *from, *buffer; int header_line; { /** Return last two words of 'from'. This is to allow painless display of long return addresses as simply the machine!username. Alternatively, if the first three characters of the 'from' address are 'To:' and 'header_line' is TRUE, then return the buffer value prepended with 'To '. **/ /** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes, ':' delimits CSNet & Bitnet nodes, and '%' delimits multiple stage ARPA hops... **/ register int loc, i = 0, cnt = 0; char tempbuffer[SLEN]; for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) { if (from[loc] == '!' || from[loc] == '@' || from[loc] == ':') cnt++; if (cnt < 2) buffer[i++] = from[loc]; } buffer[i] = '\0'; reverse(buffer); if ((strncmp(buffer,"To:", 3) == 0) && header_line) buffer[2] = ' '; else if ((strncmp(from, "To:", 3) == 0) && header_line) { sprintf(tempbuffer,"To %s", buffer); strcpy(buffer, tempbuffer); } else if (strncmp(buffer, "To:", 3) == 0) { for (i=3; i < strlen(buffer); i++) tempbuffer[i-3] = buffer[i]; tempbuffer[i-3] = '\0'; strcpy(buffer, tempbuffer); } } char *format_long(inbuff, init_len) char *inbuff; int init_len; { /** Return buffer with \n\t sequences added at each point where it would be more than 80 chars long. It only allows the breaks at legal points (ie white spaces). init-len is the characters already on the first line... Changed so that if this is called while mailing without the overhead of "msg", it'll include "\r\n\t" instead. **/ static char ret_buffer[VERY_LONG_STRING]; register int index = 0, current_length = 0, depth=15, i; char buffer[VERY_LONG_STRING]; char *word, *bufptr; strcpy(buffer, inbuff); bufptr = (char *) buffer; current_length = init_len + 2; /* for luck */ while ((word = get_token(bufptr," ", depth)) != NULL) { if (strlen(word) + current_length > 80) { if (index > 0) { if (mail_only) ret_buffer[index++] = '\r'; ret_buffer[index++] = '\n'; ret_buffer[index++] = '\t'; } for (i=0; i 0) ret_buffer[index++] = ' '; for (i=0; i 1) buffer[i--] = string[index--]; buffer[2] = '.'; buffer[1] = '.'; buffer[0] = '.'; } return( (char *) buffer); } reverse(string) char *string; { /** reverse string... pretty trivial routine, actually! **/ char buffer[SLEN]; register int i, j = 0; for (i = strlen(string)-1; i >= 0; i--) buffer[j++] = string[i]; buffer[j] = '\0'; strcpy(string, buffer); } int get_word(buffer, start, word) char *buffer, *word; int start; { /** return next word in buffer, starting at 'start'. delimiter is space or end-of-line. Returns the location of the next word, or -1 if returning the last word in the buffer. -2 indicates empty buffer! **/ register int loc = 0; while (buffer[start] == ' ' && buffer[start] != '\0') start++; if (buffer[start] == '\0') return(-2); /* nothing IN buffer! */ while (buffer[start] != ' ' && buffer[start] != '\0') word[loc++] = buffer[start++]; word[loc] = '\0'; return(start); } int chloc(string, ch) char *string, ch; { /** returns the index of ch in string, or -1 if not in string **/ register int i; for (i=0; i COLUMNS) col = 0; else col = (COLUMNS - length) / 2; PutLine(line, col, string); } char *argv_zero(string) char *string; { /** given a string of the form "/something/name" return a string of the form "name"... **/ static char buffer[NLEN]; register int i, j=0; for (i=strlen(string)-1; string[i] != '/'; i--) buffer[j++] = string[i]; buffer[j] = '\0'; reverse(buffer); return( (char *) buffer); } #define MAX_RECURSION 20 /* up to 20 deep recursion */ char *get_token(source, keys, depth) char *source, *keys; int depth; { /** This function is similar to strtok() (see "opt_utils") but allows nesting of calls via pointers... **/ register int last_ch; static char *buffers[MAX_RECURSION]; char *return_value, *sourceptr; if (depth > MAX_RECURSION) { error1("get_token calls nested greater than %d deep!", MAX_RECURSION); emergency_exit(); } if (source != NULL) buffers[depth] = source; sourceptr = buffers[depth]; if (*sourceptr == '\0') return(NULL); /* we hit end-of-string last time!? */ sourceptr += strspn(sourceptr, keys); /* skip the bad.. */ if (*sourceptr == '\0') { buffers[depth] = sourceptr; return(NULL); /* we've hit end-of-string */ } last_ch = strcspn(sourceptr, keys); /* end of good stuff */ return_value = sourceptr; /* and get the ret */ sourceptr += last_ch; /* ...value */ if (*sourceptr != '\0') /** don't forget if we're at end! **/ sourceptr++; return_value[last_ch] = '\0'; /* ..ending right */ buffers[depth] = sourceptr; /* save this, mate! */ return((char *) return_value); /* and we're outta here! */ } END-OF-FILE size=`wc -c < src/strings.c` if [ $size != 10790 ] then echo Warning: src/strings.c changed - should be 10790 bytes, not $size bytes fi chmod 644 src/strings.c # ---------- file src/syscall.c ---------- if [ -f src/syscall.c ] then echo File 'src/syscall.c' already exists\! exit 1 fi echo extracting file src/syscall.c... cat << 'END-OF-FILE' > src/syscall.c /** syscall.c **/ /** These routines are used for user-level system calls, including the '!' command and the '|' commands... (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include char *argv_zero(); int subshell() { /** spawn a subshell with either the specified command returns non-zero if screen rewrite needed **/ char command[SLEN]; int ret; PutLine(LINES-3,COLUMNS-40,"(use 'sh' or 'csh' for a shell)"); PutLine(LINES-2,0,"Shell Command: "); command[0] = '\0'; (void) optionally_enter(command, LINES-2, 15, FALSE); if (strlen(command) == 0) { MoveCursor(LINES-2,0); CleartoEOLN(); return(0); } MoveCursor(LINES,0); CleartoEOLN(); Raw(OFF); if (cursor_control) transmit_functions(OFF); ret = system_call(command, USER_SHELL); printf("\nPress to return to MSG: "); Raw(ON); (void) getchar(); if (cursor_control) transmit_functions(ON); if (ret != 0) error1("Return code was %d", ret); return(1); } system_call(string, shell_type) char *string; int shell_type; { /** execute 'string', setting uid to userid... **/ /** if shell-type is "SH" /bin/sh is used regardless of the users shell setting. Otherwise, "USER_SHELL" is sent **/ int status, pid, w; register int (*istat)(), (*qstat)(); dprint2("system_call('%s', %s)\n", string, shell_type == SH? "SH" : "USER-SHELL"); if ((pid = fork()) == 0) { setuid(userid); /* back to the normal user! */ if (strlen(shell) > 0 && shell_type == USER_SHELL) { execl(shell, argv_zero(shell), "-c", string, 0); } else execl("/bin/sh", "sh", "-c", string, 0); _exit(127); } istat = signal(SIGINT, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); while ((w = wait(&status)) != pid && w != -1) ; if (w == -1) status = -1; signal(SIGINT, istat); signal(SIGQUIT, qstat); return(status); } int pipe() { /** pipe the current message to the specified sequence.. **/ char command[SLEN], buffer[LONG_SLEN]; int ret, lines; PutLine(LINES-2,0,"Pipe current msg to: "); command[0] = '\0'; (void) optionally_enter(command, LINES-2, 21, FALSE); if (strlen(command) == 0) { MoveCursor(LINES-2,0); CleartoEOLN(); return(0); } MoveCursor(LINES,0); CleartoEOLN(); Raw(OFF); lines = header_table[current-1].lines; if (cursor_control) transmit_functions(OFF); sprintf(buffer, "%s %s %d %d - | %s", cutfile, infile, header_table[current-1].offset, lines, command); ret = system_call(buffer, USER_SHELL); printf("\nPress to return to MSG: "); Raw(ON); (void) getchar(); if (cursor_control) transmit_functions(ON); if (ret != 0) error1("Return code was %d", ret); return(1); } printmsg() { /** print specified message using 'printout' variable. Error message iff printout not defined! **/ FILE *temp; char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN]; int retcode; dprint1("printmsg()\n\tprintout = %s\n", printout); dprint1("\tcurrent message = %d\n", current); if (strlen(printout) == 0) { error("PRINTMAIL not defined! Don't know how to print message"); return; } if (current == 0) { error("No mail to print!"); return; } sprintf(filename,"%s%d", temp_print, getpid()); if ((temp = fopen(filename,"w")) == NULL) { error1("Could not open file %s as a temporary file", filename); return; } copy_message("", temp, FALSE); fclose(temp); if (in_string(printout, "%s")) sprintf(printbuffer, printout, filename); else sprintf(printbuffer, "%s %s", printout, filename); sprintf(buffer,"(%s 2>&1 ) > /dev/null", printbuffer, filename); error("working..."); if ((retcode = system_call(buffer, SH)) == 0) error("Message queued up to print"); else error1("Printout failed with return code %d", retcode); unlink(filename); /* remove da temp file! */ } END-OF-FILE size=`wc -c < src/syscall.c` if [ $size != 3869 ] then echo Warning: src/syscall.c changed - should be 3869 bytes, not $size bytes fi chmod 644 src/syscall.c # ---------- file src/utils.c ---------- if [ -f src/utils.c ] then echo File 'src/utils.c' already exists\! exit 1 fi echo extracting file src/utils.c... cat << 'END-OF-FILE' > src/utils.c /** utils.c **/ /** Utility routines for MSG All routines herein: (C) Copyright 1985 Dave Taylor **/ #include "headers.h" #include #include #include #ifdef BSD #undef tolower #endif #include #include emergency_exit() { /** used in dramatic cases when we must leave without altering ANYTHING about the system... **/ Raw(OFF); if (cursor_control) transmit_functions(OFF); if (hp_terminal) softkeys_off(); if (cursor_control) MoveCursor(LINES, 0); printf("\n\rEmergency Exit taken! All temp files intact!\n\r\n\r"); exit(1); } leave(val) int val; /* not used, placeholder for signal catching! */ { char buffer[SLEN]; dprint1("leave(%d)\n", val); Raw(OFF); if (cursor_control) transmit_functions(OFF); if (hp_terminal) softkeys_off(); sprintf(buffer,"%s%d",temp_file, getpid()); /* editor buffer */ (void) unlink(buffer); if (! mail_only) { sprintf(buffer,"%s%d",temp_file, getpid()+1); /* editor buffer */ (void) unlink(buffer); } sprintf(buffer,"%s%s",temp_mbox, username); /* temp mailbox */ (void) unlink(buffer); sprintf(buffer,"%s%s.lock",mailhome, username); /* lock file */ (void) unlink(buffer); if (! mail_only) MoveCursor(LINES-1,0); putchar('\n'); exit(0); } leave_locked(val) int val; /* not used, placeholder for signal catching! */ { /** same as leave routine, but don't disturb lock file **/ char buffer[SLEN]; dprint1("leave_locked(%d)\n", val); Raw(OFF); if (cursor_control) transmit_functions(OFF); if (hp_terminal) softkeys_off(); sprintf(buffer,"%s%d",temp_file, getpid()); /* editor buffer */ (void) unlink(buffer); sprintf(buffer,"%s%d",temp_file, getpid()+1); /* editor buffer */ (void) unlink(buffer); sprintf(buffer,"%s%s",temp_mbox, username); /* temp mailbox */ (void) unlink(buffer); MoveCursor(LINES-1,0); putchar('\n'); exit(0); } int get_page(current) int current; { /** ensure that 'current' is on the displayed page, returning non-zero iff the page changed! **/ register int first_on_page, last_on_page; first_on_page = (header_page * headers_per_page) + 1; last_on_page = first_on_page + headers_per_page - 1; if (current > last_on_page) { header_page = (int) (current-1) / headers_per_page; return(1); } else if (current < first_on_page) { header_page = (int) (current-1) / headers_per_page; return(1); } else return(0); } int copy_to_self(buffer) char *buffer; { /** returns true iff buffer = 'Cc: username' where username is the account name of the person sending the message. Used for weeding out 'Cc:' lines from the messages if 'weed' is turned on. **/ /** note: tail_of() is located in file "strings.c" **/ char name[SLEN], buf[SLEN]; register int i=0, j=0; dprint1("copy_to_self(%s)\n", buffer); tail_of(header_table[current-1].from, name, FALSE); while (name[i] != '!' && i < strlen(name)) i++; if (name[i] == '!') { for (i++; i < strlen(name); i++) name[j++] = name[i]; name[j] = 0; } sprintf(buf, "Cc: %s\n", name); return( strcmp(buf, buffer) == 0 ); } END-OF-FILE size=`wc -c < src/utils.c` if [ $size != 3154 ] then echo Warning: src/utils.c changed - should be 3154 bytes, not $size bytes fi chmod 644 src/utils.c # ---------- file src/validname.c ---------- if [ -f src/validname.c ] then echo File 'src/validname.c' already exists\! exit 1 fi echo extracting file src/validname.c... cat << 'END-OF-FILE' > src/validname.c /** validname.c **/ /** This routine takes a single address, no machine hops or anything, and returns 1 if it's valid and 0 if not. The algorithm it uses is the same one that uux uses, namely: 1. Is there a file '/usr/mail/%s'? 2. Is there a password entry for %s? (C) Copyright 1986 Dave Taylor **/ #include #include "defs.h" int valid_name(name) char *name; { /** does what it says above, boss! **/ char filebuf[SLEN]; #ifdef NOCHECK_VALIDNAME return(1); /* always say it's okay! */ #else sprintf(filebuf,"%s/%s", mailhome, name); if (access(filebuf, ACCESS_EXISTS) == 0) return(1); if (getpwnam(name) != NULL) return(1); return(0); #endif } END-OF-FILE size=`wc -c < src/validname.c` if [ $size != 707 ] then echo Warning: src/validname.c changed - should be 707 bytes, not $size bytes fi chmod 644 src/validname.c # ---------- file src/Makefile ---------- if [ -f src/Makefile ] then echo File 'src/Makefile' already exists\! exit 1 fi echo extracting file src/Makefile... cat << 'END-OF-FILE' > src/Makefile # # Makefile for the MSG mail program. # # (C) Copyright 1986, Dave Taylor # # Last modification: January 23rd, 1986 CFILES= addr_utils.c alias.c aliasdb.c aliaslib.c args.c curses.c date.c \ delete.c encode.c file.c file_utils.c fileio.c hdrconfg.c help.c \ initialize.c input_utils.c mailout.c mailtime.c mkhdrs.c msg.c \ newmbox.c notesfile.c output_utils.c pattern.c quit.c savecopy.c \ read_rc.c reply.c return_addr.c screen.c showmsg.c strings.c \ syscall.c utils.c validname.c softkeys.c opt_utils.c leavembox.c HEADERS=../hdrs/curses.h ../hdrs/defs.h ../hdrs/headers.h ../hdrs/msg.h OBJS= addr_utils.o alias.o aliasdb.o aliaslib.o args.o curses.o date.o \ delete.o encode.o file.o file_utils.o fileio.o hdrconfg.o help.o \ initialize.o input_utils.o mailout.o mailtime.o mkhdrs.o msg.o \ newmbox.o notesfile.o output_utils.o pattern.o quit.o savecopy.o \ read_rc.o reply.o return_addr.o screen.o showmsg.o strings.o \ syscall.o utils.o validname.o softkeys.o opt_utils.o leavembox.o # if on BSD use # DEFINE=-DBSD # else if on UTS use # DEFINE=-DUTS # else DEFINE= BIN= ../bin LIBS= -ltermcap CFLAGS= -O -I../hdrs CC= /bin/cc RM= /bin/rm -f .c.o: ${HEADERS} ${CC} -c ${CFLAGS} ${DEFINE} $*.c ../bin/msg: ${OBJS} ${EXTRA} ${HEADERS} ../hdrs/msg.h ${CC} -o ${BIN}/msg -n ${OBJS} ${LIBS} curses.o: curses.c ../hdrs/curses.h ${CC} -c -O -DRAWMODE ${DEFINE} -I../hdrs curses.c clean: ${RM} ${OBJS} LINT.OUT lint: LINT.OUT LINT.OUT: ${CFILES} lint -p -I../hdrs ${CFILES} > LINT.OUT listing: @../bin/makelisting Makefile ${HEADERS} ${CFILES} @echo LISTING generated. END-OF-FILE size=`wc -c < src/Makefile` if [ $size != 1647 ] then echo Warning: src/Makefile changed - should be 1647 bytes, not $size bytes fi chmod 644 src/Makefile if [ ! -d utils ] then echo creating directory utils mkdir utils fi # ---------- file utils/answer.c ---------- if [ -f utils/answer.c ] then echo File 'utils/answer.c' already exists\! exit 1 fi echo extracting file utils/answer.c... cat << 'END-OF-FILE' > utils/answer.c /** answer.c **/ /** This program is a phone message transcription system, and is designed for secretaries and the like, to allow them to painlessly generate electronic mail instead of paper forms. Note: this program ONLY uses the local alias file, and does not even read in the system alias file at all. (C) Copyright 1986, Dave Taylor **/ #include #include #include #include "defs.h" /* MSG system definitions */ struct alias_rec user_hash_table [MAX_UALIASES]; int user_data; /* fileno of user data file */ char *expand_group(), *get_alias_address(), *get_token(); main() { FILE *fd; char *address, buffer[LONG_STRING], tempfile[SLEN]; char name[SLEN], user_name[SLEN]; int msgnum = 0, eof; read_alias_files(); while (1) { if (msgnum > 9999) msgnum = 0; printf("\n-------------------------------------------------------------------------------\n"); prompt: printf("\nMessage to: "); gets(user_name, SLEN); if ((strcmp(user_name,"quit") == 0) || (strcmp(user_name,"exit") == 0) || (strcmp(user_name,"done") == 0) || (strcmp(user_name,"bye") == 0)) exit(0); if (translate(user_name, name) == 0) goto prompt; address = get_alias_address(name, 1, 0); if (strlen(address) == 0) { printf("Sorry, could not find '%s' [%s] in list!\n", user_name, name); goto prompt; } sprintf(tempfile, "%s%d", temp_file, msgnum++); if ((fd = fopen(tempfile,"w")) == NULL) exit(printf("** Fatal Error: could not open %s to write\n", tempfile)); printf("\nEnter message for %s ending with a blank line.\n\n", user_name); fprintf(fd,"\n\n"); do { printf("> "); if (! (eof = (gets(buffer, SLEN) == NULL))) fprintf(fd, "%s\n", buffer); } while (! eof && strlen(buffer) > 0); fclose(fd); sprintf(buffer, "(%s -s \"While You Were Out\" %s < %s ; %s %s) &", mailx, address, tempfile, remove, tempfile); system(buffer); } } int translate(fullname, name) char *fullname, *name; { /** translate fullname into name.. 'first last' translated to first_initial - underline - last 'initial last' translated to initial - underline - last Return 0 if error. **/ register int i, lastname = 0; for (i=0; i < strlen(fullname); i++) { if (isupper(fullname[i])) fullname[i] = fullname[i] - 'A' + 'a'; if (fullname[i] == ' ') if (lastname) { printf( "** Can't have more than 'FirstName LastName' as address!\n"); return(0); } else lastname = i+1; } if (lastname) sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname); else strcpy(name, fullname); return(1); } read_alias_files() { /** read the user alias file **/ char fname[SLEN]; int hash; sprintf(fname, "%s/.alias_hash", getenv("HOME")); if ((hash = open(fname, O_RDONLY)) == -1) exit(printf("** Fatal Error: Could not open %s!\n", fname)); read(hash, user_hash_table, sizeof user_hash_table); close(hash); sprintf(fname, "%s/.alias_data", getenv("HOME")); if ((user_data = open(fname, O_RDONLY)) == -1) return; } char *get_alias_address(name, mailing, depth) char *name; int mailing, depth; { /** return the line from either datafile that corresponds to the specified name. If 'mailing' specified, then fully expand group names. Returns NULL if not found. Depth is the nesting depth, and varies according to the nesting level of the routine. **/ static char buffer[VERY_LONG_STRING]; int loc; if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) { lseek(user_data, user_hash_table[loc].byte, 0L); get_line(user_data, buffer, LONG_STRING); if (buffer[0] == '!' && mailing) return( (char *) expand_group(buffer, depth)); else return( (char *) buffer); } return( (char *) NULL); } char *expand_group(members, depth) char *members; int depth; { /** given a group of names separated by commas, this routine will return a string that is the full addresses of each member separated by spaces. Depth is the current recursion depth of the expansion (for the 'get_token' routine) **/ char buffer[VERY_LONG_STRING]; char buf[LONG_STRING], *word, *address, *bufptr; strcpy(buf, members); /* parameter safety! */ buffer[0] = '\0'; /* nothing in yet! */ bufptr = (char *) buf; /* grab the address */ depth++; /* one more deeply into stack */ while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) { if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) { fprintf(stderr, "Alias %s not found for group expansion!", word); return( (char *) NULL); } else if (strcmp(buffer,address) != 0) { sprintf(buffer,"%s %s", buffer, address); } bufptr = NULL; } return( (char *) buffer); } int find(word, table, size) char *word; struct alias_rec table[]; int size; { /** find word and return loc, or -1 **/ register int loc; if (strlen(word) > 20) exit(printf("Bad alias name: %s. Too long.\n", word)); loc = hash_it(word, size); while (strcmp(word, table[loc].name) != 0) { if (table[loc].name[0] == '\0') return(-1); loc = (loc + 1) % size; } return(loc); } int hash_it(string, table_size) char *string; int table_size; { /** compute the hash function of the string, returning it (mod table_size) **/ register int i, sum = 0; for (i=0; string[i] != '\0'; i++) sum += (int) string[i]; return(sum % table_size); } get_line(fd, buffer) int fd; char *buffer; { /* read from file fd. End read upon reading either EOF or '\n' character (this is where it differs from a straight 'read' command!) */ register int i= 0; char ch; while (read(fd, &ch, 1) > 0) if (ch == '\n' || ch == '\r') { buffer[i] = 0; return; } else buffer[i++] = ch; } print_long(buffer, init_len) char *buffer; int init_len; { /** print buffer out, 80 characters (or less) per line, for as many lines as needed. If 'init_len' is specified, it is the length that the first line can be. **/ register int i, loc=0, space, length; /* In general, go to 80 characters beyond current character being processed, and then work backwards until space found! */ length = init_len; do { if (strlen(buffer) > loc + length) { space = loc + length; while (buffer[space] != ' ' && space > loc + 50) space--; for (i=loc;i <= space;i++) putchar(buffer[i]); putchar('\n'); loc = space; } else { for (i=loc;i < strlen(buffer);i++) putchar(buffer[i]); putchar('\n'); loc = strlen(buffer); } length = 80; } while (loc < strlen(buffer)); } /**** The following is a newly chopped version of the 'strtok' routine that can work in a recursive way (up to 20 levels of recursion) by changing the character buffer to an array of character buffers.... ****/ #define MAX_RECURSION 20 /* up to 20 deep recursion */ #undef NULL #define NULL (char *) 0 /* for this routine only */ extern int strspn(); extern char *strpbrk(); char *get_token(string, sepset, depth) char *string, *sepset; int depth; { /** string is the string pointer to break up, sepstr are the list of characters that can break the line up and depth is the current nesting/recursion depth of the call **/ register char *p, *q, *r; static char *savept[MAX_RECURSION]; /** is there space on the recursion stack? **/ if (depth >= MAX_RECURSION) { fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n", MAX_RECURSION); exit(1); } /* set up the pointer for the first or subsequent call */ p = (string == NULL)? savept[depth]: string; if(p == 0) /* return if no tokens remaining */ return(NULL); q = p + strspn(p, sepset); /* skip leading separators */ if (*q == '\0') /* return if no tokens remaining */ return(NULL); if ((r = strpbrk(q, sepset)) == NULL) /* move past token */ savept[depth] = 0; /* indicate this is last token */ else { *r = '\0'; savept[depth] = ++r; } return(q); } END-OF-FILE size=`wc -c < utils/answer.c` if [ $size != 8207 ] then echo Warning: utils/answer.c changed - should be 8207 bytes, not $size bytes fi chmod 644 utils/answer.c # ---------- file utils/arepdaemon.c ---------- if [ -f utils/arepdaemon.c ] then echo File 'utils/arepdaemon.c' already exists\! exit 1 fi echo extracting file utils/arepdaemon.c... cat << 'END-OF-FILE' > utils/arepdaemon.c /** arepdaemon.c **/ /** (C) Copyright 1986 Dave Taylor **/ /** Keep track of mail as it arrives, and respond by sending a 'recording' file to the sender as new mail is received. Note: the user program that interacts with this program is the 'autoreply' program and that should be consulted for further usage information. This program is part of the 'autoreply' system, and is designed to run every hour and check all mailboxes listed in the file "/etc/autoreply.data", where the data is in the form: username replyfile current-mailfile-size To avoid a flood of autoreplies, this program will NOT reply to mail that contains header "X-Mailer: fastmail". Further, each time the program responds to mail, the 'mailfile size' entry is updated in the file /etc/autoreply.data to allow the system to be brought down and rebooted without any loss of data or duplicate messages. This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep, to ensure that more than one copy of itself is never running. For this reason, it is recommended that this daemon be started up each morning from cron, since it will either start since it's needed or simply see that the file is there and disappear. Since this particular program is the main daemon answering any number of different users, it must be run with uid root. (C) 1985, Dave Taylor, HP Colorado Networks Operation **/ #include #include #include #include #include "defs.h" #define arep_lock_file "/usr/spool/uucp/LCK..arep" #define autoreply_file "/etc/autoreply.data" #define fastmail "/usr/local/bin/fastmail" #define logfile "/etc/autoreply.log" /* first choice */ #define logfile2 "/tmp/autoreply.log" /* second choice */ #define BEGINNING 0 /* see fseek(3S) for info */ #define SLEEP_TIME 3600 /* run once an hour */ #define MAX_PEOPLE 20 /* max number in program */ #define EXISTS 00 /* lock file exists?? */ #define MODE 0777 /* lockfile creation mode */ #define NLEN 20 #define remove_return(s) if (strlen(s) > 0) { \ if (s[strlen(s)-1] == '\n') \ s[strlen(s)-1] = '\0'; \ } struct replyrec { char username[NLEN]; /* login name of user */ char mailfile[SLEN]; /* name of mail file */ char replyfile[SLEN]; /* name of reply file */ long mailsize; /* mail file size */ int in_list; /* for new replies */ } reply_table[MAX_PEOPLE]; FILE *logfd; /* logfile (log action) */ long autoreply_size = 0L; /* size of autoreply file */ int active = 0; /* # of people 'enrolled' */ FILE *open_logfile(); /* forward declaration */ long bytes(); /* ditto */ main() { long size; int person, data_changed; if (! lock()) exit(0); /* already running! */ while (1) { logfd = open_logfile(); /* open the log */ /* 1. check to see if autoreply table has changed.. */ if ((size = bytes(autoreply_file)) != autoreply_size) { read_autoreply_file(); autoreply_size = size; } /* 2. now for each active person... */ data_changed = 0; for (person = 0; person < active; person++) { if ((size = bytes(reply_table[person].mailfile)) != reply_table[person].mailsize) { if (size > reply_table[person].mailsize) read_newmail(person); /* else mail removed - resync */ reply_table[person].mailsize = size; data_changed++; } } /* 3. if data changed, update autoreply file */ if (data_changed) update_autoreply_file(); close_logfile(); /* close the logfile again */ /* 4. Go to sleep... */ sleep(SLEEP_TIME); } } int read_autoreply_file() { /** We're here because the autoreply file has changed size!! It could either be because someone has been added or because someone has been removed...since the list will always be in order (nice, eh?) we should have a pretty easy time of it... **/ FILE *file; char username[SLEN], replyfile[SLEN]; int person; long size; log("Autoreply data file has changed! Reading..."); if ((file = fopen(autoreply_file,"r")) == NULL) { log("No-one is using autoreply..."); return(0); } for (person = 0; person < active; person++) reply_table[person].in_list = 0; while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) { /* check to see if this person is already in the list */ if ((person = in_list(username)) != -1) { reply_table[person].in_list = 1; reply_table[person].mailsize = size; /* sync */ } else { /* if not, add them */ if (active == MAX_PEOPLE) { unlock(); exit(log("Couldn't add %s - already at max people!", username)); } log("adding %s to the active list", username); strcpy(reply_table[active].username, username); sprintf(reply_table[active].mailfile, "/usr/mail/%s", username); strcpy(reply_table[active].replyfile, replyfile); reply_table[active].mailsize = size; reply_table[active].in_list = 1; /* obviously! */ active++; } } /** now check to see if anyone has been removed... **/ for (person = 0; person < active; person++) if (reply_table[person].in_list == 0) { log("removing %s from the active list", reply_table[person].username); strcpy(reply_table[person].username, reply_table[active-1].username); strcpy(reply_table[person].mailfile, reply_table[active-1].mailfile); strcpy(reply_table[person].replyfile, reply_table[active-1].replyfile); reply_table[person].mailsize = reply_table[active-1].mailsize; active--; } } update_autoreply_file() { /** update the entries in the autoreply file... **/ FILE *file; register int person; if ((file = fopen(autoreply_file,"w")) == NULL) { log("Couldn't update autoreply file!"); return; } for (person = 0; person < active; person++) fprintf(file, "%s %s %ld\n", reply_table[person].username, reply_table[person].replyfile, reply_table[person].mailsize); fclose(file); printf("updated autoreply file\n"); autoreply_size = bytes(autoreply_file); } int in_list(name) char *name; { /** search the current active reply list for the specified username. return the index if found, or '-1' if not. **/ register int index; for (index = 0; index < active; index++) if (strcmp(name, reply_table[index].username) == 0) return(index); return(-1); } read_newmail(person) int person; { /** Read the new mail for the specified person. **/ FILE *mailfile; char from_whom[LONG_SLEN], subject[SLEN]; int sendit; log("New mail for %s", reply_table[person].username); if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL) return(log("can't open mailfile for user %s", reply_table[person].username)); if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1) return(log("couldn't seek to %ld in mail file!", reply_table[person].mailsize)); while (get_return(mailfile, person, from_whom, subject, &sendit) != -1) if (sendit) reply_to_mail(person, from_whom, subject); return; } int get_return(file, person, from, subject, sendit) FILE *file; int person, *sendit; char *from, *subject; { /** Reads the new message and return the from and subject lines. sendit is set to true iff it isn't a machine generated msg **/ char name1[SLEN], name2[SLEN], lastname[SLEN]; char buffer[LONG_SLEN], hold_return[NLEN]; int done = 0, in_header = 0; from[0] = '\0'; *sendit = 1; while (! done) { if (fgets(buffer, LONG_SLEN, file) == NULL) return(-1); if (first_word(buffer, "From ")) { in_header++; sscanf(buffer, "%*s %s", hold_return); } else if (in_header) { if (first_word(buffer, ">From")) { sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2); add_site(from, name2, lastname); } else if (first_word(buffer,"Subject:")) { remove_return(buffer); strcpy(subject, (char *) (buffer + 8)); } else if (first_word(buffer,"X-Mailer: fastmail")) *sendit = 0; else if (strlen(buffer) == 1) done = 1; } } if (from[0] == '\0') strcpy(from, hold_return); /* default address! */ else add_site(from, name1, lastname); /* get the user name too! */ return(0); } add_site(buffer, site, lastsite) char *buffer, *site, *lastsite; { /** add site to buffer, unless site is 'uucp', or the same as lastsite. If not, set lastsite to site. **/ char local_buffer[LONG_SLEN], *strip_parens(); if (strcmp(site, "uucp") != 0) if (strcmp(site, lastsite) != 0) { if (buffer[0] == '\0') strcpy(buffer, strip_parens(site)); /* first in list! */ else { sprintf(local_buffer,"%s!%s", buffer, strip_parens(site)); strcpy(buffer, local_buffer); } strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */ } } remove_first_word(string) char *string; { /** removes first word of string, ie up to first non-white space following a white space! **/ register int loc; for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) ; while (string[loc] == ' ' || string[loc] == '\t') loc++; move_left(string, loc); } move_left(string, chars) char string[]; int chars; { /** moves string chars characters to the left DESTRUCTIVELY **/ register int i; chars--; /* index starting at zero! */ for (i=chars; string[i] != '\0' && string[i] != '\n'; i++) string[i-chars] = string[i]; string[i-chars] = '\0'; } reply_to_mail(person, from, subject) int person; char *from, *subject; { /** Respond to the message from the specified person with the specified subject... **/ char buffer[SLEN]; if (strlen(subject) == 0) strcpy(subject, "Auto-reply Mail"); else if (! first_word(subject,"Auto-reply")) { sprintf(buffer, "Auto-reply to:%s", subject); strcpy(subject, buffer); } log("auto-replying to '%s'", from); mail(from, subject, reply_table[person].replyfile, person); } reverse(string) char *string; { /** reverse string... pretty trivial routine, actually! **/ char buffer[SLEN]; register int i, j = 0; for (i = strlen(string)-1; i >= 0; i--) buffer[j++] = string[i]; buffer[j] = '\0'; strcpy(string, buffer); } long bytes(name) char *name; { /** return the number of bytes in the specified file. This is to check to see if new mail has arrived.... **/ int ok = 1; extern int errno; /* system error number! */ struct stat buffer; if (stat(name, &buffer) != 0) if (errno != 2) { unlock(); exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name)); } else ok = 0; return(ok ? buffer.st_size : 0); } mail(to, subject, filename, person) char *to, *subject, *filename; int person; { /** Mail 'file' to the user from person... **/ char buffer[VERY_LONG_STRING]; sprintf(buffer, "%s -f '%s [autoreply]' -s '%s' %s %s", fastmail, reply_table[person].username, subject, filename, to); system(buffer); } log(message, arg) char *message; char *arg; { /** Put log entry into log file. Use the format: date-time: **/ struct tm *localtime(), *thetime; long time(), clock; char buffer[SLEN]; /** first off, get the time and date **/ clock = time((long *) 0); /* seconds since ??? */ thetime = localtime(&clock); /* and NOW the time... */ /** then put the message out! **/ sprintf(buffer, message, arg); fprintf(logfd,"%d/%d-%d:%02d: %s\n", thetime->tm_mon+1, thetime->tm_mday, thetime->tm_hour, thetime->tm_min, buffer); } FILE *open_logfile() { /** open the logfile. returns a valid file descriptor **/ FILE *fd; if ((fd = fopen(logfile, "a")) == 0) if ((fd = fopen(logfile2, "a")) == 0) { unlock(); exit(1); /* give up! */ } return( (FILE *) fd); } close_logfile() { /** Close the logfile until needed again. **/ fclose(logfd); } char *strip_parens(string) char *string; { /** Return string with all parenthesized information removed. This is a non-destructive algorithm... **/ static char buffer[LONG_SLEN]; register int i, depth = 0, buffer_index = 0; for (i=0; i < strlen(string); i++) { if (string[i] == '(') depth++; else if (string[i] == ')') depth--; else if (depth == 0) buffer[buffer_index++] = string[i]; } buffer[buffer_index] = '\0'; return( (char *) buffer); } /*** LOCK and UNLOCK - ensure only one copy of this daemon running at any given time by using a file existance semaphore (wonderful stuff!) ***/ lock() { /** Try to create the lock file. If it's there, or we can't create it for some stupid reason, return zero, otherwise, a non-zero return code indicates success in locking this process in. **/ if (access(arep_lock_file, EXISTS) == 0) return(0); /* file already exists!! */ if (creat(arep_lock_file, MODE) == -1) return(0); /* can't create file!! */ return(1); } unlock() { /** remove lock file if it's there! **/ (void) unlink(arep_lock_file); } END-OF-FILE size=`wc -c < utils/arepdaemon.c` if [ $size != 13340 ] then echo Warning: utils/arepdaemon.c changed - should be 13340 bytes, not $size bytes fi chmod 644 utils/arepdaemon.c # ---------- file utils/autoreply.c ---------- if [ -f utils/autoreply.c ] then echo File 'utils/autoreply.c' already exists\! exit 1 fi echo extracting file utils/autoreply.c... cat << 'END-OF-FILE' > utils/autoreply.c /** autoreply.c **/ /** This is the front-end for the autoreply system, and performs two functions: it either adds the user to the list of people using the autoreply function (starting the daemon if no-one else) or removes a user from the list of people. Usage: autoreply filename autoreply "off" or autoreply [to find current status] (C) 1986, Dave Taylor **/ #include #include #include #include #define SLEN 80 /* a normal string */ #define NLEN 20 /* a short string */ #define READ_ACCESS 04 /* is file readable? */ #define mailhome "/usr/mail" /* where new mail lives */ #define tempdir "/tmp/arep" /* file prefix */ #define autoreply_file "/etc/autoreply.data" /* autoreply data file */ extern int errno; /* system error code */ char username[NLEN]; /* login name of user */ main(argc, argv) int argc; char *argv[]; { char filename[SLEN]; if (argc > 2) { printf("Usage: %s \tto start autoreply,\n", argv[0]); printf(" %s off\t\tto turn off autoreply\n", argv[0]); printf(" or %s \t\tto check current status\n", argv[0]); exit(1); } (void) cuserid(username); if (strcmp(argv[1], "off") == 0 || argc == 1) remove_user((argc == 1)); else { strcpy(filename, argv[1]); if (access(filename,READ_ACCESS) != 0) { printf("Error: Can't read file '%s'\n", filename); exit(1); } if (filename[0] != '/') /* prefix home directory */ sprintf(filename,"%s/%s", getenv("HOME"), argv[1]); add_user(filename); } exit(0); } remove_user(stat_only) int stat_only; { /** Remove the user from the list of currently active autoreply people. If 'stat_only' is set, then just list the name of the file being used to autoreply with, if any. **/ FILE *temp, *repfile; char tempfile[SLEN], user[SLEN], filename[SLEN]; int c, copied = 0, found = 0; long filesize, bytes(); if (! stat_only) { sprintf(tempfile, "%s.%06d", tempdir, getpid()); if ((temp = fopen(tempfile, "w")) == NULL) { printf("Error: couldn't open tempfile '%s'. Not removed\n", tempfile); exit(1); } } if ((repfile = fopen(autoreply_file, "r")) == NULL) { if (stat_only) { printf("You're not currently autoreplying to mail.\n"); exit(0); } printf("No-one is autoreplying to their mail!\n"); exit(0); } /** copy out of real replyfile... **/ while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) if (strcmp(user, username) != 0) { if (! stat_only) { copied++; fprintf(tempfile, "%s %s %ld\n", user, filename, filesize); } } else { if (stat_only) { printf("You're currently autoreplying to mail with the file %s\n", filename); exit(0); } found++; } fclose(temp); fclose(repfile); if (! found) { printf("You're not currently autoreplying to mail%s\n", stat_only? "." : "!"); if (! stat_only) unlink(tempfile); exit(! stat_only); } /** now copy tempfile back into replyfile **/ if (copied == 0) { /* removed the only person! */ unlink(autoreply_file); } else { /* save everyone else */ if ((temp = fopen(tempfile,"r")) == NULL) { printf("Error: couldn't reopen tempfile '%s'. Not removed.\n", tempfile); unlink(tempfile); exit(1); } if ((repfile = fopen(autoreply_file, "w")) == NULL) { printf( "Error: couldn't reopen autoreply file for writing! Not removed.\n"); unlink(tempfile); exit(1); } while ((c = getc(temp)) != EOF) putc(c, repfile); fclose(temp); fclose(repfile); } unlink(tempfile); if (found > 1) printf("Warning: your username appeared %d times!! Removed all\n", found); else printf("You've been removed from the autoreply table.\n"); } add_user(filename) char *filename; { /** add the user to the autoreply file... **/ FILE *repfile; char mailfile[SLEN]; long bytes(); if ((repfile = fopen(autoreply_file, "a")) == NULL) { printf("Error: couldn't open the autoreply file! Not added\n"); exit(1); } sprintf(mailfile,"%s/%s", mailhome, username); fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile)); fclose(repfile); printf("You've been added to the autoreply system.\n"); } long bytes(name) char *name; { /** return the number of bytes in the specified file. This is to check to see if new mail has arrived.... **/ int ok = 1; extern int errno; /* system error number! */ struct stat buffer; if (stat(name, &buffer) != 0) if (errno != 2) exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name)); else ok = 0; return(ok ? buffer.st_size : 0L); } END-OF-FILE size=`wc -c < utils/autoreply.c` if [ $size != 4840 ] then echo Warning: utils/autoreply.c changed - should be 4840 bytes, not $size bytes fi chmod 644 utils/autoreply.c echo done exit 0