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

            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 Builiding, 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   *
    ***********************************************************************
 

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


#include "headers.h"


#define VERSION "3.05"


#ifdef	DOS
extern DRIVER imapdriver;
#else
extern DRIVER imapdriver, bezerkdriver, tenexdriver, dummydriver, newsdriver;
#endif

char         version_buff[50], version_buf2[60];
struct pine *ps_global;               /* sort of THE global variable */
int          timeout = NEW_MAIL_TIME; /* referenced in weemacs */


/*----------------------------------------------------------------------
  General use big buffer. It is used in the following places:
    format_envelope: to return nice envelope string
    compose_mail:    while parsing header of postponed message
    append_message2: while writing header into folder
    q_status_messageX: while doing printf formatting
    addr_book: Used to return expanded address in. (Can only use here 
               because mm_log doesn't q_status on PARSE errors !)
    pine.c: When address specified on command line
    init.c: When expanding variable values

 ----*/
char         tmp_20k_buf[20480];      



#ifdef ANSI
static void show_main_screen(int);
static void do_menu();
static void paint_keyhelp();
#else
static void show_main_screen();
static void do_menu();
static void paint_keyhelp();
#endif


/*----------------------------------------------------------------------
     main routine -- entry point

  Args: argv, argc -- The command line arguments


 Initialize pine, parse arguments and so on

 If there is a user address on the command line go into send mode and exit,
 otherwise loop executing the various screens in Pine.
  ----*/

