/*----------------------------------------------------------------------

            T H E    P I N E    M A I L   S Y S T E M

   Laurence Lundblade and Mike Seibel
   Networks and Distributed Computing
   Computing and Communications
   University of Washington
   Administration Building, AG-44
   Seattle, Washington, 98195, USA
   Internet: lgl@CAC.Washington.EDU
             mikes@CAC.Washington.EDU

   Please address all bugs and comments to "pine-bugs@cac.washington.edu"

   Copyright 1989, 1990, 1991, 1992  University of Washington

    Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee to the University of
   Washington is hereby granted, provided that the above copyright notice
   appears in all copies and that both the above copyright notice and this
   permission notice appear in supporting documentation, and that the name
   of the University of Washington not be used in advertising or publicity
   pertaining to distribution of the software without specific, written
   prior permission.  This software is made available "as is", and
   THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
   WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
   NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
   INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
   (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
   WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  

   Pine is in part based on The Elm Mail System:
    ***********************************************************************
    *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $          *
    *                                                                     *
    * 			Copyright (c) 1986, 1987 Dave Taylor              *
    * 			Copyright (c) 1988, 1989 USENET Community Trust   *
    ***********************************************************************
 

  ----------------------------------------------------------------------*/


/*======================================================================
     mailcmd.c
     The meat and pototoes of mail processing here:
       - initial command processing and dispatch
       - save message
       - capture address off incoming mail
       - jump to specific numbered message
       - open (broach) a new folder
       - search message headers (where is) command
  ====*/

#include "headers.h"


#ifdef ANSI
static MESSAGECACHE *closest_not_deleted(MAILSTREAM *, long, long);
static save(char *, MESSAGECACHE *, long);
static void select_sort(int);
static struct attachment *attachments(int, long, char **, long *);
#ifndef	DOS
void run_viewer(char *, char *);
#endif	/* !DOS */
static int display_attachment(struct attachment *, char *, long);
static void save_attachment(int, struct attachment *, char *, long, char *);

#else
static MESSAGECACHE *closest_not_deleted();
static save();
static void select_sort();
static struct attachment *attachments();
static void save_attachment();
static int display_attachment();
#ifndef	DOS
void run_viewer();
#endif /* !DOS */

#endif


 
/*----------------------------------------------------------------------
         The giant switch on the commands for index and viewing

  Input:  command  -- The command char/code
          in_index -- flag indicating command is from index, rather than view
          orig_command -- The original command typed before pre-processing

  Result: Manifold

          Returns 1 if the message number or attachments to shown changed 
 ---*/
int
process_cmd(command, in_index, orig_command)
        int command, in_index, orig_command;
{
    int           i, mango, question_line, a_changed;
    long          current_sorted_msgno, new_sorted_mess_num, del_count, len,
                  old_sorted_msgno;
    char         *new_folder, sequence[5], prompt[40+MAXFOLDER], *contents;
    MESSAGECACHE *mc;
    ENVELOPE     *e;
    static  int   bump_end_count = 0;
    struct attachment *a;

    dprint(4, (debugfile, "\n - process_cmd((%d)%c) -\n",
                                                 command, (char)command));

    question_line             = - 3;
    ps_global->status_changed = 0;
    ps_global->mangled_screen = 0;
    ps_global->mangled_footer = 0;
    ps_global->mangled_header = 0;
    ps_global->next_screen    = SCREEN_FUN_NULL;
    current_sorted_msgno      = ps_global->current_sorted_msgno;
    old_sorted_msgno          = current_sorted_msgno;
    mc                        = NULL;
    a_changed                 = 0;

    if(command  !=  KEY_DOWN && command != PF6 && command != ctrl('N') &&
       command  !=  'n' && command != '\t')
      bump_end_count = 0;

    switch (command)
      {
          /*------------- Help --------*/
        case OPF1:
        case PF1:
        case '?':
        case ctrl('G'):
          if(ps_global->nr_mode) {
              q_status_message(1, 3,5,"No help text currently available");
              break;
          }
          helper(in_index ? h_mail_index : h_mail_view,
                 in_index ? "HELP FOR MAIL INDEX": "HELP FOR VIEW MAIL", 0);
          dprint(2, (debugfile,"MAIL_CMD: did help command\n"));
          ps_global->mangled_screen = 1;
          break;


          /*--------- return to main menu ------------*/
        case PF3 : 
        case 'm' :
          if(ps_global->nr_mode)
            goto bogus;
          ps_global->next_screen = main_menu_screen;
          dprint(2, (debugfile,"MAIL_CMD: going back to main menu"));
          break;


          /*---------- Read Mail ----------*/
        case PF4:
          dprint(1, (debugfile,"MAIL_CMD: go to %s\n",
                     in_index ? "view" : "index"));		    
          if(in_index) {
              ps_global->next_screen = mail_view_screen;
          }else{
              ps_global->next_screen = mail_index_screen;
          }
          break;
    	    

          /*---------- Quit pine ------------*/
        case 'q':
        case OPF4:
          ps_global->next_screen = quit_screen;
          dprint(1, (debugfile,"MAIL_CMD: quit\n"));		    
          break;


          /*------- View mail --------*/
        case ctrl('M'):
        case ctrl('J'):
        case 'v':
          if(ps_global->max_msgno <= 0) {
              q_status_message(0, 1, 3, "\007No mail to view");
          } else if(in_index) {
              ps_global->next_screen = mail_view_screen;
          } else {
              q_status_message(0, 1, 3, "\007Already viewing Mail");
          }
          break;


          /*------- Mail index ----------*/
        case 'i':
          if(!in_index) {
              ps_global->next_screen = mail_index_screen;
          }else {
              q_status_message(0, 1, 3, "\007Already in Index");
          }
          break;


          /*---------- Previous message ----------*/
        case PF5: 
        case 'p':
        case ctrl('P'):		    
        case KEY_UP:
          /* intercepted in viewer, done here for index */
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 1, 3, "\007No mail in folder");
          } else  if(current_sorted_msgno > 1 ){
              current_sorted_msgno--;
              ps_global->current_sorted_msgno = current_sorted_msgno;
          } else {
              q_status_message(0, 0, 1, "Already on first message");
          }
          break;


          /*---------- Compose message ----------*/
        case OPF5:		    
        case 'c' :
          if(ps_global->nr_mode)
            goto bogus;
          ps_global->prev_screen = in_index ? mail_index_screen :
                                        mail_view_screen;
          compose_screen(ps_global);
          ps_global->mangled_screen = 1;
          break;


          /*---------- Next Message ----------*/
        case KEY_DOWN:
        case PF6:
        case ctrl('N'):
        case 'n':
        case '\t':
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 1, 3, "\007No mail in folder");
          } else if(current_sorted_msgno < ps_global->max_msgno) {
              current_sorted_msgno++;
              ps_global->current_sorted_msgno = current_sorted_msgno;
          } else {
              q_status_message(0, 0,1,  "\007No more messages");
              if(bump_end_count++ > 3) {
                  new_mail(NULL, 1, 1); /* FORCE new mail check */
                  bump_end_count = 0;
              }
          }
          break;


          /*---------- print message on paper ----------*/
        case OPF6:
        case 'l' :
          if(ps_global->nr_mode)
            goto bogus;
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 1,3, "\007No mail in folder");
          } else {
              print_message(ps_global->current_sorted_msgno);
          }
          break;



          /*---------- Undelete message ----------*/
        case OPF7:
        case 'u':
          if(ps_global->nr_mode)
            goto bogus;
          dprint(4, (debugfile, "\n - undelete -\n"));
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 1,3, "\007No mail in folder");
              break;
          }
          if(ps_global->mail_stream->readonly) {
              q_status_message(1, 1,3,
                              "Can't undelete message. Mailbox is read-only");
              break;
          }
          e  = mail_fetchenvelope(ps_global->mail_stream,
                                  ps_global->sort[current_sorted_msgno]); 
          mc = mail_elt(ps_global->mail_stream,
                        ps_global->sort[current_sorted_msgno]);
          if(e == NULL || mc == NULL || ps_global->dead_stream) {
              q_status_message(1, 1, 4,
                      "Can't undelete message. Error accessing mail folder");
              break;
          }

          dprint(3,(debugfile, "Undeleted: %s\n", e->message_id));
          if (ps_global->max_msgno < 1) {
             q_status_message(0, 0, 2, "No mail to undelete");
          } else if(!mc->deleted) {
              q_status_message(0, 1,2, 
                           "\007Can't undelete a message that isn't deleted");
          } else {
              sprintf(sequence, "%ld", ps_global->sort[current_sorted_msgno]);
              mail_clearflag(ps_global->mail_stream, sequence, "\\DELETED");
              update_del(0, 1);
              ps_global->status_changed = 1;
              clear_index_cache_ent(current_sorted_msgno);
              q_status_message(0, 1,3,
                           "Deletion mark removed, message won't be deleted");
              if(ps_global->io_error_on_stream) {
                  ps_global->io_error_on_stream = 0;
                  mail_check(ps_global->mail_stream); /* forces write */
              } else {
                  check_point(1, BadTime);
              }
          }
          break;


          /*---------- Expunge ----------*/
        case OPF8:
        case 'x':
          if(ps_global->nr_mode || !in_index)
            goto bogus;
          dprint(2, (debugfile, "\n - expunge -\n"));
          if(ps_global->mail_stream->readonly) {
              q_status_message(1, 2, 4, "Can't expunge. Folder is read-only");
              break;
          }
          del_count = count_deleted(ps_global->mail_stream);
          sprintf(prompt, "Expunge %ld message%s from %s", del_count,
                  plural(del_count), pretty_fn(ps_global->cur_folder));
          ps_global->mangled_footer = 1;
          if(want_to(prompt, 'y', (char **)NULL, 0) == 'n')
            break;
          mc = closest_not_deleted(ps_global->mail_stream,
              		     ps_global->sort[current_sorted_msgno],
              		     ps_global->max_msgno);
          dprint(8,(debugfile, "Expunge max:%ld cur:l%d kill:%d ncur:%ld\n",
                    ps_global->max_msgno, ps_global->current_sorted_msgno,
                    del_count, mc == NULL ? 0 : mc->msgno));
          StartInverse();
          PutLine0(0,1,"**");/*Show something on the screen to indicate delay*/
	  MoveCursor(ps_global->ttyo->screen_rows -3, 0);
          fflush(stdout);

          mail_expunge(ps_global->mail_stream);
