|
|
|
|
|
|
|
|
|
|
|
|
#include "global.h" |
|
#include "config.h" |
|
#include "module.h" |
#include "stralloc.h" |
#include "pike_macros.h" |
#include "object.h" |
#include "program.h" |
#include "interpret.h" |
#include "builtin_functions.h" |
#include "module_support.h" |
#include "pike_error.h" |
|
#ifdef __CHAR_UNSIGNED__ |
#define SIGNED signed |
#else |
#define SIGNED |
#endif |
|
|
#define sp Pike_sp |
|
|
|
static void f_decode_base64( INT32 args ); |
static void f_encode_base64( INT32 args ); |
static void f_decode_qp( INT32 args ); |
static void f_encode_qp( INT32 args ); |
static void f_decode_uue( INT32 args ); |
static void f_encode_uue( INT32 args ); |
|
static void f_tokenize( INT32 args ); |
static void f_tokenize_labled( INT32 args ); |
static void f_quote( INT32 args ); |
static void f_quote_labled( INT32 args ); |
|
|
|
|
static const char base64tab[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
static SIGNED char base64rtab[(1<<(CHAR_BIT-1))-' ']; |
static const char qptab[16] = "0123456789ABCDEF"; |
static SIGNED char qprtab[(1<<(CHAR_BIT-1))-'0']; |
|
#define CT_CTL 0 |
#define CT_WHITE 1 |
#define CT_ATOM 2 |
#define CT_SPECIAL 3 |
#define CT_EQUAL 4 |
#define CT_LPAR 5 |
#define CT_RPAR 6 |
#define CT_LBRACK 7 |
#define CT_RBRACK 8 |
#define CT_QUOTE 9 |
unsigned char rfc822ctype[1<<CHAR_BIT]; |
|
|
|
|
|
|
|
|
|
#define TOKENIZE_KEEP_ESCAPES 1 |
|
|
|
|
|
|
|
|
PIKE_MODULE_INIT |
{ |
int i; |
|
Pike_compiler->new_program->id = PROG_MODULE_MIME_ID; |
|
|
memset( base64rtab, -1, sizeof(base64rtab) ); |
for (i = 0; i < 64; i++) |
base64rtab[base64tab[i] - ' '] = i; |
|
|
memset( qprtab, -1, sizeof(qprtab) ); |
for (i = 0; i < 16; i++) |
qprtab[qptab[i]-'0'] = i; |
for (i = 10; i < 16; i++) |
|
qprtab[qptab[i] - ('0' + 'A' - 'a')] = i; |
|
|
memset( rfc822ctype, CT_ATOM, sizeof(rfc822ctype) ); |
for (i = 0; i < 32; i++) |
rfc822ctype[i] = CT_CTL; |
rfc822ctype[127] = CT_CTL; |
rfc822ctype[' '] = CT_WHITE; |
rfc822ctype['\t'] = CT_WHITE; |
rfc822ctype['('] = CT_LPAR; |
rfc822ctype[')'] = CT_RPAR; |
rfc822ctype['['] = CT_LBRACK; |
rfc822ctype[']'] = CT_RBRACK; |
rfc822ctype['"'] = CT_QUOTE; |
rfc822ctype['='] = CT_EQUAL; |
for(i=0; i<9; i++) |
rfc822ctype[(int)"<>@,;:\\/?"[i]] = CT_SPECIAL; |
|
|
|
|
ADD_FUNCTION2( "decode_base64", f_decode_base64, |
tFunc(tStr, tStr8), 0, OPT_TRY_OPTIMIZE ); |
|
ADD_FUNCTION2( "encode_base64", f_encode_base64, |
tFunc(tStr tOr(tVoid,tInt),tStr7), 0, OPT_TRY_OPTIMIZE ); |
|
add_function_constant( "decode_qp", f_decode_qp, |
"function(string:string)", OPT_TRY_OPTIMIZE ); |
|
ADD_FUNCTION2( "encode_qp", f_encode_qp, |
tFunc(tStr tOr(tVoid,tInt),tStr7), 0, OPT_TRY_OPTIMIZE ); |
|
add_function_constant( "decode_uue", f_decode_uue, |
"function(string:string)", OPT_TRY_OPTIMIZE ); |
|
ADD_FUNCTION2( "encode_uue", f_encode_uue, |
tFunc(tStr tOr(tVoid,tStr),tStr7), 0, OPT_TRY_OPTIMIZE ); |
|
add_integer_constant("TOKENIZE_KEEP_ESCAPES", TOKENIZE_KEEP_ESCAPES, 0); |
|
add_function_constant( "tokenize", f_tokenize, |
"function(string, int|void:array(string|int))", |
OPT_TRY_OPTIMIZE ); |
add_function_constant( "tokenize_labled", f_tokenize_labled, |
"function(string, int|void:array(array(string|int)))", |
OPT_TRY_OPTIMIZE ); |
add_function_constant( "quote", f_quote, |
"function(array(string|int):string)", |
OPT_TRY_OPTIMIZE ); |
add_function_constant( "quote_labled", f_quote_labled, |
"function(array(array(string|int)):string)", |
OPT_TRY_OPTIMIZE ); |
} |
|
|
|
PIKE_MODULE_EXIT |
{ |
} |
|
|
|
|
|
|
|
|
|
|
|
|
static void f_decode_base64( INT32 args ) |
{ |
if(args != 1) |
Pike_error( "Wrong number of arguments to MIME.decode_base64()\n" ); |
else if (TYPEOF(sp[-1]) != T_STRING) |
Pike_error( "Wrong type of argument to MIME.decode_base64()\n" ); |
else if (sp[-1].u.string->size_shift != 0) |
Pike_error( "Char out of range for MIME.decode_base64()\n" ); |
else { |
|
|
|
|
|
|
struct string_builder buf; |
SIGNED char *src; |
ptrdiff_t cnt; |
INT32 d = 1; |
int pads = 3; |
|
init_string_builder( &buf, 0 ); |
|
for (src = (SIGNED char *)sp[-1].u.string->str, cnt = sp[-1].u.string->len; |
cnt--; src++) |
if(*src>=' ' && base64rtab[*src-' ']>=0) { |
|
if((d=(d<<6)|base64rtab[*src-' '])>=0x1000000) { |
|
string_builder_putchar( &buf, (d>>16)&0xff ); |
string_builder_putchar( &buf, (d>>8)&0xff ); |
string_builder_putchar( &buf, d&0xff ); |
d=1; |
} |
} else if (*src=='=') { |
|
break; |
} |
|
|
if (d & 0x3f000000) { |
|
pads = 0; |
} else if (d & 0xfc0000) { |
pads = 1; |
|
d >>= 2; |
} else if (d & 0x3f000) { |
pads = 2; |
|
d >>= 4; |
} |
switch(pads) { |
case 0: |
|
string_builder_putchar( &buf, (d>>16)&0xff ); |
case 1: |
string_builder_putchar( &buf, (d>>8)&0xff ); |
case 2: |
string_builder_putchar( &buf, d&0xff ); |
} |
|
|
pop_n_elems( 1 ); |
push_string( finish_string_builder( &buf ) ); |
} |
} |
|
|
|
|
static int do_b64_encode( ptrdiff_t groups, unsigned char **srcp, char **destp, |
int insert_crlf ) |
{ |
unsigned char *src = *srcp; |
char *dest = *destp; |
int g = 0; |
|
while (groups--) { |
|
INT32 d = *src++<<8; |
d = (*src++|d)<<8; |
d |= *src++; |
|
*dest++ = base64tab[d>>18]; |
*dest++ = base64tab[(d>>12)&63]; |
*dest++ = base64tab[(d>>6)&63]; |
*dest++ = base64tab[d&63]; |
|
if(insert_crlf && ++g == 19) { |
*dest++ = 13; |
*dest++ = 10; |
g=0; |
} |
} |
|
|
*srcp = src; |
*destp = dest; |
return g; |
} |
|
|
|
|
|
|
|
|
|
|
|
static void f_encode_base64( INT32 args ) |
{ |
if(args != 1 && args != 2) |
Pike_error( "Wrong number of arguments to MIME.encode_base64()\n" ); |
else if(TYPEOF(sp[-args]) != T_STRING) |
Pike_error( "Wrong type of argument to MIME.encode_base64()\n" ); |
else if (sp[-args].u.string->size_shift != 0) |
Pike_error( "Char out of range for MIME.encode_base64()\n" ); |
else { |
|
|
|
|
|
ptrdiff_t groups = (sp[-args].u.string->len+2)/3; |
ptrdiff_t last = (sp[-args].u.string->len-1)%3+1; |
|
int insert_crlf = !(args == 2 && TYPEOF(sp[-1]) == T_INT && |
sp[-1].u.integer != 0); |
|
|
struct pike_string *str = |
begin_shared_string( groups*4+(insert_crlf? (groups/19)*2 : 0) ); |
|
unsigned char *src = (unsigned char *)sp[-args].u.string->str; |
char *dest = str->str; |
|
if (groups) { |
|
|
unsigned char tmp[3], *tmpp = tmp; |
int i; |
|
if (do_b64_encode( groups-1, &src, &dest, insert_crlf ) == 18) |
|
str->len -= 2; |
|
|
tmp[1] = tmp[2] = 0; |
for (i = 0; i < last; i++) |
tmp[i] = *src++; |
|
|
do_b64_encode( 1, &tmpp, &dest, 0 ); |
switch (last) { |
case 1: |
*--dest = '='; |
case 2: |
*--dest = '='; |
} |
} |
|
|
pop_n_elems( args ); |
push_string( end_shared_string( str ) ); |
} |
} |
|
|
|
|
|
|
|
|
|
static void f_decode_qp( INT32 args ) |
{ |
if(args != 1) |
Pike_error( "Wrong number of arguments to MIME.decode_qp()\n" ); |
else if(TYPEOF(sp[-1]) != T_STRING) |
Pike_error( "Wrong type of argument to MIME.decode_qp()\n" ); |
else if (sp[-1].u.string->size_shift != 0) |
Pike_error( "Char out of range for MIME.decode_qp()\n" ); |
else { |
|
|
|
|
|
struct string_builder buf; |
SIGNED char *src; |
ptrdiff_t cnt; |
|
init_string_builder(&buf, 0); |
|
for (src = (SIGNED char *)sp[-1].u.string->str, cnt = sp[-1].u.string->len; |
cnt--; src++) |
if (*src == '=') { |
|
if (cnt > 0 && (src[1] == 10 || src[1] == 13)) { |
|
if (src[1] == 13) { |
--cnt; |
src++; |
} |
if (cnt>0 && src[1]==10) { |
--cnt; |
src++; |
} |
} else if (cnt >= 2 && src[1] >= '0' && src[2] >= '0' && |
qprtab[src[1]-'0'] >= 0 && qprtab[src[2]-'0'] >= 0) { |
|
string_builder_putchar( &buf, (qprtab[src[1]-'0']<<4)|qprtab[src[2]-'0'] ); |
cnt -= 2; |
src += 2; |
} |
} else |
|
string_builder_putchar( &buf, *(unsigned char *)src ); |
|
|
pop_n_elems( 1 ); |
push_string( finish_string_builder( &buf ) ); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_encode_qp( INT32 args ) |
{ |
if (args != 1 && args != 2) |
Pike_error( "Wrong number of arguments to MIME.encode_qp()\n" ); |
else if (TYPEOF(sp[-args]) != T_STRING) |
Pike_error( "Wrong type of argument to MIME.encode_qp()\n" ); |
else if (sp[-args].u.string->size_shift != 0) |
Pike_error( "Char out of range for MIME.encode_qp()\n" ); |
else { |
|
|
|
|
|
struct string_builder buf; |
unsigned char *src = (unsigned char *)sp[-args].u.string->str; |
ptrdiff_t cnt; |
int col = 0; |
int insert_crlf = !(args == 2 && TYPEOF(sp[-1]) == T_INT && |
sp[-1].u.integer != 0); |
|
init_string_builder( &buf, 0 ); |
|
for (cnt = sp[-args].u.string->len; cnt--; src++) { |
if ((*src >= 33 && *src <= 60) || |
(*src >= 62 && *src <= 126)) |
|
string_builder_putchar( &buf, *(unsigned char *)src ); |
else { |
|
string_builder_putchar( &buf, '=' ); |
string_builder_putchar( &buf, qptab[(*src)>>4] ); |
string_builder_putchar( &buf, qptab[(*src)&15] ); |
col += 2; |
} |
|
if (++col >= 73 && insert_crlf) { |
string_builder_putchar( &buf, '=' ); |
string_builder_putchar( &buf, 13 ); |
string_builder_putchar( &buf, 10 ); |
col = 0; |
} |
} |
|
|
pop_n_elems( args ); |
push_string( finish_string_builder( &buf ) ); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
static void f_decode_uue( INT32 args ) |
{ |
if (args != 1) |
Pike_error( "Wrong number of arguments to MIME.decode_uue()\n" ); |
else if(TYPEOF(sp[-1]) != T_STRING) |
Pike_error( "Wrong type of argument to MIME.decode_uue()\n" ); |
else if (sp[-1].u.string->size_shift != 0) |
Pike_error( "Char out of range for MIME.decode_uue()\n" ); |
else { |
|
|
|
|
struct string_builder buf; |
char *src; |
ptrdiff_t cnt; |
|
init_string_builder( &buf, 0 ); |
|
src = sp[-1].u.string->str; |
cnt = sp[-1].u.string->len; |
|
while (cnt--) |
if(*src++=='b' && cnt>5 && !memcmp(src, "egin ", 5)) |
break; |
|
if (cnt>=0) |
|
while (cnt--) |
if (*src++=='\n') |
break; |
|
if (cnt<0) { |
|
pop_n_elems( 1 ); |
push_int( 0 ); |
return; |
} |
|
for (;;) { |
int l, g; |
|
|
if (cnt<=0 || *src=='e') |
break; |
|
|
|
l=(*src++-' ')&63; |
--cnt; |
g = (l+2)/3; |
l -= g*3; |
if ((cnt -= g*4) < 0) |
break; |
|
while (g--) { |
|
INT32 d = ((*src++-' ')&63)<<18; |
d |= ((*src++-' ')&63)<<12; |
d |= ((*src++-' ')&63)<<6; |
d |= ((*src++-' ')&63); |
|
string_builder_putchar( &buf, (d>>16)&0xff ); |
string_builder_putchar( &buf, (d>>8)&0xff ); |
string_builder_putchar( &buf, d&0xff ); |
} |
|
|
|
|
|
|
|
if (l<0) |
buf.s->len += l; |
|
|
while (cnt-- && *src++!=10); |
} |
|
|
pop_n_elems( 1 ); |
push_string( finish_string_builder( &buf ) ); |
} |
} |
|
|
|
|
static void do_uue_encode(ptrdiff_t groups, unsigned char **srcp, char **destp, |
ptrdiff_t last ) |
{ |
unsigned char *src = *srcp; |
char *dest = *destp; |
|
while (groups || last) { |
|
ptrdiff_t g = (groups >= 15? 15 : groups); |
|
if (g<15) { |
|
*dest++ = ' ' + |
DO_NOT_WARN((char)(3*g + last)); |
last = 0; |
} else |
*dest++ = ' ' + |
DO_NOT_WARN((char)(3*g)); |
|
groups -= g; |
|
while (g--) { |
|
INT32 d = *src++<<8; |
d = (*src++|d)<<8; |
d |= *src++; |
|
if((*dest++ = ' '+(d>>18)) == ' ') dest[-1]='`'; |
if((*dest++ = ' '+((d>>12)&63)) == ' ') dest[-1]='`'; |
if((*dest++ = ' '+((d>>6)&63)) == ' ') dest[-1]='`'; |
if((*dest++ = ' '+(d&63)) == ' ') dest[-1]='`'; |
} |
|
if(groups || last) { |
|
*dest++ = 13; |
*dest++ = 10; |
} |
} |
|
|
*srcp = src; |
*destp = dest; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_encode_uue( INT32 args ) |
{ |
if (args != 1 && args != 2) |
Pike_error( "Wrong number of arguments to MIME.encode_uue()\n" ); |
else if (TYPEOF(sp[-args]) != T_STRING || |
(args == 2 && TYPEOF(sp[-1]) != T_VOID && |
TYPEOF(sp[-1]) != T_STRING && TYPEOF(sp[-1]) != T_INT)) |
Pike_error( "Wrong type of argument to MIME.encode_uue()\n" ); |
else if (sp[-args].u.string->size_shift != 0 || |
(args == 2 && TYPEOF(sp[-1]) == T_STRING && |
sp[-1].u.string->size_shift != 0)) |
Pike_error( "Char out of range for MIME.encode_uue()\n" ); |
else { |
|
|
|
|
|
char *dest, *filename = "attachment"; |
struct pike_string *str; |
unsigned char *src = (unsigned char *) sp[-args].u.string->str; |
|
ptrdiff_t groups = (sp[-args].u.string->len + 2)/3; |
ptrdiff_t last= (sp[-args].u.string->len - 1)%3 + 1; |
|
|
if (args == 2 && TYPEOF(sp[-1]) == T_STRING) |
filename = sp[-1].u.string->str; |
|
|
|
str = begin_shared_string( groups*4 + ((groups + 14)/15)*3 + |
strlen( filename ) + 20 ); |
dest = str->str; |
|
|
sprintf(dest, "begin 644 %s\r\n", filename); |
dest += 12 + strlen(filename); |
|
if (groups) { |
|
|
unsigned char tmp[3], *tmpp=tmp; |
char *kp, k; |
int i; |
|
do_uue_encode( groups-1, &src, &dest, last ); |
|
|
tmp[1] = tmp[2] = 0; |
for (i = 0; i < last; i++) |
tmp[i] = *src++; |
|
|
|
|
k = *--dest; |
kp = dest; |
|
do_uue_encode( 1, &tmpp, &dest, 0 ); |
|
|
*kp = k; |
|
|
switch (last) { |
case 1: |
dest[-2] = '`'; |
case 2: |
dest[-1] = '`'; |
} |
|
|
*dest++ = 13; |
*dest++ = 10; |
} |
|
|
memcpy( dest, "`\r\nend\r\n", 8 ); |
|
|
pop_n_elems( args ); |
push_string( end_shared_string( str ) ); |
} |
} |
|
|
static void low_tokenize( const char *funname, INT32 args, int mode ) |
{ |
|
|
|
|
|
unsigned char *src; |
int flags = 0; |
struct array *arr; |
struct pike_string *str; |
ptrdiff_t cnt; |
INT32 n = 0, l, e, d; |
char *p; |
|
get_all_args(funname, args, "%S.%d", &str, &flags); |
|
src = STR0(str); |
cnt = str->len; |
|
while (cnt>0) |
switch (rfc822ctype[*src]) { |
case CT_EQUAL: |
|
l = 0; |
if (cnt>5 && src[1] == '?') { |
int nq = 0; |
for (l=2; l<cnt && nq<3; l++) |
if (src[l]=='?') |
nq ++; |
else if(rfc822ctype[src[l]]<=CT_WHITE) |
break; |
if (nq == 3 && l<cnt && src[l] == '=') |
l ++; |
else |
l = 0; |
} |
if (l>0) { |
|
if(mode) |
push_text("encoded-word"); |
push_string( make_shared_binary_string( (char *)src, l ) ); |
if(mode) |
f_aggregate(2); |
n++; |
src += l; |
cnt -= l; |
break; |
} |
case CT_SPECIAL: |
case CT_RBRACK: |
case CT_RPAR: |
|
if(mode) |
push_text("special"); |
push_int( *src++ ); |
if(mode) |
f_aggregate(2); |
n++; |
--cnt; |
break; |
|
case CT_ATOM: |
|
for (l=1; l<cnt; l++) |
if (rfc822ctype[src[l]] != CT_ATOM) |
break; |
|
if(mode) |
push_text("word"); |
push_string( make_shared_binary_string( (char *)src, l ) ); |
if(mode) |
f_aggregate(2); |
n++; |
src += l; |
cnt -= l; |
break; |
|
case CT_QUOTE: |
|
|
for (e = 0, l = 1; l < cnt; l++) |
if (src[l] == '"') |
break; |
else |
if ((src[l] == '\\') && !(flags & TOKENIZE_KEEP_ESCAPES)) { |
e++; |
l++; |
} |
|
|
if(mode) |
push_text("word"); |
|
if (e) { |
|
|
str = begin_shared_string( l-e-1 ); |
|
|
for (p = str->str, e = 1; e < l; e++) |
*p++ = (src[e] == '\\'? src[++e] : src[e]); |
|
push_string( end_shared_string( str ) ); |
} else { |
|
push_string(make_shared_binary_string( (char *)src+1, l-1)); |
} |
if(mode) |
f_aggregate(2); |
n++; |
src += l+1; |
cnt -= l+1; |
break; |
|
case CT_LBRACK: |
|
|
for (e = 0, l = 1; l < cnt; l++) |
if(src[l] == ']') |
break; |
else |
if(src[l] == '\\') { |
e++; |
l++; |
} |
|
if (l >= cnt) { |
|
if(mode) |
push_text("special"); |
push_int( *src++ ); |
if(mode) |
f_aggregate(2); |
n++; |
--cnt; |
break; |
} |
|
|
|
str = begin_shared_string( l-e+1 ); |
|
|
for (p = str->str, e = 0; e <= l; e++) |
*p++ = (src[e] == '\\'? src[++e] : src[e]); |
|
|
if(mode) |
push_text("domain-literal"); |
push_string( end_shared_string( str ) ); |
if(mode) |
f_aggregate(2); |
n++; |
src += l+1; |
cnt -= l+1; |
break; |
|
case CT_LPAR: |
|
|
for (e = 0, d = 1, l = 1; l < cnt; l++) |
if (src[l] == '(') |
|
d++; |
else if(src[l] == ')') { |
|
if(!--d) |
break; |
} else |
|
if(src[l] == '\\') { |
e++; |
l++; |
} |
|
if(mode) { |
push_text("comment"); |
|
str = begin_shared_string( l-e-1 ); |
|
|
for (p = str->str, e = 1; e < l; e++) |
*p++ = (src[e] == '\\'? src[++e] : src[e]); |
|
push_string( end_shared_string( str ) ); |
f_aggregate(2); |
n++; |
} |
|
|
src += l+1; |
cnt -= l+1; |
break; |
|
case CT_WHITE: |
|
src++; |
--cnt; |
break; |
|
default: |
if(*src == '\0') { |
|
cnt = 0; |
break; |
} |
Pike_error( "Invalid character in header field\n" ); |
} |
|
|
arr = aggregate_array( n ); |
pop_n_elems( args ); |
push_array( arr ); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_tokenize( INT32 args ) |
{ |
low_tokenize("MIME.tokenize", args, 0 ); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_tokenize_labled( INT32 args ) |
{ |
low_tokenize("MIME.tokenize_labled", args, 1); |
} |
|
|
|
|
|
static int check_atom_chars( unsigned char *str, ptrdiff_t len ) |
{ |
|
if (len < 1) |
return 0; |
|
|
while (len--) |
if (*str >= 0x80 || rfc822ctype[*str] != CT_ATOM) |
return 0; |
else |
str++; |
|
|
return 1; |
} |
|
|
|
static int check_encword( unsigned char *str, ptrdiff_t len ) |
{ |
int q = 0; |
|
|
if (len < 6 || str[0] != '=' || str[1] != '?' || |
str[len-2] != '?' || str[len-1] != '=') |
return 0; |
|
|
len -= 4; |
str += 2; |
|
|
while (len--) |
if (*str++ == '?') |
if(++q > 2) |
return 0; |
|
|
return q == 2; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_quote( INT32 args ) |
{ |
struct svalue *item; |
INT32 cnt; |
struct string_builder buf; |
int prev_atom = 0; |
|
if (args != 1) |
Pike_error( "Wrong number of arguments to MIME.quote()\n" ); |
else if (TYPEOF(sp[-1]) != T_ARRAY) |
Pike_error( "Wrong type of argument to MIME.quote()\n" ); |
|
|
|
|
init_string_builder( &buf, 0 ); |
|
for (cnt=sp[-1].u.array->size, item=sp[-1].u.array->item; cnt--; item++) { |
|
if (TYPEOF(*item) == T_INT) { |
|
|
string_builder_putchar( &buf, item->u.integer ); |
prev_atom = 0; |
|
} else if (TYPEOF(*item) != T_STRING) { |
|
|
free_string_builder( &buf ); |
Pike_error( "Wrong type of argument to MIME.quote()\n" ); |
|
} else if (item->u.string->size_shift != 0) { |
|
free_string_builder( &buf ); |
Pike_error( "Char out of range for MIME.quote()\n" ); |
|
} else { |
|
|
|
struct pike_string *str = item->u.string; |
|
|
|
if (prev_atom) |
string_builder_putchar( &buf, ' ' ); |
|
if ((str->len>5 && str->str[0]=='=' && str->str[1]=='?' && |
check_encword((unsigned char *)str->str, str->len)) || |
check_atom_chars((unsigned char *)str->str, str->len)) { |
|
|
string_builder_binary_strcat( &buf, str->str, str->len ); |
|
} else { |
|
|
ptrdiff_t len = str->len; |
char *src = str->str; |
string_builder_putchar( &buf, '"' ); |
while(len--) { |
if(*src=='"' || *src=='\\' || *src=='\r') |
|
string_builder_putchar( &buf, '\\' ); |
string_builder_putchar( &buf, (*src++)&0xff ); |
} |
string_builder_putchar( &buf, '"' ); |
|
} |
|
prev_atom = 1; |
|
} |
} |
|
|
pop_n_elems( 1 ); |
push_string( finish_string_builder( &buf ) ); |
} |
|
|
|
|
|
|
|
|
static void f_quote_labled( INT32 args ) |
{ |
struct svalue *item; |
INT32 cnt; |
struct string_builder buf; |
int prev_atom = 0; |
|
if (args != 1) |
Pike_error( "Wrong number of arguments to MIME.quote_labled()\n" ); |
else if (TYPEOF(sp[-1]) != T_ARRAY) |
Pike_error( "Wrong type of argument to MIME.quote_labled()\n" ); |
|
|
|
|
init_string_builder( &buf, 0 ); |
|
for (cnt=sp[-1].u.array->size, item=sp[-1].u.array->item; cnt--; item++) { |
|
if (TYPEOF(*item) != T_ARRAY || item->u.array->size<2 || |
TYPEOF(item->u.array->item[0]) != T_STRING) { |
free_string_builder( &buf ); |
Pike_error( "Wrong type of argument to MIME.quote_labled()\n" ); |
} |
|
if (c_compare_string( item->u.array->item[0].u.string, "special", 7 )) { |
|
if(TYPEOF(item->u.array->item[1]) != T_INT) { |
free_string_builder( &buf ); |
Pike_error( "Wrong type of argument to MIME.quote_labled()\n" ); |
} |
|
|
string_builder_putchar( &buf, item->u.array->item[1].u.integer ); |
prev_atom = 0; |
|
} else if(TYPEOF(item->u.array->item[1]) != T_STRING) { |
|
|
free_string_builder( &buf ); |
Pike_error( "Wrong type of argument to MIME.quote_labled()\n" ); |
|
} else if (item->u.array->item[1].u.string->size_shift != 0) { |
|
free_string_builder( &buf ); |
Pike_error( "Char out of range for MIME.quote_labled()\n" ); |
|
} else if (c_compare_string( item->u.array->item[0].u.string, "word", 4 )){ |
|
|
|
struct pike_string *str = item->u.array->item[1].u.string; |
|
|
|
if (prev_atom) |
string_builder_putchar( &buf, ' ' ); |
|
if ((str->len>5 && str->str[0]=='=' && str->str[1]=='?' && |
check_encword((unsigned char *)str->str, str->len)) || |
check_atom_chars((unsigned char *)str->str, str->len)) { |
|
|
string_builder_binary_strcat( &buf, str->str, str->len ); |
|
} else { |
|
|
ptrdiff_t len = str->len; |
char *src = str->str; |
string_builder_putchar( &buf, '"' ); |
while(len--) { |
if(*src=='"' || *src=='\\' || *src=='\r') |
|
string_builder_putchar( &buf, '\\' ); |
string_builder_putchar( &buf, (*src++)&0xff ); |
} |
string_builder_putchar( &buf, '"' ); |
|
} |
|
prev_atom = 1; |
|
} else if (c_compare_string( item->u.array->item[0].u.string, |
"encoded-word", 12 )) { |
|
struct pike_string *str = item->u.array->item[1].u.string; |
|
|
string_builder_binary_strcat( &buf, str->str, str->len ); |
|
prev_atom = 1; |
|
} else if (c_compare_string( item->u.array->item[0].u.string, |
"comment", 7 )) { |
|
struct pike_string *str = item->u.array->item[1].u.string; |
|
|
ptrdiff_t len = str->len; |
char *src = str->str; |
string_builder_putchar( &buf, '(' ); |
while(len--) { |
if(*src=='(' || *src==')' || *src=='\\' || *src=='\r') |
|
string_builder_putchar( &buf, '\\' ); |
string_builder_putchar( &buf, (*src++)&0xff ); |
} |
string_builder_putchar( &buf, ')' ); |
|
prev_atom = 0; |
|
} else if (c_compare_string( item->u.array->item[0].u.string, |
"domain-literal", 14 )) { |
|
struct pike_string *str = item->u.array->item[1].u.string; |
|
|
ptrdiff_t len = str->len; |
char *src = str->str; |
|
if (len<2 || src[0] != '[' || src[len-1] != ']') { |
free_string_builder( &buf ); |
Pike_error( "Illegal domain-literal passed to MIME.quote_labled()\n" ); |
} |
|
len -= 2; |
src++; |
|
string_builder_putchar( &buf, '[' ); |
while(len--) { |
if(*src=='[' || *src==']' || *src=='\\' || *src=='\r') |
|
string_builder_putchar( &buf, '\\' ); |
string_builder_putchar( &buf, (*src++)&0xff ); |
} |
string_builder_putchar( &buf, ']' ); |
|
prev_atom = 0; |
|
} else { |
|
|
free_string_builder( &buf ); |
Pike_error( "Unknown label passed to MIME.quote_labled()\n" ); |
|
} |
|
} |
|
|
pop_n_elems( 1 ); |
push_string( finish_string_builder( &buf ) ); |
} |
|
|
|
|
|