/* This file is part of Mailfromd. -*- c -*-
Copyright (C) 2008 Sergey Poznyakoff
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; either version 3, or (at your option)
any later version.
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, see . */
#include "msg.h"
static void *
alloc_msgs()
{
return xcalloc(NMSGS, sizeof(struct mf_message));
}
static void
destroy_msgs(void *data)
{
struct mf_message *mtab = data;
struct mf_message *p;
for (p = mtab; p < mtab + NMSGS; p++) {
bi_close_message(p);
}
free(mtab);
}
void
drop_current_message(void *data)
{
int i;
struct mf_message *tab = data;
for (i = 0; i < NMSGS; i++)
if (tab[i].msg && tab[i].current) {
bi_close_message(&tab[i]);
break;
}
}
MF_DECLARE_DATA(MSGTAB, alloc_msgs, destroy_msgs, drop_current_message)
static int
find_slot(struct mf_message *tab)
{
int i;
for (i = 0; i < NMSGS; i++)
if (tab[i].msg == NULL)
return i;
return -1;
}
static int
do_msg_close(void *item, void *data)
{
bi_close_message(item);
return 0;
}
void
bi_close_message(struct mf_message *mp)
{
if (mp->msg) {
if (mp->mylist) {
mu_list_remove(mp->mylist, mp);
mu_list_destroy(&mp->mylist);
}
mu_list_do(mp->msglist, do_msg_close, NULL);
mu_list_destroy(&mp->msglist);
free(mp->buf);
memset(mp, 0, sizeof *mp);
}
}
int
bi_message_register(eval_environ_t env,
mu_list_t msglist, mu_message_t msg, int current)
{
struct mf_message *msgtab = MF_GET_DATA;
int idx = find_slot(msgtab);
if (idx >= 0) {
struct mf_message *mp = msgtab + idx;
mp->msg = msg;
mp->current = current;
mu_list_create(&mp->mylist);
mu_list_create(&mp->msglist);
if (msglist)
mu_list_append(msglist, mp);
}
return idx;
}
int
bi_get_current_message(eval_environ_t env)
{
int i;
struct mf_message *tab = MF_GET_DATA;
for (i = 0; i < NMSGS; i++)
if (tab[i].msg && tab[i].current)
return i;
return -1;
}
m4_define([],[<
struct mf_message *mtab = MF_GET_DATA;
struct mf_message *$1;
MF_ASSERT($2 >= 0 && $2 < NMSGS,
mfe_range,
_("Invalid message descriptor"));
$1 = mtab + $2;
MF_ASSERT($1->msg,
mfe_failure,
_("Message not open"))
>])
m4_define([],[<
DCL_MSG($1, $2);
if (!$1->body) {
int rc = mu_message_get_body($1->msg, &$1->body);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_message_get_body: %s",
mu_strerror(rc));
}
>])
m4_define([],[<
DCL_MSG($1, $2);
if (!$1->hdr) {
int rc = mu_message_get_header($1->msg, &$1->hdr);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_message_get_header: %s",
mu_strerror(rc));
}
>])
mu_message_t
bi_message_from_descr(eval_environ_t env, int nmsg)
{
DCL_MSG(mp, nmsg);
return mp->msg;
}
/* void message_close(number msg) */
MF_DEFUN(message_close, VOID, NUMBER nmsg)
{
DCL_MSG(mp, nmsg);
bi_close_message(mp);
}
END
/* number message_size(number nmsg) */
MF_DEFUN(message_size, NUMBER, NUMBER nmsg)
{
int rc;
size_t size;
DCL_MSG(mp, nmsg);
rc = mu_message_size(mp->msg, &size);
MF_ASSERT(rc == 0,
mfe_failure,
"%s", mu_strerror(rc));
MF_ASSERT(size < LONG_MAX,
mfe_range,
_("Message size out of representable range"));
MF_RETURN((long)size);
}
END
/* number message_lines(number nmsg) */
MF_DEFUN(message_lines, NUMBER, NUMBER nmsg)
{
int rc;
size_t lines;
DCL_MSG(mp, nmsg);
rc = mu_message_lines(mp->msg, &lines);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
MF_RETURN(lines);
}
END
/* number message_body_size(number nmsg) */
MF_DEFUN(message_body_size, NUMBER, NUMBER nmsg)
{
int rc;
size_t size;
DCL_BODY(mp, nmsg);
rc = mu_body_size(mp->body, &size);
MF_ASSERT(rc == 0,
mfe_failure,
"%s", mu_strerror(rc));
MF_ASSERT(size < LONG_MAX,
mfe_range,
_("Body size out of representable range"));
MF_RETURN((long)size);
}
END
/* number message_body_lines(number nmsg) */
MF_DEFUN(message_body_lines, NUMBER, NUMBER nmsg)
{
int rc;
size_t lines;
DCL_BODY(mp, nmsg);
rc = mu_body_lines(mp->body, &lines);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
MF_RETURN(lines);
}
END
/* Headers */
/* number message_header_size(number nmsg) */
MF_DEFUN(message_header_size, NUMBER, NUMBER nmsg)
{
int rc;
size_t size;
DCL_HDR(mp, nmsg);
rc = mu_header_size(mp->hdr, &size);
MF_ASSERT(rc == 0,
mfe_failure,
"%s", mu_strerror(rc));
MF_ASSERT(size < LONG_MAX,
mfe_range,
_("Header size out of representable range"));
MF_RETURN((long)size);
}
END
/* number message_header_lines(number nmsg) */
MF_DEFUN(message_header_lines, NUMBER, NUMBER nmsg)
{
int rc;
size_t lines;
DCL_HDR(mp, nmsg);
rc = mu_header_lines(mp->hdr, &lines);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
MF_RETURN(lines);
}
END
/* number message_header_count(number nmsg) */
MF_DEFUN(message_header_count, NUMBER, NUMBER nmsg)
{
int rc;
size_t count;
DCL_HDR(mp, nmsg);
rc = mu_header_get_field_count(mp->hdr, &count);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
MF_RETURN(count);
}
END
/* bool message_has_header(number msg, string header[, number idx]) */
MF_DEFUN(message_has_header, NUMBER, NUMBER nmsg, STRING header,
OPTIONAL, NUMBER idx)
{
int rc;
const char *val;
DCL_HDR(mp, nmsg);
rc = mu_header_sget_value_n(mp->hdr, header, MF_OPTVAL(idx, 1), &val);
MF_RETURN(rc == 0);
}
END
/* string message_find_header(number msg, string header[, number idx]) */
MF_DEFUN(message_find_header, STRING, NUMBER nmsg, STRING header,
OPTIONAL, NUMBER idx)
{
int rc;
const char *val;
DCL_HDR(mp, nmsg);
rc = mu_header_sget_value_n(mp->hdr, header, MF_OPTVAL(idx, 1), &val);
if (rc == MU_ERR_NOENT)
MF_THROW(mfe_not_found, _("Header not found"));
else if (rc)
MF_THROW(mfe_failure, "%s", mu_strerror(rc));
MF_RETURN_STRING(val);
}
END
/* Multipart messages */
/* bool message_is_multipart(number msg) */
MF_DEFUN(message_is_multipart, NUMBER, NUMBER nmsg)
{
int rc, res;
DCL_MSG(mp, nmsg);
rc = mu_message_is_multipart(mp->msg, &res);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
MF_RETURN(res);
}
END
/* number message_count_parts(number msg) */
MF_DEFUN(message_count_parts, NUMBER, NUMBER nmsg)
{
int rc;
size_t count;
DCL_MSG(mp, nmsg);
rc = mu_message_get_num_parts(mp->msg, &count);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
MF_RETURN(count);
}
END
/* number message_get_part(number msg, number idx) */
MF_DEFUN(message_get_part, NUMBER, NUMBER nmsg, NUMBER idx)
{
int rc;
mu_message_t msg;
DCL_MSG(mp, nmsg);
rc = mu_message_get_part(mp->msg, idx, &msg);
MF_ASSERT(rc == 0,
mfe_failure,
"%s",
mu_strerror(rc));
rc = bi_message_register(env, mp->msglist, msg, 0);
MF_ASSERT(rc >= 0,
mfe_failure,
_("No more message slots available"));
MF_RETURN(rc);
}
END
/* Reading */
/* string message_rewind(number nmsg) */
MF_DEFUN(message_rewind, VOID, NUMBER nmsg)
{
int rc;
mu_stream_t str;
DCL_MSG(mp, nmsg);
rc = mu_message_get_stream(mp->msg, &str);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_message_get_stream: %s",
mu_strerror(rc));
rc = mu_stream_seek(str, 0, SEEK_SET);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_stream_seek: %s",
mu_strerror(rc));
}
END
/* string message_read_line(number nmsg) */
MF_DEFUN(message_read_line, STRING, NUMBER nmsg)
{
int rc;
mu_stream_t str;
size_t size;
DCL_MSG(mp, nmsg);
rc = mu_message_get_stream(mp->msg, &str);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_message_get_stream: %s",
mu_strerror(rc));
rc = mu_stream_sequential_getline(str, &mp->buf, &mp->bufsize, &size);
MF_ASSERT(rc == 0,
mfe_io,
"mu_stream_sequential_getline: %s",
mu_strerror(rc));
MF_ASSERT(size > 0,
mfe_not_found, /* FIXME: Should be mfe_eof */
"mu_stream_sequential_getline: %s",
_("end of input"));
MF_RETURN_STRING(mp->buf);
}
END
/* string message_body_rewind(number nmsg) */
MF_DEFUN(message_body_rewind, VOID, NUMBER nmsg)
{
int rc;
mu_stream_t str;
DCL_BODY(mp, nmsg);
rc = mu_body_get_stream(mp->body, &str);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_message_get_stream: %s",
mu_strerror(rc));
rc = mu_stream_seek(str, 0, SEEK_SET);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_stream_seek: %s",
mu_strerror(rc));
}
END
/* string message_read_body_line(number msg) */
MF_DEFUN(message_read_body_line, STRING, NUMBER nmsg)
{
int rc;
mu_stream_t str;
size_t size;
DCL_BODY(mp, nmsg);
rc = mu_body_get_stream(mp->body, &str);
MF_ASSERT(rc == 0,
mfe_failure,
"mu_body_get_stream: %s",
mu_strerror(rc));
rc = mu_stream_sequential_getline(str, &mp->buf, &mp->bufsize, &size);
MF_ASSERT(rc == 0,
mfe_io,
"mu_stream_sequential_getline: %s",
mu_strerror(rc));
MF_ASSERT(size > 0,
mfe_not_found, /* FIXME: Should be mfe_eof */
"mu_stream_sequential_getline: %s",
_("end of input"));
MF_RETURN_STRING(mp->buf);
}
END
MF_INIT