#ifdef X_FINISH
          {
              dprint(1, (debugfile, "**** expunge failed ****\n"));
              q_status_message(1, 3,5 "\007Mail expunge failed!");
              break;
          }
#endif
          dprint(2,(debugfile,"expunge complete cur:%ld max:%ld\n",
                    mc==NULL ? 0 : mc->msgno, ps_global->max_msgno));
          /* mm_exists and mm_expunge take care of updating max_msgno*/
          clear_index_cache();
          reset_check_point();
          sort_current_folder();
          if(mc != NULL) {
              long j;
              for(j = 1L; j < ps_global->max_msgno; j++)
                if(ps_global->sort[j] == mc->msgno)
                  break;
              if(j < ps_global->max_msgno)
                ps_global->current_sorted_msgno = j;
              else
                ps_global->current_sorted_msgno = ps_global->max_msgno;
          } else {
             ps_global->current_sorted_msgno = -1;
         }
          current_sorted_msgno         = ps_global->current_sorted_msgno;
          ps_global->mangled_header    = 1; /* update title bar */
          ps_global->mangled_screen    = 1; /* force redraw in index */
          PutLine0(0, 1, "  ");
          EndInverse();
          fflush(stdout);
          if(ps_global->expunge_count > 0) {
              q_status_message3(0, 0,3,
                        "Expunged %s message%s from folder \"%s\"",
                         long2string(ps_global->expunge_count),
                         plural(ps_global->expunge_count),
                         pretty_fn(ps_global->cur_folder));
              ps_global->expunge_count = 0;
          }
          break;


          /*---------- Delete message ----------*/
        case PF11 : 
        case 'd' :
          if(ps_global->nr_mode)
            goto bogus;
          dprint(4, (debugfile, "\n - delete message -\n"));
          if(ps_global->max_msgno <= 0L) {
              q_status_message(0, 1, 3,"\007No mail in folder");
              break;
          }
          if(ps_global->mail_stream->readonly) {
              q_status_message(1, 1,3,
                               "Can't delete message. Mailbox is read-only");
              break;
          }
          if(ps_global->io_error_on_stream) {
              ps_global->io_error_on_stream = 0;
              mail_check(ps_global->mail_stream); /* forces write */
          }
/*          if(ps_global->io_error_on_stream) {
              q_status_message(1, 3, 5,"Error writing mail folder. Can't delete message");
              break;
          } */

          e = mail_fetchenvelope(ps_global->mail_stream,
                                 ps_global->sort[current_sorted_msgno]);
          mc = mail_elt(ps_global->mail_stream,
                        ps_global->sort[current_sorted_msgno]);
          if(e == NULL || mc == NULL || ps_global->dead_stream) {
              q_status_message(1, 1,3,
                               "Can't delete message. Error accessing folder");
              break;
          }
          dprint(3,(debugfile, "Deleted: %s\n",
                    e != NULL && e->message_id != NULL ? e->message_id : ""));
          if(mc->deleted) {
              q_status_message(0, 1, 3, "Message is already deleted");
              if(current_sorted_msgno < ps_global->max_msgno) {
                  current_sorted_msgno++;
                  ps_global->current_sorted_msgno = current_sorted_msgno;
              } 

          } else {
              sprintf(sequence, "%ld", ps_global->sort[current_sorted_msgno]);
              mail_setflag(ps_global->mail_stream, sequence, "\\DELETED");
              update_del(1, 1);
              ps_global->status_changed = 1;
              clear_index_cache_ent(current_sorted_msgno);
              if(current_sorted_msgno < ps_global->max_msgno) {
                  current_sorted_msgno++;
                  ps_global->current_sorted_msgno = current_sorted_msgno;
              } else {
                  q_status_message(0, 1, 2, "Message deleted. No more messages");
              }
              check_point(1, BadTime);
          }
          break;
          

          /*---------- Open new folder ----------*/
        case OPF11:
        case 'g':
          if(ps_global->nr_mode)
            goto bogus;
          /* broach-folder only returns a value if one was typed in. If
             the user called up the folder lister, it actually did the 
             open and has sent next_screen to mail_index_screen to pop
             out as appropriate. The setting and checking of the next_screen
             is distributed over a lot of places!
           */
          new_folder = broach_folder(question_line, 1);
          if(new_folder != NULL) {
              dprint(9, (debugfile, "do_broach_folder (%s)\n",
                         new_folder)) ;
              if(do_broach_folder(new_folder) > 0)
                  /* so we go out and come back into the index */
                  ps_global->next_screen = mail_index_screen;
          }
          break;
    	  
    	    
          /*---------- Forward message ----------*/
        case PF9 : 
        case 'f' :
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 0, 2, "\007No mail in folder to forward");
              break;
          }
          e  = mail_fetchenvelope(ps_global->mail_stream,
                                  ps_global->sort[current_sorted_msgno]);
          mc = mail_elt(ps_global->mail_stream,
                        ps_global->sort[current_sorted_msgno]);
          if(mc == NULL || e == NULL) {
              q_status_message(1, 2, 4,
                  "\007Can't forward message. Error accessing mail folder");
              break;
          }
          if(ps_global->max_msgno <= 0) {
              q_status_message(0, 0,2,
                               "\007Folder is empty. No mail to forward");
          } else {
              forward(ps_global, mc);
              ps_global->mangled_screen = 1;
          }
          break;


          /*---------- Take Address ----------*/
        case OPF9:
        case 't':
          if(ps_global->nr_mode)
            goto bogus;
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 0, 2, "\007No mail in folder");
              break;
          }
          e  = mail_fetchenvelope(ps_global->mail_stream,
                                  ps_global->sort[current_sorted_msgno]);
          mc = mail_elt(ps_global->mail_stream,
                        ps_global->sort[current_sorted_msgno]);
          if(mc == NULL || e == NULL) {
              q_status_message(1, 2, 4,
                  "\007Can't take address into address book. Error accessing mail folder");
              break;
          }
          grab_addr_cmd(mc, question_line);
          ps_global->mangled_footer = 1;
          break;


          /*---------- Reply to message ----------*/
        case PF10 : 
        case 'r' :
          if(ps_global->nr_mode)
            goto bogus;
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 0, 2, "\007No mail in folder");
              break;
          }
          e  = mail_fetchenvelope(ps_global->mail_stream,
                                  ps_global->sort[current_sorted_msgno]);
          mc = mail_elt(ps_global->mail_stream,
                        ps_global->sort[current_sorted_msgno]);
          if(mc == NULL || e == NULL) {
              q_status_message(1, 2, 4,
                  "\007Can't reply to message. Error accessing mail folder");
              break;
          }
          if(ps_global->max_msgno <= 0) {
              q_status_message(0, 0,2, "\007No mail to reply to");
          } else {
              reply(ps_global, mc );
              ps_global->mangled_screen = 1;
          }
          break;


          /*---------- Search (where is command) ----------*/
       case OPF12:	    
       case 'w':
       case OPF10:
       case 'j':
          if(ps_global->max_msgno <= 0L) {
              q_status_message(0, 0, 2,
                         command == 'j' || command == OPF10 ?
                          "\007No mail to jump to" : "\007No mail to search ");
                                
              break;
          }
          new_sorted_mess_num = command == 'j' ? jump_to(question_line) :
                     search_headers(question_line, current_sorted_msgno,
                                    ps_global->max_msgno);
          ps_global->mangled_footer = 1;
          if(new_sorted_mess_num > 0) {
              ps_global->current_sorted_msgno = new_sorted_mess_num;
              current_sorted_msgno            = new_sorted_mess_num;
          }
          break;


          /*---------- save message ----------*/
        case PF12 : 
        case 's' :
          if(ps_global->nr_mode)
            goto bogus;
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 0,2, "\007No mail in folder");
              break;
          }
          e  = mail_fetchenvelope(ps_global->mail_stream,
                                  ps_global->sort[current_sorted_msgno]);
          mc = mail_elt(ps_global->mail_stream,
                        ps_global->sort[current_sorted_msgno]);
          if(mc == NULL || e == NULL) {
              q_status_message(1, 2, 4,
                  "\007Can't save message. Error accessing mail folder");
              break;
          }
          mango = 0;
          if(!save_msg(question_line, mc, &mango, current_sorted_msgno)) {
              if(mango)
                ps_global->mangled_screen = 1;
              else
                ps_global->mangled_footer = 1;
              break; /* No save done */
          }
          if(mango) 
            ps_global->mangled_screen = 1;
          else 
            ps_global->mangled_footer = 1;
#ifdef X_NEVER  /* Don't set seen flag on a save */
          if(!mc->seen) {
              sprintf(sequence, "%ld", ps_global->sort[current_sorted_msgno]);
              mail_setflag(ps_global->mail_stream,sequence,"\\SEEN");
              ps_global->status_changed = 1;
              clear_index_cache_ent(current_sorted_msgno);
          } 
