1 module mail.utils; 2 3 import std.algorithm; 4 import std.conv : to; 5 import std.string; 6 import std.datetime; 7 8 enum months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]; 9 10 extern (C) pure nothrow 11 { 12 alias void* iconv_t; 13 14 iconv_t iconv_open(const char* tocode, const char* fromcode); 15 size_t iconv(iconv_t cd, const char** inbuf, size_t* inbytesleft, 16 char** outbuf, size_t* outbytesleft); 17 int iconv_close(iconv_t cd); 18 } 19 20 string recode(string f, string t, char[] src) 21 { 22 auto cd = iconv_open(toStringz(t.toUpper), toStringz(f.toUpper)); 23 if (cast(size_t)(cd) == -1) 24 { 25 return to!string(src); 26 } 27 char[] dst; 28 dst.length = src.length * 6; 29 30 auto src_ptr = cast(char*) src.ptr; 31 auto dst_ptr = cast(char*) dst.ptr; 32 size_t src_len = src.length; 33 size_t dst_len = dst.length; 34 35 auto r = iconv(cd, &src_ptr, &src_len, &dst_ptr, &dst_len); 36 iconv_close(cd); 37 38 if (r == -1) 39 { 40 return to!string(src); 41 } 42 return dst[0 .. $ - dst_len].to!string; 43 } 44 45 ubyte[] fromPercentEncoding(ref ubyte[] src, ubyte chr = '%') 46 { 47 ubyte[] dst; 48 if (!src.length) 49 { 50 return dst; 51 } 52 size_t i = 0; 53 size_t len = src.length; 54 int outLen = 0; 55 int a, b; 56 ubyte c; 57 while (i < len) 58 { 59 c = src[i]; 60 if (c == chr && i + 2 < len) 61 { 62 a = src[++i]; 63 b = src[++i]; 64 if (a >= '0' && a <= '9') 65 a -= '0'; 66 else if (a >= 'a' && a <= 'f') 67 a = a - 'a' + 10; 68 else if (a >= 'A' && a <= 'F') 69 a = a - 'A' + 10; 70 71 if (b >= '0' && b <= '9') 72 b -= '0'; 73 else if (b >= 'a' && b <= 'f') 74 b = b - 'a' + 10; 75 else if (b >= 'A' && b <= 'F') 76 b = b - 'A' + 10; 77 dst ~= cast(ubyte)((a << 4) | b); 78 } 79 else 80 { 81 dst ~= c; 82 } 83 ++i; 84 ++outLen; 85 } 86 if (outLen != len) 87 { 88 dst.length = outLen; 89 } 90 return dst; 91 } 92 93 ubyte[] removeAll(ubyte[] src, ubyte[] val) 94 { 95 ubyte[] dst = src; 96 if (!val.length) 97 { 98 return src; 99 } 100 ptrdiff_t i = -1; 101 do 102 { 103 i = dst.countUntil(val); 104 if (i >= 0) 105 { 106 foreach (j; 0 .. val.length) 107 { 108 dst = dst.remove(i); 109 } 110 } 111 } 112 while (i >= 0); 113 return dst; 114 } 115 116 ubyte[] removeAll(ubyte[] src, ubyte val) 117 { 118 ubyte[] dst = src; 119 ptrdiff_t i = -1; 120 do 121 { 122 i = dst.countUntil(val); 123 if (i >= 0) 124 { 125 dst = dst.remove(i); 126 } 127 } 128 while (i >= 0); 129 return dst; 130 } 131 132 SysTime parseDate(in string src, in SysTime fail = Clock.currTime) 133 { 134 import std.ascii : isDigit; 135 136 DateTime dt; 137 auto tz = new immutable SimpleTimeZone(0.minutes); 138 139 scope (failure) 140 { 141 return fail; 142 } 143 144 auto l = src.findSplitAfter(",")[1].strip().toUpper; 145 146 uint x = l[1].isDigit ? 2 : 1; 147 148 dt.day = l[0 .. x].to!int; 149 150 l = l[++x .. $]; 151 152 dt.month = cast(Month)(months.countUntil(l[0 .. 3]) + 1); 153 dt.year = l[ 4 .. 8].to!int; 154 dt.hour = l[ 9 .. 11].to!int; 155 dt.minute = l[12 .. 14].to!int; 156 dt.second = l[15 .. 17].to!int; 157 int z = 0; 158 159 if (l.length > 18) 160 { 161 auto tmp = l[18 .. $]; 162 163 switch (tmp) 164 { 165 case "UT", "UTC", "GMT": 166 break; 167 default: 168 auto sign = +1; 169 if (tmp[0] == '-') 170 { 171 sign = -1; 172 } 173 174 if (tmp[0] == '-' || tmp[0] == '+') 175 { 176 tmp = tmp[1 .. $]; 177 } 178 179 if (tmp.length == 4) 180 { 181 auto tzH = tmp[0 .. 2].to!int; 182 auto tzM = tmp[2 .. 4].to!int; 183 184 return SysTime(dt, new immutable SimpleTimeZone(((tzH * 60 + tzM) * sign).minutes)); 185 } 186 break; 187 } 188 } 189 190 return SysTime(dt, tz); 191 } 192 /// 193 unittest 194 { 195 assert(parseDate("8 Feb 2017 15:21:13 +0000").toISOExtString == "2017-02-08T15:21:13+00:00"); 196 assert(parseDate("8 Feb 2017 15:21:13 +0530").toISOExtString == "2017-02-08T15:21:13+05:30"); 197 assert(parseDate("18 Feb 2017 15:21:13 +0000").toISOExtString == "2017-02-18T15:21:13+00:00"); 198 assert(parseDate("18 Feb 2017 15:21:13 +0530").toISOExtString == "2017-02-18T15:21:13+05:30"); 199 }