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... */ }
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); }
/* 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; }
/* * 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; }