#endif            
          if(!mc->deleted && !ps_global->mail_stream->readonly) {
              sprintf(sequence, "%ld", ps_global->sort[current_sorted_msgno]);
              mail_setflag(ps_global->mail_stream, sequence, "\\DELETED");
              update_del(1, 1);
              ps_global->status_changed = 1;
              clear_index_cache_ent(current_sorted_msgno);
          }
          break;


          /*---------- Export message ----------*/
        case OPF3:
        case 'e':
          if(ps_global->nr_mode)
            goto bogus;
          if(ps_global->max_msgno == 0) {
              q_status_message(0, 0,2, "\007No mail in folder");
              break;
          }

          export_message(question_line, current_sorted_msgno);
          ps_global->mangled_footer = 1;
          break;

          /*-------- Sort command -------*/
        case 'z':
          if(!in_index)
            goto bogus;
          select_sort(question_line);
          sort_current_folder();
          ps_global->mangled_body = 1;
          ps_global->mangled_footer = 1;
          clear_index_cache();
          break;

          /*------- Attachments -----------*/
        case 'a':
          if(in_index || ps_global->nr_mode)
            goto bogus;
          a = attachments(question_line, current_sorted_msgno, &contents,&len);
          if(a != NULL) {
              char *labels[3];
              labels[0] = "Save";
              labels[1] = "View";
              labels[2] = NULL;
              if(radio_buttons("Save or View attachment? (s/v) [s] ",
                               question_line, 0, "sv", labels, 's',
                               NULL, 0) == 's')
                save_attachment(question_line, a, contents, len, "foo");
              else
                a_changed = display_attachment(a, contents, len);
              fs_give((void **)&contents);
          }
          ps_global->mangled_footer = 1;
          break;

          /*------- Full Header -----------*/
        case 'h':
          if(ps_global->feature_level != Seasoned)
            goto bogus;
          ps_global->full_header = !ps_global->full_header;
          q_status_message1(0, 0, 2, "Display of full headers is now o%s",
                           ps_global->full_header ? "n" : "ff");
          a_changed = 1;
          break;


          /*------- Pipe message -----------*/
        case '|':
          q_status_message(1, 2, 3, "\007Piping message into UNIX command not implemented yet");
          break;

          /*--------- Default, unknown command ----------*/
        default  :
        bogus:
          q_status_message1(0, 0,1, "\007Unknown Command: \"%s\"",
                            (void *)pretty_command(orig_command));
          break;
           
      }


    return(current_sorted_msgno != old_sorted_msgno || a_changed);
}




/*----------------------------------------------------------------------
   Execute save message command: prompt for folder and call function to save

  Args: screen_line    --  Line on the screen to prompt on
        message        --  The MESSAGECACHE entry of message to save
        screen_mangled --  pointer to flag to set if the screen gets mangled

 Result: The folder lister can be called to make selection; mangled screen set
         Returns 0 if unsuccessful
                 1 if saved

   This does the prompting for the folder name to save to, possibly calling 
 up the folder display for selection of folder by user.                 
 ----*/
save_msg(screen_line, message, screen_mangled, index_sorted_msgno)
     int           screen_line, *screen_mangled ;
     long          index_sorted_msgno;
     MESSAGECACHE *message;
{
    char new_folder[MAXFOLDER+1],prompt[MAXFOLDER+80],**help,tmp[MAXFOLDER+1];
    int rc;
    static char folder[MAXFOLDER+1] = {'\0'};
    ENVELOPE *env;

    dprint(4, (debugfile, "\n - saving message -\n"));

    if(message == NULL) {
        q_status_message(0, 0,2, "\007No Messages to Save");
        return(0);
    }
#ifdef X_DEFAULT_IS_LAST
    if(folder[0] == '\0') 
        strcpy(folder, DEFAULT_SAVE); 
#else
    if(ps_global->elm_style_save) {
        env = mail_fetchenvelope(ps_global->mail_stream, message->msgno);
        strcpy(folder, (env!=NULL && env->from!=NULL) ? env->from->mailbox:"");
        lcase(folder);
    } else {
        strcpy(folder, DEFAULT_SAVE);
    }
#endif

    *new_folder = '\0';
    sprintf(prompt,"Folder to save message in [\"%s\"] : ", pretty_fn(folder));
    help = (char **)NULL;

    while(1) {
        rc = optionally_enter(new_folder, screen_line, 0, MAXFOLDER, 1, 0,
                              prompt,  "To Fldrs", help, 0);

        if(rc == 3) {
            help = (help == NULL) ? h_oe_save : (char **)NULL;
            continue;
        }
        if(rc != 4)
          break;
    }

    if(rc == 2) {
        *screen_mangled = 1;      
        folder_lister(ps_global, SaveMessage, new_folder);
    }

    dprint(9, (debugfile, "rc = %d, \"%s\"  \"%s\"\n", rc, new_folder,folder));
    if(rc == 1 || (!*new_folder && !*folder) || (rc == 2 && !*new_folder)) {
        q_status_message(0, 0,2 ,"\007Save message aborted");
        return(0);
    }
    removing_trailing_white_space(new_folder);
    removing_leading_white_space(new_folder);

    if(!*new_folder) {
        strcpy(new_folder, folder);
    } else {
        if(ps_global->elm_style_save && *new_folder != '/' &&
           *new_folder != '{' && *new_folder != '~') {
            strcpy(tmp, new_folder);
            sprintf(new_folder, "~/%s", tmp);
        }
    }
            

    strcpy(folder, new_folder); /* Save default for next time */

    /* ---- By now foldername contains the name of the folder to save in */

    return(save(folder, message, index_sorted_msgno));
}

	

/*----------------------------------------------------------------------
        Do the work of actually saving message in a folder

    Args: folder  -- The folder to save the message in
          message -- The MESSAGECACHE entry of message to save

  Result: Returns 0 if message couldn't be saved
          returns 1 id it was saved

If destination is imap, then call the imap copy routines; otherwise
format the header and text of message to be saved and pass on to
append_message().
 ----*/
static
save(folder, message, index_sorted_msgno)
     char         *folder;
     MESSAGECACHE *message;
     long          index_sorted_msgno;
{
    char     filename[MAXPATH+1], sequence[10], from[MAX_ADDRESS+1];
    char     *headertext, *headertext2, *bodytext, *bodytext2;
    ENVELOPE *env;
    int       rv, seen_flag;
 
    dprint(2, (debugfile, "=== save(%s %ld %ld) ===\n", folder,
               message->msgno, index_sorted_msgno));

    strcpy(filename, folder);

    if (! expand_foldername(filename)) {
        dprint(1, (debugfile,
		 "Error: Failed on expansion of filename %s (save)\n", 
    	  filename));
        return(0);
    }

    if(filename[0] == '{') { /*----- a remote imap mailbox ------*/
        char *p = strindex(filename, '}');
        if(p == NULL) {
            q_status_message(1, 2, 4, "\007Error in remote hostname");
            return(0);
        }
        rplstr(filename, p - filename + 1, ""); /* kill "{xxxxx}" */

        sprintf(sequence, "%ld", message->msgno);
    
        dprint(4, (debugfile, "mail_copy(.. %s, %s)\n", sequence, filename));

        if(mail_copy(ps_global->mail_stream, sequence, filename)){
            q_status_message3(0, 1,3,
                     "Message %s copied to folder \"%s\"%s",
                              long2string(index_sorted_msgno), filename,
                              ps_global->mail_stream->readonly ? "" :
                              " and marked for deletion");
            return(1);
        } else {
            q_status_message1(1, 2,4,
                          "\007Error saving message in remote folder \"%s\"",
                              filename);
            return(0);
        }

    } else {
        seen_flag = message->seen;

        headertext = mail_fetchheader(ps_global->mail_stream, message->msgno);
        if(headertext == NULL) {
            q_status_message(1, 2,4,
                            "Can't save message. Error accessing mail folder");
            return(0);
        }
        headertext2 = cpystr(headertext);
        crlf2lf(headertext2);

        bodytext = mail_fetchtext(ps_global->mail_stream, message->msgno);
        if(bodytext == NULL) {
            q_status_message(1, 2,4,
                            "Can't save message. Error accessing mail folder");
            fs_give((void **)&headertext2);
            return(0);
        }
        bodytext2 = cpystr(bodytext);
        crlf2lf(bodytext2);
        if(!seen_flag) {
            sprintf(sequence, "%ld", message->msgno);
            mail_clearflag(ps_global->mail_stream, sequence, "\\SEEN");
        }
        env = mail_fetchenvelope(ps_global->mail_stream, message->msgno);
        if(env != NULL && env->from != NULL) {
            sprintf(from, "%s%s%s",env->from->mailbox,
                               env->from->host == NULL ? "" : "@",
                               env->from->host == NULL ? "" : env->from->host);
        } else {
            sprintf(from, "maid_of_heaven");
        }
                
        rv = append_message(folder, headertext2, bodytext2, from, NULL,
                            message->msgno, index_sorted_msgno,
                            rfc822date_to_ctime(message->internal_date)); 

        fs_give((void *)&bodytext2);
        fs_give((void *)&headertext2);
        return(rv);
    }
}


/*----------------------------------------------------------------------
    Append a message to a named Berkeley folder and queue status messages

 Args: folder     --  Name of folder to open and save messge in
       headertext --  String with message header
       bodytext   --  String with message body
       from       --  Berkeley style message separator "From " line
       soa        --  File position of start of append in case append
                        has to be backed out.
       number     --  The message number. If < 0 then append is due
                      do saved sent-mail rather than the user saving
                      mail. This controls the status the message saved
                      message is set to and the little message output
                      for the user reporting what happened.
       date       --  The date to put in the message separator, assumed to be
                      in ctime(3) format.
  ----*/

