static char rcsid[] = "@(#)$Id: mime_param.c,v 1.18 2006/05/07 08:35:31 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.18 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* or Kari Hurtta <elm@elmme-mailer.org>
*****************************************************************************/
#include "def_melib.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"mime");
static void free_parsed P_((struct mime_param *P));
static void free_parsed(P)
struct mime_param *P;
{
if (P->ascii_params) {
int i;
for (i = 0; i < P->ascii_param_count; i++) {
if (P->ascii_params[i].param) {
free(P->ascii_params[i].param);
P->ascii_params[i].param = NULL;
}
if (P->ascii_params[i].value) {
free(P->ascii_params[i].value);
P->ascii_params[i].value = NULL;
}
}
free(P->ascii_params);
P->ascii_params = NULL;
}
P->ascii_param_count =0;
if (P->string_params) {
int i;
for (i = 0; i < P->string_param_count; i++) {
if (P->string_params[i].param) {
free(P->string_params[i].param);
P->string_params[i].param = NULL;
}
if (P->string_params[i].value) {
free_string(& (P->string_params[i].value));
}
}
free(P->string_params);
P->string_params = NULL;
}
P->string_param_count =0;
}
static void free_raw P_((struct mime_param *P));
static void free_raw(P)
struct mime_param *P;
{
if (P->params) {
int i;
for (i = 0; i < P->param_count; i++) {
if (P->params[i].raw_param) {
free(P->params[i].raw_param);
P->params[i].raw_param = NULL;
}
if (P->params[i].raw_value) {
free(P->params[i].raw_value);
P->params[i].raw_value = NULL;
}
}
free(P->params);
P->params = NULL;
}
P->param_count =0;
}
void free_mime_param(x)
struct mime_param **x;
{
struct mime_param *P = *x;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"free_mime_param",
"Bad magic number");
free_raw(P);
free_parsed(P);
free(P);
P = NULL;
*x = P;
}
static struct mime_param * alloc_mime_param P_((void));
static struct mime_param * alloc_mime_param()
{
struct mime_param *P = safe_malloc(sizeof (*P));
bzero((void *)P, sizeof (*P));
P->magic = MIME_PARAM_magic;
P->params = NULL;
P->param_count = 0;
P->def = NULL;
P->ascii_params = NULL;
P->ascii_param_count = 0;
P->string_params = NULL;
P->string_param_count = 0;
return P;
}
struct mime_param * copy_mime_param(src)
struct mime_param *src;
{
struct mime_param *P = alloc_mime_param();
P->def = src->def;
if (src->params) {
int i;
P->params = safe_malloc(src->param_count * sizeof (P->params[0]));
for (i = 0; i < src->param_count; i++) {
if (src->params[i].raw_param)
P->params[i].raw_param = safe_strdup(src->params[i].raw_param);
if (src->params[i].raw_value)
P->params[i].raw_value = safe_strdup(src->params[i].raw_value);
}
P->param_count = src->param_count;
}
/* These params are rebuild from raw params */
P->ascii_params = NULL;
P->ascii_param_count = 0;
P->string_params = NULL;
P->string_param_count = 0;
return P;
}
static struct ascii_pair * add_ascii_pair_1 P_((struct ascii_pair **list, int *len));
static struct ascii_pair * add_ascii_pair_1(list,len)
struct ascii_pair **list;
int *len;
{
struct ascii_pair * ascii_params = *list;
int ascii_param_count = *len;
struct ascii_pair * ret = NULL;
ascii_params = safe_realloc(ascii_params,
(ascii_param_count+1) *
sizeof(ascii_params[0]));
bzero((void *)& (ascii_params[ascii_param_count]),
sizeof ((ascii_params[ascii_param_count])));
ascii_params[ascii_param_count].is_compat = 0;
ascii_params[ascii_param_count].param = NULL;
ascii_params[ascii_param_count].value = NULL;
ret = (&(ascii_params[ascii_param_count++]));
*list = ascii_params;
*len = ascii_param_count;
return ret;
}
static struct ascii_pair * add_ascii_pair P_((struct mime_param *P));
static struct ascii_pair * add_ascii_pair(P)
struct mime_param *P;
{
return add_ascii_pair_1( & (P->ascii_params),
& (P->ascii_param_count) );
}
static struct string_pair * add_string_pair_1 P_((struct string_pair **list,
int *len));
static struct string_pair * add_string_pair_1(list,len)
struct string_pair **list;
int *len;
{
struct string_pair *ret;
struct string_pair * string_params = *list;
int string_param_count = *len;
string_params = safe_realloc(string_params,
(string_param_count +1) *
sizeof(string_params[0]));
bzero((void *)& (string_params[string_param_count]),
sizeof ((string_params[string_param_count])));
string_params[string_param_count].param = NULL;
string_params[string_param_count].value = NULL;
ret = (&(string_params[string_param_count++]));
*list = string_params;
*len = string_param_count;
return ret;
}
static struct string_pair * add_string_pair P_((struct mime_param *P));
static struct string_pair * add_string_pair(P)
struct mime_param *P;
{
return add_string_pair_1 (& (P->string_params),
& (P->string_param_count));
}
static struct mp_pair * add_mp_pair_1 P_((struct mp_pair **list, int *len));
static struct mp_pair * add_mp_pair_1(list,len)
struct mp_pair **list;
int *len;
{
struct mp_pair *params = *list;
int param_count = *len;
struct mp_pair *ret = NULL;
params = safe_realloc(params,
(param_count +1) * sizeof (params[0]));
bzero ((void *) &(params[param_count]), sizeof (params[param_count]));
params[param_count].raw_param = NULL;
params[param_count].raw_value = NULL;
ret = (& (params[ param_count++]));
*list = params;
*len = param_count;
return ret;
}
static unsigned char * us_str P_((char *str));
static unsigned char * us_str(str)
char *str;
{
return (unsigned char *)str;
}
static struct mp_pair * add_mp_pair P_((struct mime_param *P));
static struct mp_pair * add_mp_pair(P)
struct mime_param *P;
{
return add_mp_pair_1(& (P->params), &(P->param_count));
}
static int append_encoded P_((struct string *buffer,char *value));
static int append_encoded(buffer,value)
struct string *buffer;
char *value;
{
unsigned char *p;
for (p = us_str(value); *p; p++) {
if ('\'' == *p || '"' == *p) {
DPRINT(Debug,9,(&Debug,
"append_encoded: bad character %c, value=%s\n",
*p,value));
return 0;
}
if ('%' == *p) {
int v1, v2;
unsigned char v;
p++;
if (! *p) {
DPRINT(Debug,9,(&Debug,
"append encoded: short %% sequence, value=%s\n",
value));
return 0;
}
v1 = hex(*p);
p++;
if (! *p) {
DPRINT(Debug,9,(&Debug,
"append encoded: short %% sequence, value=%s\n",
value));
return 0;
}
v2 = hex(*p);
if (v1 < 0 || v2 < 0) {
DPRINT(Debug,9,(&Debug,
"append encoded: bad %% sequence, value=%s\n",
value));
return 0;
}
v = ( v1 << 4) | v2;
if (! add_streambyte_to_string(buffer,v)) {
DPRINT(Debug,9,(&Debug,
"append encoded: bad character %%%02x, value=%s\n",
v,value));
return 0;
}
} else {
if (! add_streambyte_to_string(buffer,(unsigned char)*p)) {
DPRINT(Debug,9,(&Debug,
"append encoded: bad character %c, value=%s\n",
*p,value));
return 0;
}
}
}
return 1;
}
static struct string * parse_encoded_first P_((char *value));
static struct string * parse_encoded_first(value)
char *value;
{
struct string *ret = NULL;
int l = strlen(value);
char * buffer = safe_malloc(l+1);
char * lang = NULL;
char * cs = NULL;
charset_t cs1 = NULL;
int count = 0;
char *p1,*p2;
/* character set */
cs = buffer;
for (p1 = value, p2 =buffer;
*p1 && '\'' != *p1 && p2 <= buffer + l;
p1++) {
*p2++ = *p1;
}
*p2 = '\0';
if ('\'' != *p1) {
DPRINT(Debug,9,(&Debug, "parse_encoded_first: Missing ': %s\n",value));
goto fail;
}
p1++;
if (p2 == cs)
cs = NULL;
/* language */
p2++;
lang = p2;
for (;
*p1 && '\'' != *p1 && p2 <= buffer + l;
p1++) {
*p2++ = *p1;
}
*p2 = '\0';
if ('\'' != *p1) {
DPRINT(Debug,9,(&Debug, "parse_encoded_first: Missing second ': %s\n",
value));
goto fail;
}
p1++;
if (p2 == lang)
lang = NULL;
if (cs) {
DPRINT(Debug,9,(&Debug, "parse_encoded_first: cs=%s\n",cs));
cs1 = MIME_name_to_charset(cs,CHARSET_create);
} else
cs1 = RAW_BUFFER; /* charset is not relevant to parameter value! */
if (lang) {
DPRINT(Debug,9,(&Debug, "parse_encoded_first: lang=%s\n",lang));
ret = new_langstring(cs1,lang);
} else
ret = new_string(cs1);
if (!append_encoded(ret,p1)) {
DPRINT(Debug,9,(&Debug,
"parse_encoded_first: parse error .. ignoring result\n"));
free_string(&ret);
}
fail:
free(buffer);
return ret;
}
#define MAX_POSITIONAL 100
static void parse_raw_params P_((struct mime_param *P));
static void parse_raw_params(P)
struct mime_param *P;
{
struct positional_params {
char *name;
int bad;
struct loc_pos {
int is_new;
int loc;
} *locations ;
int location_count;
} * positional = NULL;
int positional_count = 0;
free_parsed(P);
/* Pass 1 look item 0 on parameters */
if (P->params) {
int i;
for (i = 0; i < P->param_count; i++) {
char * name = P->params[i].raw_param;
char * p;
if (!name)
continue;
if (!name[0]) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: parameter without name\n",
i));
continue;
}
for (p = name; *p; p++) {
if ('*' == *p)
break;
}
if ('\0' == *p) {
char *x;
/* compat parameter */
/* Check for 8-bit */
if (! P->params[i].raw_value) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: compat parameter without value\n",
i,name));
continue;
}
for (x = P->params[i].raw_value; *x; x++) {
if (0 != (*x & 0x80))
break;
}
if ('\0' == *x) {
/* Ascii value -- really compat */
struct ascii_pair * A = add_ascii_pair(P);
int l = x - P->params[i].raw_value;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,name,P->params[i].raw_value));
A->is_compat = 1;
A->param = safe_strdup(name);
A->value = dequote_opt(P->params[i].raw_value,l);
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [compat] %s=%s\n",
A->param,
A->value));
} else {
struct string_pair * S = add_string_pair(P);
char * val;
int l;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: 8-bit data on compat parameter\n",
i,name));
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,name,P->params[i].raw_value));
if (! P->def ) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: NO DEFAULT CHARSET -- parameter ignored\n"));
continue;
}
S->param = safe_strdup(name);
while (*x)
x++;
l = x - P->params[i].raw_value;
val = dequote_opt(P->params[i].raw_value,l);
S->value = new_string2(P->def,us_str(val));
free(val);
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [8-bit] %s=%S\n",
S->param,
S->value));
}
} else {
int is_new = 0;
int is_partial = 0;
int index = 0;
int l = p - name;
char * name1 = safe_malloc(l+1);
strncpy(name1,name,l);
name1[l] = '\0';
p++;
if ('\0' == *p ) {
/* '*' was last character on name */
is_new = 1;
} else if (*p >= '0' && *p <= '9') {
char *end = NULL;
long x;
is_partial = 1;
x= strtol(p,&end,10);
if (x > MAX_POSITIONAL) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: On paramater %s postion value %ld is too big (max %d)\n",
i,name,name1,x,
MAX_POSITIONAL));
goto fail1;
}
index = x;
if ('\0' != *end &&
'*' != *end) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: On paramater %s after position value %ld there is garbage: %s\n",
i,name,name1,x,end));
goto fail1;
}
p = end;
}
if ('*' == *p) {
is_new = 1;
p++;
}
if (*p) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: On paramater %s there is garbage after '*': %s\n",
i,name,name1,p));
goto fail1;
}
if (is_partial) {
int x;
for (x = 0; x < positional_count; x++) {
if (0 == istrcmp(name1,positional[x].name))
break;
}
if (x >= positional_count) {
positional = safe_realloc(positional,
(x+1) * sizeof(positional[0]));
positional[x].name = name1; name1 = NULL;
positional[x].bad = 0;
positional[x].locations = NULL;
positional[x].location_count = 0;
positional_count = x+1;
}
if (index >= positional[x].location_count) {
int y;
positional[x].locations = safe_realloc(positional[x].locations,
(index+1) *
sizeof(positional[x].locations[0]));
for (y = positional[x].location_count; y <= index; y++) {
positional[x].locations[y].is_new = 0;
positional[x].locations[y].loc = -1;
}
positional[x].location_count = index+1;
}
if (index < 0) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: On paramater %s position value %ld is negative\n",
i,name,positional[x].name,index));
positional[x].bad = 1;
goto fail1;
}
if (positional[x].locations[index].loc != -1) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: On paramater %s position value %ld is duplicate\n",
i,name,positional[x].name,index));
positional[x].bad = 1;
goto fail1;
}
positional[x].locations[index].loc = i;
positional[x].locations[index].is_new = is_new;
} else {
/* Not a partial value */
char *value = P->params[i].raw_value;
struct string * X;
struct string_pair * S;
if (!is_new)
mime_panic(__FILE__,__LINE__,"parse_raw_params",
"compat parameters should be handled already");
if (! value) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %d: %s: parameter %s without value\n",
i,name,name1));
goto fail1;
}
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,name,P->params[i].raw_value));
X = parse_encoded_first(value);
if (!X) {
goto fail1;
}
S = add_string_pair(P);
S->param = name1; name1 = NULL;
S->value = X;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [string] %s=%S\n",
S->param,
S->value));
}
fail1:
if (name1)
free(name1);
}
}
}
/* Pass 2 look positional arguments */
if (positional) {
int x;
for (x = 0; x < positional_count; x++) {
int y;
int new_seen = 0;
for (y = 0; y < positional[x].location_count; y++) {
if (positional[x].locations[y].loc == -1) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: On paramater %s position value %d is missing\n",
positional[x].name,y));
positional[x].bad = 1;
break;
}
if (positional[x].locations[y].loc < 0 ||
positional[x].locations[y].loc >= P->param_count)
mime_panic(__FILE__,__LINE__,"parse_raw_params",
"Bad location index");
new_seen |= positional[x].locations[0].is_new;
}
if (positional[x].location_count < 1)
mime_panic(__FILE__,__LINE__,"parse_raw_params",
"Inbossible location count");
if (positional[x].bad)
continue;
if (new_seen) {
struct string_pair * S = NULL;
/* Handle first parameter */
if (positional[x].locations[0].is_new) {
int i = positional[x].locations[0].loc;
char *value = P->params[i].raw_value;
struct string * X;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,
P->params[i].raw_param,
P->params[i].raw_value));
X = parse_encoded_first(value);
if (!X) {
goto fail2;
}
S = add_string_pair(P);
S->param = safe_strdup(positional[x].name);
S->value = X;
} else {
int i = positional[x].locations[0].loc;
char *value = P->params[i].raw_value;
int l = strlen(value);
char *val;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,
P->params[i].raw_param,
P->params[i].raw_value));
val = dequote_opt(value,l);
S = add_string_pair(P);
S->param = safe_strdup(positional[x].name);
/* FIXME ??? Is this correct ??? */
S->value = new_string2(RAW_BUFFER,us_str(val));
free(val);
}
/* Handle rest of parameters */
for (y = 1; y < positional[x].location_count; y++) {
int i = positional[x].locations[y].loc;
char *value = P->params[i].raw_value;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,
P->params[i].raw_param,
P->params[i].raw_value));
if (positional[x].locations[x].is_new) {
if (!append_encoded(S->value,value))
goto failX;
} else {
char * val;
int l1;
int errors = 0;
int l = strlen(value);
val = dequote_opt(value,l);
l1 = strlen(val);
if (!add_streambytes_to_string(S->value,l1,us_str(val),&errors)) {
free(val);
goto failX;
}
free(val);
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [added %d] %s=%S\n",
x,
S->param,
S->value));
}
}
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [splitted string] %s=%S\n",
S->param,
S->value));
if (0) {
failX:
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %s: Failed to parse value\n",
S->param));
free_string(& (S->value));
}
} else {
struct ascii_pair * A = add_ascii_pair(P);
char *p;
A->is_compat = 0;
A->param = safe_strdup(positional[x].name);
A->value = NULL;
for (y = 0; y < positional[x].location_count; y++) {
int i = positional[x].locations[y].loc;
char *value = P->params[i].raw_value;
int l = strlen(value);
char *val;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: *** %d: %s=%s\n",
i,
P->params[i].raw_param,
P->params[i].raw_value));
if (positional[x].locations[x].is_new)
mime_panic(__FILE__,__LINE__,"parse_raw_params",
"Inbossible encoding");
val = dequote_opt(value,l);
A->value = strmcat(A->value,val);
free(val);
}
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [splitted ascii] %s=%s\n",
A->param,
A->value));
for (p = A->value; *p; p++) {
if (0 != (*p & 0x80))
break;
}
if (*p) {
struct string_pair * S;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: %s: 8-bit data on parameter\n",
A->param));
if (! P->def ) {
DPRINT(Debug,9,(&Debug,
"parse_raw_params: NO DEFAULT CHARSET -- parameter ignored\n"));
/* Destroy non-ascii value */
free(A->value); A->value = NULL;
continue;
}
S = add_string_pair(P);
S->param = safe_strdup(A->param);
S->value = new_string2(P->def,us_str(A->value));
/* Destroy non-ascii value */
free(A->value); A->value = NULL;
DPRINT(Debug,9,(&Debug,
"parse_raw_params: [fixup string] %s=%S\n",
S->param,
S->value));
}
}
fail2: ;
}
}
/* Cleanup */
if (positional) {
int i;
for (i = 0; i < positional_count; i++) {
if (positional[i].locations) {
free(positional[i].locations);
positional[i].locations = NULL;
}
positional[i].location_count = 0;
}
free(positional);
}
}
struct mime_param * parse_mime_param(headername,value,def,header_error)
CONST char *headername;
CONST char *value;
charset_t def;
struct header_errors **header_error;
{
CONST char *ptr;
struct mime_param *P = alloc_mime_param();
DPRINT(Debug,9,(&Debug,"parse_mime_param: headername=%s value=%s\n",
headername ? headername : "<not given>",
value));
P->def = def;
/* It is assumed that comments are already removed
with rfc822_reap_comments()
*/
for (ptr = value; *ptr; ) {
CONST char * start;
CONST char * last;
int len;
struct mp_pair * mp = NULL;
while (*ptr && isascii(*ptr) && isspace(*ptr))
ptr++;
if (!*ptr)
break ;
start = ptr;
last = NULL;
/* Get param name */
while (*ptr) {
if (isascii(*ptr) && isspace(*ptr)) {
if (!last)
last = ptr;
} else if ('=' == *ptr) {
if (!last)
last = ptr;
break;
} else if ('"' == *ptr) {
if (!last)
last = ptr;
break;
} else if (';' == *ptr) {
if (!last)
last = ptr;
break;
} else if (last) {
break;
}
ptr++;
}
if (!last)
last = ptr;
while (*ptr && isascii(*ptr) && isspace(*ptr))
ptr++;
if ('=' == *ptr)
ptr++;
else {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeMissingEqual,
"PARSE ERROR: Missing = on %s header"),
headername);
}
if (last == start) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeMissingName,
"PARSE ERROR: Missing name of param on %s header"),
headername);
}
len = last-start;
mp = add_mp_pair(P);
mp->raw_param = safe_malloc(len+1);
strncpy(mp->raw_param,start,len);
mp->raw_param[len] = '\0';
DPRINT(Debug,9,(&Debug,"parse_mime_param: [%d] param=%s\n",
P->param_count-1,mp->raw_param));
while (*ptr && isascii(*ptr) && isspace(*ptr))
ptr++;
start = ptr;
last = NULL;
if ('"' == *ptr) {
ptr++;
while (*ptr && '"' != *ptr) {
if ('\\' == *ptr) {
ptr++;
if (!*ptr) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeTrailingBackslashHeader,
"PARSE ERROR: Trailing \\ on %s header"),
headername);
break;
}
}
ptr++;
}
if ('"' != *ptr) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeMissingQuote,
"PARSE ERROR: Missing ending \" on %s header"),
headername);
} else
ptr++;
} else {
while (*ptr) {
if (isascii(*ptr) && isspace(*ptr)) {
if (!last)
last = ptr;
} else if ('=' == *ptr) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeEqualOnValue,
"PARSE ERROR: Missing ; or = on param value on %s header"),
headername);
} else if ('"' == *ptr) {
if (!last)
last = ptr;
break;
} else if (';' == *ptr) {
if (!last)
last = ptr;
break;
} else if (last) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeSpaceOnValue,
"PARSE ERROR: Missing ; or space on param value on %s header"),
headername);
last = NULL;
}
ptr++;
}
}
if (!last)
last = ptr;
while (*ptr && isascii(*ptr) && isspace(*ptr))
ptr++;
if (';' == *ptr)
ptr++;
else if (*ptr) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeMissingSemicolonHeader,
"PARSE ERROR: Missing ; on %s header"),
headername);
}
if (last == start) {
if (headername)
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeMissingValue,
"PARSE ERROR: Missing value of param on %s header"),
headername);
}
len = last-start;
mp->raw_value = safe_malloc(len+1);
strncpy(mp->raw_value,start,len);
mp->raw_value[len] = '\0';
DPRINT(Debug,9,(&Debug,"parse_mime_param: [%d] value=%s\n",
P->param_count-1,mp->raw_value));
}
return P;
}
static CONST char *find_ascii_param P_((struct mime_param *P,
char *name,
int compat));
static CONST char *find_ascii_param(P,name,compat)
struct mime_param *P;
char *name;
int compat;
{
int i;
for (i = 0; i < P->ascii_param_count; i++) {
if (P->ascii_params[i].is_compat == compat &&
P->ascii_params[i].param &&
0 == istrcmp(P->ascii_params[i].param,name))
return P->ascii_params[i].value;
}
return NULL;
}
static CONST struct string *find_string_param P_((struct mime_param *P,
char *name));
static CONST struct string *find_string_param(P,name)
struct mime_param *P;
char *name;
{
int i;
for (i = 0; i < P->string_param_count; i++) {
if (P->string_params[i].param &&
0 == istrcmp(P->string_params[i].param,name))
return P->string_params[i].value;
}
return NULL;
}
CONST char * get_mime_param_compat(P,name)
struct mime_param *P;
char *name;
{
if (!P)
return NULL;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"get_mime_param_compat",
"Bad magic number");
if (! P->ascii_params && ! P->string_params)
parse_raw_params(P);
if (P->ascii_params)
return find_ascii_param(P,name,1);
DPRINT(Debug,9,(&Debug, "get_mime_param_compat: No parameters\n"));
return NULL;
}
CONST char * get_mime_param_ascii(P,name)
struct mime_param *P;
char *name;
{
int i;
if (!P)
return NULL;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"get_mime_param_ascii",
"Bad magic number");
if (! P->ascii_params && ! P->string_params)
parse_raw_params(P);
if (P->ascii_params) {
CONST char *found = find_ascii_param(P,name,0);
if (found)
return found;
return find_ascii_param(P,name,1);
}
DPRINT(Debug,9,(&Debug, "get_mime_param_ascii: No parameters\n"));
return NULL;
}
static CONST unsigned char * cus_str P_((const char *str));
static CONST unsigned char * cus_str(str)
CONST char *str;
{
return (CONST unsigned char *)str;
}
CONST struct string * get_mime_param(P,name)
struct mime_param *P;
char *name;
{
if (!P)
return NULL;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"get_mime_param",
"Bad magic number");
if (! P->ascii_params && ! P->string_params)
parse_raw_params(P);
if (P->string_params) {
CONST struct string *found = find_string_param(P,name);
if (found)
return found;
}
if (P->ascii_params) {
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
CONST char *found = find_ascii_param(P,name,0);
struct string_pair *S;
if (!found)
found = find_ascii_param(P,name,1);
if (!found)
return NULL;
if (!ascii_ptr)
mime_panic(__FILE__,__LINE__,"get_mime_param",
"US-ASCII not found");
S = add_string_pair(P);
S->param = safe_strdup(name);
S->value = new_string2(ascii_ptr,cus_str(found));
return S->value;
}
DPRINT(Debug,9,(&Debug, "get_mime_param: No parameters\n"));
return NULL;
}
static int ascii_need_quote P_((char *value));
static int ascii_need_quote(value)
char *value;
{
char *p;
if (! value[0])
return 1;
for (p = value; *p; p++) {
if (*p <= ' ')
return 1;
if (*p >= '"' &&
*p <= '/')
return 1;
if (*p >= ':' &&
*p <= '?')
return 1;
if (*p == '\\')
return 1;
}
return 0;
}
static int string_is_ascii_control P_((struct string * value));
static int string_is_ascii_control(value)
struct string * value;
{
int len = string_len(value);
int i;
for (i = 0; i < len; i++) {
uint16 code = give_unicode_from_string(value,i);
if (code <= 0x0020 /* space */ )
return 1;
if (code >= 0x007F /* DEL */)
return 1;
}
return 0;
}
static int string_need_quote P_((struct string * value));
static int string_need_quote(value)
struct string * value;
{
int len = string_len(value);
int i;
if (0 == len)
return 1;
for (i = 0; i < len; i++) {
uint16 code = give_unicode_from_string(value,i);
if (code <= 0x0020 /* space */ )
return 1;
if (code >= 0x0022 /* " */ &&
code <= 0x002F /* / */)
return 1;
if (code >= 0x003A /* : */ &&
code >= 0x003F /* ? */)
return 1;
switch(code) {
case 0x005C /* \ */:
return 1;
}
}
return 0;
}
static void append_quoted_to_string P_((struct string ** ret,
struct string * value));
static void append_quoted_to_string(ret,value)
struct string ** ret;
struct string * value;
{
charset_t cs = value->string_type;
int len = string_len(value);
int i;
struct string * tmp = new_string(cs);
add_ascii_to_string(tmp,us_str("\""));
for (i = 0; i < len; i++) {
uint16 code = give_unicode_from_string(value,i);
if (0x0022 /* " */ == code &&
0x005C /* \ */ == code)
add_ascii_to_string(tmp,us_str("\\"));
add_unicode_to_string(tmp,1,&code);
}
add_ascii_to_string(tmp,us_str("\""));
append_string(ret,tmp);
free_string(&tmp);
}
struct string * unquote_string P_((struct string * value));
struct string * unquote_string(value)
struct string * value;
{
charset_t cs = value->string_type;
int len = string_len(value);
int i;
int q = 0;
struct string * ret = new_string(cs);
for (i = 0; i < len; i++) {
uint16 code = give_unicode_from_string(value,i);
if (0x0022 /* " */ == code) {
q = !q;
continue;
}
/* Recognize \ escape only in quoted strings */
if (0x005C /* \ */ == code && q) {
i++;
if (i < len)
code = give_unicode_from_string(value,i);
else {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeTrailingBackslashOnString,
"Trailing Backslash (\\) on %S"),
value);
break;
}
}
add_unicode_to_string(ret,1,&code);
}
if (q)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeMissingEndQuote,
"Missing ending quote (\") on %S"),
value);
return ret;
}
static void add_param_string P_((struct string ** ret,
char *param,
struct string * value));
static void add_param_string(ret,param,value)
struct string ** ret;
char *param;
struct string * value;
{
if (*ret)
add_ascii_to_string(*ret,us_str("; "));
if (!*ret)
*ret = new_string(display_charset);
add_ascii_to_string(*ret,us_str(param));
add_ascii_to_string(*ret,us_str("="));
if (string_need_quote(value))
append_quoted_to_string(ret,value);
else
append_string(ret,value);
}
static void add_param_ascii P_((struct string ** ret,
char *param,
char * value));
static void add_param_ascii(ret,param,value)
struct string ** ret;
char *param;
char * value;
{
struct string * tmp ;
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
if (!ascii_ptr)
mime_panic(__FILE__,__LINE__,"add_param_ascii",
"US-ASCII not found");
tmp = new_string2(ascii_ptr,us_str(value));
add_param_string(ret,param,tmp);
free_string(&tmp);
}
struct string * show_mime_params(P)
struct mime_param *P;
{
struct string * ret = NULL;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"show_mime_params",
"Bad magic number");
if (! P->ascii_params && ! P->string_params)
parse_raw_params(P);
if (P->string_params) {
int i;
for (i = 0; i < P->string_param_count; i++) {
if (P->string_params[i].param &&
P->string_params[i].value)
add_param_string(&ret,P->string_params[i].param,
P->string_params[i].value);
}
}
if (P->ascii_params) {
int i;
for (i = 0; i < P->ascii_param_count; i++) {
if (!P->ascii_params[i].param)
continue;
if (find_string_param(P,P->ascii_params[i].param))
continue;
if (P->ascii_params[i].value)
add_param_ascii(&ret,P->ascii_params[i].param,
P->ascii_params[i].value);
}
}
return ret;
}
char * encode_mime_params(P)
struct mime_param *P;
{
char * ret = NULL;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"encode_mime_params",
"Bad magic number");
if (P->params) {
int i;
for (i = 0; i < P->param_count; i++) {
if (P->params[i].raw_param &&
P->params[i].raw_value) {
if (ret)
ret = strmcat(ret,"; ");
ret = strmcat(ret,P->params[i].raw_param);
ret = strmcat(ret,"=");
ret = strmcat(ret,P->params[i].raw_value);
}
}
}
return ret;
}
char ** encode_mime_params_v(P)
struct mime_param *P;
{
char ** ret = NULL;
if (MIME_PARAM_magic != P->magic)
mime_panic(__FILE__,__LINE__,"encode_mime_params",
"Bad magic number");
if (P->params) {
int i;
int X = 0;
ret = safe_malloc((P->param_count +1) * sizeof (ret[0]));
for (i = 0; i < P->param_count; i++) {
if (P->params[i].raw_param &&
P->params[i].raw_value) {
ret[X] = safe_strdup(P->params[i].raw_param);
ret[X] = strmcat(ret[X],"=");
ret[X] = strmcat(ret[X],P->params[i].raw_value);
X++;
}
}
ret[X] = NULL;
}
return ret;
}
static void gen_splitted_ascii_param P_((struct mime_param *P, char *name, char *value));
static void gen_splitted_ascii_param(P,name,value)
struct mime_param *P;
char *name;
char *value;
{
char * p, *p1;
int counter = 0;
for (p = value; *p; p = p1) {
struct mp_pair * mp = add_mp_pair(P);
char * tmp;
int len;
for (p1 = p; *p && p1-p < 70; p++)
/* nothing */;
len = p1-p;
mp->raw_param = elm_message(FRM("%s*%d"),name,counter++);
tmp = safe_malloc(len+1);
strncpy(tmp,p,len);
tmp[len] = '\0';
if (ascii_need_quote(tmp)) {
mp->raw_value = elm_message(FRM("%Q"),tmp);
free(tmp);
} else {
mp->raw_value = tmp;
}
}
if (counter == 0) {
struct mp_pair * mp = add_mp_pair(P);
mp->raw_param = elm_message(FRM("%s*%d"),name,counter++);
mp->raw_value = safe_strdup("\"\"");
}
}
static char * get_encoded P_((struct string *value));
static char * get_encoded(value)
struct string *value;
{
char * ret = NULL;
int alloclen = 0;
int len;
char * tmp;
int ok = charset_ok_p(value->string_type);
int i;
int count = 0;
CONST char *y = get_string_MIME_name(value);
if (y && (0 == istrcmp(y,"UTF-8") ||
0 == istrcmp(y,"UTF-7")))
ok = 1;
/* Allow producing \0 values also ... */
bytestream_from_string(value,&tmp,&len);
alloclen = len+10;
if (!ok)
alloclen = len*3+2;
ret = safe_malloc(alloclen);
#define ADD(x) { if (count >= alloclen) { \
alloclen += 20; ret = safe_realloc(ret,alloclen); } \
ret[count++] = (x); }
for (i = 0; i <len; i++) {
unsigned char val =tmp[i];
if (!ok || val == '%' || !isascii(val) || !isalnum(val)) {
ADD('%');
ADD(hexchars[val / 16]);
ADD(hexchars[val % 16]);
} else {
ADD(val);
}
}
ADD('\0');
#undef ADD
free(tmp);
return ret;
}
static char * get_first_encoded P_((struct string *value));
static char * get_first_encoded(value)
struct string *value;
{
CONST char *cs;
CONST char *lang;
char *ret;
char *tmp;
if (value->string_type == RAW_BUFFER) /* charset is not relevant to parameter value! */
cs = "";
else {
cs = get_string_MIME_name(value);
if (!cs || NULL != strpbrk(cs," \t\r\n()\"?*'="))
cs = "UNKNOWN-8BIT";
}
lang = get_string_lang(value);
if (!lang || NULL != strpbrk(lang," \t\r\n()\"?*'="))
lang = "";
tmp = get_encoded(value);
ret = elm_message(FRM("%s'%s'%s"),cs,lang,tmp);
free(tmp);
return ret;
}
static void gen_string_param P_((struct mime_param *P, char *name,
struct string *value));
static void gen_string_param(P,name,value)
struct mime_param *P;
char *name;
struct string * value;
{
struct mp_pair * mp = add_mp_pair(P);
mp->raw_param = elm_message(FRM("%s*"),name);
mp->raw_value = get_first_encoded(value);
DPRINT(Debug,9,(&Debug,
"gen_string_param: *** %s=%s\n",
mp->raw_param,mp->raw_value));
}
#define STRING_SPLIT_LEN 15
static void gen_splitted_string_param P_((struct mime_param *P, char *name,
struct string *value));
static void gen_splitted_string_param(P,name,value)
struct mime_param *P;
char *name;
struct string * value;
{
int len = string_len(value);
int pos = 0;
struct string *buffer;
int counter = 0;
struct mp_pair * mp = add_mp_pair(P);
buffer = clip_from_string(value,&pos,STRING_SPLIT_LEN);
mp->raw_param = elm_message(FRM("%s*%d*"),name,counter++);
mp->raw_value = get_first_encoded(buffer);
DPRINT(Debug,9,(&Debug,
"gen_splitted_string_param: *** %s=%s\n",
mp->raw_param,mp->raw_value));
free_string(&buffer);
while (pos < len) {
buffer = clip_from_string(value,&pos,STRING_SPLIT_LEN);
mp = add_mp_pair(P);
mp->raw_param = elm_message(FRM("%s*%d*"),name,counter++);
mp->raw_value = get_encoded(buffer);
DPRINT(Debug,9,(&Debug,
"gen_splitted_string_param: *** %s=%s\n",
mp->raw_param,mp->raw_value));
free_string(&buffer);
}
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static void parse_rest P_((struct mime_param *P, struct string_token *X,
int gen_compat_len,
int plain_mode));
static void parse_rest(P,X, gen_compat_len,plain_mode)
struct mime_param *P;
struct string_token *X;
int gen_compat_len;
int plain_mode;
{
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
int i = 0;
struct string_pair * tmp_list = NULL;
int tmp_list_len = 0;
struct ascii_pair * a_list = NULL;
int a_list_len = 0;
struct mp_pair * mp_list = NULL;
int mp_list_len = 0;
if (!ascii_ptr)
mime_panic(__FILE__,__LINE__,"parse_rest",
"US-ASCII not found");
while (X[i].token) {
struct string * name = NULL;
struct string *Y = NULL;
char * ascname = NULL;
CONST char *lang = NULL;
while (X[i].token && (
0x0020 /* SPACE */ == X[i].special ||
0x0028 /* ( */ == X[i].special
)
) {
i++;
}
if (! X[i].token)
break;
if (0 == X[i].special)
name = X[i].token;
else {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorNameExpected,
"Parse error on %S -- name expected"),
X[i].token);
goto recover;
}
if (!can_ascii_string(X[i].token))
lib_error(CATGETS(elm_msg_cat, MeSet,
MeAsciiRequiredTok,
"Ascii required for token %S"),
X[i].token);
i++;
while (X[i].token && (
0x0020 /* SPACE */ == X[i].special ||
0x0028 /* ( */ == X[i].special
)
) {
i++;
}
if (! X[i].token) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorEqualExpectedEOS,
"Parse error on end of string -- = expected"));
break;
}
if (0x003D /* = */ != X[i].special) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorEqualExpected,
"Parse error on %S -- = expected"),
X[i].token);
goto recover;
}
i++;
while (X[i].token && (
0x0020 /* SPACE */ == X[i].special ||
0x0028 /* ( */ == X[i].special
)
) {
i++;
}
if (! X[i].token) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorValueExpectedEOS,
"Parse error on end of string -- value of param expected"));
break;
}
if (0x003B /* ';' */ == X[i].special) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorValueExpected,
"Parse error on %S -- value of param expected"),
X[i].token);
continue;
}
Y = convert_string(ascii_ptr,name,0);
ascname = us2s(stream_from_string(Y,0,NULL));
free_string(&Y);
if (NULL != strchr(ascname,'*')) {
struct mp_pair *mp = add_mp_pair_1(&mp_list,&mp_list_len);
DPRINT(Debug,9,(&Debug,
"parse_rest: %s: String as raw parameter: %S\n",
ascname,X[i].token));
if (!can_ascii_string(X[i].token))
lib_error(CATGETS(elm_msg_cat, MeSet,
MeAsciiRequiredTok,
"Ascii required for token %S"),
X[i].token);
Y = convert_string(ascii_ptr,X[i].token,0);
mp->raw_param = ascname;
mp->raw_value = us2s(stream_from_string(Y,0,NULL));
free_string(&Y);
} else {
struct string * value1 = NULL;
struct string * value0 = NULL;
if (0x0022 /* " */ == X[i].special)
value1 = unquote_string(X[i].token);
else
value1 = dup_string(X[i].token);
value0 = value1; /* synonym */
if (plain_mode) {
struct ascii_pair *A = NULL;
struct string *Y;
if (!can_ascii_string(value1))
lib_error(CATGETS(elm_msg_cat, MeSet,
MeAsciiRequiredTok,
"Ascii required for token %S"),
value1);
Y = convert_string(ascii_ptr,value1,0);
A = add_ascii_pair_1(&a_list,&a_list_len);
A->param = ascname;
A->value = us2s(stream_from_string(Y,0,NULL));
A->is_compat = 1;
free_string(& Y);
DPRINT(Debug,9,(&Debug,
"parse_rest: [compat] %s=%s\n",
A->param,
A->value));
} else {
/* Ascii version ... */
lang = get_string_lang(value1);
if (plain_mode ||
!lang && can_ascii_string(value1) &&
!string_is_ascii_control(value1)) {
struct ascii_pair *A = NULL;
struct string *Y = convert_string(ascii_ptr,value1,0);
/* Is really ascii */
A = add_ascii_pair_1(&a_list,&a_list_len);
A->param = safe_strdup(ascname);
A->value = us2s(stream_from_string(Y,0,NULL));
A->is_compat = string_len(Y) < gen_compat_len;
DPRINT(Debug,9,(&Debug,
"parse_rest: [%s] %s=%s\n",
A->is_compat ? "compat" : "ascii",
A->param,
A->value));
if (!A->is_compat)
goto gencompat;
} else {
CONST struct string * Y1;
CONST char * Y2;
{
struct string_pair *S = NULL;
S = add_string_pair_1(&tmp_list,&tmp_list_len);
S->param = ascname;
S->value = value1;
value1 = NULL;
DPRINT(Debug,9,(&Debug,
"parse_rest: [string] %s=%S\n",
S->param,
S->value));
}
gencompat:
Y1 = get_mime_param(P,ascname);
Y2 = find_ascii_param(P,ascname,1);
if (Y1 && 0 == string_cmp(Y1,value0,999) &&
Y2) {
/* Preserve existing compat parameter */
struct ascii_pair *A = NULL;
DPRINT(Debug,9,(&Debug,
"parse_rest: %s: Preserving existing compat parameter: %s\n",
ascname,Y2));
A = add_ascii_pair_1(&a_list,&a_list_len);
A->param = safe_strdup(ascname);
A->value = safe_strdup(Y2);
A->is_compat = 1;
DPRINT(Debug,9,(&Debug,
"parse_rest: [compat] %s=%s\n",
A->param,
A->value));
} else {
if (Y1) {
DPRINT(Debug,9,(&Debug,
"parse_rest: old string param was: %S\n",
Y1));
}
if (Y2) {
DPRINT(Debug,9,(&Debug,
"parse_rest: old compat param was: %s\n",
Y2));
}
if (gen_compat_len) {
struct ascii_pair *A = NULL;
struct string *Y = convert_string(ascii_ptr,value0,0);
int pos = 0;
A = add_ascii_pair_1(&a_list,&a_list_len);
A->param = safe_strdup(ascname);
A->value = us2s(streamclip_from_string(Y,&pos,gen_compat_len,NULL,NULL));
A->is_compat = 1;
DPRINT(Debug,9,(&Debug,
"parse_rest: [compat] %s=%s\n",
A->param,
A->value));
}
}
}
if (value1)
free_string(& value1);
}
}
i++;
while (X[i].token && (
0x0020 /* SPACE */ == X[i].special ||
0x0028 /* ( */ == X[i].special
)
) {
i++;
}
if (X[i].token &&
0x003B /* ';' */ != X[i].special) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorSemicolonExpected,
"Parse error on %S -- ; or end of string expected"),
X[i].token);
/* syncronize */
recover:
while (X[i].token &&
0x003B /* ';' */ != X[i].special )
i++;
}
if (X[i].token &&
0x003B /* ';' */ == X[i].special)
i++;
}
if (X[i].token)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeParseErrorFailed,
"Parse error on %S -- failed to parse parameters"),
X[i].token);
free_parsed(P);
P->string_params = tmp_list;
P->string_param_count = tmp_list_len;
P->ascii_params = a_list;
P->ascii_param_count = a_list_len;
free_raw(P);
P->params = mp_list;
P->param_count = mp_list_len;
for (i = 0; i < a_list_len; i++) {
if (a_list[i].is_compat) {
struct mp_pair * mp = add_mp_pair(P);
mp->raw_param = safe_strdup(a_list[i].param);
if (ascii_need_quote(a_list[i].value))
mp->raw_value = elm_message(FRM("%Q"),a_list[i].value);
else
mp->raw_value = safe_strdup(a_list[i].value);
DPRINT(Debug,9,(&Debug,
"parse_rest: *** %s=%s\n",
mp->raw_param,mp->raw_value));
} else {
gen_splitted_ascii_param(P,a_list[i].param,a_list[i].value);
}
}
for (i = 0; i < tmp_list_len; i++) {
/* If there exists ascii -- non-compat version of same
parameter, do not add this ...
*/
if (find_ascii_param(P,tmp_list[i].param,0))
continue;
if (string_len(tmp_list[i].value) > STRING_SPLIT_LEN)
gen_splitted_string_param(P,tmp_list[i].param,tmp_list[i].value);
else
gen_string_param(P,tmp_list[i].param,tmp_list[i].value);
}
}
struct mime_param * parse_mime_param_string(value, gen_compat_len,
plain_mode)
struct string * value;
int gen_compat_len;
int plain_mode;
{
struct mime_param *P = alloc_mime_param();
struct string_token *X = string_tokenize(value,TOK_mime);
P->def = value->string_type;
if (X) {
parse_rest(P,X,gen_compat_len, plain_mode);
free_string_tokenized(&X);
}
return P;
}
char ** split_mime_params(P,in_buffer,gen_compat_len,plain_mode)
struct mime_param **P;
struct string *in_buffer;
int gen_compat_len;
int plain_mode;
{
char **ret = NULL;
struct string_token *X;
int i,count = 0;
if (!*P)
*P = alloc_mime_param();
if (MIME_PARAM_magic != (*P)->magic)
mime_panic(__FILE__,__LINE__,"split_mime_params",
"Bad magic number");
X = string_tokenize(in_buffer,TOK_mime);
if (!X)
return NULL;
for (i=0; X[i].token; i++) {
if (0x003B /* ';' */ == X[i].special)
break;
count++;
}
if (count) {
int j;
int k = 0;
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
if (!ascii_ptr)
mime_panic(__FILE__,__LINE__,"split_mime_params",
"US-ASCII not found");
ret = safe_malloc((count+1) * sizeof(ret[0]));
for (j = 0; j < count; j++) {
struct string *Y;
if (0x0020 /* SPACE */ == X[j].special)
continue;
/* Skips comment */
if (0x0028 /* ( */ == X[j].special)
continue;
if (!can_ascii_string(X[j].token))
lib_error(CATGETS(elm_msg_cat, MeSet,
MeAsciiRequiredTok,
"Ascii required for token %S"),
X[j].token);
Y = convert_string(ascii_ptr,X[j].token,0);
ret[k] = us2s(stream_from_string(Y,0,NULL));
DPRINT(Debug,9,(&Debug,
"split_mime_params: ret[%d]=%s\n",
k,ret[k]));
k++;
free_string(&Y);
}
ret[k] = NULL;
}
if (0x003B /* ';' */ == X[i].special) {
i++;
parse_rest(*P,X+i,gen_compat_len, plain_mode);
} else {
DPRINT(Debug,9,(&Debug,
"split_mime_params: Removing all parameters\n"));
free_raw(*P);
free_parsed(*P);
}
free_string_tokenized(&X);
return ret;
}
void mime_params_add_compat(P,name,value)
struct mime_param **P;
char *name;
char *value;
{
struct ascii_pair *A = NULL;
struct mp_pair * mp = NULL;
if (!*P)
*P = alloc_mime_param();
if (MIME_PARAM_magic != (*P)->magic)
mime_panic(__FILE__,__LINE__,"mime_params_add_compat",
"Bad magic number");
A = add_ascii_pair(*P);
A->param = safe_strdup(name);
A->value = safe_strdup(value);
A->is_compat = 1;
DPRINT(Debug,9,(&Debug,
"mime_params_add_compat: [compat] %s=%s\n",
A->param,A->value));
mp = add_mp_pair(*P);
mp->raw_param = safe_strdup(name);
if (ascii_need_quote(value))
mp->raw_value = elm_message(FRM("%Q"),value);
else
mp->raw_value = safe_strdup(value);
DPRINT(Debug,9,(&Debug,
"mime_params_add_compat: *** %s=%s\n",
mp->raw_param,mp->raw_value));
}
void mime_params_add(P,name,value)
struct mime_param **P;
char *name;
struct string *value;
{
struct string_pair *S = NULL;
CONST char *lang;
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
if (!*P)
*P = alloc_mime_param();
if (MIME_PARAM_magic != (*P)->magic)
mime_panic(__FILE__,__LINE__,"mime_params_add",
"Bad magic number");
if (!ascii_ptr)
mime_panic(__FILE__,__LINE__,"mime_params_add",
"US-ASCII not found");
S = add_string_pair(*P);
S->param = safe_strdup(name);
S->value = dup_string(value);
DPRINT(Debug,9,(&Debug,
"mime_params_add: [string] %s=%S\n",
S->param,S->value));
/* Compat parameter is not generated -- it is asusmed that
caller calls mime_params_add_compat instead ...
*/
lang = get_string_lang(value);
if (!lang && can_ascii_string(value) &&
!string_is_ascii_control(value)) {
struct ascii_pair *A = NULL;
struct string *Y = convert_string(ascii_ptr,value,0);
/* Is really ascii */
A = add_ascii_pair(*P);
A->param = safe_strdup(name);
A->value = us2s(stream_from_string(Y,0,NULL));
A->is_compat = 0;
DPRINT(Debug,9,(&Debug,
"mime_params_add: [ascii] %s=%s\n",
A->param,A->value));
gen_splitted_ascii_param(*P,A->param,A->value);
} else {
if (string_len(S->value) > STRING_SPLIT_LEN)
gen_splitted_string_param(*P,S->param,S->value);
else
gen_string_param(*P,S->param,S->value);
}
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1