/* elmo - ELectronic Mail Operator Copyright (C) 2002 bazyl Copyright (C) 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. ---------------------------------------------------------------------- showing e-mail in scrolling window */ /**************************************************************************** * IMPLEMENTATION HEADERS ****************************************************************************/ #include #include #include #include #include "ecurses.h" #include "mailreader.h" #include "status.h" #include "error.h" #include "xmalloc.h" #include "attach.h" #include "cmd.h" #include "wrapbox.h" #include "gettext.h" #include "folder.h" #include "select.h" #include "color.h" #include "label.h" #include "interface.h" #include "ask.h" #include "rarray.h" /**************************************************************************** * IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES ****************************************************************************/ struct header { str_t *str; chtype color; }; /**************************************************************************** * IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID) ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE DATA ****************************************************************************/ /* This tells us if user is watching a header or a message. */ static int header_view = 0; /* Mailreader window consists of select_t object and an optional label. */ static elabel_t *label = NULL; static select_t *mail_select = NULL; /* Message body and header split into single lines. */ static rstring_t *mail_lines = NULL; /* Message body as a string. */ static char *mail_body = NULL; /* Colors used in mailreader window. */ static chtype text_color; static chtype signature_color; static chtype quote_color; static chtype to_color; static chtype from_color; static chtype subject_color; static chtype cc_color; static chtype mua_color; static chtype date_color; static chtype replyto_color; static chtype sigok_color; static chtype sigwarn_color; static chtype sigfail_color; static chtype hilight_color; /* This is the index of the first line of the signature. */ static unsigned signature_index = -1; /* Header consists of struct header objects. */ static rarray_t *headers = NULL; /**************************************************************************** * INTERFACE DATA ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES ****************************************************************************/ /**************************************************************************** * HEADERS MANIPULATION FUNCTIONS ****************************************************************************/ static void header_destroy (void) { int i; struct header *header; if (headers == NULL) return; for (i = 0; i < headers->count; i++){ header = (struct header *) headers->array[i]; str_destroy (header->str); xfree (header); } rarray_destroy (headers); headers = NULL; } static void header_create (void) { header_destroy (); headers = rarray_create_size (10); } static void header_add_str (str_t *str, chtype color) { struct header *item = xmalloc (sizeof (struct header)); item->str = str; item->color = color; rarray_add (headers, item); } static void header_add (chtype color, const char *fmt, ...) { str_t *str; va_list ap; va_start (ap, fmt); str = str_create (); str_vsprintf (str, fmt, ap); va_end (ap); header_add_str (str, color); } static void header_add_raddress (chtype color, raddress_t *addr, const char *s) { int i; if (addr && addr->count > 0){ if (addr->array[0] && addr->array[0]->full) header_add (color, "%s: %s", s, addr->array[0]->full); for (i = 1; i < addr->count; i++) header_add (color, " %s", addr->array[i]->full); } } static void header_add_signature (mime_info_t *mime) { switch (mime->sig){ case SIG_NOT_SIGNED: break; case SIG_OK: if (mime->sig_by) header_add (sigok_color, "PGP: ok (%s)", mime->sig_by); else header_add_str (str_dup ("PGP: ok"), sigok_color); break; case SIG_WARN: if (mime->sig_by) header_add (sigwarn_color, "PGP: %s (%s)", mime->sig_text, mime->sig_by); else header_add (sigwarn_color, "PGP: %s", mime->sig_text); break; case SIG_FAIL: if (mime->sig_by) header_add (sigfail_color, "PGP: %s (%s)", mime->sig_text, mime->sig_by); else header_add (sigfail_color, "PGP: %s", mime->sig_text); break; } } static int header_draw_line (WINDOW *window, int maxlen, int index) { struct header *header; if (headers == NULL || index >= headers->count) return 0; header = headers->array[index]; wattrset (window, header->color); maxlen -= window_addnstr (window, header->str->str, maxlen); while (maxlen-- > 0) window_addch (window, ' '); return 1; } /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTIONS ****************************************************************************/ static void generate_header (mail_t *mail) { header_create (); if (mail->date_str) header_add (date_color, "Date: %s", mail->date_str); if (mail->from) header_add (from_color, "From: %s", mail->from->full); if (mail->subject) header_add (subject_color, "Subject: %s", mail->subject); header_add_raddress (to_color, mail->to, "To"); header_add_raddress (cc_color, mail->cc, "Cc"); header_add_raddress (cc_color, mail->bcc, "Bcc"); if (mail->reply_to && mail->reply_to != mail->from) header_add (replyto_color, "Reply-To: %s", mail->reply_to->full); if (mail->mua) header_add (mua_color, "MUA: %s", mail->mua); header_add_signature (mail->mime); header_add_str (str_dup (""), text_color); } static int set_mail_lines (mail_t *mail, mime_t *mime) { int width, nothing; str_t *str; if (mail_body){ xfree (mail_body); mail_body = NULL; } str = wrapbox_mail_body (mail, mime, 0); if (str == NULL && errno != 0){ error_ (errno, _("impossible to display mail contents")); return 1; } mail_body = (str) ? str_finished (str) : NULL; if (mail_lines){ rstring_delete (mail_lines); mail_lines = NULL; } generate_header (mail); getmaxyx (mail_select->win, nothing, width); if (mail_body){ mail_lines = rstring_split_lines (mail_body, width); } return 0; } static int set_header_lines (void) { mail_t *mail = folder_mail_selected (); if (mail == NULL) return 1; if (mail_body){ xfree (mail_body); mail_body = NULL; } if (wrapbox_mail_header (mail, &mail_body)){ error_ (errno, _("impossible to display mail header")); return 1; } if (mail_lines){ rstring_delete (mail_lines); mail_lines = NULL; } header_destroy (); if (mail_body){ mail_lines = rstring_split_lines (mail_body, COLS); } return 0; } static int quote_delta (int state, char c) { if (state == 0 && isspace (c)) return 0; if (c == '>') return 111; if (isalnum (c)) return state + 1; return 5; } static int is_quote (char *str) { int state = 0; while (*str && state < 4){ state = quote_delta (state, *str); str++; } return state == 111; } static int sig_delta (int state, char c) { if (state < 2 && c == '-') return state + 1; if (state == 2 && c == ' ') return 3; return 4; } static int is_signature (char *str, int index) { int state = 0; if (index >= signature_index) return 1; while (*str && state < 4){ state = sig_delta (state, *str); str++; } if (*str == '\0' && state == 3){ signature_index = index; return 1; } return 0; } static void change_color (WINDOW *window, char *str, int index) { if (is_signature (str, index)){ wattrset (window, signature_color); } else if (is_quote (str)){ wattrset (window, quote_color); } else { wattrset (window, text_color); } } 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); wattrset (win, hilight_color); window_addnstr (win, str + pos, len); wattrset (win, text_color); maxlen -= pos + len; } return pos + len + window_addnstr (win, str + pos + len, maxlen - 1); } static void draw_line (WINDOW *window, int maxlen, int index, search_t *search) { int i; if (headers == NULL && mail_lines == NULL) return; if (header_draw_line (window, maxlen, index)) return; if (headers) index -= headers->count; if (mail_lines && index < mail_lines->count){ change_color (window, mail_lines->array[index], index); i = add_string (window, mail_lines->array[index], maxlen, search); while (i < maxlen){ window_addch (window, ' '); i++; } } else { for (i = 0; i < maxlen; i++){ window_addch (window, ' '); } } } static int reader_count (select_t *nothing) { int ret = 1; if (headers) ret += headers->count; if (mail_lines) ret += mail_lines->count; return ret; } /* This file is generated by interface.pl script from interface.desc, and inc.in. */ static WINDOW *interface_init (void); #include "mailreader.inc" static int load_mail (void) { mail_t *mail = folder_mail_selected (); if (mail == NULL) return 1; select_first (mail_select); set_mail_lines (mail, NULL); header_view = 0; folder_after_read (); signature_index = -1; mailreader_redraw (); return 0; } static int match_line (search_t *search, int index) { if (headers == NULL && mail_lines == NULL) return 0; if (headers && index < headers->count) return 0; if (headers) index -= headers->count; if (mail_lines == NULL || index >= mail_lines->count) return 0; if (search_perform (search, mail_lines->array[index]) != -1) return 1; return 0; } /**************************************************************************** * INTERFACE FUNCTIONS ****************************************************************************/ void mailreader_init (void) { WINDOW *window; window = interface_init (); mail_select = select_open (window, 1, draw_line, reader_count); header_view = 0; window_set_functions (window, mailreader_refresh, mailreader_redraw, mailreader_set_focus, mailreader_unset_focus); } void mailreader_free_resources (void) { if (mail_select) select_close (mail_select); mail_select = NULL; if (mail_lines) rstring_delete (mail_lines); mail_lines = NULL; header_destroy (); if (mail_body) xfree (mail_body); mail_body = NULL; if (label) label_destroy (label); label = NULL; } void mailreader_line_up (void) { select_prev (mail_select); } void mailreader_line_down (void) { select_next (mail_select); } void mailreader_page_up (void) { select_prev_page (mail_select); } void mailreader_page_down (void) { select_next_page (mail_select); } void mailreader_top (void) { select_first (mail_select); } void mailreader_bottom (void) { select_last (mail_select); } void mailreader_header_switch (void) { mail_t *mail = folder_mail_selected (); if (mail == NULL) return; select_first (mail_select); if (! header_view){ signature_index = -1; set_header_lines (); mailreader_redraw (); header_view = 1; } else { set_mail_lines (mail, NULL); mailreader_redraw (); header_view = 0; } } void mailreader_load (void) { load_mail (); } void mailreader_show (void) { if (load_mail ()) return; window_show (mail_select->win); } void mailreader_close (void) { signature_index = -1; if (mail_lines) rstring_delete (mail_lines); mail_lines = 0; window_hide (mail_select->win); interface_focus (1); } void mailreader_redraw (void) { mail_t *mail; mail = folder_mail_selected (); if (mail == NULL) return; select_redraw (mail_select); if (label) label_redraw (label); status_put_mailinfo (address_name (mail->from), mail->subject); } void mailreader_refresh (void) { select_show (mail_select); if (label) label_show (label); status_refresh (); } void mailreader_set_focus (void) { mail_t *mail; mail = folder_mail_selected (); if (mail == NULL) return; if (label){ label_set_focus (label); } status_put_mailinfo (address_name (mail->from), mail->subject); cmd_state_push (CMD_READ_MAIL); mailreader_redraw (); } void mailreader_unset_focus (void) { if (label){ label_unset_focus (label); label_redraw (label); } cmd_state_pop (); } void mailreader_change_mime (mail_t *mail, mime_t *mime) { set_mail_lines (mail, mime); signature_index = -1; mailreader_redraw (); } void mailreader_search_forward (void) { select_search_setup_forward (mail_select, match_line); } void mailreader_search_backward (void) { select_search_setup_backward (mail_select, match_line); } /**************************************************************************** * INTERFACE CLASS BODIES ****************************************************************************/ /**************************************************************************** * * END MODULE mailreader.c * ****************************************************************************/