append_message(folder, headertext, bodytext, from, soa, raw_number,
               index_sorted_msgno, date)
     char *folder, *headertext, *bodytext, *from, *date;
     long *soa;
     long  raw_number, index_sorted_msgno;
{
    register char *p;
    char           filename[MAXPATH+1];
    FILE          *folder_file;
    int            appending, rv;
    long           now, start_of_append;


    dprint(2, (debugfile, "append_message(%s ,%x, %x, %s, %x, %ld %s)\n",
               folder, headertext, bodytext, from, soa, raw_number, date));
    dprint(9, (debugfile, "headertext: \"%s\"\n",headertext));
  
    strcpy(filename, folder);

    if (! expand_foldername(filename)) {
        dprint(1, (debugfile,
              "Error: Failed on expansion of filename %s (save)\n", filename));
        return(0);
    }

    if(!strcmp(filename, "inbox") ||
       can_access(filename, ACCESS_EXISTS) == 0){ /* already there!! */
        appending = 1;
    } else {
        char question[100];
        sprintf(question, "Folder \"%.40s\" doesn't exist. Create it",
                       pretty_fn(folder));
        if(want_to(question, 'y', (char **)NULL, 0) != 'y') {
            q_status_message(0, 1, 3, "\007Save message aborted");
            return(0);
        }
        if(create_folder(NULL, filename) < 0)
          return(0);
        appending = 0;
    }

    folder_file = fopen(filename, "a");

    if(folder_file == NULL) {
        q_status_message2(1, 2, 4, "\007Error opening folder \"%s\", %s",
                         pretty_fn(filename), error_description(errno));
        return(0);
    }

    start_of_append = ftell(folder_file);
    if(soa != NULL)
      *soa = start_of_append;

    now = time(0);
    rv = fprintf(folder_file, "From %s %s%s", from,
                 date != NULL ? date : ctime(&now),
                 date != NULL ? "\n" : "");     /* ctime gives\n */
                                           
    if (rv == EOF) 
       goto done;

    for(p = &headertext[strlen(headertext)-1]; *p=='\n' && *(p-1)=='\n'; p --)
      *p = '\0'; /* kill any blank lines at the end */

    rv = fputs(headertext, folder_file);
    if(rv == EOF)
      goto done;
    if(raw_number > 0L) {
        MESSAGECACHE *mc = mail_elt(ps_global->mail_stream, raw_number);
        rv = fprintf(folder_file,"Status: %sO\nX-Status: %s%s\n\n",
                 mc->seen ? "R" : "",  /* don't ever copy DELETED flag */
	         mc->flagged ? "F" : "",mc->answered ? "A" : "");
                                   /* include extra \n that divides header*/
    } else {
        /* saved out going mail. Always marked as seen */
        rv = fputs("Status: R   \nX-Status:     \n\n",folder_file);
    }
    if(rv == EOF)
       goto done;

    /*---- copy message to file, turning 'From ' into '>From '----*/
    for(p = bodytext; *p; p++) {
        if(*p == '\n' && *(p+1) == 'F' && *(p+2) == 'r' && *(p+3) == 'o' &&
           *(p+4) == 'm' && *(p+5) == ' ') {
            rv = fputs("\n>From ", folder_file);
            p += 5;
        } else {
            rv = putc(*p, folder_file);
        }
        if(rv == EOF)
          goto done;
    }
    if(bodytext[strlen(bodytext) - 1] != '\n')
      fputc('\n', folder_file);
    fputc('\n',folder_file); /* Always one blank line because some Bezerk
                                mail formats are "\n\nFrom xxxx" */
    if(rv == EOF)
      goto done;
    rv = fclose(folder_file);

  done:
    if(rv == EOF) {
        int save_errno = errno;
        /*--- truncate it back to it's original length ---*/
        fclose(folder_file);
#ifndef	DOS
        truncate(filename, start_of_append);
#endif
        q_status_message2(1, 2, 4, "Error writing to folder \"%s\" %s",
                          pretty_fn(folder), error_description(save_errno));
        dprint(1, (debugfile, "Error writing folder \"%s\" %s\n",
                   filename, error_description(save_errno)));
        return(0);

    } else {
        char number_string[10];
        if(index_sorted_msgno < 0)
          number_string[0] = '\0';
        else
          sprintf(number_string, " %ld", index_sorted_msgno);
        q_status_message4(0, 1,3, "Message%s %s to folder \"%s\"%s",
                          number_string,
                          appending ? "appended" : "saved",
                          pretty_fn(folder),
                          raw_number > 0 && !ps_global->mail_stream->readonly ?
                                             " and marked for deletion" : "");
    }

    return(1);
}




/*----------------------------------------------------------------------
    Export a message to a plain file in users home directory

   Args:  q_line -- screen line to prompt on
         message -- MESSAGECACHE enrty of message to export

 Result: 
 ----*/
export_message(q_line, sorted_msgno)
     int  q_line;
     long sorted_msgno;
{
    char           filename[MAXPATH+1], full_filename[MAXPATH+1],**help, *ill,
                  *text, from[MAX_ADDRESS+1];
    int            rc, rv, new_file;
    FILE          *f;
    ENVELOPE      *env;
    MESSAGECACHE  *mc;
    long           now, raw_msgno;

    raw_msgno = ps_global->sort[sorted_msgno];

    env  = mail_fetchenvelope(ps_global->mail_stream, raw_msgno);
    mc   = mail_elt(ps_global->mail_stream, raw_msgno);

    if(mc == NULL || env == NULL) {
        q_status_message(1, 2, 4,
                  "\007Can't export message. Error accessing mail folder");
         return(0);
    }

    if(ps_global->restricted){
	q_status_message(1, 1,3, "Pine demo can't export messages to files");
	return(0);
    }

    help = (char **)NULL;
    filename[0] = '\0';
    while(1) {
        rc = optionally_enter(filename, q_line, 0, MAXPATH, 1, 0,
                         "File (in home directory) to save message text in: ",
                          NULL, help,0);

        /*--- Help ----*/
        if(rc == 3) {
            help = (help == NULL) ? h_oe_export : (char **)NULL;
            continue;
        }


        if(rc == 1 || filename[0] == '\0') {
            q_status_message(0, 0, 2, "\007Export message aborted");
            return(0);
        }

        if(rc == 4)
          continue;


        /*-- check out and expand file name. give possible error messages --*/
        strcpy(full_filename, filename);
        removing_trailing_white_space(full_filename);
        removing_leading_white_space(full_filename);
        if((ill = filter_filename(filename)) != NULL) {
            q_status_message1(1, 1,3, "\007%s in file name", ill);
            display_message('x');
            sleep(3);
            continue;
        }
        if(full_filename[0] == '~') {
            if(fnexpand(full_filename, sizeof(full_filename)) == NULL) {
                char *p = strindex(full_filename, '/');
                if(p != NULL)
                  *p = '\0';
                q_status_message1(1, 1,3,
                    "\007Error expanding file name: \"%s\" unknown user",
    	            full_filename);
                display_message('x');
                sleep(3);
                continue;
            }
        } else if(full_filename[0] != '/') {
            build_path(full_filename, ps_global->home_dir, filename);
        }


        break; /* Must have got an OK file name */

    }


    /* ---- full_filename already contains the absolute path ---*/
    if(!can_access(full_filename, 0)) {
        char wt, prompt[100];
        sprintf(prompt, "File \"%s\" already exists. Append message to it",
                filename);
        wt = want_to(prompt, 'y', (char **)NULL, 0);
        if(wt == 'n') {
            q_status_message(0, 0,2, "\007Export message aborted");
            return(0);
        }
        new_file = 0;
    } else {
        new_file = 1;
    }

    dprint(5, (debugfile, "Opening file \"%s\" for export\n", full_filename));

    f = fopen(full_filename, "a");
    if(f == NULL) {
        q_status_message2(1, 2,4,
                        "\007Error opening file \"%s\" to export message: %s",
                          filename, error_description(errno));
        return(0);
    }


    /*--------- The message separator -------*/
    if(env != NULL && env->from != NULL)
      sprintf(from, "%s%s%s",env->from->mailbox,
                           env->from->host == NULL ? "" : "@",
                           env->from->host == NULL ? "" : env->from->host);
    else
      strcpy(from, "the-concourse-on-high");
    now = time(0);
    rv = fprintf(f, "%sFrom %s %s", new_file ? "" : "\n", from, ctime(&now));

#ifdef OLD_EXPORT
    /*------- The message header ---------*/
    rv = fputs(format_envelope(env),f);
    if(rv == EOF)
      goto blegh;

    rv = putc('\n', f);
    if(rv == EOF)
      goto blegh;

    
    /*---- Output the message text ----*/
    text = cpystr(mail_fetchtext(ps_global->mail_stream, raw_msgno));
    if(text == NULL)
      goto blegh;
    crlf2lf(text);
    rv = fputs(text,f);
    fs_give((void **)&text);
    if(rv == EOF)
      goto blegh;
#else
    text = format_message(mc, 1, 1);
    crlf2lf(text);
    rv = fputs(text, f);
    fs_give((void **)&text);
    if(rv == EOF)
      goto blegh;
#endif

    rv = fclose(f);

    f = NULL;
    if(rv == EOF)
      goto blegh;

    q_status_message2(0, 1, 3, "Message %s exported to file \"%s\"",
                      long2string(sorted_msgno), filename);
    return(0);

  blegh:
    if(f != NULL)
      fclose(f);
    q_status_message2(1, 2,4, "\007Error exporting message to folder\"%s\" : %s",
                     filename, error_description(errno));
    return(0);
}
        
    
		      

  
/*----------------------------------------------------------------------
     Execute command to take address out of message and put in the address book

   Args: message --  The MESSAGECACHE of message to take address from
         quest_line -- The screen line number to prompt on

  Result: -1 is returned on failure, 0 on success
          The entry is added to the incode address book and to the file
 ----*/     