main(argc, argv)
     int   argc;
     char *argv[];
{
    char         *folder_to_open;
    int           rv;
    struct pine  *pine_state;
    char          int_mail[MAXPATH+1];
#ifdef DYN
    char stdiobuf[64];
#endif

    /*----------------------------------------------------------------------
          Set up buffering and some data structures
      ----------------------------------------------------------------------*/

    pine_state                 = (struct pine *)fs_get(sizeof (struct pine));
#ifdef	DOS
/* got to zero out this stuff ourselves because DOS won't!! */
    fs_zero((void *)pine_state, sizeof(struct pine));
#endif
    ps_global                  = pine_state;
    ps_global->mail_stream     = NULL; /* In case of SIGHUP before open */
    ps_global->inbox_stream    = NULL; /* In case of SIGHUP before open */
    ps_global->ttyo            = NULL;
    ps_global->cur_folder[0]   = '\0';
    ps_global->sort            = (long *)fs_get(2 * sizeof(long));
    ps_global->sort_allocated  = 2;
    ps_global->sort_order      = SortArrival;
    ps_global->reverse_sort    = 0;
    ps_global->new_current_sorted_msgno = -1L;
    ps_global->sort_types[0]   = SortSubject;
    ps_global->sort_types[1]   = SortArrival;
    ps_global->sort_types[2]   = SortFrom;
    ps_global->sort_types[3]   = SortDate;
    ps_global->sort_types[4]   = SortSize;
    ps_global->sort_types[5]   = EndofList;
    ps_global->atmts           = (struct attachment *)
                                       fs_get(sizeof(struct attachment));
    ps_global->atmts_allocated = 1;
    ps_global->atmts->description = NULL;
    pine_state->full_header    = 0;
    ps_global->low_speed       = 1;
    ps_global->noticed_dead_stream = 0;
    ps_global->noticed_dead_inbox  = 0;
    ps_global->dead_stream = 0;
    ps_global->dead_inbox  = 0;

    ps_global->max_msgno     = 0;
                           

#ifndef	DOS
    srandom(getpid());  /* for new mail notification which uses random */
#endif

#ifdef DYN
    /*-------------------------------------------------------------------
      There's a bug in DYNIX that causes the terminal driver to lose
      characters when large I/O writes are done on slow lines. Like
      a 1Kb write(2) on a 1200 baud line. Usually CR is output which
      causes a flush before the buffer is too full, some the pine composer
      doesn't output newlines a lot. Either stdio should be fixed to
      continue with more writes when the write request is partial, or
      fix the tty driver to always complete the write.
     */
    setbuffer(stdout, stdiobuf, 64);
#endif	



    /*----------------------------------------------------------------------
           Parse arguemnts and initialize debugging
      ----------------------------------------------------------------------*/
#ifdef	DOS
/* until parsing code gets fixed, start with imap inbox. */
    folder_to_open = NULL;
#else
    folder_to_open = argc ? pine_args(pine_state, argv) : NULL;
#endif

#ifdef DEBUG
    if(debug == 0)
      debug =  DEFAULT_DEBUG;
              /* never more than 7 for production */

    /* Since this is specific debugging we don't mind if the
       ifdef is the type of system. See conf/templets.h
     */
#ifdef HAVE_SMALLOC 
    if(debug > 8)
      malloc_debug(2);
#endif 
#ifdef NXT
    if(debug > 8)
      malloc_debug(32); 
#endif 

#endif  /* DEBUG */


    strcpy(version_buff, VERSION);
    sprintf(version_buf2, "Pine version: %s (olive%s)\n", VERSION, "branch");


    /* Must do this here, so we can get the .pinerc file and debug file */
    if(getenv("HOME") != NULL) { 
        pine_state->home_dir = cpystr(getenv("HOME"));
    } else if(get_system_homedir() != NULL) {
        pine_state->home_dir = cpystr(get_system_homedir());
    } else {
        pine_state->home_dir = cpystr("");
    }


#ifdef DEBUG
    init_debug();
#endif


    /*------- Set up c-client drivers -------------- */ 
    mail_link((DRIVER *)&imapdriver);
#ifndef	DOS
    mail_link((DRIVER *)&newsdriver);
    mail_link((DRIVER *)&tenexdriver);   
    mail_link((DRIVER *)&bezerkdriver);
    mail_link((DRIVER *)&dummydriver);
#endif

    init_vars(pine_state);

    if(init_username(pine_state) < 0)
      exit(-1);

    if(init_hostname(pine_state) < 0)
      exit(-1);

    write_pinerc(pine_state); /* Temporary, to get new entries in .pinerc
                                  on first run until pinerc is more robust */

#ifdef	DOS
/* again, only this way until arg parsing is fixed */
    if(1)
#else
    if(*argv == NULL)
#endif
      /* do mail dir if we're not in send only mode */
      if(init_mail_dir(pine_state->folders_dir) < 0)
        exit(-1);


    init_signals();

    /*--- input side ---*/
    if(init_tty_driver(pine_state)){
        fprintf(stderr, "Can't access terminal or input is not a terminal. Redirection of\n");
        fprintf(stderr, "standard input is not allowed. For example \"pine < file\" doesn't work.\n\007");
        exit(-1);
    }
        

    /*--- output side ---*/
    rv = config_screen(&(pine_state->ttyo));
    if(rv) {
        switch(rv) {
          case -1: printf("Terminal type (envronment variable TERM) not set.\n");
            break;
          case -2: printf("Terminal type \"%s\", is unknown.\n", getenv("TERM"));
            break;
          case -3:
            printf("Can't open termcap file; check TERMCAP variable and/or system manager.\n");
            break;
          case -4:
            printf("Your terminal, of type \"%s\", is lacking functions needed to run pine.\n", getenv("TERM"));
            break;
        }
        printf("\r");
        end_tty_driver(pine_state);
        exit(-1);
    }
    init_screen();
            

    init_keyboard(pine_state->use_fkeys);

#ifdef	DOS
/* boy, it'd be nice to have arg parsing fixed! */
    if(1) {
#else
    if(*argv == NULL) {
#endif
        /*======================== Normal pine mail reading mode ==========*/
            
        pine_state->mail_stream = NULL;
        pine_state->inbox_stream = NULL;
        strcpy(pine_state->inbox_name, INBOX_NAME);
    
        if(!pine_state->start_in_index) {
            show_main_screen(1);
        } else {
            do_index_border(1,1,1);
            PutLine1(4, 0, "           Please wait, opening %s......",
                     pine_state->nr_mode ? "news articles" : "mail folder");
            fflush(stdout);
        }

        if(folder_to_open != NULL) {
            if(do_broach_folder(folder_to_open) <= 0) {
                display_message('x');
                sleep(4);
                end_screen();
                end_keyboard(pine_state->use_fkeys);
                end_tty_driver(pine_state);
            
                clear_index_cache();
                end_scroll_text();
                end_adrbk();
                printf("\n\nUnable to open %s \"%s\". Pine finished\n\n",
                       pine_state->nr_mode ? "news articles" : "folder",
                       folder_to_open);
                exit(-1);
            }
        } else {
            do_broach_folder(pine_state->inbox_name);
        }

        ps_global->painted_on_startup = 1;

        if(ps_global->mangled_footer) {
            ps_global->painted_on_startup = 2;
            ps_global->mangled_footer = 1;
        }

#ifndef	DOS
/* this is something to worry about after we've got local storage on DOS */
        if(!ps_global->nr_mode)
          if(expire_sent_mail())
            ps_global->painted_on_startup = 2;
#endif

        if(ps_global->show_new_version)
          q_status_message(1, 1,3,
                    " * * This is a new version of Pine. To use old Pine run \"pine.old\". * * "); 

        build_path(int_mail, ps_global->folders_dir, INTERRUPTED_MAIL);
        if(can_access(int_mail, ACCESS_EXISTS) == 0) {
            q_status_message(1, 4,5, "\007Use compose command to continue composing last message. It was interrupted.");
        }

    
#if defined(USE_QUOTAS)
        {
          long q;
          int  over;
          q = disk_quota(ps_global->home_dir, &over);
          if(q > 0 && over) {
              q_status_message2(1, 4,5,
                       "\007WARNING! Over your disk quota by %s bytes (%s)",
                           comatose(q),byte_string(q));
          }
        }
#endif

        /*-------------------------------------------------------------------
                         Loop executing the commands
    
            This is done like this so that one command screen can cause
            another one to execute it with out going through the main
            menu. 
            BUG- need for comments
    
          ------------------------------------------------------------------*/
        pine_state->next_screen = pine_state->start_in_index ?
                                         mail_index_screen : 
                                         main_menu_screen;

        while(1) {
            if(pine_state->next_screen == SCREEN_FUN_NULL) 
              pine_state->next_screen = main_menu_screen;

            (*(pine_state->next_screen))(pine_state);
        }

    } else {
        /*======= address on command line/send one message mode ============*/
        char *to, **t, *error;
        int   len, good_addr;

        ps_global = pine_state;

        /*----- Format the To: line with commas for the composer ---*/
        for(t = argv, len = 0; *t != NULL; len += strlen(*t++) + 2);
        to = fs_get(len + 5);
        to[0] = '\0';
        for(t = argv, len = 0; *t != NULL; t++) {
            if(to[0] != '\0')
              strcat(to, ", ");
            strcat(to, *t);
        }

        good_addr = (build_address(to, tmp_20k_buf, &error) >= 0);

        if(good_addr) {
            char *addr = cpystr(tmp_20k_buf);
            compose_mail(addr);
            fs_give((void **)&addr);
        }

        fs_give((void *)&to);
        end_screen();
        end_keyboard(pine_state->use_fkeys);
        end_tty_driver(pine_state);
        if(!good_addr) {
            fprintf(stderr, "Bad address: %s\n", error);
            exit(-1);
        }
        fflush(stdout);
        exit(0);
    }
}



/*----------------------------------------------------------------------
      display main menu and execute main menu commands

    Args: The usual pine structure

  Result: main menu commands are executed


              M A I N   M E N U    S C R E E N

   Paint the main menu on the screen, get the commands and either execute
the fucntion or pass back the name of the function to execute for the menu
selection. Only simple functions that always return here can be execute
here.


This functions handling of new mail, redrawing, errors and such can 
serve as a template for the other screen that do much the same thing.

There is a loop that fetchs and executes commands until a command to leave
this screen is given. Then the name of the next screen to display is
stored in next_screen member of the structure and this function is exited with a return.


First a check for new mail is performed. This might involve reading the new
mail into the inbox which might then cause the screen to be repainted.


Then the general screen painting is done. This is usually controlled
by a few flags and some other position variables. If they change they
tell this part of the code what to repaint. This will include cursor
motion and so on.
  ----*/

static struct key_menu main_key_menu =
    { 0,{
        {"?","Help",0},        {"C","Compose",0},     {"Q","Quit",0},    
#ifdef VIEW
        {"V","View Mail",0},   {"I","Mail Index", 0}, {"F","Folders",0}, 
        {"A","Addresses",0},   {"O","Other",0},       {NULL,NULL,0},
#else
        {"I","Mail Index", 0}, {"F","Folders",0},     {"A","Addresses",0},
        {"O","Other",0},       {NULL,NULL,0},         {NULL,NULL,0},
#endif
        {NULL,NULL,0},         {NULL,NULL,0},         {NULL,NULL,0}}};
    

void
main_menu_screen(pine_state)
     struct pine *pine_state;
{
    int  redraw, first_time;
    int  ch, orig_ch;

    ps_global = pine_state;

    dprint(1, (debugfile, "\n\n    ---- MAIN_MENU_SCREEN ----\n"));
    redraw     = 1;
    first_time = 1;
    ch         = 'x'; /* For display_message first time through */

    pine_state->prev_screen = main_menu_screen;

    while (1) {
	/*----------- Check for new mail -----------*/
        if(new_mail(NULL, 0,ch==NO_OP_IDLE ? 0 : ch==NO_OP_COMMAND ?1 :2) >= 0)
          pine_state->mangled_header = 1;

        if(streams_died())
          pine_state->mangled_header = 1;

        if(pine_state->mangled_header) {
	    /* This set anchor causes the message count to be updated */
            set_titlebar("MAIN MENU",1, FolderName,
                         pine_state->current_sorted_msgno, 0, 0);
            pine_state->mangled_header = 0;
        }


	/* ----- Most screen painting ------*/
        if(pine_state->painted_on_startup) {
	    redraw = 0;
            set_titlebar("MAIN MENU",1, FolderName,0 , 0, 0);
            if(pine_state->painted_on_startup > 1)
              paint_keyhelp();
	    pine_state->painted_on_startup = 0;
	}
        if(redraw){
            show_main_screen(ch==ctrl('L') || first_time || ch == KEY_RESIZE);
            first_time = 0;
            redraw     = 0;
        }

	/*---- This displays new mail notification, or errors ---*/
        display_message(ch);


        /*------ Read the command from the keyboard ----*/      
        MoveCursor(min(0, pine_state->ttyo->screen_rows - 3), 0);
        ch = read_command();
        orig_ch = ch;

	/*----- Validate the command ----*/
        if(ch <= 0xff && isupper(ch))
          ch = tolower(ch);
        if(ch != 'q')
          /* 'q' is always valid as a way to exit pine even in function key
             mode, because the user might have got in accidentally and
             not have function keys to get out.
          */
          ch = validatekeys(ch);

	/*------ Execute the command ------*/
	switch (ch)
	{
	  case PF1:
	  case ctrl('G'):
	  case '?':
            helper(main_menu_tx, "HELP FOR MAIN MENU", 0);
            redraw++;
	    break;
  
	  case PF2:
	  case 'c':
	    pine_state->next_screen = compose_screen;
	    return;
  
  
	  case PF3: 
	  case 'q':
	    pine_state->next_screen = quit_screen;
	    return;

#ifdef VIEW  
	  case PF4:
	  case 'v':
	    pine_state->next_screen = mail_view_screen;
	    return;
#endif
  
	
#ifdef VIEW	  
	  case PF5:
#else
	  case PF4:
#endif
	  case 'i':
	    pine_state->next_screen = mail_index_screen;
	    return;
		    
	
#ifdef VIEW	  
	  case PF6: 
#else
	  case PF5: 
#endif
	  case 'f':
	    pine_state->next_screen = folder_screen;
	    return;

#ifdef VIEW  
	  case PF7 :
#else
	  case PF6 :
#endif
	  case 'a':
	    pine_state->next_screen = addr_book_screen;
	    return;
  
  
#ifdef VIEW
	  case PF8:
#else
	  case PF7:
#endif
	  case 'o':
	    pine_state->next_screen = other_screen;
	    return;
		  

#ifdef DEBUG
          case '#':
            if(debug > 8 &&
               want_to("Test panic and abort now", 'n',NULL, 0) == 'y')
              panic("Testing panic");
            break;
#endif


          case ctrl('Z'):
            if(!have_job_control())
              goto bleep;
            if(!pine_state->can_suspend) {
                q_status_message(1, 1,3,
                           "\007Pine suspension not enabled - see help text");
                break;
            } else {
                do_suspend(pine_state);
            }
            /*-- Fall through to redraw --*/


          case KEY_RESIZE:
	  case ctrl('L'):
	    redraw++;
	    break;
  
  
	  case NO_OP_COMMAND :
          case NO_OP_IDLE:
            break;	/* noop for timeout loop mail check */
  
  
	  default:
          bleep:
            q_status_message2(0, 0,2,
                              "\007Unknown command: \"%s\". Use %s for help",
                              (void *)pretty_command(orig_ch),
                              pine_state->use_fkeys ? "F1" : "?");
	 } /* the switch */
    } /* the BIG while loop! */
}


	
/*----------------------------------------------------------------------
         call the various components to show the main menu

    Args: redraw -- flag indicating window size change: recalculate sizes

  Result: main menu is displayed
  ----*/
static void
show_main_screen(do_redraw)
    int do_redraw;
{
    ClearScreen();
    do_menu();
    paint_keyhelp();
    fflush(stdout);
}


static char *main_menu[] = {
"  %s  HELP        - Get help using Pine",
"",
"  %s  COMPOSE     - Compose and send a message",
"",
#ifdef VIEW
"  %s  VIEW MAIL   - Read current message in current folder",
"",
#endif
"  %s  MAIL INDEX  - Read mail in current folder",
"",
"  %s  FOLDERS     - Open a different mail folder",
"",
"  %s  ADDRESSES   - Update your address book",
"",
"  %s  OTHER       - Use other functions",
"",
"  %s  QUIT        - Exit the Pine mail program",
NULL};

static char *menu_f_keys[] = {
"F1 ",
"",
"F2 ",
"",
"F4 ",
"",
"F5 ",
"",
"F6 ",
"",
"F7 ",
"",
#ifdef VIEW
"F8 ",
"",
#endif
"F3 ",
"                    (You may also press \"q\" to leave pine.)",
NULL};


static char *menu_keys[] = {
"? ",
"",
"C ",
"",
#ifdef VIEW
"V ",
"",
#endif
"I ",
"",
"F ",
"",
"A ",
"",
"O ",
"",
"Q ",
"",
NULL};







/*----------------------------------------------------------------------
         Actually display the main menu

    Args: redraw -- flag indicating window size change: recalculate sizes

  Result: Main menu is displayed
  ---*/
static void
do_menu()
{
    int  dline, use_fkeys;
    char buf[MAX_SCREEN_COLS+1];


    use_fkeys = ps_global->use_fkeys;
    
    set_titlebar("MAIN MENU",1, FolderName,0 , 0, 0);

    for(dline = 2; dline < ps_global->ttyo->screen_rows - 3; dline++) {
        if(main_menu[dline-2] == NULL)
          break;
        sprintf(buf, main_menu[dline -2],
                use_fkeys ? menu_f_keys[dline-2] : menu_keys[dline-2]);
        buf[ps_global->ttyo->screen_cols] = '\0';
        PutLine0(dline+1 + (ps_global->show_new_version ? 0 : 1) , 4, buf);
    }
    dline += 2;
    if(ps_global->show_new_version) {
        PutLine0(dline, 3, "Note: In Pine 3.0 we are encouraging folks to use the MAIL INDEX to read");
        dline++;
        PutLine0(dline, 9, "mail instead of VIEW MAIL, so it is no longer on the main menu. Once"); 
        dline++;
        PutLine0(dline, 9, "in the mail index, it is available as usual as the \"V\" command.");
    }
    
/*    PutLine0(dline, 3, "Old Pine is available as "pine.old". Comments on this new version to "pine@cac"); */
        
}



/*----------------------------------------------------------------------
    Paint the keyhelp at the bottom of the sceen

 Args: redraw -- If set recalculate the spacing, otherwise just repaint

 ----*/
static void
paint_keyhelp()
{
    format_keymenu(&main_key_menu, ps_global->ttyo->screen_cols);
    output_keymenu(&main_key_menu, -2, 0);
}



/*----------------------------------------------------------------------
          Quite pine if the user wants to 

    Args: The usual pine structure

  Result: User is asked if she wants to quit, if yes then execute quit.

       Q U I T    S C R E E N

Not really a full screen. Just count up deletions and ask if we really
want to quit.
  ----*/
void
quit_screen(pine_state)
     struct pine *pine_state;
{
    int cur_is_inbox;

    dprint(1, (debugfile, "\n\n    ---- QUIT SCREEN ----\n"));    

    if(!pine_state->nr_mode &&
       want_to("Really quit pine", 'y', h_oe_export, 0) == 'n') {
        pine_state->next_screen = pine_state->prev_screen;
        return;
    }

    cur_is_inbox = (pine_state->inbox_stream == pine_state->mail_stream);

    expunge_and_close(pine_state->mail_stream, pine_state->cur_folder);

    if(pine_state->inbox_stream != NULL && !cur_is_inbox){
        expunge_and_close(pine_state->inbox_stream, pine_state->inbox_name);
    }

    end_screen();
    end_keyboard(pine_state->use_fkeys);
    end_tty_driver(pine_state);

    clear_index_cache();
    end_scroll_text();
    end_adrbk();

    if(pine_state->hostname != NULL)
      fs_give((void **)&pine_state->hostname);
    if(pine_state->localdomain != NULL)
      fs_give((void **)&pine_state->localdomain);
    if(pine_state->userdomain != NULL)
      fs_give((void **)&pine_state->userdomain);
    if(pine_state->ttyo != NULL)
      fs_give((void **)&pine_state->ttyo);
    if(pine_state->home_dir != NULL)
      fs_give((void **)&pine_state->home_dir);
    if(pine_state->folders_dir != NULL)
      fs_give((void **)&pine_state->folders_dir);

    fs_give((void **)&pine_state);

#ifdef DEBUG
    fclose(debugfile);
#endif    

    printf("\n\n\nPine finished\n\n");
#ifdef MEMLOG
    dump_memlog(1);
#endif
    fflush(stdout);
    exit(0);
}



/*----------------------------------------------------------------------
     Count up the number of deleted message on a give mail stream

  Args: stream -- The stream/folder to count deleted messages on

 Result: returns number of messages deleted on that stream
  ----------------------------------------------------------------------*/
count_deleted(stream )
     MAILSTREAM *stream;
{
    int           i, delete_count = 0;
    char         sequence[10];
    MESSAGECACHE *mc;

    if(stream->nmsgs <= 0)
      return(0);
    sprintf(sequence,"1:%d",stream->nmsgs); /* so we can do elts and look  */
    mail_fetchflags(stream, sequence);      /* at flags and they'll be vaild */
    for(i = 0 ; i < stream->nmsgs; i++) {
	mc = mail_elt(stream, (long)(i+1));
        if(mc != NULL && mc->deleted)
          delete_count++;
    }
    return(delete_count);
}



/*----------------------------------------------------------------------
     Find the first unread message 

  Args: stream -- The stream/folder to look at message status

 Result: Message number of first unread message
  ----------------------------------------------------------------------*/
MsgNo
first_sorted_unread(stream )
     MAILSTREAM *stream;
{
    MsgNo        i;
    char         sequence[10];
    MESSAGECACHE *mc;

    sprintf(sequence,"1:%d", stream->nmsgs); /* so we can do elts and look  */
    mail_fetchflags(stream, sequence);      /* at flags and they'll be vaild */
    for(i = 1 ; i <= stream->nmsgs; i++) {
	mc = mail_elt(stream, (long)(ps_global->sort[i]));
        if(mc != NULL && !mc->seen)
          break;
    }
    if(i > stream->nmsgs)
      i = stream->nmsgs;
    dprint(4, (debugfile, "First unseen returning %ld\n", (long)i));
    return(i);
}




/*----------------------------------------------------------------------
    Panic pine - call on detected programmatic errors to exit pine

   Args: message -- message to record in debug file and to be printed for user

 Result: The various tty modes are restored
         If debugging is active a core dump will be generated
         Exits Pine

  This is also called from imap routines and fs_get and fs_resize.
  ----*/
void
panic(message)
     char *message;
{
    MoveCursor(ps_global->ttyo->screen_rows -1, 0);
    NewLine();
    end_screen();
    end_keyboard(ps_global != NULL ? ps_global->use_fkeys : 0);
    end_tty_driver(ps_global);
    end_signals();
    dprint(1, (debugfile, "Pine Panic: %s\n", message));
    fprintf(stderr, "\n\nBug in Pine detected: \"%s\".\nExiting pine.\n",
            message);
#ifdef DEBUG
    if(debug)
      fclose(debugfile);
    coredump();   /*--- If we're debugging get a core dump --*/
#endif

    exit(-1);
    fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
}



/*----------------------------------------------------------------------
    Panic pine - call on detected programmatic errors to exit pine, with arg

  Input: message --  printf styule string for panic message (see above)
         arg     --  argument for printf string

 Result: The various tty modes are restored
         If debugging is active a core dump will be generated
         Exits Pine
  ----*/
void
panic1(message, arg)
    char *message;
    char *arg;
{
    char buf[1001];
    if(strlen(message) > 1000) {
        panic("Pine paniced. (Reason for panic is too long to tell)");
    } else {
        sprintf(buf, message, arg);
        panic(buf);
    }
}


