module dinc.mime.HeaderItem; /* just a simple Key value container */ private import std.string; private import std.cstream; private import std.stream; private import std.gc; private import dinc.mime.iconv; private import dinc.mime.Encodings; class HeaderItem { private: char[] _key = ""; char[] _value = ""; public: /* GETTERS */ char[] key() { return this._key; } char[] value() { return this._value; } /* CONSTRUCTORS */ this() { } this(char[] key, char[] value) { this._key = key; this._value = value; } char[] toString() { return _key ~ ": " ~ _value; } char[][char[]] extractParts() // read filename=xxx;mimetype=ssss etc. { //scope(exit) { // std.gc.genCollect(); //} char[][char[]] ret; bool inval = true; bool inquote = false; char[] key= ":"; char[] val= ""; for (int i =0; i < _value.length;i++) { if (inquote && inval) { if (_value[i] == '"') { val ~= _value[i]; inquote = false; continue; } if ((_value[i] == '\\') && (i < (_value.length-1)) && (_value[i+1] == '"') ) { val ~= _value[i]; val ~= _value[i+1]; i++; continue; } val ~= _value[i]; continue; } if (inval && (_value[i] == '"')) { inquote = true; val ~= _value[i]; continue; } if (inval && _value[i] == ';') { // in va; found ; =end of val..; // push key = std.string.tolower(std.string.strip(key)); ret[key] = std.string.strip(val); key = ""; val = ""; inquote = false; inval = false; continue; } if (!inval && _value[i] == '=') { inval = true; continue; } if (inval) { val ~= _value[i]; continue; } key ~= _value[i]; } if (std.string.strip(val).length) { // in va; found ; =end of val..; key = std.string.tolower(std.string.strip(key)); ret[key] = std.string.strip(val); } return ret; } char[] extractAddress() { if (!value.length) { return ""; } char[] r = new char[value.length]; r = ""; bool start = false; for (int i=0;i 0) { ret ~= std.string.strip(r.toString().dup); } delete r; return ret; } char[] valueAsUTF8() // returns a UTF-8 decoded version of the header.. { // fixme - use memory stream.. std.stdio.writefln("fetching value as UTF8: %s = %s", _key, _value); enum { IN_NONE, IN_EQ1, IN_CHARSET, IN_ENC, IN_CONTENT, IN_EQ4, } char[] ret = ""; char[] charset = ""; char[] encoded = ""; char encoding = 0; int i = 0; int i_begin = 0; int state = IN_NONE; void backout() { for (int j= i_begin; j< i; j++) { ret ~= _value[j]; } state = IN_NONE; encoding = 0; i_begin = 0; charset = ""; encoded = ""; } void addEncoded() { std.stdio.writefln("Done encoding %s / %s", encoding, charset); // first decode it.. char[] raw = encoding == 'q' ? dinc.mime.Encodings.quotedPrintable(encoded) : dinc.mime.Encodings.base64(encoded); //std.stdio.writefln("Iconv it:"); std.cstream.dout.writeString(raw);std.stdio.writefln(""); // now iconv it.. auto v = new Iconv("UTF-8//IGNORE", charset.length? charset : "ISO-8859-1"); char[] rawc = v.conv(raw); //std.stdio.writefln("Iconved:"); std.cstream.dout.writeString("'"~rawc~"'");std.stdio.writefln(""); ret ~= rawc; delete v; state = IN_NONE; encoding = 0; i_begin = 0; charset = ""; encoded = ""; } for (i= 0; i< _value.length; i++) { char c = _value[i]; switch(state) { case IN_NONE: if (c != '=') { ret ~= c; continue; } i_begin = i; // for backout.. state = IN_EQ1; continue; case IN_EQ1: if (c != '?') { backout(); continue; } state = IN_CHARSET; continue; case IN_CHARSET: if (c != '?') { charset ~= c; continue; } state = IN_ENC; continue; case IN_ENC: if (c != '?') { if (encoding != 0) { // got encoding alreay?!?! backout(); } if ( std.ctype.tolower(c) != 'b' && std.ctype.tolower(c) != 'q') { backout(); continue; } encoding = std.ctype.tolower(c); continue; } //std.stdio.writefln("GOT %s / %s", charset, encoding); state = IN_CONTENT; continue; case IN_CONTENT: if (c != '?') { encoded ~= c; continue; } state = IN_EQ4; continue; case IN_EQ4: if (c != '=') { backout(); continue; } addEncoded(); // fixme need- to sort out padding rules after an encoded text.. i++; if (_value.length > i+2 ) { if ((_value[i] == '\n') && (_value[i+1] == '\t')) { i+=2; } } //i++; continue; default: // should not get here!!! continue; } } if (state != IN_NONE) { backout(); } return ret; } }