grab_addr_cmd(message, quest_line)
     MESSAGECACHE *message;
     int quest_line;
{
    int rc;
    char nickname[MAX_NICKNAME+1], name[MAX_FULLNAME+1],
    address[MAX_ADDRESS + 1], **help, *prompt;
    ADDRESS *addr;


    dprint(4, (debugfile, "\n - taking address into address book - \n"));
    if(ps_global->max_msgno == 0) {
	q_status_message(0, 1, 3, "\007No messages to grab the address from");
	return(-1);
    }
    addr = message->env->from;

    strcpy(address, addr->mailbox); /* BUG, this could overflow address */
    if(addr->host != NULL && addr->host[0] != '\0') {
        strcat(address, "@");
	strcat(address, addr->host);
    }


    prompt = "Enter nick name :";
    help = NULL;
    *nickname = '\0';
    while(1) {
        rc = optionally_enter(nickname, quest_line, 0, MAX_NICKNAME, 1, 0,
                              prompt, NULL, help, 0);
        if(rc == 3) {
            help = (help == NULL) ? h_oe_takenick : NULL;
            continue;
        }
        if(rc == 4)
          continue;

        if(rc == 1 || (rc == 0 && !*nickname))
           goto take_abort;

        if(strindex(nickname, ' ') != NULL) {
            q_status_message(0, 1,1,"\007Blank spaces not allowed in nick names");
            display_message(NO_OP_COMMAND);
            sleep(3);
            continue;
        }

        if(addr_lookup(nickname) == NULL)
          break;

        q_status_message1(0, 1,1,"\007Already an entry with nick name \"%s\"",
                         nickname);
        display_message(NO_OP_COMMAND);
        sleep(3);
    }


    /*-- reearrange full name ---*/
    if(addr->personal != NULL) {
        if(strindex(addr->personal, ',') != NULL) {
            name[0] = '"';
            strcpy(&name[1], addr->personal);
            strcat(name, "\"");
        } else if(strindex(addr->personal, ' ') == NULL) {
            strcpy(name, addr->personal);
        } else {
            char *p, *q, *r;
            p = addr->personal;
            while((q = strindex(p, ' ')) != NULL) p = q+1;
            for(q = p, r = name; *q; *r++ = *q++);
            *r++ = ',';
            *r++ = ' ';
            for(q = addr->personal; q < p; *r++ = *q++);
            *r = '\0';
        }
    } else {
        name[0] = '\0';
    }
            

    prompt = "Full Name :";
    help = NULL;
    while(1) {
        rc = optionally_enter(name,quest_line, 0, MAX_FULLNAME, 1, 0, prompt,
                              NULL, help, 0);
        if(rc == 3) {
            help = (help == NULL) ? h_oe_takename : NULL;
            continue;
        }
        if(rc != 4)
          break;
    }
    if(rc == 1 || !*name)
      goto take_abort;


    prompt = "Address :";
    help = (char **)NULL;
    while(1) {
        rc = optionally_enter(address, quest_line, 0, MAX_ADDRESS, 1, 0,
                              "Address :", NULL, help, 0);
        if(rc == 3) {
            help = (help == NULL) ? h_oe_takeaddr : NULL;
            continue;
        }
        if(rc != 4)
          break;
    }
    if(rc == 1 || !*address)
      goto take_abort;


    rc = addr_add(nickname, name, address);

    /* addr_add does a status message for us */

    return(0);
    
  take_abort:
    q_status_message(0, 0,2, "\007Address book addition aborted");
    return(-1);
}



/*----------------------------------------------------------------------
      Execute command to jump to a given message number

    Args: qline -- Line to ask question on

  Result: returns -1 or the message number to jump to
          the mangled_footer flag is set
 ----*/
long
jump_to(qline)
     int qline;
{
    char jump_num_string[80], *j, prompt[70], **help;
    int  rc;
    long jump_num;

    dprint(4, (debugfile, "\n - jump_to -\n"));

    jump_num_string[0] = '\0';
    strcpy(prompt, ps_global->nr_mode ? "Article": "Message");
    strcat(prompt, " number to jump to : ");
    help = NULL;
    while (1) {
        rc = optionally_enter(jump_num_string, qline, 0,
                              sizeof(jump_num_string) - 1, 1, 0, prompt,
                              NULL, help, 0);
        if(rc == 3) {
            help = help == NULL ? h_oe_jump : NULL;
            continue;
        }

        if(rc == 0 && *jump_num_string != '\0') {
            for(j = jump_num_string; isdigit(*j) || *j == '-'; j++);
	    if(*j != '\0') {
	        q_status_message(0, 2,2,
                           "\007Invalid number entered. Use only digits 0-9");
            } else {
                jump_num = atol(jump_num_string);
                if(jump_num < 1L) {
	            q_status_message1(1, 2,2,
                                "\007Message number %s must be greater than 0",
                                      long2string(jump_num));
                } else if(jump_num > ps_global->max_msgno) {
                    q_status_message1(1, 2, 2,
	     "\007Message number must be less than %s, the number of message",
		    long2string(ps_global->max_msgno));
                } else {
                    return(jump_num);
                }
            }
            jump_num_string[0] = '\0';
            display_message(NO_OP_COMMAND);
            sleep (3);
            continue;
	}

        if(rc != 4)
          break;
    }
    return(-1L);
}
		


/*----------------------------------------------------------------------
     Prompt for folder name to open, expand the name and return it

   Args: qline      -- Screen line to prompt on
         allow_list -- if 1, allow ^T to bring up folder lister

 Result: returns the folder name or NULL
         pine structure mangled_footer flag is set
         may call the folder lister in which case mangled screen will be set

 This prompts the user for the folder to open, possibly calling up
the folder lister of the user types ^T.
----------------------------------------------------------------------*/
char *
broach_folder(qline, allow_list)
     int qline;
{
    static char new_folder[MAXFOLDER+1];
    char        expanded[MAXPATH+1], **help, prompt[MAXFOLDER+80];
    int         rc, rv;

    help = NULL;
    sprintf(prompt, "Folder to open [%s] : ", ps_global->last_folder);
    ps_global->mangled_footer = 1;
    *new_folder = '\0';
    while(1) {
        
        rc = optionally_enter(new_folder, qline, 0, MAXFOLDER, 1 ,0, prompt,
                               allow_list ? "To Fldrs" : NULL, help, 0);

        if(rc == -1) {
	    q_status_message(1, 1,3, "\007Error reading folder name");
	    return(NULL);
        }
         
        if(rc == 3) {
            help = help == NULL ? h_oe_broach : NULL;
            continue;
        }

        if(rc == 1) {
	    q_status_message(0, 0, 2, "\007Open Folder aborted");
	    return(NULL);
        }

        if(rc != 4)
          break;
    }

    if(rc == 2) {
        /* Call up the folder_lister which will actually do the open   
           and set the next screen to be mail_index_screen if open 
           succeeded. Always return from here because the folder lister
           has either succeeded with a new folder or canceled open
           altogether.
        */
        rv = folder_lister(ps_global, OpenFolder, NULL);
	ps_global->mangled_screen = 1;
        if(rv == 0) {
	    q_status_message(0, 0, 2, "\007Open folder aborted");
        }
        return(NULL); 
    }
    if(*new_folder == '\0'  && *(ps_global->last_folder) == '\0') {
        q_status_message(0, 0, 2, "\007Open folder aborted");
        return(NULL);
    }

    removing_trailing_white_space(new_folder);
    removing_leading_white_space(new_folder);

    if(*new_folder == '\0') 
        strcpy(new_folder, ps_global->last_folder);


    strcpy(ps_global->last_folder, ps_global->cur_folder);
      /* Save the current as default for next time so this
         can act as a toggle between two folders */

    dprint(2, (debugfile, "broach folder, name entered \"%s\"\n",new_folder));
    dprint(2, (debugfile, "broach folder, saved \"%s\"\n",
               ps_global->last_folder));

    /*-- Just check that we can expand this. It gets done for real later --*/
    strcpy(expanded, new_folder);
    if (! expand_foldername(expanded)) {
        dprint(1, (debugfile,
                    "Error: Failed on expansion of filename %s (save)\n", 
    	  expanded));
        return(NULL);
    }
    return(new_folder);
}




/*----------------------------------------------------------------------
    Actually attempt to open given folder 

  Args: new_folder -- The folder name to open

 Result:  1 if the folder was successfully opened
          0 if the folder open failed and went back to old folder
         -1 if open failed and no folder is left open
      
  Attempt to open the folder name given. If the open of the new folder
  fails then the previously open folder will remain open, unless
  something really bad has happened. The designate inbox will always be
  kept open, and when a request to open it is made the already open
  stream will be used. Making a folder the current folder requires
  setting the following elements of struct pine: mail_stream, cur_folder,
  current_msgno, max_msgno. Attempting to reopen the current folder is a 
  no-op.

  The first time the inbox folder is opened, usually as Pine starts up,
  it will be actually opened.
  ----*/
