/*
elmo - ELectronic Mail Operator
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.
----------------------------------------------------------------------
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "sender.h"
#include "smtp.h"
#include "clock.h"
#include "ask.h"
#include "error.h"
#include "eprintf.h"
#include "rstring.h"
#include "mlex.h"
#include "select.h"
#include "file.h"
#include "xmalloc.h"
#include "mailinfo.h"
#include "read.h"
#include "compose.h"
#include "line.h"
#include "misc.h"
#include "cmd.h"
#include "gettext.h"
#include "wrapbox.h"
#include "mybox.h"
#include "ecurses.h"
#include "interface.h"
#include "color.h"
#include "label.h"
#include "rmime.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define PREAMBLE do { if (message.type != BOX_SENDER) return; } while (0)
typedef enum {SENDER_DROP, SENDER_DRAFT, SENDER_SENT} sent_t;
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
/* Sender window consists of select_t object, and an optional label. */
static select_t *sender_select = NULL;
static elabel_t *label = NULL;
/* Colors used in sender window, and in mailinfo window. */
static chtype text_color;
static chtype info_color;
/* Format used to display attachments. */
static char *sender_fmt = NULL;
/* This object stores the message being sent. */
static mail_t message;
/* Used in draw_line. */
static str_t *str_line = NULL;
/* Saved directory. It is used when adding attachment. */
static char *attach_dir = NULL;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/**
* this holds everything we need to know about smtp account and data
* associated with it
*/
ask_t *sender_ask = NULL;
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* REWRITE FUNCTIONS
****************************************************************************/
static void
write_references (FILE *fp, rstring_t *references)
{
char **iterator;
fprintf (fp, "References:");
for (iterator = references->array; *iterator; iterator++){
fprintf (fp, " %s\n", *iterator);
}
fprintf (fp, "In-Reply-To: %s\n",
references->array[references->count - 1]);
}
static int
write_headers (FILE *fp, mime_t *mime, char *boundary, char *charset)
{
char *enc;
char *fname;
if (boundary == NULL)
return 0;
fprintf (fp, "\n--%s\n", boundary);
if (mime->type)
fprintf (fp, "Content-Type: %s\n", mime->type);
else
fprintf (fp, "Content-Type: text/plain; charset=%s\n",
charset);
if (mime->file_name){
fname = strrchr (mime->file_name, '/');
if (fname)
fname++;
else
fname = mime->file_name;
fprintf (fp, "Content-Disposition: attachment; "
"filename=\"%s\"\n", fname);
}
else {
fprintf (fp, "Content-Disposition: inline\n");
}
enc = mime_encoding_str (mime);
if (enc == NULL)
enc = "8bit";
fprintf (fp, "Content-Transfer-Encoding: %s\n", enc);
fprintf (fp, "\n");
return 0;
}
static int
get_buffer (mime_t *mime, char **place, int *size)
{
int ret;
FILE *fp;
if (mime->file_name){
fp = fopen (mime->file_name, "r");
if (fp == NULL){
error_ (errno, "%s", mime->file_name);
return 1;
}
ret = file_whole (fp, place, size);
fclose (fp);
return ret;
}
else {
*size = mime->off_end - mime->off_start;
return file_part (message.place.file_name, mime->off_start,
mime->off_end, place);
}
}
static int
write_attachment (FILE *fp, mime_t *mime)
{
char *buf;
int size;
str_t *str;
if (get_buffer (mime, & buf, & size))
return 1;
str = mime_encode (mime, buf, size);
if (fwrite (str->str, 1, str->len, fp) != str->len){
error_ (errno, "%s", _("writing attachment"));
return 1;
}
str_destroy (str);
return 0;
}
static int
write_end (FILE *fp, char *boundary)
{
if (boundary)
fprintf (fp, "\n--%s--\n", boundary);
return 0;
}
static int
rewrite_file (const char *where)
{
int i;
FILE *fp;
char *smtp;
char *fname;
char *header;
char *boundary = NULL;
char *charset = ask_for_default ("charset", NULL);
if (charset == NULL || *charset == '\0')
charset = "us-ascii";
if (where == NULL)
return 1;
fname = wrapbox_fetch_where (0);
if (fname == NULL)
return 1;
fp = file_open (fname, "w", O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fp == NULL){
error_ (errno, "%s", fname);
xfree (fname);
return 1;
}
if (message.from && message.from->full)
fprintf (fp, "From: %s\n", message.from->full);
header = raddress_list (message.to, "To", 1, " ");
if (header){
fprintf (fp, "%s\n", header);
xfree (header);
}
header = raddress_list (message.cc, "Cc", 1, " ");
if (header){
fprintf (fp, "%s\n", header);
xfree (header);
}
header = raddress_list (message.bcc, "Bcc", 1, " ");
if (header){
fprintf (fp, "%s\n", header);
xfree (header);
}
if (message.subject)
fprintf (fp, "Subject: %s\n", message.subject);
if (message.date_str)
fprintf (fp, "Date: %s\n", message.date_str);
if (message.msg_id)
fprintf (fp, "Message-ID: %s\n", message.msg_id);
if (message.in_reply_to)
write_references (fp, message.in_reply_to);
smtp = ask_get_field (sender_ask, "name");
fprintf (fp, "User-Agent: %s/%s\n", PACKAGE, VERSION);
fprintf (fp, "MIME-Version: 1.0\n");
if (smtp)
fprintf (fp, "X-Elmo-SMTP: %s\n", smtp);
if (message.headers){
for (i = 0; i < message.headers->count; i++){
fprintf (fp, "%s\n", message.headers->array[i]);
}
}
if (message.mime->mime->parts == NULL){
if (message.mime->mime->type)
fprintf (fp, "Content-Type: %s\n",
message.mime->mime->type);
else
fprintf (fp, "Content-Type: text/plain; charset=%s\n",
charset);
fprintf (fp, "Content-Transfer-Encoding: 8bit\n");
fprintf (fp, "\n");
}
else {
boundary = compose_boundary ();
fprintf (fp,
"Content-Type: multipart/mixed; boundary=\"%s\"\n",
boundary);
fprintf (fp, "\n");
}
if (message.mime->mime->parts){
for (i = 0; i < message.mime->mime->parts->count; i++){
write_headers (fp,
message.mime->mime->parts->array[i],
boundary, charset);
write_attachment (fp, message.mime->mime->parts->array[i]);
}
write_end (fp, boundary);
}
else {
write_attachment (fp, message.mime->mime);
}
fclose (fp);
if (boundary)
xfree (boundary);
if (wrapbox_deliver_to (fname, where)){
error_ (0, _("couldn't store the message in %s"), where);
xfree (fname);
return 1;
}
xfree (fname);
return 0;
}
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static void
save_dir (char *file)
{
int c;
char *seek = strrchr (file, '/');
if (seek == NULL)
return;
if (attach_dir)
xfree (attach_dir);
seek++;
c = *seek;
*seek = '\0';
attach_dir = xstrdup (file);
*seek = c;
}
static int
parse_mail (char *file)
{
yyin = fopen (file, "r");
if (yyin == NULL){
error_ (errno, "%s", file);
return 1;
}
if (mlex_outmail_scan () != NEXT_MAIL){
fclose (yyin);
error_ (0, _("file %s has bad format"), file);
return 1;
}
fclose (yyin);
memcpy (& message, newmail, sizeof (message));
message.place.file_name = file;
message.type = BOX_SENDER;
if (message.from && message.from->email){
ask_change_where (sender_ask, "email", message.from->email);
}
return 0;
}
static void
draw_line (WINDOW *win, int maxlen, int index, search_t *search)
{
mime_t *mime = (message.type == BOX_SENDER)
? mime_nth_leaf (message.mime, index) : NULL;
if (str_line == NULL)
str_line = str_create ();
if (message.type == BOX_SENDER && mime){
eprintf_mime_str (sender_fmt, mime, str_line);
maxlen -= window_addnstr (win, str_line->str, maxlen);
}
while (maxlen-- > 0)
window_addch (win, ' ');
}
static int
count (select_t *nothing)
{
return (message.type == BOX_SENDER)
? mime_leaf_count (message.mime) : 0;
}
static void
set_focus (void)
{
if (label){
label_set_focus (label);
}
cmd_state_push (CMD_SENDER);
sender_redraw ();
}
static void
unset_focus (void)
{
if (label){
label_unset_focus (label);
label_redraw (label);
}
cmd_state_pop ();
}
static void
hide_window (void)
{
if (sender_ask)
ask_destroy (sender_ask);
sender_ask = NULL;
window_hide (sender_select->win);
}
/* This file is generated by interface.pl script from interface.desc,
and inc.in. */
static WINDOW *interface_init (void);
#include "sender.inc"
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
sender_init (void)
{
WINDOW *window = interface_init ();
sender_select = select_open (window, 0, draw_line, count);
window_set_functions (window, sender_refresh, sender_redraw,
set_focus, unset_focus);
message.type = BOX_INVALID;
mailinfo_init (window, info_color);
}
void
sender_free_resources (void)
{
if (sender_select)
select_close (sender_select);
sender_select = NULL;
if (label)
label_destroy (label);
label = NULL;
if (str_line)
str_destroy (str_line);
str_line = NULL;
if (message.type == BOX_SENDER)
mail_destroy (& message, BOX_SENDER);
message.type = BOX_INVALID;
if (sender_ask)
ask_destroy (sender_ask);
sender_ask = NULL;
if (attach_dir)
xfree (attach_dir);
attach_dir = NULL;
mailinfo_free_resources ();
}
void
sender_refresh (void)
{
if (label)
label_show (label);
select_show (sender_select);
mailinfo_refresh ();
}
void
sender_redraw (void)
{
if (label)
label_redraw (label);
select_redraw (sender_select);
mailinfo_show (& message);
}
void
sender_open (char *file)
{
if (parse_mail (file))
return;
window_show (sender_select->win);
sender_redraw ();
}
void
sender_open_new_to (char *to)
{
char *file;
sender_ask = ask_select_default ("smtp_acc");
if (sender_ask == NULL)
return;
file = compose_new (to);
if (file == NULL){
ask_destroy (sender_ask);
sender_ask = NULL;
return;
}
sender_open (file);
}
void
sender_open_new (void)
{
sender_open_new_to (NULL);
}
void
sender_open_reply (void)
{
char *file;
sender_ask = ask_select_default ("smtp_acc");
if (sender_ask == NULL)
return;
file = compose_reply (0);
if (file == NULL){
ask_destroy (sender_ask);
sender_ask = NULL;
return;
}
sender_open (file);
}
void
sender_open_reply_all (void)
{
char *file;
sender_ask = ask_select_default ("smtp_acc");
if (sender_ask == NULL)
return;
file = compose_reply (1);
if (file == NULL){
ask_destroy (sender_ask);
sender_ask = NULL;
return;
}
sender_open (file);
}
void
sender_open_fwd (void)
{
char *file;
sender_ask = ask_select_default ("smtp_acc");
if (sender_ask == NULL)
return;
file = compose_fwd (NULL);
if (file == NULL){
ask_destroy (sender_ask);
sender_ask = NULL;
return;
}
sender_open (file);
}
void
sender_open_edit (void)
{
char *file;
sender_ask = ask_select_default ("smtp_acc");
if (sender_ask == NULL)
return;
file = compose_edit ();
if (file == NULL){
ask_destroy (sender_ask);
sender_ask = NULL;
}
sender_open (file);
}
void
sender_close (void)
{
int ret;
char *box;
PREAMBLE;
ret = ask_if_sure ("save message as draft (y/n)? ");
switch (ret){
case -1:
return;
case 0:
break;
case 1:
box = mybox_draft ();
if (rewrite_file (box)){
xfree (box);
return;
}
xfree (box);
break;
}
if (message.type == BOX_SENDER)
mail_destroy (& message, BOX_SENDER);
message.type = BOX_INVALID;
hide_window ();
}
void
sender_go (void)
{
char *box;
PREAMBLE;
box = mybox_outbox ();
if (rewrite_file (box)){
xfree (box);
return;
}
xfree (box);
if (message.type == BOX_SENDER)
mail_destroy (& message, BOX_SENDER);
message.type = BOX_INVALID;
hide_window ();
compose_after_send ();
}
void
sender_next (void)
{
PREAMBLE;
select_next (sender_select);
}
void
sender_prev (void)
{
PREAMBLE;
select_prev (sender_select);
}
void
sender_next_page (void)
{
PREAMBLE;
select_next_page (sender_select);
}
void
sender_prev_page (void)
{
PREAMBLE;
select_prev_page (sender_select);
}
void
sender_first (void)
{
PREAMBLE;
select_first (sender_select);
}
void
sender_last (void)
{
PREAMBLE;
select_last (sender_select);
}
void
sender_change_smtp (void)
{
char *name;
char *email;
address_t *addr;
PREAMBLE;
if (sender_ask == NULL)
return;
ask_select_different (sender_ask);
email = ask_get_field (sender_ask, "email");
name = ask_get_field (sender_ask, "my_name");
addr = address_empty ();
addr->name = name;
addr->email = email;
message.reply_to = message.from = address_complete (addr);
sender_redraw ();
}
void
sender_change_from (void)
{
char *from;
PREAMBLE;
if (message.from){
from = read_argument (_("From: "), message.from->full,
COMPLETE_ADDRS, HIDE_NO);
}
else {
from = read_argument (_("From: "), NULL, COMPLETE_ADDRS,
HIDE_NO);
}
if (from){
message.reply_to = message.from = address_from_string (from);
}
mailinfo_show (& message);
}
void
sender_change_reply_to (void)
{
char *reply;
PREAMBLE;
if (message.reply_to){
reply = read_argument (_("Reply-To: "),
message.reply_to->full,
COMPLETE_ADDRS, HIDE_NO);
}
else {
reply = read_argument (_("Reply-To: "), NULL, COMPLETE_ADDRS,
HIDE_NO);
}
if (reply){
message.reply_to = address_from_string (reply);
}
mailinfo_show (& message);
}
void
sender_change_to (void)
{
char *to;
char *newto;
PREAMBLE;
to = raddress_list (message.to, NULL, 0, "");
newto = read_argument (_("To: "), to, COMPLETE_ADDRS, HIDE_NO);
if (newto == NULL){
xfree (to);
return;
}
if (message.to)
raddress_destroy (message.to);
message.to = raddress_get_from_header (newto);
if (to)
xfree (to);
mailinfo_show (& message);
}
void
sender_change_cc (void)
{
char *cc;
char *newcc;
PREAMBLE;
cc = raddress_list (message.cc, NULL, 0, "");
newcc = read_argument (_("Cc: "), cc, COMPLETE_ADDRS, HIDE_NO);
if (newcc == NULL){
xfree (cc);
return;
}
if (message.cc)
raddress_destroy (message.cc);
message.cc = raddress_get_from_header (newcc);
if (cc)
xfree (cc);
mailinfo_show (& message);
}
void
sender_change_bcc (void)
{
char *bcc;
char *newbcc;
PREAMBLE;
bcc = raddress_list (message.bcc, NULL, 0, "");
newbcc = read_argument (_("Bcc: "), bcc, COMPLETE_ADDRS, HIDE_NO);
if (newbcc == NULL){
xfree (bcc);
return;
}
if (message.bcc)
raddress_destroy (message.bcc);
message.bcc = raddress_get_from_header (newbcc);
if (bcc)
xfree (bcc);
mailinfo_show (& message);
}
void
sender_change_subject (void)
{
char *subject;
PREAMBLE;
subject = read_argument (_("Subject: "), message.subject,
COMPLETE_NONE, HIDE_NO);
if (subject == NULL)
return;
if (message.subject)
xfree (message.subject);
message.subject = xstrdup (subject);
mailinfo_show (& message);
}
void
sender_add_attachment (void)
{
char *attachment;
char *true_name;
mime_t *mime;
int size;
PREAMBLE;
attachment = read_argument (_("File: "), attach_dir, COMPLETE_FILES,
HIDE_NO);
true_name = file_expand_tilde (attachment);
if (true_name == NULL || *true_name == '\0')
return;
size = file_size (true_name);
if (size == -1){
error_ (errno, "%s", attachment);
if (true_name != attachment)
xfree (true_name);
return;
}
save_dir (attachment);
mime = mime_from_file_name (true_name);
mime->off_start = 0;
mime->off_end = size;
if (message.mime->mime->parts == NULL){
mime_t *mime = mime_create ();
mime->type = xstrdup ("multipart/mixed");
mime->parts = rmime_create_size (4);
rmime_add (mime->parts, message.mime->mime);
message.mime->mime = mime;
}
rmime_add (message.mime->mime->parts, mime);
if (true_name != attachment)
xfree (true_name);
sender_redraw ();
}
void
sender_delete_attachment (void)
{
int index = sender_select->bar_pos;
mime_t *mime;
PREAMBLE;
if (message.mime->mime->parts == NULL
|| message.mime->mime->parts->count <= 1){
error_ (0, "%s", _("Can't make a message empty. Please add "
"something else first."));
return;
}
mime = message.mime->mime->parts->array[index];
mime_destroy (mime);
rmime_remove (message.mime->mime->parts, index);
sender_redraw ();
}
void
sender_change_type (void)
{
int index = sender_select->bar_pos;
char *type;
mime_t *mime;
PREAMBLE;
if (message.mime->mime->parts == NULL)
mime = message.mime->mime;
else
mime = message.mime->mime->parts->array[index];
type = read_argument (_("Content-Type: "), mime->type, COMPLETE_NONE,
HIDE_NO);
if (type && *type){
if (mime->type)
xfree (mime->type);
mime->type = xstrdup (type);
}
sender_redraw ();
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE sender.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1