/* view.c */

#include "ml.h"

/* 
 *  These MUST correspond with the Representation_Type 
 *  enum in structures.h 
 */
 
MLRepresentation Representation[] = {
  { "Normal",   NULL, XtNpresentNormal,  },
  { "Reverse",  NULL, XtNpresentReverse, },
  { "Sender",   NULL, XtNpresentSender,  },
  { "Subject",  NULL, XtNpresentSubject, },
  { "Thread",   NULL, XtNpresentThread,  },
  { "Size",     NULL, XtNpresentSize,    },
  { NULL,       NULL, NULL,              },
};

#ifdef __STDC__
void init_representation(void)
#else
void init_representation()
#endif
{ 
  int i;
  for(i = 0; Representation[i].name != NULL; i ++)
    Representation[i].localized = 
      MLGetLocalized(Representation[i].resource,Representation[i].name);
  return;
}


MLFlag Flags[] = {
  { "deleted",   NULL, XtNflagDeleted,  "\\Deleted",  TRUE  },
  { "seen",      NULL, XtNflagSeen,     "\\Seen"   ,  TRUE  },
  { "flagged",   NULL, XtNflagFlagged,  "\\Flagged",  TRUE  },
  { "answered",  NULL, XtNflagAnswered, "\\Answered", TRUE  },
  { "draft",     NULL, XtNflagDraft,    "\\Draft",    TRUE  },
  { "recent",    NULL, XtNflagRecent,   "\\Recent",   FALSE },
  { NULL,        NULL, NULL,            NULL,         FALSE },
};


#ifdef __STDC__
void init_flags(void)
#else
void init_flags()
#endif
{
  int i;
  for(i = 0; Flags[i].name != NULL; i ++)
    Flags[i].localized = MLGetLocalized(Flags[i].resource,Flags[i].name);
  return;
}



Menu view_lview_menu[] = {
  { NULL, "dismiss", NUL_TERM,
      view_lview_dismiss, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "save", NUL_TERM,
      view_lview_save, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "filter", NUL_TERM, 
      view_filter, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "detach", NUL_TERM,
      view_lview_detach, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "hide", NUL_TERM,
      view_lview_hide, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "HELP", NUL_TERM,
      view_lview_help, NULL, 0, NULL, NULL, BTN_ON },
};