do_broach_folder(new_folder)
     char *new_folder;
{
    MAILSTREAM *m;
    int         open_inbox, rv;
    char        expanded_file[MAXPATH+1], *old_folder,*old_path, *p;
    long        x;

    dprint(1, (debugfile, "About to open folder \"%s\"    inbox: \"%s\"\n",
	       new_folder, ps_global->inbox_name));

    /*----- Little to do to reopen same folder -----*/
    if(!strcmp(new_folder, ps_global->cur_folder) &&
                                          ps_global->mail_stream != NULL) {
         return(1); /* OK To reopen same folder */
    }

    if(strcmp(new_folder, POSTPONED_MAIL) == 0) {
        q_status_message1(1, 2, 4,
     "\007Can't open \"%s\". To continue postponed mail, give compose command",
                          POSTPONED_MAIL);
        return(0);
    }

    if(strcmp(new_folder, INTERRUPTED_MAIL) == 0) {
        q_status_message1(1, 2, 4, 
    "\007To continue interruped mail, give compose command. (Can't open %s.)",
                          INTERRUPTED_MAIL);
        return(0);
    }
    
	
    /*--- Set flag that we're opening the inbox, a special case ---*/
    open_inbox = ! strcmp(new_folder, ps_global->inbox_name);

    /*--- Opening inbox, inbox has been already opened, the easy case ---*/
    if(open_inbox && ps_global->inbox_stream != NULL ) {
        expunge_and_close(ps_global->mail_stream, ps_global->cur_folder);

	ps_global->mail_stream              = ps_global->inbox_stream;
	ps_global->current_sorted_msgno     = ps_global->inbox_sorted_msgno;
	ps_global->max_msgno                = ps_global->inbox_max_msgno;
        ps_global->new_mail_count           = 0L;
        ps_global->expunge_count            = 0L;
        ps_global->mail_box_changed         = 0;
        ps_global->new_current_sorted_msgno = -1L;
        ps_global->noticed_dead_stream = 0;
        ps_global->noticed_dead_inbox  = 0;
        ps_global->dead_stream = 0;
        ps_global->dead_inbox  = 0;
        ps_global->current_sort_order = ps_global->sort_order;
        ps_global->current_reverse_sort = ps_global->reverse_sort;

	dprint(7, (debugfile, "%ld %ld %x\n", ps_global->current_sorted_msgno,
                   ps_global->max_msgno,
		   ps_global->mail_stream));
	strcpy(ps_global->cur_folder, ps_global->inbox_name);
        clear_index_cache();
        sort_current_folder();
        q_status_message2(0, 1,3, "Opened folder \"inbox\" with %s message%s",
                          long2string(ps_global->max_msgno),
                          ps_global->max_msgno != 1 ? "s" : "" );
                          
	return(1);
    }

    strcpy(expanded_file, new_folder);
    if(! expand_foldername(expanded_file)) {
        return(0);
    }

    old_folder = NULL;
    old_path   = NULL;
    /*---- now close the old one we had open if there was one ----*/
    if(ps_global->mail_stream != NULL) {
        old_folder = cpystr(ps_global->cur_folder);
        old_path   = cpystr(ps_global->mail_stream->mailbox);
	if(strcmp(ps_global->cur_folder, ps_global->inbox_name) == 0) {
	    /*-- don't close the inbox stream, save a bit of state --*/
	    ps_global->inbox_sorted_msgno   = ps_global->current_sorted_msgno;
	    ps_global->inbox_max_msgno      = ps_global->max_msgno;
	    dprint(2, (debugfile, "Close - saved inbox state %ld %ld\n",
                  ps_global->inbox_sorted_msgno, ps_global->inbox_max_msgno));
	} else {
            expunge_and_close(ps_global->mail_stream, ps_global->cur_folder);
	}
    }
    
        
#ifdef DEBUG
    m = mail_open(NULL, expanded_file, (long)debug);
#else
    m = mail_open(NULL, expanded_file, 0L);
#endif

    dprint(8, (debugfile, "Opened folder %x \"%s\"\n", m,
               m != NULL ? m->mailbox : "nil"));    


    /* Can get m != NULL if correct passwd for remote, but wrong name */
    if(m == NULL || ((p = strindex(m->mailbox, '<')) != NULL &&
                      strcmp(p, "no mailbox>") == 0)) {
	/*-- non-existent local mailbox, or wrong passwd for remote mailbox--*/
        /* fall back to currently open mailbox */
        rv = 0;
        dprint(8, (debugfile, "Old folder: \"%s\"\n",
               old_folder == NULL ? "" : old_folder));
        if(old_folder != NULL) {
            if(strcmp(old_folder, ps_global->inbox_name) == 0){
                ps_global->mail_stream          = ps_global->inbox_stream;
                ps_global->current_sorted_msgno =ps_global->inbox_sorted_msgno;
                ps_global->max_msgno            = ps_global->inbox_max_msgno;
                dprint(8, (debugfile, "Reactivate inbox %ld %ld %x\n",
                           ps_global->current_sorted_msgno,
                           ps_global->max_msgno,
                           ps_global->mail_stream));
                strcpy(ps_global->cur_folder, ps_global->inbox_name);
            } else {
#ifdef DEBUG          
                ps_global->mail_stream = mail_open(NULL, old_path,(long)debug);
#else
                ps_global->mail_stream = mail_open(NULL, old_path, 0L);
#endif
                /* mm_log will take care of error message here */
                if(ps_global->mail_stream == NULL) {
                    rv = -1;
                } else {
                    ps_global->max_msgno = ps_global->mail_stream->nmsgs;
                    ps_global->expunge_count     = 0;
                    ps_global->new_mail_count    = 0;
                    ps_global->noticed_dead_stream = 0;
                    ps_global->dead_stream = 0;

                    reset_check_point();
                    ps_global->current_sorted_msgno =
                      min(ps_global->current_sorted_msgno,
                          ps_global->max_msgno);
                    q_status_message1(0, 1, 3, "Folder \"%s\" reopened",
                                      old_folder);
                }
            }
            fs_give((void **)&old_folder);
            fs_give((void **)&old_path);
        } else {
            rv = -1;
        }
        if(rv == -1) {
            q_status_message(0, 2,4, "\007No mail folder opened");
            ps_global->max_msgno            = 0L;
            ps_global->current_sorted_msgno = -1L;
            strcpy(ps_global->cur_folder, "");
        }
        return(rv);
    } else {
        if(old_folder != NULL) {
            fs_give((void **)&old_folder);
            fs_give((void **)&old_path);
        }
    }



    /*----- success in opening the new folder ----*/
    dprint(2, (debugfile, "Opened folder \"%s\" with %ld messages\n",
	       m->mailbox, m->nmsgs));


    /*--- A Little house keeping ---*/
    ps_global->mail_stream          = m;
    ps_global->max_msgno            = m->nmsgs;
    ps_global->current_sorted_msgno = -1L;
    ps_global->expunge_count        = 0L;
    ps_global->new_mail_count       = 0L;
    ps_global->current_sort_order   = ps_global->sort_order;
    ps_global->current_reverse_sort = ps_global->reverse_sort;
    ps_global->noticed_dead_stream  = 0;
    ps_global->noticed_dead_inbox   = 0;
    ps_global->dead_stream          = 0;
    ps_global->dead_inbox           = 0;

    if(ps_global->sort_allocated < ps_global->max_msgno * 2) {
        ps_global->sort_allocated = ps_global->max_msgno * 2 + 1;
        if(ps_global->sort != NULL)
          fs_resize((void **)&ps_global->sort,
                    ps_global->sort_allocated * sizeof(long));
        else
          ps_global->sort = (long *)fs_get(ps_global->sort_allocated * 
                                                            sizeof(long));
    }
    strcpy(ps_global->cur_folder, new_folder);
    reset_check_point();


    q_status_message4(0, 2,4, "Folder \"%s\" opened with %s message%s%s",
                      pretty_fn(new_folder),
                      comatose(ps_global->max_msgno),
                      plural(ps_global->max_msgno),
                      m->readonly ? "\007 READONLY" : "");

#ifdef X_MAXMESSAGES /* Used when there was a limit to the number of messages*/
    if(ps_global->max_msgno > (80 * MAXMESSAGES)/ 100) {
        /* warn at 80% of capacity. warn early -- he might go on vacation */
        char tmp[30];
        strcpy(tmp, comatose(MAXMESSAGES));
        q_status_message2(1, 3,4,
           "\007Warning! Folder has %s messages. Maximum allowed is %s",
                         comatose(ps_global->max_msgno), tmp);
    }
#endif
                      
    clear_index_cache();

    ps_global->mail_box_changed = 0;

    sort_current_folder();



    if(ps_global->max_msgno > 0) {
        MsgNo first_unseen;
        if(strcmp(ps_global->cur_folder, ps_global->inbox_name) == 0 &&
           (first_unseen = first_sorted_unread(m)) >= 0)
          ps_global->current_sorted_msgno = first_unseen;
        else
          ps_global->current_sorted_msgno = ps_global->current_reverse_sort ?
                                                 (MsgNo) 1:
                                                 (MsgNo)ps_global->max_msgno;

    } else {
        ps_global->current_sorted_msgno = -1L;
    }

    /*--- If we just opened the inbox remember it's special stream ---*/
    if(open_inbox && ps_global->inbox_stream == NULL) {
	ps_global->inbox_stream = ps_global->mail_stream;
    }
	
    return(1);
}

/*----------------------------------------------------------------------
      Expunge (if confirmed) and close a mail stream

    Args: stream   -- The MAILSTREAM * to close
          folder   -- The name the folder is know by 

   Result:  Mail box is expunged and closed. A message is displayed to
             say what happened
 ----*/
