示例#1
0
文件: alias.c 项目: wfp5p/elm
void alias(void)
{
/*
 *	Work with alias commands...
 */

	char name[NLEN], *address, buffer[SLEN];
	char *commap;
	static int  newaliases = 0;
	int  ch, i;
	int nutitle = 0;
	int too_long;

/*
 *	We're going to try to match the way elm does it at
 * 	he main menu.  I probably won't be able to use any
 *	main menu routines, but I will "borrow" from them. RLH
 */

	alias_main_state();		/* Save globals for return to main menu */

	open_alias_files(FALSE);	/* First, read the alias files. RLH */

	alias_screen(newaliases);

	while (1) {

	  redraw = 0;
	  nucurr = 0;
	  nufoot = 0;

	  prompt(nls_Prompt);
	  CleartoEOLN();
	  ch = GetKey(0);

	  MoveCursor(LINES-3,strlen(nls_Prompt)); CleartoEOS();

	  dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));

	  switch (ch) {
	    case '?': redraw += alias_help();			break;

#ifdef ALLOW_SUBSHELL
	    case '!' : WriteChar('!');
	      alias_main_state(); /** reload index screen vars **/
	      redraw += subshell();
	      alias_main_state(); /** reload alias screen vars **/
	      break;
#endif /* ALLOW_SUBSHELL */

	    case '$': PutLine(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesResync,
					"Resynchronize aliases..."));
	           /*
	            * Process deletions and then see if we need to
	            * re-run the "newalias" routine.
	            */
		      if (resync_aliases(newaliases)) {
		        install_aliases();
	                newaliases = 0;
		        redraw++;
		      }
		      break;

	    case 'a': PutLine(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesAddCurrent,
					"Add address from current message..."));
		      clear_error();
		      if (add_current_alias()) {
		          newaliases++;
		          nutitle++;
		      }
		      break;

	    case 'c':
	              if (curr_alias > 0) {
			  PutLine(-1, -1, catgets(elm_msg_cat,
	                              AliasesSet, AliasesReplaceCurrent,
	                              "Replace current alias in database..."));
		          clear_error();
		          if (add_alias(TRUE, curr_alias-1)) {
		              newaliases++;
		              nutitle++;
		          }
	              }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToReplace,
				  "Warning: no aliases to replace!"));
	              }
		      break;

	    case 'e': PutLine(LINES-3, strlen(nls_Prompt),
	                  catgets(elm_msg_cat, AliasesSet, AliasesEdit,
	                      "Edit %s..."), ALIAS_TEXT);
	           /*
	            * Process aliases.text for deletions, etc.  You
	            * have to do this *before* checking current because
	            * all aliases could be marked for deletion.
	            */
	              (void) resync_aliases(newaliases);
	              if (edit_aliases_text()) {
	                  newaliases = 0;
	              }
		      redraw++;
		      break;

	    case 'm':
	              if (curr_alias > 0) {
			  PutLine(-1, -1, catgets(elm_msg_cat,
					  AliasesSet, AliasesMail, "Mail..."));
	                  redraw += a_sendmsg();
	              }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToMail,
				  "Warning: no aliases to send mail to!"));
	              }
		      break;

	    case 'n': PutLine(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesAddNew,
					"Add a new alias to database..."));
		      clear_error();
		      if (add_alias(FALSE, -1)) {
		          newaliases++;
		          nutitle++;
		      }
		      break;

	    case 'q':
	    case 'Q':
	    case 'i':
	    case 'I':
	    case 'r':
	    case 'R': PutLine(-1, -1, catgets(elm_msg_cat,
	    				AliasesSet, AliasesAddReturn,
					"Return to main menu..."));
	           /*
	            * leaving the alias system.  Must check for
	            * pending deletes, etc.  prompt is set to FALSE
	            * on uppercase letters so that deletions are
	            * NOT queried.
	            */
	              if (delete_aliases(newaliases, islower(ch))) {
	                install_aliases();
	                newaliases = 0;
	              }
		      clear_error();
		      alias_main_state();		/* Done with aliases. */
		      return;

	    case RETURN:
	    case LINE_FEED:
	    case ' ':
	    case 'v':
		      if (newaliases) {		/* Need this ?? */
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNotInstalled,
				  "Warning: new aliases not installed yet!"));
	              }

	              if (curr_alias > 0) {
	                  if (aliases[curr_alias-1]->type & GROUP) {
	                      PutLine(LINES-1, 0, catgets(elm_msg_cat,
	                              AliasesSet, AliasesGroupAlias,
				      "Group alias: %-60.60s"),
	                          aliases[curr_alias-1]->address);
		          }
		          else {
	                      PutLine(LINES-1, 0, catgets(elm_msg_cat,
	                              AliasesSet, AliasesAliasedAddress,
				      "Aliased address: %-60.60s"),
	                          aliases[curr_alias-1]->address);
		          }
		      }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToView,
				  "Warning: no aliases to view!"));
		      }
		      break;

	    case 'x':
	    case 'X': PutLine(-1, -1, catgets(elm_msg_cat,
	    				AliasesSet, AliasesAddReturn,
					"Return to main menu..."));
	              exit_alias();
		      clear_error();
		      alias_main_state();		/* Done with aliases. */
		      return;

	    case 'f':
	    case 'F':
	              if (curr_alias > 0) {
		          clear_error();
		          strcpy(name, aliases[curr_alias-1]->alias);
		          if (ch == 'F') {
		              strcpy(buffer, catgets(elm_msg_cat,
	                              AliasesSet, AliasesFullyExpanded,
				      "Fully expand alias: "));
		              PutLine(LINES-2, 0, buffer);
			      if (enter_string(name, sizeof(name), -1, -1,
					  ESTR_REPLACE) < 0 || name[0] == '\0')
				break;
		          }
	                  too_long = FALSE;
		          address = get_alias_address(name, TRUE, &too_long);
		          if (address != NULL) {
		              while (TRUE) {
	                          ClearScreen();
			          PutLine(2,0, catgets(elm_msg_cat,
	                                  AliasesSet, AliasesAliasedFull,
					  "Aliased address for:\t%s\n\r"),
	                              name);
		                  i = 4;
		                  while (i < LINES-2) {
		                      if ((commap = strchr(address, (int)','))
	                                          == NULL) {
		                          PutLine(i, 4, address);
		                          break;
		                      }
		                      *commap = '\0';
		                      PutLine(i++, 4, address);
		                      address = commap+2;
		                  }
	                          PutLine(LINES-1, 0, catgets(elm_msg_cat,
	                                  AliasesSet, AliasesPressReturn,
					  "Press <return> to continue."));
			          (void) ReadCh();
		                  if (commap == NULL) {
			              redraw++;
		                      break;
		                  }
		              }
		          }
	                  else if (! too_long) {
			      show_error(catgets(elm_msg_cat,
	                              AliasesSet, AliasesNotFound,
				      "Not found."));
		          }
		      }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToView,
				  "Warning: no aliases to view!"));
		      }
		      break;

	  case KEY_REDRAW:
		      redraw = 1;
		      break;

	 /*
	  * None of the menu specific commands were chosen, therefore
	  * it must be a "motion" command (or an error).
	  */
	    default	: motion(ch);

	  }

	  if (redraw) {			/* Redraw screen if necessary */
	      alias_screen(newaliases);
	      nutitle = 0;
	  }

	  if (nutitle) {		/* Redraw title if necessary */
	      alias_title(newaliases);
	      nutitle = 0;
	  }

	  check_range();

	  if (nucurr == NEW_PAGE)
	    show_headers();
	  else if (nucurr == SAME_PAGE)
	    show_current();
	  else if (nufoot) {
	    if (mini_menu) {
	      MoveCursor(LINES-7, 0);
              CleartoEOS();
	      show_alias_menu();
	    }
	    else {
	      MoveCursor(LINES-4, 0);
	      CleartoEOS();
	    }
	    show_last_error();	/* for those operations that have to
				 * clear the footer except for a message.
				 */
	  }
	}			/* BIG while loop... */
}
示例#2
0
文件: alias.c 项目: wfp5p/elm
static int alias_help(void)
{
/*
 *	Help section for the alias menu...
 *
 *	Return non-0 if main part of screen overwritten, else 0
 */

	int  ch;
	int  redraw=0;
	char *alias_prompt;


	if (mini_menu)
		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesShortKey,
			"Key: ");
	else
		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesLongKey,
			"Key you want help for: ");

	MoveCursor(LINES-3, 0);
	CleartoEOS();
	if (mini_menu) {
	  CenterLine(LINES-3, catgets(elm_msg_cat, AliasesSet, AliasesKeyMenu,
 "Press the key you want help for, '?' for a key list, or '.' to exit help"));
	}

	lower_prompt(alias_prompt);

	while ((ch = ReadCh()) != '.') {
	  switch(ch) {
	    case '?' : display_helpfile("alias");
		       redraw++;
		       return(redraw);

	    case '$': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpDollar,
"$ = Force resynchronization of aliases, processing additions and deletions."));
		      break;

	    case '/': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpSlash,
			"/ = Search for specified name or alias in list."));
		      break;

	    case RETURN:
	    case LINE_FEED:
	    case ' ':
	    case 'v': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpv,
	    "v = View the address for the currently selected alias."));
		      break;

	    case 'a': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpa,
	    "a = Add (return) address of current message to alias database."));
		      break;

	    case 'c': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpc,
