2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
5 * This file is part of mutt-ng, see http://www.muttng.org/.
6 * It's licensed under the GNU General Public License,
7 * please see the file GPL in the top level source directory.
10 /* Close approximation of the mailx(1) builtin editor for sending mail. */
17 #include "mutt_curses.h"
18 #include "mutt_idna.h"
33 * SLcurses_waddnstr() can't take a "const char *", so this is only
34 * declared "static" (sigh)
36 static char *EditorHelp = N_("\
37 ~~ insert a line begining with a single ~\n\
38 ~b users add users to the Bcc: field\n\
39 ~c users add users to the Cc: field\n\
40 ~f messages include messages\n\
41 ~F messages same as ~f, except also include headers\n\
42 ~h edit the message header\n\
43 ~m messages include and quote messages\n\
44 ~M messages same as ~m, except include headers\n\
45 ~p print the message\n\
46 ~q write file and quit editor\n\
47 ~r file read a file into the editor\n\
48 ~t users add users to the To: field\n\
49 ~u recall the previous line\n\
50 ~v edit message with the $visual editor\n\
51 ~w file write message to file\n\
52 ~x abort changes and quit editor\n\
54 . on a line by itself ends input\n");
56 static char **be_snarf_data (FILE * f, char **buf, int *bufmax, int *buflen,
57 int offset, int bytes, int prefix)
59 char tmp[HUGE_STRING];
61 int tmplen = sizeof (tmp);
63 tmp[sizeof (tmp) - 1] = 0;
65 strfcpy (tmp, NONULL (Prefix), sizeof (tmp));
66 tmplen = mutt_strlen (tmp);
68 tmplen = sizeof (tmp) - tmplen;
73 if (fgets (p, tmplen - 1, f) == NULL)
75 bytes -= mutt_strlen (p);
76 if (*bufmax == *buflen)
77 safe_realloc (&buf, sizeof (char *) * (*bufmax += 25));
78 buf[(*buflen)++] = safe_strdup (tmp);
80 if (buf && *bufmax == *buflen) { /* Do not smash memory past buf */
81 safe_realloc (&buf, sizeof (char *) * (++*bufmax));
88 static char **be_snarf_file (const char *path, char **buf, int *max, int *len,
92 char tmp[LONG_STRING];
95 if ((f = fopen (path, "r"))) {
96 fstat (fileno (f), &sb);
97 buf = be_snarf_data (f, buf, max, len, 0, sb.st_size, 0);
99 snprintf (tmp, sizeof (tmp), "\"%s\" %lu bytes\n", path,
100 (unsigned long) sb.st_size);
106 snprintf (tmp, sizeof (tmp), "%s: %s\n", path, strerror (errno));
112 static int be_barf_file (const char *path, char **buf, int buflen)
117 if ((f = safe_fopen (path, "w")) == NULL) { /* __FOPEN_CHECKED__ */
118 addstr (strerror (errno));
122 for (i = 0; i < buflen; i++)
126 printw ("fclose: %s\n", strerror (errno));
130 static void be_free_memory (char **buf, int buflen)
138 static char **be_include_messages (char *msg, char **buf, int *bufmax,
139 int *buflen, int pfx, int inc_hdrs)
141 int offset, bytes, n;
142 char tmp[LONG_STRING];
144 while ((msg = strtok (msg, " ,")) != NULL) {
146 if (n > 0 && n <= Context->msgcount) {
149 /* add the attribution */
151 mutt_make_string (tmp, sizeof (tmp) - 1, Attribution, Context,
153 strcat (tmp, "\n"); /* __STRCAT_CHECKED__ */
156 if (*bufmax == *buflen)
157 safe_realloc (&buf, sizeof (char *) * (*bufmax += 25));
158 buf[(*buflen)++] = safe_strdup (tmp);
160 bytes = Context->hdrs[n]->content->length;
162 offset = Context->hdrs[n]->offset;
163 bytes += Context->hdrs[n]->content->offset - offset;
166 offset = Context->hdrs[n]->content->offset;
167 buf = be_snarf_data (Context->fp, buf, bufmax, buflen, offset, bytes,
170 if (*bufmax == *buflen)
171 safe_realloc (&buf, sizeof (char *) * (*bufmax += 25));
172 buf[(*buflen)++] = safe_strdup ("\n");
175 printw (_("%d: invalid message number.\n"), n);
181 static void be_print_header (ENVELOPE * env)
183 char tmp[HUGE_STRING];
188 rfc822_write_address (tmp, sizeof (tmp), env->to, 1);
195 rfc822_write_address (tmp, sizeof (tmp), env->cc, 1);
202 rfc822_write_address (tmp, sizeof (tmp), env->bcc, 1);
207 addstr ("Subject: ");
208 addstr (env->subject);
215 * force override the $ask* vars (used for the ~h command)
217 static void be_edit_header (ENVELOPE * e, int force)
219 char tmp[HUGE_STRING];
225 mutt_addrlist_to_local (e->to);
226 rfc822_write_address (tmp, sizeof (tmp), e->to, 0);
227 if (!e->to || force) {
228 if (mutt_enter_string (tmp, sizeof (tmp), LINES - 1, 4, 0) == 0) {
229 rfc822_free_address (&e->to);
230 e->to = mutt_parse_adrlist (e->to, tmp);
231 e->to = mutt_expand_aliases (e->to);
232 mutt_addrlist_to_idna (e->to, NULL); /* XXX - IDNA error reporting? */
234 rfc822_write_address (tmp, sizeof (tmp), e->to, 1);
235 mvaddstr (LINES - 1, 4, tmp);
239 mutt_addrlist_to_idna (e->to, NULL); /* XXX - IDNA error reporting? */
244 if (!e->subject || force) {
245 addstr ("Subject: ");
246 strfcpy (tmp, e->subject ? e->subject : "", sizeof (tmp));
247 if (mutt_enter_string (tmp, sizeof (tmp), LINES - 1, 9, 0) == 0)
248 mutt_str_replace (&e->subject, tmp);
252 if ((!e->cc && option (OPTASKCC)) || force) {
255 mutt_addrlist_to_local (e->cc);
256 rfc822_write_address (tmp, sizeof (tmp), e->cc, 0);
257 if (mutt_enter_string (tmp, sizeof (tmp), LINES - 1, 4, 0) == 0) {
258 rfc822_free_address (&e->cc);
259 e->cc = mutt_parse_adrlist (e->cc, tmp);
260 e->cc = mutt_expand_aliases (e->cc);
262 mutt_addrlist_to_idna (e->cc, NULL);
263 rfc822_write_address (tmp, sizeof (tmp), e->cc, 1);
264 mvaddstr (LINES - 1, 4, tmp);
267 mutt_addrlist_to_idna (e->cc, NULL);
271 if (option (OPTASKBCC) || force) {
274 mutt_addrlist_to_local (e->bcc);
275 rfc822_write_address (tmp, sizeof (tmp), e->bcc, 0);
276 if (mutt_enter_string (tmp, sizeof (tmp), LINES - 1, 5, 0) == 0) {
277 rfc822_free_address (&e->bcc);
278 e->bcc = mutt_parse_adrlist (e->bcc, tmp);
279 e->bcc = mutt_expand_aliases (e->bcc);
280 mutt_addrlist_to_idna (e->bcc, NULL);
282 rfc822_write_address (tmp, sizeof (tmp), e->bcc, 1);
283 mvaddstr (LINES - 1, 5, tmp);
286 mutt_addrlist_to_idna (e->bcc, NULL);
291 int mutt_builtin_editor (const char *path, HEADER * msg, HEADER * cur)
294 int bufmax = 0, buflen = 0;
295 char tmp[LONG_STRING];
301 scrollok (stdscr, TRUE);
303 be_edit_header (msg->env, 0);
305 addstr (_("(End message with a . on a line by itself)\n"));
307 buf = be_snarf_file (path, buf, &bufmax, &buflen, 0);
311 if (mutt_enter_string (tmp, sizeof (tmp), LINES - 1, 0, 0) == -1) {
317 if (EscChar && tmp[0] == EscChar[0] && tmp[1] != EscChar[0]) {
318 /* remove trailing whitespace from the line */
319 p = tmp + mutt_strlen (tmp) - 1;
320 while (p >= tmp && ISSPACE (*p))
328 addstr (_(EditorHelp));
331 msg->env->bcc = mutt_parse_adrlist (msg->env->bcc, p);
332 msg->env->bcc = mutt_expand_aliases (msg->env->bcc);
335 msg->env->cc = mutt_parse_adrlist (msg->env->cc, p);
336 msg->env->cc = mutt_expand_aliases (msg->env->cc);
339 be_edit_header (msg->env, 1);
347 /* include the current message */
348 p = tmp + mutt_strlen (tmp) + 1;
349 snprintf (tmp + mutt_strlen (tmp),
350 sizeof (tmp) - mutt_strlen (tmp), " %d",
353 buf = be_include_messages (p, buf, &bufmax, &buflen,
354 (ascii_tolower (tmp[1]) == 'm'),
356 ((unsigned char) tmp[1])));
359 addstr (_("No mailbox.\n"));
363 addstr (_("Message contains:\n"));
364 be_print_header (msg->env);
365 for (i = 0; i < buflen; i++)
367 addstr (_("(continue)\n"));
374 strncpy (tmp, p, sizeof (tmp));
375 mutt_expand_path (tmp, sizeof (tmp));
376 buf = be_snarf_file (tmp, buf, &bufmax, &buflen, 1);
379 addstr (_("missing filename.\n"));
382 mutt_str_replace (&msg->env->subject, p);
385 msg->env->to = rfc822_parse_adrlist (msg->env->to, p);
386 msg->env->to = mutt_expand_aliases (msg->env->to);
391 strfcpy (tmp, buf[buflen], sizeof (tmp));
392 tmp[mutt_strlen (tmp) - 1] = 0;
398 addstr (_("No lines in message.\n"));
403 if (be_barf_file (path, buf, buflen) == 0) {
406 be_free_memory (buf, buflen);
410 if (option (OPTEDITHDRS)) {
411 mutt_env_to_local (msg->env);
412 mutt_edit_headers (NONULL (Visual), path, msg, NULL, 0);
413 if (mutt_env_to_idna (msg->env, &tag, &err))
414 printw (_("Bad IDN in %s: '%s'\n"), tag, err);
417 mutt_edit_file (NONULL (Visual), path);
419 buf = be_snarf_file (path, buf, &bufmax, &buflen, 0);
421 addstr (_("(continue)\n"));
425 be_barf_file (*p ? p : path, buf, buflen);
432 printw (_("%s: unknown editor command (~? for help)\n"), tmp);
436 else if (mutt_strcmp (".", tmp) == 0)
439 safe_strcat (tmp, sizeof (tmp), "\n");
440 if (buflen == bufmax)
441 safe_realloc (&buf, sizeof (char *) * (bufmax += 25));
442 buf[buflen++] = safe_strdup (tmp[1] == '~' ? tmp + 1 : tmp);
449 be_barf_file (path, buf, buflen);
450 be_free_memory (buf, buflen);
452 return (abort ? -1 : 0);