void
expunge_and_close(stream, folder)
     MAILSTREAM *stream;
     char *folder;
{
    long  delete_count, max_folder;
    char  prompt_b[MAX_SCREEN_COLS+1], short_folder_name[MAXFOLDER*2+1],
          temp[MAXFOLDER*2+1];

    if(stream != NULL) {
        dprint(2, (debugfile, "expunge and close mail stream \"%s\"\n",
                   stream->mailbox));

        if(!stream->readonly) {
            delete_count = count_deleted(stream);
            if(delete_count != 0L)  {
                max_folder =    ps_global->ttyo->screen_cols - 50;
                strcpy(temp, pretty_fn(folder));
                if(strlen(temp) > max_folder){
                   strcpy(short_folder_name, "...");
                   strcat(short_folder_name,temp + strlen(temp) -max_folder);
                } else {
                   strcpy(short_folder_name, temp);
                }
                            
                sprintf(prompt_b,
                       "Expunge the %ld deleted message%s from \"%s\"",
                       delete_count,
                         delete_count == 1 ? "" : "s",
                         short_folder_name);
                if(want_to(prompt_b, 'y', (char **)NULL,0)=='y' &&
                   delete_count>0){
                    q_status_message4(0, 2, 3,
                       "Closing \"%s\". Keeping %s message%s and deleting %s",
                                      pretty_fn(folder),
                                      comatose((stream->nmsgs - delete_count)),
                                      plural(stream->nmsgs - delete_count),
                                      long2string(delete_count));
                    display_message('q'); /* So they see the message */
                    mail_expunge(stream);
                } else {
                    q_status_message3(0, 2,3,
                             "Closing folder \"%s\". Keeping all %s message%s",
                                   pretty_fn(folder), comatose(stream->nmsgs),
                                      plural(stream->nmsgs));
                    display_message('q'); /* So they see the message */
                }
            } else {
                q_status_message3(0, 2,3,
                            "Closing folder \"%s\". Keeping all %s message%s",
                             pretty_fn(folder), comatose(stream->nmsgs),
                                  plural(stream->nmsgs));
                display_message('q'); /* So they see the message */	
            }
        } else {
            q_status_message1(0, 2,3,
                       "Closing read-only folder \"%s\". No changes to save",
                              pretty_fn(folder));
            display_message('q');
        }
    }
    mail_close(stream);
}




/*----------------------------------------------------------------------
     Find the closest message in the list that is not marked for deletion

   Args:  stream -- The mail stream/folder to find the messages in
          cur    -- The current message number
          maxmn  -- The largest message number in folder/stream

  Result: Returns a pointer to the MESSAGECACHE of undeleted message
          or NULL
 ----*/

static MESSAGECACHE *
closest_not_deleted(stream, cur_raw_msgno, maxmn)
     MAILSTREAM *stream;
     long cur_raw_msgno, maxmn;
{
    long          i;
    MESSAGECACHE *mc;

    if(maxmn == 0)
      return((MESSAGECACHE *)NULL);

    (void)mail_fetchenvelope(stream, cur_raw_msgno);
    mc = mail_elt(stream, cur_raw_msgno);
    if(mc == NULL || !mc->deleted)
      return(mc);

    for(i = 0; cur_raw_msgno - i > 0 || cur_raw_msgno + i < maxmn; i++) {
	if(i + cur_raw_msgno < maxmn) {
            (void)mail_fetchenvelope(stream, cur_raw_msgno + i);
            mc = mail_elt(stream, cur_raw_msgno + i);
            if(mc == NULL)
              return(NULL);
	    if(!mc->deleted)
	      return(mc);
	}
        if(cur_raw_msgno - i > 0) {
            (void)mail_fetchenvelope(stream, cur_raw_msgno - i);
            mc = mail_elt(stream, cur_raw_msgno - i);
            if(mc == NULL)
              return(NULL);
	    if(!mc->deleted)
	      return(mc);
	}
    }
    /*--- mailbox will be empty ---*/
    return(NULL);
}
	    
	    

/*----------------------------------------------------------------------
      Search the message headers as display in index
 
  Args: command_line -- The screen line to prompt on
        msg          -- The current message number to start searching at
        max_msg      -- The largest message number in the current folder

  The headers are searched exactly as they are displayed on the screen. The
search will wrap around to the beginning if not string is not found right 
away.
  ----*/
long 
search_headers(command_line, sorted_msg, max_msg)
     int  command_line;
     long sorted_msg, max_msg;
{
    int         rc;
    long        i;
    static char search_string[MAX_SEARCH+1] = { '\0' };
    char        prompt[MAX_SEARCH+50], new_string[MAX_SEARCH+1], **help;

    dprint(4, (debugfile, "\n - search headers - \n"));

    sprintf(prompt, "Word to search for [%s] : ", search_string);
    help = (char **)NULL;
    new_string[0] = '\0';

    while(1) {
        rc = optionally_enter(new_string, command_line, 0, MAX_SEARCH, 1,
                             0, prompt, NULL, help, 0);

        if(rc == 3) {
            help = (char **)(help == NULL ? NULL : NULL);
            continue;
        }

        if(rc != 4) /* redraw */
          break; /* redraw */
    }

    if(rc == 1 || (new_string[0] == '\0' && search_string[0] == '\0')) {
        q_status_message(0, 0,2, "\007Search aborted");
        return(0);
    }

    if(new_string[0] == '\0')
        strcpy(new_string, search_string);

    strcpy(search_string, new_string);

    for(i = sorted_msg + 1; i <= max_msg; i++) {
        if(srchstr(build_header_line(i, 0), search_string) != NULL)
          goto found;
    }

    for(i = 1; i < sorted_msg; i ++) {
        if(srchstr(build_header_line(i, 0), search_string) != NULL)
          goto found;
    }

    q_status_message(0, 1,3, "\007Word not found");
    return(-1);

  found:
     q_status_message1(0, 1,3, "Word found%s", i > sorted_msg ? "" :
                        ". Search wrapped to beginning"); 
    return(i);
}
    

/*----------------------------------------------------------------------
    Print message number "m"

  Args:  m - Message number to print.

 Filters the original header and sends stuff to printer
  ---*/
print_message(sorted_m)
     long sorted_m;
{
    char          *text;
    char           prompt[30];
    MESSAGECACHE  *mc;

    sprintf(prompt, "message %ld ", sorted_m);
    if(open_printer(prompt) == 0) {
        mc = mail_elt(ps_global->mail_stream, ps_global->sort[sorted_m]);
        text = format_message(mc, 1, 1);
        crlf2lf(text);
        print_text(text);
        fs_give((void **)&text);
        close_printer();
    }
}



/*----------------------------------------------------------------------
   Prompt the user for the type of sort he desires

Args: q1 -- Line to prompt on

  ----*/
static void
select_sort(ql)
     int ql;
{
    char      prompt[200], tmp[40], first_chars[10], *fc, *sort_names[10];
    int       s, i;
    char    **help;
    SortOrder prev_sort;


    /*----- String together the prompt ------*/
    strcpy(prompt, "Sort by ");
    fc = first_chars;

    for(i = 0; ps_global->sort_types[i] != EndofList; i++) {
        sort_names[i] = cpystr(sort_name(ps_global->sort_types[i]));
        sort_names[i][0] = toupper(sort_names[i][0]);
        if(i != 0)
          strcat(prompt, ",");
        if(ps_global->current_sort_order == ps_global->sort_types[i]) {
            strcat(prompt, "[");
            *fc++ = '[';
        }
        strcpy(tmp,sort_name(ps_global->sort_types[i]));
        if(strcmp(tmp, "size") == 0) {
            tmp[2] = toupper(tmp[2]);
            *fc++ = tmp[2];
        } else {
            tmp[0] = toupper(tmp[0]);
            *fc++  = tmp[0];
        }
        strcat(prompt, tmp);
        if(ps_global->current_sort_order == ps_global->sort_types[i]) {
            strcat(prompt, "]");
            *fc++ = ']';
        }
    }
    sort_names[i++] = cpystr("Reverse");
    sort_names[i]   = NULL;
    strcat(prompt,",Reverse");
    *fc = '\0';

    sprintf(prompt+strlen(prompt)," (type %s or R): ", first_chars);
    help = h_select_sort;
    s = radio_buttons(prompt, ql, 0, "safdzr", sort_names, 'a', help, 0);

    prev_sort = ps_global->current_sort_order;

    switch(s) {
      case 's':
        ps_global->current_sort_order = SortSubject;
        break;
      case 'z':
        ps_global->current_sort_order = SortSize;
        break;
      case 'f':
        ps_global->current_sort_order = SortFrom;
        break;
      case 'd':
        ps_global->current_sort_order = SortDate;
        break;
      case 'a':
        ps_global->current_sort_order = SortArrival;
        break;
      case 'r':
        ps_global->current_reverse_sort = !ps_global->current_reverse_sort;
        break;
    }

    blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
}



static struct attachment *
attachments(qline, sorted_msgno, decoded_contents, decoded_len)
     int    qline;
     long   sorted_msgno, *decoded_len;
     char **decoded_contents;
{
    char               prompt[100], section[100], **help, *contents;
    long               len;
    int                r;
    MESSAGECACHE      *mc;
    struct attachment *a;
    extern char *rfc822_qprint(), *rfc822_base64();

    
    mc = mail_elt(ps_global->mail_stream, ps_global->sort[sorted_msgno]);
    
    for(a = ps_global->atmts; (a+1)->description != NULL; a++);

    sprintf(prompt, "Enter attachment number to view or save (%s - %s) :",
            ps_global->atmts->number, a->number);
            

    section[0] = '\0';
    help       = NULL;
    while(1) {
        r = optionally_enter(section, qline, 0, sizeof(section), 1, 0,
                             prompt, NULL, help, 0);
        if(r == 3) {
            help = (char **)(help == NULL ? NULL : NULL);
            continue;
        }

        if(r == 1 || section[0] == '\0') {
            q_status_message(0, 0, 2, "\007Attachment aborted");
            return(NULL);
        }
        removing_trailing_white_space(section);
        removing_leading_white_space(section);
        for(a = ps_global->atmts; a->description != NULL ; a++)
          if(strcmp(section, a->number) == 0)
            break;
        if(a->description == NULL) {
            q_status_message1(1, 2,4,
             "\007No such attachment number \"%s\". Must be in displayed list",
                              section);
            display_message('x');
            sleep(3);
            continue;
        }

        contents = mail_fetchbody(ps_global->mail_stream,
                                  ps_global->sort[sorted_msgno], section,&len);
        if(contents == NULL) {
            q_status_message1(1, 2, 4, "Unable to access attachment %s",
                              a->number);
            display_message('x');
            sleep(2);
            continue;
        }

        if(r != 4) /* redraw */
          break; /* redraw */
    }

    contents[len] = '\0'; /* Still dealing with text till decoded */

    switch(a->body->encoding) {
      case ENC7BIT:
      case ENC8BIT:
      case ENCBINARY:
        crlf2lf(contents);
        *decoded_contents = cpystr(contents);
        *decoded_len      = strlen(*decoded_contents);
        break;
      case ENCBASE64:
        *decoded_contents = (char *)rfc822_base64(contents, len, decoded_len);
        break;
      case ENCQUOTEDPRINTABLE:
        crlf2lf(contents);
        len = strlen(contents);
        *decoded_contents = (char *)rfc822_qprint_nl(contents,len,decoded_len);
        break;
      case ENCOTHER:
        break;
    }
    dprint(9, (debugfile, "Attachment lengths: %ld (decoded)  %ld (encoded)\n",
               *decoded_len, len));
    if(*decoded_contents == NULL) {
        q_status_message2(1, 2, 4, "Error removing \"%s\" encoding from message part %s",
                         a->body->encoding  == ENCBASE64          ? "Base 64" :
                         a->body->encoding  == ENCQUOTEDPRINTABLE ? "Quoted printable" :
                                                                    "none",
                          section);
        return(NULL);
    }
    return(a);
}


