static char rcsid[] = "@(#)$Id: outheaders.c,v 1.28 2006/04/09 07:37:08 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.28 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
*****************************************************************************/
#include "headers.h"
#include "hdr_imp.h"
#include "s_me.h"
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
DEBUG_VAR(Debug,__FILE__,"header");
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
int add_expanded_addr_ (x,ADR,FN,COM)
struct expanded_address *x;
CONST char *ADR;
CONST struct string *FN;
CONST struct string *COM;
{
if (x->magic != EXP_ADDR_magic)
panic("HEADERS PANIC",__FILE__,__LINE__,"add_expanded_addr_",
"Bad magic number",0);
x->addrs = safe_realloc(x->addrs,(x->addrs_len + 2) *
sizeof (struct addr_item));
x->addrs[x->addrs_len].addr = safe_strdup(ADR);
x->addrs[x->addrs_len].fullname = dup_string(FN);
x->addrs[x->addrs_len].comment = dup_string(COM);
x->addrs[x->addrs_len+1].addr = NULL;
x->addrs[x->addrs_len+1].fullname = NULL;
x->addrs[x->addrs_len+1].comment = NULL;
return x->addrs_len++;
}
int add_textual_addr_ (x,TEXTUAL,POS,LEN)
struct expanded_address *x;
CONST struct string *TEXTUAL;
int POS, LEN;
{
if (x->magic != EXP_ADDR_magic)
panic("HEADERS PANIC",__FILE__,__LINE__,"add_textual_addr_",
"Bad magic number",0);
x->surface = safe_realloc(x->surface,(x->surface_len + 2) *
sizeof (struct textual));
if (!TEXTUAL)
x->surface[x->surface_len].Textual = NULL;
else
x->surface[x->surface_len].Textual = dup_string(TEXTUAL);
x->surface[x->surface_len].pos = POS;
x->surface[x->surface_len].len = LEN;
x->surface[x->surface_len+1].Textual = NULL;
x->surface[x->surface_len+1].pos = POS+LEN;
x->surface[x->surface_len+1].len = 0;
return x->surface_len++;
}
void zero_expanded_address (x)
struct expanded_address *x;
{
/* bzero is defined hdrs/defs.h */
bzero((void *)x,sizeof (*x));
x->magic = EXP_ADDR_magic;
x->addrs = NULL;
x->addrs_len = 0;
x->surface = NULL;
x->surface_len = 0;
}
void copy_expanded_address (result,source)
struct expanded_address *result;
struct expanded_address source;
{
int i;
free_expanded_address(result);
if (source.magic != EXP_ADDR_magic)
panic("HEADERS PANIC",__FILE__,__LINE__,"copy_expanded_address",
"Bad magic number",0);
for (i = 0; i < source.surface_len; i++) {
int count = 0;
int pos = result->addrs_len;
int j;
for (j = 0; j < source.surface[i].len; j++) {
CONST struct addr_item *ptr1 = &
(source.addrs[source.surface[i].pos+j]);
int p = add_expanded_addr_(result,ptr1->addr,ptr1->fullname,
ptr1->comment);
if (0 == count)
pos = p;
count++;
}
add_textual_addr_(result,source.surface[i].Textual,pos,count);
}
}
void free_expanded_address(x)
struct expanded_address *x;
{
int i;
if (x->magic != EXP_ADDR_magic)
panic("HEADERS PANIC",__FILE__,__LINE__,"free_expanded_address",
"Bad magic number",0);
if (x->addrs) {
free_addr_items(x->addrs);
x->addrs = NULL;
}
x->addrs_len = 0;
if (x->surface) {
for (i = 0; i < x->surface_len; i++) {
if (x->surface[i].Textual) {
free_string (&(x->surface[i].Textual));
}
}
free(x->surface);
x->surface = NULL;
}
x->surface_len = 0;
}
struct string * make_surface_addr(ITEM)
struct addr_item ITEM;
{
struct string * result = new_string(display_charset);
int fl,cl;
if ((fl = string_len(ITEM.fullname))) {
int i;
add_ascii_to_string(result,s2us("\""));
for (i = 0; i < fl; i++) {
uint16 code = give_unicode_from_string(ITEM.fullname,i);
/* No fancy quotation stuff on textual form for editing */
switch(code) {
case 0x0022 /* '"' */:
case 0x005C /* '\\' */:
code = 0x005F /* '_' */;
break;
}
add_unicode_to_string(result,1,&code);
}
add_ascii_to_string(result,s2us("\" "));
}
add_ascii_to_string(result,s2us("<"));
add_ascii_to_string(result,s2us(ITEM.addr));
add_ascii_to_string(result,s2us(">"));
if ((cl = string_len(ITEM.comment))) {
int i;
add_ascii_to_string(result,s2us(" ("));
for (i = 0; i < cl; i++) {
uint16 code = give_unicode_from_string(ITEM.comment,i);
/* No fancy quotation stuff on textual form for editing */
switch(code) {
case 0x0022 /* '"' */:
case 0x005C /* '\\' */:
case 0x0028 /* '(' */:
case 0x0029 /* ')' */:
case 0x003A /* ':' */:
case 0x003C /* '<' */:
case 0x003E /* '>' */:
code = '_';
break;
}
add_unicode_to_string(result,1,&code);
}
add_ascii_to_string(result,s2us(")"));
}
return result;
}
void expanded_address_from_items(result,TMP)
struct expanded_address *result;
struct addr_item *TMP;
{
int j;
if (!TMP)
return;
for (j = 0; TMP[j].addr && TMP[j].fullname; j++) {
int pos = add_expanded_addr_(result,
TMP[j].addr,
TMP[j].fullname,
TMP[j].comment);
struct string *s = make_surface_addr(TMP[j]);
add_textual_addr_(result,s,pos,1);
free_string(&s);
}
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_from_hdr;
#endif
int add_from_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
struct addr_item * TMP;
TMP = break_down_address(value,demime,defcharset);
if (replace)
free_expanded_address(&(headers->from));
expanded_address_from_items(&(headers->from), TMP);
free_addr_items(TMP);
return 1;
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_to_hdr;
#endif
int add_to_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
struct addr_item * TMP;
TMP = break_down_address(value,demime,defcharset);
if (replace)
free_expanded_address(&(headers->to));
expanded_address_from_items(&(headers->to), TMP);
free_addr_items(TMP);
return 1;
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_cc_hdr;
#endif
int add_cc_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
struct addr_item * TMP;
TMP = break_down_address(value,demime,defcharset);
if (replace)
free_expanded_address(&(headers->cc));
expanded_address_from_items(&(headers->cc), TMP);
free_addr_items(TMP);
return 1;
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_bcc_hdr;
#endif
int add_bcc_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
int j;
struct addr_item * TMP;
TMP = break_down_address(value,demime,defcharset);
if (replace)
free_expanded_address(&(headers->bcc));
expanded_address_from_items(&(headers->bcc), TMP);
free_addr_items(TMP);
return 1;
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_replyto_hdr;
#endif
int add_replyto_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
int j;
struct addr_item * TMP;
TMP = break_down_address(value,demime,defcharset);
if (replace)
free_expanded_address(&(headers->reply_to));
expanded_address_from_items(&(headers->reply_to), TMP);
free_addr_items(TMP);
return 1;
}
#if ANSI_C
static env_from_change_hook dummy_env_from_change;
#endif
static int dummy_env_from_change P_((struct mailer_env_from *X,
const char * value));
static int dummy_env_from_change(X,value)
struct mailer_env_from *X;
const char * value;
{
return 0;
}
static env_from_change_hook * ef_hook = &dummy_env_from_change;
void set_env_from_change_hook(hook)
env_from_change_hook *hook;
{
ef_hook = hook;
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_env_from_hdr;
#endif
int add_env_from_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
int ret = 0;
if (0 == strcmp(value,"<>")) {
ret = ef_hook(headers->env_from,value);
} else {
struct addr_item * TMP;
TMP = break_down_address(value,demime,defcharset);
if (TMP[0].addr && headers->env_from) {
char * t = elm_message(FRM("<%s>"),TMP[0].addr);
ret = ef_hook(headers->env_from,t);
free(t);
}
free_addr_items(TMP);
}
return ret;
}
/* This replaces always */
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_subject_hdr;
#endif
int add_subject_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
if (headers->subject)
free_string( & (headers->subject) );
headers->subject =
hdr_to_string(HDR_TEXT,value,defcharset,demime);
return 1;
}
#ifdef ANSI_C
hdr_add_to_mailing_hdr add_user_hdr;
#endif
int add_user_hdr(headers,X,value,demime,defcharset,replace)
struct mailing_headers * headers;
header_ptr X;
CONST char *value;
int demime;
charset_t defcharset;
int replace;
{
if (replace) {
/* Only replace header with same name */
int i;
int count = 0;
for (i = 0; i < headers->user_header_count; i++) {
if (X == headers->user_header[i].name) {
if (headers->user_header[i].value)
free_string(&(headers->user_header[i].value));
headers->user_header[i].name = NULL;
} else {
headers->user_header[count] = headers->user_header[i];
if (count != i) {
headers->user_header[i].value = NULL;
headers->user_header[i].name = NULL;
}
count++;
}
}
headers->user_header_count = count;
}
headers->user_header = safe_realloc(headers->user_header,
(headers->user_header_count +1) *
sizeof (headers->user_header[0]));
headers->user_header[headers->user_header_count].name = X;
headers->user_header[headers->user_header_count].value =
hdr_to_string(HDR_TEXT,value,defcharset,demime);
headers->user_header_count++;
return 1;
}
void dump_expanded_address(debuglevel,text,expanded)
int debuglevel;
CONST char *text;
struct expanded_address expanded;
{
struct textual *ptr;
int l = strlen(text);
int LASTPOS = -1;
DPRINT(Debug,debuglevel,
(&Debug,
"%s: %d surfaces, %d addresses\n",
text, expanded.surface_len, expanded.addrs_len));
for (ptr = expanded.surface;
ptr < expanded.surface + expanded.surface_len;
ptr++) {
int j;
if (!ptr->Textual) {
DPRINT(Debug,debuglevel,
(&Debug,
"%*s [%d] surface NULL! \t(%d addresses)\n",
l,"",ptr-expanded.surface,ptr->len));
} else {
DPRINT(Debug,debuglevel,
(&Debug,
"%*s [%d] surface=%S \t(%d addresses)\n",
l,"",ptr-expanded.surface,ptr->Textual,
ptr->len));
}
if (ptr->pos != LASTPOS + 1) {
DPRINT(Debug,debuglevel,
(&Debug,
"%*s [%d] ERROR! address pos = %d != %d (lastpost +1)\n",
l,"",ptr-expanded.surface, ptr->pos, LASTPOS+1));
}
for (j = 0; j < ptr->len; j++) {
if (ptr->pos+j < 0 || ptr->pos+j >= expanded.addrs_len) {
DPRINT(Debug,debuglevel,
(&Debug,
"%*s %d [%d] ERROR, not range 0 - %d\n",
l,"",j,ptr->pos,
expanded.addrs_len-1));
} else {
CONST struct addr_item *ptr1 = & (expanded.addrs[ptr->pos+j]);
if (!ptr1->addr || !ptr1->fullname || !ptr1->comment) {
DPRINT(Debug,debuglevel,
(&Debug,
"%*s %d [%d] ERROR! NULL element!\n",
l,"",j,ptr->pos+j));
} else {
CONST char *A, *B;
DPRINT(Debug,debuglevel,
(&Debug,
"%*s %d [%d] addr=%s \tfullname=%S\tcomment=%S\n",
l,"",j,ptr->pos+j,
ptr1->addr,ptr1->fullname,
ptr1->comment));
A = get_string_MIME_name(ptr1->fullname);
B = get_string_lang(ptr1->fullname);
DPRINT(Debug,debuglevel,
(&Debug,
"%*s fullname cs=%s lang=%s, ",
l,"",
A ? A : "<none>",
B ? B : "<none>"));
A = get_string_MIME_name(ptr1->comment);
B = get_string_lang(ptr1->comment);
DPRINT(Debug,debuglevel,
(&Debug,"comment cs=%s lang=%s\n",
A ? A : "<none>",
B ? B : "<none>"));
}
LASTPOS = ptr->pos+j;
}
}
}
DPRINT(Debug,debuglevel,
(&Debug,
"%*s === end\n",l,""));
}
/* Returns either backquote replaced string or original
if return value != buffer, value is malloced
*/
static char * eval_backquote P_((char *buffer));
static char * eval_backquote(buffer)
char *buffer;
{
char *ptr ;
char *result = NULL;
char *x1 = buffer;
char *cptr = NULL;
int quitflag = 0;
DPRINT(Debug,8,(&Debug, "eval_backquote: %s\n",
buffer));
for (ptr = buffer; (*ptr || result) && !quitflag; ptr++) {
if ('`' == *ptr || !*ptr) {
char * start = cptr ? cptr : x1;
int len;
char * clip;
quitflag = !*ptr;
if (!start)
panic("HEADERS PANIC",__FILE__,__LINE__,"eval_backquote",
"No start pointer",0);
len = ptr - start;
if (len < 0)
panic("HEADERS PANIC",__FILE__,__LINE__,"eval_backquote",
"Bad start pointer",0);
clip = safe_malloc(len+1);
memcpy(clip,start,len);
clip[len] = '\0';
DPRINT(Debug,11,(&Debug, "eval_backquote: clip(len=%d)=%s\n",
len,clip));
if (!cptr) {
/* Got start of command */
result = strmcat(result,clip);
cptr = ptr +1;
x1 = NULL;
free(clip);
continue;
}
if (len > 0) {
struct run_state RS;
CONST char * argv[4];
int retcode;
char local_buffer[80];
char * sh = give_dt_estr_as_str(&shell_e,"shell");
int n;
int res;
if (!sh)
sh = "/bin/sh";
DPRINT(Debug,5,(&Debug, "eval_backquote: command: %s\n",
clip));
argv[0] = sh;
argv[1] = "-c";
argv[2] = clip;
argv[3] = NULL;
res = start_run(&RS,
SY_ENAB_SIGHUP|SY_ENAB_SIGINT|
SY_RUN_STATE_OPIPE,argv,-1,-1);
if (0 == res) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeBackquoteCmdFailed,
"Backquoted command \"%s\" in elmheaders failed."),
clip);
free(clip);
free(result);
DPRINT(Debug,5,(&Debug,
"eval_backquote: start_run failed\n"));
return NULL;
}
while (0 < (n =
mail_gets(local_buffer, sizeof local_buffer,
RS.pfd))) {
DPRINT(Debug,5,(&Debug,
"eval_backquote: output: %s",
local_buffer));
if (local_buffer[n-1] != '\n') {
DPRINT(Debug,5,(&Debug,
"<-- no NEWLINE\n"));
}
result = strmcat(result,local_buffer);
}
if (result && 0 < (n = strlen(result)) &&
'\n' == result[n-1]) {
result[n-1] = '\0';
DPRINT(Debug,5,(&Debug,
"... Removed newline from end of result\n"));
}
res = wait_end(&RS,&retcode);
if (res < 0 || retcode != 0) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeBackquoteCmdFailed,
"Backquoted command \"%s\" in elmheaders failed."),
clip);
free(clip);
free(result);
DPRINT(Debug,5,(&Debug,
"eval_backquote: command failed: res=%d, retcode=%d\n",
res,retcode));
return NULL;
}
}
x1 = ptr +1;
cptr = NULL;
free(clip);
}
}
if (result) {
DPRINT(Debug,8,(&Debug, "eval_backquote: result=%s\n",
result));
}
return result ? result : buffer;
}
void import_mailheaders(headers)
struct mailing_headers * headers;
{
int err;
FILE *F;
char buffer[32*1024];
if (0 != (err = can_open(user_mailheaders,"r"))) {
DPRINT(Debug,5,(&Debug, "%s not available: %s (errno=%d)\n",
user_mailheaders,error_description(err),err));
return;
}
F = fopen(user_mailheaders,"r");
if (!F) {
/* In than point opening should have succeed */
int err = errno;
lib_error(FRM("%s: %s"),user_mailheaders,err);
return;
}
while (0 < read_header_line(F,buffer,sizeof buffer,0)) {
header_ptr header_name;
char *k;
char * value1 = NULL;
value1 = eval_backquote(buffer);
if (!value1)
continue;
k = strchr(value1,':');
if (!k)
break;
*k = '\0';
k++;
while (whitespace(*k))
k++;
header_name = find_header(value1,1);
if (!add_to_mailing_header(headers,header_name,k,
!allow_no_hdrencoding,
system_charset,0)) {
/* TODO: Notice failure ... */
}
if (value1 != buffer)
free(value1);
}
fclose(F);
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1