1 module mail.headers; 2 3 import std.conv; 4 import std.algorithm; 5 import std.string; 6 import std.array; 7 8 debug import std.stdio; 9 10 enum maxLen = 78; 11 12 string norm(string)(string key) 13 { 14 return map!("a.capitalize()")(key.split("-")).join("-"); 15 } 16 17 struct Headers 18 { 19 private 20 { 21 struct Header 22 { 23 string key; 24 string value; 25 } 26 27 Header[] _headers; 28 } 29 30 this(in Headers rsh) 31 { 32 _headers ~= rsh._headers.idup; 33 } 34 35 string[] all(string key) const pure 36 { 37 auto nKey = key.norm; 38 string[] result; 39 foreach (h; _headers) 40 { 41 if (h.key == nKey) 42 { 43 result ~= h.value; 44 } 45 } 46 return result; 47 } 48 49 void update(string[string] values) pure 50 { 51 foreach (k, ref v; values) 52 { 53 opIndexAssign(v, k); 54 } 55 } 56 57 string opIndex(string key) pure const 58 { 59 auto nKey = key.norm; 60 auto val = ""; 61 foreach (h; _headers) 62 { 63 if (h.key == nKey) 64 { 65 val = h.value; 66 break; 67 } 68 } 69 return val; 70 } 71 72 string get(string key, lazy string defVal = null) pure const 73 { 74 auto nKey = key.norm; 75 foreach (h; _headers) 76 { 77 if (h.key == nKey) 78 { 79 return h.value; 80 } 81 } 82 return defVal; 83 } 84 85 void opIndexAssign(ulong val, string key) pure 86 { 87 opIndexAssign(to!string(val), key); 88 } 89 90 void opIndexAssign(string[] val, string key) pure 91 { 92 opIndexAssign(val.join(","), key); 93 } 94 95 void opIndexAssign(string val, string key) pure 96 { 97 auto nKey = key.norm; 98 foreach (h; _headers) 99 { 100 if (h.key == nKey) 101 { 102 h.value = val; 103 return; 104 } 105 } 106 _headers ~= Header(nKey, val); 107 } 108 109 void add(string key, string val) pure 110 { 111 _headers ~= Header(key.norm, val); 112 } 113 114 void toString(scope void delegate(const(char)[]) sink) const 115 { 116 foreach (item; _headers) 117 { 118 // TODO: Folding 119 sink(item.key); 120 sink(": "); 121 sink(item.value); 122 sink("\r\n"); 123 } 124 sink("\r\n"); 125 } 126 127 void parse(string data) pure 128 { 129 string key; 130 string[] val; 131 void save() 132 { 133 add(key, val.join(" ")); 134 val.length = 0; 135 } 136 137 auto lines = data.split("\n"); 138 while (lines.length) 139 { 140 auto tmp = lines.front.strip.findSplit(":"); 141 key = tmp[0]; 142 val ~= tmp[2].strip; 143 lines.popFront; 144 while (lines.length && (lines.front.startsWith("\t") || lines.front.startsWith(" "))) 145 { 146 val ~= lines.front.strip; 147 lines.popFront; 148 } 149 save(); 150 } 151 } 152 } 153 154 unittest 155 { 156 Headers h; 157 158 h["key1"] = "val1"; 159 h["key2"] = "val2"; 160 161 assert(h.get("key1") == "val1"); 162 assert(h["key2"] == "val2"); 163 164 h.add("key2", "val2_2"); 165 assert(h["key2"] == "val2"); 166 assert(h.all("key2") == ["val2", "val2_2"]); 167 168 }