/*----------------------------------------------------------------------
  ----*/
static void
save_attachment(qline,a, contents, len, suggested_name)
     struct attachment *a;
     char *contents, *suggested_name;
     long  len;
     int   qline;
{
    char  filename[MAXPATH+1], full_filename[MAXPATH+1], *ill, **help, *prompt;
    char *l_string, prompt_buf[200];
    int   r, is_text;
    FILE *stream;
    PARAMETER *param;

    dprint(9, (debugfile, "save_attachments(length: %ld, name: %s)\n",
               len, suggested_name == NULL ? "NULL" : suggested_name));

    is_text = a->body->type == TYPETEXT;
    /*-------  Figure out suggested file name ----*/
    for(param = a->body->parameter; param != NULL; param = param->next) {
        if(strucmp(param->attribute, "name") == 0)
          break;
    }
    if(param != NULL && param->value != NULL) 
      strcpy(filename, param->value);
    else
      filename[0] = '\0';

    /*---------- Prompt the user for the file name -------------*/
    help = (char **)NULL;
    while(1) {
        prompt = "File (in home directory) to save attachment in: ";
        r = optionally_enter(filename, qline, 0, MAXPATH, 1, 0, prompt,
                             NULL, help, 0);

        /*--- Help ----*/
        if(r == 3) {
            help = (help == NULL) ? h_oe_export : (char **)NULL;
            continue;
        }

        if(r == 1 || filename[0] == '\0') {
            q_status_message(0, 0, 2, "\007Save attachment aborted");
            return;
        }

        if(r == 4)
          continue;

        /* check out and expand file name. give possible error messages */
        strcpy(full_filename, filename);
        removing_trailing_white_space(full_filename);
        removing_leading_white_space(full_filename);
        if((ill = filter_filename(filename)) != NULL) {
            q_status_message1(0, 1,3, "\007%s in file name", ill);
            display_message('x');
            sleep(3);
            continue;
        }
#ifndef	DOS
        if(full_filename[0] == '~') {
            if(fnexpand(full_filename, sizeof(full_filename)) == NULL) {
                char *p = strindex(full_filename, '/');
                if(p != NULL)
                  *p = '\0';
                q_status_message1(1, 1,3,
                    "\007Error expanding file name: \"%s\" unknown user",
                    full_filename);
                display_message('x');
                sleep(3);
                continue;
            }
        } else if(full_filename[0] != '/') {
            build_path(full_filename, ps_global->home_dir, filename);
        }
#endif	/* !DOS */
        break; /* Must have got an OK file name */
    }

    if(ps_global->restricted) {
        q_status_message(1, 2, 4, "\007Pine demo can't save attachments");
        return;
    }
     

    /*----------- Write the contents to the file -------------*/
    if(can_access(full_filename, 0) == 0) {
        sprintf(prompt_buf, "File \"%s\" already exists. Overwrite it",
                full_filename);
        if(want_to(prompt_buf, 'n', (char **)NULL, 0) == 'n') {
            q_status_message(0, 1, 3, "\007Save of attachment aborted");
            return;
        }
    }
    if(is_text) 
      crlf2lf(contents);
#ifdef	DOS
    stream = fopen(full_filename, "wb");
#else
    stream = fopen(full_filename, "w");
#endif
    if(stream != NULL) {
        r = fwrite(contents, 1, len, stream);
        if(r <= 0) {
            r = -1;
            fclose(stream);
        } else {
            r = fclose(stream);
        }
    }
    if(stream == NULL || r < 0) 
      q_status_message2(1, 3,5,"\007Error writing attachment to \"%s\": %s",
                        full_filename, error_description(errno));
    else {
        l_string = cpystr(byte_string(len));
        q_status_message7(0, 2,4, "Part %s, %s%s written to \"%s\"%s%s%s",
                         a->number, 
                         is_text ?   comatose(a->body->size.lines) :
                                     l_string,
                         is_text ?   " lines" : "",
                         full_filename,
                         is_text || len == a->body->size.bytes ?
                                        "" : "(decoded from ",
                         is_text || len == a->body->size.bytes ?
                                        "" : byte_string(a->body->size.bytes),
                         is_text || len == a->body->size.bytes ?
                                        "" : ")");
        fs_give((void **)&l_string);
    }
    return;
}


/*----------------------------------------------------------------------

  ----*/        
static int
display_attachment(a, contents, len)
     struct attachment *a;
     char              *contents;
     long               len;
{
    FILE  *stream;
    int    r;
    char  filename[MAXPATH+1];

    /*------- Display the attachment -------*/
    if(!a->can_display) {
        /*----- Can't display this type ------*/
        q_status_message3(1, 3,5,
                 "\007Don't know how to display attachment format %s%s%s",
                          body_type_names(a->body->type),
                          a->body->subtype != NULL ? "/" : "",
                          a->body->subtype != NULL ? a->body->subtype :"");
        return(0);
    }
    
    if(a->body->type == TYPETEXT) {
        /*----- All text is displayed by scrolltool -----*/
        /*----
          Change the current attachment. Scrolltool() detects that the
          current attachment has changed and pops back up in to 
          mailview() where a whole new scroll text is formatted and
          scrolltool is reinvoked.
          ----*/
        a->shown = 1;
        return(1);
    }
        
#ifdef	DOS
/* DOS can't do much with the attachment */
    return(0);
#else

    /*------ Write the image to a temporary file ------*/
    strcpy(filename, temp_file_name("/usr/tmp", "pine-image-view"));
    if(a->body->subtype != NULL)
      strcat(filename, a->body->subtype);
    stream = fopen(filename, "w");
    if(stream != NULL) {
        r = fwrite(contents, 1, len, stream);
        if(r <= 0) {
            fclose(stream);
            r = -1;
        } else {
            r = fclose(stream);
        }
    }
    if(stream == NULL || r < 0) {
        q_status_message2(1, 3,5,
                          "\007Error \"%s\" saving image to temporary file %s",
                          error_description(errno), filename);
        return(0);
    }

    /*----- Run the viewer process ----*/
    run_viewer(filename, type_desc(a->body->type, a->body->subtype,
                                   a->body->parameter, 1));
    unlink(filename);
    return(0);
#endif
}


#ifndef	DOS

/*----------------------------------------------------------------------
   Run xloadimage to display gif,pbm and other such files

Args: image_file -- The name of the file to pass to xloadimage

If xloadimage produces any output on the command line or the shell
produces output because it can't find or execute xloadimage the first
5 lines will be displayed on the status line one at a time.
 ----*/
void
run_viewer(image_file, description)
     char *image_file, *description;
{
    char      command[100], result_file[100], buf[512];
    int       messages_queued, pid, r, status;
    FILE     *f;
    SigType (*hsig)(), (*isig)(), (*qsig)();
    
    sprintf(command, "%s %s &\n", ps_global->VAR_IMAGE_VIEWER, image_file);

    strcpy(result_file, temp_file_name(NULL, "pine_cmd_result"));

    if((pid = fork()) == 0) {
        int output = creat(result_file, 0777);
        dup2(output, 1); 
        dup2(output, 2);
        execl("/bin/sh", "sh", "-c", command, 0);
        exit(-1);
    }
    isig = signal(SIGINT, SIG_IGN);
    qsig = signal(SIGQUIT, SIG_IGN);
    hsig = signal(SIGHUP, SIG_IGN);
#ifdef HAVE_WAIT_UNION
    while((r=  wait((union wait *)&status)) && r != -1 && r != pid);
#else
    while((r=  wait(&status)) && r != -1 && r != pid);
#endif
    signal(SIGINT,  isig);
    signal(SIGHUP,  hsig);
    signal(SIGQUIT, qsig);

    if(file_size(result_file) == 0L) 
      sleep(3); /* Give the process time to do something */

    messages_queued = 0;
    f = fopen(result_file, "r");
    if(f != NULL){
        unlink(result_file);
        while(fgets(buf, sizeof(buf), f) != NULL && messages_queued < 5) {
            buf[strlen(buf) - 1] = '\0';
            if(strlen(buf) == 0)
              continue;
            q_status_message1(0, 2, 4, "Display result: %s", buf);
            messages_queued++;
        }
        fclose(f);
    }
    if(!messages_queued) 
      q_status_message1(0, 1,4, "Display of %s complete", description);
    display_message('x');
}
#endif	/* !DOS */
