rsalz@uunet.uu.net (Rich Salz) (04/13/89)
Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein) Posting-number: Volume 18, Issue 92 Archive-name: elm2.2/part13 #!/bin/sh # this is part 13 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/domains.c continued # CurArch=13 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file src/domains.c" sed 's/^X//' << 'SHAR_EOF' >> src/domains.c X X while (fgets(buffer, SLEN, domainfd) != NULL) { X if (buffer[0] == '#') /* skip comments */ X continue; X if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */ X matched++; /* Gotcha! Remember this momentous event! */ X break; X } X } X X if (! matched) X continue; /* Nothing. Not a sausage! Step through! */ X X /** We've matched the domain! **/ X X no_ret(buffer); X X (void) strtok(buffer, ","); /* skip the domain info */ X X strcpy(field1, strtok(NULL, ",")); /* fun */ X strcpy(field2, strtok(NULL, ",")); /* stuff */ X strcpy(field3, strtok(NULL, ",")); /* eh? */ X X path = (char *) NULL; X X /* now we merely need to figure out what permutation this is! X X Fields are null if they have only a blank in them or are null. X If fields 2 and 3 are null, use field 1 as the template. X --else-- X If field 3 is null and 2 is not, use field 2 as the template. X --else-- X Field 3 is the template. */ X X X if (strcmp(field3," ") == 0 || field3[0] == '\0'){ X if (strcmp(field2," ") == 0 || field2[0] == '\0') X template = (char *) field1; X else { X path = (char *) field1; X template = (char *) field2; X } X } X else { X path = (char *) field1; X template = (char *) field3; X } X dprint(1, (debugfile, X "-> %s\n-> %s\n-> %s\n", field1, field2, field3)); X dprint(1, (debugfile, X "Path-> %s\nTemplate-> %s\n", path, template)); X X if (strlen(path) > 0 && path[0] == '>') X path++; /* skip the '>' character, okay? */ X X j = 0; /* address is zero, right now, right?? */ X address[j] = '\0'; /* make sure string is too! */ X X for (i=0; i < strlen(template); i++) { X if (template[i] == '%') { X if (! in_percent) /* just hit a NEW percent! */ X in_percent = 1; X else { /* just another percent sign on the wall... */ X address[j++] = '%'; X address[j] = '\0'; /* ALWAYS NULL terminate */ X in_percent = 0; X } X } X else if (in_percent) { /* Hey! a real command string */ X in_percent = 0; X switch (template[i]) { X case USERNAME: strcat(address, name); break; X case RMTMNAME: strcat(address, machine); break; X case FULLNAME: strcat(address, machine); X strcat(address, domain); break; X case NPATH : X X if ((expanded = find_path_to(machine, FALSE)) == NULL) { X dprint(3, (debugfile, X "\nCouldn't expand system path '%s' (%s)\n\n", X machine, "domains")); X error1("Couldn't find a path to %s!", machine); X sleep(2); X return(NULL); /* failed!! */ X } X strcat(address, expanded); /* isn't this fun??? */ X X break; X X case PPATH : X X if ((expanded = find_path_to(path, FALSE)) == NULL) { X dprint(3, (debugfile, X "\nCouldn't expand system path '%s' (%s)\n\n", X path, "domains")); X error1("Couldn't find a path to %s!", path); X sleep(2); X return(NULL); /* failed!! */ X } X strcat(address, expanded); /* isn't this fun??? */ X X break; X X case OBSOLETE: /* fall through.. */ X default : dprint(1, (debugfile, X "\nError: Bad sequence in template file for domain '%s': %%%c\n\n", X domain, template[i])); X } X j = strlen(address); X } X else { X address[j++] = template[i]; X address[j] = '\0'; /* null terminate */ X } X } X X address[j] = '\0'; X X } while (strlen(address) < 1); X X return( (char *) address); X} SHAR_EOF echo "File src/domains.c is complete" chmod 0444 src/domains.c || echo "restore of src/domains.c fails" echo "x - extracting src/edit.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/edit.c && X Xstatic char rcsid[] = "@(#)$Id: edit.c,v 2.12 89/03/25 21:46:03 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.12 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: edit.c,v $ X * Revision 2.12 89/03/25 21:46:03 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This routine is for allowing the user to edit their current folder X as they wish. X X**/ X X#include "headers.h" X#include <errno.h> X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(); Xlong bytes(); Xunsigned long sleep(); X X#ifdef ALLOW_MAILBOX_EDITING X Xedit_mailbox() X{ X /** Allow the user to edit their folder, always resynchronizing X afterwards. Due to intense laziness on the part of the X programmer, this routine will invoke $EDITOR on the entire X file. The mailer will ALWAYS resync on the folder X even if nothing has changed since, not unreasonably, it's X hard to figure out what occurred in the edit session... X X Also note that if the user wants to edit their incoming X mailbox they'll actually be editing the tempfile that is X an exact copy. More on how we resync in that case later X in this code. X **/ X X FILE *real_folder, *temp_folder; X char edited_file[SLEN], buffer[SLEN]; X X if(folder_type == SPOOL) { X if(save_file_stats(cur_folder) != 0) { X error1("Problems saving permissions of folder %s!", cur_folder); X Raw(ON); X sleep(2); X return(0); X } X } X X PutLine0(LINES-1,0,"Invoking editor..."); X X strcpy(edited_file, (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder)); X sprintf(buffer, "%s %s", alternative_editor, edited_file); X X Raw(OFF); X X if (system_call(buffer, SH, TRUE) != 0) { X error1("Problems invoking editor %s!", alternative_editor); X Raw(ON); X sleep(2); X return(0); X } X X Raw(ON); X X if (folder_type == SPOOL) { /* uh oh... now the toughie... */ X X if (bytes(cur_folder) != mailfile_size) { X X /* SIGH. We've received mail since we invoked the editor X on the folder. We'll have to do some strange stuff to X remedy the problem... */ X X PutLine0(LINES, 0, "Warning: new mail received..."); X CleartoEOLN(); X X if ((temp_folder = fopen(edited_file, "a")) == NULL) { X dprint(1, (debugfile, X "Attempt to open \"%s\" to append failed in %s\n", X edited_file, "edit_mailbox")); X set_error("Couldn't reopen tempfile. Edit LOST!"); X return(1); X } X /** Now let's lock the folder up and stream the new stuff X into the temp file... **/ X X lock(OUTGOING); X if ((real_folder = fopen(cur_folder, "r")) == NULL) { X dprint(1, (debugfile, X "Attempt to open \"%s\" for reading new mail failed in %s\n", X cur_folder, "edit_mailbox")); X sprintf(buffer, "Couldn't open %s for reading! Edit LOST!", X cur_folder); X set_error(buffer); X unlock(); X return(1); X } X if (fseek(real_folder, mailfile_size, 0) == -1) { X dprint(1, (debugfile, X "Couldn't seek to end of cur_folder (offset %ld) (%s)\n", X mailfile_size, "edit_mailbox")); X set_error("Couldn't seek to end of folder. Edit LOST!"); X unlock(); X return(1); X } X X /** Now we can finally stream the new mail into the tempfile **/ X X while (fgets(buffer, SLEN, real_folder) != NULL) X fprintf(temp_folder, "%s", buffer); X X fclose(real_folder); X fclose(temp_folder); X X } else lock(OUTGOING); X X /* remove real mail_file and then X * link or copy the edited mailfile to real mail_file */ X X (void)unlink(cur_folder); X X if (link(edited_file, cur_folder) != 0) { X if (errno == EXDEV || errno == EEXIST) { X /* attempt to link across file systems */ X if (copy(edited_file, cur_folder) != 0) { X Write_to_screen( X "\n\rCouldn't copy %s to mailfile %s!\n\r", X 2, edited_file, cur_folder); X Write_to_screen( X "\n\rYou'll need to check out %s for your mail.\n\r", X 1, edited_file); X Write_to_screen("** %s - %s. **\n\r", 2, X error_name(errno), error_description(errno)); X unlock(); /* ciao!*/ X emergency_exit(); X } X } else { X Write_to_screen("\n\rCouldn't link %s to mailfile %s!\n\r",2, X edited_file, cur_folder); X Write_to_screen( X "\n\rYou'll need to check out %s for your mail.\n\r", X 1, edited_file); X Write_to_screen("** %s - %s. **\n\r", 2, X error_name(errno), error_description(errno)); X unlock(); /* ciao!*/ X emergency_exit(); X } X } X X /* restore file permissions before removing lock */ X X if(restore_file_stats(cur_folder) != 1) { X error1("Problems restoring permissions of folder %s!", cur_folder); X Raw(ON); X sleep(2); X } X X unlock(); X unlink(edited_file); /* remove the edited mailfile */ X error("Changes incorporated into new mail..."); X X } else X error("Resynchronizing with new version of folder..."); X X sleep(2); X ClearScreen(); X newmbox(cur_folder, FALSE); X showscreen(); X return(1); X} X X#endif SHAR_EOF chmod 0444 src/edit.c || echo "restore of src/edit.c fails" echo "x - extracting src/editmsg.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/editmsg.c && X Xstatic char rcsid[] = "@(#)$Id: editmsg.c,v 2.12 89/03/25 21:46:04 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.12 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: editmsg.c,v $ X * Revision 2.12 89/03/25 21:46:04 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This contains routines to do with starting up and using an editor (or two) X from within Elm. This stuff used to be in mailmsg2.c... X**/ X X#include "headers.h" X#include <errno.h> X#include <setjmp.h> X#include <signal.h> X#include <ctype.h> X X#ifdef BSD X#undef tolower X#endif X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(), *format_long(); Xunsigned long sleep(); X Xint Xedit_the_message(filename, already_has_text) Xchar *filename; Xint already_has_text; X{ X /** Invoke the users editor on the filename. Return when done. X If 'already has text' then we can't use the no-editor option X and must use 'alternative editor' (e.g. $EDITOR or default_editor) X instead... **/ X X char buffer[SLEN]; X register int stat, return_value = 0; X int old_raw; X X buffer[0] = '\0'; X X if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) { X if (already_has_text) X sprintf(buffer, "%s %s", alternative_editor, filename); X else X return(no_editor_edit_the_message(filename)); X } X X PutLine0(LINES, 0, "Invoking editor..."); fflush(stdout); X if (strlen(buffer) == 0) X sprintf(buffer,"%s %s", editor, filename); X X if( (old_raw = RawState()) == ON) X Raw(OFF); X X chown(filename, userid, groupid); /* file was owned by root! */ X X if (cursor_control) X transmit_functions(OFF); /* function keys are local */ X X if ((stat = system_call(buffer, SH, TRUE)) != 0) { X dprint(1,(debugfile, X "System call failed with stat %d (edit_the_message)\n", X stat)); X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X ClearLine(LINES-1); X error1("Can't invoke editor '%s' for composition.", editor); X sleep(2); X return_value = 1; X } X X if (cursor_control) X transmit_functions(ON); /* function keys are local */ X X if ( old_raw == ON) X Raw(ON); X X return(return_value); X} X Xextern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING], X expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING], X bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING], X subject[SLEN]; X Xint interrupts_while_editing; /* keep track 'o dis stuff */ Xjmp_buf edit_location; /* for getting back from interrupt */ X Xchar *strip_commas(); Xlong fsize(); X Xint Xno_editor_edit_the_message(filename) Xchar *filename; X{ X /** If the current editor is set to either "builtin" or "none", then X invoke this program instead. As it turns out, this and the X routine above have a pretty incestuous relationship (!)... X **/ X X FILE *edit_fd; X char buffer[SLEN], editor_name[SLEN], buf[SLEN]; X int edit_interrupt(); X int old_raw; X#ifdef VOIDSIG X void (*oldint)(), (*oldquit)(); X#else X int (*oldint)(), (*oldquit)(); X#endif X X if (( old_raw = RawState()) == ON) X Raw(OFF); X X if ((edit_fd = fopen(filename, "a")) == NULL) { X error2("Couldn't open %s for appending [%s].", filename, X error_name(errno)); X sleep (2); X dprint(1, (debugfile, X "Error encountered trying to open file %s;\n", filename)); X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X if ( old_raw == ON) X Raw(ON); X return(1); X } X X /** is there already text in this file? **/ X X if (fsize(edit_fd) > 0L) X printf( X "\nPlease continue message, ^D or '.' to end, %cp to list, %c? for help;\n\n", X escape_char, escape_char); X else X printf( X "\nPlease enter message, ^D or '.' to end, or %c? <RETURN> for help;\n\n", X escape_char); X X oldint = signal(SIGINT, edit_interrupt); X oldquit = signal(SIGQUIT, edit_interrupt); X X interrupts_while_editing = 0; X X if (setjmp(edit_location) != 0) { X if (interrupts_while_editing > 1) { X Raw(ON); X X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X X if (edit_fd != NULL) /* insurance... */ X fclose(edit_fd); X return(1); X } X goto more_input; /* read input again, please! */ X } X Xraw_input : Raw(ON); X Xmore_input: buffer[0] = '\0'; X X while (optionally_enter(buffer, -1,-1, FALSE, FALSE) == 0) { X X interrupts_while_editing = 0; /* reset to zero... */ X X if (strcmp(buffer, ".") == 0) X break; /* '.' is as good as a ^D to us dumb programs :-) */ X if (buffer[0] == escape_char) { X Raw(OFF); X switch (tolower(buffer[1])) { X case '?' : tilde_help(); X printf("(continue)\n"); goto raw_input; X X case TILDE_ESCAPE: move_left(buffer, 1); X Raw(ON); goto tilde_input; /*!!*/ X X case 't' : get_with_expansion("\nTo: ", to, expanded_to, buffer); X goto raw_input; X case 'b' : get_with_expansion("\nBcc: ",bcc,expanded_bcc, buffer); X goto raw_input; X case 'c' : get_with_expansion("\nCc: ", cc, expanded_cc, buffer); X goto raw_input; X case 's' : get_with_expansion("\nSubject: ", subject,NULL,buffer); X goto raw_input; X X case 'h' : get_with_expansion("\nTo: ", to, expanded_to, NULL); X get_with_expansion("Cc: ", cc, expanded_cc, NULL); X get_with_expansion("Bcc: ", bcc,expanded_bcc, NULL); X get_with_expansion("Subject: ", subject,NULL, NULL); X goto raw_input; X X case 'r' : read_in_file(edit_fd, (char *) buffer + 2, 1); X goto raw_input; X case 'e' : if (strlen(emacs_editor) > 0) X if (access(emacs_editor, ACCESS_EXISTS) == 0) { X strcpy(buffer, editor); X strcpy(editor, emacs_editor); X fclose(edit_fd); X (void) edit_the_message(filename,0); X strcpy(editor, buffer); X edit_fd = fopen(filename, "a"); X printf("(continue entering message, ^D or '.' to end)\n"); X goto raw_input; X } X else X printf( X "\n(Can't find Emacs on this system! continue)\n"); X else X printf( X "\n(Don't know where Emacs would be...continue)\n"); X goto raw_input; X X case 'v' : strcpy(buffer, editor); X strcpy(editor, default_editor); X fclose(edit_fd); X (void) edit_the_message(filename,0); X strcpy(editor, buffer); X edit_fd = fopen(filename, "a"); X printf("(continue entering message, ^D or '.' to end)\n"); X goto raw_input; X X case 'o' : printf("\nPlease enter the name of the editor : "); X editor_name[0] = '\0'; X optionally_enter(editor_name,-1,-1, FALSE, FALSE); X if (strlen(editor_name) > 0) { X strcpy(buffer, editor); X strcpy(editor, editor_name); X fclose(edit_fd); X (void) edit_the_message(filename,0); X strcpy(editor, buffer); X edit_fd = fopen(filename, "a"); X printf("(continue entering message, ^D or '.' to end)\n"); X goto raw_input; X } X printf("(continue)\n"); X goto raw_input; X X case '<' : putchar('\n'); X if (strlen(buffer) < 3) X (void) printf( X "(you need to use a specific command here. Continue...)\n"); X else { X sprintf(buf, " > %s.%d 2>&1", temp_edit, getpid()); X strcat(buffer, buf); X (void) system_call((char *) buffer+2, SH, TRUE); X sprintf(buffer, "~r %s.%d", temp_edit, getpid()); X read_in_file(edit_fd, (char *) buffer + 3, 0); X (void) unlink((char *) buffer+3); X } X goto raw_input; X X case '!' : putchar('\n'); X if (strlen(buffer) < 3) X (void) system_call(shell, USER_SHELL, TRUE); X else X (void) system_call((char *) buffer+2, X USER_SHELL, TRUE); X printf("(continue)\n"); X goto raw_input; X X case 'm' : /* same as 'f' but with leading prefix added */ X X case 'f' : /* this can be directly translated into a X 'readmsg' call with the same params! */ X putchar('\n'); X read_in_messages(edit_fd, (char *) buffer + 1); X goto raw_input; X X case 'p' : /* print out message so far. Soooo simple! */ X print_message_so_far(edit_fd, filename); X goto raw_input; X X default : printf( X "\n(don't know what %c%c is. Try %c? for help)\n", X escape_char, buffer[1], escape_char); X } X } X else { Xtilde_input: X fprintf(edit_fd, "%s\n", buffer); X printf("\r\n"); X } X buffer[0] = '\0'; X } X X printf("\n<end-of-message>\n\r\n\r"); X X if ( old_raw == ON) X Raw(ON); X X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X X if (edit_fd != NULL) /* insurance... */ X fclose(edit_fd); X X return(0); X} X Xtilde_help() X{ X /* a simple routine to print out what is available at this level */ X X int old_raw; X X if ( (old_raw = RawState()) == ON) X Raw(OFF); X X printf("\n(Available options at this point are;\n\n"); X printf("\t%c?\tPrint this help menu\n", escape_char); X if (escape_char == TILDE_ESCAPE) X printf("\t~~\tAdd line prefixed by a single '~' character\n"); X /* doesn't make sense otherwise... */ X X printf("\t%cb\tChange the addresses in the Blind-carbon-copy list\n", X escape_char); X X printf("\t%cc\tChange the addresses in the Carbon-copy list\n", X escape_char); X printf("\t%ce\tInvoke the Emacs editor on the message, if possible\n", X escape_char); X printf("\t%cf\tadd the specified list of messages, or current\n", X escape_char); X printf("\t%ch\tchange all available headers (to,cc,bcc,subject)\n", X escape_char); X printf("\t%cm\tsame as '%cf', but with the current 'prefix'\n", X escape_char, escape_char); X printf("\t%co\tInvoke a user specified editor on the message\n", X escape_char); X printf("\t%cp\tprint out message as typed in so far\n", escape_char); X printf("\t%cr\tRead in the specified file\n", escape_char); X printf("\t%cs\tChange the subject of the message\n", escape_char); X printf("\t%ct\tChange the addresses in the To list\n", X escape_char); X printf("\t%cv\tInvoke the Vi visual editor on the message\n\n", X escape_char); X printf( X "\t%c!\texecute a unix command (or give a shell if no command)\n", X escape_char); X printf( X "\t%c<\texecute a unix command adding the output to the message\n\n", X escape_char); X printf( X "\t. \tby itself on a line (or a control-D) ends the message\n\n"); X X if ( old_raw == ON) X Raw(ON); X} X Xread_in_file(fd, filename, show_user_filename) XFILE *fd; Xchar *filename; Xint show_user_filename; X{ X /** Open the specified file and stream it in to the already opened X file descriptor given to us. When we're done output the number X of lines we added, if any... **/ X X FILE *myfd; X char myfname[SLEN], buffer[SLEN]; X register int lines = 0; X X while (whitespace(filename[lines])) lines++; X X /** expand any shell variables, '~' or other notation... **/ X /* temp copy of filename to buffer since expand_env is destructive */ X strcpy(buffer, &filename[lines]); X expand_env(myfname, buffer); X X if (strlen(myfname) == 0) { X printf("\n(no filename specified for file read! Continue...)\n"); X return; X } X X if ((myfd = fopen(myfname,"r")) == NULL) { X printf("\n(Couldn't read file '%s'! Continue...)\n", X myfname); X return; X } X X lines = 0; X X while (fgets(buffer, SLEN, myfd) != NULL) { X if(buffer[strlen(buffer)-1] == '\n') lines++; X fputs(buffer, fd); X fflush(stdout); X } X X fclose(myfd); X X if (show_user_filename) X printf("\n(added %d line%s from file %s. Please continue...)\n", X lines, plural(lines), myfname); X else X printf("\n(added %d line%s to message. Please continue...)\n", X lines, plural(lines)); X X return; X} X Xprint_message_so_far(edit_fd, filename) XFILE *edit_fd; Xchar *filename; X{ X /** This prints out the message typed in so far. We accomplish X this in a cheap manner - close the file, reopen it for reading, X stream it to the screen, then close the file, and reopen it X for appending. Simple, but effective! X X A nice enhancement would be for this to -> page <- the message X if it's sufficiently long. Too much work for now, though. X **/ X X char buffer[SLEN]; X X fclose(edit_fd); X X if ((edit_fd = fopen(filename, "r")) == NULL) { X printf("\nMayday! Mayday! Mayday!\n"); X printf("\nPanic: Can't open file for reading! Bail!\n"); X emergency_exit(); X } X X printf("\nTo: %s\n", format_long(to, 4)); X printf("Cc: %s\n", format_long(cc, 4)); X printf("Bcc: %s\n", format_long(bcc, 5)); X printf("Subject: %s\n\n", subject); X X while (fgets(buffer, SLEN, edit_fd) != NULL) X printf("%s", buffer); X X fclose(edit_fd); X X if ((edit_fd = fopen(filename, "a")) == NULL) { X printf("Mayday! Mayday! Abandon Ship! Aiiieeeeee\n"); X printf("\nPanic: Can't reopen file for appending!\n"); X emergency_exit(); X } X X printf("\n(continue entering message, please)\n"); X} X Xread_in_messages(fd, buffer) XFILE *fd; Xchar *buffer; X{ X /** Read the specified messages into the open file. If the X first character of "buffer" is 'm' then prefix it, other- X wise just stream it in straight...Since we're using the X pipe to 'readmsg' we can also allow the user to specify X patterns and such too... X **/ X X FILE *myfd, *popen(); X char local_buffer[SLEN]; X register int lines = 0, add_prefix=0, mindex; X X if (add_prefix = (tolower(buffer[0]) == 'm')) X buffer++; X X if (! isdigit(buffer[0])) X sprintf(local_buffer, "%s %s", readmsg, buffer); X else { X mindex = atoi(buffer); /* map requested # to real # */ X sprintf(local_buffer, "%s %d", readmsg, X headers[mindex-1]->index_number); X } X X if ((myfd = popen(local_buffer, "r")) == NULL) { X printf("(can't get to 'readmsg' command. Sorry...)\n"); X return; X } X X dprint(5, (debugfile, "** readmsg call: \"%s\" **\n", local_buffer)); X X while (fgets(local_buffer, SLEN, myfd) != NULL) { X if(local_buffer[strlen(local_buffer)-1] == '\n') lines++; X if (add_prefix) X fprintf(fd, "%s%s", prefixchars, local_buffer); X else X fputs(local_buffer, fd); X } X X pclose(myfd); X X if (lines == 0) X printf("(Couldn't add the requested message. Continue)\n"); X else X printf("(added %d line%s to message... Please continue)\n", X lines, plural(lines)); X X return; X} X Xget_with_expansion(prompt, buffer, expanded_buffer, sourcebuf) Xchar *prompt, *buffer, *expanded_buffer, *sourcebuf; X{ X /** This is used to prompt for a new value of the specified field. X If expanded_buffer == NULL then we won't bother trying to expand X this puppy out! (sourcebuf could be an initial addition) X **/ X X char mybuffer[VERY_LONG_STRING]; X int old_raw; X X if ( (old_raw = RawState()) == OFF) X Raw(ON); X X printf(prompt); fflush(stdout); /* output! */ X X if (sourcebuf != NULL) { X while (!whitespace(*sourcebuf) && *sourcebuf != '\0') X sourcebuf++; X if (*sourcebuf != '\0') { X while (whitespace(*sourcebuf)) X sourcebuf++; X if (strlen(sourcebuf) > 0) { X strcat(buffer, " "); X strcat(buffer, sourcebuf); X } X } X } X X strcpy(mybuffer, buffer); X X optionally_enter(buffer, -1, -1, TRUE, FALSE); /* already data! */ X X if ( old_raw == OFF) X Raw(OFF); X X putchar('\n'); X X /** if it's changed and we're supposed to expand addresses... **/ X X if (strcmp(buffer, mybuffer) != 0 && expanded_buffer != NULL) X if (build_address(strip_commas(buffer), expanded_buffer)) X printf("%s%s\n\r", prompt, expanded_buffer); X X return; X} X Xedit_interrupt() X{ X /** This routine is called when the user hits an interrupt key X while in the builtin editor...it increments the number of X times an interrupt is hit and returns it. X **/ X X signal(SIGINT, edit_interrupt); X signal(SIGQUIT, edit_interrupt); X X if (interrupts_while_editing++ == 0) X printf("(Interrupt. One more to cancel this letter...)\n\r"); X X longjmp(edit_location, 1); /* get back */ X} SHAR_EOF chmod 0444 src/editmsg.c || echo "restore of src/editmsg.c fails" echo "x - extracting src/elm.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/elm.c && X Xstatic char rcsid[] = "@(#)$Id: elm.c,v 2.33 89/03/25 21:46:10 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.33 $ $State: Exp $ X * X * This file and all associated files and documentation: X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: elm.c,v $ X * Revision 2.33 89/03/25 21:46:10 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/* Main program of the ELM mail system! X*/ X X#include "elm.h" X X#ifdef BSD X#undef toupper X#undef tolower X#endif X Xlong bytes(); Xchar *format_long(), *parse_arguments(); X Xmain(argc, argv) Xint argc; Xchar *argv[]; X { X int ch; X char address[SLEN], to_whom[SLEN], buffer[SLEN], *req_mfile; X int key_offset; /** Position offset within keyboard string **/ X int redraw, /** do we need to rewrite the entire screen? **/ X nuhead, /** or perhaps just the headers section... **/ X nucurr, /** or just the current message pointer... **/ X nufoot; /** clear lines 16 thru bottom and new menu **/ X int i,j; /** Random counting variables (etc) **/ X int pageon, /** for when we receive new mail... **/ X last_in_folder; /** for when we receive new mail too... **/ X long num; /** another variable for fun.. **/ X extern char version_buff[]; X X req_mfile = parse_arguments(argc, argv, to_whom); X X initialize(req_mfile); X X if (mail_only) { X dprint(3, (debugfile, "Mail-only: mailing to\n-> \"%s\"\n", X format_long(to_whom, 3))); X if(!batch_only) { X sprintf(buffer, "Send only mode [ELM %s]", version_buff); X Centerline(1, buffer); X } X (void) sendmsg(to_whom, "", batch_subject, TRUE, X (batch_only ? NO : allow_forms), FALSE); X leave(0); X } else if (check_only) { X dprint(3, (debugfile, "Check-only: checking \n-> \"%s\"\n", X format_long(to_whom, 3))); X (void) build_address(strip_commas(to_whom), buffer); X printf("Expands to: %s", X format_long(buffer, strlen("Expands to: "))); X leave(0); X } X X ScreenSize(&LINES, &COLUMNS); X X showscreen(); X X while (1) { X redraw = 0; X nuhead = 0; X nufoot = 0; X nucurr = 0; X if ((num = bytes(cur_folder)) != mailfile_size) { X dprint(2, (debugfile, "Just received %d bytes more mail (elm)\n", X num - mailfile_size)); X error("New mail has arrived! Hang on..."); X fflush(stdin); /* just to be sure... */ X last_in_folder = message_count; X pageon = header_page; X newmbox(cur_folder, TRUE); /* last won't be touched! */ X clear_error(); X header_page = pageon; X X if (on_page(current)) /* do we REALLY have to rewrite? */ X showscreen(); X else { X update_title(); X ClearLine(LINES-1); /* remove reading message... */ X error2("%d new message%s received.", X message_count - last_in_folder, X plural(message_count - last_in_folder)); X } X /* mailfile_size = num; */ X if (cursor_control) X transmit_functions(ON); /* insurance */ X } X X prompt("Command: "); X X CleartoEOLN(); X ch = GetPrompt(); X CleartoEOS(); X#ifdef DEBUG X if (! movement_command(ch)) X dprint(4, (debugfile, "\nCommand: %c [%d]\n\n", ch, ch)); X#endif X X set_error(""); /* clear error buffer */ X X MoveCursor(LINES-3,strlen("Command: ")); X X switch (ch) { X X case '?' : if (help(FALSE)) X redraw++; X else X nufoot++; X break; X X case '$' : PutLine0(LINES-3, strlen("Command: "), X "Resynchronize folder"); X redraw = resync(); X break; X Xnext_page: X case '+' : /* move to next page if we're not on the last */ X if((selected && X ((header_page+1)*headers_per_page < selected)) X ||(!selected && X ((header_page+1)*headers_per_page<message_count))){ X X header_page++; X nuhead++; X X if(move_when_paged) { X /* move to first message of new page */ X if(selected) X current = visible_to_index( X header_page * headers_per_page + 1) + 1; X else X current = header_page * headers_per_page + 1; X } X } else error("Already on last page."); X break; X Xprev_page: X case '-' : /* move to prev page if we're not on the first */ X if(header_page > 0) { X header_page--; X nuhead++; X X if(move_when_paged) { X /* move to first message of new page */ X if(selected) X current = visible_to_index( X header_page * headers_per_page + 1) + 1; X else X current = header_page * headers_per_page + 1; X } X } else error("Already on first page."); X break; X Xfirst_msg: X case '=' : if (selected) X current = visible_to_index(1)+1; X else X current = 1; X if (get_page(current)) X nuhead++; X else X nucurr++; break; X Xlast_msg: X case '*' : if (selected) X current = (visible_to_index(selected)+1); X else X current = message_count; X if (get_page(current)) X nuhead++; X else X nucurr++; break; X X case '|' : Writechar('|'); X softkeys_off(); X redraw = do_pipe(); X softkeys_on(); break; X X case '!' : Writechar('!'); X softkeys_off(); X redraw = subshell(); X softkeys_on(); break; X X case '%' : if (current > 0) { X get_return(address, current-1); X clear_error(); X PutLine1(LINES,(COLUMNS-strlen(address))/2, X "%.78s", address); X } else { X error("No mail to get return address of!"); X fflush(stdin); X } X break; X X case '/' : if (pattern_match()) { X if (get_page(current)) X nuhead++; X else X nucurr++; X } X else { X error("pattern not found!"); X fflush(stdin); X } X break; X X case '<' : /* scan current message for calendar information */ X#ifdef ENABLE_CALENDAR X PutLine0(LINES-3, strlen("Command: "), X "Scan message for calendar entries..."); X scan_calendar(); X#else X error("Sorry. Calendar function disabled."); X fflush(stdin); X#endif X break; X X case 'a' : if(alias()) redraw++; X else nufoot++; X define_softkeys(MAIN); break; X X case 'b' : PutLine0(LINES-3, strlen("Command: "), X "Bounce message"); X fflush(stdout); X if (message_count < 1) { X error("No mail to bounce!"); X fflush(stdin); X } X else X nufoot = remail(); X break; X X case 'c' : PutLine0(LINES-3, strlen("Command: "), X "Change folder"); X define_softkeys(CHANGE); X redraw = change_file(); X define_softkeys(MAIN); X break; X X case ctrl('D') : X case '^' : X case 'd' : if (message_count < 1) { X error("No mail to delete!"); X fflush(stdin); X } X else { X if(ch == ctrl('D')) { X X /* if current message did not become deleted, X * don't to move to the next undeleted msg. */ X if(!meta_match(DELETED)) break; X X } else X delete_msg((ch == 'd'), TRUE); X X if (resolve_mode) /* move after mail resolved */ X if((i=next_message(current-1, TRUE)) != -1) { X current = i+1; X if (get_page(current)) X nuhead++; X else X nucurr++; X } X } X break; X X X#ifdef ALLOW_MAILBOX_EDITING X case 'e' : PutLine0(LINES-3,strlen("Command: "),"Edit folder"); X if (current > 0) { X edit_mailbox(); X if (cursor_control) X transmit_functions(ON); /* insurance */ X } X else { X error("Folder is empty!"); X fflush(stdin); X } X break; X#else X case 'e' : error( X "Folder editing isn't configured in this version of ELM."); X fflush(stdin); X break; X#endif X X case 'f' : PutLine0(LINES-3, strlen("Command: "), "Forward"); X define_softkeys(YESNO); X if (current > 0) { X if(forward()) redraw++; X else nufoot++; X } else { X error("No mail to forward!"); X fflush(stdin); X } X define_softkeys(MAIN); X break; X X case 'g' : PutLine0(LINES-3,strlen("Command: "), "Group reply"); X fflush(stdout); X if (current > 0) { X if (headers[current-1]->status & FORM_LETTER) { X error("Can't group reply to a Form!!"); X fflush(stdin); X } X else { X define_softkeys(YESNO); X redraw = reply_to_everyone(); X define_softkeys(MAIN); X } X } X else { X error("No mail to reply to!"); X fflush(stdin); X } X break; X X case 'h' : if (filter) X PutLine0(LINES-3, strlen("Command: "), X "Message with headers..."); X else X PutLine0(LINES-3, strlen("Command: "),"Display message"); X if(current > 0) { X fflush(stdout); X j = filter; X filter = FALSE; X i = show_msg(current); X while (i) X i = process_showmsg_cmd(i); X filter = j; X redraw++; X (void)get_page(current); X } else error("No mail to read!"); X break; X X case 'J' : if(current > 0) { X if((i=next_message(current-1, FALSE)) != -1) { X current = i+1; X if (get_page(current)) X nuhead++; X else X nucurr++; X } else error("No more messages below."); X } else error("No mail in folder!"); X break; X Xnext_undel_msg: X case 'j' : if(current > 0) { X if((i=next_message(current-1, TRUE)) != -1) { X current = i+1; X if (get_page(current)) X nuhead++; X else X nucurr++; X } else error("No more undeleted messages below."); X } else error("No mail in folder!"); X break; X X case 'K' : if(current > 0) { X if((i=prev_message(current-1, FALSE)) != -1) { X current = i+1; X if (get_page(current)) X nuhead++; X else X nucurr++; X } else error("No more messages above."); X } else error("No mail in folder!"); X break; X Xprev_undel_msg: X case 'k' : if(current > 0) { X if((i=prev_message(current-1, TRUE)) != -1) { X current = i+1; X if (get_page(current)) X nuhead++; X else X nucurr++; X } else error("No more undeleted messages above."); X } else error("No mail in folder!"); X break; X X case 'l' : PutLine0(LINES-3, strlen("Command: "), X "Limit displayed messages by..."); X clear_error(); X if (limit() != 0) { X get_page(current); X redraw++; X } else { X nufoot++; X } X break; X X case 'm' : PutLine0(LINES-3, strlen("Command: "), "Mail"); X redraw = sendmsg("", "", "", TRUE,allow_forms,FALSE); X break; X X case ' ' : X case ctrl('J'): X case ctrl('M'):PutLine0(LINES-3, strlen("Command: "), X "Display message"); X fflush(stdout); X if(current > 0 ) { X define_softkeys(READ); X X i = show_msg(current); X while (i) X i = process_showmsg_cmd(i); X redraw++; X (void)get_page(current); X }else error ("No mail to read!"); X break; X X case 'n' : PutLine0(LINES-3,strlen("Command: "),"Next Message"); X fflush(stdout); X define_softkeys(READ); X X if(current > 0 ) { X define_softkeys(READ); X X i = show_msg(current); X while (i) X i = process_showmsg_cmd(i); X redraw++; X if (++current > message_count) X current = message_count; X (void)get_page(current); X }else error ("No mail to read!"); X break; X X case 'o' : PutLine0(LINES-3, strlen("Command: "), "Options"); X if((i=options()) > 0) X get_page(current); X else if(i < 0) X leave(); X redraw++; /* always fix da screen... */ X break; X X case 'p' : PutLine0(LINES-3, strlen("Command: "), "Print mail"); X fflush(stdout); X if (message_count < 1) { X error("No mail to print!"); X fflush(stdin); X } X else X print_msg(); X break; X X case 'q' : PutLine0(LINES-3, strlen("Command: "), "Quit"); X X if (mailfile_size != bytes(cur_folder)) { X error("New Mail! Quit cancelled..."); X fflush(stdin); X if (folder_type == SPOOL) unlock(); X } X else X quit(TRUE); X X break; X X case 'Q' : PutLine0(LINES-3, strlen("Command: "), "Quick quit"); X X if (mailfile_size != bytes(cur_folder)) { X error("New Mail! Quick Quit cancelled..."); X if (folder_type == SPOOL) unlock(); X } X else X quit(FALSE); X X break; X X case 'r' : PutLine0(LINES-3, strlen("Command: "), X "Reply to message"); X if (current > 0) X redraw = reply(); X else { X error("No mail to reply to!"); X fflush(stdin); X } X softkeys_on(); X break; X X case '>' : /** backwards compatibility **/ X X case 'C' : X case 's' : if (message_count < 1) { X error1("No mail to %s!", X ch != 'C' ? "save" : "copy"); X fflush(stdin); X } X else { X PutLine1(LINES-3, strlen("Command: "), X "%s to folder", X ch != 'C' ? "Save" : "Copy"); X PutLine0(LINES-3,COLUMNS-40, X "(Use '?' to list your folders)"); X if (save(&redraw, FALSE, (ch != 'C')) X && resolve_mode && ch != 'C') { X X i = current; X while (current <= message_count && X (headers[current-1]->status & DELETED)) X current++; X X if (current > message_count) X current = i; /* reset - overshot! */ X X if (get_page(current)) X nuhead++; X else X nucurr++; X } X } X ClearLine(LINES-2); X break; X X case ctrl('T') : X case 't' : if (message_count < 1) { X error("No mail to tag!"); X fflush(stdin); X } X else if (ch == 't') X tag_message(TRUE); X else X meta_match(TAGGED); X break; X X case 'u' : if (message_count < 1) { X error("No mail to mark as undeleted!"); X fflush(stdin); X } X else { X undelete_msg(TRUE); X if (resolve_mode) /* move after mail resolved */ X if((i=next_message(current-1, FALSE)) != -1) { X current = i+1; X if (get_page(current)) X nuhead++; X else X nucurr++; X } X/************************************************************************* X ** What we've done here is to special case the "U)ndelete" command to X ** ignore whether the next message is marked for deletion or not. The X ** reason is obvious upon usage - it's a real pain to undelete a series X ** of messages without this quirk. Thanks to Jim Davis @ HPLabs for X ** suggesting this more intuitive behaviour. X ** X ** The old way, for those people that might want to see what the previous X ** behaviour was to call next_message with TRUE, not FALSE. X**************************************************************************/ X } X break; X X case ctrl('U') : if (message_count < 1) { X error("No mail to undelete!"); X fflush(stdin); X } X else X meta_match(UNDELETE); X break; X X case ctrl('Q') : X case '\177' : X case 'x' : PutLine0(LINES-3, strlen("Command: "), "Exit"); X fflush(stdout); leave(); X X case ctrl('L') : redraw++; break; X X case EOF : leave(); /* Read failed, control tty died? */ X break; X X case '@' : debug_screen(); redraw++; break; X X case '#' : if (message_count) { X debug_message(); X redraw++; X } X else { X error("No mail to check."); X fflush(stdin); X } X break; X X case NO_OP_COMMAND : break; /* noop for timeout loop */ X X case ESCAPE : if (cursor_control) { X key_offset = 1; X ch = ReadCh(); X X if ( ch == '[' || ch == 'O') X { X ch = ReadCh(); X key_offset++; X } X X if(ch == up[key_offset]) goto prev_undel_msg; X else if(ch == down[key_offset]) goto next_undel_msg; X else if(ch == right[key_offset]) goto next_page; X else if(ch == left[key_offset]) goto prev_page; X else if (hp_terminal) { X switch (ch) { X case 'U': goto next_page; X case 'V': goto prev_page; X case 'h': X case 'H': goto first_msg; X case 'F': goto last_msg; X case 'A': X case 'D': X case 'i': goto next_undel_msg; X case 'B': X case 'I': X case 'C': goto prev_undel_msg; X default: PutLine2(LINES-3, strlen("Command: "), X "%c%c", ESCAPE, ch); X } X } else /* false hit - output */ X PutLine2(LINES-3, strlen("Command: "), X "%c%c", ESCAPE, ch); X } X X /* else fall into the default error message! */ X X default : if (ch > '0' && ch <= '9') { X PutLine0(LINES-3, strlen("Command: "), X "New Current Message"); X i = read_number(ch); X X if( i > message_count) X error("Not that many messages."); X else if(selected X && isoff(headers[i-1]->status, VISIBLE)) X error("Message not in limited display."); X else { X current = i; X if (get_page(current)) X nuhead++; X else X nucurr++; X } X } X else { X error("Unknown command. Use '?' for help."); X fflush(stdin); X } X } X X if (redraw) X showscreen(); X X if ((current < 1) || (selected && compute_visible(current) < 1)) { X if (message_count > 0) { X /* We are out of range! Get to first message! */ X if (selected) X current = compute_visible(1); X else X current = 1; X } X else X current = 0; X } X else if ((current > message_count) X || (selected && compute_visible(current) > selected)) { X if (message_count > 0) { X /* We are out of range! Get to last (visible) message! */ X if (selected) X current = visible_to_index(selected)+1; X else X current = message_count; X } X else X current = 0; X } X X if (nuhead) X show_headers(); X else if (nucurr) X show_current(); X else if (nufoot) { X if (mini_menu) { X MoveCursor(LINES-7, 0); X CleartoEOS(); X show_menu(); X } X else { X MoveCursor(LINES-4, 0); X CleartoEOS(); X } X show_last_error(); /* for those operations that have to X * clear the footer except for a message. X */ X } X X } /* the BIG while loop! */ X} X Xdebug_screen() X{ X /**** spit out all the current variable settings and the table X entries for the current 'n' items displayed. ****/ X X register int i, j; X char buffer[SLEN]; X X ClearScreen(); X Raw(OFF); X X PutLine2(0,0,"Current message number = %d\t\t%d message(s) total\n", X current, message_count); X PutLine2(2,0,"Header_page = %d \t\t%d possible page(s)\n", X header_page, (int) (message_count / headers_per_page) + 1); X X PutLine1(4,0,"\nCurrent mailfile is %s.\n\n", cur_folder); X X i = header_page*headers_per_page; /* starting header */ X X if ((j = i + (headers_per_page-1)) >= message_count) X j = message_count-1; X X Write_to_screen( X"Num From Subject Lines Offset\n\r\n\r",0); X X while (i <= j) { X sprintf(buffer, X "%3d %-16.16s %-40.40s %4d %d\n\r", X i+1, X headers[i]->from, X headers[i]->subject, X headers[i]->lines, X headers[i]->offset); X Write_to_screen(buffer, 0); X i++; X } X X Raw(ON); X X PutLine0(LINES,0,"Press any key to return."); X (void) ReadCh(); X} X X Xdebug_message() X{ X /**** Spit out the current message record. Include EVERYTHING X in the record structure. **/ X X char buffer[SLEN]; X register struct header_rec *current_header = headers[current-1]; X X ClearScreen(); X Raw(OFF); X X Write_to_screen("\t\t\t----- Message %d -----\n\r\n\r\n\r\n\r", 1, SHAR_EOF echo "End of part 13" echo "File src/elm.c is continued in part 14" echo "14" > s2_seq_.tmp exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.