"c = Change current user alias, modifying alias database at next resync."));
		      break;

	    case 'd': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpd,
	    "d = Mark the current alias for deletion from alias database."));
		      break;

	    case ctrl('D'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlD,
	    "^D = Mark for deletion user aliases matching specified pattern."));
		      break;

	    case 'e': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpe,
	    "e = Edit the alias text file directly (will run newalias)."));
		      break;

	    case 'f': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpf,
		"f = Display fully expanded address of current alias."));
		      break;

	    case 'l': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpl,
	    "l = Limit displayed aliases on the specified criteria."));
		      break;

	    case ctrl('L'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlL,
		      "^L = Rewrite the screen."));
	    	      break;

	    case 'm': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpm,
	    "m = Send mail to the current or tagged aliases."));
		      break;

	    case 'n': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpn,
"n = Add a new user alias, adding to alias database at next resync."));
		      break;

	    case 'r':
	    case 'q':
	    case 'i': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpi,
		      "r,q,i = Return from alias menu (with prompting)."));
	   	      break;

	    case 'R':
	    case 'Q':
	    case 'I': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpQ,
		      "R,Q,I = Return from alias menu (no prompting)."));
	   	      break;

	    case 't': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpt,
		      "t = Tag current alias for further operations."));
		      break;

	    case 'T': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpT,
		      "T = Tag current alias and go to next alias."));
		      break;

	    case ctrl('T'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlT,
	    "^T = Tag aliases matching specified pattern."));
		      break;

	    case 'u': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpu,
	    "u = Unmark the current alias for deletion from alias database."));
		      break;

	    case ctrl('U'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlU,
"^U = Mark for undeletion user aliases matching specified pattern."));
		      break;

	    case 'x':
	    case 'X': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpX,
	    "x = Exit from alias menu, abandoning any pending deletions."));
	   	      break;

	    default : show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpNoHelp,
			"That key isn't used in this section."));
	   	      break;
	  }
	  lower_prompt(alias_prompt);
	}

	/* Remove help lines */
	MoveCursor(LINES-3, 0);	CleartoEOS();
	return(redraw);
}
示例#3
0
文件: savecopy.c 项目: wfp5p/elm
/* FOO - should this routine use the file browser? */
int name_copy_file(char *fn)
{
    /*
     * Prompt user for name of file for saving copy of outbound msg to.
     * Update "fn" with user's response.
     * Return TRUE if we need a redraw (i.e. help displayed).
     */

    int redraw, i;
    char buffer[SLEN], origbuffer[SLEN], *ncf_prompt;

    redraw = FALSE;
    ncf_prompt = catgets(elm_msg_cat, ElmSet, ElmSaveCopyInPrompt,
		"Save copy in (use '?' for help/to list folders): ");

    /* convert the save cookie to readable explanation */
    (void) strcpy(origbuffer, cf_english(fn));

    for (;;) {

	/* load in the default value */
	strcpy(buffer, origbuffer);

	/* prompt for save file name */
	MoveCursor(LINES-2, 0);
	CleartoEOS();
	PutLine(LINES-2, 0, ncf_prompt);
	if (enter_string(buffer, sizeof(buffer), -1, -1, ESTR_REPLACE) < 0) {
	    /* aborted - restore value */
	    (void) strcpy(buffer, origbuffer);
	    break;
	}

	/* break out if if we got an answer */
	if (strcmp(buffer, "?") != 0)
	    break;

	/* user asked for help */
	redraw = TRUE;
	Raw(OFF | NO_TITE);
	ClearScreen();
	printf(catgets(elm_msg_cat, ElmSet, ElmListFoldersHelp,
"Enter: <nothing> to not save a copy of the message,\n\
\r       '<'       to save in your \"sent\" folder (%s),\n\
\r       '='       to save by name (the folder name depends on whom the\n\
\r                     message is to, in the end),\n\
\r       '=?'      to save by name if the folder already exists,\n\
\r                     and if not, to your \"sent\" folder,\n\
\r       or a filename (a leading '=' denotes your folder directory).\n\
\r\n\
\r"), sent_mail);
	printf(catgets(elm_msg_cat, ElmSet, ElmContentsOfYourFolderDir,
		    "\n\rContents of your folder directory:\n\r\n\r"));
	sprintf(buffer, "cd %s;ls -C", folders);
	(void) system_call(buffer, 0); 
	for (i = 0 ; i < 4 ; ++i)
	    printf("\n\r");
	Raw(ON | NO_TITE);

    }

    /* snarf any entry made by the user */
    if (!streq(origbuffer, buffer))
	strcpy(fn, buffer);

    /* display English expansion of new user input a while */
    PutLine(LINES-2, strlen(ncf_prompt), cf_english(fn));
    MoveCursor(LINES-1, 0);
    FlushOutput();
    if (sleepmsg > 0)
	sleep((sleepmsg + 1) / 2);
    MoveCursor(LINES-2, 0);
    CleartoEOS();

    return redraw;
}
示例#4
0
文件: editmsg.c 项目: wfp5p/elm
/*
 * The editor used by edit_message() when "builtin" or "none" are selected.
 * Return 0 if successful, -1 on error.
 */
