8dac46 | 2002-11-10 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
#pike __REAL_VERSION__
inherit ___MIME;
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | |
protected class StringRange
{
string data;
int start;
int end;
protected void create(string|StringRange s, int start, int end)
{
if (start == end) {
data = "";
|
8e06a3 | 2014-09-30 | Martin Nilsson | | this::start = this::end = 0;
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return;
}
if (start < 0) start = 0;
if (end < 0) end = 0;
if (objectp(s)) {
start += s->start;
if (start > s->end) start = s->end;
end += s->start;
if (end > s->end) end = s->end;
s = s->data;
}
if ((end - start)*16 < sizeof(s)) {
s = s[start..end-1];
end -= start;
start = 0;
}
data = s;
|
8e06a3 | 2014-09-30 | Martin Nilsson | | this::start = start;
this::end = end;
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | }
protected int _sizeof()
{
return end-start;
}
protected string|StringRange `[..](int low, int ltype, int high, int htype)
{
int len = end - start;
if (ltype == Pike.INDEX_FROM_END) {
low = len - (low + 1);
}
high += 1;
if (htype == Pike.INDEX_FROM_END) {
high = len - high;
} else if (htype == Pike.OPEN_BOUND) {
high = len;
}
if (low < 0) low = 0;
if (high < 0) high = 0;
if (low > len) low = len;
if (high > len) high = len;
if (!low && (high == len)) return this_object();
|
cc251a | 2010-03-11 | Stephen R. van den Berg | | if ((high - low) < 65536) return data[start+low..start+high-1];
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return StringRange(this_object(), low, high);
}
protected int `[](int pos)
{
int npos = pos;
if (npos < 0) {
npos += end;
if (npos < start) {
error("Index out of range [-%d..%d]\n", 1 + end-start, end-start);
}
} else {
npos += start;
if (npos >= end) {
error("Index out of range [-%d..%d]\n", 1 + end-start, end-start);
}
}
return data[npos];
}
protected mixed cast(string type)
{
|
709106 | 2014-08-18 | Martin Nilsson | | if( type == "string" )
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return data[start..end-1];
|
709106 | 2014-08-18 | Martin Nilsson | | return UNDEFINED;
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | }
protected int _search(string frag, int|void pos)
{
|
569d8e | 2010-03-11 | Stephen R. van den Berg | | if (pos < 0)
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | error("Start must be greater or equal to zero.\n");
int npos = pos + start;
|
569d8e | 2010-03-11 | Stephen R. van den Berg | | if (npos > end)
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | error("Start must not be greater than the length of the string.\n");
|
569d8e | 2010-03-11 | Stephen R. van den Berg | | if ((npos + sizeof(frag)) > end) return -1;
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | npos = search(data, frag, npos);
if (npos < 0) return npos;
if ((npos + sizeof(frag)) > end) return -1;
return npos - start;
}
protected string _sprintf(int c)
{
if (c == 'O')
|
cc251a | 2010-03-11 | Stephen R. van den Berg | | return sprintf("StringRange(%d bytes[%d..%d] %O)",
data && sizeof(data), start, end-1, data && data[..40]);
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return (string)this_object();
}
}
|
1e6eaa | 2010-02-23 | Henrik Grubbström (Grubba) | | #if (__REAL_VERSION__ < 7.8) || ((__REAL_VERSION__) < 7.9 && (__REAL_BUILD__ < 413))
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | |
protected int(0..1) has_prefix(string|object s, string prefix)
{
if (!objectp(s)) return predef::has_prefix(s, prefix);
for(int i = 0; i < sizeof(prefix); i++) {
if (s[i] != prefix[i]) return 0;
}
return 1;
}
#endif
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string generate_boundary( )
{
return "'ThIs-RaNdOm-StRiNg-/=_."+random( 1000000000 )+":";
}
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | string|StringRange decode( string|StringRange data, string encoding )
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
switch (lower_case( encoding || "binary" )) {
case "base64":
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return decode_base64( (string)data );
|
8dac46 | 2002-11-10 | Martin Nilsson | | case "quoted-printable":
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return decode_qp( (string)data );
|
8dac46 | 2002-11-10 | Martin Nilsson | | case "x-uue":
case "x-uuencode":
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return decode_uue( (string)data );
|
8dac46 | 2002-11-10 | Martin Nilsson | | case "7bit":
case "8bit":
case "binary":
return data;
default:
error("Unknown transfer encoding %s.\n", encoding);
}
}
string encode( string data, string encoding, void|string filename,
void|int no_linebreaks )
{
switch (lower_case( encoding || "binary" )) {
case "base64":
return encode_base64( data, no_linebreaks );
case "quoted-printable":
return encode_qp( data, no_linebreaks );
case "x-uue":
case "x-uuencode":
return encode_uue( data, filename );
case "7bit":
case "8bit":
case "binary":
return data;
default:
error("Unknown transfer encoding %s.\n", encoding);
}
}
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
array(string) decode_word( string word )
{
string charset, encoding, encoded_text;
if (sscanf( word,
"=?%[^][ \t()<>@,;:\"\\/?.=]?%[^][ \t()<>@,;:\"\\/?.=]?%s?=",
charset, encoding, encoded_text) == 3 ) {
switch (lower_case( encoding )) {
case "b":
encoding = "base64";
break;
case "q":
encoding = "quoted-printable";
break;
default:
error( "Invalid rfc1522 encoding %s.\n", encoding );
}
return ({ decode( replace( encoded_text, "_", " " ), encoding ),
lower_case( charset ) });
} else
return ({ word, 0 });
}
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string encode_word( string|array(string) word, string encoding )
{
if (stringp(word))
return word;
if (!encoding || !word[1])
return word[0];
switch (lower_case(encoding)) {
case "b":
case "base64":
encoding = "base64";
break;
case "q":
case "quoted-printable":
encoding = "quoted-printable";
break;
default:
error( "Invalid rfc1522 encoding %s.\n", encoding);
}
string enc = encode( word[0], encoding, 0, 1 );
if (encoding == "quoted-printable")
enc = replace( enc, ({ "?", "_", "(", ")", "\\", "\"" }),
({ "=3F", "=5F", "=28", "=29", "=5C", "=22" }) );
return "=?"+word[1]+"?"+encoding[0..0]+"?"+ enc +"?=";
}
|
9eaf1d | 2008-06-28 | Martin Nilsson | | protected string remap(array(string) item)
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
if (sizeof(item)>1 && item[1])
|
0b8d2f | 2013-06-17 | Martin Nilsson | | return Charset.decoder(item[1])->feed(item[0])->drain();
|
8dac46 | 2002-11-10 | Martin Nilsson | | else
return item[0];
}
|
9eaf1d | 2008-06-28 | Martin Nilsson | | protected array(string) reremap(string word, string|function(string:string) selector,
|
c105d2 | 2005-06-05 | Marcus Comstedt | | string|void replacement,function(string:string)|void repcb)
{
if(max(@values(word))<128)
return ({ word,0 });
string s = stringp(selector)? selector : selector(word);
return s?
|
0b8d2f | 2013-06-17 | Martin Nilsson | | ({ Charset.encoder(s,replacement,repcb)->feed(word)->drain(), s }) :
|
c105d2 | 2005-06-05 | Marcus Comstedt | | ({ word,0 });
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | array(array(string)) decode_words_text( string txt )
{
|
92858c | 2002-12-12 | Marcus Comstedt | | object r = Regexp("^(.*[ \t\n\r]|)(=\\?[^\1- ?]*\\?[^\1- ?]*\\?"
"[^\1- ?]*\\?=)(([ \t\n\r]+)(.*)|)$");
|
8dac46 | 2002-11-10 | Martin Nilsson | | array a, res = ({});
while ((a = r->split(txt)))
{
|
92858c | 2002-12-12 | Marcus Comstedt | | if(!sizeof(a[2])) a = a[..2]+({"",""});
|
a6f59a | 2002-12-12 | Marcus Comstedt | | txt = a[0]||"";
if(!sizeof(res) || sizeof(a[4])) a[4]=a[3]+a[4];
|
92858c | 2002-12-12 | Marcus Comstedt | | array w = decode_word(a[1]);
|
a6f59a | 2002-12-12 | Marcus Comstedt | | if (sizeof(a[4]))
res = ({ w, ({ a[4], 0 }) }) + res;
|
8dac46 | 2002-11-10 | Martin Nilsson | | else
res = ({ w }) + res;
}
|
b800f8 | 2011-12-13 | Henrik Grubbström (Grubba) | | a = res;
res = ({});
if (sizeof(txt)) res = ({ ({ txt, 0 }) });
foreach(a, array(string) word) {
if (sizeof(res) && res[-1][1] && (res[-1][1] == word[1])) {
res[-1][0] += word[0];
} else {
res += ({ word });
}
}
return res;
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | string decode_words_text_remapped( string txt )
{
return Array.map(decode_words_text(txt), remap)*"";
}
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | array(array(string)|int) decode_words_tokenized( string phrase, int|void flags )
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | return Array.map(tokenize(phrase, flags),
|
8dac46 | 2002-11-10 | Martin Nilsson | | lambda(string|int item) {
return intp(item)? item : decode_word(item);
});
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | array(string|int) decode_words_tokenized_remapped( string phrase,
int|void flags )
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | return Array.map(decode_words_tokenized(phrase, flags),
|
8dac46 | 2002-11-10 | Martin Nilsson | | lambda(array(string)|int item) {
return intp(item)? item : remap(item);
});
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | array(array(string|int|array(array(string))))
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | decode_words_tokenized_labled( string phrase, int|void flags )
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | return Array.map( tokenize_labled( phrase, flags ),
|
8dac46 | 2002-11-10 | Martin Nilsson | | lambda(array(string|int) item) {
switch(item[0]) {
case "encoded-word":
return ({ "word", @decode_word(item[1]) });
case "word":
return item + ({ 0 });
case "comment":
return ({ "comment", decode_words_text(item[1]) });
default:
return item;
}
});
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | array(array(string|int))
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | decode_words_tokenized_labled_remapped(string phrase, int|void flags)
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | return Array.map(decode_words_tokenized_labled(phrase, flags),
|
8dac46 | 2002-11-10 | Martin Nilsson | | lambda(array(string|int|array(array(string|int))) item) {
switch(item[0]) {
case "word":
return ({ "word", remap(item[1..]) });
case "comment":
return ({ "comment", Array.map(item[1], remap)*"" });
default:
return item;
}
});
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | string encode_words_text(array(string|array(string)) phrase, string encoding)
{
|
92858c | 2002-12-12 | Marcus Comstedt | | phrase = filter(phrase, lambda(string|array(string) w) {
return stringp(w)? sizeof(w) :
sizeof(w[0]) || w[1];
});
array(string) ephrase = map(phrase, encode_word, encoding);
if(!encoding) return ephrase*"";
string res="";
for(int i=0; i<sizeof(ephrase); i++)
if(ephrase[i] != (stringp(phrase[i])? phrase[i] : phrase[i][0])) {
if(sizeof(res) && !(<' ','\t','\n','\r'>)[res[-1]])
res += " ";
res += ephrase[i];
if(i+1<sizeof(ephrase) && !(<' ','\t','\n','\r'>)[ephrase[i+1][0]])
res += " ";
} else
res += ephrase[i];
return res;
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
|
0b8d2f | 2013-06-17 | Martin Nilsson | |
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
|
0b8d2f | 2013-06-17 | Martin Nilsson | |
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
string encode_words_text_remapped(string text, string encoding,
string|function(string:string) charset,
string|void replacement,
function(string:string)|void repcb)
{
array(array(string)) out = ({});
string lastword = "";
while(sizeof(text)) {
sscanf(text, "%[ \t\n\r]%[^ \t\n\r]%s", string ws, string word, text);
array(string) ww = reremap(word, charset, replacement, repcb);
if(sizeof(ws))
if(!ww[1])
ww[0] = ws + ww[0];
else if(!sizeof(out))
out = ({({ws,0})});
else if(!out[-1][1])
out[-1][0] += ws;
else {
word = lastword+ws+word;
ww = reremap(word, charset, replacement, repcb);
|
8a531a | 2006-11-04 | Martin Nilsson | | out = out[..<1];
|
c105d2 | 2005-06-05 | Marcus Comstedt | | }
lastword = word;
out += ({ ww });
}
return encode_words_text(out, encoding);
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | string encode_words_quoted(array(array(string)|int) phrase, string encoding)
{
return quote(Array.map(phrase, lambda(array(string)|int item) {
return intp(item)? item :
encode_word(item, encoding);
}));
}
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
string encode_words_quoted_remapped(array(string|int) phrase, string encoding,
string|function(string:string) charset,
string|void replacement,
function(string:string)|void repcb)
{
return encode_words_quoted(map(phrase, lambda(string|int item) {
return intp(item)? item :
reremap(item, charset,
replacement, repcb);
}), encoding);
}
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
|
27b07f | 2002-11-25 | Marcus Comstedt | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | string encode_words_quoted_labled(array(array(string|int|array(string|array(string)))) phrase, string encoding)
{
return
quote_labled(Array.map(phrase,
lambda(array(string|int|array(string)) item) {
switch(item[0]) {
case "word":
if(sizeof(item)>2 && item[2])
return ({
"encoded-word",
encode_word(item[1..], encoding) });
else
return item;
case "comment":
return ({
"comment",
encode_words_text(item[1], encoding) });
default:
return item;
}
}));
}
|
c105d2 | 2005-06-05 | Marcus Comstedt | |
string encode_words_quoted_labled_remapped(array(array(string|int)) phrase,
string encoding,
string|function(string:string) charset,
string|void replacement,
function(string:string)|void repcb)
{
return quote_labled(map(phrase, lambda(array(string|int) item) {
switch(item[0]) {
case "word":
item = item[..0]+reremap(item[1],
charset,
replacement,
repcb);
if(sizeof(item)>2 && item[2])
return ({
"encoded-word",
encode_word(item[1..], encoding) });
else
return item;
case "comment":
return ({
"comment",
encode_words_text_remapped(item[1],
encoding,
charset,
replacement,
repcb) });
default:
return item;
}
}));
}
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
91b0c6 | 2015-08-21 | Henrik Grubbström (Grubba) | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string guess_subtype( string type )
{
switch (type) {
case "text":
return "plain";
case "message":
return "rfc822";
case "multipart":
return "mixed";
}
return 0;
}
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | array(mapping(string:string|array(string))|string|StringRange)
parse_headers(string|StringRange message, void|int(1..1) use_multiple)
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | string head, header, hname, hcontents;
string|StringRange body;
|
d80569 | 2013-08-12 | Martin Nilsson | | int mesgsep;
|
8dac46 | 2002-11-10 | Martin Nilsson | | if (has_prefix(message, "\r\n") || has_prefix(message, "\n")) {
return ({ ([]), message[1 + (message[0] == '\r')..] });
} else {
int mesgsep1 = search(message, "\r\n\r\n");
int mesgsep2 = search(message, "\n\n");
|
d80569 | 2013-08-12 | Martin Nilsson | | mesgsep = (mesgsep1<0? mesgsep2 :
(mesgsep2<0? mesgsep1 :
(mesgsep1<mesgsep2? mesgsep1 : mesgsep2)));
|
8dac46 | 2002-11-10 | Martin Nilsson | | if (mesgsep<0) {
|
d80569 | 2013-08-12 | Martin Nilsson | |
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | head = (string)message;
|
8dac46 | 2002-11-10 | Martin Nilsson | | body = "";
} else if (mesgsep) {
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | head = (string)(mesgsep>0? message[..mesgsep-1]:"");
|
8dac46 | 2002-11-10 | Martin Nilsson | | body = message[mesgsep+(message[mesgsep]=='\r'? 4:2)..];
}
}
mapping(string:string|array) headers = ([ ]);
foreach( replace(head, ({"\r", "\n ", "\n\t"}),
({"", " ", " "}))/"\n", header )
{
if(4==sscanf(header, "%[!-9;-~]%*[ \t]:%*[ \t]%s", hname, hcontents))
{
|
d80569 | 2013-08-12 | Martin Nilsson | | hname = lower_case(hname);
|
8dac46 | 2002-11-10 | Martin Nilsson | | if (use_multiple)
|
d80569 | 2013-08-12 | Martin Nilsson | | headers[hname] += ({hcontents});
|
8dac46 | 2002-11-10 | Martin Nilsson | | else
|
d80569 | 2013-08-12 | Martin Nilsson | | if(headers[hname])
headers[hname] += "\0"+hcontents;
|
8dac46 | 2002-11-10 | Martin Nilsson | | else
|
d80569 | 2013-08-12 | Martin Nilsson | | headers[hname] = hcontents;
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
}
|
d80569 | 2013-08-12 | Martin Nilsson | |
if( mesgsep<0 && !sizeof(headers) )
return ({ ([]), (string)message });
|
8dac46 | 2002-11-10 | Martin Nilsson | | return ({ headers, body });
}
class Message {
import Array;
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | protected string|StringRange encoded_data;
protected string|StringRange decoded_data;
|
8dac46 | 2002-11-10 | Martin Nilsson | |
mapping(string:string) headers;
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
array(object) body_parts;
string boundary;
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string charset;
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string type;
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string subtype;
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string transfer_encoding;
mapping (string:string) params;
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string disposition;
mapping (string:string) disp_params;
string get_filename( )
{
string fn = disp_params["filename"] || params["name"];
return fn && decode_words_text_remapped(fn);
}
array(string|int) is_partial( )
{
return (type == "message" && subtype == "partial") &&
({ params["id"], (int)params["number"], (int)(params["total"]||"0") });
}
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
void setdata( string data )
{
if (data != decoded_data) {
decoded_data = data;
encoded_data = 0;
}
}
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | |
void `->data=(string data)
{
setdata(data);
}
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string getdata( )
{
if (encoded_data && !decoded_data)
decoded_data = decode( encoded_data, transfer_encoding );
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | return decoded_data = (string)decoded_data;
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
|
a9ab33 | 2008-01-25 | Henrik Grubbström (Grubba) | | string `->data()
{
return getdata();
}
|
8dac46 | 2002-11-10 | Martin Nilsson | |
string getencoded( )
{
if (decoded_data && !encoded_data)
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | encoded_data = encode( (string)decoded_data, transfer_encoding,
get_filename() );
|
87b471 | 2013-11-21 | Tobias S. Josefowitz | | return (string)encoded_data;
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
void setencoding( string encoding )
{
if(encoded_data && !decoded_data)
decoded_data = getdata( );
headers["content-transfer-encoding"] = transfer_encoding =
lower_case( encoding );
encoded_data = 0;
}
void setparam( string param, string value )
{
param = lower_case(param);
params[param] = value;
switch(param) {
case "charset":
charset = value;
break;
case "boundary":
boundary = value;
break;
case "name":
if(transfer_encoding != "x-uue" && transfer_encoding != "x-uuencode")
break;
if(encoded_data && !decoded_data)
decoded_data = getdata( );
encoded_data = 0;
break;
}
headers["content-type"] =
quote(({ type, '/', subtype })+
`+(@map(indices(params), lambda(string param) {
return ({ ';', param, '=', params[param] });
})));
}
void setdisp_param( string param, string value )
{
param = lower_case( param );
disp_params[param] = value;
switch (param) {
case "filename":
if (transfer_encoding != "x-uue" && transfer_encoding != "x-uuencode")
break;
if (encoded_data && !decoded_data)
decoded_data = getdata( );
encoded_data = 0;
break;
}
headers["content-disposition"] =
quote(({ disposition || "attachment" })+
`+(@map(indices(disp_params), lambda(string param) {
return ({ ';', param, '=', disp_params[param] });
})));
}
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
void setcharset( string charset )
{
setparam( "charset", charset );
}
|
e5ef06 | 2003-04-01 | Martin Nilsson | |
|
8dac46 | 2002-11-10 | Martin Nilsson | |
void setboundary( string boundary )
{
setparam( "boundary", boundary );
}
|
ec1a0f | 2014-08-16 | Martin Nilsson | | protected string cast( string dest_type )
|
8dac46 | 2002-11-10 | Martin Nilsson | | {
string data;
object body_part;
if (dest_type != "string")
|
ec1a0f | 2014-08-16 | Martin Nilsson | | return UNDEFINED;
|
8dac46 | 2002-11-10 | Martin Nilsson | |
data = getencoded( );
if (body_parts) {
if (!boundary) {
if (type != "multipart") {
type = "multipart";
subtype = "mixed";
}
setboundary( generate_boundary( ) );
}
data += "\r\n";
foreach( body_parts, body_part )
data += "--"+boundary+"\r\n"+((string)body_part)+"\r\n";
data += "--"+boundary+"--\r\n";
}
|
ead972 | 2003-01-20 | Martin Nilsson | | headers["content-length"] = ""+sizeof(data);
|
8dac46 | 2002-11-10 | Martin Nilsson | |
return map( indices(headers),
lambda(string hname){
|
73b09f | 2006-05-16 | Adam Montague | | return map(arrayp(headers[hname]) ? headers[hname] :
headers[hname]/"\0",
|
8dac46 | 2002-11-10 | Martin Nilsson | | lambda(string header,string hname) {
return hname+": "+header;
},
replace(map(hname/"-",
String.capitalize)*"-",
"Mime","MIME"))*"\r\n";
} )*"\r\n" + "\r\n\r\n" + data;
}
|
63de60 | 2009-03-31 | Henrik Grubbström (Grubba) | | protected string token_to_string(string|int token)
{
return intp(token) ? sprintf("%c", token) : token;
}
protected void parse_param(mapping(string:string) params,
array(string|int) entry,
string header,
int|void guess,
array(string|int)|void entry2)
{
if(sizeof(entry)) {
if(sizeof(entry)<3 || entry[1]!='=' || !stringp(entry[0]))
|
5f8c49 | 2009-09-04 | Henrik Grubbström (Grubba) | | if(guess) {
if ((sizeof(entry) == 1) && stringp(entry[0])) {
if (sizeof(entry = (entry[0]/"-")) > 1) {
entry = ({ entry[0], '=', entry[1..]*"-" });
}
}
else
return;
} else
|
63de60 | 2009-03-31 | Henrik Grubbström (Grubba) | | error("invalid parameter %O in %s %O (%O)\n",
entry[0], header, headers[lower_case(header)], guess);
string param = lower_case(entry[0]);
string val;
if (guess) {
val = map(entry[2..], token_to_string) * "";
} else if (sizeof(filter(entry[2..], intp))) {
error("invalid quoting of parameter %O in %s %O (%O)\n",
entry[0], header, headers[lower_case(header)], guess);
} else {
val = entry[2..]*"";
}
params[param] = val;
if ((param == "filename") && guess && entry2 &&
!has_value(val, "/") && !has_value(val[1..], "\\") &&
(sizeof(entry2) >= 3) && (entry2[1] == '=') &&
(lower_case(entry2[0]) == param)) {
val = map(entry2[2..], token_to_string) * "";
if (has_value(val, "\\"))
params[param] = val;
}
}
}
|
8dac46 | 2002-11-10 | Martin Nilsson | |
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | | void create(void | string|StringRange message,
|
8dac46 | 2002-11-10 | Martin Nilsson | | void | mapping(string:string|array(string)) hdrs,
void | array(object) parts,
void | int guess)
{
encoded_data = 0;
decoded_data = 0;
headers = ([ ]);
params = ([ ]);
disp_params = ([ ]);
body_parts = 0;
type = "text";
subtype = "plain";
charset = "us-ascii";
boundary = 0;
disposition = 0;
|
cc251a | 2010-03-11 | Stephen R. van den Berg | | if (message && stringp(message) && (sizeof(message) > 0x100000)) {
|
0512fc | 2010-02-23 | Henrik Grubbström (Grubba) | |
message = StringRange(message, 0, sizeof(message));
}
|
8dac46 | 2002-11-10 | Martin Nilsson | | if (hdrs || parts) {
string|array(string) hname;
decoded_data = message;
if (hdrs)
foreach( indices(hdrs), hname )
headers[lower_case(hname)] = hdrs[hname];
body_parts = parts;
|
bbf017 | 2009-03-30 | Martin Nilsson | | } else if (message)
[ headers, encoded_data ] = parse_headers(message);
|
8dac46 | 2002-11-10 | Martin Nilsson | | if (headers["content-type"]) {
array(array(string|int)) arr =
tokenize(headers["content-type"]) / ({';'});
array(string|int) p;
|
c0df4d | 2012-05-10 | Henrik Grubbström (Grubba) | | if (guess && sizeof(arr[0]) > 3) {
arr[0] = arr[0][..2];
}
|
8dac46 | 2002-11-10 | Martin Nilsson | | if(sizeof(arr[0])!=3 || arr[0][1]!='/' ||
!stringp(arr[0][0]) || !stringp(arr[0][2]))
if(sizeof(arr[0])==1 && stringp(arr[0][0]) &&
(subtype = guess_subtype(lower_case(type = arr[0][0]))))
arr = ({ ({ type, '/', subtype }) }) + arr[1..];
else if(!guess)
error("invalid Content-Type %O\n", headers["content-type"]);
else
|
c0df4d | 2012-05-10 | Henrik Grubbström (Grubba) | | arr = ({ ({ "application", '/', "octet-stream" }) }) + arr[1..];
|
8dac46 | 2002-11-10 | Martin Nilsson | | type = lower_case(arr[0][0]);
subtype = lower_case(arr[0][2]);
foreach( arr[1..], p )
|
63de60 | 2009-03-31 | Henrik Grubbström (Grubba) | | parse_param(params, p, "Content-Type", guess);
|
8dac46 | 2002-11-10 | Martin Nilsson | | charset = lower_case(params["charset"] || charset);
boundary = params["boundary"];
}
if (headers["content-disposition"]) {
|
878f77 | 2008-01-25 | Henrik Grubbström (Grubba) | | array(array(string|int)) arr;
array(array(string|int)) arr2;
mixed err = catch {
arr = tokenize(headers["content-disposition"]) / ({';'});
};
mixed err2 = catch {
arr2 = tokenize(headers["content-disposition"],
MIME.TOKENIZE_KEEP_ESCAPES) / ({';'});
};
if (err) {
if (!guess || err2) throw(err);
arr = arr2;
arr2 = 0;
|
6a3fef | 2007-09-10 | Stephen R. van den Berg | | }
|
878f77 | 2008-01-25 | Henrik Grubbström (Grubba) | |
|
8dac46 | 2002-11-10 | Martin Nilsson | | array(string|int) p;
if(sizeof(arr[0])!=1 || !stringp(arr[0][0]))
{
if(!guess)
error("invalid Content-Disposition in message\n");
} else
{
disposition = lower_case(arr[0][0]);
|
63de60 | 2009-03-31 | Henrik Grubbström (Grubba) | | foreach( arr[1..]; int i; p )
parse_param(disp_params, p, "Content-Disposition", guess,
arr2 && ((i+1) < sizeof(arr2)) && arr2[i+1]);
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
}
if (headers["content-transfer-encoding"]) {
array(string) arr=tokenize(headers["content-transfer-encoding"]);
if(sizeof(arr)!=1 || !stringp(arr[0]))
{
if(!guess)
error("invalid Content-Transfer-Encoding %O\n",
headers["content-transfer-encoding"]);
} else
transfer_encoding = lower_case(arr[0]);
}
if (boundary && type=="multipart" && !body_parts &&
(encoded_data || decoded_data)) {
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | |
|
ec0ff1 | 2010-02-23 | Henrik Grubbström (Grubba) | | string|StringRange data = decoded_data || getdata();
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | string separator = "--" + boundary;
array(string) parts = ({});
int start = 0;
int found = 0;
encoded_data = 0;
decoded_data = 0;
while ((found = search(data, separator, found)) != -1) {
if (found) {
if (data[found-1] != '\n') {
found += sizeof(separator);
continue;
}
string part;
if ((found > 1) && (data[found - 2] == '\r')) {
|
2e0ec6 | 2010-02-22 | Henrik Grubbström (Grubba) | | part = data[start..found-3];
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | } else {
|
2e0ec6 | 2010-02-22 | Henrik Grubbström (Grubba) | | part = data[start..found-2];
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | }
if (start) {
parts += ({ part });
} else {
decoded_data = part;
}
} else {
decoded_data = "";
}
found += sizeof(separator);
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | | string terminator = data[found..found+1];
if (terminator == "--") {
found += 2;
} else {
terminator = 0;
}
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | while ((found < sizeof(data)) &&
((data[found] == ' ') || (data[found] == '\t'))) {
found++;
}
|
b157b1 | 2010-08-26 | Henrik Grubbström (Grubba) | | if ((found < sizeof(data)) && (data[found] == '\n')) {
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | found++;
} else if ((found < sizeof(data)) &&
(data[found..found+1] == "\r\n")) {
found += 2;
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | | } else if (!guess && !terminator) {
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | error("newline missing after multipart boundary\n");
}
start = found;
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | | if (terminator) break;
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | }
|
fb440e | 2010-02-22 | Henrik Grubbström (Grubba) | | string epilogue = data[start..];
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | if (!decoded_data) {
if (guess) {
decoded_data = epilogue;
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | | epilogue = "";
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | } else
error("boundary missing from multipart-body\n");
}
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | | if ((epilogue != "") && !guess) {
|
0825c0 | 2010-02-22 | Henrik Grubbström (Grubba) | | error("multipart message improperly terminated (%O%s)\n",
epilogue[..200],
sizeof(epilogue) > 201 ? "[...]" : "");
}
|
fcac51 | 2010-02-23 | Henrik Grubbström (Grubba) | | body_parts = map(parts, this_program, 0, 0, guess);
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
if((hdrs || parts) && !decoded_data) {
decoded_data = (parts?
"This is a multi-part message in MIME format.\r\n":
"");
}
}
|
96d641 | 2010-04-08 | Henrik Grubbström (Grubba) | |
|
cc251a | 2010-03-11 | Stephen R. van den Berg | | protected string _sprintf(int c)
{
if (c == 'O')
return sprintf("Message(%O)", disp_params);
return (string)this_object();
}
|
8dac46 | 2002-11-10 | Martin Nilsson | | }
int|object reconstruct_partial(array(object) collection)
{
int got = 0, maxgot = 0, top = sizeof(collection), total = 0;
mapping(int:object) parts = ([ ]);
string id;
if(!top)
return 0;
if(!(id = (collection[0]->is_partial()||({0}))[0]))
return 0;
foreach(collection, object m) {
array(int|string) p = m->is_partial();
if(!(p && p[0] == id))
return 0;
if((!total || p[1]==p[2]) && p[2])
total = p[2];
if(p[1]>maxgot)
maxgot = p[1];
if(p[1]>0 && !parts[p[1]]) {
parts[p[1]] = m;
got++;
}
}
if(!total)
return -1;
if(got == total && maxgot == total) {
mapping(string:string) enclosing_headers = parts[1]->headers;
object reconstructed =
Message(`+(@Array.map(sort(indices(parts)),
lambda(int i, mapping(int:object) parts){
return parts[i]->getencoded();
}, parts)));
foreach(indices(reconstructed->headers), string h) {
if(h != "message-id" && h != "encrypted" && h != "mime-version" &&
|
ead972 | 2003-01-20 | Martin Nilsson | | h != "subject" && (sizeof(h)<8 || h[0..7] != "content-"))
|
8dac46 | 2002-11-10 | Martin Nilsson | | m_delete(reconstructed->headers, h);
}
foreach(indices(enclosing_headers), string h) {
if(h != "message-id" && h != "encrypted" && h != "mime-version" &&
|
ead972 | 2003-01-20 | Martin Nilsson | | h != "subject" && (sizeof(h)<8 || h[0..7] != "content-"))
|
8dac46 | 2002-11-10 | Martin Nilsson | | reconstructed->headers[h] = enclosing_headers[h];
}
return reconstructed;
} else return (maxgot>total? -1 : total-got);
}
|