utils.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. #pragma once
  2. static const char threadTimestampFmt[] = "%Y/%m/%d %H:%M:%S %Z";
  3. static const char httpTimestampFmt[] = "%a, %d %b %Y %H:%M:%S GMT";
  4. static void *
  5. memmem_priv(const void *l, size_t l_len, const void *s, size_t s_len)
  6. {
  7. register char *cur, *last;
  8. const char *cl = (const char *)l;
  9. const char *cs = (const char *)s;
  10. /* we need something to compare */
  11. if (l_len == 0 || s_len == 0)
  12. return NULL;
  13. /* "s" must be smaller or equal to "l" */
  14. if (l_len < s_len)
  15. return NULL;
  16. /* special case where s_len == 1 */
  17. if (s_len == 1)
  18. return (void *)memchr(l, (int)*cs, l_len);
  19. /* the last position where its possible to find "s" in "l" */
  20. last = (char *)cl + l_len - s_len;
  21. for (cur = (char *)cl; cur <= last; cur++)
  22. if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
  23. return cur;
  24. return NULL;
  25. }
  26. static int decryptMail(unsigned char *decrypted, char *encrypted)
  27. {
  28. char current[5]="0x";
  29. unsigned char *ptr = decrypted;
  30. current[2] = encrypted[0];
  31. current[3] = encrypted[1];
  32. unsigned int r = strtol(current,NULL,16);
  33. int len = strlen(encrypted);
  34. int n = 2;
  35. for(;n<len;n+=2) {
  36. current[2] = encrypted[n];
  37. current[3] = encrypted[n+1];
  38. unsigned int i = strtol(current,NULL,16);
  39. *ptr++ = i^r;
  40. }
  41. *ptr = 0;
  42. //fprintf(stderr,"%s->%s\n",encrypted,decrypted);
  43. return ptr - decrypted;
  44. }
  45. static size_t header_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
  46. {
  47. BBS2chProxyConnection *conn = reinterpret_cast<BBS2chProxyConnection *>(userdata);
  48. if(conn->status) return size*nitems;
  49. if(!strncasecmp("Connection",buffer,10)) {
  50. fprintf(conn->fpw,"Connection: Close\r\n");
  51. return size*nitems;
  52. }
  53. else if(!strncasecmp("Transfer-Encoding",buffer,17)) {
  54. if(allow_chunked && strstr(buffer+19,"chunked")) {
  55. conn->chunked = true;
  56. //fprintf(stderr,"%s",buffer);
  57. size_t ret = fwrite(buffer,size,nitems,conn->fpw);
  58. return ret;
  59. }
  60. return size*nitems;
  61. }
  62. else if(conn->force5ch && !strncasecmp("Set-Cookie:",buffer,11)) {
  63. char *ptr = (char *)memmem_priv(buffer,size*nitems,"domain=",7);
  64. if(ptr) {
  65. char *end = ptr;
  66. while(*end != ';' && *end != '\r') end++;
  67. ptr = (char *)memmem_priv(ptr,end-ptr,"5ch.net",7);
  68. if(ptr) {
  69. fwrite(buffer,1,ptr-buffer,conn->fpw);
  70. fputc('2',conn->fpw);
  71. fwrite(ptr+1,1,size*nitems-(ptr+1-buffer),conn->fpw);
  72. return size*nitems;
  73. }
  74. }
  75. return fwrite(buffer,1,size*nitems,conn->fpw);
  76. }
  77. else {
  78. #ifdef USE_LUA
  79. if (conn->bbscgi) {
  80. if (!strncasecmp("X-MonaKey:", buffer, 10)) {
  81. const char *ptr = buffer + 10;
  82. while (*ptr == ' ') ptr++;
  83. const char *end = ptr;
  84. while (*end != '\n' && *end != '\r' && *end) end++;
  85. conn->setMonaKey(std::string(ptr, end-ptr));
  86. }
  87. else if (!strncasecmp("X-Chx-Error:", buffer, 12)) {
  88. const char *ptr = buffer + 12;
  89. while (*ptr == ' ') ptr++;
  90. if (*ptr == 'E' && atoi(ptr+1) == 3310) {
  91. conn->setMonaKey("");
  92. }
  93. }
  94. }
  95. #endif
  96. size_t ret = fwrite(buffer,size,nitems,conn->fpw);
  97. //fprintf(stderr,"%s",buffer);
  98. if(!memcmp(buffer,"\r\n",2)) {
  99. fflush(conn->fpw);
  100. conn->status = 1;
  101. }
  102. return ret;
  103. }
  104. }
  105. static size_t write_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
  106. {
  107. BBS2chProxyConnection *conn = reinterpret_cast<BBS2chProxyConnection *>(userdata);
  108. if(conn->chunked) fprintf(conn->fpw,"%lx\r\n",size*nitems);
  109. size_t ret = fwrite(buffer,size,nitems,conn->fpw);
  110. if(conn->chunked) fprintf(conn->fpw,"\r\n");
  111. fflush(conn->fpw);
  112. return ret;
  113. }
  114. static size_t header_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
  115. {
  116. DataStorage *data = reinterpret_cast<DataStorage *>(userdata);
  117. if(!strncasecmp("Connection",buffer,10)) {
  118. data->appendBytes("Connection: Close\r\n",19);
  119. return size*nitems;
  120. }
  121. else if(!strncasecmp("Transfer-Encoding",buffer,17)) {
  122. return size*nitems;
  123. }
  124. else {
  125. data->appendBytes(buffer,size*nitems);
  126. return size*nitems;
  127. }
  128. }
  129. static size_t write_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
  130. {
  131. DataStorage *data = reinterpret_cast<DataStorage *>(userdata);
  132. size_t downloaded = size*nitems;
  133. data->appendBytes(buffer, downloaded);
  134. return downloaded;
  135. }
  136. static size_t read_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
  137. {
  138. BBS2chProxyConnection *conn = reinterpret_cast<BBS2chProxyConnection *>(userdata);
  139. if(size*nitems < 1) return 0;
  140. if(conn->content_length) {
  141. size_t bytesToRead = conn->content_length;
  142. if(size*nitems < conn->content_length) bytesToRead = size*nitems;
  143. size_t ret = fread(buffer,1,bytesToRead,conn->fpr);
  144. conn->content_length -= ret;
  145. return ret;
  146. }
  147. return 0;
  148. }
  149. static void sendBasicHeaders(int respCode, const char *respMsg, FILE *fpw)
  150. {
  151. char date[256];
  152. time_t now = time(0);
  153. strftime(date, 256, httpTimestampFmt, gmtime(&now));
  154. if(0 > fprintf(fpw, "HTTP/1.1 %d %s\r\n",respCode,respMsg)) return;
  155. if(0 > fprintf(fpw, "Connection: Close\r\n")) return;
  156. if(0 > fprintf(fpw, "Server: 2ch Proxy\r\n")) return;
  157. if(0 > fprintf(fpw, "Date: %s\r\n",date)) return;
  158. fflush(fpw);
  159. }
  160. static void sendResponse(int respCode, const char *respMsg, FILE *fpw)
  161. {
  162. sendBasicHeaders(respCode, respMsg, fpw);
  163. if(0 > fprintf(fpw, "Content-Type: text/plain; charset=UTF-8\r\n")) return;
  164. if(0 > fprintf(fpw, "\r\n")) return;
  165. if(respCode >= 400) {
  166. if(0 > fprintf(fpw, "   ∧_∧   / ̄ ̄ ̄ ̄ ̄\n")) return;
  167. if(0 > fprintf(fpw, "  ( ´∀`)< %s\n",respMsg)) return;
  168. if(0 > fprintf(fpw, "  (    ) \_____\n")) return;
  169. if(0 > fprintf(fpw, "   │ │ │\n")) return;
  170. if(0 > fprintf(fpw, "  (__)_)\n")) return;
  171. }
  172. fflush(fpw);
  173. }
  174. #ifdef __WIN32__
  175. const char * strp_weekdays[] =
  176. { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"};
  177. const char * strp_monthnames[] =
  178. { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"};
  179. bool strp_atoi(const char * & s, int & result, int low, int high, int offset)
  180. {
  181. bool worked = false;
  182. char * end;
  183. unsigned long num = strtoul(s, & end, 10);
  184. if (num >= (unsigned long)low && num <= (unsigned long)high)
  185. {
  186. result = (int)(num + offset);
  187. s = end;
  188. worked = true;
  189. }
  190. return worked;
  191. }
  192. char * strptime(const char *s, const char *format, struct tm *tm)
  193. {
  194. bool working = true;
  195. while (working && *format && *s)
  196. {
  197. switch (*format)
  198. {
  199. case '%':
  200. {
  201. ++format;
  202. switch (*format)
  203. {
  204. case 'a':
  205. case 'A': // weekday name
  206. tm->tm_wday = -1;
  207. working = false;
  208. for (size_t i = 0; i < 7; ++ i)
  209. {
  210. size_t len = strlen(strp_weekdays[i]);
  211. if (!strnicmp(strp_weekdays[i], s, len))
  212. {
  213. tm->tm_wday = i;
  214. s += len;
  215. working = true;
  216. break;
  217. }
  218. else if (!strnicmp(strp_weekdays[i], s, 3))
  219. {
  220. tm->tm_wday = i;
  221. s += 3;
  222. working = true;
  223. break;
  224. }
  225. }
  226. break;
  227. case 'b':
  228. case 'B':
  229. case 'h': // month name
  230. tm->tm_mon = -1;
  231. working = false;
  232. for (size_t i = 0; i < 12; ++ i)
  233. {
  234. size_t len = strlen(strp_monthnames[i]);
  235. if (!strnicmp(strp_monthnames[i], s, len))
  236. {
  237. tm->tm_mon = i;
  238. s += len;
  239. working = true;
  240. break;
  241. }
  242. else if (!strnicmp(strp_monthnames[i], s, 3))
  243. {
  244. tm->tm_mon = i;
  245. s += 3;
  246. working = true;
  247. break;
  248. }
  249. }
  250. break;
  251. case 'd':
  252. case 'e': // day of month number
  253. working = strp_atoi(s, tm->tm_mday, 1, 31, 0);
  254. break;
  255. case 'D': // %m/%d/%y
  256. {
  257. const char * s_save = s;
  258. working = strp_atoi(s, tm->tm_mon, 1, 12, -1);
  259. if (working && *s == '/')
  260. {
  261. ++ s;
  262. working = strp_atoi(s, tm->tm_mday, 1, 31, 0);
  263. if (working && *s == '/')
  264. {
  265. ++ s;
  266. working = strp_atoi(s, tm->tm_year, 0, 99, 0);
  267. if (working && tm->tm_year < 69)
  268. tm->tm_year += 100;
  269. }
  270. }
  271. if (!working)
  272. s = s_save;
  273. }
  274. break;
  275. case 'H': // hour
  276. working = strp_atoi(s, tm->tm_hour, 0, 23, 0);
  277. break;
  278. case 'I': // hour 12-hour clock
  279. working = strp_atoi(s, tm->tm_hour, 1, 12, 0);
  280. break;
  281. case 'j': // day number of year
  282. working = strp_atoi(s, tm->tm_yday, 1, 366, -1);
  283. break;
  284. case 'm': // month number
  285. working = strp_atoi(s, tm->tm_mon, 1, 12, -1);
  286. break;
  287. case 'M': // minute
  288. working = strp_atoi(s, tm->tm_min, 0, 59, 0);
  289. break;
  290. case 'n': // arbitrary whitespace
  291. case 't':
  292. while (isspace((int)*s))
  293. ++s;
  294. break;
  295. case 'p': // am / pm
  296. if (!strnicmp(s, "am", 2))
  297. { // the hour will be 1 -> 12 maps to 12 am, 1 am .. 11 am, 12 noon 12 pm .. 11 pm
  298. if (tm->tm_hour == 12) // 12 am == 00 hours
  299. tm->tm_hour = 0;
  300. }
  301. else if (!strnicmp(s, "pm", 2))
  302. {
  303. if (tm->tm_hour < 12) // 12 pm == 12 hours
  304. tm->tm_hour += 12; // 1 pm -> 13 hours, 11 pm -> 23 hours
  305. }
  306. else
  307. working = false;
  308. break;
  309. case 'r': // 12 hour clock %I:%M:%S %p
  310. {
  311. const char * s_save = s;
  312. working = strp_atoi(s, tm->tm_hour, 1, 12, 0);
  313. if (working && *s == ':')
  314. {
  315. ++ s;
  316. working = strp_atoi(s, tm->tm_min, 0, 59, 0);
  317. if (working && *s == ':')
  318. {
  319. ++ s;
  320. working = strp_atoi(s, tm->tm_sec, 0, 60, 0);
  321. if (working && isspace((int)*s))
  322. {
  323. ++ s;
  324. while (isspace((int)*s))
  325. ++s;
  326. if (!strnicmp(s, "am", 2))
  327. { // the hour will be 1 -> 12 maps to 12 am, 1 am .. 11 am, 12 noon 12 pm .. 11 pm
  328. if (tm->tm_hour == 12) // 12 am == 00 hours
  329. tm->tm_hour = 0;
  330. }
  331. else if (!strnicmp(s, "pm", 2))
  332. {
  333. if (tm->tm_hour < 12) // 12 pm == 12 hours
  334. tm->tm_hour += 12; // 1 pm -> 13 hours, 11 pm -> 23 hours
  335. }
  336. else
  337. working = false;
  338. }
  339. }
  340. }
  341. if (!working)
  342. s = s_save;
  343. }
  344. break;
  345. case 'R': // %H:%M
  346. {
  347. const char * s_save = s;
  348. working = strp_atoi(s, tm->tm_hour, 0, 23, 0);
  349. if (working && *s == ':')
  350. {
  351. ++ s;
  352. working = strp_atoi(s, tm->tm_min, 0, 59, 0);
  353. }
  354. if (!working)
  355. s = s_save;
  356. }
  357. break;
  358. case 'S': // seconds
  359. working = strp_atoi(s, tm->tm_sec, 0, 60, 0);
  360. break;
  361. case 'T': // %H:%M:%S
  362. {
  363. const char * s_save = s;
  364. working = strp_atoi(s, tm->tm_hour, 0, 23, 0);
  365. if (working && *s == ':')
  366. {
  367. ++ s;
  368. working = strp_atoi(s, tm->tm_min, 0, 59, 0);
  369. if (working && *s == ':')
  370. {
  371. ++ s;
  372. working = strp_atoi(s, tm->tm_sec, 0, 60, 0);
  373. }
  374. }
  375. if (!working)
  376. s = s_save;
  377. }
  378. break;
  379. case 'w': // weekday number 0->6 sunday->saturday
  380. working = strp_atoi(s, tm->tm_wday, 0, 6, 0);
  381. break;
  382. case 'Y': // year
  383. working = strp_atoi(s, tm->tm_year, 1900, 65535, -1900);
  384. break;
  385. case 'y': // 2-digit year
  386. working = strp_atoi(s, tm->tm_year, 0, 99, 0);
  387. if (working && tm->tm_year < 69)
  388. tm->tm_year += 100;
  389. break;
  390. case '%': // escaped
  391. if (*s != '%')
  392. working = false;
  393. ++s;
  394. break;
  395. default:
  396. working = false;
  397. }
  398. }
  399. break;
  400. case ' ':
  401. case '\t':
  402. case '\r':
  403. case '\n':
  404. case '\f':
  405. case '\v':
  406. // zero or more whitespaces:
  407. while (isspace((int)*s))
  408. ++ s;
  409. break;
  410. default:
  411. // match character
  412. if (*s != *format)
  413. working = false;
  414. else
  415. ++s;
  416. break;
  417. }
  418. ++format;
  419. }
  420. return (working?(char *)s:0);
  421. }
  422. #endif