/*
elmo - ELectronic Mail Operator
Copyright (C) 2002, 2003, 2004 rzyjontko
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------
handle mail folder
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#include <string.h>
#include <ctype.h>
#include "ecurses.h"
#include "folder.h"
#include "xmalloc.h"
#include "status.h"
#include "error.h"
#include "ask.h"
#include "cmd.h"
#include "wrapbox.h"
#include "bayes.h"
#include "mybox.h"
#include "hook.h"
#include "exec.h"
#include "eprintf.h"
#include "read.h"
#include "str.h"
#include "select.h"
#include "color.h"
#include "gettext.h"
#include "label.h"
#include "interface.h"
#include "frames.h"
#include "search.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define MIN(a,b) (((a)<(b))?(a):(b))
#define PREAMBLE do { if (wrapbox_mail_count () < 0) return; } while (0)
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
/* Folder window consists of select_t object, and an optional label. */
static elabel_t *label = NULL;
static select_t *folder_select = NULL;
/* This is used in print_line, to avoid frequent alloc/free calls. */
static str_t *line_str = NULL;
/* Colors used in folder window. */
static chtype text_color;
static chtype tree_color;
static chtype tree_bar_color;
static chtype hilight_color;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static void
set_tree_color (WINDOW *win)
{
if (win == folder_select->win){
wattrset (win, tree_color);
}
else {
wattrset (win, tree_bar_color);
}
}
static void
unset_tree_color (WINDOW *win)
{
if (win == folder_select->win){
wattrset (win, text_color);
}
else {
wattrset (win, select_bar_color ());
}
}
static void
set_hilight_color (WINDOW *win)
{
if (win == folder_select->win)
wattrset (win, hilight_color);
else
wattrset (win, select_hilight_color ());
}
static void
unset_hilight_color (WINDOW *win)
{
if (win == folder_select->win)
wattrset (win, text_color);
else
wattrset (win, select_bar_color ());
}
static int
add_tree (WINDOW *window, mail_t *mail, int maxlen)
{
int y, x;
int ret;
if (mail == NULL)
return 0;
if (mail->tree == NULL || mail->tree_len == 0)
return 0;
if (maxlen <= 0)
return 0;
getyx (window, y, x);
set_tree_color (window);
ret = window_addchnstr (window, mail->tree, maxlen);
unset_tree_color (window);
return ret;
}
static int
add_string (WINDOW *win, char *str, int maxlen, search_t *search)
{
int pos = -1;
int len = 1;
if (maxlen <= 0)
return 0;
if (search)
pos = search_perform (search, str);
if (pos != -1){
len = search->pattern->len;
pos -= len - 1;
if (pos < 0)
pos = 0;
window_addnstr (win, str, pos);
set_hilight_color (win);
window_addnstr (win, str + pos, len);
unset_hilight_color (win);
maxlen -= pos + len;
}
return pos + len + window_addnstr (win, str + pos + len, maxlen - 1);
}
static int
add_subject (WINDOW *win, mail_t *mail, int maxlen, search_t *search)
{
if (mail == NULL || mail->subject == NULL)
return 0;
return add_string (win, mail->subject, maxlen, search);
}
static void
print_line (WINDOW *win, int maxlen, int index, search_t *search)
{
mail_t *mail = mail_array_get (wrapbox_marray, index);
if (win == NULL)
return;
if (line_str == NULL)
line_str = str_create ();
if (mail == NULL)
str_clear (line_str);
else
eprintf_mail_str (mybox_format, mail, line_str);
maxlen -= add_string (win, line_str->str, maxlen, search);
if (wrapbox_marray && wrapbox_marray->order == ORDER_THREAD)
maxlen -= add_tree (win, mail, maxlen);
maxlen -= add_subject (win, mail, maxlen, search);
while (maxlen-- > 0)
window_addch (win, ' ');
}
static void
redraw_label (void)
{
if (label == NULL)
return;
if (line_str == NULL)
line_str = str_create ();
eprintf_mail_desc (mybox_format, line_str);
label_set_text (label, line_str->str);
label_redraw (label);
}
static void
copy_tree (chtype *to, chtype *from)
{
while (*from && *from != '>'){
if (*from == ' ' || *from == frames_ch (ACS_VLINE))
*to = *from;
else if (*from == frames_ch (ACS_LLCORNER)
|| *from == frames_ch (ACS_HLINE))
*to = ' ';
else if (*from == frames_ch (ACS_LTEE))
*to = frames_ch (ACS_VLINE);
else
*to = *from;
to++;
from++;
}
}
static void
make_trees (void)
{
int i;
int mail_count;
mail_t *mail;
mail_t *parent;
mail_count = wrapbox_mail_count ();
for (i = 0; i < mail_count; i++){
mail = mail_array_get (wrapbox_marray, i);
parent = mail_array_get (wrapbox_marray, mail->parent);
if (mail->tree)
xfree (mail->tree);
if (parent){
mail->tree_len = parent->tree_len
+ ((parent->tree_len) ? 2 : 4);
mail->tree = xmalloc (mail->tree_len
* sizeof (chtype));
mail->tree[mail->tree_len - 3] = frames_ch (ACS_HLINE);
mail->tree[mail->tree_len - 2] = '>';
mail->tree[mail->tree_len - 1] = 0;
copy_tree (mail->tree, parent->tree);
if (mail->is_last_child)
mail->tree[mail->tree_len - 4] = frames_ch (ACS_LLCORNER);
else
mail->tree[mail->tree_len - 4] = frames_ch (ACS_LTEE);
}
else {
mail->tree_len = 0;
mail->tree = xcalloc (1, sizeof (chtype));
}
}
}
static void
free_resources (void)
{
if (line_str)
str_destroy (line_str);
line_str = NULL;
if (folder_select)
select_close (folder_select);
folder_select = NULL;
if (label)
label_destroy (label);
label = NULL;
}
static void
display_status_info (void)
{
int count;
int read;
int old;
int new;
char *seek = NULL;
if (wrapbox_marray == NULL)
return;
if (ask_for_default ("relative_names", NULL))
seek = strrchr (wrapbox_marray->path, '/');
if (seek == NULL)
seek = wrapbox_marray->path;
else
seek++;
count = wrapbox_marray->count;
read = mail_array_read (wrapbox_marray);
old = mail_array_old (wrapbox_marray);
new = count - read - old;
status_put_mailbox (seek, count, old, new);
}
static int
folder_count (select_t *nothing)
{
return (wrapbox_marray) ? wrapbox_marray->count : 0;
}
/* This file is generated by interface.pl script from interface.desc,
and inc.in. */
static WINDOW *interface_init (void);
#include "folder.inc"
/****************************************************************************
* DISPLAY FUNCTIONS
****************************************************************************/
void
folder_init (void)
{
WINDOW *window;
char *box;
window = interface_init ();
folder_select = select_open (window, 0, print_line, folder_count);
window_set_functions (window, folder_refresh, folder_redraw,
folder_set_focus, folder_unset_focus);
window_show (window);
box = mybox_start ();
if (box){
mybox_switching_to (box);
folder_read_box (box);
xfree (box);
}
}
void
folder_redraw (void)
{
select_redraw (folder_select);
redraw_label ();
display_status_info ();
}
void
folder_refresh (void)
{
select_show (folder_select);
if (label)
label_show (label);
}
void
folder_set_focus (void)
{
if (label){
label_set_focus (label);
}
folder_redraw ();
}
void
folder_unset_focus (void)
{
if (label){
label_unset_focus (label);
redraw_label ();
}
}
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
mail_t *
folder_mail_selected (void)
{
int mail_count = wrapbox_mail_count ();
int index;
mail_t *mail = NULL;
index = folder_select->bar_pos;
if (mail_count == -1 || index < 0 || index >= mail_count)
return NULL;
mail = mail_array_get (wrapbox_marray, index);
return mail;
}
void
folder_free_resources (void)
{
folder_at_leave ();
free_resources ();
}
int
folder_read_box (char *name)
{
int index;
if (wrapbox_read_box (name)){
error_ (0, "%s is not a valid mailbox", name);
return 1;
}
display_status_info ();
mail_array_sort_date (wrapbox_marray);
index = mail_array_first_unread_index (wrapbox_marray);
if (index == -1)
index = wrapbox_mail_count () - 1;
select_goto (folder_select, index);
folder_spam_check_all ();
folder_sort_threads ();
return 0;
}
void
folder_update (void)
{
int index;
mail_t *mail;
void *ptr;
void *ptr_next;
void *ptr_prev;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
ptr = (mail) ? mail->place.generic : NULL;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos + 1);
if (mail == NULL)
mail = mail_array_get (wrapbox_marray,
folder_select->bar_pos);
ptr_next = (mail) ? mail->place.generic : NULL;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos - 1);
if (mail == NULL)
mail = mail_array_get (wrapbox_marray,
folder_select->bar_pos);
ptr_prev = (mail) ? mail->place.generic : NULL;
wrapbox_refresh ();
mail_array_sort_date (wrapbox_marray);
index = mail_array_find_place (wrapbox_marray, ptr);
if (index == -1)
index = mail_array_find_place (wrapbox_marray, ptr_next);
if (index == -1)
index = mail_array_find_place (wrapbox_marray, ptr_prev);
if (index != -1)
select_goto (folder_select, index);
folder_spam_check_all ();
folder_sort_threads ();
display_status_info ();
folder_at_bar_move ();
}
void
folder_flush (void)
{
PREAMBLE;
folder_spam_check_all ();
folder_spam_flush ();
folder_update ();
}
/****************************************************************************
* SEARCHING PRIVATE FUNCTIONS
****************************************************************************/
static int
match_subject (search_t *search, int index)
{
mail_t *mail = mail_array_get (wrapbox_marray, index);
if (mail == NULL)
return 0;
if (search == NULL)
return 1;
if (mail->subject == NULL)
return 0;
if (search_perform (search, mail->subject) != -1)
return 1;
return 0;
}
static int
match_from (search_t *search, int index)
{
mail_t *mail = mail_array_get (wrapbox_marray, index);
if (mail == NULL)
return 0;
if (search == NULL)
return 1;
if (mail->from == NULL || mail->from->full == NULL)
return 0;
if (search_perform (search, mail->from->full) != -1)
return 1;
return 0;
}
static int
match_any (search_t *search, int index)
{
return match_subject (search, index) || match_from (search, index);
}
/****************************************************************************
* SEARCHING FUNCTIONS
****************************************************************************/
void
folder_search_backward (void)
{
select_search_setup_backward (folder_select, match_any);
}
void
folder_search_forward (void)
{
select_search_setup_forward (folder_select, match_any);
}
/****************************************************************************
* SORTING FUNCTIONS
****************************************************************************/
void
folder_sort_threads (void)
{
int index;
mail_t *mail;
void *ptr = NULL;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail){
ptr = mail->place.generic;
}
mail_array_sort_threads (wrapbox_marray);
if (mail){
index = mail_array_find_place (wrapbox_marray, ptr);
}
else {
index = wrapbox_marray->count - 1;
}
make_trees ();
select_goto (folder_select, index);
folder_redraw ();
}
void
folder_sort_date (void)
{
int index;
mail_t *mail;
void *ptr = NULL;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail) {
ptr = mail->place.generic;
}
mail_array_sort_date (wrapbox_marray);
index = mail_array_find_place (wrapbox_marray, ptr);
select_goto (folder_select, index);
folder_redraw ();
}
void
folder_sort_from (void)
{
int index;
mail_t *mail;
void *ptr = NULL;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail) {
ptr = mail->place.generic;
}
mail_array_sort_from (wrapbox_marray);
index = mail_array_find_place (wrapbox_marray, ptr);
select_goto (folder_select, index);
folder_redraw ();
}
void
folder_sort_subject (void)
{
int index;
mail_t *mail;
void *ptr = NULL;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail) {
ptr = mail->place.generic;
}
mail_array_sort_subject (wrapbox_marray);
index = mail_array_find_place (wrapbox_marray, ptr);
select_goto (folder_select, index);
folder_redraw ();
}
/****************************************************************************
* BAR MOVEMENT FUNCTIONS
****************************************************************************/
void
folder_page_next (void)
{
PREAMBLE;
select_next_page (folder_select);
folder_at_bar_move ();
}
void
folder_page_prev (void)
{
PREAMBLE;
select_prev_page (folder_select);
folder_at_bar_move ();
}
void
folder_bar_next (void)
{
PREAMBLE;
select_next (folder_select);
folder_at_bar_move ();
}
void
folder_bar_prev (void)
{
PREAMBLE;
select_prev (folder_select);
folder_at_bar_move ();
}
void
folder_scroll_down (void)
{
PREAMBLE;
select_scroll_down (folder_select);
}
void
folder_scroll_up (void)
{
PREAMBLE;
select_scroll_up (folder_select);
}
void
folder_bar_first (void)
{
PREAMBLE;
select_first (folder_select);
folder_at_bar_move ();
}
void
folder_bar_last (void)
{
PREAMBLE;
select_last (folder_select);
folder_at_bar_move ();
}
void
folder_recenter (void)
{
PREAMBLE;
select_recenter (folder_select);
}
void
folder_next_unread (void)
{
int index;
PREAMBLE;
index = mail_array_find_unread (wrapbox_marray,
folder_select->bar_pos + 1);
if (index != -1)
select_goto (folder_select, index);
folder_redraw ();
}
void
folder_prev_unread (void)
{
int index;
PREAMBLE;
index = mail_array_find_unread_back (wrapbox_marray,
folder_select->bar_pos - 1);
if (index != -1)
select_goto (folder_select, index);
folder_redraw ();
}
/****************************************************************************
* ACTIONS PRIVATE FUNCTIONS
****************************************************************************/
static void
action_move_mail (mail_t *mail, char *box)
{
if (box == NULL)
return;
if (wrapbox_move_mail_to (mail, box)){
error_ (0, _("couldn't move mail to %s"), box);
}
}
static void
action_remove_mail (mail_t *mail, char *nothing)
{
wrapbox_remove (mail);
}
static void
action_make_read (mail_t *mail, char *nothing)
{
mail->flags |= FLAG_READ;
}
static void
action_check_spam (mail_t *mail, char *nothing)
{
if (bayes_is_spam (mail)){
mail->flags &= ~ FLAG_NOSPAM;
mail->flags &= ~ FLAG_LEGITIMATE;
mail->flags |= FLAG_SPAM;
}
else {
mail->flags &= ~ FLAG_SPAM;
mail->flags |= FLAG_NOSPAM;
}
}
static void
action_delete_spam (mail_t *mail, char *trash)
{
if (mail->flags & FLAG_LEGITIMATE){
bayes_unscan_legitimate (mail);
}
bayes_scan_spam (mail);
wrapbox_move_mail_to (mail, trash);
}
static void
action_is_not_spam (mail_t *mail, char *nothing)
{
mail->flags |= FLAG_NOSPAM;
mail->flags &= ~ FLAG_SPAM;
}
static void
action_remove_flag (mail_t *mail, char *flag)
{
if (*flag == 'L')
mail->flags &= ~ FLAG_LEGITIMATE;
}
static void
take_action (void (*fun)(mail_t *, char*), char *arg)
{
int i;
int took = 0;
mail_t *mail;
PREAMBLE;
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
if (mail == NULL)
continue;
if (mail->flags & FLAG_FLAGGED){
mail->flags &= ~ FLAG_FLAGGED;
fun (mail, arg);
took = 1;
}
}
if (! took){
mail = mail_array_get (wrapbox_marray,
folder_select->bar_pos);
if (mail)
fun (mail, arg);
}
}
/****************************************************************************
* ACTIONS INTERFACE FUNCTIONS
****************************************************************************/
void
folder_after_read (void)
{
mail_t *mail;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail == NULL)
return;
mail->flags |= FLAG_OLD;
mail->flags |= FLAG_READ;
wrapbox_marray->old_count = -1;
wrapbox_marray->read_count = -1;
folder_redraw ();
}
void
folder_after_reply (void)
{
mail_t *mail;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail == NULL)
return;
mail->flags |= FLAG_ANSWERED;
folder_redraw ();
}
void
folder_after_fwd (void)
{
mail_t *mail;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail == NULL)
return;
mail->flags |= FLAG_PASSED;
folder_redraw ();
}
void
folder_kill_mail (void)
{
PREAMBLE;
take_action (action_remove_mail, NULL);
folder_update ();
}
void
folder_delete_mail (void)
{
char *box;
PREAMBLE;
box = mybox_trash ();
if (box == NULL){
folder_kill_mail ();
}
else {
take_action (action_move_mail, box);
xfree (box);
folder_update ();
}
}
void
folder_move_mail (void)
{
char *box;
PREAMBLE;
box = mybox_select_subdir ();
if (box == NULL)
return;
take_action (action_move_mail, box);
xfree (box);
folder_update ();
}
void
folder_make_read (void)
{
PREAMBLE;
take_action (action_make_read, NULL);
folder_redraw ();
}
void
folder_at_leave (void)
{
exec_t *exec;
exec = exec_lookup_fun (folder_at_leave);
hook_execute (exec->hook);
folder_spam_flush ();
wrapbox_apply_flags ();
wrapbox_dump_box ();
}
void
folder_at_bar_move (void)
{
exec_t *exec;
exec = exec_lookup_fun (folder_at_bar_move);
hook_execute (exec->hook);
}
/****************************************************************************
* FLAGGING FUNCTIONS
****************************************************************************/
void
folder_toggle_flag (void)
{
mail_t *mail;
PREAMBLE;
mail = mail_array_get (wrapbox_marray, folder_select->bar_pos);
if (mail == NULL)
return;
if (mail->flags & FLAG_FLAGGED)
mail->flags &= ~ FLAG_FLAGGED;
else
mail->flags |= FLAG_FLAGGED;
folder_redraw ();
}
void
folder_flag_all (void)
{
int i;
mail_t *mail;
PREAMBLE;
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
mail->flags |= FLAG_FLAGGED;
}
folder_redraw ();
}
void
folder_unflag_all (void)
{
int i;
mail_t *mail;
PREAMBLE;
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
mail->flags &= ~ FLAG_FLAGGED;
}
folder_redraw ();
}
void
folder_flag_invert (void)
{
int i;
mail_t *mail;
PREAMBLE;
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
if (mail->flags & FLAG_FLAGGED)
mail->flags &= ~ FLAG_FLAGGED;
else
mail->flags |= FLAG_FLAGGED;
}
folder_redraw ();
}
void
folder_flag_duplicates (void)
{
int i;
mail_t *mail;
PREAMBLE;
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
if (mail->flags & FLAG_DUPLICATE)
mail->flags |= FLAG_FLAGGED;
}
folder_redraw ();
}
void
folder_remove_flag (void)
{
char *flag;
PREAMBLE;
flag = read_argument ("Flag: ", NULL, COMPLETE_FILES, HIDE_NO);
if (flag && *flag != '\0')
take_action (action_remove_flag, flag);
folder_update ();
}
/****************************************************************************
* SPAM FUNCTIONS
****************************************************************************/
void
folder_spam_check (void)
{
if (! mybox_protect)
return;
PREAMBLE;
take_action (action_check_spam, NULL);
folder_redraw ();
}
void
folder_spam_check_all (void)
{
int i;
mail_t *mail;
if (! mybox_protect)
return;
PREAMBLE;
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
if ((mail->flags & FLAG_SPAM) || (mail->flags & FLAG_NOSPAM)
|| (mail->flags & FLAG_LEGITIMATE))
continue;
if (bayes_is_spam (mail))
mail->flags |= FLAG_SPAM;
else
mail->flags |= FLAG_NOSPAM;
}
folder_redraw ();
}
void
folder_spam_delete (void)
{
char *box;
if (! mybox_protect)
return;
PREAMBLE;
box = mybox_spam ();
take_action (action_delete_spam, box);
xfree (box);
folder_update ();
}
void
folder_spam_is_not (void)
{
if (! mybox_protect)
return;
PREAMBLE;
take_action (action_is_not_spam, NULL);
folder_redraw ();
}
void
folder_spam_flush (void)
{
int i;
char *box;
mail_t *mail;
if (! mybox_protect)
return;
PREAMBLE;
box = mybox_spam ();
for (i = 0; i < wrapbox_marray->count; i++){
mail = mail_array_get (wrapbox_marray, i);
if (mail->flags & FLAG_SPAM){
bayes_scan_spam (mail);
wrapbox_move_mail_to (mail, box);
}
else if ((mail->flags & FLAG_NOSPAM)
&& ! (mail->flags & FLAG_LEGITIMATE)){
mail->flags |= FLAG_LEGITIMATE;
bayes_scan_legitimate (mail);
}
}
if (box)
xfree (box);
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE folder.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1