/*
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 <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#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
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1