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 (was hurtta+elm@ozone.FMI.FI) *****************************************************************************/ #include "headers.h" #include "hdr_imp.h" #include "s_me.h" #include #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 : "", B ? B : "")); 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 : "", B ? B : "")); } 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: */