Menu view_save_menu[] = {
  { NULL, "fullhead", NUL_TERM,
      view_savefull, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
  { NULL, "parthead", NUL_TERM,
      view_savepart, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
  { NULL, "nonehead", NUL_TERM,
      view_savenone, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
};

Menu view_pipe_menu[] = {
  { NULL, "fullhead", NUL_TERM,
      view_execfull, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
  { NULL, "parthead", NUL_TERM,
      view_execpart, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
  { NULL, "nonehead", NUL_TERM,
      view_execnone, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
};

Menu view_print_menu[] = {
  { NULL, "fullhead", NUL_TERM,
      view_printfull, NULL, 0, NULL, NULL,
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
  { NULL, "parthead", NUL_TERM,
      view_printpart, NULL, 0, NULL, NULL,
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
  { NULL, "nonehead", NUL_TERM,
      view_printnone, NULL, 0, NULL, NULL,
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN},
};


Menu main_message_menu[] = {
  { NULL, "read_selected", NUL_TERM,
      view_read_selected, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "read_selected_newwin", NUL_TERM,
      view_read_selected_newwin, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "select_messages", NUL_TERM,
      view_select_messages, NULL, 0, NULL, NULL, 
      BTN_NOMAILBOXESOPEN },
  { NULL, "select_new_messages", NUL_TERM,
      view_select_new_messages, NULL, 0, NULL, NULL, 
      BTN_NOMAILBOXESOPEN },
  { NULL, "select_unseen_messages", NUL_TERM,
      view_select_unseen_messages, NULL, 0, NULL, NULL, 
      BTN_NOMAILBOXESOPEN },
  { NULL, "unselect_messages", NUL_TERM, 
      view_unselect_messages, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "find_messages", NUL_TERM, 
      view_find, NULL, 0, NULL, NULL, 
      BTN_NOMAILBOXESOPEN },

};

Menu view_file_menu[] = {
  { NULL, "copy", NUL_TERM,
      view_copy, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "print_menu", NUL_TERM,
      NULL, view_print_menu, XtNumber(view_print_menu), 
      NULL, NULL, BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "save_menu", NUL_TERM,
      NULL, view_save_menu, XtNumber(view_save_menu), 
      NULL, NULL, BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "pipe_menu", NUL_TERM,
      NULL, view_pipe_menu, XtNumber(view_pipe_menu), 
      NULL, NULL, BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },

};

Menu view_setflags_menu[] = {
  { NULL, "set_deleted", NUL_TERM,
      view_set_deleted, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "set_seen", NUL_TERM,
      view_set_seen, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "set_flagged", NUL_TERM,
      view_set_flagged, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "set_answered", NUL_TERM,
      view_set_answered, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
};

Menu view_clearflags_menu[] = {
  { NULL, "clear_deleted", NUL_TERM,
      view_clear_deleted, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "clear_seen", NUL_TERM,
      view_clear_seen, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "clear_flagged", NUL_TERM,
      view_clear_flagged, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "clear_answered", NUL_TERM,
      view_clear_answered, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
};


Menu sort_menu[] = {
  { NULL, "sort_normal",  NUL_TERM,
      view_sort_normal, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "sort_reverse", NUL_TERM,
      view_sort_reverse, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "sort_subject", NUL_TERM,
      view_sort_subject, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "sort_sender", NUL_TERM,
      view_sort_sender, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "sort_size", NUL_TERM,
      view_sort_size, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },

};


Menu view_edit_menu[] = {
  { NULL, "setflags_menu",  NUL_TERM,
      NULL, view_setflags_menu, XtNumber(view_setflags_menu), 
      NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "clearflags_menu",  NUL_TERM,
      NULL, view_clearflags_menu, XtNumber(view_clearflags_menu),
      NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "sort_menu", NUL_TERM,
      NULL, sort_menu, XtNumber(sort_menu), NULL, NULL, BTN_NOMAILBOXESOPEN },
};




Menu view_options_menu[] = {
  { NULL, "configure", NUL_TERM,
      view_configure, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "preferences", NUL_TERM,
      main_preferences, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "more_preferences", NUL_TERM,
      main_more_preferences, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "address_book", NUL_TERM,
      main_address_book, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "note_book", NUL_TERM,
      main_note_book, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "show_log", NUL_TERM,
      main_logwin, NULL, 0, NULL, NULL, BTN_ON },


};

Menu view_reply_submenu[] = {
  { NULL, "reply_sender", NUL_TERM, 
      view_reply_sender, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "reply_all", NUL_TERM,
      view_reply_all, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
};

Menu view_forward_submenu[] = {
  { NULL, "forward", NUL_TERM, 
      view_forward, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "forward_attach",  NUL_TERM,
      view_forward_attach, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
};

Menu view_send_menu[] = {
  { NULL, "compose_new", NUL_TERM, 
      main_compose, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "reply_menu", NUL_TERM, 
      NULL, view_reply_submenu, XtNumber(view_reply_submenu), 
      NULL, NULL, BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "forward_menu", NUL_TERM,
      NULL, view_forward_submenu, XtNumber(view_forward_submenu),
      NULL, NULL, BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
  { NULL, "remail", NUL_TERM,
      view_remail, NULL, 0, NULL, NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN },
};

Menu view_main_mailbox_menu[] = {
  { NULL, "listwin", NUL_TERM,
      view_lview_window, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "new", NUL_TERM,
      view_new, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "open_mailbox", NUL_TERM,
      view_open, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "check_mailbox", NUL_TERM,
     view_check_mailbox, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "expunge_messages", NUL_TERM, 
      view_expunge_messages, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "no_update",   NUL_TERM,
      view_no_update, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN|BTN_ISMAIL },
  { NULL, "stopload_mailbox", NUL_TERM,
      view_stopload_mailbox, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "contload_mailbox", NUL_TERM,
      view_contload_mailbox, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "close_mailbox", NUL_TERM, 
      view_close_mailbox,   NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "close", NUL_TERM, 
      main_close, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "exit", NUL_TERM, 
      bye,   NULL, 0, 
      NULL, NULL, BTN_ON },

};


Menu view_sub_mailbox_menu[] = {
  { NULL, "listwin", NUL_TERM,
      view_lview_window, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "new", NUL_TERM,
      view_new, NULL, 0, NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "open_mailbox", NUL_TERM,
      view_open, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "check_mailbox", NUL_TERM,
     view_check_mailbox, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "expunge_messages", NUL_TERM, 
      view_expunge_messages, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },

  { NULL, "no_update",   NUL_TERM,
      view_no_update, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN|BTN_ISMAIL },
  { NULL, "stopload_mailbox", NUL_TERM,
      view_stopload_mailbox, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "contload_mailbox", NUL_TERM,
      view_contload_mailbox, NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },
  { NULL, "close_mailbox", NUL_TERM, 
      view_close_mailbox,   NULL, 0, 
      NULL, NULL, BTN_NOMAILBOXESOPEN },

};


Menu view_help_menu[] = {

  { NULL, "tophelp", NUL_TERM,
      main_help, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "window_help", NUL_TERM,
      view_window_help, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "keyboard_help", NUL_TERM,
      main_keyboard_help, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "config_help", NUL_TERM,
      main_config_help, NULL, 0, NULL, NULL, NUL_TERM },
  { NULL, "resources_help", NUL_TERM,
      main_resources_help, NULL, 0, NULL, NULL, NUL_TERM },
  { NULL, "intl_help", NUL_TERM,
      main_intl_help, NULL, 0, NULL, NULL, NUL_TERM },
  { NULL, "version_help", NUL_TERM,
      main_version_help, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "action_help", NUL_TERM, 
      view_action_help, NULL, 0, NULL, NULL, BTN_ON },
};

Menu view_menu[] = {
  { NULL, "mailbox_menu", NUL_TERM,
      NULL, view_main_mailbox_menu, XtNumber(view_main_mailbox_menu),
      NULL, NULL, BTN_ON },
  { NULL, "message_menu", NUL_TERM, 
      NULL, main_message_menu, XtNumber(main_message_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "file_menu", NUL_TERM, 
      NULL, view_file_menu, XtNumber(view_file_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "edit_menu", NUL_TERM, 
      NULL, view_edit_menu, XtNumber(view_edit_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "option_menu", NUL_TERM,
      NULL, view_options_menu, XtNumber(view_options_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "send_menu", NUL_TERM,
      NULL, view_send_menu, XtNumber(view_send_menu), 
      NULL, NULL, BTN_ON },

  { NULL, "HELP_menu", NUL_TERM, 
      NULL, view_help_menu, XtNumber(view_help_menu), 
      NULL, NULL, BTN_ON },
};

Menu view_secondmenu[] = {
  { NULL, "mailbox_menu", NUL_TERM,
      NULL, view_sub_mailbox_menu, XtNumber(view_sub_mailbox_menu),
      NULL, NULL, BTN_ON },
  { NULL, "message_menu", NUL_TERM, 
      NULL, main_message_menu, XtNumber(main_message_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "file_menu", NUL_TERM, 
      NULL, view_file_menu, XtNumber(view_file_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "edit_menu", NUL_TERM, 
      NULL, view_edit_menu, XtNumber(view_edit_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "option_menu", NUL_TERM,
      NULL, view_options_menu, XtNumber(view_options_menu), 
      NULL, NULL, BTN_ON },
  { NULL, "send_menu", NUL_TERM,
      NULL, view_send_menu, XtNumber(view_send_menu), 
      NULL, NULL, BTN_ON },

  { NULL, "HELP_menu", NUL_TERM, 
      NULL, view_help_menu, XtNumber(view_help_menu), 
      NULL, NULL, BTN_ON },
};


Button_Menu second_buttons[] = {
  { "view_read_selected_btn",view_read_selected,       NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
  { "view_read_selectednew_btn",view_read_selected_newwin,       
      NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
  { "view_set_deleted_btn",  view_set_deleted,         NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
  { "view_expunge_btn",      view_expunge_messages,    NULL, 
      BTN_NOMAILBOXESOPEN,                 NULL },
  { "view_copy_btn",         view_copy,                NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
  { "view_save_btn",         view_savepart,            NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
  { "view_reply_btn",        view_reply_sender,        NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
  { "view_replyall_btn",     view_reply_all,           NULL, 
      BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, NULL },
};

#ifdef __STDC__
void view_check_buttons(void)
#else
void view_check_buttons()
#endif
{
  ButtonState state;
  MainWindow *mwin;

  for(mwin = session->mwin; mwin; mwin = mwin->next) {
    if(mwin->destroyed)
      continue;
    state = (mwin->current) ? mwin->current->buttonstate : BTN_ON;
    update_buttons(mwin->buttonlist, session->buttonstate | state);

    XtVaSetValues(mwin->action_button, XmNsensitive,
		  (session->buttonstate & BTN_NOMAILBOXESOPEN) 
		  ? FALSE : TRUE,  NULL);
  }
  return;
}



#ifdef __STDC__
Mailbox *new_mailbox(void)
#else
Mailbox *new_mailbox()
#endif
{
  Mailbox *mailbox = (Mailbox *) fs_get(sizeof(Mailbox));

  mailbox->mailstream     = NULL;
  mailbox->host           = NULL;
  mailbox->port           = 0L;
  mailbox->auth_type      = 0L;
  mailbox->ispop          = FALSE;
  mailbox->imap_protocol  = 0;
  mailbox->server         = NULL;
  mailbox->mailboxname    = NULL;
  mailbox->imapname       = NULL;
  mailbox->type           = MAILBOX_TYPE_MAIL;
  mailbox->fetched        = FALSE;
  mailbox->auto_scan      = FALSE;
  mailbox->no_update      = FALSE;
  mailbox->bg_timer       = (XtIntervalId) 0;
  mailbox->first_fetch    = 0L;
  mailbox->has_new_mail   = FALSE;
  mailbox->nmsgs          = 0L;
  mailbox->found          = NULL;
  mailbox->flags_changed  = 0L;
  mailbox->update_needed  = 0;
  mailbox->refresh_needed = 0;
  mailbox->timer          = (XtIntervalId) 0;
  mailbox->next           = NULL;
  mailbox->prev           = NULL;

  return(mailbox);
}

#ifdef __STDC__
void free_mailbox(Mailbox *mailbox)
#else
void free_mailbox(mailbox)
     Mailbox *mailbox;
#endif
{
  if(mailbox != NULL) {
    if(mailbox->host)
      fs_give((void **) &mailbox->host);
    if(mailbox->mailboxname)
      fs_give((void **) &mailbox->mailboxname);
    if(mailbox->imapname)
      fs_give((void **) &mailbox->imapname);

    if(mailbox->found)
      free_message_list(mailbox->found,TRUE,FALSE);

    fs_give((void **) &mailbox);
  }
  return;
}

#ifdef __STDC__
Lview *new_lview(void)
#else
Lview *new_lview()
#endif
{
  Lview *lview = (Lview *) fs_get(sizeof(Lview));

  lview->title            = NULL;
  lview->mailstream       = NULL;
  lview->mailbox          = NULL;
  lview->message_list     = NULL;
  lview->count            = 0L;
  lview->pruned           = 0L;
  lview->prune_happened   = FALSE;
  lview->num_selected     = 0L;
  lview->has_new          = FALSE;
  lview->selected         = FALSE;
  lview->number           = 0L;
  lview->buttonstate      = BTN_ON;
  lview->level            = 0;
  lview->representation   = REP_ASCENDING;
  lview->scripting        = FALSE;
  lview->script_arg       = NULL;
  lview->script_header    = HEADER_UNKNOWN;

  lview->filter           = NULL;
  lview->parent           = NULL;
  lview->next             = NULL;
  lview->prev             = NULL;
  
  return(lview);
}

#ifdef __STDC__
void free_lview(Lview *lview)
#else
void free_lview(lview)
     Lview *lview;
#endif
{
  if(lview) {
    if(lview->title)
      fs_give((void **) &lview->title);
    if(lview->script_arg)
      fs_give((void **) &lview->script_arg);

    fs_give((void **) &lview);
  }
  return;
}

#ifdef __STDC__
Filter *new_filter(void)
#else
Filter *new_filter()
#endif
{
  Filter *filter = (Filter *) fs_get(sizeof(Filter));

  filter->mailboxname     = NULL;
  filter->name            = NULL;
  filter->text            = NULL;
  filter->action          = NULL;
  filter->search_tree     = NULL;
  filter->search_types    = 0L;
  filter->archived        = FALSE;
  filter->filter_type     = FILTER_TYPE_UNKNOWN;
  filter->representation  = REP_ASCENDING;
  filter->number          = 0L;
  filter->next            = NULL;
  filter->prev            = NULL;

  return(filter);
}

#ifdef __STDC__
void free_filter(Filter *filter)
#else
void free_filter(filter)
     Filter *filter;
#endif
{
  if(filter) {
    if(filter->mailboxname) 
      fs_give((void **) &filter->mailboxname);
    if(filter->name)
      fs_give((void **) &filter->name);
    if(filter->action)
      fs_give((void **) &filter->action);
    if(filter->text)
      fs_give((void **) &filter->text);

    cut_down_the_tree(filter->search_tree);

    fs_give((void **) &filter);
  }
  return;
}

#ifdef __STDC__
Message_List *new_message_list(void)
#else
Message_List *new_message_list()
#endif
{
  Message_List *message_list = (Message_List *) fs_get(sizeof(Message_List));

  message_list->message     = NULL;
  message_list->selected    = FALSE;
  message_list->number      = 0L;
  message_list->level       = 0;
  message_list->prev        = NULL;
  message_list->next        = NULL;

  return(message_list);
}
     
#ifdef __STDC__
Message *new_message(void)
#else
Message *new_message()
#endif
{
  Message *message = (Message *) fs_get(sizeof(Message));
  
  message->mailbox          = NULL;
  message->mailstream       = NULL;
  message->envelope         = NULL;
  message->body             = NULL;
  message->longcache        = NULL;
  message->msgno            = 0L;
  message->viewline         = NULL;
  message->sender           = NULL;
  message->subject          = NULL;
  message->references       = NULL;
  message->message_id       = NULL;
  message->thread_parent    = NULL;
  message->thread_child     = FALSE;
  message->in_view          = FALSE;
  message->fetched          = FALSE;
  return(message);
}

#ifdef __STDC__
void free_message(Message *message)
#else
void free_message(message)
     Message *message;
#endif
{
  if(message == NULL)
    return;

  if(message->viewline)
    XmStringFree(message->viewline);
  if(message->sender)
    fs_give((void **) &message->sender);
  if(message->subject)
    fs_give((void **) &message->subject);
  if(message->references)
    fs_give((void **) &message->references);
  if(message->message_id != NULL)
    fs_give((void **) &message->message_id);
  fs_give((void **) &message);

  return;
}



#ifdef __STDC__
Filter_Map *new_filter_map(void)
#else
Filter_Map *new_filter_map()
#endif
{
  Filter_Map *filter_map = (Filter_Map *) fs_get(sizeof(Filter_Map));

  filter_map->mailboxname   = NULL;
  filter_map->filename      = NULL;
  filter_map->sequence      = 0;
  filter_map->next          = NULL;

  return(filter_map);
}

#ifdef __STDC__
Filter_Map *get_filter_map(Lview *lview)
#else
Filter_Map *get_filter_map(lview)
     Lview *lview;
#endif
{
  Filter_Map *filter_map = NULL;
  
  if((lview == NULL) 
     || (lview->mailbox == NULL) 
     || (lview->mailbox->imapname == NULL))
    return(NULL);

  for(filter_map = session->filter_map; filter_map; 
      filter_map = filter_map->next) {
    if((strcmp(filter_map->mailboxname,
	       lview->mailbox->imapname)) == STRMATCH)
      return(filter_map);
  }
  return(NULL);
}

#ifdef __STDC__
Filter_Map *generate_filter_map(Lview *lview)
#else
Filter_Map *generate_filter_map(lview)
     Lview *lview;
#endif
{
  char buffer[MAXPATHLEN];
  Filter_Map *prev = NULL;
  Filter_Map *filter_map = new_filter_map();
 
  filter_map->mailboxname = cpystr(lview->mailbox->imapname);
 
  if(session->filter_map == NULL) {
    session->filter_map = filter_map;
    sprintf(buffer,"%s/%s.1", session->cachedir,FILTERFILE);
    filter_map->sequence = 1;
    filter_map->filename = cpystr(buffer);
  }
  else {
    for(prev = session->filter_map; prev->next; prev = prev->next)
      ;
    filter_map->sequence = prev->sequence + 1;
    sprintf(buffer,"%s/%s.%d",session->cachedir,
	    FILTERFILE, filter_map->sequence);
    filter_map->filename = cpystr(buffer);
    prev->next = filter_map;
  }
  (void) save_defaults();
  return(filter_map);
}


#ifdef __STDC__
void free_message_list(Message_List *message_list, 
		       Boolean recurse, Boolean free_messages)
#else 
void free_message_list(message_list, recurse, free_messages) 
     Message_List *message_list;
     Boolean recurse;
     Boolean free_messages;
#endif
{
  if(message_list == NULL)
    return;
  if(recurse)
    free_message_list(message_list->next, recurse, free_messages);
  if(free_messages)
    free_message(message_list->message);
  fs_give((void **) &message_list);
  return;
}












#ifdef __STDC__
MainWindow *create_main_window(MainWindow *mainwin)
#else
MainWindow *create_main_window(mainwin)
     MainWindow *mainwin;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  XtTranslations translations;
  MainWindow *mwin;
  MainWindow *curr;
  Boolean is_main = FALSE;



  if(mainwin) {
    mwin = mainwin;
    mwin->next = mwin->prev = NULL;
    mwin->is_main = is_main = TRUE;
    mwin->destroyed = FALSE;
    mwin->serialno = 1;
  }
  else {
    for(curr = session->mwin; curr; curr = curr->next)
      if(curr->destroyed == TRUE)
	break;
    if(curr) {
      curr->destroyed = FALSE;
      view_context_switch(curr, NULL, NULL);
      XtPopup(curr->shell,XtGrabNone);
      curr->lview = curr->current = NULL;
      view_check_buttons();
      return(curr);
    }
    mwin = (MainWindow *) fs_get(sizeof(MainWindow));
    mwin->is_main = FALSE;
    mwin->destroyed = FALSE;
    for(curr = session->mwin; curr->next; curr = curr->next)
      ;
    mwin->serialno = curr->serialno + 1;
    curr->next = mwin;
    mwin->prev = curr;
    mwin->next = NULL;

    if(preferences.autoPlace == TRUE) {
      XtSetArg(args[n], XtNx, -1000); n ++;
      XtSetArg(args[n], XtNy, -1000); n ++;
    }

    XtSetArg (args[n], XmNdeleteResponse, XmDO_NOTHING); n++;        

    mwin->shell = XtCreatePopupShell("mainwindow",
				     topLevelShellWidgetClass,
				     session->shell,
				     args, n);
    n = 0;
    AddDestroyCallback (mwin->shell);
  }

  mwin->lview = mwin->current = NULL;
  mwin->listwin = (ListWindow *) fs_get(sizeof(ListWindow));
  mwin->listwin->is_realized = FALSE;
  mwin->listwin->hide_empty = preferences.hide_empty;

  mwin->buttonlist = NULL;


  setup_editres(mwin->shell);

  if(view_icon != (Pixmap) None)
    XtVaSetValues(mwin->shell,
		  XmNiconPixmap,view_icon,
		  NULL);

  mwin->form = XmCreateForm(mwin->shell,"form",args, n); n = 0;

  XtSetArg(args[n], XmNtopAttachment,   XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++;

  mwin->menubar = XmCreateMenuBar(mwin->form,"menubar", args, n); n = 0;
  XtManageChild(mwin->menubar);

  if(mwin->is_main)
    make_buttons(&mwin->buttonlist, NULL, mwin->menubar, view_menu, 
		 XtNumber(view_menu), 
		 BTN_NOSELECTION|BTN_NOMAILBOXESOPEN|BTN_NOPREV|BTN_NONEXT, 
		 (XtPointer) mwin, ROOTMENULEVEL);
  else
    make_buttons(&mwin->buttonlist, NULL, mwin->menubar, view_secondmenu, 
		 XtNumber(view_secondmenu), 
		 BTN_NOSELECTION|BTN_NOMAILBOXESOPEN|BTN_NOPREV|BTN_NONEXT, 
		 (XtPointer) mwin, ROOTMENULEVEL);






  XtSetArg(args[n], XmNadjustMargin, FALSE);      n ++;
  XtSetArg(args[n], XmNmarginWidth, 0);           n ++;
  XtSetArg(args[n], XmNborderWidth, 0);           n ++;

  XtSetArg(args[n], XmNtopAttachment,   XmATTACH_WIDGET); n ++;
  XtSetArg(args[n], XmNtopWidget, mwin->menubar);  n ++;
  XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n ++;
  XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n ++;
  mwin->rowcol = XmCreateRowColumn(mwin->form, "rowcol", args, n); n = 0;


  make_secondbuttons(mwin->buttonlist,
		     mwin->rowcol, 
		     second_buttons,
		     XtNumber(second_buttons),
		     BTN_NOSELECTION|BTN_NOMAILBOXESOPEN, 
		     (XtPointer) mwin);


  XtManageChild(mwin->rowcol);

  XtSetArg(args[n], XmNborderWidth,    0);                      n ++;
  XtSetArg(args[n], XmNtraversalOn,    FALSE);                  n ++;
  XtSetArg(args[n], XmNtopAttachment,  XmATTACH_WIDGET);        n ++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);          n ++;
  XtSetArg(args[n], XmNtopWidget,      mwin->rowcol);           n ++;
  XtSetArg(args[n], XmNsensitive,      FALSE);                  n ++;

  mwin->action_button = XmCreatePushButton(mwin->form,"action_button", 
					   args, n); 
  n = 0;

  XtAddCallback(mwin->action_button,XmNactivateCallback,
		(XtCallbackProc) view_do_actions, mwin);
  XtManageChild(mwin->action_button);

  XtSetArg(args[n], XmNborderWidth,     0                        ); n ++;
  XtSetArg(args[n], XmNtopAttachment,   XmATTACH_WIDGET          ); n ++;
  XtSetArg(args[n], XmNtopWidget,       mwin->rowcol             ); n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM            ); n ++;
  XtSetArg(args[n], XmNleftAttachment,  XmATTACH_WIDGET          ); n ++;
  XtSetArg(args[n], XmNleftWidget,      mwin->action_button      ); n ++;

  mwin->action = XmCreateTextField(mwin->form, "action_textfld",
				   args, n); 
  n = 0;

  XtManageChild(mwin->action);
  translations = XtParseTranslationTable(GLOBAL_text_field_translations);
  XtOverrideTranslations(mwin->action,translations);

  translations = 
    XtParseTranslationTable(GLOBAL_terminal_text_field_translations);
  XtOverrideTranslations(mwin->action,translations);  
  XtAddCallback(mwin->action, XmNactivateCallback, 
		(XtCallbackProc) view_do_actions, mwin);

  XtAddCallback(mwin->action, XmNmodifyVerifyCallback, 
		(XtCallbackProc) text_field_edit, NULL);

  XtSetArg(args[n], XmNtopAttachment,   XmATTACH_WIDGET);        n ++;
  XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM);          n ++;
  XtSetArg(args[n], XmNtopWidget,       mwin->action);           n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);          n ++;
  XtSetArg(args[n], XmNtraversalOn,     FALSE);                  n ++;
  XtSetArg(args[n], XmNorientation,     XmHORIZONTAL);           n ++;
  XtSetArg(args[n], XmNvalue,           100);                    n ++;
  mwin->slider = XmCreateScale(mwin->form, "slider", args, n);
  n = 0;
  XtManageChild(mwin->slider);

  XtSetArg(args[n], XmNtopAttachment,     XmATTACH_WIDGET);      n ++;
  XtSetArg(args[n], XmNtopWidget,         mwin->slider);         n ++;
  XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM);        n ++;
  XtSetArg(args[n], XmNrightAttachment,   XmATTACH_FORM);        n ++;
  XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_FORM);        n ++;

  XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC);        n ++;
  XtSetArg(args[n], XmNselectionPolicy,   XmEXTENDED_SELECT);    n ++;
  XtSetArg(args[n], XmNlistSizePolicy,    XmCONSTANT);           n ++;


  mwin->list = XmCreateScrolledList(mwin->form,"list",args,n); n = 0;

  XtAddCallback(mwin->list, XmNextendedSelectionCallback,
		(XtCallbackProc) view_set_select_messages, session);

  XtAddCallback(mwin->list, XmNdefaultActionCallback,
		(XtCallbackProc) view_read_message, session);

  translations = 
    XtParseTranslationTable(GLOBAL_lview_pop_translations);
  XtOverrideTranslations(mwin->list,translations);

  XtManageChild(mwin->list);
  XtManageChild(mwin->form);

  if(is_main)
    XtRealizeWidget(mwin->shell);
  else {
    XtAddCallback(mwin->shell, XmNdestroyCallback,
		  (XtCallbackProc) mwin_destroy, mwin);
    XtManageChild(mwin->shell);
    XtPopup(mwin->shell, XtGrabNone);
    position_popup_widget(mwin->shell, FALSE);
  }

  XmProcessTraversal(mwin->list, XmTRAVERSE_CURRENT);

  return(mwin);
}


/*
 *  Window was destroyed. Possibly by a window manager.
 *  Be nice and close the mailboxes. We have no control over
 *  this or it would be nicer to ask first. It's quite possible
 *  this happened by mistake.
 */

#ifdef __STDC__
void mwin_destroy(Tool w, MainWindow *mwin, XtPointer xp)
#else
void mwin_destroy(w, mwin, xp)
     Tool w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  MainWindow *curr;
  Lview *lview;
  Boolean found;

  if(mwin->is_main == TRUE)
    return;

  if(mwin->prev == NULL)       /* shouldn't happen */
    session->mwin = mwin->next;
  if(mwin->next)
    mwin->next->prev = mwin->prev;
  if(mwin->prev)
    mwin->prev->next = mwin->next;

  do {
    found = FALSE;
    if((lview = mwin->lview) != NULL) {
      close_mailbox(lview->mailbox);
      found = TRUE;
    }
  } while(found == TRUE);

  free_buttonlist(mwin->buttonlist);
  fs_give((void **) &mwin);
  
  return;
}


#ifdef __STDC__
MainWindow *find_main_window(Mailbox *mailbox)
#else
MainWindow *find_main_window(mailbox)
     Mailbox *mailbox;
#endif
{
  MainWindow *curr;
  Lview *lview;
  for(curr = session->mwin; curr; curr = curr->next) {
    if(curr->destroyed)
      continue;
    for(lview = curr->lview; lview; lview = lview->prev)
      if(lview->mailbox == mailbox)
	return(curr);
  }
  return(NULL);
}


#ifdef __STDC__
void mwin_cancel(MainWindow *mwin)
#else
void mwin_cancel(mwin)
     MainWindow *mwin;
#endif
{

  if((mwin) && (mwin->lview == NULL) && (mwin->is_main == FALSE)) {
    XtPopdown(mwin->shell);
    mwin->destroyed = TRUE;
    if(mwin->listwin->is_realized)
      XtPopdown(mwin->listwin->shell);
  }
  return;
}

#ifdef __STDC__
void view_select_from_read(Lview *lview, Message *message)
#else
void view_select_from_read(lview,message)
     Lview *lview;
     Message *message;
#endif
{
  MainWindow *mwin;
  Message_List *ml = NULL;
  Lview *lv;
  Boolean found = FALSE;
  Boolean found_view = FALSE;

  if(message == NULL)
    return;

  for(mwin = session->mwin; mwin; mwin = mwin->next) {
    for(lv = mwin->lview; lv; lv = lv->prev) {
      if(lv == lview) {
	found_view = TRUE;
	break;
      }
    }
    if(found_view == TRUE)
      break;
  }

  if((mwin == NULL) || (lv == NULL))
    return;

  if(lv == mwin->current) 
    XmListDeselectAllItems(mwin->list);

  for(ml = lv->message_list; ml; ml = ml->next) {
    if(ml->selected == TRUE)
      ml->selected = FALSE;
    if(ml->message == message) {
      found = TRUE;
      if(lv == mwin->current)
	XmListSelectPos(mwin->list,ml->number,FALSE);
      ml->selected = TRUE;
      lv->buttonstate &= ~(BTN_NOSELECTION);
    }
  }
  if(found == FALSE) 
    lv->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  return;
}



/* 
 * Used in the do_action function for scripting flag settings.
 * IMAP flags have a preceding backslash. User flags don't.
 * Here we see if it's an IMAP flag, and return a pointer to
 * the flag name (which has the backslash). Otherwise, return
 * the original pointer; which is then assumed to be a user flag.
 */

#ifdef __STDC__
char *sys_flagname(char *flag)
#else
char *sys_flagname(flag)
     char *flag;
#endif
{
  int i;
  if(flag) {
    for(i = 0; Flags[i].name != NULL; i ++)
      if((strcasecmp(flag,Flags[i].localized)) == STRMATCH)
	return(Flags[i].protocol);
  }
  return(flag);
}



#ifdef __STDC__
Widget new_list_widget(MainWindow *mwin)
#else
Widget new_list_widget(mwin) 
     MainWindow *mwin;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  
  Widget list;

  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++;
  XtSetArg(args[n], XmNtopWidget, mwin->slider); n ++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);  n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);  n ++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM);  n ++;

  XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n ++;
  XtSetArg(args[n], XmNselectionPolicy,XmEXTENDED_SELECT); n ++;
  XtSetArg(args[n], XmNlistSizePolicy,XmCONSTANT); n ++;

  list = XmCreateScrolledList(mwin->form,"list",args,n); n = 0;

  XtAddCallback(list, XmNextendedSelectionCallback,
		(XtCallbackProc) view_set_select_messages, mwin);

  XtAddCallback(list, XmNdefaultActionCallback,
		(XtCallbackProc) view_read_message, mwin);

  return(list);
}

#ifdef __STDC__
void view_open(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_open(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  mailboxes(mwin,FALSE);
  return;
}


#ifdef __STDC__
void view_configure(Widget w, void *xp, XtPointer cb)
#else
void view_configure(w,xp,cb)
     Widget w;
     void *xp;
     XtPointer cb;
#endif
{
  create_host_window(session->shell, NULL);
  return;
}





#ifdef __STDC__
void view_new(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_new(w, mwin, xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  MainWindow *new_win = create_main_window(NULL);
  mailboxes(new_win,FALSE);
  return;
}


#ifdef __STDC__
void view_action_help(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_action_help(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  help(mwin->shell, VIEWACTIONHELPFILE);
  return;
}

#ifdef __STDC__
void view_window_help(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_window_help(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  help(mwin->shell, VIEWWINDOWHELPFILE);
  return;
}


#ifdef __STDC__
void view_do_actions(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_do_actions(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  char **parsed_actions;
  char *raw_action = NULL;
  char *clean_action = NULL;
  int n;
  char * ptr;
  ACTIONREC * a;
  HEADERREC * h;
  Lview *lview;

  char warn[FILEBUFFLEN];

  lview = mwin->current;

  raw_action = GetTextField(mwin->action);

  if((lview == NULL) || (raw_action == NULL))
    return;

  if(*raw_action == NUL_TERM) {
    fs_give((void **) &raw_action);
    return;
  }

  clean_action = clean_and_parse_action(raw_action);
  raw_action = NULL;

  parsed_actions = get_actions(clean_action);
  fs_give((void **) &clean_action);

  if(parsed_actions == NULL)
    return;

  for(n = 0; parsed_actions[n]; n ++ ) {

    if(lview->script_arg)
      fs_give((void **) &lview->script_arg);

    lview->script_arg = NULL;

    a = find_action(parsed_actions[n]);

    if(a == NULL) {
      sprintf(warn,MLGetLocalized(XtNmsgUnknownAction,MsgUnknownAction),
				  parsed_actions[n]);
      mm_log(warn,WARN);
      break;
    }

    ptr = &parsed_actions[n][strlen(a->localized) + 1];
    if(a->option == TRUE) {
      h = get_hdrlist(ptr);
      if(h != NULL) {
	lview->script_header = h->hdrtype;
	ptr += strlen(h->name) + 1;
      }
    }

    if(a->arg == TRUE)
      lview->script_arg = unquote(ptr);

    lview->scripting = TRUE;

    switch(a->action) {

    case DELETE_ACT:
      view_set_deleted(w,mwin,xp);
      break;
    case EXPUNGE_ACT:
      view_expunge_messages(w,mwin,xp);
      break;
    case COPY_ACT:
      view_copy(w,mwin,xp);
      break;
    case MOVE_ACT:
      view_move(w,mwin,xp);
      break;
    case SAVE_ACT:
      view_save_dispatch(w,mwin,HEADER_UNKNOWN);
      break;
    case PRINT_ACT:
      view_print_dispatch(w,mwin,HEADER_UNKNOWN);
      break;
    case SHELL_ACT:
      view_exec_dispatch(w,mwin,HEADER_UNKNOWN);
      break;
    case SELECT_ACT:
      view_select_messages(w,mwin,xp);
      break;
    case NEW_ACT:
      view_select_new_messages(w,mwin,xp);
      break;
    case UNSEEN_ACT:
      view_select_unseen_messages(w,mwin,xp);
      break;
    case UNSELECT_ACT:
      view_unselect_messages(w,mwin,xp);
      break;
    case FLAG_ACT:
      view_set_flagged(w,mwin,xp);
      break;
    case SET_ACT:
      view_setflag(w,mwin,sys_flagname(lview->script_arg));
      break;
    case UNSET_ACT:
      view_clearflag(w,mwin,sys_flagname(lview->script_arg));
      break;
    case READ_ACT:
      view_read_selected(w,mwin,(XmListCallbackStruct *) xp);
      break;
      
    default:
      sprintf(warn,MLGetLocalized(XtNmsgUnknownAction,MsgUnknownAction),
				  a->localized);
      mm_log(warn,WARN);

      break;
    }

    lview->scripting = FALSE;
    continue;
  }

  free_actions(parsed_actions);
  return;
}

#ifdef __STDC__
void view_set_select_messages(Widget w, MainWindow *mwin, 
			      XmListCallbackStruct *xp)
#else
void view_set_select_messages(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XmListCallbackStruct *xp;
#endif
{
  unsigned long n = 0;
  Message_List *message_list;

  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    if((is_selected(xp, message_list->number)) == TRUE)
      message_list->selected = TRUE;
    else
      message_list->selected = FALSE;
    if(message_list->selected == TRUE)
      n ++;
  }

  mwin->current->num_selected = n;
  if(n) 
    mwin->current->buttonstate &= ~(BTN_NOSELECTION);
  else
    mwin->current->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  return;
}


#ifdef __STDC__
void view_check_mailbox(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_check_mailbox(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Mailbox *mailbox;

  for(mailbox = session->mailboxes; mailbox; mailbox = mailbox->next) {
    if(mailbox->mailstream == mwin->current->mailstream) {
      check_mailbox(mailbox,FALSE);
      break;
    }
  }
  return;
}

#ifdef __STDC__
void view_stopload_mailbox(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_stopload_mailbox(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Mailbox *mailbox;

  for(mailbox = session->mailboxes; mailbox; mailbox = mailbox->next) {
    if(mailbox->mailstream == mwin->current->mailstream) {
      if(mailbox->bg_timer) {
	update_logical_views(mailbox,TRUE);
	mailbox->update_needed = 0;
	XtRemoveTimeOut(mailbox->bg_timer);
	mailbox->bg_timer = (XtIntervalId) 0;
	mm_log(MLGetLocalized(XtNmsgBackgroundStop,MsgBackgroundStop),
	       MLNOTIFY);
	break;
      }
      else
	break;
    }
  }
  return;
}

#ifdef __STDC__
void view_contload_mailbox(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_contload_mailbox(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Mailbox *mailbox;

  for(mailbox = session->mailboxes; mailbox; mailbox = mailbox->next) {
    if(mailbox->mailstream == mwin->current->mailstream) {
      if(mailbox->bg_timer != (XtIntervalId) 0)
	return;
      mailbox->bg_timer 
	= XtAppAddTimeOut(context,
			  (mailbox->type == MAILBOX_TYPE_NEWS) 
			  ? (preferences.news_background * 1000)
			  : (preferences.mail_background * 1000),
			  (XtTimerCallbackProc) background_fetch,
			  mailbox);
      return;
    }
  }
  return;
}

#ifdef __STDC__
void view_find(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_find(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Lview *lview;
  Filter *filter;
  char *text;
  parse_errors errors;
  Message_List *new, *curr;
  Message_List *message_list;
  unsigned long count = 0L;
  char errmsg[FILEBUFFLEN];

  text = input_string(mwin->shell,MLGetLocalized(XtNmsgFilterDefinition,
						    MsgFilterDefinition),
		      NULL,EDFILTERHELPFILE);
  if(text == NULL)
    return;
  if(*text == NUL_TERM) {
    fs_give((void **) &text);
    return;
  }

  filter = new_filter();
  filter->name = cpystr("Search");
  errors = lv_parse_filter(filter->name,text,
			   (LEAF **) &filter->search_tree,
			   &filter->text,
			   errmsg);

  if(errors != parse_success) {
    free_filter(filter);
    fs_give((void **) &text);
    mm_log(errmsg,WARN);
    return;
  }

  view_unselect_messages(w,mwin,xp);

  new = do_imap_search(mwin->current->mailbox,mwin->current,
		       filter->search_tree);

  for(message_list = new; message_list; message_list = message_list->next)
    count ++;

  sprintf(errmsg,MLGetLocalized(XtNmsgFoundMessage,MsgFoundMessage),count,
	  (count == 1) 
	  ? MLGetLocalized(XtNmsgMessageSingular,MsgMessageSingular)
	  : MLGetLocalized(XtNmsgMessagePlural,MsgMessagePlural));
  mm_log(errmsg,MLNOTIFY);
  if(count) {
    XtVaSetValues(mwin->list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
    for(curr = mwin->current->message_list; curr; curr = curr->next) {
      for(message_list = new; message_list; message_list = message_list->next){
	if(message_list->message == curr->message) {
	  XmListSelectPos(mwin->list,curr->number,FALSE);
	  curr->selected = TRUE;
	}
      }
    }
    XtVaSetValues(mwin->list, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
  }

  mwin->current->num_selected = count;
  if(count) 
    mwin->current->buttonstate &= ~(BTN_NOSELECTION);
  else
    mwin->current->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  free_message_list(new,TRUE,FALSE);
  free_filter(filter);
  fs_give((void **) &text);
  return;
}


#ifdef __STDC__
void view_read_message(Widget w, MainWindow *mwin, XmListCallbackStruct *xp)
#else
void view_read_message(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XmListCallbackStruct *xp;
#endif
{

  Message_List *message_list;

  mwin->current->num_selected = 0L;
  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    message_list->selected = FALSE;
    if(message_list->number == xp->item_position) {
      message_list->selected = TRUE;
      mwin->current->num_selected = 1L;
      mwin->current->buttonstate &= ~(BTN_NOSELECTION);
      view_check_buttons();
      view_read_selected(w,mwin,xp);
      break;
    }
  }
  return;
}

#ifdef __STDC__
void view_read_selected(Widget w, MainWindow *mwin, XmListCallbackStruct *xp)
#else
void view_read_selected(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XmListCallbackStruct *xp;
#endif
{
  int slider_value;
  if(mwin->current->num_selected) {
    XtVaGetValues(mwin->slider, XmNvalue, &slider_value, NULL);
    if(slider_value == 0)
      slider_value = 1;
    push_cursor(WATCH_CURSOR);
    read_messagelist(mwin, mwin->current,
		     mwin->current->message_list, slider_value, FALSE);
    if(slider_value != 100)
      XtVaSetValues(mwin->slider, XmNvalue, 100, NULL);
    pop_cursor();
  }
  return;
}


#ifdef __STDC__
void view_read_selected_newwin(Widget w, MainWindow *mwin, 
			       XmListCallbackStruct *xp)
#else
void view_read_selected_newwin(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XmListCallbackStruct *xp;
#endif
{
  int slider_value;
  if(mwin->current->num_selected) {
    XtVaGetValues(mwin->slider, XmNvalue, &slider_value, NULL);
    if(slider_value == 0)
      slider_value = 1;
    push_cursor(WATCH_CURSOR);
    read_messagelist(mwin, mwin->current,
		     mwin->current->message_list, slider_value, TRUE);
    if(slider_value != 100)
      XtVaSetValues(mwin->slider, XmNvalue, 100, NULL);
    pop_cursor();
  }
  return;
}




#ifdef __STDC__
void view_next(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_next(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  if(mwin->current->next)
    view_context_switch(mwin,mwin->current,mwin->current->next);
  return;
}

#ifdef __STDC__
void view_prev(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_prev(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  if(mwin->current->prev)
    view_context_switch(mwin,mwin->current,mwin->current->prev);
  return;
}

#ifdef __STDC__
void view_expunge_messages(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_expunge_messages(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  push_cursor(WATCH_CURSOR);
  mail_expunge(mwin->current->mailstream);
  view_after_expunge(mwin);
  pop_cursor();
  return;
}

#ifdef __STDC__
char *rep_to_sortstr(Representation_Type representation)
#else
char *rep_to_sortstr(representation)
     Representation_Type representation;
#endif
{
  return(Representation[representation].localized);
}


#ifdef __STDC__
Representation_Type sortstr_to_rep(char * sortstr)
#else
Representation_Type sortstr_to_rep(sortstr)
     char *sortstr;
#endif
{
  int i = 0;
  if(sortstr != NULL) {
    for(i = 0; Representation[i].name != NULL; i ++) 
      if((strncasecmp(sortstr,Representation[i].localized,
		      strlen(Representation[i].localized))) == STRMATCH)
	return(i);
  }
  return(i);
}

#ifdef __STDC__
void view_sort_reverse(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_sort_reverse(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *old, *new;

  if((mwin->current == NULL)
     || (mwin->current->filter == NULL)
     || (mwin->current->message_list == NULL))
    return;
  
  push_cursor(WATCH_CURSOR);

  mwin->current->representation = REP_DESCENDING;
  old = mwin->current->message_list;

  new = sort_message_list(mwin->current->message_list, 
			  mwin->current->representation);

  update_lview_message_list(mwin,mwin->current,old, new, FALSE);

  pop_cursor();
  return;
}

#ifdef __STDC__
void view_sort_size(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_sort_size(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *old, *new;

  if((mwin->current == NULL)
     || (mwin->current->filter == NULL)
     || (mwin->current->message_list == NULL))
    return;
  
  push_cursor(WATCH_CURSOR);

  mwin->current->representation = REP_SORT_SIZE;
  old = mwin->current->message_list;

  new = sort_message_list(mwin->current->message_list, 
			  mwin->current->representation);

  update_lview_message_list(mwin,mwin->current,old, new, FALSE);

  pop_cursor();
  return;
}


#ifdef __STDC__
void view_sort_normal(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_sort_normal(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *old, *new;
  
  if((mwin->current == NULL)
     || (mwin->current->filter == NULL)
     || (mwin->current->message_list == NULL))
    return;

  push_cursor(WATCH_CURSOR);

  mwin->current->representation = REP_ASCENDING;
  old = mwin->current->message_list;

  new = sort_message_list(mwin->current->message_list, 
			  mwin->current->representation);

  update_lview_message_list(mwin,mwin->current,old,new, FALSE);

  pop_cursor();
  return;
}

#ifdef __STDC__
void view_sort_subject(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_sort_subject(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *old, *new;
  
  if((mwin->current == NULL)
     || (mwin->current->filter == NULL)
     || (mwin->current->message_list == NULL))
    return;

  push_cursor(WATCH_CURSOR);

  mwin->current->representation = REP_SORT_SUBJECT;
  old = mwin->current->message_list;

  new = sort_message_list(mwin->current->message_list, 
			  mwin->current->representation);

  update_lview_message_list(mwin,mwin->current,old,new, FALSE);

  pop_cursor();
  return;
}

#ifdef __STDC__
void view_sort_sender(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_sort_sender(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *old, *new;
  
  if((mwin->current == NULL)
     || (mwin->current->filter == NULL)
     || (mwin->current->message_list == NULL))
    return;

  push_cursor(WATCH_CURSOR);

  mwin->current->representation = REP_SORT_SENDER;
  old = mwin->current->message_list;

  new = sort_message_list(mwin->current->message_list, 
			  mwin->current->representation);

  update_lview_message_list(mwin,mwin->current,old,new,FALSE);

  pop_cursor();
  return;
}


#ifdef __STDC__
void view_select_messages(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_select_messages(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;
  unsigned long selected = 0L;

  view_unselect_messages(w,mwin,xp);

  push_cursor(WATCH_CURSOR);

  XtVaSetValues(mwin->list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    XmListSelectPos(mwin->list,message_list->number,FALSE);
    message_list->selected = TRUE;
    selected ++;
  }
  XtVaSetValues(mwin->list, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);

  mwin->current->num_selected = selected;
  if(selected > 0) 
    mwin->current->buttonstate &= ~(BTN_NOSELECTION);
  else
    mwin->current->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  pop_cursor();
  return;
}

#ifdef __STDC__
void view_unselect_messages(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_unselect_messages(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;

  push_cursor(WATCH_CURSOR);

  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    XmListDeselectPos(mwin->list,message_list->number);
    message_list->selected = FALSE;
  }

  mwin->current->num_selected = 0L;
  mwin->current->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  pop_cursor();
  return;
}

#ifdef __STDC__
void view_select_new_messages(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_select_new_messages(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;
  MESSAGECACHE *elt;
  unsigned long selected = 0L;

  view_unselect_messages(w,mwin,xp);

  push_cursor(WATCH_CURSOR);

  XtVaSetValues(mwin->list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    if((message_list->message == NULL) 
       || (message_list->message->fetched == FALSE)
       || (message_list->message->longcache == NULL))
      continue;
    elt = &(message_list->message->longcache->elt);
    if((elt) && (elt->recent) && (!elt->seen)) {
      XmListSelectPos(mwin->list,message_list->number,FALSE);
      message_list->selected = TRUE;
      selected ++;
    }
  }
  XtVaSetValues(mwin->list, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
  mwin->current->num_selected = selected;
  if(selected) 
    mwin->current->buttonstate &= ~(BTN_NOSELECTION);
  else
    mwin->current->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  pop_cursor();
  return;
}


#ifdef __STDC__
void view_select_unseen_messages(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_select_unseen_messages(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;
  MESSAGECACHE *elt;
  unsigned long selected = 0L;

  view_unselect_messages(w,mwin,xp);

  push_cursor(WATCH_CURSOR);

  XtVaSetValues(mwin->list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);

  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    if((message_list->message == NULL) 
       || (message_list->message->fetched == FALSE)
       || (message_list->message->longcache == NULL))
      continue;
    elt = &(message_list->message->longcache->elt);
    if((elt) && (!elt->seen)) {
      XmListSelectPos(mwin->list,message_list->number,FALSE);
      message_list->selected = TRUE;
      selected ++;
    }
  }

  XtVaSetValues(mwin->list, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);

  mwin->current->num_selected = selected;
  if(selected) 
    mwin->current->buttonstate &= ~(BTN_NOSELECTION);
  else
    mwin->current->buttonstate |= BTN_NOSELECTION;

  view_check_buttons();
  pop_cursor();
  return;
}

#ifdef __STDC__
void view_copy_dispatch(Widget w, MainWindow *mwin, Boolean move)
#else
void view_copy_dispatch(w,mwin,move)
     Widget w;
     MainWindow *mwin;
     Boolean move;
#endif
{
  extern STRINGDRIVER mail_string;
  STRING bs;
  char *ptr;
  Boolean changed = FALSE;
  char *sequence = NULL;
  char *mailbox_name = NULL;
  Message_List *message_list;
  Message_List *new_message_list = NULL;
  int result = NIL;

  if(mwin->current->scripting && mwin->current->script_arg)
    mailbox_name = fix_netmailboxpath(mwin->current->script_arg,&changed);

  if(mailbox_name == NULL)
    mailbox_name = 
      get_mailbox_name(mwin->shell, 
		       (mwin->current->mailbox->host)
		       ? mwin->current->mailbox->host
		       : EMPTYSTR, &changed, &move);

  if(mailbox_name == NULL) {
    session->active = NULL;
    return;
  }

  if(*mailbox_name == NUL_TERM) {
    fs_give((void **) &mailbox_name);
    session->active = NULL;
    return;
  }

  push_cursor(WATCH_CURSOR);

  if(changed == FALSE) {
    sequence = generate_sequence(mwin->current);

    if(sequence && *sequence && *mailbox_name) 
      result = mail_copy(mwin->current->mailstream, sequence, mailbox_name);
    if(result == T) {
      if(move) {
	mm_log(MLGetLocalized(XtNmsgMoveSuccess,MsgMoveSuccess), NIL);
	view_setflag(w,mwin, DELETED_FLAG);
	for(message_list = mwin->current->message_list; message_list; 
	    message_list = message_list->next) {
	  if(message_list->selected == TRUE) 
	    update_view_line(mwin->current->mailbox, message_list->message);
	}
      }
      else
	mm_log(MLGetLocalized(XtNmsgCopySuccess,MsgCopySuccess), NIL);
    }
    else {
      if(move)
	mm_log(MLGetLocalized(XtNmsgMoveFail,MsgMoveFail), WARN);
      else
	mm_log(MLGetLocalized(XtNmsgCopyFail,MsgCopyFail), WARN);
    }
  }
  else {
    free_message_list(mwin->current->mailbox->found, TRUE, FALSE);
    mwin->current->mailbox->found = NULL;
    for(message_list = mwin->current->message_list; message_list;
	message_list = message_list->next) {
      if(message_list->selected == TRUE)
	mm_searched(message_list->message->mailstream,
		    message_list->message->msgno);
    }
    new_message_list = sort_message_list(mwin->current->mailbox->found, 
				     REP_ASCENDING);
    mwin->current->mailbox->found = NULL;
    result = SYSCALL_SUCCESS;
    if(new_message_list) {
      for(message_list = new_message_list; 
	  message_list; message_list = message_list->next) {
	if(message_list->message) {
	  result = copy_message_to_mailbox(message_list->message->mailstream,
					   message_list->message->msgno,
					   mailbox_name);
	  if(result != SYSCALL_SUCCESS)
	    break;
	}
      }
      if(result == SYSCALL_SUCCESS) {
	if(move) {
	  view_setflag(w,mwin, DELETED_FLAG);
	  for(message_list = new_message_list; 
	      message_list; message_list = message_list->next) 
	    update_view_line(mwin->current->mailbox, message_list->message);
	}
	mm_log((move) ? MLGetLocalized(XtNmsgMoveSuccess,MsgMoveSuccess) 
	       : MLGetLocalized(XtNmsgCopySuccess,MsgCopySuccess), NIL);
      }
      else
	mm_log((move) ? MLGetLocalized(XtNmsgMoveFail,MsgMoveFail) 
	       : MLGetLocalized(XtNmsgCopyFail,MsgCopyFail), WARN );
      free_message_list(new_message_list, TRUE, FALSE);
    }
  }
  
  if(sequence)
    fs_give((void **) &sequence);
  fs_give((void **) &mailbox_name);
  session->active = NULL;
  pop_cursor();
  return;
}




#ifdef __STDC__
void view_copy(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_copy(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_copy_dispatch(w, mwin, FALSE);
  return;
}


#ifdef __STDC__
void view_move(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_move(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_copy_dispatch(w, mwin, TRUE);
  return;
}

/*
 * To avoid excessive scrolling and flicker when we change context,
 * we grab a new list widget, load it up, and then change the old
 * one out from under the user. There's still a screen flash, but
 * that's life...
 */

#ifdef __STDC__
void view_context_switch(MainWindow *mwin, Lview *old, Lview *new)
#else
void view_context_switch(mwin,old,new)
     MainWindow *mwin;
     Lview *old;
     Lview *new;
#endif
{
  Dimension width, height;
  XtTranslations translations;
  char *new_title = NULL;
  Widget list, oldlist;
  unsigned long total = 0L;
  unsigned long highlighted = 0L;
  Message_List *message_list;
  char *act = NULL;

  XtVaGetValues(mwin->shell,XmNwidth,&width,XmNheight,&height,NULL);

  mwin->current = new;

  list = new_list_widget(mwin);

  if((old != NULL) && (old->filter != NULL)) {
    act = XmTextGetString(mwin->action);
    if(old->filter->action)
      fs_give((void **) &old->filter->action);
    old->filter->action = act;
  }

  if(new != NULL) {
    if(new->title) {
      new_title = (char *) fs_get(strlen(new->title) + 64);
      sprintf(new_title,"%s (%s)", new->title,
	      Representation[new->representation].localized);
      XtVaSetValues(mwin->shell,XmNtitle,new_title,NULL);
      fs_give((void **) &new_title);
    }
 

    if((new->filter) && (new->filter->action))
      XmTextSetString(mwin->action,new->filter->action);
    else
      XmTextSetString(mwin->action,preferences.default_action);

    XtVaSetValues(list,XmNselectionPolicy,XmMULTIPLE_SELECT,NULL);
    for(message_list = new->message_list;
	message_list; message_list = message_list->next) {
      if(message_list->message) {
	XmListAddItemUnselected(list,message_list->message->viewline,0);
	message_list->number = (++total);
	if(message_list->selected) {
	  XmListSelectPos(list,message_list->number, FALSE);
	  highlighted ++;
	}
      }
    }
    XtVaSetValues(list,XmNselectionPolicy,XmEXTENDED_SELECT,NULL);

    new->num_selected = highlighted;
    if(new->representation == REP_ASCENDING 
       || new->representation == REP_SORT_SIZE)
      XmListSetBottomPos(list, new->count);
    else
      XmListSetBottomPos(list,1);

    if(highlighted != 0L)
      new->buttonstate &= ~(BTN_NOSELECTION);
    else
      new->buttonstate |= BTN_NOSELECTION;
    view_check_buttons();
  }
  else {                 /* No more open mailboxes. */ 
    XtVaSetValues(mwin->shell,XmNtitle,PROGRAM,NULL);
    XmTextSetString(mwin->action,EMPTYSTR);
    view_check_buttons();
    mwin->lview = NULL;
  }

  translations = 
    XtParseTranslationTable(GLOBAL_lview_pop_translations);
  XtOverrideTranslations(list,translations);

  oldlist = mwin->list;
  XtUnmanageChild(oldlist);
  mwin->list = list;
  XtManageChild(list);
  XtVaSetValues(mwin->shell,XmNwidth,width,XmNheight,height,NULL);
  XtDestroyWidget(oldlist);
  return;
}

/* 
 * Called when we are going to close a mailbox, and we need to 
 * destroy the current lview. Since any other views of this mailbox
 * are going away, we can't use them. This finds a view unrelated
 * to this mailbox or else NULL. It's safe to context switch to
 * another mailbox.
 */

#ifdef __STDC__
Lview *find_lview_another_mailbox(MainWindow *mwin,Mailbox *mailbox)
#else
Lview *find_lview_another_mailbox(mwin,mailbox)
     MainWindow *mwin;
     Mailbox *mailbox;
#endif
{
  Lview *lview = NULL;
  
  for(lview = mwin->lview; lview; lview = lview->prev) {
    if(lview->mailbox != mailbox)
      return(lview);
  }
  return(NULL);
}


#ifdef __STDC__
void mwin_close_mailbox(Mailbox *mailbox)
#else
void mwin_close_mailbox(mailbox)
     Mailbox *mailbox;
#endif
{
  Lview *lview;
  Boolean found = FALSE;
  MainWindow *mwin = find_main_window(mailbox);

  if(! mwin)
    return;

  do {
    found = FALSE;
    for(lview = mwin->lview; lview; lview = lview->prev)
      if(lview->mailstream == mailbox->mailstream) {
	found = TRUE;
	view_unlink_destroy_lview(mwin,lview,TRUE);
	break;
      }
  } while(found == TRUE);

  if(mwin->lview == NULL) { 
    if(! mwin->is_main) {
      XtPopdown(mwin->shell);
      mwin->destroyed = TRUE;
      if(mwin->listwin->is_realized)
	XtPopdown(mwin->listwin->shell);
    }
  }
  return;
}

#ifdef __STDC__
void view_unlink_destroy_lview(MainWindow *mwin,Lview *lview,Boolean closing)
#else
void view_unlink_destroy_lview(mwin,lview,closing)
     MainWindow *mwin;
     Lview *lview;
     Boolean closing;
#endif
{
  Lview *curr = NULL;
  Lview *next_view = NULL;

  /* First reparent any orphans we might make */

  if((closing == FALSE) && (lview->filter != NULL) 
     && (lview->filter->filter_type != FILTER_TYPE_ALL)) {
    for(curr = mwin->lview; curr; curr = curr->prev) {
      if((curr->mailstream == lview->mailstream) && (curr->parent == lview))
	  curr->parent = lview->parent;
    }
    for(curr = mwin->lview; curr; curr = curr->prev) {
      if((curr->parent != NULL) && (curr->level != (curr->parent->level + 1)))
	curr->level --;
    }
  }

  read_lview_detach(lview);

  /* Extract this sucker from mwin->lview */

  if(mwin->lview == lview)
    mwin->lview = lview->prev;

  if(lview->prev) {
    lview->prev->next = lview->next;
    if(lview->next)
      lview->prev->buttonstate &= ~(BTN_NONEXT);
    else
      lview->prev->buttonstate |= BTN_NONEXT;
  }

  if(lview->next) {
    lview->next->prev = lview->prev;
    if(lview->prev)
      lview->next->buttonstate &= ~(BTN_NOPREV);
    else
      lview->next->buttonstate |= BTN_NOPREV;
  }

  if(lview->filter && lview->filter->filter_type == FILTER_TYPE_ALL) 
    free_message_list(lview->message_list,TRUE,TRUE);
  else
    free_message_list(lview->message_list,TRUE,FALSE);

  free_filter(lview->filter);

  if(lview == mwin->current) {
    if(closing)
      next_view = find_lview_another_mailbox(mwin,lview->mailbox);
    else {
      if(lview->prev)
	next_view = lview->prev;
      else
	if(lview->next)
	  next_view = lview->next;
    }
    view_context_switch(mwin, NULL, next_view);
  }
  stuff_lview_list(mwin,TRUE,closing);
  free_lview(lview);
  lview = NULL;
  return;
}

/* Returns the "ALL" lview (main mailbox) for a particular mailstream */

#ifdef __STDC__
Lview *get_all_lview(MAILSTREAM *mailstream)
#else
Lview *get_all_lview(mailstream)
     MAILSTREAM *mailstream;
#endif
{
  MainWindow *mwin;
  Lview *lview;

  for(mwin = session->mwin; mwin; mwin = mwin->next) 
    for(lview = mwin->lview; lview ; lview = lview->prev) 
      if((lview->mailstream == mailstream) && (lview->filter) 
	 && (lview->filter->filter_type == FILTER_TYPE_ALL))
	return(lview);

  return(NULL);
}

/* Returns the "UNFILTERED" lview for a particular mailstream */

#ifdef __STDC__
Lview *get_bucket_lview(MAILSTREAM *mailstream)
#else
Lview *get_bucket_lview(mailstream)
     MAILSTREAM *mailstream;
#endif
{
  MainWindow *mwin;
  Lview *lview;

  for(mwin = session->mwin; mwin; mwin = mwin->next)
    for(lview = mwin->lview; lview ; lview = lview->prev) 
      if((lview->mailstream == mailstream) && (lview->filter) 
	 && (lview->filter->filter_type == FILTER_TYPE_BUCKET))
	return(lview);

  return(NULL);
}

#ifdef __STDC__
void load_default_filters(MainWindow *mwin,Lview *lview,Filter_Map *filter_map)
#else
void load_default_filters(mwin,lview,filter_map)
     MainWindow *mwin;
     Lview *lview;
     Filter_Map *filter_map;
#endif
{
  FILE *fp;
  Boolean found = FALSE;
  char buf[FILEBUFFLEN];
  char pname[FILEBUFFLEN];
  char *name;
  int level;
  char *parent_name;
  char *ptr;
  Lview *our_lview;
  Lview *parent_lview;
  Lview *pptr;
  Filter *our_filter;
  Filter *curr_filter;
  parse_errors errors;
  char *temp_txt;
  char errmsg[FILEBUFFLEN];

  mm_log(MLGetLocalized(XtNmsgLoadingFilters,MsgLoadingFilters), NIL);

  if((fp = fopen(filter_map->filename,"r")) == NULL) {
    return;
  }

  /* 
   * parse the filter map file. 
   * filter_name [SP] level [SP] parent_name ( [SP] parent_name ) [LF]
   */

  while(fgets(buf,sizeof(buf),fp)) {
    buf[strlen(buf) - 1] = NUL_TERM;
    name = buf;
    ptr = strchr(buf,SPACECHAR);
    if(ptr == NULL)
      continue;
    *ptr = NUL_TERM;
    ptr ++;
    level = atoi(ptr);
    if(level == 0)
      continue;
    parent_name = strchr(ptr,SPACECHAR);
    if(parent_name == NULL)
      continue;
    parent_name ++;

    for(curr_filter = session->filters; 
	curr_filter; curr_filter = curr_filter->next) {

      /* find requested filter */

      if(strcmp(curr_filter->name,name) == STRMATCH)
	break;
    }

    if(curr_filter == NULL)
      continue;
    
    /* find the (active) parent */

    for(parent_lview = mwin->lview; 
	parent_lview; parent_lview = parent_lview->prev) {

      if(parent_lview->mailstream != lview->mailstream)
	continue;

      if(parent_lview->level != (level - 1))
	 continue;

      if(parent_lview->filter == NULL)
	continue;

      *pname = NUL_TERM;

      for(pptr = parent_lview, found = FALSE; pptr; pptr = pptr->parent) {
	if(pptr->filter && pptr->filter->name) {
	  if(found)
	    strcat(pname,SPACESTR);
	  found = TRUE;
	  strcat(pname,pptr->filter->name);
	}
	if(pptr->filter && pptr->filter->filter_type == FILTER_TYPE_ALL)
	    break;
      }
      if((*pname != NUL_TERM) && ((strcmp(pname,parent_name)) == STRMATCH))
	break;
    }

    /* no parent found */
    if(parent_lview == NULL)
      continue;

    /* we have a parent -- now see if the filter parses */

    our_filter = new_filter();
    
    our_filter->filter_type = FILTER_TYPE_USER;
    our_filter->representation = curr_filter->representation;
    our_filter->name = cpystr(curr_filter->name);
    temp_txt = cpystr(curr_filter->text);
    our_filter->action = cpystr(curr_filter->action);

    errors = lv_parse_filter(our_filter->name,temp_txt,
			     (LEAF **) &our_filter->search_tree,
			     &our_filter->text,
			     errmsg);

    fs_give((void **) &temp_txt);

    if(errors != parse_success) {
      free_filter(our_filter);
      mm_log(errmsg,WARN);
      continue;
    }
    our_lview = new_lview();
    our_lview->filter = our_filter;
    our_lview->parent = parent_lview;
    our_lview->level = level;
    create_lview(mwin,our_lview,TRUE);
  }
  fclose(fp);

  update_logical_views(lview->mailbox,FALSE);
  view_check_buttons();
  return;
}

#ifdef __STDC__
void attach_session_filters(Lview *lview)
#else
void attach_session_filters(lview)
     Lview *lview;
#endif
{

#if 0
  Lview *our_lview;
  Lview *parent_lview;
  Filter *our_filter;
  Filter *curr_filter;
  parse_errors errors;
  char *temp_txt;
  char errmsg[FILEBUFFLEN];


  if(session->session_filters == NULL)
    return;

  mm_log(MLGetLocalized(XtNmsgAttachingFilters,MsgAttachingFilters),NIL);


  for(curr_filter = session->session_filters; 
      curr_filter; curr_filter = curr_filter->next) {
    
    our_filter = new_filter();
    
    our_filter->filter_type = FILTER_TYPE_ONESHOT;
    our_filter->name = cpystr(curr_filter->name);
    temp_txt = cpystr(curr_filter->text);
    our_filter->action = cpystr(curr_filter->action);

    errors = lv_parse_filter(our_filter->name,temp_txt,
			     (LEAF **) &our_filter->search_tree,
			     &our_filter->text,
			     errmsg);

    fs_give((void **) &temp_txt);
    our_lview = new_lview();
    our_lview->filter = our_filter;
    our_lview->parent = lview;
    our_lview->level = lview->level + 1;
    create_lview(our_lview,TRUE);
  }
  update_logical_views(lview->mailbox,TRUE);

  view_context_switch(mwin, mwin->current, our_lview);
#endif
  return;
}




#ifdef __STDC__
void create_lview(MainWindow *mwin,Lview *lview, Boolean batch)
#else
void create_lview(mwin,lview, batch)
     MainWindow *mwin;
     Lview *lview;
     Boolean batch;
#endif
{
  char buffer[FILEBUFFLEN];
  char *fixedname;
  Mailbox *mailbox;
  Lview *parent;
  Lview *bucket;
  Filter *filter;
  
  push_cursor(WATCH_CURSOR);
  
  if(! mwin->current) {
    pop_cursor();
    return;
  }

  mailbox = mwin->current->mailbox;

  lview->mailstream   = mailbox->mailstream;
  lview->mailbox      = mailbox;

  if(((bucket = get_bucket_lview(mailbox->mailstream)) == NULL)
     && lview->filter && lview->filter->filter_type == FILTER_TYPE_USER) {
    
    /* create the "UNFILTERED" view */
    
    filter = new_filter();
    filter->name = cpystr(MLGetLocalized(XtNstrBucket,StrBucket));
    filter->action = cpystr(preferences.default_action);
    filter->filter_type = FILTER_TYPE_BUCKET;
    
    bucket = new_lview();
    bucket->parent = get_all_lview(mailbox->mailstream);
    bucket->level = 1;
    bucket->mailstream = mailbox->mailstream;
    bucket->mailbox = mailbox;
    bucket->filter = filter;

    if(mailbox->type == MAILBOX_TYPE_NEWS)
      filter->representation = sortstr_to_rep(preferences.news_sort);
    else
      filter->representation = sortstr_to_rep(preferences.mail_sort);

    bucket->representation = filter->representation;

    filter->mailboxname = cpystr(mailbox->imapname);
    fixedname = unfix_mailboxpath(mailbox->mailboxname);
    
    sprintf(buffer,"[%d]%s%s%s[%s]",
	    mwin->serialno,
	    (mailbox->host) ? mailbox->host : EMPTYSTR,
	    (mailbox->host) ? ":" : EMPTYSTR,
	    fixedname, 
	    filter->name);
    
    fs_give((void **) &fixedname);
    
    bucket->title = cpystr(buffer);
    
    if(mailbox->type == MAILBOX_TYPE_NEWS)
      bucket->buttonstate |= BTN_ISNEWS;
    else
      bucket->buttonstate |= BTN_ISMAIL;
    
    for(parent = mwin->lview; parent; parent = parent->prev) {
      if(parent == bucket->parent)
	break;
    }
    
    if(parent) {
      bucket->next = parent;
      bucket->prev = parent->prev;
      parent->prev = bucket;
      parent->buttonstate &= ~(BTN_NOPREV);
      if(bucket->prev) {
	bucket->buttonstate &= ~(BTN_NOPREV);
	bucket->prev->next = bucket;
	bucket->prev->buttonstate &= ~(BTN_NONEXT);
      }
      else
	bucket->buttonstate |= BTN_NOPREV;
      
      bucket->buttonstate &= ~(BTN_NONEXT);
    }
    else
      mm_log(MLGetLocalized(XtNmsgNoParentView,MsgNoParentView), ERROR);
  }
  
  lview->filter->mailboxname = cpystr(mailbox->imapname);
  
  fixedname = unfix_mailboxpath(mailbox->mailboxname);
  
  sprintf(buffer,"[%d]%s%s%s[%s]",
	  mwin->serialno,
	  (mailbox->host) ? mailbox->host : EMPTYSTR,
	  (mailbox->host && *mailbox->host) ? ":" : EMPTYSTR,
	  fixedname, 
	  lview->filter->name);
  
  fs_give((void **) &fixedname);
  
  lview->title = cpystr(buffer);
  lview->representation = lview->filter->representation;

  /* 
   *  Link into our structure beneath the parent. We should always
   *  have a parent. session->->lview is ordered in reverse.
   *  (Everything is "prev" to the root node).
   */
  
  if(mailbox->type == MAILBOX_TYPE_NEWS)
    lview->buttonstate |= BTN_ISNEWS;
  else
    lview->buttonstate |= BTN_ISMAIL;

  for(parent = mwin->lview; parent; parent = parent->prev) {
    if(parent == lview->parent)
      break;
  }
  
  if(parent) {
    lview->next = parent;
    lview->prev = parent->prev;
    parent->prev = lview;
    parent->buttonstate &= ~(BTN_NOPREV);
    if(lview->prev) {
      lview->buttonstate &= ~(BTN_NOPREV);
      lview->prev->next = lview;
      lview->prev->buttonstate &= ~(BTN_NONEXT);
    }
    else
      lview->buttonstate |= BTN_NOPREV;

    lview->buttonstate &= ~(BTN_NONEXT);
  }

  else 
    mm_log(MLGetLocalized(XtNmsgNoParentView,MsgNoParentView), ERROR);

  /* 
   * If we're running in "batch" mode, there could be several filters
   * to attach. The caller has promised to update the logical views
   * when it's done attaching everything it needs. This avoids lengthy
   * (steadily increasing) delays as the number of filters is growing;
   * and it also avoids excessive flicker. Set batch to false if there's
   * only one filter to attach. Everything will be updated and sorted for 
   * you when this function returns.
   */

  if(batch == FALSE) {
    update_logical_views(mailbox,TRUE);
    view_context_switch(mwin, mwin->current, lview);
  }
  pop_cursor();
  return;
}

/* 
 * Creates a main mailbox ("ALL" lview) and loads 
 * its message info.
 */

#ifdef __STDC__
void create_all_lview(MainWindow *mwin,Mailbox *mailbox)
#else
void create_all_lview(mwin,mailbox)
     MainWindow *mwin;
     Mailbox *mailbox;
#endif
{
  Lview  *lview;
  Filter *filter;
  Filter_Map *filter_map;
  Message_List *old, *new;
  char buffer[FILEBUFFLEN];
  char *fixedname;

  if(! mwin)
    return;

  push_cursor(WATCH_CURSOR);

  /* 
   * "ALL" is just another logical view except it has a few
   * special properties. It ALWAYS holds a message structure
   * for each message in the mailbox. So whenever mailbox changes 
   * occur, we update this view to guarantee that it stays consistent
   * with the server's representation. We then derive other logical
   * views from it. We also don't put any special meaning on the name 
   * "ALL". We set the filter_type to FILTER_TYPE_ALL instead, and
   * use a combination of the filter_type and either the mailstream or 
   * mailbox to absolutely identify it.
   */

  lview = new_lview();
  lview->mailstream   = mailbox->mailstream;
  lview->mailbox      = mailbox;
  lview->count        = mailbox->nmsgs;

  filter = new_filter();
  filter->mailboxname = cpystr(mailbox->imapname);
  filter->name = cpystr(MLGetLocalized(XtNstrAll, StrAll));
  filter->filter_type = FILTER_TYPE_ALL;

  if(mailbox->type == MAILBOX_TYPE_NEWS)
    filter->representation = sortstr_to_rep(preferences.news_sort);
  else
    filter->representation = sortstr_to_rep(preferences.mail_sort);

  lview->filter = filter;
  lview->representation = filter->representation;

  fixedname = unfix_mailboxpath(mailbox->mailboxname);

  sprintf(buffer,"[%d]%s%s%s[%s]",
	  mwin->serialno,
	  (mailbox->host) ? mailbox->host : EMPTYSTR,
	  (mailbox->host && *mailbox->host) ? ":" : EMPTYSTR,
	  fixedname,
	  filter->name);

  fs_give((void **) &fixedname);

  lview->title = cpystr(buffer);
  lview->next = NULL;
  lview->buttonstate |= BTN_NONEXT;

  if(mwin->lview) {
    lview->prev = mwin->lview;
    lview->buttonstate &= ~(BTN_NOPREV);
    mwin->lview->next = lview;
    mwin->lview->buttonstate &= ~(BTN_NONEXT);
  }
  else { 
    lview->buttonstate |= BTN_NOPREV;
    lview->prev = NULL;
  }

  if(mailbox->type == MAILBOX_TYPE_NEWS)
    lview->buttonstate |= BTN_ISNEWS;
  else
    lview->buttonstate |= BTN_ISMAIL;

  lview->buttonstate |= BTN_ISALL;

  mwin->lview = lview;

  if(mailbox->ispop) {
    check_mailbox(mailbox,TRUE);
    lview->count = mailbox->nmsgs;
  }

  fast_fetch_message_info(mailbox,lview);

  lview->has_new = has_new_messages(lview,TRUE);

  old = lview->message_list;

  new = sort_message_list(lview->message_list,lview->representation);

  update_lview_message_list(mwin,lview,old,new,FALSE);


  view_context_switch(mwin, mwin->current, lview);

  /* 
   * If there are any saved active filters for this mailbox, load them 
   * at this time.
   */

  if((filter_map = get_filter_map(lview)) != NULL)
    load_default_filters(mwin,lview,filter_map);
  attach_session_filters(lview);
  stuff_lview_list(mwin,TRUE, FALSE);

  pop_cursor();
  return;
}

/*
 * Called from the c-client when a (single) message is expunged.
 * We go through this in distinct steps. First, remove the message
 * from the "ALL" view (main mailbox), but !!DON'T!! yet free the message.
 * We need to check it against all our views for this mailbox. Decrement 
 * any higher message numbers in the message structures we encounter in
 * this view by one. Once that's accomplished, we go through all our 
 * logical views for this mailbox and unlink any message_list structures 
 * which contain the expunged message. We can free these message_list 
 * structures at this point, but we still don't free the message itself.
 * The final act is to destroy the message structure itself once all of 
 * its references have been eliminated.
 * Since expunge is always initiated by us, when we perform the act,
 * we follow up by calling the view_after_expunge() procedure to update
 * the visuals. This takes care of all the highlighting stuff, and
 * avoids excessive flicker if we are expunging several messages.
 */

#ifdef __STDC__
void view_expunge(MAILSTREAM *mailstream,unsigned long msgno)
#else
void view_expunge(mailstream,msgno)
     MAILSTREAM *mailstream;
     unsigned long msgno;
#endif
{
  MainWindow *mwin;
  Boolean found_it = FALSE;
  Lview *lview;

  Message_List *message_list;
  Message_List *dead_message_list = NULL;
  unsigned long x = 1L;

  lview = get_all_lview(mailstream);

  if(! lview)
    return;

  found_it = FALSE;

  for(message_list = lview->message_list; 
      message_list; message_list = message_list->next) {

    if(message_list->message == NULL)
      continue;

    if(message_list->message->msgno == msgno) {
      found_it = TRUE;
      dead_message_list = message_list;

      if(lview->count)
	lview->count --;

      if((message_list->selected == TRUE) && (lview->num_selected > 0L)) {
	lview->num_selected --;
	if(lview->num_selected == 0L)
	  lview->buttonstate |= BTN_NOSELECTION;
      }

      if(message_list->next)
	message_list->next->prev = message_list->prev;
      if(message_list->prev) 
	message_list->prev->next = message_list->next;
      else
	lview->message_list = message_list->next;
    }  

    if(message_list->message->msgno > msgno) 
      message_list->message->msgno --;
  }

  /* 
   * Yes, we could have done this while we were running through but it 
   * complicates the logic. I'll probably work that in at some point, 
   * because this could cause delays on a huge mailbox.
   */

  for(message_list = lview->message_list; 
      message_list; message_list = message_list->next) {
    message_list->number = x;
    x ++;
  }

  lview->has_new = has_new_messages(lview,FALSE);
  
  if(found_it == FALSE)       /* shouldn't happen */
    return;

  /* Update any other lviews attached to this stream. */

  for(mwin = session->mwin; mwin; mwin = mwin->next) {
    for(lview = mwin->lview; lview; lview = lview->prev) {
      if(lview->mailstream != mailstream)
	continue;
      if(lview->filter && lview->filter->filter_type == FILTER_TYPE_ALL)
	continue;  /* already got this guy */
      do {
	found_it = FALSE;
	for(message_list = lview->message_list; 
	    message_list; message_list = message_list->next) {
	  
	  if(message_list->message == NULL)
	    continue;
	  
	  if(message_list->message == dead_message_list->message) {
	    found_it = TRUE;
	    
	    if(lview->count)
	      lview->count --;
	    if((message_list->selected == TRUE) 
	       && (lview->num_selected > 0L)) {
	      lview->num_selected --;
	      if(lview->num_selected == 0L)
		lview->buttonstate |= BTN_NOSELECTION;
	    }
	  
	    if(message_list->next)
	      message_list->next->prev = message_list->prev;
	    if(message_list->prev) 
	      message_list->prev->next = message_list->next;
	    else
	      lview->message_list = message_list->next;
	  
	    free_message_list(message_list,FALSE,FALSE);
	    break;
	  }
	}
      } while (found_it == TRUE);

      lview->has_new = has_new_messages(lview,FALSE);
      
      x = 1L;
      for(message_list = lview->message_list; 
	  message_list; message_list = message_list->next) {
	message_list->number = x;
	x ++;
      }
    }
  }

  free_message_list(dead_message_list,FALSE,TRUE);
  return;
}

#ifdef __STDC__
void view_after_expunge(MainWindow *mwin)
#else
void view_after_expunge(mwin)
     MainWindow *mwin;
#endif
{

  read_after_expunge();
  view_context_switch(mwin,mwin->current,mwin->current);
  stuff_lview_list(mwin,TRUE,FALSE);
  return;
}

#ifdef __STDC__
void view_close_mailbox(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_close_mailbox(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Mailbox *mailbox, *next;

  for(mailbox = session->mailboxes; mailbox ; mailbox = next) {

    next = mailbox->next;
    if((mwin->current) && (mailbox->mailstream != mwin->current->mailstream))
      continue;
    close_mailbox(mailbox);
    break;

  }
  return;
}


#ifdef __STDC__
void view_no_update(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_no_update(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  if(mwin && mwin->current && mwin->current->mailbox)
    mwin->current->mailbox->no_update = TRUE;
  return;
}




#ifdef __STDC__
void view_lview_window(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_window(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Arg args[ARGLISTSIZE];
  char buffer[FILEBUFFLEN];
  int n = 0;
  XtTranslations translations;
  Widget form, menubar, dummy;

  if(mwin->listwin->is_realized == TRUE) {
    de_iconify(mwin->listwin->shell);
    return;
  }

  sprintf(buffer,"[%d] %s",mwin->serialno,MLGetLocalized(XtNstrLogicalViews,
							 StrLogicalViews));



  XtSetArg(args[n], XmNtitle, buffer);                  n ++;
  XtSetArg (args[n], XmNdeleteResponse, XmDO_NOTHING);  n ++; 
  XtSetArg(args[n], XmNx, -1000);                       n ++;
  XtSetArg(args[n], XmNy, -1000);                       n ++;

  mwin->listwin->shell = XtCreatePopupShell("lview",
					    topLevelShellWidgetClass,
					    mwin->shell,
					    args, n);
  n = 0;
  AddDestroyCallback (mwin->listwin->shell);
  setup_editres(mwin->listwin->shell);

  if(list_icon != (Pixmap) None)
    XtVaSetValues(mwin->listwin->shell,
		  XmNiconPixmap,list_icon,
		  NULL);

  form = XmCreateForm(mwin->listwin->shell, "form", args, n); n = 0;
  XtSetArg(args[n], XmNtopAttachment,   XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++;

  menubar = XmCreateMenuBar(form,"menubar", args, n);     n = 0;
  XtManageChild(menubar);
  create_buttons(NULL, menubar,view_lview_menu, 
		 XtNumber(view_lview_menu), 
		 BTN_ON, (XtPointer) mwin, ROOTMENULEVEL);

  /* 
   * An invisible text field. This is used only to set the window 
   * width, since the list widget living under the form can change 
   * size otherwise, depending only on its contents.
   */

  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++;
  dummy = XmCreateTextField(form,"dummy", args, n); n = 0;
  XtManageChild(dummy);

  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++;
  XtSetArg(args[n], XmNtopWidget, menubar); n ++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++;
  
  XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC);        n ++;
  XtSetArg(args[n], XmNlistSizePolicy,         XmCONSTANT);      n ++;
  XtSetArg(args[n], XmNselectionPolicy,        XmSINGLE_SELECT); n ++;
  mwin->listwin->list = 
    XmCreateScrolledList(form,"list",args,n); 
  n = 0;

  XtAddCallback(mwin->listwin->list,
		XmNsingleSelectionCallback, 
		(XtCallbackProc) view_lview_select, mwin);
  XtAddCallback(mwin->listwin->list,
		XmNdefaultActionCallback, 
		(XtCallbackProc) view_lview_accept, mwin);
  translations = 
    XtParseTranslationTable(GLOBAL_lview_pop_translations);
  XtOverrideTranslations(mwin->listwin->list,translations);

  XtAddCallback(mwin->listwin->shell,
		XmNpopdownCallback, 
		(XtCallbackProc) view_lview_destroy, mwin);

  stuff_lview_list(mwin,FALSE,FALSE);

  XtManageChild(mwin->listwin->list); 
  XtManageChild(form);
  XtManageChild(mwin->listwin->shell);
  position_popup_widget(mwin->listwin->shell, FALSE);
  XtPopup(mwin->listwin->shell, XtGrabNone);
  mwin->listwin->is_realized = TRUE;
  return;
}

#ifdef __STDC__
void view_lview_save(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_save(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  FILE *fp;
  Lview *lview;
  Lview *current;
  Filter_Map *filter_map;
  char log[MAXPATHLEN + 128];
  Lview *pptr;

  push_cursor(WATCH_CURSOR);

  for(current = mwin->lview; current; current = current->prev) {
    if((current->filter == NULL) 
       || (current->filter->filter_type != FILTER_TYPE_ALL))
      continue;
    filter_map = get_filter_map(current);
    if(filter_map == NULL)
      filter_map = generate_filter_map(current);
    

    if((fp = fopen(filter_map->filename,"w")) == NULL) {
      sprintf(log,MLGetLocalized(XtNmsgCannotWriteFile,MsgCannotWriteFile),
	      filter_map->filename);
      mm_log(log,WARN);
      pop_cursor();
      continue;
    }
    (void) chmod(filter_map->filename,S_IRWXU);

    for(lview = current->prev; lview; lview = lview->prev) {
      if(lview->filter == NULL)
	continue;
      if(lview->filter->filter_type == FILTER_TYPE_ALL) {
	fclose(fp);
	break;
      }
      if(lview->filter->filter_type != FILTER_TYPE_USER)
	continue;
      if((lview->parent == NULL) 
	 || (lview->parent->filter == NULL)
	 || (lview->parent->filter->name == NULL))
	continue;

      fprintf(fp,"%s %d",
	      lview->filter->name,
	      lview->level);
      pptr = lview->parent;

      for(pptr = lview->parent; pptr; pptr = pptr->parent) {
	fprintf(fp," %s",(pptr->filter && pptr->filter->name) ? 
		  pptr->filter->name : SPACESTR);
	if(pptr->filter 
	   && pptr->filter->filter_type == FILTER_TYPE_ALL)
	  break;
      }
      fprintf(fp,"\n");
    }
    fclose(fp);
  }
  pop_cursor();
  return;
}


#ifdef __STDC__
void view_lview_select(Widget w, MainWindow *mwin, XmListCallbackStruct *xp)
#else
void view_lview_select(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XmListCallbackStruct *xp;
#endif
{
  Lview *lview;

  for(lview = mwin->lview; lview; lview = lview->prev) {
    if(lview->number == xp->item_position) {
      if(lview->selected == FALSE) {
	lview->selected = TRUE;
	view_context_switch(mwin,mwin->current,lview);
	de_iconify(mwin->shell);
      }
      else
	XmListSelectPos(mwin->listwin->list,xp->item_position, FALSE);
    }
    else
      lview->selected = FALSE;
  }
  return;
}

#ifdef __STDC__
void view_lview_accept(Widget w, MainWindow *mwin, XmListCallbackStruct *xp)
#else
void view_lview_accept(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XmListCallbackStruct *xp;
#endif
{
  return;
}

#ifdef __STDC__
void view_lview_hide(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_hide(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  if(mwin->listwin->hide_empty == TRUE)
    mwin->listwin->hide_empty = FALSE;
  else
    mwin->listwin->hide_empty = TRUE;
  stuff_lview_list(mwin,TRUE,FALSE);
  return;
}


#ifdef __STDC__
void view_lview_detach(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_detach(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Lview *lview;
  Filter *filter, *session_filter;
  Boolean found = FALSE;

  for(lview = mwin->lview; lview; lview = lview->prev) {
    if(lview->selected == TRUE) {

      /* 
       * Annoying, but we have to make the lview we want
       * to detach the ``current'' lview. We might get some update 
       * flicker as it gets switched in, and then immediately
       * switched out again. That's life. "view_close_mailbox()"
       * and "view_unlink_destroy_lview()" operate on the assumption
       * that the current lview is the target.
       */

      view_context_switch(mwin,mwin->current,lview);
      break;
    }
  }

  if(! lview)
    return;

  if(lview->filter && lview->filter->filter_type == FILTER_TYPE_ALL)
    view_close_mailbox(w,mwin,xp);
  else  
    view_unlink_destroy_lview(mwin,lview,FALSE);
  return;
}

#ifdef __STDC__
void view_lview_dismiss(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_dismiss(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Lview *lview;

/*  for(lview = mwin->lview; lview; lview = lview->prev)
 *   if(lview->selected == TRUE)
 *     lview->selected = FALSE;
 */

  XtRemoveCallback(mwin->listwin->shell,
		   XmNpopdownCallback, 
		   (XtCallbackProc) view_lview_destroy, mwin);
  XtPopdown(mwin->listwin->shell);
  XtDestroyWidget(mwin->listwin->shell);
  mwin->listwin->is_realized = FALSE;
  return;
}

#ifdef __STDC__
void view_lview_destroy(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_destroy(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Lview *lview;

  for(lview = mwin->lview; lview; lview = lview->prev)
    if(lview->selected == TRUE)
      lview->selected = FALSE;
  XtDestroyWidget(mwin->listwin->shell);
  mwin->listwin->is_realized = FALSE;
  return;
}

#ifdef __STDC__
void view_lview_help(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_lview_help(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  help(mwin->listwin->shell, VIEWLISTHELPFILE);
  return;
}


/* 
 * Stuff the view selector window. Update is set to false to stuff
 * it the first time around. Thereafter, it is always called with
 * update set to true, in order to refresh the contents. The closing
 * flag means to not check the new message status, since the message cache
 * structures might be bogus at that point. It will just go on prior
 * knowledge which should still be accurate.
 */


#ifdef __STDC__
void stuff_lview_list(MainWindow *mwin, Boolean update, Boolean closing)
#else
void stuff_lview_list(mwin, update, closing)
     MainWindow *mwin;
     Boolean update;
     Boolean closing;
#endif
{
  Lview *lview;
  int n = 1;
  int level = 0;
  char buffer[FILEBUFFLEN];
  int spaces;
  char *fixed_name = NULL;
  int font_type = 0;
  XmString xstr;


  if(session == NULL || mwin == NULL) 
    return;

  if(update) {
    if(mwin->listwin->is_realized == FALSE)
      return;
    XmListDeselectAllItems(mwin->listwin->list);
    XmListDeleteAllItems(mwin->listwin->list);
  }

  for(lview = mwin->lview; lview; lview = lview->prev) {

    if(closing != TRUE)
      lview->has_new = has_new_messages(lview,FALSE);

    font_type = 0;

    /* Always show "ALL", even if empty */

    if((lview->filter != NULL) 
       && (lview->filter->filter_type != FILTER_TYPE_ALL)) {
      if((mwin->listwin->hide_empty == TRUE) && (lview->count == 0L)) {
	lview->number = 0;
	lview->selected = FALSE;
	continue;
      }
    }

    lview->number = n;
    lview->selected = FALSE;
    buffer[0] = NUL_TERM;

    sprintf(buffer,"%6lu ",lview->count);

    if((lview->filter) 
       && (lview->filter->filter_type == FILTER_TYPE_ONESHOT))
      font_type += 2;

    if(lview->has_new)
      font_type += 1;

    for(level = 0; level < lview->level; level ++)
      strcat(buffer,">");
    if(lview->level)
      strcat(buffer," ");
    strcat(buffer,lview->filter->name);
    for(spaces = strlen(buffer); spaces < 30; spaces ++)
      strcat(buffer,SPACESTR);

    if((lview->mailbox != NULL) 
       && (lview->mailbox->host != NULL) 
       && (*lview->mailbox->host != NUL_TERM)) {
      strcat(buffer,lview->mailbox->host);
      strcat(buffer,":");
    }

    if(lview->mailbox && lview->mailbox->mailboxname)
      fixed_name = unfix_mailboxpath(lview->mailbox->mailboxname);
    if(fixed_name) {
      strcat(buffer,fixed_name);
      fs_give((void **) &fixed_name);
    }
    else
      strcat(buffer,EMPTYSTR);

      
    switch(font_type) {
    case 1:
      xstr = XmStringCreate(buffer, "BOLD");
      break;
    case 2:
      xstr = XmStringCreate(buffer, "ITALIC");
      break;
    case 3:
      xstr = XmStringCreate(buffer, "BOLD_ITALIC");
      break;
    case 0:
    default:
      xstr = XmStringCreate(buffer, "NORMAL");
      break;
    }

    XmListAddItemUnselected(mwin->listwin->list,xstr,0);
    if(lview == mwin->current) {
      XmListSelectPos(mwin->listwin->list,n,FALSE);
      lview->selected = TRUE;
    }
    XmStringFree(xstr);
    n ++;
  }
  return;
}

#ifdef __STDC__
char *view_fetch(Message *message,Header_Mode header_mode)
#else
char *view_fetch(message,header_mode)
     Message *message;
     Header_Mode header_mode;
#endif
{
  char *mail_header = NULL;
  char *header = NULL;
  char *mail_text = NULL;
  char *everything;

  if((message == NULL) 
     || (message->mailstream == NULL)
     || (message->msgno == 0L))
    return(NULL);

  mail_header = cpystr(mail_fetchheader(message->mailstream,message->msgno));
  stripcr(mail_header);
  if(mail_header[strlen(mail_header) - 1] == LFCHAR)
    mail_header[strlen(mail_header) - 1] = NUL_TERM;

  if(header_mode == HEADER_FULL) 
    header = cpystr(mail_header);

  if(header_mode == HEADER_PART)
    header = get_short_header(mail_header);

  if(header == NULL)
    header = cpystr(EMPTYSTR);

  mail_text = cpystr(mail_fetchtext(message->mailstream,message->msgno));
  stripcr(mail_text);

  everything = (char *) fs_get(strlen(header) + strlen(mail_text) + 8);
  strcpy(everything,header);
  if(*header != NUL_TERM)
    strcat(everything,LFSTR);
  strcat(everything,mail_text);

  fs_give((void **) &mail_header);
  fs_give((void **) &header);
  fs_give((void **) &mail_text);

  return(everything);
}

#ifdef __STDC__
void view_printfull(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_printfull(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_print_dispatch(w,mwin,HEADER_FULL);
  return;
}

#ifdef __STDC__
void view_printpart(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_printpart(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_print_dispatch(w,mwin,HEADER_PART);
  return;
}

#ifdef __STDC__
void view_printnone(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_printnone(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_print_dispatch(w,mwin,HEADER_NONE);
  return;
}

#ifdef __STDC__
void view_print_dispatch(Widget w,MainWindow *mwin,Header_Mode header_mode)
#else
void view_print_dispatch(w,mwin,header_mode)
     Widget w;
     MainWindow *mwin;
     Header_Mode header_mode;
#endif
{
  Message_List *message_list;
  char *contents;
  int errors = 0;

  if(*preferences.print_command == NUL_TERM) {
    mm_log(MLGetLocalized(XtNmsgNoPrintCommand,MsgNoPrintCommand), WARN);
    return;
  }

  push_cursor(WATCH_CURSOR);

  for(message_list = mwin->current->message_list; message_list;
      message_list = message_list->next ) {

    if(message_list->selected) {
      contents = view_fetch(message_list->message,
			    (mwin->current->scripting)
			    ? mwin->current->script_header : header_mode);
      if(! contents)
	continue;
      
      if(write_to_pipe(preferences.print_command,
		    NULL, contents, strlen(contents)))
	errors ++;
      fs_give((void **) &contents);
    }
  }
  if(errors)
    mm_log(MLGetLocalized(XtNmsgPrintFail,MsgPrintFail), WARN);
  else
    mm_log(MLGetLocalized(XtNmsgPrintSuccess,MsgPrintSuccess), NIL);

  pop_cursor();
  return;
}

#ifdef __STDC__
void view_execfull(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_execfull(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_exec_dispatch(w,mwin,HEADER_FULL);
  return;
}

#ifdef __STDC__
void view_execpart(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_execpart(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_exec_dispatch(w,mwin,HEADER_PART);
  return;
}

#ifdef __STDC__
void view_execnone(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_execnone(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_exec_dispatch(w,mwin,HEADER_NONE);
  return;
}


#ifdef __STDC__
void view_exec_dispatch(Widget w, MainWindow *mwin, Header_Mode header_mode)
#else
void view_exec_dispatch(w,mwin,header_mode)
     Widget w;
     MainWindow *mwin;
     Header_Mode header_mode;
#endif
{
  Message_List *message_list;
  char *contents;
  int errors = 0;
  char *command = NULL;

  if(mwin->current->scripting && mwin->current->script_arg)
    command = cpystr(mwin->current->script_arg);

  if(command == NULL)
    command = input_string(mwin->shell,MLGetLocalized(XtNmsgInputCommand,
							 MsgInputCommand),
			   session->last_command, SHELLCOMMANDHELPFILE);
  if(command == NULL)
    return;

  if(*command == NUL_TERM) {
    fs_give((void **) &command);
    return;
  }

  push_cursor(WATCH_CURSOR);

  for(message_list = mwin->current->message_list; message_list;
      message_list = message_list->next ) {

    if(message_list->selected) {
      contents = view_fetch(message_list->message,
			    (mwin->current->scripting)
			    ? mwin->current->script_header : header_mode);
      if(! contents)
	continue;

      
      if(write_to_pipe(command,
		    NULL, contents, strlen(contents)))
	errors ++;
      fs_give((void **) &contents);
    }
  }
  if(errors)
    mm_log(MLGetLocalized(XtNmsgPipeFail,MsgPipeFail), WARN);

  if(session->last_command != NULL)
    fs_give((void **) &session->last_command);
  session->last_command = command;

  pop_cursor();
  return;
}


#ifdef __STDC__
void view_savefull(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_savefull(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_save_dispatch(w,mwin,HEADER_FULL);
  return;
}

#ifdef __STDC__
void view_savepart(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_savepart(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_save_dispatch(w,mwin,HEADER_PART);
  return;
}

#ifdef __STDC__
void view_savenone(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_savenone(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_save_dispatch(w,mwin,HEADER_NONE);
  return;
}

#ifdef __STDC__
void view_save_dispatch(Widget w, MainWindow *mwin, Header_Mode header_mode)
#else
void view_save_dispatch(w,mwin,header_mode)
     Widget w;
     MainWindow *mwin;
     Header_Mode header_mode;
#endif
{
  FILE *fp;
  char *filename = NULL;
  Message_List *message_list;
  char *contents;
  int errors = 0;
  Boolean append_it;

  if((mwin->current) 
     && mwin->current->scripting && mwin->current->script_arg) {
    filename = cpystr(mwin->current->script_arg);
    append_it = TRUE;
  }

  if(! filename)
    filename = file_select(mwin->shell,NULL, NULL, NULL, TRUE, &append_it);
  if(filename == NULL)
    return;

  push_cursor(WATCH_CURSOR);

  if((fp = fopen(filename,(append_it == TRUE) ? "a" : "w")) != NULL) {
    (void) chmod(filename,S_IRWXU);

    for(message_list = mwin->current->message_list; message_list;
	message_list = message_list->next ) {

      if(message_list->selected) {
	contents = view_fetch(message_list->message,
			      (mwin->current->scripting) 
			      ? mwin->current->script_header : header_mode);
	if(! contents)
	  continue;
	if((fwrite(contents,strlen(contents),1,fp)) != 1)
	  errors ++;
	fs_give((void **) &contents);
      }
      if(errors)
	break;
    }
    if((fclose(fp)) != SYSCALL_SUCCESS)
      errors ++;
  }

  if(errors)
    mm_log(MLGetLocalized(XtNmsgSaveFail,MsgSaveFail), WARN);
  else
    mm_log(MLGetLocalized(XtNmsgSaveSuccess,MsgSaveSuccess), NIL);

  pop_cursor();
  return;
}


#ifdef __STDC__
void view_set_deleted(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_set_deleted(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_setflag(w,mwin,DELETED_FLAG);
  return;
}

#ifdef __STDC__
void view_set_seen(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_set_seen(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_setflag(w,mwin,SEEN_FLAG);
  return;
}

#ifdef __STDC__
void view_set_flagged(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_set_flagged(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_setflag(w,mwin,FLAGGED_FLAG);
  return;
}

#ifdef __STDC__
void view_set_answered(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_set_answered(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_setflag(w,mwin,ANSWERED_FLAG);
  return;
}

#ifdef __STDC__
void view_clear_deleted(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_clear_deleted(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_clearflag(w,mwin,DELETED_FLAG);
  return;
}

#ifdef __STDC__
void view_clear_seen(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_clear_seen(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_clearflag(w,mwin,SEEN_FLAG);
  return;
}

#ifdef __STDC__
void view_clear_flagged(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_clear_flagged(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_clearflag(w,mwin,FLAGGED_FLAG);
  return;
}

#ifdef __STDC__
void view_clear_answered(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_clear_answered(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  view_clearflag(w,mwin,ANSWERED_FLAG);
  return;
}

#ifdef __STDC__
void update_flags(Lview *lview)
#else
void update_flags(lview)
     Lview *lview;
#endif
{
  Message_List *message_list;

  if((lview == NULL) || (lview->num_selected == 0L))
    return;

  for(message_list = lview->message_list; message_list;
      message_list = message_list->next) {
    if((message_list->selected == TRUE)
       && (message_list->message != NULL))
      mm_flags(message_list->message->mailstream, 
	       message_list->message->msgno);
  }
  return;
}

#ifdef __STDC__
void view_setflag(Widget w, MainWindow *mwin, char *flag)
#else
void view_setflag(w,mwin,flag)
     Widget w;
     MainWindow *mwin;
     char *flag;
#endif
{
  char *sequence = NULL;

  sequence = generate_sequence(mwin->current);
  if(sequence == NULL)
    return;

  push_cursor(WATCH_CURSOR);

  mail_setflag(mwin->current->mailstream,sequence,flag);
  update_flags(mwin->current);

  fs_give((void **) &sequence);
  pop_cursor();
  return;
}

#ifdef __STDC__
void view_clearflag(Widget w, MainWindow *mwin, char *flag)
#else
void view_clearflag(w,mwin,flag)
     Widget w;
     MainWindow *mwin;
     char *flag;
#endif
{
  char *sequence = NULL;

  sequence = generate_sequence(mwin->current);
  if(sequence == NULL)
    return;
  push_cursor(WATCH_CURSOR);

  mail_clearflag(mwin->current->mailstream,sequence,flag);
  update_flags(mwin->current);

  fs_give((void **) &sequence);
  pop_cursor();
  return;
}

#ifdef __STDC__
void view_filter(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_filter(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  create_edfilter_window(mwin);
  return;
}

#ifdef __STDC__
void view_reply_sender(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_reply_sender(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;
  
  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    if(message_list->selected)
      compose_message(COMPOSE_REPLY, FALSE,NULL, message_list->message, NULL);
  }
  return;
}

#ifdef __STDC__
void view_reply_all(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_reply_all(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;
  
  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    if(message_list->selected)
      compose_message(COMPOSE_REPLYALL, FALSE, NULL, 
		      message_list->message, NULL);
  }
  return;
}

#ifdef __STDC__
void view_remail(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_remail(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  Message_List *message_list;
  
  for(message_list = mwin->current->message_list;
      message_list; message_list = message_list->next) {
    if(message_list->selected)
      compose_message(COMPOSE_REMAIL, FALSE, NULL, 
		      message_list->message, NULL);
  }
  return;
}

#ifdef __STDC__
void view_forward(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_forward(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  (void) compose_message(COMPOSE_FORWARD, FALSE, mwin->current, NULL, NULL);
  return;
}

#ifdef __STDC__
void view_forward_attach(Widget w, MainWindow *mwin, XtPointer xp)
#else
void view_forward_attach(w,mwin,xp)
     Widget w;
     MainWindow *mwin;
     XtPointer xp;
#endif
{
  (void) compose_message(COMPOSE_FORWARDATTACH, FALSE, mwin->current, 
			 NULL, NULL);
  return;
}

#ifdef __STDC__
int message_list_compare(Message_List *list1,Message_List *list2)
#else
int message_list_compare(list1,list2)
     Message_List *list1;
     Message_List *list2;
#endif
{
  Message_List *ptr1 = list1;
  Message_List *ptr2 = list2;

  for( ; ; ) {
    if((ptr1 != NULL) && (ptr2 != NULL)) {
      if(ptr1->message != ptr2->message)
	return(LISTNOMATCH);
      else {
	ptr1 = ptr1->next;
	ptr2 = ptr2->next;
	continue;
      }
    }
    else {
      if(ptr1 != ptr2)
	return(LISTNOMATCH);
      else
	return(LISTMATCH);
    }
  }
  /* NOTREACHED */
}

#ifdef __STDC__
void update_current_view(Mailbox *mailbox)
#else
void update_current_view(mailbox)
     Mailbox *mailbox;
#endif
{
  MainWindow *mwin = find_main_window(mailbox);
  Lview *lview;
  Message_List *message_list;
  char ** strtab;
  int n;

  if((mwin == NULL) || (mwin->current == NULL) || (mwin->current->count == 0L))
    return;

  lview = mwin->current;

  /* 
   * If we're pruning the view, zero it and start over. Then
   * set prune_happened so we don't ever do it again. 
   */
    
  XmListDeselectAllItems(mwin->list);

  if(lview->pruned && (lview->prune_happened == FALSE))
    XmListDeleteAllItems(mwin->list);

  strtab = (char **) fs_get(lview->count * (sizeof(char *)));
  for(message_list = lview->message_list, n = 0 ; message_list;
      message_list = message_list->next) {
    strtab[n] = (char *) message_list->message->viewline;
    n ++;
  }

  lview->count = n;

  if(lview->pruned && (lview->prune_happened == FALSE)) {
    XmListAddItems(mwin->list,
		   (XmStringTable) strtab,
		   lview->count, 1);
    if(lview->representation == REP_ASCENDING
       || lview->representation == REP_SORT_SIZE)
      XmListSetBottomPos(mwin->list, lview->count);
    else
      XmListSetBottomPos(mwin->list,1);
  }

  else
    XmListReplaceItemsPos(mwin->list,
			  (XmStringTable) strtab, 
			  lview->count,1);


  if(lview->pruned)
    lview->prune_happened = TRUE;

  free(strtab);

  XtVaSetValues(mwin->list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
  for(message_list = lview->message_list; message_list;
      message_list = message_list->next) {
    if(message_list->selected == TRUE) 
      XmListSelectPos(mwin->list, message_list->number, FALSE);
  }
  XtVaSetValues(mwin->list, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);

  stuff_lview_list(mwin,TRUE,FALSE);

  return;
}

#ifdef __STDC__
void update_bucket(Mailbox *mailbox)
#else
void update_bucket(mailbox)
     Mailbox *mailbox;
#endif
{
  Lview *all;
  Lview *bucket;
  Message_List *message_list;
  Message_List *old;
  Message_List *new;
  MainWindow *mwin = find_main_window(mailbox);

  all = get_all_lview(mailbox->mailstream);
  bucket = get_bucket_lview(mailbox->mailstream);

  if(mwin == NULL || all == NULL || bucket == NULL)
    return;

  free_message_list(mailbox->found,TRUE,FALSE);
  mailbox->found = NULL;

  for(message_list = all->message_list; message_list; 
      message_list = message_list->next) {
    if((message_list->message) && (message_list->message->in_view == FALSE))
      mm_searched(mailbox->mailstream,message_list->message->msgno);
  }

  new = mailbox->found;
  mailbox->found = NULL;
  old = bucket->message_list;

  if((message_list_compare(old,new)) == LISTMATCH)
    free_message_list(new,TRUE,FALSE);
  else {
    update_lview_message_list(mwin,bucket,old,new,FALSE);
    free_message_list(old,TRUE,FALSE);
  }
  return;
}

#ifdef __STDC__
void set_found_flags(Message_List *message_list)
#else
void set_found_flags(message_list)
     Message_List *message_list;
#endif
{
  Message_List *curr;

  for(curr = message_list; curr; curr = curr->next)
    if(curr->message)
      curr->message->in_view = TRUE;
  return;
}

/* 
 *  The initialize flag says to update all views.
 *  We set it to true when creating a filter, and after an expunge
 *  to catch the one-shot filters.
 */

#ifdef __STDC__
void update_logical_views(Mailbox *mailbox,Boolean initialize)
#else
void update_logical_views(mailbox,initialize)
     Mailbox *mailbox;
     Boolean initialize;
#endif
{
  Lview *lview;
  Message_List *old;
  Message_List *new;
  MainWindow *mwin = find_main_window(mailbox);

  if(! mwin)
    return;

  for(lview = mwin->lview; lview ; lview = lview->prev) {
    if(lview->filter == NULL || lview->mailbox != mailbox)
      continue;

    if(lview->filter->filter_type == FILTER_TYPE_ALL) {
      lview->has_new = has_new_messages(lview,TRUE); /* and wipe "in_view" */
      continue;
    }

    if(lview->filter->filter_type == FILTER_TYPE_BUCKET)
      continue;

    if((lview->filter->filter_type == FILTER_TYPE_ONESHOT)
       && (initialize == FALSE))
      continue;

    new = do_imap_search(lview->mailbox,lview->parent,
			 lview->filter->search_tree);

    new = sort_message_list(new, lview->representation);

    old = lview->message_list;

    if((message_list_compare(old,new)) == LISTMATCH) {
      free_message_list(new,TRUE,FALSE);
      set_found_flags(old);
      continue;
    }
    
    update_lview_message_list(mwin,lview,old,new, TRUE);
    free_message_list(old,TRUE,FALSE);
  }

  update_bucket(mailbox);

  stuff_lview_list(mwin,TRUE,FALSE);
  mailbox->update_needed  = 0;
  return;
}

#ifdef __STDC__
int sort_ascending(const void *list1,const void *list2)
#else
int sort_ascending(list1,list2) 
     const void *list1;
     const void *list2;
#endif
{
  Message_List ** l1 = (Message_List **) list1;
  Message_List ** l2 = (Message_List **) list2;

  return((*l1)->message->msgno - (*l2)->message->msgno);
}


#ifdef __STDC__
int sort_size(const void *list1,const void *list2)
#else
int sort_size(list1,list2) 
     const void *list1;
     const void *list2;
#endif
{
  Message_List ** l1 = (Message_List **) list1;
  Message_List ** l2 = (Message_List **) list2;
  MESSAGECACHE *elt1;
  MESSAGECACHE *elt2;
  unsigned long size1 = 0L;
  unsigned long size2 = 0L;

  elt1 = ((*l1)->message 
	  && (*l1)->message->longcache)
    ? &((*l1)->message->longcache->elt)
    : NULL;

  elt2 = ((*l2)->message 
	  && (*l2)->message->longcache)
    ? &((*l2)->message->longcache->elt)
    : NULL;

  size1 = (elt1) ? elt1->rfc822_size : 0L;
  size2 = (elt2) ? elt2->rfc822_size : 0L;

  return(size1 - size2);
}



#ifdef __STDC__
int sort_reverse(const void *list1, const void *list2)
#else
int sort_reverse(list1,list2) 
     const void *list1;
     const void *list2;
#endif
{
  Message_List ** l1 = (Message_List **) list1;
  Message_List ** l2 = (Message_List **) list2;

  return((*l2)->message->msgno - (*l1)->message->msgno);
}

#ifdef __STDC__
int sort_subject(const void *list1,const void *list2)
#else
int sort_subject(list1,list2) 
     const void *list1;
     const void *list2;
#endif
{
  Message_List ** l1 = (Message_List **) list1;
  Message_List ** l2 = (Message_List **) list2;

  int result;
  unsigned char *ptr1;
  unsigned char *ptr2;


  if((*l1)->message->subject == NULL) 
    ptr1 = (unsigned char *) EMPTYSTR;
  else
    ptr1 = (unsigned char *) (*l1)->message->subject;

  if((*l2)->message->subject == NULL)
    ptr2 = (unsigned char *) EMPTYSTR;
  else
    ptr2 = (unsigned char *) (*l2)->message->subject;

  do {
    if((result = strncasecmp((char *) ptr1,"re",2)) == STRMATCH) {
      if((*(ptr1 + 2) == ':') || (*(ptr1 + 2) == '[')) { 
	while(*ptr1 && ! isspace(*ptr1))
	  ptr1 ++;
	while(*ptr1 && isspace(*ptr1))
	  ptr1 ++;
      }
      else
	result = ~STRMATCH;
    }
  } while(result == STRMATCH);

  do {
    if((result = strncasecmp((char *) ptr2,"re",2)) == STRMATCH) {
      if((*(ptr2 + 2) == ':') || (*(ptr2 + 2) == '[')) { 
	while(*ptr2 && ! isspace(*ptr2))
	  ptr2 ++;
	while(*ptr2 && isspace(*ptr2))
	  ptr2 ++;
      }
      else
	result = ~STRMATCH;
    }
  } while(result == STRMATCH);

  while((*ptr1) && (isspace(*ptr1)))
    ptr1 ++;

  while((*ptr2) && (isspace(*ptr2)))
    ptr2 ++;

  result = strcasecmp((char *) ptr1,(char *) ptr2);
  if(result == STRMATCH)
    return((*l1)->message->msgno - (*l2)->message->msgno);
  else
    return(result);
}


#ifdef __STDC__
int sort_sender(const void *list1, const void *list2)
#else
int sort_sender(list1,list2) 
     const void *list1;
     const void *list2;
#endif
{
  Message_List ** l1 = (Message_List **) list1;
  Message_List ** l2 = (Message_List **) list2;

  int result;
  char * ptr1, *ptr2;

  if((*l1)->message->sender)
    ptr1 = (*l1)->message->sender;
  else
    ptr1 = EMPTYSTR;

  if((*l2)->message->sender)
    ptr2 = (*l2)->message->sender;
  else
    ptr2 = EMPTYSTR;

  result = strcasecmp(ptr1, ptr2);
  if(result == STRMATCH)
    return((*l1)->message->msgno - (*l2)->message->msgno);
  else
    return(result);

}	       



#ifdef __STDC__
void thread_preprocess(Message_List *message_list, Message *message)
#else
void thread_preprocess(message_list,message)
  Message_List *message_list;
  Message *message;
#endif
{
  Message_List *tmp;
  Boolean found = FALSE;
  
  if((message != NULL) && (message->references != NULL) 
     && (*message->references != NUL_TERM)) {

    for(tmp = message_list; tmp; tmp = tmp->next) {
      if((tmp->message != NULL) 
	 && (tmp->message->message_id != NULL)
	 && (*tmp->message->message_id != NUL_TERM)
	 && ((strcmp(tmp->message->message_id,
		     message->references)) == STRMATCH)) {
	message->thread_parent = tmp->message;
	message->thread_child = TRUE;
	found = TRUE;
	break;
      }
    }
  }
  if(found == FALSE) {
    message->thread_parent = NULL;
    message->thread_child  = FALSE;
  }
  return;
}






#ifdef __STDC__
Message_List * sort_message_list(Message_List *message_list, 
				 Representation_Type representation)
#else
Message_List * sort_message_list(message_list, representation)
     Message_List *message_list;
     Representation_Type representation;
#endif
{
  Message_List **sort;
  Message_List *ml_ptr;
  Message_List *result = NULL;
  int n = 0;
  int total = 0;

  if(message_list == NULL)
    return(message_list);



  for(ml_ptr = message_list; ml_ptr; ml_ptr = ml_ptr->next)
    total ++;

  if(total < 2)
    return(message_list);

  sort = (Message_List **) fs_get(total * sizeof(Message_List *));

  for(ml_ptr = message_list; ml_ptr; ml_ptr = ml_ptr->next) {
    if(ml_ptr->message == NULL)
      continue;
    sort[n] = ml_ptr; 
    n ++;
  }

  switch (representation) {
  case REP_DESCENDING:
    qsort((char *) sort,total,sizeof(Message_List **),sort_reverse);
    break;
  case REP_SORT_SUBJECT:
    qsort((char *) sort,total,sizeof(Message_List **),sort_subject);
    break;
  case REP_SORT_SIZE:
    qsort((char *) sort,total,sizeof(Message_List **),sort_size);
    break;
  case REP_SORT_SENDER:
    qsort((char *) sort,total,sizeof(Message_List **),sort_sender);
    break;
  case REP_ASCENDING:
  default:
    qsort((char *) sort,total,sizeof(Message_List **),sort_ascending);
    break;
  }

  for(n = 0; n < total; n ++) {
    ml_ptr = sort[n];
    if(n == 0) {
      result = ml_ptr;
      ml_ptr->next = sort[n + 1];
      ml_ptr->prev = NULL;
      ml_ptr->number = n + 1;
    }
    else {
      ml_ptr->prev = sort[n - 1];
      ml_ptr->number = n + 1;
      if(n == (total - 1))
	ml_ptr->next = NULL;
      else
	ml_ptr->next = sort[n + 1];
    }
  }
  fs_give((void **) &sort);
  return(result);
}

/* 
 *  This function has been overloaded a bit to save running through the list
 * a second time to clear the "in_view" flag.
 */

#ifdef __STDC__
Boolean has_new_messages(Lview *lview,Boolean wipe)
#else
Boolean has_new_messages(lview,wipe)
     Lview *lview;
     Boolean wipe;
#endif
{
  Message_List *message_list;
  MESSAGECACHE *elt;
  Boolean has_new = FALSE;

  for(message_list = lview->message_list; message_list;
      message_list = message_list->next) {

    if(! message_list->message)
      continue;

    if(wipe)
      message_list->message->in_view = FALSE;

    if((message_list->message->fetched == TRUE)
       && (message_list->message->longcache)) {
      elt = &(message_list->message->longcache->elt);
      if((! elt->seen) && elt->recent) {
	has_new = TRUE;
	if(wipe == FALSE)
	  return(has_new);
      }
    }
  }
  return(has_new);
}

#ifdef __STDC__
void update_lview_message_list(MainWindow *mwin, Lview *lview,
			       Message_List *old, Message_List *new,
			       Boolean update_in_view_flag)
#else
void update_lview_message_list(mwin,lview,old,new,update_in_view_flag)
     MainWindow *mwin;
     Lview *lview;
     Message_List *old;
     Message_List *new;
     Boolean update_in_view_flag;
#endif
{
  int n = 0;
  Message_List *list1, *list2;

  for(list1 = old; list1; list1 = list1->next) {
    for(list2 = new; list2; list2 = list2->next) {
      if(list1->message != list2->message)
	continue;
      if(list1->selected == TRUE)
	list2->selected = TRUE;
    }
  }

  for(list2 = new; list2; list2 = list2->next) {
    n ++;
    if((list2->message) && (update_in_view_flag == TRUE))
      list2->message->in_view = TRUE;
  }

  lview->count = n;
  lview->message_list = new;

  lview->has_new = has_new_messages(lview,FALSE);

  if(lview == mwin->current)
    view_context_switch(mwin,mwin->current,lview);
  return;
}


#ifdef __STDC__
void lview_pop(Widget w, XtPointer xp)
#else
void lview_pop(w,xp)
     Widget w;
     XtPointer xp;
#endif
{
  MainWindow *mwin;
  for(mwin = session->mwin; mwin; mwin = mwin->next) {
    if((mwin->list == w) || 
       ((mwin->listwin->list == w) && (mwin->listwin->is_realized == TRUE))) {
      if(mwin->listwin->is_realized == FALSE)
	view_lview_window(w,mwin,NULL);
      else
	view_lview_dismiss(w,mwin,NULL);
      return;
    }
  }
  return;
}















syntax highlighted by Code2HTML, v. 0.9.1