home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume12
/
mush
/
part09
< prev
next >
Wrap
Text File
|
1990-05-05
|
57KB
|
1,875 lines
Newsgroups: comp.sources.misc
subject: v12i037: Mail User's Shell, Part09/19
from: argv@Eng.Sun.COM (Dan Heller)
Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Posting-number: Volume 12, Issue 37
Submitted-by: argv@Eng.Sun.COM (Dan Heller)
Archive-name: mush/part09
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 9 (of 19)."
# Contents: mush/doproc.c mush/mail.c.a
# Wrapped by argv@turnpike on Wed May 2 13:59:29 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mush/doproc.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/doproc.c'\"
else
echo shar: Extracting \"'mush/doproc.c'\" \(21819 characters\)
sed "s/^X//" >'mush/doproc.c' <<'END_OF_FILE'
X/* @(#)doproc.c (c) copyright 10/18/86 (Dan Heller) */
X
X/* do main panel item procedures */
X#include "mush.h"
X
Xextern void start_textsw_edit();
Xvoid set_comp_items();
X
Xextern Panel_item
X file_item, folder_text_item, folder_item, msg_num_item, read_item,
X reply_item, save_item, sub_hdr_item[6];
X
X/* following macro is for the next two procedures */
X#define hdr_item(item) \
X (item == sub_hdr_item[0] || item == sub_hdr_item[1] || \
X item == sub_hdr_item[2] || item == sub_hdr_item[3] || \
X item == sub_hdr_item[4] || item == sub_hdr_item[5])
X
Xvoid
Xdelete_mail(item, value, event)
Xregister Panel_item item;
Xint value;
Xregister Event *event;
X{
X int val = value; /* save cuz we reset value immediately */
X u_long bang = ison(glob_flags, IGN_BANG);
X char buf[128];
X
X (void) panel_set(item, PANEL_VALUE, 0, 0);
X if (hdr_item(item) && event_id(event) != MS_LEFT || val == 2) {
X help(0, "delete", tool_help);
X return;
X }
X /* delete current message */
X wprint(sprintf(buf, "\\%sdelete %s\n",
X ((event_id(event) == MS_LEFT || val == 0)? "" : "un"),
X panel_get_value(msg_num_item)) + 1); /* +1 skips the backslash */
X turnon(glob_flags, IGN_BANG);
X (void) cmd_line(buf, msg_list);
X if (!bang)
X turnoff(glob_flags, IGN_BANG);
X}
X
Xvoid
Xread_mail(item, value, event)
XPanel_item item;
XEvent *event;
X{
X int this_msg = current_msg;
X
X /* check "event" in case we were called from hdr_sw.c
X * in which case event would be NULL
X */
X if (event && event_id(event) == MS_RIGHT && item &&
X (item == read_item ||
X (item == sub_hdr_item[0] || item == sub_hdr_item[1]))) {
X (void) help(0, "next", tool_help);
X return;
X }
X if (item && (item == sub_hdr_item[4] || item == sub_hdr_item[5])) {
X (void) help(0, "Menu Read", tool_help);
X return;
X }
X if (!msg_cnt) {
X wprint ("No Mail.\n");
X return;
X }
X if (item && item == read_item || ison(msg[current_msg].m_flags, DELETE))
X (void) next_msg();
X if (this_msg != current_msg || ison(msg[current_msg].m_flags, UNREAD) ||
X (current_msg < n_array[0] || current_msg > n_array[screen])) {
X set_isread(current_msg);
X (void) do_hdrs(0, DUBL_NULL, NULL);
X }
X if (isoff(msg[current_msg].m_flags, DELETE))
X display_msg(current_msg, (u_long)0);
X}
X
X/* the panel button that says "filename" and "directory", etc... text item */
XPanel_setting
Xfile_dir(item, event)
XPanel_item item;
XEvent *event;
X{
X register char *p;
X u_long bang = ison(glob_flags, IGN_BANG);
X char buf[MAXPATHLEN];
X
X if (event_id(event) == ESC) {
X /* file expansion request */
X int n;
X char **files;
X p = panel_get_value(item);
X (void) sprintf(buf, "%s*", p);
X timeout_cursors(1);
X if ((n = filexp(buf, &files)) > 0) {
X Debug("%d: ",n), print_argv(files);
X if (n > 1) {
X n = lcprefix(files, 0);
X files[0][n] = 0;
X }
X panel_set_value(item, trim_filename(files[0]));
X free_vec(files);
X } else
X errbell(n); /* see curs_io.c */
X timeout_cursors(0);
X return PANEL_NONE;
X }
X
X if (item == folder_text_item) {
X (void) sprintf(buf, "folder %s %s",
X (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
X !ask("Folder has been modified. Update changes?"))? "!" : "",
X panel_get_value(folder_text_item));
X }
X else if (item == file_item) {
X register char *b = buf;
X char msgstr[BUFSIZ];
X
X if (event_id(event) == '\n' || event_id(event) == '\r')
X b += Strcpy(buf, "save ");
X else
X b += Strcpy(buf, "write ");
X if ((p = panel_get_value(msg_num_item)) && *p)
X b += Strcpy(b, p);
X else {
X if (ison(msg[current_msg].m_flags, DELETE) &&
X !do_set(set_options, "show_deleted")) {
X (void) sprintf(msgstr, "Message %d deleted -- save anyway?",
X current_msg+1);
X if (ask(msgstr) != TRUE) {
X wprint("Message not saved\n");
X return PANEL_NONE;
X }
X }
X b += strlen(sprintf(b, "%d", current_msg+1));
X }
X *b++ = ' ', *b = 0;
X if (!(p = panel_get_value(item)) || !*p &&
X (!(p = do_set(set_options, "mbox")) || !*p))
X p = DEF_MBOX;
X (void) sprintf(msgstr, "%s in \"%s\"?", buf, trim_filename(p));
X if (ask(msgstr) != TRUE) {
X wprint("Message not saved\n");
X return PANEL_NONE;
X }
X (void) strcpy(b, p); /* now add to command */
X }
X turnon(glob_flags, IGN_BANG);
X (void) cmd_line(buf, msg_list);
X if (!bang)
X turnoff(glob_flags, IGN_BANG);
X return PANEL_NONE;
X}
X
X/*
X * callback routine for the panel items that need filename input.
X * (folder and save)
X */
Xvoid
Xdo_file_dir(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X char buf[BUFSIZ];
X u_long bang = ison(glob_flags, IGN_BANG);
X
X if (item == folder_item) {
X (void) sprintf(buf, "folder %s ",
X (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
X !ask("Folder has been modified. Update changes?"))? "!" : "");
X if (event_id(event) == MS_LEFT) {
X char *p = panel_get_value(folder_text_item);
X if (!*p) {
X ok_box("Enter folder name.");
X return;
X }
X (void) strcat(buf, p);
X } else if (!value)
X (void) strcat(buf, "%");
X else if (value == 1)
X (void) strcat(buf, "&");
X else if (value == 2)
X (void) strcat(buf, "#");
X else
X (void) strcat(buf, panel_get(item, PANEL_CHOICE_STRING, value));
X } else if (item == save_item) {
X char msgstr[BUFSIZ], *p;
X (void) strcpy(buf, "save ");
X if (event_id(event) == MS_LEFT) {
X if (!strcmp("Filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
X event_id(event) = '\n'; /* let file_dir think it got a \n */
X file_dir(file_item, event);
X return;
X }
X } else if (value == 0) {
X register char *p2 = (char *)panel_get_value(msg_num_item);
X
X if (!(p = do_set(set_options, "mbox")) || !*p)
X p = DEF_MBOX;
X if (p2 && *p2) {
X (void) strcat(buf, p2);
X (void) strcat(buf, " ");
X }
X (void) strcat(buf, p);
X } else
X (void) strcat(buf, p = panel_get(item, PANEL_CHOICE_STRING, value));
X (void) sprintf(msgstr, "Save in %s? ", trim_filename(p));
X if (ask(msgstr) != TRUE) {
X wprint("Message not saved\n");
X return;
X }
X }
X turnon(glob_flags, IGN_BANG);
X (void) cmd_line(buf, msg_list);
X if (!bang)
X turnoff(glob_flags, IGN_BANG);
X (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
X}
X
X/*ARGSUSED*/
Xvoid
Xdo_help(item, value, event)
XPanel_item item;
Xregister int value;
XEvent *event;
X{
X register char *p, *helpfile = tool_help;
X if (!event || event_id(event) == MS_LEFT)
X value = 0;
X switch(value) {
X case 1: p = "help";
X when 2: p = "mouse";
X when 3: p = "windows";
X when 4: p = "hdr_format", helpfile = cmd_help;
X when 5: p = "msg_list", helpfile = cmd_help;
X when 6: p = "folder";
X otherwise: p = "general";
X }
X (void) help(0, p, helpfile);
X}
X
X/*ARGSUSED*/
Xvoid
Xdo_update(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X char *argv[2];
X if (event && event_id(event) != MS_LEFT) {
X if (value == 0) {
X if (check_new_mail() == 0)
X print("No new mail.\n");
X } else
X (void) help(0, "update", tool_help);
X return;
X }
X argv[0] = "update";
X argv[1] = NULL;
X timeout_cursors(TRUE);
X (void) folder(0, argv, NULL);
X timeout_cursors(FALSE);
X}
X
X/*ARGSUSED*/
Xvoid
Xtoolquit(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X void wmgr_changestate(), wmgr_changelevel();
X register int which;
X
X if (!value || event_id(event) == MS_LEFT) {
X if (ison(glob_flags, DO_UPDATE)) {
X do_update(NO_ITEM, 0, NO_EVENT);
X turnoff(glob_flags, NEW_MAIL);
X }
X check_icons();
X mail_status(0); /* lower flag (if up) print current num of msgs */
X /* wmgr_changestate (window_get(tool, WIN_FD), rootfd, TRUE); */
X /* wmgr_changelevel (window_get(tool, WIN_FD), parentfd, TRUE); */
X window_set(tool, FRAME_CLOSED, TRUE, NULL);
X is_iconic = ((int) window_get(tool, FRAME_CLOSED));
X return;
X } else if (value == 2) {
X (void) help(0, "quit", tool_help);
X return;
X }
X /* modify this to check for "abort" choice when ternary return values
X * are possible!
X */
X if (isoff(glob_flags, DO_UPDATE) ||
X ask("Folder has been modified -- update?")) {
X if (!copyback("Quit anyway?"))
X return;
X }
X cleanup(0);
X}
X
X/*ARGSUSED*/
Xvoid
Xdo_lpr(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X char buf[128];
X
X if (event && (event_id(event) == MS_LEFT || value == 1)) {
X wprint("Sending message %d to printer...\n", current_msg+1);
X (void) strcpy(buf, "lpr ");
X if (value)
X (void) sprintf(buf, "lpr \"%s\"", panel_get_value(msg_num_item));
X timeout_cursors(TRUE);
X (void) cmd_line(buf, msg_list);
X timeout_cursors(FALSE);
X } else
X (void) help(0, "printer", tool_help);
X}
X
X/* panel selection button pressed to send a letter.
X * we've attached the sign panel item to this item to 1) avoid
X * using a global and 2) make it general enough so that multiple
X * compose windows can have multiple send_items and we can
X * identify which sign/fortune items are associated with this
X * particular letter. The fortune item is attached to the sign
X * item.
X */
X/*ARGSUSED*/
Xvoid
Xdo_send(item, value, event)
XPanel_item item;
Xint value;
Xregister Event *event;
X{
X Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
X Panel_item sign_item = (Panel_item)panel_get(item, PANEL_CLIENT_DATA);
X Panel_item fortune_item =
X (Panel_item)panel_get(sign_item, PANEL_CLIENT_DATA);
X Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X char *argv[5], buf[64];
X char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X char *p, *oldsign = NULL, *oldfortune = NULL;
X Textsw save_sw = wprint_sw;
X
X if (textsw_store_file(textsw, file, 0, 0)) {
X error("Can't save to %s", file);
X return;
X }
X /* check if user changed variables before sending */
X if (p = do_set(set_options, "autosign"))
X oldsign = savestr(p);
X if (panel_get_value(sign_item) && !oldsign)
X cmd_line(strcpy(buf, "\\set autosign"), NULL);
X else if (!panel_get_value(sign_item) && oldsign)
X cmd_line(strcpy(buf, "\\unset autosign"), NULL);
X if (p = do_set(set_options, "fortune"))
X oldfortune = savestr(p);
X if (panel_get_value(fortune_item) && !oldfortune)
X (void) cmd_line(strcpy(buf, "set fortune"), NULL);
X else if (!panel_get_value(fortune_item) && oldfortune)
X (void) cmd_line(strcpy(buf, "\\unset fortune"), NULL);
X wprint_sw = NULL;
X wprint_sw = save_sw;
X turnoff(glob_flags, IS_GETTING);
X argv[0] = "mail";
X argv[1] = "-Uh";
X argv[2] = file;
X argv[3] = NULL;
X clear_msg_list(msg_list);
X timeout_cursors(TRUE);
X if (do_mail(3, argv, msg_list) == 0) {
X (void) unlink(file);
X set_comp_items(panel);
X }
X if (panel_get_value(sign_item) && !oldsign)
X (void) cmd_line(strcpy(buf, "\\unset autosign"), NULL);
X else if (!panel_get_value(sign_item) && oldsign) {
X argv[0] = "set";
X argv[1] = "autosign";
X if (*oldsign) {
X argv[2] = "=";
X argv[3] = oldsign;
X argv[4] = NULL;
X (void) set(4, argv, NULL);
X } else {
X argv[2] = NULL;
X (void) set(2, argv, NULL);
X }
X }
X if (panel_get_value(fortune_item) && !oldfortune)
X cmd_line(strcpy(buf, "\\unset fortune"), NULL);
X else if (!panel_get_value(fortune_item) && oldfortune) {
X argv[0] = "set";
X argv[1] = "fortune";
X if (*oldfortune) {
X argv[2] = "=";
X argv[3] = oldfortune;
X argv[4] = NULL;
X (void) set(4, argv, NULL);
X } else {
X argv[2] = NULL;
X (void) set(2, argv, NULL);
X }
X }
X xfree(oldsign), xfree(oldfortune);
X timeout_cursors(FALSE);
X}
X
X/*ARGSUSED*/
Xvoid
Xdo_include(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X extern FILE *ed_fp;
X char *p, buf[64], *file;
X Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X PANEL_CLIENT_DATA);
X
X if (event && event_id(event) == MS_LEFT)
X value = 0;
X if (value == 2) {
X (void) help(0, "include", tool_help);
X return;
X }
X p = panel_get_value(msg_num_item);
X (void) sprintf(buf, "%c%c%s", *escape, value == 0? 'i' : 'f', p? p : "");
X
X file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X if (textsw_store_file(textsw, file, 0, 0)) {
X (void) ask("Something's wrong... Click anything.");
X return;
X }
X if (ed_fp) {
X (void) ask("tmpfile already in use... Click anything.");
X (void) fclose(ed_fp);
X }
X if (!(ed_fp = mask_fopen(file, "a"))) {
X error("Cannot open %s to append msg.", file);
X return;
X }
X (void) add_to_letter(buf);
X (void) fclose(ed_fp), ed_fp = NULL_FILE;
X#ifdef SUN_4_0 /* SunOS 4.0+ */
X window_set(textsw, TEXTSW_FILE_CONTENTS, file, NULL);
X#else /* SUN_4_0 */
X textsw_load_file(textsw, file, 1, 0, 0);
X#endif /* SUN_4_0 */
X window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
X (void) unlink(file);
X}
X
X/*ARGSUSED*/
Xvoid
Xdo_compose(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X char buf[5];
X Textsw textsw;
X
X if (event && event_id(event) != MS_LEFT) {
X (void) help(0, "compose", tool_help);
X return;
X }
X open_compose();
X clear_msg_list(msg_list);
X if (do_mail(0, DUBL_NULL, msg_list) == 0) {
X#ifdef SUN_4_0
X Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 1);
X#else
X Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 0);
X#endif /* SUN_4_0 */
X Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X start_textsw_edit(textsw, TRUE);
X set_comp_items(panel);
X }
X}
X
X/*
X * notify proc for reply button -- also called from select.c (do_menu()) ,
X * in which case "event" is null and "value" contains the message
X * number of the message to reply to.
X */
X/*ARGSUSED*/
Xvoid
Xrespond_mail(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X int tmp = current_msg;
X char buf[256];
X
X if (event && event_id(event) == MS_LEFT)
X value = 0;
X if (event && value == 4) {
X (void) help(0, "respond", tool_help);
X return;
X }
X if (!msg_cnt) {
X wprint("No messages to respond to.\n");
X return;
X }
X if (ison(glob_flags, IS_GETTING)) {
X wprint("Finish editing current message first.\n");
X return;
X }
X if (!event)
X tmp = value, value = 0;
X open_compose();
X (void) sprintf(buf, "%s %s %d",
X (value == 2 || value == 3)? "\\replyall" : "\\replysender",
X (value == 1 || value == 3)? "-i": NO_STRING, tmp+1);
X if (cmd_line(buf, NULL) != -1) {
X#ifdef SUN_4_0
X Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 1);
X#else
X Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 0);
X#endif /* SUN_4_0 */
X Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X wprint("Responding to message %d\n", tmp+1);
X start_textsw_edit(textsw, FALSE);
X set_comp_items(panel);
X }
X}
X
X/*ARGSUSED*/
Xvoid
Xload_from_file(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X int x = 0;
X Textsw textsw;
X Panel_item filename_item = (Panel_item)panel_get(item, PANEL_CLIENT_DATA);
X char *file, *p = panel_get_value(filename_item);
X#ifndef SUN_4_0 /* SunOS 4.0+ */
X char *sfile, buf[128];
X extern FILE *ed_fp;
X#endif /* SUN_4_0 */
X
X if (!*p) {
X wprint("Specify Filename.\n");
X return;
X }
X file = getpath(p, &x);
X if (x == 1)
X wprint("%s: is a directory.\n", p);
X else if (x == -1)
X wprint("%s: %s\n", p, file);
X if (x)
X return;
X timeout_cursors(TRUE);
X textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X PANEL_CLIENT_DATA);
X if (event_id(event) != MS_LEFT && value == 1)
X /* replace */
X textsw_load_file(textsw, file, 1, 0, 0);
X else {
X /* insert */
X#ifdef SUN_4_0 /* SunOS 4.0+ */
X window_set(textsw, TEXTSW_INSERT_FROM_FILE, file, NULL);
X#else /* SUN_4_0 */
X /* best we can do with pre 4.0 is save the current file
X * and append the new file onto the end.
X */
X sfile = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X if (textsw_store_file(textsw, sfile, 0, 0)) {
X (void) ask("Can't save file... Click anything.");
X return;
X }
X if (ed_fp) {
X (void) ask("tmpfile already in use... Click anything.");
X fclose(ed_fp);
X }
X if (!(ed_fp = mask_fopen(sfile, "a"))) {
X error("Cannot open %s.", sfile);
X return;
X }
X (void) sprintf(buf, "%c%c%s", *escape, 'r', trim_filename(p));
X (void) add_to_letter(buf);
X (void) fclose(ed_fp), ed_fp = NULL_FILE;
X textsw_load_file(textsw, sfile, 1, 0, 0);
X (void) unlink(sfile);
X#endif /* SUN_4_0 */
X }
X window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
X panel_set_value(item, 0);
X timeout_cursors(FALSE);
X}
X
X/*ARGSUSED*/
Xvoid
Xsave_to_file(item, value, event)
XPanel_item item;
XEvent *event;
X{
X Panel_item filename_item = panel_get(item, PANEL_CLIENT_DATA);
X char *file = panel_get_value(filename_item);
X FILE *fp;
X Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X PANEL_CLIENT_DATA);
X
X if (!*file) {
X wprint("Specify Filename\n");
X return;
X }
X timeout_cursors(TRUE);
X /* append to file -- no confirmation necessary */
X if (fp = open_file(file, FALSE, TRUE)) {
X char buf[BUFSIZ];
X Textsw_index next_pos = 0, tmp;
X Textsw_index length =
X (Textsw_index)window_get(textsw, TEXTSW_LENGTH);
X do {
X tmp = next_pos;
X next_pos = (Textsw_index) window_get(textsw, TEXTSW_CONTENTS,
X next_pos, buf, sizeof(buf));
X if (fwrite(buf, sizeof(char), (int)(next_pos - tmp), fp) == 0)
X error("%s may be incomplete", file);
X } while (next_pos < length);
X (void) close_lock(file, fp);
X wprint("Wrote %d bytes to %s\n", length, trim_filename(file));
X }
X timeout_cursors(FALSE);
X}
X
Xvoid
Xabort_mail(item, event)
XPanel_item item;
XEvent *event;
X{
X Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
X Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X wprint("Aborted letter.\n");
X textsw_reset(textsw, 0, 0);
X rm_edfile(0);
X set_comp_items(panel);
X}
X
X/* set the compose panel items */
Xvoid
Xset_comp_items(panel)
XPanel panel;
X{
X Panel_item item, next;
X Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X int getting = ison(glob_flags, IS_GETTING) != 0;
X int i = 0;
X
X window_set(textsw, TEXTSW_READ_ONLY, !getting, NULL);
X /* remove next line when multiple composes become a reality */
X (void) panel_set(reply_item, PANEL_SHOW_ITEM, !getting, NULL);
X /* skip "close" item */
X item = (Panel_item) panel_get(panel, PANEL_FIRST_ITEM);
X for (item = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
X item; item = next) {
X next = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
X (void) panel_set(item,
X PANEL_SHOW_ITEM, (i++ < 1)? !getting : getting, NULL);
X }
X}
X
X/*
X * Ask a yes/no question and return an answer: TRUE or FALSE.
X */
Xask(question)
Xchar *question;
X{
X#ifdef SUN_4_0 /* SunOS 4.0+ */
X return alert_prompt(tool, (Event *)NULL,
X ALERT_MESSAGE_STRINGS, question, NULL,
X ALERT_BUTTON_YES, "Yes",
X ALERT_BUTTON_NO, "No",
X NULL) == ALERT_YES;
X#else /* SUN_4_0 */
X Event event;
X struct prompt prompt;
X Rect *rect = (Rect *)window_get(tool, WIN_RECT);
X char buf[MAXPATHLEN];
X
X (void) sprintf(buf,
X "%s \nPress LEFT Button to Confirm. Anything else to cancel.",
X question);
X prompt.prt_rect.r_left = rect->r_left + (rect->r_width / 3);
X prompt.prt_rect.r_top = rect->r_top + (rect->r_height / 3);
X prompt.prt_rect.r_width = prompt.prt_rect.r_height = PROMPT_FLEXIBLE;
X prompt.prt_font = mush_font;
X prompt.prt_text = buf;
X
X menu_prompt(&prompt, &event, window_get(tool, WIN_FD));
X return event_id(&event) == MS_LEFT;
X#endif /* SUN_4_0 */
X}
X
Xvoid
Xok_box(buf)
Xchar *buf;
X{
X#ifdef SUN_4_0
X (void) alert_prompt(tool, (Event *)NULL,
X ALERT_MESSAGE_STRINGS, buf, NULL,
X ALERT_BUTTON_YES, "Ok",
X NULL);
X#else /* SUN_4_0 */
X Event event;
X struct prompt prompt;
X Rect *rect = (Rect *)window_get(tool, WIN_RECT);
X (void) strcat(buf, " \nPress LEFT Button to Continue.");
X prompt.prt_rect.r_left = rect->r_left + (rect->r_width / 3);
X prompt.prt_rect.r_top = rect->r_top + (rect->r_height / 3);
X prompt.prt_rect.r_width = prompt.prt_rect.r_height = PROMPT_FLEXIBLE;
X prompt.prt_font = mush_font;
X prompt.prt_text = buf;
X menu_prompt(&prompt, &event, window_get(tool, WIN_FD));
X#endif /* SUN_4_0 */
X}
X
XPanel_setting
Xmsg_num_done(item, event)
XPanel_item item;
XEvent *event;
X{
X char buf[82];
X u_long bang = ison(glob_flags, IGN_BANG);
X register char *p;
X int n;
X
X if (event_id(event) != '\n' && event_id(event) != '\r') {
X (void) help(0, "message range", tool_help);
X return PANEL_NONE;
X }
X (void) sprintf(buf, "headers %s", (p = (char *)panel_get_value(item)));
X (void) panel_set(item, PANEL_VALUE, NO_STRING, NULL);
X if (!(n = chk_msg(p)))
X return PANEL_NONE;
X current_msg = --n;
X turnon(glob_flags, IGN_BANG);
X (void) cmd_line(buf, msg_list);
X if (!bang)
X turnoff(glob_flags, IGN_BANG);
X (void) display_msg(n, (u_long)0);
X return PANEL_NONE;
X}
X
Xvoid
Xdo_sort(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X char *argv[3], list[MAXMSGS_BITS];
X char *p = (char *)panel_get_value(msg_num_item);
X int n = 0;
X
X if (p && *p) {
X argv[0] = p;
X argv[1] = NULL;
X n = get_msg_list(argv, list);
X }
X argv[0] = "sort";
X argv[2] = NULL;
X
X if (event_id(event) == MS_LEFT)
X argv[1] = do_set(set_options, "sort");
X else switch(value) {
X case 0: argv[1] = "d";
X when 1: argv[1] = "a";
X when 2: argv[1] = "l";
X when 3: argv[1] = "R";
X when 4: argv[1] = "s";
X when 5: argv[1] = "S";
X when 6: (void) help(0, "sort", tool_help);
X }
X if (value != 6) {
X if (n > 0) {
X turnon(glob_flags, IS_PIPE);
X (void) sort(2, argv, list);
X turnoff(glob_flags, IS_PIPE);
X } else
X (void) sort(2, argv, NULL);
X (void) do_hdrs(0, DUBL_NULL, NULL);
X }
X (void) panel_set(item, PANEL_VALUE, 0, NULL);
X}
X
Xvoid
Xdo_options(item, value, event)
XPanel_item item;
Xint value;
XEvent *event;
X{
X if (event_id(event) == MS_LEFT) {
X view_options();
X return;
X }
X switch (value) {
X case 0:
X view_options();
X when 1:
X do_ignore();
X when 2:
X do_aliases();
X }
X}
END_OF_FILE
if test 21819 -ne `wc -c <'mush/doproc.c'`; then
echo shar: \"'mush/doproc.c'\" unpacked with wrong size!
fi
# end of 'mush/doproc.c'
fi
if test -f 'mush/mail.c.a' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/mail.c.a'\"
else
echo shar: Extracting \"'mush/mail.c.a'\" \(30778 characters\)
sed "s/^X//" >'mush/mail.c.a' <<'END_OF_FILE'
X/* @(#)mail.c (c) copyright 1986 (Dan Heller) */
X
X#include "mush.h"
X
X/*
X * mail.c --
X * do_mail() external interface to these functions; parses options.
X * mail_someone() called from do_mail() to begin composing the message.
X * start_file() creates the editing file and reset signal catching.
X * add_to_letter() adds the next line to letter --determine ~ escapes.
X * finish_up_letter() prompts for Cc:, verifies send, adds signatures.
X * send_it() expands aliases, invokes mailer, sends to record file.
X * add_headers() adds all headers to a FILE *, reads draft files
X * rm_edfile() signals are directed here. remove letter, longjmp
X * dead_letter() make a dead.letter if mail failed.
X */
X
Xstatic char Subject[BUFSIZ],To[HDRSIZ],Cc[HDRSIZ],Bcc[HDRSIZ],in_reply_to[256];
Xstatic int killme;
Xstatic u_long flags;
Xstatic SIGRET (*oldterm)(), (*oldint)(), (*oldquit)();
Xstatic int finish_up_letter(), send_it(), start_file();
Xstatic long add_headers();
Xstatic jmp_buf cntrl_c_buf;
Xstatic char *Hfile, *edfile;
XFILE *ed_fp;
Xchar *hfile, *mktemp();
X
X/* argc and argv could be null if coming from tool mode compose */
Xdo_mail(n, argv, list)
Xregister int n; /* no need for "argc", so use the space for a variable */
Xregister char **argv, *list;
X{
X char firstchar = (argv)? **argv: 'm';
X char *to = NULL, *cc = NULL, *addcc = NULL, *bcc = NULL, *subj = NULL;
X char *route = NULL;
X char inc_list[MAXMSGS_BITS], buf[HDRSIZ];
X u_long flgs = 0;
X
X if (ison(glob_flags, IS_GETTING)) {
X wprint("You must finish the letter you are editing first.\n");
X return -1;
X }
X if (ison(glob_flags, DO_PIPE)) {
X wprint("You can't pipe through the mail command.\n");
X return -1;
X }
X clear_msg_list(inc_list);
X hfile = Hfile = NULL;
X
X /* If piped to mail, include the messages piped */
X if (ison(glob_flags, IS_PIPE) ||
X (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))) {
X turnon(flgs, INCLUDE);
X bitput(list, inc_list, msg_cnt, =);
X }
X /* Set SIGN and DO_FORTUNE now so we can turn them off later */
X if (do_set(set_options, "autosign"))
X turnon(flgs, SIGN);
X if (do_set(set_options, "fortune"))
X turnon(flgs, DO_FORTUNE);
X while (argv && *argv && *++argv && **argv == '-') {
X n = 1;
X while (n && argv[0][n])
X switch (argv[0][n]) {
X#ifdef VERBOSE_ARG
X case 'v': turnon(flgs, VERBOSE); n++; break;
X#endif /* VERBOSE_ARG */
X case 'H':
X if (argv[1]) {
X n = 0;
X Hfile = *++argv;
X } else {
X wprint("Must specify a file\n");
X return -1;
X }
X when 'h':
X if (argv[1]) {
X n = -1; /* it gets incremented below */
X hfile = savestr(*++argv);
X if (ison(glob_flags, REDIRECT)) {
X turnoff(glob_flags, REDIRECT);
X turnon(flgs, SEND_NOW);
X }
X } else {
X wprint("Must specify a file containing headers\n");
X return -1;
X }
X /* Fall through */
X case 'E': turnon(flgs, EDIT_HDRS); n++;
X when 'e': turnon(flgs, EDIT); n++;
X when 'F': turnon(flgs, DO_FORTUNE); n++;
X when 'b':
X if (argv[1]) {
X n = 0, bcc = *++argv;
X fix_up_addr(bcc);
X } else {
X wprint("Must specify blind-carbon list\n");
X return -1;
X }
X when 'c':
X if (argv[1]) {
X n = 0, addcc = *++argv;
X fix_up_addr(addcc);
X } else {
X wprint("Must specify carbon-copy list\n");
X return -1;
X }
X when 's':
X if (argv[1])
X n = 0, subj = *++argv;
X else
X n++, turnon(flgs, NEW_SUBJECT);
X when 'i': case 'I': case 'f': {
X int m;
X if (!msg_cnt) {
X wprint("No message to include!\n");
X return -1;
X }
X if (argv[0][n] == 'i') {
X turnon(flgs, INCLUDE);
X turnoff(flgs, INCLUDE_H);
X turnoff(flgs, FORWARD);
X } else if (argv[0][n] == 'I') {
X turnon(flgs, INCLUDE_H);
X turnoff(flgs, INCLUDE);
X turnoff(flgs, FORWARD);
X } else if (argv[0][n] == 'f') {
X turnon(flgs, FORWARD);
X turnon(flgs, SEND_NOW);
X turnoff(flgs, INCLUDE_H);
X turnoff(flgs, INCLUDE);
X }
X /* "-i 3-5" or "-i3-5" Consider the latter case first */
X if (!argv[0][++n])
X argv++, n = 0;
X (*argv) += n;
X m = get_msg_list(argv, inc_list);
X (*argv) -= n;
X if (m == -1)
X return -1;
X /* if there were args, then go back to the first char
X * in the next argv
X */
X if (m)
X n = 0;
X if (!n) /* n may be 0 from above! */
X argv += (m-1);
X }
X when 'U':
X turnon(flgs, SEND_NOW);
X n++;
X when 'u':
X turnoff(flgs, SIGN);
X turnoff(flgs, DO_FORTUNE);
X n++;
X when 'r':
X if (lower(firstchar) == 'r') {
X route = *++argv;
X n = 0;
X break;
X }
X /* fall thru */
X default:
X if (argv[0][n] != '?') {
X wprint("%c: unknown option\n\n", argv[0][n]);
X return -1;
X } else
X return help(0, "mail", cmd_help);
X }
X }
X if (isoff(flgs, FORWARD)) {
X if (ison(flgs, SEND_NOW)) {
X if (!hfile && !Hfile) {
X wprint("Can't send immediately without draft file.\n");
X return -1;
X }
X turnoff(flgs, EDIT); /* -U overrides -e */
X } else if (do_set(set_options, "autoedit"))
X turnon(flgs, EDIT);
X } else if (ison(flgs, EDIT)) /* -e modifies -f */
X turnoff(flgs, SEND_NOW);
X#ifdef VERBOSE_ARG
X if (do_set(set_options, "verbose"))
X turnon(flgs, VERBOSE);
X#endif /* VERBOSE_ARG */
X *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
X if (lower(firstchar) == 'r') {
X char *in_reply_fmt, *pcc = NULL;
X to = To, cc = Cc;
X /*
X * Generate a reply to all the messages passed to respond(). This
X * list is different than the include-msg list above. Get info about
X * whom the messages were sent to for reply-all.
X * BUG: currently, redundant addresses aren't pruned from Bcc list!
X */
X for (n = 0; n < msg_cnt; n++)
X if (msg_bit(list, n)) {
X if (to != To)
X *to++ = ',', *to++ = ' ';
X (void) reply_to(n, (firstchar == 'R'), buf);
X if (strlen(buf) + (to - To) > sizeof(To) - 1) {
X wprint("# recipients exceeded at msg %d\n", n);
X break;
X }
X to += Strcpy(to, buf);
X if (firstchar == 'R') {
X if (pcc = cc_to(n, buf)) {
X /* if there was a previous cc, append ", " */
X if (cc != Cc)
X *cc++ = ',', *cc++ = ' ';
X if (strlen(pcc) + (cc - Cc) > sizeof(Cc) - 1)
X wprint("# Cc's exceeded at msg %d\n", n);
X else
X cc += Strcpy(cc, pcc);
X }
X }
X /* remove redundant addresses now, or headers could get too
X * long before the list runs out (it still might)
X */
X rm_redundant_addrs(To, Cc);
X to = To + strlen(To);
X cc = Cc + strlen(Cc);
X }
X /* clean up end of Cc line for replyall's */
X while (*cc == ' ' || *cc == ',')
X *cc-- = '\0';
X if (firstchar == 'R' && !do_set(set_options, "metoo")) {
X /* Each reply_to() call above will leave at least
X * one person in To. If that one person was us,
X * we need to get removed from the complete list.
X */
X (void) take_me_off(to);
X }
X to = To, cc = Cc;
X if (route || (route = do_set(set_options, "auto_route")))
X /* careful! This routine could add lots-o-bytes and lose addresses
X * to avoid writing out of segment.
X */
X route_addresses(To, Cc, route);
X if (in_reply_fmt = do_set(set_options, "in_reply_to"))
X /* "9" here is a magic # --see compose_hdr() */
X (void) strcpy(in_reply_to,
X format_hdr(current_msg, in_reply_fmt, FALSE)+9);
X }
X if (ison(flgs, FORWARD) && ison(flgs, EDIT) ||
X lower(firstchar) == 'r' && isoff(flgs, NEW_SUBJECT)) {
X turnoff(flgs, NEW_SUBJECT);
X if (subj && *subj && (isoff(flgs, FORWARD) || ison(flgs, EDIT)))
X subj = strcpy(Subject, subj);
X else if (subj = subject_to(current_msg, buf))
X subj = strcpy(Subject, buf + 4*(lower(firstchar) != 'r'));
X } else if (isoff(flgs, NEW_SUBJECT) && isoff(flgs, FORWARD) &&
X (do_set(set_options, "ask") || do_set(set_options, "asksub")))
X turnon(flgs, NEW_SUBJECT);
X if (argv && *argv) {
X char buf[HDRSIZ];
X (void) argv_to_string(buf, argv);
X fix_up_addr(buf);
X to = &To[strlen(To)];
X if (*To)
X *to++ = ',', *to++ = ' ';
X (void) strcpy(to, buf);
X to = To;
X }
X if (addcc && *addcc) {
X cc = &Cc[strlen(Cc)];
X if (*Cc)
X *cc++ = ',', *cc++ = ' ';
X (void) strcpy(cc, addcc); /* addcc has already been fixed up */
X cc = Cc;
X }
X /* remove any redundant addresses that just got added */
X rm_redundant_addrs(To, Cc);
X if (bcc && *bcc)
X (void) strncpy(Bcc, bcc, sizeof(Bcc)); /* bcc already fixed up */
X bcc = Bcc;
X
X return mail_someone(to, subj, cc, bcc, flgs, inc_list);
X}
X
Xstatic
Xmail_someone(to, subject, cc, bcc, flgs, list)
Xregister char *to, *subject, *cc, *bcc, *list;
Xu_long flgs;
X{
X register char *p;
X
X flags = flgs;
X if (to && *to) {
X if (!*To)
X (void) strncpy(To, to, sizeof(To));
X } else
X to = NO_STRING;
X if (subject && *subject) {
X if (!*Subject)
X (void) strncpy(Subject, subject, sizeof(Subject));
X } else
X subject = NO_STRING;
X if (cc && *cc) {
X if (!*Cc)
X (void) strncpy(Cc, cc, sizeof(Cc));
X } else
X Cc[0] = '\0';
X if (bcc && *bcc) {
X if (!*Bcc)
X (void) strncpy(Bcc, bcc, sizeof(Bcc));
X } else
X Bcc[0] = '\0';
X
X if (ison(glob_flags, REDIRECT)) {
X /*
X * NOTE: Could change this to finish_up_letter() to allow
X * signatures to be appended. The -U! option to mush would
X * be extended to suppress signing when redirection is on.
X */
X int sent = send_it();
X if (sent == -1) {
X wprint("Message not sent!\n");
X rm_edfile(-1);
X }
X return sent;
X }
X /* if (!*to) then prompting will be done */
X if (!istool && !hfile) {
X if (p = set_header("To: ", to, !*to)) {
X if (!*to) /* if user typed To-line here, fix up the addresses */
X fix_up_addr(p);
X (void) strcpy(To, p);
X }
X if (!*To && ison(flags, FORWARD) && ison(flags, SEND_NOW)) {
X turnoff(flags, SEND_NOW); /* user must edit To: line or do again */
X print("(You must add a To: address.)\n");
X }
X /* don't prompt for subject if forwarding mail */
X if (isoff(flags, FORWARD) && (*subject || ison(flags, NEW_SUBJECT)) &&
X (p = set_header("Subject: ", subject,
X !*subject && ison(flags, NEW_SUBJECT))))
X (void) strcpy(Subject, p);
X if (*Cc || ison(flags, EDIT_HDRS) && do_set(set_options, "askcc")) {
X if ((p = set_header("Cc: ", cc, !*Cc)) && *p) {
X fix_up_addr(p);
X (void) strcpy(Cc, p);
X }
X }
X if (*Bcc)
X print("Bcc: %s\n", Bcc);
X putchar('\n');
X }
X
X /* If forwarding w/o editing, start a new file for each. */
X if (ison(flags, FORWARD) && ison(flags, SEND_NOW)) {
X char fwd[MAXMSGS_BITS];
X register int i;
X clear_msg_list(fwd);
X for (i = 0; i < msg_cnt; i++)
X if (msg_bit(list, i)) {
X set_msg_bit(fwd, i);
X if (start_file(fwd) < 0)
X return -1;
X turnon(msg[i].m_flags, FORWARD);
X if (isoff(glob_flags, READ_ONLY))
X turnon(glob_flags, DO_UPDATE);
X clear_msg_list(fwd);
X }
X } else
X return start_file(list);
X return 0;
X}
X
Xstatic
Xstart_file(list)
Xchar *list;
X{
X register char *dir;
X register int i;
X char line[MAXPATHLEN];
X int had_hfile = FALSE;
X
X /* getdir() uses the home directory if no tmpdir */
X if (!(dir = getdir(do_set(set_options, "tmpdir"))))
Xalted:
X dir = ALTERNATE_HOME;
X (void) mktemp(sprintf(line, "%s/%s", dir, EDFILE));
X strdup(edfile, line);
X if (!(ed_fp = mask_fopen(edfile, "w+"))) {
X if (strcmp(dir, ALTERNATE_HOME))
X goto alted;
X error("can't create %s", edfile);
X return -1;
X }
X if (!istool) {
X oldint = signal(SIGINT, rm_edfile);
X oldquit = signal(SIGQUIT, rm_edfile);
X oldterm = signal(SIGTERM, rm_edfile);
X }
X
X if (istool && isoff(flags, SEND_NOW) ||
X (isoff(flags, FORWARD) || isoff(flags, SEND_NOW)) &&
X (ison(flags, EDIT_HDRS) || do_set(set_options, "edit_hdrs"))) {
X turnon(flags, EDIT_HDRS);
X if (hfile)
X had_hfile = TRUE;
X if (add_headers(NULL_FILE, &ed_fp, 1, flags) == (long) -1)
X return -1;
X }
X if (Hfile) {
X (void) file_to_fp(Hfile, ed_fp, "r");
X Hfile = NULL;
X had_hfile = TRUE;
X }
X if (istool && isoff(flags, SEND_NOW))
X strdup(hfile, edfile);
X
X /* if flags call for it, include current message (with header?) */
X if (ison(flags, INCLUDE|FORWARD|INCLUDE_H)) {
X long copy_flgs = 0, is_forw = ison(flags, FORWARD);
X char buf[sizeof(To)];
X if (!is_forw) {
X turnon(copy_flgs, INDENT);
X if (ison(flags, INCLUDE_H) &&
X !chk_option("alwaysignore", "include"))
X turnon(copy_flgs, NO_IGNORE);
X else if (ison(flags, INCLUDE))
X turnon(copy_flgs, NO_HEADER);
X } else if (ison(flags, SEND_NOW) ||
X !chk_option("alwaysignore", "forward"))
X turnon(copy_flgs, FORWARD); /* FORWARD implies NO_IGNORE */
X#ifdef MSG_SEPARATOR
X turnon(copy_flgs, NO_SEPARATOR);
X#endif /* MSG_SEPARATOR */
X for (i = 0; i < msg_cnt; i++)
X if (msg_bit(list, i)) {
X if (is_forw && isoff(flags, SEND_NOW)) {
X (void) reply_to(i, FALSE, buf);
X (void) fprintf(ed_fp,"--- Forwarded mail from %s\n\n",buf);
X }
X wprint("%sing message %d ...",
X is_forw? "forward" : "includ", i+1);
X wprint("(%d lines)\n",
X copy_msg(i, ed_fp, (u_long) copy_flgs, NULL));
X set_isread(i); /* if we included it, we read it, right? */
X if (is_forw && isoff(flags, SEND_NOW))
X (void) fprintf(ed_fp,
X "\n--- End of forwarded message from %s\n", buf);
X if (!is_forw || isoff(flags, SEND_NOW))
X (void) fputc('\n', ed_fp);
X }
X (void) fflush(ed_fp);
X }
X if (!istool && ison(glob_flags, WARNING)) {
X if (escape && strncmp(escape, DEF_ESCAPE, 1))
X print("(escape character is set to `%c')\n", *escape);
X if (wrapcolumn && wrapcolumn < 20)
X print("(warning: wrapping only %d columns from the left!)\n",
X wrapcolumn);
X }
X
X /* do an "if" again in case editor not found and EDIT turned off */
X if (!istool && ison(flags, EDIT)) {
X char **argv, *edit;
X int argc;
X if ((!(edit = do_set(set_options, "visual")) || !*edit) &&
X (!(edit = do_set(set_options, "editor")) || !*edit))
X edit = DEF_EDITOR;
X (void) sprintf(line, "%s %s", edit, edfile);
X if ((argv = mk_argv(line, &argc, FALSE)) && argc > 0) {
X print("Starting \"%s\"...\n", argv[0]);
X (void) fclose(ed_fp);
X ed_fp = NULL_FILE;
X execute(argv);
X free_vec(argv);
X turnoff(flags, EDIT);
X turnoff(flags, FORWARD); /* forwarded messages must be unedited */
X /* upon exit of editor, user must now type eofc or "." to send */
X if (!(ed_fp = fopen(edfile, "r+"))) {
X error("can't reopen %s", edfile);
X return -1;
X }
X (void) fseek(ed_fp, 0L, 2);
X } else
X print("Unable to start \"%s\"\n", edit);
X wprint("(continue editing letter or ^%c to send)\n", eofc + '@');
X } else if (ison(flags, SEND_NOW)) {
X /* if finish_up_letter() was successful, file was successfully sent. */
X if (!setjmp(cntrl_c_buf) && finish_up_letter() == 0) {
X rm_edfile(0);
X return 0;
X }
X } else if (had_hfile) {
X /* it's not obvious what's going on -- enlighten user */
X wprint("(continue editing or ^%c to send)\n", eofc + '@');
X }
X
X#ifdef SUNTOOL
X if (istool) {
X /* toolmode doesn't care if SEND_NOW -- user continues to edit file.
X * if SEND_NOW is not set, then the editor file has just been started,
X * so again, just return so user can edit file.
X */
X if (ed_fp)
X fclose(ed_fp), ed_fp = NULL_FILE;
X turnon(glob_flags, IS_GETTING);
X return 0;
X }
X#endif /* SUNTOOL */
X if (ison(flags, SEND_NOW)) {
X /* editing couldn't have been on -- finish_up_letter() failed */
X rm_edfile(0 - ison(flags, FORWARD));
X return -1;
X }
X
X i = 0;
X turnon(glob_flags, IS_GETTING);
X do {
X /* If the user hits ^C in cbreak mode, mush will return to
X * Getstr and not clear the buffer. whatever is typed next will
X * be appended to the line. jumping here will force the line to
X * be cleared cuz it's a new call.
X */
X (void) setjmp(cntrl_c_buf);
X while (Getstr(line, sizeof(line), 0) > -1) {
X if (!istool) /* toolmode checks on a timer -- don't do it here */
X (void) check_new_mail(); /* if new mail comes in, get it */
X if ((i = add_to_letter(line)) <= 0)
X break;
X }
X } while (i >= 0 && finish_up_letter() == -1);
X turnoff(glob_flags, IS_GETTING);
X return i; /* return -1 if ~x or ~q to terminate letter */
X}
X
Xchar *tilde_commands[] = {
X "commands: [OPTIONAL argument]",
X "t [list]\tChange list of recipients",
X "s [subject]\tModify [set] subject header",
X "c [cc list]\tModify [set] carbon copy recipients",
X "b [bcc list]\tModify [set] blind carbon recipients",
X "h\t\tModify all message headers",
X "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
X "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
X "u\t\tEdit previous (last) line in file.",
X "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
X "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
X "I [msg#'s]\tSame, but include the message headers from included messages",
X "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
X "S[!]\t\tInclude Signature file [suppress file]",
X "F[!]\t\tAdd a fortune at end of letter [don't add]",
X "w file\t\tWrite msg buffer to file name",
X "a file\t\tAppend msg buffer to file name",
X "r file\t\tRead filename into message buffer",
X "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
X "x \t\tQuit message; don't save in dead.letter.",
X "$variable\tInsert the string value for \"variable\" into message.",
X ":cmd\t\tRun the mail command \"cmd\".",
X "|cmd\t\tPipe the message through the unix command \"cmd\".",
X "E[!]\t\tClear contents of letter after saving to dead.letter [unless !].",
X 0
X};
X
X/*
X * TC_EDIT(tc) returns TRUE if tilde_command[tc] involves message
X * editing operations. Used when EDIT_HDRS is active.
X */
X#define TC_EDIT(tc) ((tc) && ((tc) < 6 || !tilde_commands[(tc)+1]))
X
X/*
X * Add the line (char *) parameter to the letter. Determine tilde
X * escapes and determine what to do. This function returns 0 to
X * indicate user wants to end the letter, -1 if the letter cannot
X * be sent (~q, ~x no buffer after editor, etc...) or 1 to indicate
X * successful addition of the line to the letter.
X * This function may be called by toolmode just to change certain mush
X * internal variables via tilde escapes. Thus, ed_fp might be null.
X */
Xadd_to_letter(line)
Xchar line[];
X{
X register char *p;
X char buf[HDRSIZ > MAXPATHLEN ? HDRSIZ : MAXPATHLEN];
X
X killme = 0;
X if (ed_fp) /* may be null if istool */
X (void) fseek(ed_fp, 0L, 2);
X
X if (!strcmp(line, ".") && do_set(set_options, "dot"))
X return 0;
X if (line[0] != *escape) {
X (void) fputs(line, ed_fp);
X (void) fputc('\n', ed_fp);
X (void) fflush(ed_fp);
X return 1;
X }
X /* all commands are "~c" (where 'c' is the command). set p = first
X * character after 'c' and skip whitespace
X */
X p = &line[2];
X skipspaces(0);
X switch (line[1]) {
X case 'v' : case 'p': case 'e' : case '|' : {
X if (!*p || *p == 'i')
X switch (line[1]) {
X case 'p' :
X if (!*p && !(p = do_set(set_options, "pager")))
X p = DEF_PAGER;
X if (!*p || !strcmp(p, "internal"))
X p = NULL;
X when 'v' :
X if (*p && p[1] || (p = do_set(set_options, "visual")))
X break;
X /* else fall through */
X default :
X if (!(p = do_set(set_options, "editor")) || !*p)
X p = DEF_EDITOR;
X when '|' :
X print("No command for pipe\n");
X return 1;
X }
X if (line[1] == 'p' || line[1] == '|')
X rewind(ed_fp);
X if (line[1] == 'p') {
X (void) do_pager(p, TRUE); /* start the pager "p" */
X if (isoff(flags, EDIT_HDRS)) {
X (void) do_pager(sprintf(buf, "To: %s\n", To), FALSE);
X if (Subject[0])
X (void) do_pager(sprintf(buf, "Subject: %s\n", Subject),
X FALSE);
X if (Cc[0])
X (void) do_pager(sprintf(buf, "Cc: %s\n", Cc), FALSE);
X if (Bcc[0])
X (void) do_pager(sprintf(buf, "Bcc: %s\n", Bcc), FALSE);
X (void) do_pager(strcpy(buf,
X "--------\nMessage contains:\n"),
X FALSE);
X }
X while (fgets(buf, sizeof(buf), ed_fp))
X if (do_pager(buf, FALSE) == EOF)
X break;
X (void) do_pager(NULL, FALSE); /* end pager */
X } else if (line[1] == '|') {
X FILE *pipe_fp;
X (void) sprintf(buf, "( %s ) > %s", p, edfile);
X if (unlink(edfile) < 0) {
X error("Can't unlink %s:", edfile);
X break; /* Drop out of switch */
X }
X if ((pipe_fp = popen(buf, "w")) == NULL_FILE) {
X error("Can't run \"%s\":", p);
X (void) file_to_fp(edfile, ed_fp, "w");
X } else {
X while (fgets(buf, sizeof(buf), ed_fp))
X if (fputs(buf, pipe_fp) == EOF) {
X print("Broken pipe\n");
X break;
X }
X (void) pclose(pipe_fp);
X }
X pipe_fp = ed_fp; /* save ed_fp until we can reopen it */
X if (!(ed_fp = fopen(edfile, "r+"))) {
X error("can't reopen %s", edfile);
X (void) rewind(pipe_fp);
X if (file_to_fp(edfile, pipe_fp, "w") < 0 ||
X !(ed_fp = fopen(edfile, "r+"))) {
X error("can't restore old contents of %s", edfile);
X ed_fp = pipe_fp;
X dead_letter(0);
X return -1;
X }
X }
X (void) fclose(pipe_fp);
X } else {
X char **argv;
X int argc;
X (void) sprintf(buf, "%s %s", p, edfile);
X if ((argv = mk_argv(buf, &argc, FALSE)) && argc > 0) {
X (void) fclose(ed_fp);
X ed_fp = NULL_FILE;
X execute(argv);
X free_vec(argv);
X /* tool will return even tho editor isn't done */
X if (!(ed_fp = fopen(edfile, "r+"))) {
X error("can't reopen %s", edfile);
X return -1;
X }
X } else
X print("Unable to start \"%s\"\n", p);
X }
X }
X when '$': {
X register char *p2;
X if (!(p2 = do_set(set_options, p)))
X print("(%s isn't set)\n", p);
X else
X putstring(p2, ed_fp);
X }
X when ':': {
X char new[MAXMSGS_BITS];
X u_long save_flags = glob_flags;
X
X turnon(glob_flags, IGN_SIGS);
X turnoff(glob_flags, DO_PIPE);
X turnoff(glob_flags, IS_PIPE);
X (void) cmd_line(p, new);
X glob_flags = save_flags;
X }
X when 'i': case 'f': case 'I': case 'm': {
X int n;
X u_long copy_flgs = 0;
X char list[MAXMSGS_BITS];
X
X if (!msg_cnt) {
X wprint("No messages.\n");
X break;
X }
X clear_msg_list(list);
X if (line[1] != 'f') {
X turnon(copy_flgs, INDENT);
X if (line[1] == 'i')
X turnon(copy_flgs, NO_HEADER);
X else if (!chk_option("alwaysignore", "include"))
X turnon(copy_flgs, NO_IGNORE);
X } else if (!chk_option("alwaysignore", "forward"))
X turnon(copy_flgs, NO_IGNORE);
X#ifdef MSG_SEPARATOR
X turnon(copy_flgs, NO_SEPARATOR);
X#endif /* MSG_SEPARATOR */
X if (!*p)
X set_msg_bit(list, current_msg);
X else if (!do_range(p, list))
X return 1;
X for (n = 0; n < msg_cnt; n++)
X if (msg_bit(list, n)) {
X if (line[1] == 'f') {
X (void) reply_to(n, FALSE, buf);
X (void) fprintf(ed_fp,
X "--- Forwarded mail from %s\n\n", buf);
X }
X wprint("Including message %d ... ", n+1);
X wprint("(%d lines)\n", copy_msg(n, ed_fp, copy_flgs, NULL));
X set_isread(n);
X if (line[1] == 'f')
X (void) fprintf(ed_fp,
X "\n--- End of forwarded message from %s\n\n", buf);
X else
X (void) fputc('\n', ed_fp);
X }
X }
X /* To: Cc: and Bcc: headers */
X when 'b':
X case 't':
X case 'c': {
X char *h = (line[1] == 't')? To : (line[1] == 'c')? Cc : Bcc;
X char *Prompt = line[1] == 't'? "To: " :
X line[1] == 'c'? "Cc: " : "Bcc: ";
X if (ison(flags, EDIT_HDRS)) {
X print("You must use an editor to change your headers.\n");
X break;
X }
X
X if (*p) {
X fix_up_addr(p);
X if (*h)
X (void) sprintf(h+strlen(h), ", %s", p);
X else
X (void) strcpy(h, p);
X } else if (!(p = set_header(Prompt, h, TRUE)) || !*p)
X *h = 0;
X else {
X fix_up_addr(p);
X (void) strcpy(h, p);
X }
X }
X when 's':
X if (ison(flags, EDIT_HDRS)) {
X print("You must use an editor to change your headers.\n");
X break;
X }
X if (*p || (p = set_header("Subject: ", Subject, 1)))
X if (!*p)
X Subject[0] = 0;
X else
X (void) strcpy(Subject, p);
X when 'h':
X if (ison(flags, EDIT_HDRS)) {
X print("You must use an editor to change your headers.\n");
X break;
X }
X while ((p = set_header("To: ", To, 1)) && !*p)
X print("(There must be a recipient.)\n");
X (void) strcpy(To, p);
X if (p = set_header("Subject: ", Subject, 1))
X if (!*p)
X Subject[0] = 0;
X else
X (void) strcpy(Subject, p);
X if (p = set_header("Cc: ", Cc, 1))
X if (!*p)
X Cc[0] = 0;
X else {
X fix_up_addr(p);
X (void) strcpy(Cc, p);
X }
X if (p = set_header("Bcc: ", Bcc, 1))
X if (!*p)
X Bcc[0] = 0;
X else {
X fix_up_addr(p);
X (void) strcpy(Bcc, p);
X }
X when 'F': case 'S' : {
X if (*p == '!')
X turnoff(flags, line[1] == 'F'? DO_FORTUNE : SIGN);
X else
X turnon(flags, line[1] == 'F'? DO_FORTUNE : SIGN);
X wprint("%sadding %s at end of message.\n", *p == '!'? "not " : "",
X line[1] == 'F'? "fortune" : "signature");
X }
X when 'w': case 'a': case 'r':
X if (!*p) {
X print("(you must specify a filename)\n");
X return 1;
X }
X (void) fseek(ed_fp, 0L, 2); /* append */
X (void) file_to_fp(p, ed_fp, (line[1] == 'r')? "r":
X (line[1] == 'w')? "w": "a");
X /* go up one line in the message file and allow the user to edit it */
X when 'u': {
X long newpos, pos = ftell(ed_fp);
X char oldline[256];
X if (pos <= 0L) { /* pos could be -1 if ftell() failed */
X print("(No previous line in file.)\n");
X return 1;
X }
X /* get the last 256 bytes written and read backwards from the
X * current place until '\n' is found. Start by moving past the
X * first \n which is at the end of the line we want to edit
X */
X newpos = max(0, pos - 256L);
X (void) fseek(ed_fp, newpos, L_SET);
X /* don't fgets -- it'll stop at a \n */
X (void) fread(line, sizeof(char), (int)(pos-newpos), ed_fp);
X pos--;
X /* the last char in line should be a \n cuz it was last input */
X if (line[(int)(pos-newpos)] != '\n')
X print("I don't know how, but your last line ended with %c.\n",
X line[(int)(pos-newpos)]);
X else
X line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
X for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
X ;
X /* we've gone back to the end of the second previous line. Check
X * to see if the char we're pointing to is a \n. It should be, but
X * if it's not, we moved back to the first line of the file.
X */
X if (line[(int)(pos-newpos)] == '\n')
X ++pos;
X /* save the old line that's there in case the user boo-boos */
X (void) strcpy(oldline, &line[(int)(pos-newpos)]);
X /* let set header print out the line and get the input */
X if (!(p = set_header("", &line[(int)(pos-newpos)], TRUE))) {
X print("Something bad happened and I don't know what it is.\n");
X p = oldline;
X } else if (*p == *escape)
X print("(Warning: %c escapes ignored on %cu lines.)\n",
X *escape, *escape);
X /* seek to to the position where the new line will go */
X (void) fseek(ed_fp, pos, L_SET);
X /* put the newly typed line */
X (void) fputs(p, ed_fp); /* don't add \n. padding may be necessary */
X /* if the new line is less than the old line, we're going to do
X * one of two things. The best thing to do is to truncate the
X * file to the end of the new line. Sys-v can't do that, so we
X * pad the line with blanks. May be messy in some cases, but...
X */
X if ((pos = strlen(p) - strlen(oldline)) < 0) {
X#ifndef SYSV
X /* add the \n, flush the file, truncate to the current pos */
X (void) fputc('\n', ed_fp);
X (void) fflush(ed_fp);
X (void) ftruncate(fileno(ed_fp), (off_t) ftell(ed_fp));
X#else /* SYSV */
X /* pad with blanks to the length of the old line. add \n */
X while (pos++ < 0)
X (void) fputc(' ', ed_fp);
X (void) fputc('\n', ed_fp), (void) fflush(ed_fp);
X#endif /* SYSV */
X } else {
X /* the new line is >= the old line, add \n -- no trunc req. */
X (void) fputc('\n', ed_fp);
X (void) fflush(ed_fp);
X }
X return 1;
X }
X /* break; not here cuz of "return" (lint). */
X case 'E':
X if (ison(flags, EDIT_HDRS)) {
X print("You must use an editor to empty the message buffer.\n");
X break;
X }
X if (*p != '!' && !do_set(set_options, "nosave"))
X dead_letter(0);
X if (emptyfile(&ed_fp, edfile) == -1)
X error(edfile);
X else
X print("Message buffer empty\n");
X when 'q':
X /* save in dead.letter if nosave not set -- rm_edfile(-2). */
X rm_edfile(-2); /* doesn't return out of tool mode */
X return -1;
X /* break; not stated cuz of "return" (lint) */
X case 'x':
X /* don't save dead.letter -- simulate normal rm_edfile() call */
X rm_edfile(0);
X return -1;
X /* break; (not specified for lint) */
X default:
X if (line[1] == *escape) {
X (void) fputs(&line[1], ed_fp);
X (void) fputc('\n', ed_fp);
X (void) fflush(ed_fp);
X return 1;
X } else if (line[1] == '?') {
X register int x;
X (void) do_pager(NULL, TRUE); /* start pager */
X for (x = 0; tilde_commands[x]; x++) {
X if (ison(flags, EDIT_HDRS) && TC_EDIT(x))
X continue;
X (void) sprintf(buf, "%s%s\n", escape, tilde_commands[x]);
X if (do_pager(buf, FALSE) == EOF)
X break;
X }
X if (tilde_commands[x] == NULL) {
X (void) sprintf(buf,
X "%s%s\t\tBegin a line with a single %s\n",
X escape, escape, escape);
X (void) do_pager(buf, FALSE);
X }
X (void) do_pager(NULL, FALSE); /* end pager */
X } else
X print("`%c': unknown %c escape. Use %c? for help.\n",
X line[1], *escape, *escape);
X return 1;
X }
X if (ed_fp)
X (void) fseek(ed_fp, 0L, 2);
X if (!istool)
X wprint("(continue editing letter)\n");
X return 1;
X}
X
X/*
X * finish up the letter. ask for the cc line, if verify is set, ask to
X * verify sending, continue editing, or to dump the whole idea.
X * Then check for signature and fortune. Finally, pass it to send_it()
X * to actually send it off.
X * Return 0 on success, -1 on failure.
X */
Xstatic int
Xfinish_up_letter()
X{
X register char *p;
X int c;
X char buf[MAXPATHLEN];
X
X /* forwarded mail has no additional personalized text */
X if (ison(flags, FORWARD)) {
X if (send_it() == -1) {
X wprint("Message not sent!\n");
X return -1;
X }
X turnoff(glob_flags, IS_GETTING);
X return 0;
X }
X
X /* REDIRECT should never be on here, but just in case */
X if (isoff(glob_flags, REDIRECT)) {
X if (!istool) {
X if (isoff(flags, EDIT_HDRS) && do_set(set_options, "askcc")) {
X if (p = set_header("Cc: ", Cc, 1))
X (void) strcpy(Cc, p);
X }
X }
X /* ~v on the Cc line asks for verification, first initialize p! */
X p = NULL;
X if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
X if (!p) /* so we don't Cc to ~v! */
X *Cc = 0;
X for (;;) {
X#ifdef SUNTOOL
X if (istool)
X c = (ask("Send Message?") == TRUE)? 's' : 'c';
X else
X#endif /* SUNTOOL */
X {
X print("send, continue editing, discard [s,c,d]? ");
X c = Getstr(buf, sizeof(buf), 0);
X if (c < 0)
X putchar('\n');
X else if (!istool)
X c = lower(*buf);
END_OF_FILE
if test 30778 -ne `wc -c <'mush/mail.c.a'`; then
echo shar: \"'mush/mail.c.a'\" unpacked with wrong size!
fi
# end of 'mush/mail.c.a'
fi
echo shar: End of archive 9 \(of 19\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 19 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0