static char rcsid[] = "@(#)$Id: editmsg.c,v 1.50 2006/05/30 16:33:21 hurtta Exp $";
/*****************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.50 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
*****************************************************************************
* The Elm Mail System
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*****************************************************************************/
/** This contains routines to do with starting up and using an editor (or two)
from within Elm. This stuff used to be in mailmsg2.c...
**/
#include "def_elm.h"
#include "s_elm.h"
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
DEBUG_VAR(Debug,__FILE__,"misc");
/* The built-in editor is not re-entrant! */
static int builtin_editor_active = FALSE;
static char *simple_continue = NULL;
int interrupts_while_editing; /* keep track 'o dis stuff */
JMP_BUF edit_location; /* for getting back from interrupt */
struct builtin_edit {
struct mailing_headers * headers;
FILE * edit_fd;
char * filename;
charset_t file_set;
struct MailboxView * mailbox; /* needed for system_call() */
};
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static void tilde_help P_((void));
static void tilde_help()
{
/* a simple routine to print out what is available at this level */
struct menu_context *page = new_menu_context();
int LINES, COLUMNS;
redraw:
if (menu_resized(page) ||
menu_need_redraw(page))
/* Nothing */;
menu_get_sizes(page, &LINES, &COLUMNS);
menu_ClearScreen(page);
StartInverse();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinEditorHelp,
"Help for builtin editor"));
EndInverse();
NewLine();
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgAvailOpts,
"\n\r(Available options at this point are:\n\r\n\r"));
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgHelpMenu,
"\t%c?\tPrint this help menu.\n\r"),
escape_char);
if (escape_char == TILDE_ESCAPE) /* doesn't make sense otherwise... */
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgAddLine,
"\t~~\tAdd line prefixed by a single '~' character.\n\r"));
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgBCC,
"\t%cb\tChange the addresses in the Blind-carbon-copy list.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgCC,
"\t%cc\tChange the addresses in the Carbon-copy list.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgEmacs,
"\t%ce\tInvoke the Emacs editor on the message, if possible.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgAddMessage,
"\t%cf\tAdd the specified message or current.\n\r"),
escape_char);
#if 0
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgToCCBCC,
"\t%ch\tChange all available headers (to, cc, bcc, subject).\n\r"),
escape_char);
#endif
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgSameCurrentPrefix,
"\t%cm\tSame as '%cf', but with the current 'prefix'.\n\r"),
escape_char, escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgUserEditor,
"\t%co\tInvoke a user specified editor on the message.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgPrintMsgHdr,
"\t%cp\tPrint out message headers.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgReadFile,
"\t%cr\tRead in the specified file.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgSubject,
"\t%cs\tChange the subject of the message.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgTo,
"\t%ct\tChange the addresses in the To list.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgVi,
"\t%cv\tInvoke the Vi visual editor on the message.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgUnixCmd,
"\t%c!\tExecute a UNIX command (or give a shell if no command).\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgAddUnixCmd,
"\t%c<\tExecute a UNIX command adding the output to the message.\n\r"),
escape_char);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgEndMsg,
"\t. \tby itself on a line (or a control-D) ends the message.\n\r"));
menu_PutLineX(page,LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpPressRet,
"Press any key to return..."));
if (REDRAW_MARK == menu_ReadCh(page,REDRAW_MARK))
goto redraw;
erase_menu_context(&page);
return;
}
static void read_in_file P_((struct enter_info *I,
char *filename,
int show_user_filename));
static void redraw_editor P_((struct enter_info *I));
static void add_to_vector P_((struct enter_info *I, struct string *str));
static void read_in_file(I, filename, show_user_filename)
struct enter_info *I;
char *filename;
int show_user_filename;
{
/** Open the specified file and stream it in to the already opened
file descriptor given to us. When we're done output the number
of lines and characters we added, if any... **/
FILE *myfd;
char exp_fname[SLEN], buffer[LONG_STRING];
int n;
int lines = 0, nchars = 0;
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
while (whitespace(*filename))
++filename;
/** expand any shell variables or leading '~' **/
(void) expand_env(exp_fname, filename, sizeof(exp_fname));
if (exp_fname[0] == '\0') {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNoFilenameSpecified,
"(No filename specified for file read! Continue.)"));
return;
}
if (can_open(exp_fname,"r") != 0 ||
(myfd = fopen(exp_fname,"r")) == NULL) {
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmCouldntReadFile,
"(Couldn't read file '%s'! Continue.)"),
exp_fname);
return;
}
/* system charset assumend on file */
while (0 < (n =
mail_gets(buffer, SLEN, myfd))) {
struct string * str;
if(buffer[n-1] == '\n') {
buffer[n-1] = '\0';
lines++;
}
nchars += n;
str = new_string2(system_charset,s2us(buffer));
add_to_vector(I,str);
}
fclose(myfd);
I->py = I->counter-1;
redraw_editor(I);
MoveCursor(LINES-1,0);
if (lines == 1)
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedLine,
"(Added 1 line ["));
else
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedLinePlural,
"(Added %d lines ["), lines);
if (nchars == 1)
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedChar,
"1 char] "));
else
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedCharPlural,
"%d chars] "), nchars);
if (show_user_filename)
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedFromFile,
"from file %s. Continue.)"),
exp_fname);
else
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedToMessage,
"to message. Continue.)"));
return;
}
static void read_in_messages P_((struct enter_info *I));
static void read_in_messages(I)
struct enter_info *I;
{
/** Read the specified messages into the open file. If the
first character of "buffer" is 'm' then prefix it, other-
wise just stream it in straight...Since we're using the
pipe to 'readmsg' we can also allow the user to specify
patterns and such too...
**/
char * readmsg_v = give_dt_estr_as_str(&readmsg_e, "readmsg");
char * local_buffer;
int add_prefix=0, mindex,res,retcode;
int n;
int lines = 0, nchars = 0;
struct run_state RS;
CONST char * argv[4];
uint16 ch = give_unicode_from_string(I->pvector[0],0);
int X;
struct string * arg;
char local_buffer1[LONG_STRING];
int LINES, COLUMNS;
if (!readmsg_v) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantFindReadmsg,
"(Can't find 'readmsg' command! Continue.)"));
return;
}
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
switch (ch) {
case 0x006D: /* 'm' */
case 0x004D: /* 'M' */
add_prefix = 1;
break;
default:
add_prefix = 0;
break;
}
/* strip whitespace to get argument */
for (X = 1; X < string_len(I->pvector[0]); X ++) {
ch = give_unicode_from_string(I->pvector[0],X);
if (0x0009 /* HT */ != ch &&
0x0020 /* SPACE */ != ch)
break;
}
/* a couple of quick checks */
if(get_message_count(I->builtin->mailbox) < 1) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoMessageReadContinue,
"(No messages to read in! Continue.)"));
return;
}
/* clip_from_string updates X */
arg = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
if (ch >= 0x0030 /* '0' */ &&
ch <= 0x0039 /* '9' */) {
int bad_pos;
if((mindex = string_to_long(arg,&bad_pos)) < 1 ||
mindex > get_message_count(I->builtin->mailbox) || bad_pos >= 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmValidNumbersBetween,
"(Valid message numbers are between 1 and %d. Continue.)\n\r"),
get_message_count(I->builtin->mailbox));
free_string(&arg);
return;
}
}
/* dump state information for "readmsg" to use
* -- start_run() does not support SY_DUMPSTATE
*/
if (create_folder_state_file(I->builtin->mailbox) != 0)
return;
/* go run readmsg and get output */
local_buffer = elm_message(FRM("%s -- %S"), readmsg_v, arg);
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = local_buffer;
argv[3] = NULL;
free_string(&arg);
res = start_run(&RS,
SY_ENAB_SIGHUP|SY_ENAB_SIGINT|
SY_RUN_STATE_OPIPE,argv,-1,-1);
DPRINT(Debug,5,(&Debug,
"** readmsg call: \"%s\" **\n", local_buffer));
if (0 == res) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantFindReadmsg,
"(Can't find 'readmsg' command! Continue.)"));
(void) remove_folder_state_file();
free(local_buffer);
return;
}
/* system charset assumed on command */
while (0 < (n =
mail_gets(local_buffer1, sizeof local_buffer1, RS.pfd))) {
struct string * str;
nchars += n;
if (local_buffer1[n-1] == '\n') {
lines++;
local_buffer1[n-1] = '\0';
}
str = new_string2(system_charset,s2us(local_buffer1));
if (add_prefix) {
/* prefixchars probably is added with wrong charset ... */
add_to_vector(I,format_string(FRM("%s%S"),prefixchars,str));
free_string(&str);
} else {
add_to_vector(I,str);
}
}
res = wait_end(&RS,&retcode);
(void) remove_folder_state_file();
free(local_buffer);
I->py = I->counter-1;
redraw_editor(I);
if (lines == 0 || res < 0 || retcode != 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgCouldntAdd,
"(Couldn't add the requested message. Continue.)"));
return;
}
MoveCursor(LINES-1,0);
if (lines == 1)
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedLine,
"(Added 1 line ["));
else
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedLinePlural,
"(Added %d lines ["), lines);
if (nchars == 1)
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedChar,
"1 char] "));
else
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedCharPlural,
"%d chars] "), nchars);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmAddedToMessage,
"to message. Continue.)"));
return;
}
static SIGHAND_TYPE edit_interrupt P_((int sig));
static SIGHAND_TYPE
edit_interrupt(sig)
int sig;
{
/** This routine is called when the user hits an interrupt key
while in the builtin editor...it increments the number of
times an interrupt is hit and returns it.
**/
signal(SIGINT, edit_interrupt);
signal(SIGQUIT, edit_interrupt);
SIGDPRINT(Debug,1,(&Debug,
" edit_interrupt() --- DANGER\n"));
if (interrupts_while_editing++ == 0)
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmEditmsgOneMoreCancel,
"(Interrupt. One more to cancel this letter.)"));
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgCancelled,
"(Interrupt. Letter canceled.)"));
#if defined(SIGSET) && defined(HASSIGHOLD)
/*
* During execution of a signal handler set with sigset(),
* the originating signal is held. It must be released or
* it cannot recur.
*/
sigrelse(sig);
#endif /* SIGSET and HASSIGHOLD */
LONGJMP(edit_location, 1); /* get back */
}
static int enforce_newline P_((char *filename));
static int enforce_newline(filename)
char *filename;
{
/** Make sure there is a newline at the end of filename. Mostly to
be nice to Sun's sendmail, who hangs if there isn't. Return 0
if something went wrong, 1 otherwise. **/
int err, ch, retcode = 0;
FILE* fp;
if ((fp = fopen(filename, "r+")) == NULL) {
err = errno;
DPRINT(Debug,1,
(&Debug, "fopen failed on %s with mode r+\n", filename));
DPRINT(Debug,1,
(&Debug, "** %s **\n", error_description(err)));
} else if (fseek(fp, -1, 2) == -1) {
err = errno;
DPRINT(Debug,1,(&Debug,
"fseek(-1,2) failed on %s\n", filename));
DPRINT(Debug,1,(&Debug,
"** %s **\n", error_description(err)));
} else if ((ch = fgetc(fp)) == EOF) {
err = errno;
DPRINT(Debug,1,(&Debug,
"unexpected EOF on %s\n", filename));
if (ferror(fp))
DPRINT(Debug,1,(&Debug,
"** %s **\n", error_description(err)));
} else if (ch == '\n') {
retcode = 1;
} else if (fseek(fp, 0, 2) == -1) {
err = errno;
DPRINT(Debug,1,(&Debug,"fseek(0,2) failed on %s\n", filename));
DPRINT(Debug,1,(&Debug, "** %s **\n", error_description(err)));
fclose(fp);
} else if (fputc('\n', fp) == EOF) {
err = errno;
DPRINT(Debug,1,(&Debug, "fputc('\\n') failed on %s\n", filename));
DPRINT(Debug,1,(&Debug, "** %s **\n", error_description(err)));
} else {
retcode = 1;
}
fclose(fp);
return retcode;
}
int have_editor(editor)
char *editor;
{
int return_value = 1;
if (strcmp(editor,"none") == 0 ||
editor[0] == '\0') {
return_value = 0;
}
else if (editor[0] == '/') {
char *test = safe_strdup(editor),*ptr;
if (NULL != (ptr = strchr(test,' ')))
*ptr = '\0';
DPRINT(Debug,5,
(&Debug,"have_editor(%s) -- test=%s\n",
editor,test));
if (-1 == access(test,EXECUTE_ACCESS)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmEditCantExecute,
"Can't execute editor: %.50s: %.30s"),
test, error_description(err));
DPRINT(Debug,5,(&Debug,
"have_editor: no access %s: %s\n",test,
error_description(err)));
sleep_message();
return_value = 0;
}
free(test);
}
DPRINT(Debug,5,(&Debug,
"have_editor=%d\n",return_value));
return return_value;
}
int edit_the_message(filename, already_has_text, headers,
editor,file_set,mailer_info,mailbox,
aview, page)
char *filename;
int already_has_text;
struct mailing_headers * headers;
char *editor;
charset_t file_set; /* charset on file */
struct mailer_info *mailer_info;
struct MailboxView *mailbox; /* needed for system_call() */
struct AliasView *aview;
struct menu_context *page;
{
/** Invoke the users editor on the filename. Return when done.
**/
char * buffer = NULL;
int stat, return_value = 0;
int err;
char * filename2 ;
int LINES,COLUMNS;
menu_get_sizes(page,&LINES, &COLUMNS);
DPRINT(Debug,5,
(&Debug,"edit_the_message: %s -- %seditor=%s charset=%s\n",
filename,already_has_text?"(has text) ":"",
editor,
file_set->MIME_name ? file_set->MIME_name : "<no MIME name>"));
if (system_charset != file_set)
filename2 = elm_message(FRM("%sC"),filename);
else
filename2 = filename;
if ((already_has_text ||
!have_editor(editor)) &&
0 != strcmp(alternative_editor, "EDITOR") &&
have_editor(alternative_editor)) {
editor=alternative_editor;
DPRINT(Debug,5,(&Debug,
"edit_the_message: using editor=%s instead\n",
editor));
}
if (strcmp(editor, "builtin") == 0 ||
strcmp(editor, "none") == 0 ||
!have_editor(editor)) {
if (filename2 != filename)
free(filename2);
return(no_editor_edit_the_message(filename, headers,file_set,
mailer_info,
mailbox
/* needed for system_call() */,
aview));
}
PutLineX(LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, ElmInvokeEditor,
"Invoking editor..."));
FlushBuffer();
if (in_string(editor, "%s"))
buffer = elm_message(FRM(editor),
filename2);
else
buffer = elm_message(FRM("%s %s"),
editor, filename2);
if (filename2 != filename) {
char linebuf[1024];
FILE *tmpfp = safeopen_rdwr(filename2);
FILE *f;
int err = can_open(filename,"r");
if (err) {
if (tmpfp)
fclose(tmpfp);
return_value = 1;
goto fail;
}
f = fopen(filename,"r");
if (!f || !tmpfp) {
if (tmpfp)
fclose(tmpfp);
if (f)
fclose(f);
return_value = 1;
goto fail;
}
DPRINT(Debug,5,(&Debug, "Conversion %s [%s] -> %s [%s]\n",
file_set->MIME_name ?
file_set->MIME_name :
"<no MIME name>",
filename,
system_charset->MIME_name ?
system_charset->MIME_name :
"<no MIME name>",
filename2));
/* Conversion file_set -> system charset */
while (0 < mail_gets(linebuf, sizeof linebuf, f)) {
struct string * in_str = new_string2(file_set,
s2us(linebuf));
struct string * out_str = convert_string(system_charset,in_str,0);
char * s = us2s(stream_from_string(out_str,0,NULL));
fputs(s,tmpfp);
free(s);
free_string(&out_str);
free_string(&in_str);
}
fclose(tmpfp);
fclose(f);
}
(void) elm_chown(filename2, userid, groupid);
Raw(OFF);
if ((stat = system_call(buffer, SY_ENAB_SIGHUP|SY_DUMPSTATE,
mailbox)) == -1) {
err = errno;
DPRINT(Debug,1,(&Debug,
"System call failed with stat %d (edit_the_message)\n",
stat));
DPRINT(Debug,1,(&Debug,
"** %s **\n", error_description(err)));
ClearLine(LINES-2); /* ? ? ? */
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantInvokeEditor,
"Can't invoke editor '%s' for composition."),
editor);
sleep_message();
return_value = 1;
}
Raw(ON);
enforce_newline(filename2);
if (filename2 != filename) {
char linebuf[1024];
FILE *tmpfp;
FILE *f;
int err = can_open(filename,"w");
int err2 = can_open(filename2,"r");
if (err || err2) {
return_value = 1;
goto fail;
}
tmpfp = fopen(filename,"w");
f= fopen(filename2,"r");
if (!f || !tmpfp) {
if (tmpfp)
free(tmpfp);
if (f)
free(f);
return_value = 1;
goto fail;
}
DPRINT(Debug,5,(&Debug, "Conversion %s [%s] -> %s [%s]\n",
system_charset->MIME_name ?
system_charset->MIME_name :
"<no MIME name>",
filename2,
file_set->MIME_name ?
file_set->MIME_name :
"<no MIME name>",
filename));
/* Conversion system charset -> file_set */
while (0 < mail_gets(linebuf, sizeof linebuf, f)) {
struct string * in_str = new_string2(system_charset,
s2us(linebuf));
struct string * out_str = convert_string(file_set,in_str,0);
char * s = us2s(stream_from_string(out_str,0,NULL));
fputs(s,tmpfp);
free(s);
free_string(&out_str);
free_string(&in_str);
}
fclose(tmpfp);
fclose(f);
}
fail:
if (filename2 != filename) {
unlink(filename2);
free(filename2);
}
if (buffer) {
free(buffer); buffer = NULL;
}
DPRINT(Debug,5,(&Debug,
"edit_the_message=%d\n",return_value));
return(return_value);
}
/* Prints that part of line which fits one line;
returns start of next line on string
*/
static int FitLine P_((struct string *s, int edit,
struct menu_context *page));
static int FitLine(s,edit,page)
struct string *s;
int edit;
struct menu_context *page;
{
int X = 0;
int LINES, COLUMNS;
menu_get_sizes(page,&LINES, &COLUMNS);
while (X < string_len(s)) {
uint16 ch = give_unicode_from_string(s,X);
int line, col;
GetXYLocation(&line, &col);
if (col >= COLUMNS-2) {
DPRINT(Debug,9,(&Debug,
"FitLine ... No space for characters (col %d)\n",
col));
break;
}
if (ch <= 31) {
switch(ch) {
case 0x0009: /* HT */
Writechar('\t');
break;
default:
if (col > COLUMNS-2)
break;
StartBold();
Writechar('?');
EndBold();
break;
}
X++;
} else {
int len = 1;
struct string * data;
int visible_len;
/* calculate clip len ... */
while (X + len < string_len(s) &&
col + len < COLUMNS -2) {
ch = give_unicode_from_string(s,X+len);
if (ch <= 31)
break;
len++;
}
/* clip_from_string updates X */
data = curses_printable_clip(s,&X,len,&visible_len,
COLUMNS-col-1);
if (data) {
PutLineX(line,col,FRM("%S"),data);
free_string(&data);
if (visible_len < 1) {
DPRINT(Debug,9,(&Debug,
"FitLine ... No space for next character on line\n"));
break;
}
} else {
/* Treat next character as control character */
/* Output character set is assumed to be ASCII
compatible on here: */
StartBold();
Writechar('?');
EndBold();
X++;
}
}
}
if (!edit && X < string_len(s)) {
int line,col;
GetXYLocation(&line, &col);
StartBold();
Writechar('$');
EndBold();
MoveCursor(line,col);
}
return X;
}
/* -2 : 0 Title
1
2 To:
3 Cc:
4 Bcc:
5 Subject:
6
7 buffer ...
-1 : 0 Title
1
2 ( intro ..... )
3 help 1
4 help 2
5
6 buffer ...
0 : 0 Title
1
2 buffer ...
*/
static void write_line P_((struct enter_info *I,int idx));
static void write_line(I,idx)
struct enter_info *I;
int idx;
{
struct string *s = NULL;
switch (idx) {
case 0:
ClearLine(0);
print_format_center(0,
CATGETS(elm_msg_cat, ElmSet,
ElmBuiltinScreenTitle,
"Message Edit Screen"));
return;
case 1:
ClearLine(1);
return;
}
switch(I->px) {
int buffer_line;
case -2:
switch (idx) {
case 2:
PutLineX(2,0,CATGETS(elm_msg_cat, ElmSet, ElmTo, "To: "));
s = hdr_to_expval(I->builtin->headers->to);
break;
case 3:
PutLineX(3,0,CATGETS(elm_msg_cat, ElmSet, ElmCc, "Cc: "));
s = hdr_to_expval(I->builtin->headers->cc);
break;
case 4:
PutLineX(4,0,CATGETS(elm_msg_cat, ElmSet, ElmBcc, "Bcc: "));
s = hdr_to_expval(I->builtin->headers->bcc);
break;
case 5:
PutLineX(5,0,CATGETS(elm_msg_cat, ElmSet, ElmSubject,
"Subject: "));
s = dup_string(I->builtin->headers->subject);
break;
case 6:
MoveCursor(6,0);
break;
default:
MoveCursor(idx,0);
buffer_line = idx-6;
goto draw_it;
}
break;
case -1:
switch (idx) {
case 2:
if (I->counter > 1)
PutLineX(2,0,CATGETS(elm_msg_cat, ElmSet, ElmContinueEntering,
"Continue entering message."));
else
PutLineX(2,0,CATGETS(elm_msg_cat, ElmSet, ElmEnterMessage,
"Enter message."));
break;
case 3:
PutLineX(3,0,CATGETS(elm_msg_cat, ElmSet, ElmTypeElmCommands,
"Type Elm commands on lines by themselves."));
break;
case 4:
PutLineX(4,0,
CATGETS(elm_msg_cat, ElmSet, ElmCommandsInclude,
"Commands include: ^D or '.' to end, %c? for help."),
escape_char);
break;
case 5:
MoveCursor(5,0);
break;
default:
MoveCursor(idx,0);
buffer_line = idx-5;
goto draw_it;
}
break;
default:
MoveCursor(idx,0);
buffer_line = idx+I->px-1;
draw_it:
if (buffer_line == I->counter) {
StartBold();
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmEndOfMessage,
"<end-of-message>"));
EndBold();
} else if (buffer_line > I->counter) {
Write_to_screen(FRM("~"));
} else if (I->pvector[buffer_line])
s = dup_string(I->pvector[buffer_line]);
break;
}
/* Prints just one line of buffer */
if (s) {
if (FitLine(s,0,I->current_page) == string_len(s))
CleartoEOLN();
free_string(&s);
} else
CleartoEOLN();
}
static struct string ** write_edit_line P_((struct enter_info *I));
static struct string **write_edit_line(I)
struct enter_info *I;
{
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
if (I->py <0) { /* Header editor */
if (-5 == I->py) { /* ~o editor */
/* Actual prompting is done on elm_LINES-1 -- elm_LINES lines */
PutLineX(LINES-2,0,
CATGETS(elm_msg_cat, ElmSet,
ElmEnterNameEditor,
"Please enter the name of the editor: "));
I->flags = OE_REDRAW_MARK| OE_SIG_CHAR;
if (I->pvector[0])
Write_to_screen(FRM("%S"),I->pvector[0]);
CleartoEOS();
return & (I->pvector[0]);
} else if (I -> px != -2) { /* Switch to header editing screen */
int r;
menu_ClearScreen(I->current_page);
I->px = -2;
for (r = 0; r < LINES-2; r++)
write_line(I,r);
}
/* Actual editing is done on LINES-2 -- LINES-1 lines */
MoveCursor(LINES-2,0);
/* py:
-4 == To:
-3 == Cc:
-2 == Bcc:
-1 == Subject:
*/
switch(I->py) {
case -4:
PutLineX(LINES-2,0,
CATGETS(elm_msg_cat, ElmSet, ElmTo, "To: "));
if (! I->pvector[0]) {
expanded_to_edit_buffer(& (I->pvector[0]),
I->builtin->headers->to);
}
/* XXXX_edit_buffer (char * -routines) handles mime encoded
words so no OE_ALLOW_MIMEENC here ...
*/
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_ADD_COMMA
| OE_SIG_CHAR;
break;
case -3:
PutLineX(LINES-2,0,
CATGETS(elm_msg_cat, ElmSet, ElmCc, "Cc: "));
if (! I->pvector[0]) {
expanded_to_edit_buffer(& (I->pvector[0]),
I->builtin->headers->cc);
}
/* XXXX_edit_buffer (char * -routines) handles mime encoded
words so no OE_ALLOW_MIMEENC here ...
*/
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_ADD_COMMA
| OE_SIG_CHAR;
break;
case -2:
PutLineX(LINES-2,0,
CATGETS(elm_msg_cat, ElmSet, ElmBcc, "Bcc: "));
if (! I->pvector[0]) {
expanded_to_edit_buffer(& (I->pvector[0]),
I->builtin->headers->bcc);
}
/* XXXX_edit_buffer (char * -routines) handles mime encoded
words so no OE_ALLOW_MIMEENC here ...
*/
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_ADD_COMMA
| OE_SIG_CHAR;
break;
case -1:
PutLineX(LINES-2,0,
CATGETS(elm_msg_cat, ElmSet, ElmSubject, "Subject: "));
if (! I->pvector[0])
I->pvector[0] = dup_string(I->builtin->headers->subject);
/* OE_ALLOW_MIMEENC so that user can paste mime encoded words
to buffer and they are converted
*/
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_ALLOW_MIMEENC
| OE_SIG_CHAR;
break;
}
if (I->pvector[0])
Write_to_screen(FRM("%S"),I->pvector[0]);
CleartoEOS();
return & (I->pvector[0]);
} else if (0 == (I->flags & OE_EDITOR_ESCAPE)) { /* Command editor */
StartBold();
PutLineX(LINES-2,0,FRM("%c"),escape_char);
EndBold();
if (I->pvector[0])
Write_to_screen(FRM("%S"),I->pvector[0]);
CleartoEOS();
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK| OE_SIG_CHAR;
return & (I->pvector[0]);
} else { /* Text editor */
int ok = 0;
int buffer_line = I->py+1;
do {
int start_line = 2;
int shift = 0;
int line_cordinate;
int added = 0;
buffer_line = I->py+1;
while(buffer_line >= I->counter) {
add_to_vector(I,NULL);
added++;
}
switch(I -> px) {
case -2: start_line = 7; shift = 0; break;
case -1: start_line = 6; shift = 0; break;
default: start_line = 2; shift = 0; break;
}
if (I -> px > 0)
shift = I -> px;
line_cordinate = start_line + I->py - shift;
if (line_cordinate >= LINES-2) {
/* Repage */
int r;
menu_ClearScreen(I->current_page);
I->px = I->py-1;
for (r = 0; r < LINES-2; r++)
write_line(I,r);
ok = 0;
} else if (line_cordinate < 2) {
/* Repage */
int r;
menu_ClearScreen(I->current_page);
I->px = I->py-1;
if (I->px < 0)
I->px = -1;
for (r = 0; r < LINES-2; r++)
write_line(I,r);
ok = 0;
} else {
int left = 0;
MoveCursor(line_cordinate,0);
ok = 1;
if (I->pvector[buffer_line]) {
/* With argument 1 FitLine does not use last position */
left = FitLine(I->pvector[buffer_line],1,
I->current_page);
CleartoEOLN();
if (left < string_len(I->pvector[buffer_line])) {
/* Wrapping .... */
int Y = 0;
int j;
struct string * tmp, *tmp2;
I->pvector = safe_realloc(I->pvector,
(I->counter+1) *
sizeof (struct string *));
for (j = I->counter-1; j > buffer_line; j--) {
I->pvector[j+1] = I->pvector[j];
I->pvector[j] = NULL;
}
I->counter++;
/* clip_from_string updates Y */
tmp = clip_from_string(I->pvector[buffer_line],&Y,
left);
tmp2 = clip_from_string(I->pvector[buffer_line],&Y,
string_len(I->pvector[buffer_line]));
free_string(&(I->pvector[buffer_line]));
I->pvector[buffer_line] = tmp;
I->pvector[buffer_line+1] = tmp2;
added++;
/* Goto to next line */
I->py++;
ok = 0;
}
/* handle escape_char */
I->ch_count = string_len(I->pvector[buffer_line]);
} else {
CleartoEOLN();
I->ch_count = 0; /* handle escape_char */
}
/* handle escape_char */
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK |
OE_EDITOR_ESCAPE| OE_SIG_CHAR;
/* Update end of file mark and wrapped lines*/
if (added && line_cordinate+1 < LINES-2) {
int j;
int line,col;
GetXYLocation(&line, &col);
for (j = line_cordinate+1; j < LINES-2; j++)
write_line(I,j);
MoveCursor(line,col);
}
}
} while (!ok);
return & (I->pvector[buffer_line]);
}
/* NOT REACHED */
}
static void start_edit_addr P_((struct enter_info *I,
struct expanded_address addr));
static void start_edit_addr(I,addr)
struct enter_info *I;
struct expanded_address addr;
{
int X = 1;
struct string *tmp;
tmp = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
free_string(&I->pvector[0]);
expanded_to_edit_buffer(& (I->pvector[0]),
addr);
if (string_len(tmp)) {
struct string *tmp2;
if (string_len(I->pvector[0]))
add_ascii_to_string(I->pvector[0],s2us(", "));
tmp2 = cat_strings(I->pvector[0],tmp,0);
free_string(&I->pvector[0]);
I->pvector[0] = tmp2;
}
free_string(&tmp);
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_ADD_COMMA
| OE_SIG_CHAR;
}
static void start_edit_subject P_((struct enter_info *I));
static void start_edit_subject(I)
struct enter_info *I;
{
int X = 1;
struct string *tmp;
tmp = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
free_string(&I->pvector[0]);
I->pvector[0] = dup_string(I->builtin->headers->subject);
if (string_len(tmp)) {
struct string *tmp2;
if (string_len(I->pvector[0]))
add_ascii_to_string(I->pvector[0],s2us(", "));
tmp2 = cat_strings(I->pvector[0],tmp,0);
free_string(&I->pvector[0]);
I->pvector[0] = tmp2;
}
free_string(&tmp);
/* OE_ALLOW_MIMEENC so that user can paste mime encoded words
to buffer and they are converted
*/
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_ALLOW_MIMEENC
| OE_SIG_CHAR;
}
static void redraw_editor(I)
struct enter_info *I;
{
int r;
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
menu_ClearScreen(I->current_page);
for (r = 0; r < LINES-2; r++)
write_line(I,r);
}
static int read_editor P_((struct enter_info *I));
static int read_editor(I)
struct enter_info *I;
{
char buffer[LONG_STRING];
int i,len;
int err = can_open(I->builtin->filename, "r");
if (err) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenFile,
"Can't open %s!"),
I->builtin->filename, error_description(err));
return 0;
}
if (I->builtin->edit_fd) {
fclose(I->builtin->edit_fd);
I->builtin->edit_fd = NULL;
}
if ((I->builtin->edit_fd = fopen(I->builtin->filename,
"r")) == NULL) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenFile,
"Can't open %s!"),
I->builtin->filename, error_description(err));
DPRINT(Debug,1,
(&Debug,
"Error encountered trying to open file %s;\n",
I->builtin->filename));
DPRINT(Debug,1,
(&Debug, "** %s **\n", error_description(err)));
return 0;
}
if (I->counter) {
for (i = 1; i < I->counter; i++)
if (I->pvector[i])
free_string(&(I->pvector[i]));
I->counter = 1;
} else
add_to_vector(I,NULL); /* pvector[0] is working space
for header editing ....
*/
while (0 < (len =
mail_gets(buffer, sizeof buffer,I->builtin->edit_fd))) {
struct string * str;
if(buffer[len-1] == '\n') {
buffer[len-1] = '\0';
}
str = new_string2(I->builtin->file_set,s2us(buffer));
add_to_vector(I,str);
}
return 1;
}
static int write_editor P_((struct enter_info *I));
static int write_editor(I)
struct enter_info *I;
{
int err = can_open(I->builtin->filename, "w");
int i;
if (0 != err) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
"Can't open %s!"),
I->builtin->filename);
return 0;
}
if (I->builtin->edit_fd) {
fclose(I->builtin->edit_fd);
I->builtin->edit_fd = NULL;
}
if ((I->builtin->edit_fd = fopen(I->builtin->filename, "w")) == NULL) {
err = errno;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenFile,
"Can't open %s!"),
I->builtin->filename, error_description(err));
DPRINT(Debug,1,
(&Debug,
"Error encountered trying to open file %s;\n",
I->builtin->filename));
DPRINT(Debug,1,
(&Debug, "** %s **\n", error_description(err)));
return 0;
}
for (i = 1; i < I->counter; i++) {
if (I->pvector[i]) {
struct string * S= convert_string(I->builtin->file_set,
I->pvector[i],
0); /* Assurance */
char * s = us2s(stream_from_string(S,0,NULL));
fputs(s,I->builtin->edit_fd);
free(s);
free_string(&S);
}
putc('\n',I->builtin->edit_fd);
}
if (EOF == fflush(I->builtin->edit_fd)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmWriteFailedCopy,
"Write failed to temp file in copy"));
return 0;
}
return 1;
}
static struct string ** editor_enter P_((struct enter_info *I));
static struct string ** editor_enter(I)
struct enter_info *I;
{
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
if (I->py <0) { /* Header editor */
MoveCursor(LINES-2,0);
CleartoEOS();
if (! I->pvector[0]) {
I->py = 0;
return write_edit_line(I);
}
/* -f ~o prompt
-4 == To:
-3 == Cc:
-2 == Bcc:
-1 == Subject:
*/
switch(I->py) {
char *s;
case -5: /* ~o */
s= us2s(stream_from_string(I->pvector[0],0,NULL));
if (strlen(s) > 0 &&
have_editor(s)) {
if (!write_editor(I)) {
free(s);
return NULL;
}
fclose(I->builtin->edit_fd);
I->builtin->edit_fd = NULL;
(void) edit_the_message(I->builtin->filename,0,
I->builtin->headers,
s,
I->builtin->file_set,
I->mailer_info,
I->builtin->mailbox
/* needed for system_call() */,
I->aview,
I->current_page /* ? ? ? */
);
if (!read_editor(I)) {
free(s);
return NULL;
}
I->py = I->counter-1;
redraw_editor(I);
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmPostEdContinue,
"(Continue entering message. Type ^D or '.' on a line by itself to end.)"));
} else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmSimpleContinue,
"(Continue.)"));
free(s);
break;
case -4:
update_expanded_from_edit_buffer(&(I->builtin->headers->to),
I->pvector[0],
I->mailer_info,
I->aview
);
write_line(I,2);
break;
case -3:
update_expanded_from_edit_buffer(&(I->builtin->headers->cc),
I->pvector[0],
I->mailer_info,
I->aview);
write_line(I,3);
break;
case -2:
update_expanded_from_edit_buffer(&(I->builtin->headers->bcc),
I->pvector[0],
I->mailer_info,
I->aview
);
write_line(I,4);
break;
case -1:
if (I->builtin->headers->subject)
free_string(&(I->builtin->headers->subject));
I->builtin->headers->subject = dup_string(I->pvector[0]);
write_line(I,5);
break;
}
free_string(&(I->pvector[0]));
I->py = I->counter-1;
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_EDITOR_ESCAPE
| OE_SIG_CHAR;
return write_edit_line(I);
} else if (0 == (I->flags & OE_EDITOR_ESCAPE)) { /* Command editor */
int buffer_line = I->py+1;
uint16 ch;
MoveCursor(LINES-2,0);
CleartoEOS();
if (! I->pvector[0] ||
0 == string_len(I->pvector[0])) {
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_EDITOR_ESCAPE
| OE_SIG_CHAR;
return write_edit_line(I);
}
while(buffer_line >= I->counter)
add_to_vector(I,NULL);
ch = give_unicode_from_string(I->pvector[0],0);
switch(ch) {
int X;
struct string *S;
char *s;
case 0x003F: /* '?' */
tilde_help();
redraw_editor(I);
free_string(&I->pvector[0]);
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_EDITOR_ESCAPE
| OE_SIG_CHAR;
return write_edit_line(I);
case 0x007E: /* '~' */
if (I->pvector[buffer_line])
free_string(&(I->pvector[buffer_line]));
I->pvector[buffer_line] = I->pvector[0];
I->pvector[0] = NULL;
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_EDITOR_ESCAPE
| OE_SIG_CHAR;
I->ch_count = 1;
return write_edit_line(I);
case 0x0074: /* 't' */
case 0x0054: /* 'T' */
I->py = -4;
I->ch_count = 0;
start_edit_addr(I,I->builtin->headers->to);
return write_edit_line(I);
case 0x0063: /* 'c' */
case 0x0043: /* 'C' */
I->py = -3;
I->ch_count = 0;
start_edit_addr(I,I->builtin->headers->cc);
return write_edit_line(I);
case 0x0062: /* 'b' */
case 0x0042: /* 'B' */
I->py = -2;
I->ch_count = 0;
start_edit_addr(I,I->builtin->headers->bcc);
return write_edit_line(I);
case 0x0073: /* 's' */
case 0x0053: /* 'S' */
I->py = -1;
I->ch_count = 0;
start_edit_subject(I);
return write_edit_line(I);
case 0x0068: /* 'h' */
case 0x0048: /* 'H' */
/* TODO: Ask To: Cc: Bcc: Subject: */
I->flags |= OE_EDITOR_ESCAPE| OE_SIG_CHAR;
free_string(&I->pvector[0]);
return write_edit_line(I);
case 0x0072: /* 'r' */
case 0x0052: /* 'R' */
X = 1;
S = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
s = us2s(stream_from_string(S,0,NULL));
read_in_file(I, s, 1);
free_string(&S);
free(s);
I->flags |= OE_EDITOR_ESCAPE| OE_SIG_CHAR;
free_string(&I->pvector[0]);
return write_edit_line(I);
case 0x0065: /* 'e' */
case 0x0045: /* 'E' */
I->flags |= OE_EDITOR_ESCAPE| OE_SIG_CHAR;
free_string(&I->pvector[0]);
if (strlen(e_editor) > 0 ||
0 != strcmp(e_editor,"none"))
if (have_editor(e_editor)) {
if (!write_editor(I))
return NULL;
fclose(I->builtin->edit_fd);
I->builtin->edit_fd = NULL;
(void) edit_the_message(I->builtin->filename,0,
I->builtin->headers,
e_editor,
I->builtin->file_set,
I->mailer_info,
I->builtin->mailbox
/* needed for system_call() */,
I->aview,
I->current_page /* ? ? ? */);
if (!read_editor(I))
return NULL;
I->py = I->counter-1;
redraw_editor(I);
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmPostEdContinue,
"(Continue entering message. Type ^D or '.' on a line by itself to end.)"));
return write_edit_line(I);
} else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCantFindEmacs,
"(Can't find Emacs on this system! Continue.)"));
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmDontKnowEmacs,
"(Don't know where Emacs would be. Continue.)"));
return write_edit_line(I);
case 0x0076: /* 'v' */
case 0x0056: /* 'V' */
I->flags |= OE_EDITOR_ESCAPE| OE_SIG_CHAR;
free_string(&I->pvector[0]);
if (have_editor(v_editor)) {
if (!write_editor(I))
return NULL;
fclose(I->builtin->edit_fd);
I->builtin->edit_fd = NULL;
(void) edit_the_message(I->builtin->filename,
0,
I->builtin->headers,v_editor,
I->builtin->file_set,
I->mailer_info,
I->builtin->mailbox
/* needed for system_call() */,
I->aview,
I->current_page /* ? ? ? */);
if (!read_editor(I))
return NULL;
}
I->py = I->counter-1;
redraw_editor(I);
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmPostEdContinue,
"(Continue entering message. Type ^D or '.' on a line by itself to end.)"));
return write_edit_line(I);
case 0x006F: /* 'o' */
case 0x004F: /* 'O' */
I->py = -5; /* Ask editor name first */
X = 1;
S = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
I->flags = OE_REDRAW_MARK
| OE_SIG_CHAR;
I->ch_count = 0;
free_string(&I->pvector[0]);
I->pvector[0] = S;
return write_edit_line(I);
case 0x003C: /* '<' */
if (string_len(I->pvector[0]) < 3) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmUseSpecificCommand,
"(You need to use a specific command here. Continue.)"));
} else {
char * tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
char * s3 = elm_message(FRM("%s%s.%d"),
tmp ? tmp : "/tmp/",
temp_edit, getpid());
char * s1;
X = 1;
S = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
s = us2s(stream_from_string(S,0,NULL));
s1 = elm_message(FRM("%s > %s 2>&1"),s,s3);
Raw(OFF);
(void) system_call(s1, SY_ENAB_SIGINT|SY_DUMPSTATE,
I->builtin->mailbox);
Raw(ON);
read_in_file(I, s3, 0);
(void) unlink(s3);
free(s3);
free(s1);
free(s);
}
I->flags |= OE_EDITOR_ESCAPE | OE_SIG_CHAR;
free_string(&I->pvector[0]);
return write_edit_line(I);
case 0x0021: /* '!' */
{
Raw(OFF);
X = 1;
S = clip_from_string(I->pvector[0],&X,string_len(I->pvector[0]));
s = us2s(stream_from_string(S,0,NULL));
(void) system_call((!*s ? (char *)NULL : s),
SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE,
I->builtin->mailbox);
if (*s) {
struct menu_context *cpage;
cpage = Raw(ON | NO_TITE);
redraw2:
/* ? ? ? */
menu_PutLineX(cpage,
LINES-1, 0, CATGETS(elm_msg_cat, ElmSet,
ElmPressAnyKeyToReturn,
"\n\nPress any key to return to ELM: "));
if (menu_ReadCh(cpage, REDRAW_MARK) == REDRAW_MARK) {
goto redraw2;
}
Raw(OFF | NO_TITE);
printf("\r\n");
}
Raw(ON);
free(s);
free_string(&S);
redraw_editor(I);
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmSimpleContinue,
"(Continue.)"));
}
I->flags |= OE_EDITOR_ESCAPE | OE_SIG_CHAR;
free_string(&I->pvector[0]);
return write_edit_line(I);
case 0x006D: /* 'm' */ /* same as 'f' but with leading prefix added */
case 0x004D: /* 'M' */
case 0x0066: /* 'f' */
case 0x0046: /* 'F' */
/* this can be directly translated into a
'readmsg' call with the same params! */
read_in_messages(I);
I->flags |= OE_EDITOR_ESCAPE | OE_SIG_CHAR;
free_string(&I->pvector[0]);
return write_edit_line(I);
case 0x0070: /* 'p' */
I->px = -2;
I->py = 0;
redraw_editor(I);
I->flags |= OE_EDITOR_ESCAPE | OE_SIG_CHAR;
free_string(&I->pvector[0]);
return write_edit_line(I);
default :
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmDontKnowChar,
"(Don't know what %c%.1S is. Try %c? for help.)"),
escape_char,I->pvector[0],escape_char);
sleep_message();
/* reprompt */
I->flags = OE_REDRAW_MARK | OE_SIG_CHAR;
I->ch_count = 0;
return write_edit_line(I);
}
} else { /* Text editor */
int buffer_line = I->py+1;
if (I->pvector[buffer_line]) {
if (string_len(I->pvector[buffer_line]) == 1 &&
buffer_line == I->counter-1) {
uint16 ch = give_unicode_from_string(I->pvector[buffer_line],
0);
if (ch == 0x002E /* '.' */) {
int line, col,a = 0;
GetXYLocation(&line, &col);
/* Update end of file mark */
free_string(&(I->pvector[buffer_line]));
I->counter--;
while(line < LINES-2 && a++ < 2)
write_line(I,line++);
return NULL; /* End mark */
}
}
}
I->py++;
return write_edit_line(I);
}
}
static void add_to_vector(I,str)
struct enter_info *I;
struct string *str;
{
I->pvector = safe_realloc(I->pvector,
(I->counter+1) * sizeof (struct string *));
I->pvector[I->counter++] = str;
}
static struct string ** editor_prev P_((struct enter_info *I));
static struct string ** editor_prev(I)
struct enter_info *I;
{
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
if (I->py > 0) { /* Text editor */
if (0 == (I->flags & OE_EDITOR_ESCAPE)) {
MoveCursor(LINES-2,0);
CleartoEOS();
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_EDITOR_ESCAPE
| OE_SIG_CHAR;
}
I->py--;
}
return write_edit_line(I);
}
static struct string ** editor_next P_((struct enter_info *I));
static struct string ** editor_next(I)
struct enter_info *I;
{
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
if (I->py >= 0) { /* Text editor */
if (0 == (I->flags & OE_EDITOR_ESCAPE)) {
MoveCursor(LINES-2,0);
CleartoEOS();
I->flags = OE_APPEND_CURRENT | OE_REDRAW_MARK | OE_EDITOR_ESCAPE
| OE_SIG_CHAR;
}
if (I->py <= I->counter)
I->py++;
}
return write_edit_line(I);
}
static struct string ** editor_wrap P_((struct enter_info *I));
static struct string ** editor_wrap(I)
struct enter_info *I;
{
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
if (I->py >= 0 &&
0 != (I->flags & OE_EDITOR_ESCAPE)) {
int buffer_line = I->py+1;
int X;
for (X = string_len(I->pvector[buffer_line]) -1;
X >= 0;
X--) {
uint16 ch = give_unicode_from_string(I->pvector[buffer_line],X);
if (ch == 0x0009 /* HT */ ||
ch == 0x0020 /* SPACE */)
break;
}
/* Text editor */
if (X >= 0) {
int j;
struct string * tmp, *tmp2;
int Y = 0;
int need_redraw = buffer_line < I->counter-1;
I->pvector = safe_realloc(I->pvector,
(I->counter+1) *
sizeof (struct string *));
for (j = I->counter-1; j > buffer_line; j--) {
I->pvector[j+1] = I->pvector[j];
I->pvector[j] = NULL;
}
I->counter++;
/* clip_from_string updates Y */
tmp = clip_from_string(I->pvector[buffer_line],&Y,X+1);
tmp2 = clip_from_string(I->pvector[buffer_line],&Y,
string_len(I->pvector[buffer_line]));
free_string(&(I->pvector[buffer_line]));
I->pvector[buffer_line] = tmp;
I->pvector[buffer_line+1] = tmp2;
if (need_redraw)
redraw_editor(I);
else {
int line,col;
GetXYLocation(&line, &col);
write_line(I,line);
/* Update end of file mark */
if (line+1 < LINES-2)
write_line(I,line+1);
}
I->py++;
}
}
return write_edit_line(I);
}
static struct string ** editor_escape P_((struct enter_info *I));
static struct string ** editor_escape(I)
struct enter_info *I;
{
int line,col;
int LINES, COLUMNS;
menu_get_sizes(I->current_page,&LINES, &COLUMNS);
GetXYLocation(&line, &col);
write_line(I,line);
I->flags = OE_REDRAW_MARK| OE_SIG_CHAR;
MoveCursor(LINES-2,0);
CleartoEOS();
if (I->pvector[0])
free_string(&(I->pvector[0]));
return write_edit_line(I);
}
static struct string **gb_editmsg P_((struct enter_info *I,
enum enter_mode em,
struct menu_context *base_page));
static struct string **gb_editmsg(I,em, base_page)
struct enter_info *I;
enum enter_mode em;
struct menu_context *base_page;
{
switch(em) {
case em_redraw_initial:
case em_redraw:
return write_edit_line(I);
case em_enter:
return editor_enter(I);
case em_prev:
case em_bs_prev:
return editor_prev(I);
case em_next:
return editor_next(I);
case em_wrap:
return editor_wrap(I);
case em_editor_escape:
return editor_escape(I);
}
return NULL;
}
int no_editor_edit_the_message(filename,headers,file_set,mailer_info,
mailbox,aview)
char *filename;
struct mailing_headers * headers;
charset_t file_set;
struct mailer_info *mailer_info;
struct MailboxView *mailbox;
struct AliasView *aview;
{
/** If the current editor is set to either "builtin" or "none", then
invoke this program instead. As it turns out, this and the
routine above have a pretty incestuous relationship (!)...
**/
SIGHAND_TYPE edit_interrupt P_((int));
SIGHAND_TYPE (*oldint) P_((int)), (*oldquit)P_((int));
struct builtin_edit INFO_1;
struct enter_info INFO;
int j;
struct menu_context * page = NULL;
int LINES, COLUMNS;
int code1;
/* The built-in editor is not re-entrant! */
if (builtin_editor_active) {
Write_to_screen(CATGETS(elm_msg_cat, ElmSet, ElmIntReentrantBuiltinEditor,
"\r\nInternal error - reentrant call to builtin editor attempted.\r\n\r\n"), 0);
DPRINT(Debug,1,
(&Debug,
"Reentrant call to builtin editor for %s attempted\n", filename));
return(1);
}
if (simple_continue == NULL) {
simple_continue = catgets(elm_msg_cat, ElmSet, ElmSimpleContinue,
"(Continue.)\n\r");
}
page = new_menu_context();
menu_get_sizes(page, &LINES, &COLUMNS);
INFO.counter = 0;
INFO.pvector = NULL;
INFO.px = -1;
INFO.py = 0;
INFO.give_buffer = gb_editmsg;
INFO.flags = OE_APPEND_CURRENT | OE_REDRAW_MARK |
OE_EDITOR_ESCAPE | OE_SIG_CHAR;
INFO.ch_count = 0;
INFO.builtin = &INFO_1;
INFO.dir_p = NULL;
INFO.mailer_info = mailer_info;
INFO.aview = aview;
INFO.current_page = page;
INFO_1.headers = headers;
INFO_1.filename = filename;
INFO_1.file_set = file_set;
INFO_1.edit_fd = NULL;
INFO_1.mailbox = mailbox;
if (!read_editor(&INFO))
return 1;
INFO.py = INFO.counter-1;
INFO.px = INFO.py - LINES + 3;
if (INFO.px < -1 )
INFO.px = -1;
redraw_editor(&INFO);
oldint = signal(SIGINT, edit_interrupt);
oldquit = signal(SIGQUIT, edit_interrupt);
builtin_editor_active = TRUE;
interrupts_while_editing = 0;
if (SETJMP(edit_location) != 0) {
restart_sig:
if (interrupts_while_editing > 1) {
(void) signal(SIGINT, oldint);
(void) signal(SIGQUIT, oldquit);
goto out;
}
goto more_input; /* read input again, please! */
}
more_input:
while (REDRAW_MARK == (code1 = enter_helper(&INFO, page))) {
if (menu_resized(page))
menu_get_sizes(page, &LINES, &COLUMNS);
else if (menu_need_redraw(page))
/* Nothing */;
redraw_editor(&INFO);
}
if (-1 == code1) {
DPRINT(Debug,1,(&Debug,"interrupt char given (no signal)\n"));
if (interrupts_while_editing++ == 0)
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmEditmsgOneMoreCancel,
"(Interrupt. One more to cancel this letter.)"));
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmEditmsgCancelled,
"(Interrupt. Letter canceled.)"));
goto restart_sig;
}
(void) signal(SIGINT, oldint);
(void) signal(SIGQUIT, oldquit);
write_editor(&INFO);
out:
if (INFO_1.edit_fd) {
fclose(INFO_1.edit_fd); /* insurance... */
INFO_1.edit_fd = NULL;
}
if (INFO.pvector) {
for (j = 0; j < INFO.counter; j++) {
if (INFO.pvector[j])
free_string(&(INFO.pvector[j]));
}
free(INFO.pvector);
}
erase_menu_context(&page);
builtin_editor_active = FALSE;
return(0);
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1