static int builtin_editor(const char *filename, SEND_HEADER *shdr)
{
    char linebuf[SLEN];		/* line input buffer			*/
    char wrapbuf[SLEN];		/* wrapped line overflow buffer		*/
    char tmpbuf[SLEN];		/* scratch buffer			*/
    FILE *fp;			/* output stream to "filename"		*/
    int rc;			/* return code from this procedure	*/
    int is_wrapped;		/* wrapped line flag			*/
    int err;			/* temp holder for errno		*/
    SIGHAND_TYPE (*oldint)();	/* previous value of SIGINT		*/
    SIGHAND_TYPE (*oldquit)();	/* previous value of SIGQUIT		*/
    SIGHAND_TYPE builtin_interrupt_handler();

    /* the built-in editor is not re-entrant! */
    assert(!builtin_active);

    /* initialize return code to failure */
    rc = -1;

    if ((fp = fopen(filename, "r+")) == NULL) {
	err = errno;
	sprintf(tmpbuf, catgets(elm_msg_cat, ElmSet, ElmCouldntOpenAppend,
	    "Couldn't open %s for update [%s]."),
	    filename, strerror(err));
	PutLine(-1, -1, tmpbuf);
	dprint(1, (debugfile,
	    "Error encountered trying to open file %s;\n", filename));
	dprint(1, (debugfile, "** %s **\n", strerror(err)));
	return rc;
    }

    /* skip past any existing text */
    fseek(fp, 0, SEEK_END);

    /* prompt user, depending upon whether file already has text */
    if (fsize(fp) > 0L)
	strcpy(tmpbuf, catgets(elm_msg_cat, ElmSet, ElmContinueEntering,
	    "\n\rContinue entering message."));
    else
	strcpy(tmpbuf, catgets(elm_msg_cat, ElmSet, ElmEnterMessage,
	    "\n\rEnter message."));
    strcat(tmpbuf, catgets(elm_msg_cat, ElmSet, ElmTypeElmCommands,
	"  Type Elm commands on lines by themselves.\n\r"));
    sprintf(tmpbuf+strlen(tmpbuf),
	catgets(elm_msg_cat, ElmSet, ElmCommandsInclude,
	"Commands include:  ^D or '.' to end, %cp to list, %c? for help.\n\r\n\r"),
	escape_char, escape_char);
    CleartoEOS();
    PutLine(-1, -1, tmpbuf);

    builtin_active = TRUE;
    builtin_interrupt_count = 0;

    oldint  = signal(SIGINT,  builtin_interrupt_handler);
    oldquit = signal(SIGQUIT, builtin_interrupt_handler);

    /* return location for interrupts */
    while (SETJMP(builtin_jmpbuf) != 0) {
	if (builtin_interrupt_count == 1) {
	    PutLine(-1, -1, catgets(elm_msg_cat, ElmSet,
		ElmEditmsgOneMoreCancel,
		"(Interrupt. One more to cancel this letter.)\n\r"));
	} else {
	    PutLine(-1, -1, catgets(elm_msg_cat, ElmSet, ElmEditmsgCancelled,
		"(Interrupt. Letter canceled.)\n\r"));
	    goto done;
	}
    }

    for (;;) {

	/* re-open file if it was closed out on a call to an external editor */
	if (fp == NULL) {
	    if ((fp = fopen(filename, "a+")) == NULL) {
		err = errno;
		sprintf(tmpbuf, catgets(elm_msg_cat, ElmSet,
		    ElmCouldntOpenAppend,
		    "Couldn't open %s for update [%s]."),
		    filename, strerror(err));
		PutLine(-1, -1, tmpbuf);
		dprint(1, (debugfile,
		    "Error encountered trying to open file %s;\n", filename));
		dprint(1, (debugfile, "** %s **\n", strerror(err)));
		goto done;
	    }
	    PutLine(-1, -1, catgets(elm_msg_cat, ElmSet, ElmPostEdContinue,
		"(Continue entering message.  Type ^D or '.' on a line by itself to end.)\n\r"));
	}

	linebuf[0] = '\0';
	wrapbuf[0] = '\0';
	is_wrapped = 0;

more_wrap:
	if (wrapped_enter(linebuf, wrapbuf, -1, -1, fp, &is_wrapped) != 0)
	    break;

	if (is_wrapped) {
	    fprintf(fp, "%s\n", linebuf);
	    NewLine();
	    (void) strcpy(linebuf, wrapbuf);
	    wrapbuf[0] = '\0';
	    goto more_wrap;
	}

	/* reset consecutive interrupt counter */
	builtin_interrupt_count = 0;

	/* a lone "." signals end of text */
	if (strcmp(linebuf, ".") == 0)
	    break;

	/* process line of text */
	if (linebuf[0] != escape_char) {
	   fprintf(fp, "%s\n", linebuf);
	   NewLine();
	   continue;
	}

	/* command character was escaped */
	if (linebuf[1] == escape_char) {
	    fprintf(fp, "%s\n", linebuf+1);
	    continue;
	}

	switch (tolower(linebuf[1])) {

	case '?':
	    tilde_help();
	    break;

	case 't':
	    get_with_expansion("\n\rTo: ",
			shdr->to, shdr->expanded_to, linebuf);
	    break;

	case 'b':
	    get_with_expansion("\n\rBcc: ",
			shdr->bcc, shdr->expanded_bcc, linebuf);
	    break;

	case 'c':
	    get_with_expansion("\n\rCc: ",
			shdr->cc, shdr->expanded_cc, linebuf);
	    break;

	case 's':
	    get_with_expansion("\n\rSubject: ",
			shdr->subject, (char *)NULL, linebuf);
	    break;

	case 'h':
	    get_with_expansion("\n\rTo: ",
			shdr->to, shdr->expanded_to, (char *)NULL);
	    get_with_expansion("Cc: ",
			shdr->cc, shdr->expanded_cc, (char *)NULL);
	    get_with_expansion("Bcc: ",
			shdr->bcc, shdr->expanded_bcc, (char *)NULL);
	    get_with_expansion("Subject: ",
			shdr->subject, (char *)NULL, (char *)NULL);
	    break;

	case 'r':
	    read_in_file(fp, linebuf+2, 1);
	    break;

	case 'e':
	    if (e_editor[0] == '\0') {
		PutLine(-1, -1, catgets(elm_msg_cat, ElmSet, ElmDontKnowEmacs,
		    "\n\r(Don't know where Emacs would be. Continue.)\n\r"));
		break;
	    }
	    NewLine();
	    fclose(fp);
	    fp = NULL;
	    (void) edit_message(filename, shdr, e_editor);
	    break;

	case 'v':
	    NewLine();
	    fclose(fp);
	    fp = NULL;
	    (void) edit_message(filename, shdr, v_editor);
	    break;

	case 'o':
	    PutLine(-1, -1, catgets(elm_msg_cat, ElmSet, ElmEnterNameEditor,
		"\n\rPlease enter the name of the editor: "));
	    if (enter_string(tmpbuf, sizeof(tmpbuf), -1, -1, ESTR_ENTER) < 0
			|| tmpbuf[0] == '\0') {
		PutLine(-1, -1, catgets(elm_msg_cat, ElmSet, ElmSimpleContinue,
		    "(Continue.)\n\r"));
		break;
	    }
	    NewLine();
	    fclose(fp);
	    fp = NULL;
	    (void) edit_message(filename, shdr, tmpbuf);
	    break;

	case '<':
	    NewLine();
	    if (strlen(linebuf) < 3) {
		PutLine(-1, -1, catgets(elm_msg_cat,
		    ElmSet, ElmUseSpecificCommand,
		   "(You need to use a specific command here. Continue.)\n\r"));
		break;
	    }
	    sprintf(tmpbuf, "%s%s.%d", temp_dir, temp_edit, getpid());
	    sprintf(linebuf+strlen(linebuf), " >%s 2>&1", tmpbuf);
	    (void) system_call(linebuf+2, SY_COOKED|SY_ENAB_SIGINT|SY_DUMPSTATE);
	    read_in_file(fp, tmpbuf, 0);
	    (void) unlink(tmpbuf);
	    break;

	case '!':
	    NewLine();
	    (void) system_call(
		(strlen(linebuf) < 3 ? (char *)NULL : linebuf+2),
		SY_COOKED|SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE);
	    PutLine(LINES, 0, catgets(elm_msg_cat, ElmSet, ElmSimpleContinue,
		"(Continue.)\n\r"));
	    break;

	case 'm': /* same as 'f' but with leading prefix added */
	case 'f': /* this can be directly translated into a
			 'readmsg' call with the same params! */
	    NewLine();
	    read_in_messages(fp, linebuf+1);
	    break;

	case 'p': /* print out message so far */
	    print_message_so_far(fp, shdr);
	    break;

	default:
	    sprintf(tmpbuf, catgets(elm_msg_cat, ElmSet, ElmDontKnowChar,
		"\n\r(Don't know what %c%c is. Try %c? for help.)\n\r"),
		 escape_char, linebuf[1], escape_char);
	    PutLine(-1, -1, tmpbuf);
	    break;

	}

    }

    PutLine(-1, -1, catgets(elm_msg_cat, ElmSet, ElmEndOfMessage,
	"\n\r<end-of-message>\n\r\n\r\n\r\n\r"));
    rc = 0;

done:
    (void) signal(SIGINT,  oldint);
    (void) signal(SIGQUIT, oldquit);
    if (fp != NULL)
	fclose(fp);
    builtin_active = FALSE;
    return rc;
}
int
subshell()
{
	/** spawn a subshell with either the specified command
	    returns non-zero if screen rewrite needed
	**/

	char command[SLEN];
	int  old_raw, helpful, ret;

	helpful = (user_level == 0);

	if (helpful)
	  PutLine0(LINES-3, COLUMNS-40, catgets(elm_msg_cat, ElmSet, ElmUseShellName,
		"(Use the shell name for a shell.)"));
	PutLine0(LINES-2, 0, catgets(elm_msg_cat, ElmSet, ElmShellCommand,
		"Shell command: "));
	CleartoEOS();
	command[0] = '\0';
	(void) optionally_enter(command, LINES-2, 15, FALSE, FALSE);
	if (command[0] == 0) {
	  if (helpful)
	    MoveCursor(LINES-3,COLUMNS-40);
	  else
	    MoveCursor(LINES-2,0);
	  CleartoEOS();
	  return 0;
	}

	MoveCursor(LINES,0);
	CleartoEOLN();

	if ((old_raw = RawState()) == ON)
	  Raw(OFF);
	softkeys_off();
	if (cursor_control)
	  transmit_functions(OFF);

	umask(original_umask);	/* restore original umask so users new files are ok */
	ret = system_call(command, SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE);
	umask(077);		/* now put it back to private for mail files */

	SetXYLocation(0, 40);	/* a location not near the next request, so an absolute is used */
	PutLine0(LINES, 0, catgets(elm_msg_cat, ElmSet, ElmPressAnyKeyToReturn,
		"\n\nPress any key to return to ELM: "));
	Raw(ON | NO_TITE);
	(void) getchar();
	printf("\r\n");
	Raw(OFF | NO_TITE); /* Done even if old_raw == ON, to get ti/te right */
	if (old_raw == ON)
	  Raw(ON);

	softkeys_on();
	if (cursor_control)
	  transmit_functions(ON);

	if (ret)
	  error1(catgets(elm_msg_cat, ElmSet, ElmReturnCodeWas,
		"Return code was %d."), ret);

	return 1;
}