mutt stable branch with some hacks
at master 1370 lines 37 kB view raw
1/* 2 * Copyright (C) 1996-2000,2002,2007,2010,2012 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 2004 g10 Code GmbH 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21# include "config.h" 22#endif 23 24#include "mutt.h" 25#include "mutt_curses.h" 26#include "mutt_idna.h" 27#include "mutt_menu.h" 28#include "rfc1524.h" 29#include "mime.h" 30#include "attach.h" 31#include "mapping.h" 32#include "mailbox.h" 33#include "sort.h" 34#include "charset.h" 35 36#ifdef MIXMASTER 37#include "remailer.h" 38#endif 39 40#include <errno.h> 41#include <string.h> 42#include <sys/stat.h> 43#include <sys/wait.h> 44#include <unistd.h> 45#include <stdlib.h> 46 47static const char* There_are_no_attachments = N_("There are no attachments."); 48 49#define CHECK_COUNT if (idxlen == 0) { mutt_error _(There_are_no_attachments); break; } 50 51 52 53enum 54{ 55 HDR_FROM = 0, 56 HDR_TO, 57 HDR_CC, 58 HDR_BCC, 59 HDR_SUBJECT, 60 HDR_REPLYTO, 61 HDR_FCC, 62 63#ifdef MIXMASTER 64 HDR_MIX, 65#endif 66 67 HDR_CRYPT, 68 HDR_CRYPTINFO, 69 70 HDR_ATTACH = (HDR_FCC + 5) /* where to start printing the attachments */ 71}; 72 73#define HDR_XOFFSET 10 74#define TITLE_FMT "%10s" /* Used for Prompts, which are ASCII */ 75#define W (MuttIndexWindow->cols - HDR_XOFFSET) 76 77static const char * const Prompts[] = 78{ 79 "From: ", 80 "To: ", 81 "Cc: ", 82 "Bcc: ", 83 "Subject: ", 84 "Reply-To: ", 85 "Fcc: " 86}; 87 88static const struct mapping_t ComposeHelp[] = { 89 { N_("Send"), OP_COMPOSE_SEND_MESSAGE }, 90 { N_("Abort"), OP_EXIT }, 91 { "To", OP_COMPOSE_EDIT_TO }, 92 { "CC", OP_COMPOSE_EDIT_CC }, 93 { "Subj", OP_COMPOSE_EDIT_SUBJECT }, 94 { N_("Attach file"), OP_COMPOSE_ATTACH_FILE }, 95 { N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION }, 96 { N_("Help"), OP_HELP }, 97 { NULL, 0 } 98}; 99 100static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num) 101{ 102 mutt_FormatString (b, blen, 0, MuttIndexWindow->cols, NONULL (AttachFormat), mutt_attach_fmt, 103 (unsigned long)(((ATTACHPTR **) menu->data)[num]), 104 MUTT_FORMAT_STAT_FILE | MUTT_FORMAT_ARROWCURSOR); 105} 106 107 108 109#include "mutt_crypt.h" 110 111static void redraw_crypt_lines (HEADER *msg) 112{ 113 mutt_window_mvprintw (MuttIndexWindow, HDR_CRYPT, 0, TITLE_FMT, "Security: "); 114 115 if ((WithCrypto & (APPLICATION_PGP | APPLICATION_SMIME)) == 0) 116 { 117 addstr(_("Not supported")); 118 return; 119 } 120 121 if ((msg->security & (ENCRYPT | SIGN)) == (ENCRYPT | SIGN)) 122 addstr (_("Sign, Encrypt")); 123 else if (msg->security & ENCRYPT) 124 addstr (_("Encrypt")); 125 else if (msg->security & SIGN) 126 addstr (_("Sign")); 127 else 128 addstr (_("None")); 129 130 if ((msg->security & (ENCRYPT | SIGN))) 131 { 132 if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) 133 { 134 if ((msg->security & INLINE)) 135 addstr (_(" (inline PGP)")); 136 else 137 addstr (_(" (PGP/MIME)")); 138 } 139 else if ((WithCrypto & APPLICATION_SMIME) && 140 (msg->security & APPLICATION_SMIME)) 141 addstr (_(" (S/MIME)")); 142 } 143 144 if (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT)) 145 addstr (_(" (OppEnc mode)")); 146 147 mutt_window_clrtoeol (MuttIndexWindow); 148 mutt_window_move (MuttIndexWindow, HDR_CRYPTINFO, 0); 149 mutt_window_clrtoeol (MuttIndexWindow); 150 151 if ((WithCrypto & APPLICATION_PGP) 152 && (msg->security & APPLICATION_PGP) && (msg->security & SIGN)) 153 printw (TITLE_FMT "%s", _("sign as: "), PgpSignAs ? PgpSignAs : _("<default>")); 154 155 if ((WithCrypto & APPLICATION_SMIME) 156 && (msg->security & APPLICATION_SMIME) && (msg->security & SIGN)) { 157 printw (TITLE_FMT "%s", _("sign as: "), SmimeDefaultKey ? SmimeDefaultKey : _("<default>")); 158 } 159 160 if ((WithCrypto & APPLICATION_SMIME) 161 && (msg->security & APPLICATION_SMIME) 162 && (msg->security & ENCRYPT) 163 && SmimeCryptAlg 164 && *SmimeCryptAlg) { 165 mutt_window_mvprintw (MuttIndexWindow, HDR_CRYPTINFO, 40, "%s%s", _("Encrypt with: "), 166 NONULL(SmimeCryptAlg)); 167 } 168} 169 170 171#ifdef MIXMASTER 172 173static void redraw_mix_line (LIST *chain) 174{ 175 int c; 176 char *t; 177 178 /* L10N: "Mix" refers to the MixMaster chain for anonymous email */ 179 mutt_window_mvprintw (MuttIndexWindow, HDR_MIX, 0, TITLE_FMT, _("Mix: ")); 180 181 if (!chain) 182 { 183 addstr ("<no chain defined>"); 184 mutt_window_clrtoeol (MuttIndexWindow); 185 return; 186 } 187 188 for (c = 12; chain; chain = chain->next) 189 { 190 t = chain->data; 191 if (t && t[0] == '0' && t[1] == '\0') 192 t = "<random>"; 193 194 if (c + mutt_strlen (t) + 2 >= MuttIndexWindow->cols) 195 break; 196 197 addstr (NONULL(t)); 198 if (chain->next) 199 addstr (", "); 200 201 c += mutt_strlen (t) + 2; 202 } 203} 204#endif /* MIXMASTER */ 205 206static int 207check_attachments(ATTACHPTR **idx, short idxlen) 208{ 209 int i, r; 210 struct stat st; 211 char pretty[_POSIX_PATH_MAX], msg[_POSIX_PATH_MAX + SHORT_STRING]; 212 213 for (i = 0; i < idxlen; i++) 214 { 215 strfcpy(pretty, idx[i]->content->filename, sizeof(pretty)); 216 if(stat(idx[i]->content->filename, &st) != 0) 217 { 218 mutt_pretty_mailbox(pretty, sizeof (pretty)); 219 mutt_error(_("%s [#%d] no longer exists!"), 220 pretty, i+1); 221 return -1; 222 } 223 224 if(idx[i]->content->stamp < st.st_mtime) 225 { 226 mutt_pretty_mailbox(pretty, sizeof (pretty)); 227 snprintf(msg, sizeof(msg), _("%s [#%d] modified. Update encoding?"), 228 pretty, i+1); 229 230 if((r = mutt_yesorno(msg, MUTT_YES)) == MUTT_YES) 231 mutt_update_encoding(idx[i]->content); 232 else if(r == -1) 233 return -1; 234 } 235 } 236 237 return 0; 238} 239 240static void draw_envelope_addr (int line, ADDRESS *addr) 241{ 242 char buf[LONG_STRING]; 243 244 buf[0] = 0; 245 rfc822_write_address (buf, sizeof (buf), addr, 1); 246 mutt_window_mvprintw (MuttIndexWindow, line, 0, TITLE_FMT, Prompts[line]); 247 mutt_paddstr (W, buf); 248} 249 250static void draw_envelope (HEADER *msg, char *fcc) 251{ 252 draw_envelope_addr (HDR_FROM, msg->env->from); 253 draw_envelope_addr (HDR_TO, msg->env->to); 254 draw_envelope_addr (HDR_CC, msg->env->cc); 255 draw_envelope_addr (HDR_BCC, msg->env->bcc); 256 mutt_window_mvprintw (MuttIndexWindow, HDR_SUBJECT, 0, TITLE_FMT, Prompts[HDR_SUBJECT]); 257 mutt_paddstr (W, NONULL (msg->env->subject)); 258 draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to); 259 mutt_window_mvprintw (MuttIndexWindow, HDR_FCC, 0, TITLE_FMT, Prompts[HDR_FCC]); 260 mutt_paddstr (W, fcc); 261 262 if (WithCrypto) 263 redraw_crypt_lines (msg); 264 265#ifdef MIXMASTER 266 redraw_mix_line (msg->chain); 267#endif 268 269 SETCOLOR (MT_COLOR_STATUS); 270 mutt_window_mvaddstr (MuttIndexWindow, HDR_ATTACH - 1, 0, _("-- Attachments")); 271 mutt_window_clrtoeol (MuttIndexWindow); 272 273 NORMAL_COLOR; 274} 275 276static int edit_address_list (int line, ADDRESS **addr) 277{ 278 char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */ 279 char *err = NULL; 280 281 mutt_addrlist_to_local (*addr); 282 rfc822_write_address (buf, sizeof (buf), *addr, 0); 283 if (mutt_get_field (Prompts[line], buf, sizeof (buf), MUTT_ALIAS) == 0) 284 { 285 rfc822_free_address (addr); 286 *addr = mutt_parse_adrlist (*addr, buf); 287 *addr = mutt_expand_aliases (*addr); 288 } 289 290 if (option (OPTNEEDREDRAW)) 291 { 292 unset_option (OPTNEEDREDRAW); 293 return (REDRAW_FULL); 294 } 295 296 if (mutt_addrlist_to_intl (*addr, &err) != 0) 297 { 298 mutt_error (_("Warning: '%s' is a bad IDN."), err); 299 mutt_refresh(); 300 FREE (&err); 301 } 302 303 /* redraw the expanded list so the user can see the result */ 304 buf[0] = 0; 305 rfc822_write_address (buf, sizeof (buf), *addr, 1); 306 mutt_window_move (MuttIndexWindow, line, HDR_XOFFSET); 307 mutt_paddstr (W, buf); 308 309 return 0; 310} 311 312static int delete_attachment (MUTTMENU *menu, short *idxlen, int x) 313{ 314 ATTACHPTR **idx = (ATTACHPTR **) menu->data; 315 int y; 316 317 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 318 319 if (x == 0 && menu->max == 1) 320 { 321 mutt_error _("You may not delete the only attachment."); 322 idx[x]->content->tagged = 0; 323 return (-1); 324 } 325 326 for (y = 0; y < *idxlen; y++) 327 { 328 if (idx[y]->content->next == idx[x]->content) 329 { 330 idx[y]->content->next = idx[x]->content->next; 331 break; 332 } 333 } 334 335 idx[x]->content->next = NULL; 336 idx[x]->content->parts = NULL; 337 mutt_free_body (&(idx[x]->content)); 338 FREE (&idx[x]->tree); 339 FREE (&idx[x]); 340 for (; x < *idxlen - 1; x++) 341 idx[x] = idx[x+1]; 342 idx[*idxlen - 1] = NULL; 343 menu->max = --(*idxlen); 344 345 return (0); 346} 347 348static void update_idx (MUTTMENU *menu, ATTACHPTR **idx, short idxlen) 349{ 350 idx[idxlen]->level = (idxlen > 0) ? idx[idxlen-1]->level : 0; 351 if (idxlen) 352 idx[idxlen - 1]->content->next = idx[idxlen]->content; 353 idx[idxlen]->content->aptr = idx[idxlen]; 354 menu->current = idxlen++; 355 mutt_update_tree (idx, idxlen); 356 menu->max = idxlen; 357 return; 358} 359 360 361/* 362 * cum_attachs_size: Cumulative Attachments Size 363 * 364 * Returns the total number of bytes used by the attachments in the 365 * attachment list _after_ content-transfer-encodings have been 366 * applied. 367 * 368 */ 369 370static unsigned long cum_attachs_size (MUTTMENU *menu) 371{ 372 size_t s; 373 unsigned short i; 374 ATTACHPTR **idx = menu->data; 375 CONTENT *info; 376 BODY *b; 377 378 for (i = 0, s = 0; i < menu->max; i++) 379 { 380 b = idx[i]->content; 381 382 if (!b->content) 383 b->content = mutt_get_content_info (b->filename, b); 384 385 if ((info = b->content)) 386 { 387 switch (b->encoding) 388 { 389 case ENCQUOTEDPRINTABLE: 390 s += 3 * (info->lobin + info->hibin) + info->ascii + info->crlf; 391 break; 392 case ENCBASE64: 393 s += (4 * (info->lobin + info->hibin + info->ascii + info->crlf)) / 3; 394 break; 395 default: 396 s += info->lobin + info->hibin + info->ascii + info->crlf; 397 break; 398 } 399 } 400 } 401 402 return s; 403} 404 405/* prototype for use below */ 406static void compose_status_line (char *buf, size_t buflen, size_t col, int cols, MUTTMENU *menu, 407 const char *p); 408 409/* 410 * compose_format_str() 411 * 412 * %a = total number of attachments 413 * %h = hostname [option] 414 * %l = approx. length of current message (in bytes) 415 * %v = Mutt version 416 * 417 * This function is similar to status_format_str(). Look at that function for 418 * help when modifying this function. 419 */ 420 421static const char * 422compose_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src, 423 const char *prefix, const char *ifstring, 424 const char *elsestring, 425 unsigned long data, format_flag flags) 426{ 427 char fmt[SHORT_STRING], tmp[SHORT_STRING]; 428 int optional = (flags & MUTT_FORMAT_OPTIONAL); 429 MUTTMENU *menu = (MUTTMENU *) data; 430 431 *buf = 0; 432 switch (op) 433 { 434 case 'a': /* total number of attachments */ 435 snprintf (fmt, sizeof (fmt), "%%%sd", prefix); 436 snprintf (buf, buflen, fmt, menu->max); 437 break; 438 439 case 'h': /* hostname */ 440 snprintf (fmt, sizeof (fmt), "%%%ss", prefix); 441 snprintf (buf, buflen, fmt, NONULL(Hostname)); 442 break; 443 444 case 'l': /* approx length of current message in bytes */ 445 snprintf (fmt, sizeof (fmt), "%%%ss", prefix); 446 mutt_pretty_size (tmp, sizeof (tmp), menu ? cum_attachs_size(menu) : 0); 447 snprintf (buf, buflen, fmt, tmp); 448 break; 449 450 case 'v': 451 snprintf (fmt, sizeof (fmt), "Mutt %%s"); 452 snprintf (buf, buflen, fmt, MUTT_VERSION); 453 break; 454 455 case 0: 456 *buf = 0; 457 return (src); 458 459 default: 460 snprintf (buf, buflen, "%%%s%c", prefix, op); 461 break; 462 } 463 464 if (optional) 465 compose_status_line (buf, buflen, col, cols, menu, ifstring); 466 else if (flags & MUTT_FORMAT_OPTIONAL) 467 compose_status_line (buf, buflen, col, cols, menu, elsestring); 468 469 return (src); 470} 471 472static void compose_status_line (char *buf, size_t buflen, size_t col, int cols, 473 MUTTMENU *menu, const char *p) 474{ 475 mutt_FormatString (buf, buflen, col, cols, p, compose_format_str, 476 (unsigned long) menu, 0); 477} 478 479 480/* return values: 481 * 482 * 1 message should be postponed 483 * 0 normal exit 484 * -1 abort message 485 */ 486int mutt_compose_menu (HEADER *msg, /* structure for new message */ 487 char *fcc, /* where to save a copy of the message */ 488 size_t fcclen, 489 HEADER *cur, /* current message */ 490 int flags) 491{ 492 char helpstr[LONG_STRING]; 493 char buf[LONG_STRING]; 494 char fname[_POSIX_PATH_MAX]; 495 MUTTMENU *menu; 496 ATTACHPTR **idx = NULL; 497 short idxlen = 0; 498 short idxmax = 0; 499 int i, close = 0; 500 int r = -1; /* return value */ 501 int op = 0; 502 int loop = 1; 503 int fccSet = 0; /* has the user edited the Fcc: field ? */ 504 CONTEXT *ctx = NULL, *this = NULL; 505 /* Sort, SortAux could be changed in mutt_index_menu() */ 506 int oldSort, oldSortAux; 507 struct stat st; 508 509 mutt_attach_init (msg->content); 510 idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); 511 512 menu = mutt_new_menu (MENU_COMPOSE); 513 menu->offset = HDR_ATTACH; 514 menu->max = idxlen; 515 menu->make_entry = snd_entry; 516 menu->tag = mutt_tag_attach; 517 menu->data = idx; 518 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp); 519 520 while (loop) 521 { 522 switch (op = mutt_menuLoop (menu)) 523 { 524 case OP_REDRAW: 525 draw_envelope (msg, fcc); 526 menu->offset = HDR_ATTACH; 527 menu->pagelen = MuttIndexWindow->rows - HDR_ATTACH; 528 break; 529 case OP_COMPOSE_EDIT_FROM: 530 menu->redraw = edit_address_list (HDR_FROM, &msg->env->from); 531 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 532 break; 533 case OP_COMPOSE_EDIT_TO: 534 menu->redraw = edit_address_list (HDR_TO, &msg->env->to); 535 if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) 536 { 537 crypt_opportunistic_encrypt (msg); 538 redraw_crypt_lines (msg); 539 } 540 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 541 break; 542 case OP_COMPOSE_EDIT_BCC: 543 menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc); 544 if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) 545 { 546 crypt_opportunistic_encrypt (msg); 547 redraw_crypt_lines (msg); 548 } 549 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 550 break; 551 case OP_COMPOSE_EDIT_CC: 552 menu->redraw = edit_address_list (HDR_CC, &msg->env->cc); 553 if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) 554 { 555 crypt_opportunistic_encrypt (msg); 556 redraw_crypt_lines (msg); 557 } 558 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 559 break; 560 case OP_COMPOSE_EDIT_SUBJECT: 561 if (msg->env->subject) 562 strfcpy (buf, msg->env->subject, sizeof (buf)); 563 else 564 buf[0] = 0; 565 if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0) 566 { 567 mutt_str_replace (&msg->env->subject, buf); 568 mutt_window_move (MuttIndexWindow, HDR_SUBJECT, HDR_XOFFSET); 569 if (msg->env->subject) 570 mutt_paddstr (W, msg->env->subject); 571 else 572 mutt_window_clrtoeol(MuttIndexWindow); 573 } 574 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 575 break; 576 case OP_COMPOSE_EDIT_REPLY_TO: 577 menu->redraw = edit_address_list (HDR_REPLYTO, &msg->env->reply_to); 578 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 579 break; 580 case OP_COMPOSE_EDIT_FCC: 581 strfcpy (buf, fcc, sizeof (buf)); 582 if (mutt_get_field ("Fcc: ", buf, sizeof (buf), MUTT_FILE | MUTT_CLEAR) == 0) 583 { 584 strfcpy (fcc, buf, fcclen); 585 mutt_pretty_mailbox (fcc, fcclen); 586 mutt_window_move (MuttIndexWindow, HDR_FCC, HDR_XOFFSET); 587 mutt_paddstr (W, fcc); 588 fccSet = 1; 589 } 590 MAYBE_REDRAW (menu->redraw); 591 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 592 break; 593 case OP_COMPOSE_EDIT_MESSAGE: 594 if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS)) 595 { 596 mutt_edit_file (Editor, msg->content->filename); 597 mutt_update_encoding (msg->content); 598 menu->redraw = REDRAW_FULL; 599 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 600 break; 601 } 602 /* fall through */ 603 case OP_COMPOSE_EDIT_HEADERS: 604 if (mutt_strcmp ("builtin", Editor) != 0 && 605 (op == OP_COMPOSE_EDIT_HEADERS || 606 (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS)))) 607 { 608 char *tag = NULL, *err = NULL; 609 mutt_env_to_local (msg->env); 610 mutt_edit_headers (NONULL (Editor), msg->content->filename, msg, 611 fcc, fcclen); 612 if (mutt_env_to_intl (msg->env, &tag, &err)) 613 { 614 mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); 615 FREE (&err); 616 } 617 if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) 618 crypt_opportunistic_encrypt (msg); 619 } 620 else 621 { 622 /* this is grouped with OP_COMPOSE_EDIT_HEADERS because the 623 attachment list could change if the user invokes ~v to edit 624 the message with headers, in which we need to execute the 625 code below to regenerate the index array */ 626 mutt_builtin_editor (msg->content->filename, msg, cur); 627 } 628 mutt_update_encoding (msg->content); 629 630 /* attachments may have been added */ 631 if (idxlen && idx[idxlen - 1]->content->next) 632 { 633 for (i = 0; i < idxlen; i++) 634 { 635 FREE (&idx[i]->tree); 636 FREE (&idx[i]); 637 } 638 idxlen = 0; 639 idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); 640 menu->data = idx; 641 menu->max = idxlen; 642 } 643 644 menu->redraw = REDRAW_FULL; 645 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 646 break; 647 648 649 650 case OP_COMPOSE_ATTACH_KEY: 651 if (!(WithCrypto & APPLICATION_PGP)) 652 break; 653 if (idxlen == idxmax) 654 { 655 safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5)); 656 menu->data = idx; 657 } 658 659 idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); 660 if ((idx[idxlen]->content = crypt_pgp_make_key_attachment(NULL)) != NULL) 661 { 662 update_idx (menu, idx, idxlen++); 663 menu->redraw |= REDRAW_INDEX; 664 } 665 else 666 FREE (&idx[idxlen]); 667 668 menu->redraw |= REDRAW_STATUS; 669 670 if (option(OPTNEEDREDRAW)) 671 { 672 menu->redraw = REDRAW_FULL; 673 unset_option(OPTNEEDREDRAW); 674 } 675 676 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 677 break; 678 679 680 case OP_COMPOSE_ATTACH_FILE: 681 { 682 char *prompt, **files; 683 int error, numfiles; 684 685 fname[0] = 0; 686 prompt = _("Attach file"); 687 numfiles = 0; 688 files = NULL; 689 690 if (_mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files, &numfiles) == -1 || 691 *fname == '\0') 692 break; 693 694 if (idxlen + numfiles >= idxmax) 695 { 696 safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + numfiles)); 697 menu->data = idx; 698 } 699 700 error = 0; 701 if (numfiles > 1) 702 mutt_message _("Attaching selected files..."); 703 for (i = 0; i < numfiles; i++) 704 { 705 char *att = files[i]; 706 idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); 707 idx[idxlen]->unowned = 1; 708 idx[idxlen]->content = mutt_make_file_attach (att); 709 if (idx[idxlen]->content != NULL) 710 update_idx (menu, idx, idxlen++); 711 else 712 { 713 error = 1; 714 mutt_error (_("Unable to attach %s!"), att); 715 FREE (&idx[idxlen]); 716 } 717 } 718 719 FREE (&files); 720 if (!error) mutt_clear_error (); 721 722 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; 723 } 724 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 725 break; 726 727 case OP_COMPOSE_ATTACH_MESSAGE: 728 { 729 char *prompt; 730 HEADER *h; 731 732 fname[0] = 0; 733 prompt = _("Open mailbox to attach message from"); 734 735 if (Context) 736 { 737 strfcpy (fname, NONULL (Context->path), sizeof (fname)); 738 mutt_pretty_mailbox (fname, sizeof (fname)); 739 } 740 741 if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0]) 742 break; 743 744 mutt_expand_path (fname, sizeof (fname)); 745#ifdef USE_IMAP 746 if (!mx_is_imap (fname)) 747#endif 748#ifdef USE_POP 749 if (!mx_is_pop (fname)) 750#endif 751 /* check to make sure the file exists and is readable */ 752 if (access (fname, R_OK) == -1) 753 { 754 mutt_perror (fname); 755 break; 756 } 757 758 menu->redraw = REDRAW_FULL; 759 760 ctx = mx_open_mailbox (fname, MUTT_READONLY, NULL); 761 if (ctx == NULL) 762 { 763 mutt_error (_("Unable to open mailbox %s"), fname); 764 break; 765 } 766 767 if (!ctx->msgcount) 768 { 769 mx_close_mailbox (ctx, NULL); 770 FREE (&ctx); 771 mutt_error _("No messages in that folder."); 772 break; 773 } 774 775 this = Context; /* remember current folder and sort methods*/ 776 oldSort = Sort; oldSortAux = SortAux; 777 778 Context = ctx; 779 set_option(OPTATTACHMSG); 780 mutt_message _("Tag the messages you want to attach!"); 781 close = mutt_index_menu (); 782 unset_option(OPTATTACHMSG); 783 784 if (!Context) 785 { 786 /* go back to the folder we started from */ 787 Context = this; 788 /* Restore old $sort and $sort_aux */ 789 Sort = oldSort; 790 SortAux = oldSortAux; 791 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; 792 break; 793 } 794 795 if (idxlen + Context->tagged >= idxmax) 796 { 797 safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + Context->tagged)); 798 menu->data = idx; 799 } 800 801 for (i = 0; i < Context->msgcount; i++) 802 { 803 h = Context->hdrs[i]; 804 if (h->tagged) 805 { 806 idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); 807 idx[idxlen]->content = mutt_make_message_attach (Context, h, 1); 808 if (idx[idxlen]->content != NULL) 809 update_idx (menu, idx, idxlen++); 810 else 811 { 812 mutt_error _("Unable to attach!"); 813 FREE (&idx[idxlen]); 814 } 815 } 816 } 817 menu->redraw |= REDRAW_FULL; 818 819 if (close == OP_QUIT) 820 mx_close_mailbox (Context, NULL); 821 else 822 mx_fastclose_mailbox (Context); 823 FREE (&Context); 824 825 /* go back to the folder we started from */ 826 Context = this; 827 /* Restore old $sort and $sort_aux */ 828 Sort = oldSort; 829 SortAux = oldSortAux; 830 } 831 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 832 break; 833 834 case OP_DELETE: 835 CHECK_COUNT; 836 if (idx[menu->current]->unowned) 837 idx[menu->current]->content->unlink = 0; 838 if (delete_attachment (menu, &idxlen, menu->current) == -1) 839 break; 840 mutt_update_tree (idx, idxlen); 841 if (idxlen) 842 { 843 if (menu->current > idxlen - 1) 844 menu->current = idxlen - 1; 845 } 846 else 847 menu->current = 0; 848 849 if (menu->current == 0) 850 msg->content = idx[0]->content; 851 852 menu->redraw |= REDRAW_STATUS; 853 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 854 break; 855 856#define CURRENT idx[menu->current]->content 857 858 case OP_COMPOSE_TOGGLE_RECODE: 859 { 860 CHECK_COUNT; 861 if (!mutt_is_text_part (CURRENT)) 862 { 863 mutt_error (_("Recoding only affects text attachments.")); 864 break; 865 } 866 CURRENT->noconv = !CURRENT->noconv; 867 if (CURRENT->noconv) 868 mutt_message (_("The current attachment won't be converted.")); 869 else 870 mutt_message (_("The current attachment will be converted.")); 871 menu->redraw = REDRAW_CURRENT; 872 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 873 break; 874 } 875#undef CURRENT 876 877 case OP_COMPOSE_EDIT_DESCRIPTION: 878 CHECK_COUNT; 879 strfcpy (buf, 880 idx[menu->current]->content->description ? 881 idx[menu->current]->content->description : "", 882 sizeof (buf)); 883 /* header names should not be translated */ 884 if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0) 885 { 886 mutt_str_replace (&idx[menu->current]->content->description, buf); 887 menu->redraw = REDRAW_CURRENT; 888 } 889 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 890 break; 891 892 case OP_COMPOSE_UPDATE_ENCODING: 893 CHECK_COUNT; 894 if (menu->tagprefix) 895 { 896 BODY *top; 897 for (top = msg->content; top; top = top->next) 898 { 899 if (top->tagged) 900 mutt_update_encoding (top); 901 } 902 menu->redraw = REDRAW_FULL; 903 } 904 else 905 { 906 mutt_update_encoding(idx[menu->current]->content); 907 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; 908 } 909 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 910 break; 911 912 case OP_COMPOSE_TOGGLE_DISPOSITION: 913 /* toggle the content-disposition between inline/attachment */ 914 idx[menu->current]->content->disposition = (idx[menu->current]->content->disposition == DISPINLINE) ? DISPATTACH : DISPINLINE; 915 menu->redraw = REDRAW_CURRENT; 916 break; 917 918 case OP_EDIT_TYPE: 919 CHECK_COUNT; 920 { 921 mutt_edit_content_type (NULL, idx[menu->current]->content, NULL); 922 923 /* this may have been a change to text/something */ 924 mutt_update_encoding (idx[menu->current]->content); 925 926 menu->redraw = REDRAW_CURRENT; 927 } 928 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 929 break; 930 931 case OP_COMPOSE_EDIT_ENCODING: 932 CHECK_COUNT; 933 strfcpy (buf, ENCODING (idx[menu->current]->content->encoding), 934 sizeof (buf)); 935 if (mutt_get_field ("Content-Transfer-Encoding: ", buf, 936 sizeof (buf), 0) == 0 && buf[0]) 937 { 938 if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED) 939 { 940 idx[menu->current]->content->encoding = i; 941 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; 942 mutt_clear_error(); 943 } 944 else 945 mutt_error _("Invalid encoding."); 946 } 947 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 948 break; 949 950 case OP_COMPOSE_SEND_MESSAGE: 951 952 /* Note: We don't invoke send2-hook here, since we want to leave 953 * users an opportunity to change settings from the ":" prompt. 954 */ 955 956 if(check_attachments(idx, idxlen) != 0) 957 { 958 menu->redraw = REDRAW_FULL; 959 break; 960 } 961 962 963#ifdef MIXMASTER 964 if (msg->chain && mix_check_message (msg) != 0) 965 break; 966#endif 967 968 if (!fccSet && *fcc) 969 { 970 if ((i = query_quadoption (OPT_COPY, 971 _("Save a copy of this message?"))) == -1) 972 break; 973 else if (i == MUTT_NO) 974 *fcc = 0; 975 } 976 977 loop = 0; 978 r = 0; 979 break; 980 981 case OP_COMPOSE_EDIT_FILE: 982 CHECK_COUNT; 983 mutt_edit_file (NONULL(Editor), idx[menu->current]->content->filename); 984 mutt_update_encoding (idx[menu->current]->content); 985 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; 986 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 987 break; 988 989 case OP_COMPOSE_TOGGLE_UNLINK: 990 CHECK_COUNT; 991 idx[menu->current]->content->unlink = !idx[menu->current]->content->unlink; 992 993#if 0 994 /* OPTRESOLVE is otherwise ignored on this menu. 995 * Where's the bug? 996 */ 997 998 if (option (OPTRESOLVE) && menu->current + 1 < menu->max) 999 menu->current++; 1000# endif 1001 menu->redraw = REDRAW_INDEX; 1002 /* No send2hook since this doesn't change the message. */ 1003 break; 1004 1005 case OP_COMPOSE_GET_ATTACHMENT: 1006 CHECK_COUNT; 1007 if(menu->tagprefix) 1008 { 1009 BODY *top; 1010 for(top = msg->content; top; top = top->next) 1011 { 1012 if(top->tagged) 1013 mutt_get_tmp_attachment(top); 1014 } 1015 menu->redraw = REDRAW_FULL; 1016 } 1017 else if (mutt_get_tmp_attachment(idx[menu->current]->content) == 0) 1018 menu->redraw = REDRAW_CURRENT; 1019 1020 /* No send2hook since this doesn't change the message. */ 1021 break; 1022 1023 case OP_COMPOSE_RENAME_ATTACHMENT: 1024 { 1025 char *src; 1026 int ret; 1027 1028 CHECK_COUNT; 1029 if (idx[menu->current]->content->d_filename) 1030 src = idx[menu->current]->content->d_filename; 1031 else 1032 src = idx[menu->current]->content->filename; 1033 strfcpy (fname, mutt_basename (NONULL (src)), sizeof (fname)); 1034 ret = mutt_get_field (_("Send attachment with name: "), 1035 fname, sizeof (fname), MUTT_FILE); 1036 if (ret == 0) 1037 { 1038 /* 1039 * As opposed to RENAME_FILE, we don't check fname[0] because it's 1040 * valid to set an empty string here, to erase what was set 1041 */ 1042 mutt_str_replace (&idx[menu->current]->content->d_filename, fname); 1043 menu->redraw = REDRAW_CURRENT; 1044 } 1045 } 1046 break; 1047 1048 case OP_COMPOSE_RENAME_FILE: 1049 CHECK_COUNT; 1050 strfcpy (fname, idx[menu->current]->content->filename, sizeof (fname)); 1051 mutt_pretty_mailbox (fname, sizeof (fname)); 1052 if (mutt_get_field (_("Rename to: "), fname, sizeof (fname), MUTT_FILE) 1053 == 0 && fname[0]) 1054 { 1055 if (stat(idx[menu->current]->content->filename, &st) == -1) 1056 { 1057 /* L10N: 1058 "stat" is a system call. Do "man 2 stat" for more information. */ 1059 mutt_error (_("Can't stat %s: %s"), fname, strerror (errno)); 1060 break; 1061 } 1062 1063 mutt_expand_path (fname, sizeof (fname)); 1064 if(mutt_rename_file (idx[menu->current]->content->filename, fname)) 1065 break; 1066 1067 mutt_str_replace (&idx[menu->current]->content->filename, fname); 1068 menu->redraw = REDRAW_CURRENT; 1069 1070 if(idx[menu->current]->content->stamp >= st.st_mtime) 1071 mutt_stamp_attachment(idx[menu->current]->content); 1072 1073 } 1074 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1075 break; 1076 1077 case OP_COMPOSE_NEW_MIME: 1078 { 1079 char type[STRING]; 1080 char *p; 1081 int itype; 1082 FILE *fp; 1083 1084 mutt_window_clearline (MuttMessageWindow, 0); 1085 fname[0] = 0; 1086 if (mutt_get_field (_("New file: "), fname, sizeof (fname), MUTT_FILE) 1087 != 0 || !fname[0]) 1088 continue; 1089 mutt_expand_path (fname, sizeof (fname)); 1090 1091 /* Call to lookup_mime_type () ? maybe later */ 1092 type[0] = 0; 1093 if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0 1094 || !type[0]) 1095 continue; 1096 1097 if (!(p = strchr (type, '/'))) 1098 { 1099 mutt_error _("Content-Type is of the form base/sub"); 1100 continue; 1101 } 1102 *p++ = 0; 1103 if ((itype = mutt_check_mime_type (type)) == TYPEOTHER) 1104 { 1105 mutt_error (_("Unknown Content-Type %s"), type); 1106 continue; 1107 } 1108 if (idxlen == idxmax) 1109 { 1110 safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5)); 1111 menu->data = idx; 1112 } 1113 1114 idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); 1115 /* Touch the file */ 1116 if (!(fp = safe_fopen (fname, "w"))) 1117 { 1118 mutt_error (_("Can't create file %s"), fname); 1119 FREE (&idx[idxlen]); 1120 continue; 1121 } 1122 safe_fclose (&fp); 1123 1124 if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL) 1125 { 1126 mutt_error _("What we have here is a failure to make an attachment"); 1127 continue; 1128 } 1129 update_idx (menu, idx, idxlen++); 1130 1131 idx[menu->current]->content->type = itype; 1132 mutt_str_replace (&idx[menu->current]->content->subtype, p); 1133 idx[menu->current]->content->unlink = 1; 1134 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; 1135 1136 if (mutt_compose_attachment (idx[menu->current]->content)) 1137 { 1138 mutt_update_encoding (idx[menu->current]->content); 1139 menu->redraw = REDRAW_FULL; 1140 } 1141 } 1142 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1143 break; 1144 1145 case OP_COMPOSE_EDIT_MIME: 1146 CHECK_COUNT; 1147 if (mutt_edit_attachment (idx[menu->current]->content)) 1148 { 1149 mutt_update_encoding (idx[menu->current]->content); 1150 menu->redraw = REDRAW_FULL; 1151 } 1152 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1153 break; 1154 1155 case OP_VIEW_ATTACH: 1156 case OP_DISPLAY_HEADERS: 1157 CHECK_COUNT; 1158 mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen, NULL, 0); 1159 menu->redraw = REDRAW_FULL; 1160 /* no send2hook, since this doesn't modify the message */ 1161 break; 1162 1163 case OP_SAVE: 1164 CHECK_COUNT; 1165 mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, NULL, menu); 1166 MAYBE_REDRAW (menu->redraw); 1167 /* no send2hook, since this doesn't modify the message */ 1168 break; 1169 1170 case OP_PRINT: 1171 CHECK_COUNT; 1172 mutt_print_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content); 1173 /* no send2hook, since this doesn't modify the message */ 1174 break; 1175 1176 case OP_PIPE: 1177 case OP_FILTER: 1178 CHECK_COUNT; 1179 mutt_pipe_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, op == OP_FILTER); 1180 if (op == OP_FILTER) /* cte might have changed */ 1181 menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT; 1182 menu->redraw |= REDRAW_STATUS; 1183 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1184 break; 1185 1186 case OP_EXIT: 1187 if ((i = query_quadoption (OPT_POSTPONE, _("Postpone this message?"))) == MUTT_NO) 1188 { 1189 for (i = 0; i < idxlen; i++) 1190 if (idx[i]->unowned) 1191 idx[i]->content->unlink = 0; 1192 1193 if (!(flags & MUTT_COMPOSE_NOFREEHEADER)) 1194 { 1195 while (idxlen-- > 0) 1196 { 1197 /* avoid freeing other attachments */ 1198 idx[idxlen]->content->next = NULL; 1199 idx[idxlen]->content->parts = NULL; 1200 mutt_free_body (&idx[idxlen]->content); 1201 FREE (&idx[idxlen]->tree); 1202 FREE (&idx[idxlen]); 1203 } 1204 FREE (&idx); 1205 idxlen = 0; 1206 idxmax = 0; 1207 } 1208 r = -1; 1209 loop = 0; 1210 break; 1211 } 1212 else if (i == -1) 1213 break; /* abort */ 1214 1215 /* fall through to postpone! */ 1216 1217 case OP_COMPOSE_POSTPONE_MESSAGE: 1218 1219 if(check_attachments(idx, idxlen) != 0) 1220 { 1221 menu->redraw = REDRAW_FULL; 1222 break; 1223 } 1224 1225 loop = 0; 1226 r = 1; 1227 break; 1228 1229 case OP_COMPOSE_ISPELL: 1230 endwin (); 1231 snprintf (buf, sizeof (buf), "%s -x %s", NONULL(Ispell), msg->content->filename); 1232 if (mutt_system (buf) == -1) 1233 mutt_error (_("Error running \"%s\"!"), buf); 1234 else 1235 { 1236 mutt_update_encoding (msg->content); 1237 menu->redraw |= REDRAW_STATUS; 1238 } 1239 break; 1240 1241 case OP_COMPOSE_WRITE_MESSAGE: 1242 1243 fname[0] = '\0'; 1244 if (Context) 1245 { 1246 strfcpy (fname, NONULL (Context->path), sizeof (fname)); 1247 mutt_pretty_mailbox (fname, sizeof (fname)); 1248 } 1249 if (idxlen) 1250 msg->content = idx[0]->content; 1251 if (mutt_enter_fname (_("Write message to mailbox"), fname, sizeof (fname), 1252 &menu->redraw, 1) != -1 && fname[0]) 1253 { 1254 mutt_message (_("Writing message to %s ..."), fname); 1255 mutt_expand_path (fname, sizeof (fname)); 1256 1257 if (msg->content->next) 1258 msg->content = mutt_make_multipart (msg->content); 1259 1260 if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0) 1261 msg->content = mutt_remove_multipart (msg->content); 1262 else 1263 mutt_message _("Message written."); 1264 } 1265 break; 1266 1267 1268 1269 case OP_COMPOSE_PGP_MENU: 1270 if (!(WithCrypto & APPLICATION_PGP)) 1271 break; 1272 if ((WithCrypto & APPLICATION_SMIME) 1273 && (msg->security & APPLICATION_SMIME)) 1274 { 1275 if (msg->security & (ENCRYPT | SIGN)) 1276 { 1277 if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "), 1278 MUTT_YES) != MUTT_YES) 1279 { 1280 mutt_clear_error (); 1281 break; 1282 } 1283 msg->security &= ~(ENCRYPT | SIGN); 1284 } 1285 msg->security &= ~APPLICATION_SMIME; 1286 msg->security |= APPLICATION_PGP; 1287 crypt_opportunistic_encrypt (msg); 1288 redraw_crypt_lines (msg); 1289 } 1290 msg->security = crypt_pgp_send_menu (msg, &menu->redraw); 1291 redraw_crypt_lines (msg); 1292 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1293 break; 1294 1295 1296 case OP_FORGET_PASSPHRASE: 1297 crypt_forget_passphrase (); 1298 break; 1299 1300 1301 case OP_COMPOSE_SMIME_MENU: 1302 if (!(WithCrypto & APPLICATION_SMIME)) 1303 break; 1304 1305 if ((WithCrypto & APPLICATION_PGP) 1306 && (msg->security & APPLICATION_PGP)) 1307 { 1308 if (msg->security & (ENCRYPT | SIGN)) 1309 { 1310 if (mutt_yesorno (_("PGP already selected. Clear & continue ? "), 1311 MUTT_YES) != MUTT_YES) 1312 { 1313 mutt_clear_error (); 1314 break; 1315 } 1316 msg->security &= ~(ENCRYPT | SIGN); 1317 } 1318 msg->security &= ~APPLICATION_PGP; 1319 msg->security |= APPLICATION_SMIME; 1320 crypt_opportunistic_encrypt (msg); 1321 redraw_crypt_lines (msg); 1322 } 1323 msg->security = crypt_smime_send_menu(msg, &menu->redraw); 1324 redraw_crypt_lines (msg); 1325 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1326 break; 1327 1328 1329#ifdef MIXMASTER 1330 case OP_COMPOSE_MIX: 1331 1332 mix_make_chain (&msg->chain, &menu->redraw); 1333 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1334 break; 1335#endif 1336 1337 } 1338 1339 /* Draw formatted compose status line */ 1340 if (menu->redraw & REDRAW_STATUS) 1341 { 1342 compose_status_line (buf, sizeof (buf), 0, MuttStatusWindow->cols, menu, NONULL(ComposeFormat)); 1343 mutt_window_move (MuttStatusWindow, 0, 0); 1344 SETCOLOR (MT_COLOR_STATUS); 1345 mutt_paddstr (MuttStatusWindow->cols, buf); 1346 NORMAL_COLOR; 1347 menu->redraw &= ~REDRAW_STATUS; 1348 } 1349 } 1350 1351 mutt_menuDestroy (&menu); 1352 1353 if (idxlen) 1354 { 1355 msg->content = idx[0]->content; 1356 for (i = 0; i < idxlen; i++) 1357 { 1358 idx[i]->content->aptr = NULL; 1359 FREE (&idx[i]->tree); 1360 FREE (&idx[i]); 1361 } 1362 } 1363 else 1364 msg->content = NULL; 1365 1366 FREE (&idx); 1367 1368 return (r); 1369} 1370