PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/miranda/protocols/MSN/msn_mime.cpp

http://miranda.googlecode.com/
C++ | 534 lines | 434 code | 73 blank | 27 comment | 81 complexity | ad93709b82cb112081e14d0b9c104370 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, LGPL-2.1
  1. /*
  2. Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
  3. Copyright (c) 2006-2014 Boris Krasnovskiy.
  4. Copyright (c) 2003-2005 George Hazan.
  5. Copyright (c) 2002-2003 Richard Hughes (original version).
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "msn_global.h"
  18. /////////////////////////////////////////////////////////////////////////////////////////
  19. // constructors and destructor
  20. MimeHeaders::MimeHeaders() :
  21. mCount(0),
  22. mAllocCount(0),
  23. mVals(NULL)
  24. {
  25. }
  26. MimeHeaders::MimeHeaders(unsigned iInitCount) :
  27. mCount(0)
  28. {
  29. mAllocCount = iInitCount;
  30. mVals = (MimeHeader*)mir_alloc(iInitCount * sizeof(MimeHeader));
  31. }
  32. MimeHeaders::~MimeHeaders()
  33. {
  34. clear();
  35. mir_free(mVals);
  36. }
  37. void MimeHeaders::clear(void)
  38. {
  39. for (unsigned i=0; i < mCount; i++)
  40. {
  41. MimeHeader& H = mVals[i];
  42. if (H.flags & 1) mir_free((void*)H.name);
  43. if (H.flags & 2) mir_free((void*)H.value);
  44. }
  45. mCount = 0;
  46. }
  47. unsigned MimeHeaders::allocSlot(void)
  48. {
  49. if (++mCount >= mAllocCount)
  50. {
  51. mAllocCount += 10;
  52. mVals = (MimeHeader*)mir_realloc(mVals, sizeof(MimeHeader) * mAllocCount);
  53. }
  54. return mCount - 1;
  55. }
  56. /////////////////////////////////////////////////////////////////////////////////////////
  57. // add various values
  58. void MimeHeaders::addString(const char* name, const char* szValue, unsigned flags)
  59. {
  60. if (szValue == NULL) return;
  61. MimeHeader& H = mVals[allocSlot()];
  62. H.name = name;
  63. H.value = szValue;
  64. H.flags = flags;
  65. }
  66. void MimeHeaders::addLong(const char* name, long lValue, unsigned flags)
  67. {
  68. MimeHeader& H = mVals[allocSlot()];
  69. H.name = name;
  70. char szBuffer[20];
  71. _ltoa(lValue, szBuffer, 10);
  72. H.value = mir_strdup(szBuffer);
  73. H.flags = 2 | flags;
  74. }
  75. void MimeHeaders::addULong(const char* name, unsigned lValue)
  76. {
  77. MimeHeader& H = mVals[allocSlot()];
  78. H.name = name;
  79. char szBuffer[20];
  80. _ultoa(lValue, szBuffer, 10);
  81. H.value = mir_strdup(szBuffer);
  82. H.flags = 2;
  83. }
  84. void MimeHeaders::addBool(const char* name, bool lValue)
  85. {
  86. MimeHeader& H = mVals[allocSlot()];
  87. H.name = name;
  88. H.value = lValue ? "true" : "false";
  89. H.flags = 0;
  90. }
  91. char* MimeHeaders::flipStr(const char* src, size_t len, char* dest)
  92. {
  93. if (len == -1) len = strlen(src);
  94. if (src == dest)
  95. {
  96. const unsigned b = (unsigned)len-- / 2;
  97. for (unsigned i = 0; i < b; i++)
  98. {
  99. const char c = dest[i];
  100. dest[i] = dest[len - i];
  101. dest[len - i] = c;
  102. }
  103. ++len;
  104. }
  105. else
  106. {
  107. for (unsigned i = 0; i < len; i++)
  108. dest[i] = src[len - 1 - i];
  109. dest[len] = 0;
  110. }
  111. return dest + len;
  112. }
  113. /////////////////////////////////////////////////////////////////////////////////////////
  114. // write all values to a buffer
  115. size_t MimeHeaders::getLength(void)
  116. {
  117. size_t iResult = 0;
  118. for (unsigned i=0; i < mCount; i++)
  119. {
  120. MimeHeader& H = mVals[i];
  121. iResult += strlen(H.name) + strlen(H.value) + 4;
  122. }
  123. return iResult + (iResult ? 2 : 0);
  124. }
  125. char* MimeHeaders::writeToBuffer(char* dest)
  126. {
  127. for (unsigned i=0; i < mCount; i++)
  128. {
  129. MimeHeader& H = mVals[i];
  130. if (H.flags & 4)
  131. {
  132. dest = flipStr(H.name, -1, dest);
  133. *(dest++) = ':';
  134. *(dest++) = ' ';
  135. dest = flipStr(H.value, -1, dest);
  136. *(dest++) = '\r';
  137. *(dest++) = '\n';
  138. *dest = 0;
  139. }
  140. else
  141. dest += sprintf(dest, "%s: %s\r\n", H.name, H.value);
  142. }
  143. if (mCount)
  144. {
  145. *(dest++) = '\r';
  146. *(dest++) = '\n';
  147. *dest = 0;
  148. }
  149. return dest;
  150. }
  151. /////////////////////////////////////////////////////////////////////////////////////////
  152. // read set of values from buffer
  153. char* MimeHeaders::readFromBuffer(char* src)
  154. {
  155. clear();
  156. while (*src)
  157. {
  158. char* peol = strchr(src, '\n');
  159. if (peol == NULL)
  160. return strchr(src, 0);
  161. else if (peol == src)
  162. return src + 1;
  163. else if (peol == (src + 1) && *src == '\r')
  164. return src + 2;
  165. *peol = 0;
  166. char* delim = strchr(src, ':');
  167. if (delim)
  168. {
  169. *delim = 0;
  170. MimeHeader& H = mVals[allocSlot()];
  171. H.name = lrtrimp(src);
  172. H.value = lrtrimp(delim + 1);
  173. H.flags = 0;
  174. }
  175. src = peol + 1;
  176. }
  177. return src;
  178. }
  179. const char* MimeHeaders::find(const char* szFieldName)
  180. {
  181. size_t i;
  182. for (i = 0; i < mCount; i++)
  183. {
  184. MimeHeader& MH = mVals[i];
  185. if (_stricmp(MH.name, szFieldName) == 0)
  186. return MH.value;
  187. }
  188. const size_t len = strlen(szFieldName);
  189. char* szFieldNameR = (char*)alloca(len + 1);
  190. flipStr(szFieldName, len, szFieldNameR);
  191. for (i = 0; i < mCount; i++)
  192. {
  193. MimeHeader& MH = mVals[i];
  194. if (_stricmp(MH.name, szFieldNameR) == 0 && (MH.flags & 3) == 0)
  195. {
  196. strcpy((char*)MH.name, szFieldNameR);
  197. flipStr(MH.value, -1, (char*)MH.value);
  198. return MH.value;
  199. }
  200. }
  201. return NULL;
  202. }
  203. static const struct _tag_cpltbl
  204. {
  205. unsigned cp;
  206. const char* mimecp;
  207. } cptbl[] =
  208. {
  209. { 37, "IBM037" }, // IBM EBCDIC US-Canada
  210. { 437, "IBM437" }, // OEM United States
  211. { 500, "IBM500" }, // IBM EBCDIC International
  212. { 708, "ASMO-708" }, // Arabic (ASMO 708)
  213. { 720, "DOS-720" }, // Arabic (Transparent ASMO); Arabic (DOS)
  214. { 737, "ibm737" }, // OEM Greek (formerly 437G); Greek (DOS)
  215. { 775, "ibm775" }, // OEM Baltic; Baltic (DOS)
  216. { 850, "ibm850" }, // OEM Multilingual Latin 1; Western European (DOS)
  217. { 852, "ibm852" }, // OEM Latin 2; Central European (DOS)
  218. { 855, "IBM855" }, // OEM Cyrillic (primarily Russian)
  219. { 857, "ibm857" }, // OEM Turkish; Turkish (DOS)
  220. { 858, "IBM00858" }, // OEM Multilingual Latin 1 + Euro symbol
  221. { 860, "IBM860" }, // OEM Portuguese; Portuguese (DOS)
  222. { 861, "ibm861" }, // OEM Icelandic; Icelandic (DOS)
  223. { 862, "DOS-862" }, // OEM Hebrew; Hebrew (DOS)
  224. { 863, "IBM863" }, // OEM French Canadian; French Canadian (DOS)
  225. { 864, "IBM864" }, // OEM Arabic; Arabic (864)
  226. { 865, "IBM865" }, // OEM Nordic; Nordic (DOS)
  227. { 866, "cp866" }, // OEM Russian; Cyrillic (DOS)
  228. { 869, "ibm869" }, // OEM Modern Greek; Greek, Modern (DOS)
  229. { 870, "IBM870" }, // IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2
  230. { 874, "windows-874" }, // ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows)
  231. { 875, "cp875" }, // IBM EBCDIC Greek Modern
  232. { 932, "shift_jis" }, // ANSI/OEM Japanese; Japanese (Shift-JIS)
  233. { 936, "gb2312" }, // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
  234. { 949, "ks_c_5601-1987" }, // ANSI/OEM Korean (Unified Hangul Code)
  235. { 950, "big5" }, // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
  236. { 1026, "IBM1026" }, // IBM EBCDIC Turkish (Latin 5)
  237. { 1047, "IBM01047" }, // IBM EBCDIC Latin 1/Open System
  238. { 1140, "IBM01140" }, // IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)
  239. { 1141, "IBM01141" }, // IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)
  240. { 1142, "IBM01142" }, // IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)
  241. { 1143, "IBM01143" }, // IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)
  242. { 1144, "IBM01144" }, // IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)
  243. { 1145, "IBM01145" }, // IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)
  244. { 1146, "IBM01146" }, // IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)
  245. { 1147, "IBM01147" }, // IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)
  246. { 1148, "IBM01148" }, // IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)
  247. { 1149, "IBM01149" }, // IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)
  248. { 1250, "windows-1250" }, // ANSI Central European; Central European (Windows)
  249. { 1251, "windows-1251" }, // ANSI Cyrillic; Cyrillic (Windows)
  250. { 1252, "windows-1252" }, // ANSI Latin 1; Western European (Windows)
  251. { 1253, "windows-1253" }, // ANSI Greek; Greek (Windows)
  252. { 1254, "windows-1254" }, // ANSI Turkish; Turkish (Windows)
  253. { 1255, "windows-1255" }, // ANSI Hebrew; Hebrew (Windows)
  254. { 1256, "windows-1256" }, // ANSI Arabic; Arabic (Windows)
  255. { 1257, "windows-1257" }, // ANSI Baltic; Baltic (Windows)
  256. { 1258, "windows-1258" }, // ANSI/OEM Vietnamese; Vietnamese (Windows)
  257. { 20127, "us-ascii" }, // US-ASCII (7-bit)
  258. { 20273, "IBM273" }, // IBM EBCDIC Germany
  259. { 20277, "IBM277" }, // IBM EBCDIC Denmark-Norway
  260. { 20278, "IBM278" }, // IBM EBCDIC Finland-Sweden
  261. { 20280, "IBM280" }, // IBM EBCDIC Italy
  262. { 20284, "IBM284" }, // IBM EBCDIC Latin America-Spain
  263. { 20285, "IBM285" }, // IBM EBCDIC United Kingdom
  264. { 20290, "IBM290" }, // IBM EBCDIC Japanese Katakana Extended
  265. { 20297, "IBM297" }, // IBM EBCDIC France
  266. { 20420, "IBM420" }, // IBM EBCDIC Arabic
  267. { 20423, "IBM423" }, // IBM EBCDIC Greek
  268. { 20424, "IBM424" }, // IBM EBCDIC Hebrew
  269. { 20838, "IBM-Thai" }, // IBM EBCDIC Thai
  270. { 20866, "koi8-r" }, // Russian (KOI8-R); Cyrillic (KOI8-R)
  271. { 20871, "IBM871" }, // IBM EBCDIC Icelandic
  272. { 20880, "IBM880" }, // IBM EBCDIC Cyrillic Russian
  273. { 20905, "IBM905" }, // IBM EBCDIC Turkish
  274. { 20924, "IBM00924" }, // IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
  275. { 20932, "EUC-JP" }, // Japanese (JIS 0208-1990 and 0121-1990)
  276. { 21025, "cp1025" }, // IBM EBCDIC Cyrillic Serbian-Bulgarian
  277. { 21866, "koi8-u" }, // Ukrainian (KOI8-U); Cyrillic (KOI8-U)
  278. { 28591, "iso-8859-1" }, // ISO 8859-1 Latin 1; Western European (ISO)
  279. { 28592, "iso-8859-2" }, // ISO 8859-2 Central European; Central European (ISO)
  280. { 28593, "iso-8859-3" }, // ISO 8859-3 Latin 3
  281. { 28594, "iso-8859-4" }, // ISO 8859-4 Baltic
  282. { 28595, "iso-8859-5" }, // ISO 8859-5 Cyrillic
  283. { 28596, "iso-8859-6" }, // ISO 8859-6 Arabic
  284. { 28597, "iso-8859-7" }, // ISO 8859-7 Greek
  285. { 28598, "iso-8859-8" }, // ISO 8859-8 Hebrew; Hebrew (ISO-Visual)
  286. { 28599, "iso-8859-9" }, // ISO 8859-9 Turkish
  287. { 28603, "iso-8859-13" }, // ISO 8859-13 Estonian
  288. { 28605, "iso-8859-15" }, // ISO 8859-15 Latin 9
  289. { 38598, "iso-8859-8-i" }, // ISO 8859-8 Hebrew; Hebrew (ISO-Logical)
  290. { 50220, "iso-2022-jp" }, // ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
  291. { 50221, "csISO2022JP" }, // ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)
  292. { 50222, "iso-2022-jp" }, // ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)
  293. { 50225, "iso-2022-kr" }, // ISO 2022 Korean
  294. { 50227, "ISO-2022-CN" }, // ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)
  295. { 50229, "ISO-2022-CN-EXT" }, // ISO 2022 Traditional Chinese
  296. { 51932, "euc-jp" }, // EUC Japanese
  297. { 51936, "EUC-CN" }, // EUC Simplified Chinese; Chinese Simplified (EUC)
  298. { 51949, "euc-kr" }, // EUC Korean
  299. { 52936, "hz-gb-2312" }, // HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)
  300. { 54936, "GB18030" }, // Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
  301. };
  302. static unsigned FindCP(const char* mimecp)
  303. {
  304. unsigned cp = CP_ACP;
  305. for (unsigned i = 0; i < SIZEOF(cptbl); ++i)
  306. {
  307. if (_stricmp(mimecp, cptbl[i].mimecp) == 0)
  308. {
  309. cp = cptbl[i].cp;
  310. break;
  311. }
  312. }
  313. return cp;
  314. }
  315. static int SingleHexToDecimal(char c)
  316. {
  317. if (c >= '0' && c <= '9') return c-'0';
  318. if (c >= 'a' && c <= 'f') return c-'a'+10;
  319. if (c >= 'A' && c <= 'F') return c-'A'+10;
  320. return -1;
  321. }
  322. static void PQDecode(char* str)
  323. {
  324. char* s = str, *d = str;
  325. while(*s)
  326. {
  327. switch (*s)
  328. {
  329. case '=':
  330. {
  331. int digit1 = SingleHexToDecimal(s[1]);
  332. if (digit1 != -1)
  333. {
  334. int digit2 = SingleHexToDecimal(s[2]);
  335. if (digit2 != -1)
  336. {
  337. s += 3;
  338. *d++ = (char)((digit1 << 4) | digit2);
  339. }
  340. }
  341. break;
  342. }
  343. case '_':
  344. *d++ = ' '; ++s;
  345. break;
  346. default:
  347. *d++ = *s++;
  348. break;
  349. }
  350. }
  351. *d = 0;
  352. }
  353. static size_t utf8toutf16(char* str, wchar_t* res)
  354. {
  355. wchar_t *dec = mir_utf8decodeW(str);
  356. if (dec == NULL) dec = mir_a2u(str);
  357. wcscpy(res, dec);
  358. mir_free(dec);
  359. return wcslen(res);
  360. }
  361. wchar_t* MimeHeaders::decode(const char* val)
  362. {
  363. size_t ssz = strlen(val) * 2 + 1;
  364. char* tbuf = (char*)alloca(ssz);
  365. memcpy(tbuf, val, ssz);
  366. wchar_t* res = (wchar_t*)mir_alloc(ssz * sizeof(wchar_t));
  367. wchar_t* resp = res;
  368. char *p = tbuf;
  369. while (*p)
  370. {
  371. char *cp = strstr(p, "=?");
  372. if (cp == NULL) break;
  373. *cp = 0;
  374. size_t sz = utf8toutf16(p, resp);
  375. ssz -= sz; resp += sz;
  376. cp += 2;
  377. char *enc = strchr(cp, '?');
  378. if (enc == NULL) break;
  379. *(enc++) = 0;
  380. char *fld = strchr(enc, '?');
  381. if (fld == NULL) break;
  382. *(fld++) = 0;
  383. char *pe = strstr(fld, "?=");
  384. if (pe == NULL) break;
  385. *pe = 0;
  386. switch (*enc)
  387. {
  388. case 'b':
  389. case 'B':
  390. {
  391. char* dec = MSN_Base64Decode(fld);
  392. strcpy(fld, dec);
  393. mir_free(dec);
  394. break;
  395. }
  396. case 'q':
  397. case 'Q':
  398. PQDecode(fld);
  399. break;
  400. }
  401. if (_stricmp(cp, "UTF-8") == 0)
  402. {
  403. sz = utf8toutf16(fld, resp);
  404. ssz -= sz; resp += sz;
  405. }
  406. else
  407. {
  408. int sz = MultiByteToWideChar(FindCP(cp), 0, fld, -1, resp, (int)ssz);
  409. if (sz == 0)
  410. sz = MultiByteToWideChar(CP_ACP, 0, fld, -1, resp, (int)ssz);
  411. ssz -= --sz; resp += sz;
  412. }
  413. p = pe + 2;
  414. }
  415. utf8toutf16(p, resp);
  416. return res;
  417. }
  418. char* MimeHeaders::decodeMailBody(char* msgBody)
  419. {
  420. char* res;
  421. const char *val = find("Content-Transfer-Encoding");
  422. if (val && _stricmp(val, "base64") == 0)
  423. {
  424. char *src = msgBody, *dst = msgBody;
  425. while (*src != 0)
  426. {
  427. if (isspace(*src)) ++src;
  428. else *(dst++) = *(src++);
  429. }
  430. *dst = 0;
  431. res = MSN_Base64Decode(msgBody);
  432. }
  433. else
  434. {
  435. res = mir_strdup(msgBody);
  436. if (val && _stricmp(val, "quoted-printable") == 0)
  437. PQDecode(res);
  438. }
  439. return res;
  440. }
  441. int sttDivideWords(char* parBuffer, int parMinItems, char** parDest)
  442. {
  443. int i;
  444. for (i=0; i < parMinItems; i++)
  445. {
  446. parDest[i] = parBuffer;
  447. size_t tWordLen = strcspn(parBuffer, " \t");
  448. if (tWordLen == 0)
  449. return i;
  450. parBuffer += tWordLen;
  451. if (*parBuffer != '\0')
  452. {
  453. size_t tSpaceLen = strspn(parBuffer, " \t");
  454. memset(parBuffer, 0, tSpaceLen);
  455. parBuffer += tSpaceLen;
  456. } }
  457. return i;
  458. }