post.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. #include "main.h"
  2. #include "api.h"
  3. #include "resource.h"
  4. #include "../xml/obj_xml.h"
  5. #include "nu/AutoChar.h"
  6. #include "../nu/AutoUrl.h"
  7. #include "../nu/AutoHeader.h"
  8. #include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
  9. #include "../agave/albumart/svc_albumartprovider.h"
  10. #include <api/service/waservicefactory.h>
  11. #include <shlwapi.h>
  12. #include <strsafe.h>
  13. static const GUID internetConfigGroupGUID =
  14. {
  15. 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
  16. };
  17. #define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/)
  18. static void SetUserAgent(api_httpreceiver *http)
  19. {
  20. char user_agent[USER_AGENT_SIZE] = {0};
  21. int bigVer = ((winampVersion & 0x0000FF00) >> 12);
  22. int smallVer = ((winampVersion & 0x000000FF));
  23. StringCchPrintfA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/%01x.%02x", bigVer, smallVer);
  24. http->addheader(user_agent);
  25. }
  26. #define HTTP_BUFFER_SIZE 8192
  27. #define POST_BUFFER_SIZE (128*1024)
  28. int PostFile(const char *base_url, const wchar_t *filename, const itemRecordW *track, obj_xml *parser, int *killswitch,
  29. void (*callback)(void *callbackContext, wchar_t *status), void *context, char *new_item_id, size_t new_item_id_len)
  30. {
  31. //if (!parser)
  32. // return 1;
  33. bool first=true;
  34. char url[2048] = {0};
  35. char *p_url=url;
  36. size_t url_cch=sizeof(url)/sizeof(*url);
  37. FILE *f = _wfopen(filename, L"rb");
  38. if (!f)
  39. return 1;
  40. api_httpreceiver *http = 0;
  41. waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
  42. if (sf)
  43. http = (api_httpreceiver *)sf->getInterface();
  44. if (!http)
  45. return 1;
  46. int use_proxy = 1;
  47. bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
  48. if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
  49. use_proxy = 0;
  50. const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
  51. fseek(f, 0, SEEK_END);
  52. size_t clen = ftell(f);
  53. size_t transferred=0;
  54. size_t total_clen = clen;
  55. fseek(f, 0, SEEK_SET);
  56. http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
  57. http->set_sendbufsize(POST_BUFFER_SIZE);
  58. SetUserAgent(http);
  59. char data[POST_BUFFER_SIZE] = {0};
  60. StringCbCopyExA(p_url, url_cch, base_url, &p_url, &url_cch, 0);
  61. StringCbPrintfA(data, sizeof(data), "Content-Length: %u", clen);
  62. http->addheader(data);
  63. // http->addheader("Content-Type: application/octet-stream");
  64. /* send metadata */
  65. if (track->artist && track->artist[0])
  66. {
  67. if (first)
  68. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?artist=%s", AutoUrl(track->artist));
  69. else
  70. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&artist=%s", AutoUrl(track->artist));
  71. first=false;
  72. }
  73. if (track->title && track->title[0])
  74. {
  75. if (first)
  76. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?title=%s", AutoUrl(track->title));
  77. else
  78. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&title=%s", AutoUrl(track->title));
  79. first=false;
  80. }
  81. if (track->album && track->album[0])
  82. {
  83. if (first)
  84. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?album=%s", AutoUrl(track->album));
  85. else
  86. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&album=%s", AutoUrl(track->album));
  87. first=false;
  88. }
  89. if (track->composer && track->composer[0])
  90. {
  91. if (first)
  92. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?composer=%s", AutoUrl(track->composer));
  93. else
  94. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&composer=%s", AutoUrl(track->composer));
  95. first=false;
  96. }
  97. if (track->albumartist && track->albumartist[0])
  98. {
  99. if (first)
  100. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?albumartist=%s", AutoUrl(track->albumartist));
  101. else
  102. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&albumartist=%s", AutoUrl(track->albumartist));
  103. first=false;
  104. }
  105. if (track->genre && track->genre[0])
  106. {
  107. if (first)
  108. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?genre=%s", AutoUrl(track->genre));
  109. else
  110. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&genre=%s", AutoUrl(track->genre));
  111. first=false;
  112. }
  113. if (track->track > 0)
  114. {
  115. if (first)
  116. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?track=%d", track->track);
  117. else
  118. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&track=%d", track->track);
  119. first=false;
  120. }
  121. const wchar_t *ext = PathFindExtension(filename);
  122. if (ext && ext[0])
  123. {
  124. if (ext[0] == '.') ext++;
  125. if (ext[0])
  126. {
  127. if (first)
  128. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?extension=%s", AutoUrl(ext));
  129. else
  130. StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&extension=%s", AutoUrl(ext));
  131. first=false;
  132. }
  133. }
  134. wchar_t mime_type[128] = {0};
  135. if (AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"mime", mime_type, 128) == 1 && mime_type[0])
  136. {
  137. http->AddHeaderValue("Content-Type", AutoHeader(mime_type));
  138. }
  139. http->AddHeaderValue("X-Winamp-ID", winamp_id_str);
  140. http->AddHeaderValue("X-Winamp-Name", winamp_name);
  141. http->AddHeaderValue("Expect", "100-continue");
  142. /* connect */
  143. callback(context, WASABI_API_LNGSTRINGW(IDS_CONNECTING));
  144. http->connect(url, 0, "POST");
  145. // spin and wait for a 100 response
  146. for (;;)
  147. {
  148. Sleep(55);
  149. if (*killswitch)
  150. goto connection_failed;
  151. int ret = http->run();
  152. if (ret != HTTPRECEIVER_RUN_OK) // connection failed or closed
  153. goto connection_failed;
  154. int reply_code = http->getreplycode();
  155. if (reply_code == 100)
  156. break;
  157. else if (reply_code)
  158. goto connection_failed;
  159. }
  160. /* POST the data */
  161. api_connection *connection = http->GetConnection();
  162. if (connection)
  163. {
  164. if (http->run() == -1)
  165. goto connection_failed;
  166. while (clen)
  167. {
  168. int percent = MulDiv(100, (int)transferred, (int)total_clen);
  169. wchar_t msg[128] = {0};
  170. StringCbPrintfW(msg, sizeof(msg), WASABI_API_LNGSTRINGW(IDS_UPLOADING), percent);
  171. callback(context, msg);
  172. if (*killswitch)
  173. goto connection_failed;
  174. if (http->run() == -1)
  175. goto connection_failed;
  176. int connection_state = connection->get_state();
  177. if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
  178. goto connection_failed;
  179. size_t lengthToSend = min(clen, connection->GetSendBytesAvailable());
  180. lengthToSend = min(lengthToSend, sizeof(data));
  181. if (lengthToSend)
  182. {
  183. int bytes_read = (int)fread(data, 1, lengthToSend, f);
  184. connection->send(data, bytes_read);
  185. clen-=bytes_read;
  186. transferred+=bytes_read;
  187. }
  188. else
  189. {
  190. Sleep(10);
  191. }
  192. }
  193. int x;
  194. while (x = (int)connection->GetSendBytesInQueue())
  195. {
  196. int connection_state = connection->get_state();
  197. if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
  198. goto connection_failed;
  199. Sleep(10);
  200. if (*killswitch)
  201. goto connection_failed;
  202. if (http->run() == -1)
  203. goto connection_failed;
  204. }
  205. }
  206. fclose(f);
  207. f=0;
  208. /* retrieve reply */
  209. int ret;
  210. do
  211. {
  212. Sleep(55);
  213. ret = http->run();
  214. if (ret == -1) // connection failed
  215. break;
  216. // ---- check our reply code ----
  217. int status = http->get_status();
  218. switch (status)
  219. {
  220. case HTTPRECEIVER_STATUS_CONNECTING:
  221. case HTTPRECEIVER_STATUS_READING_HEADERS:
  222. break;
  223. case HTTPRECEIVER_STATUS_READING_CONTENT:
  224. {
  225. const char *location = http->getheader("Location");
  226. if (location)
  227. StringCchCopyA(new_item_id, new_item_id_len, location);
  228. else
  229. new_item_id[0]=0;
  230. sf->releaseInterface(http);
  231. return 0;
  232. }
  233. break;
  234. case HTTPRECEIVER_STATUS_ERROR:
  235. default:
  236. sf->releaseInterface(http);
  237. return 1;
  238. }
  239. }
  240. while (ret == HTTPRECEIVER_RUN_OK);
  241. connection_failed:
  242. if (f)
  243. fclose(f);
  244. sf->releaseInterface(http);
  245. return 1;
  246. }
  247. int PostAlbumArt(const char *url, const itemRecordW *track, obj_xml *parser, int *killswitch, void (*callback)(void *callbackContext, wchar_t *status), void *context)
  248. {
  249. void *artData=0;
  250. size_t datalen=0;
  251. wchar_t *mimeType=0;
  252. if (AGAVE_API_ALBUMART->GetAlbumArtData(track->filename, L"cover", &artData, &datalen, &mimeType) != ALBUMART_SUCCESS)
  253. return 1;
  254. api_httpreceiver *http = 0;
  255. waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
  256. if (sf)
  257. http = (api_httpreceiver *)sf->getInterface();
  258. if (!http)
  259. return 1;
  260. int use_proxy = 1;
  261. bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
  262. if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
  263. use_proxy = 0;
  264. const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
  265. uint8_t *artDataPtr=(uint8_t *)artData;
  266. size_t clen = datalen;
  267. size_t transferred=0;
  268. size_t total_clen = datalen;
  269. http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
  270. http->set_sendbufsize(POST_BUFFER_SIZE);
  271. SetUserAgent(http);
  272. char data[POST_BUFFER_SIZE] = {0};
  273. StringCbPrintfA(data, sizeof(data), "Content-Length: %u", datalen);
  274. http->addheader(data);
  275. if (mimeType)
  276. {
  277. StringCbPrintfA(data, sizeof(data), "Content-Type: %s", AutoHeader(mimeType));
  278. http->addheader(data);
  279. }
  280. http->AddHeaderValue("X-Winamp-ID", winamp_id_str);
  281. http->AddHeaderValue("X-Winamp-Name", winamp_name);
  282. /* connect */
  283. http->AddHeaderValue("Expect", "100-continue");
  284. callback(context, WASABI_API_LNGSTRINGW(IDS_CONNECTING));
  285. http->connect(url, 0, "POST");
  286. // spin and wait for a 100 response
  287. for (;;)
  288. {
  289. Sleep(55);
  290. int ret = http->run();
  291. if (ret != HTTPRECEIVER_RUN_OK) // connection failed or closed
  292. goto connection_failed;
  293. if (*killswitch)
  294. goto connection_failed;
  295. int reply_code = http->getreplycode();
  296. if (reply_code == 100)
  297. break;
  298. else if (reply_code)
  299. goto connection_failed;
  300. }
  301. /* POST the data */
  302. api_connection *connection = http->GetConnection();
  303. if (connection)
  304. {
  305. if (http->run() == -1)
  306. goto connection_failed;
  307. while (clen)
  308. {
  309. int percent = MulDiv(100, (int)transferred, (int)total_clen);
  310. wchar_t msg[128] = {0};
  311. StringCbPrintfW(msg, sizeof(msg), L"Uploading Album Art (%d%%)", percent);
  312. callback(context, msg);
  313. if (*killswitch)
  314. goto connection_failed;
  315. if (http->run() == -1)
  316. goto connection_failed;
  317. int connection_state = connection->get_state();
  318. if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
  319. goto connection_failed;
  320. size_t lengthToSend = min(clen, connection->GetSendBytesAvailable());
  321. if (lengthToSend)
  322. {
  323. connection->send(artDataPtr, (int)lengthToSend);
  324. artDataPtr += lengthToSend;
  325. clen-=lengthToSend;
  326. transferred+=lengthToSend;
  327. }
  328. else
  329. {
  330. Sleep(10);
  331. }
  332. }
  333. int x;
  334. while (x = (int)connection->GetSendBytesInQueue())
  335. {
  336. int connection_state = connection->get_state();
  337. if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
  338. goto connection_failed;
  339. Sleep(10);
  340. if (*killswitch)
  341. goto connection_failed;
  342. if (http->run() == -1)
  343. goto connection_failed;
  344. }
  345. }
  346. /* retrieve reply */
  347. int ret;
  348. do
  349. {
  350. Sleep(55);
  351. ret = http->run();
  352. if (ret == -1) // connection failed
  353. break;
  354. // ---- check our reply code ----
  355. int status = http->get_status();
  356. switch (status)
  357. {
  358. case HTTPRECEIVER_STATUS_CONNECTING:
  359. case HTTPRECEIVER_STATUS_READING_HEADERS:
  360. break;
  361. case HTTPRECEIVER_STATUS_READING_CONTENT:
  362. {
  363. sf->releaseInterface(http);
  364. WASABI_API_MEMMGR->sysFree(artData);
  365. WASABI_API_MEMMGR->sysFree(mimeType);
  366. return 0;
  367. }
  368. break;
  369. case HTTPRECEIVER_STATUS_ERROR:
  370. default:
  371. sf->releaseInterface(http);
  372. WASABI_API_MEMMGR->sysFree(artData);
  373. WASABI_API_MEMMGR->sysFree(mimeType);
  374. return 1;
  375. }
  376. }
  377. while (ret == HTTPRECEIVER_RUN_OK);
  378. connection_failed:
  379. WASABI_API_MEMMGR->sysFree(artData);
  380. WASABI_API_MEMMGR->sysFree(mimeType);
  381. sf->releaseInterface(http);
  382. return 1;
  383. }
  384. int HTTP_Delete(const char *url)
  385. {
  386. api_httpreceiver *http = 0;
  387. waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
  388. if (sf)
  389. http = (api_httpreceiver *)sf->getInterface();
  390. if (!http)
  391. return 1;
  392. int use_proxy = 1;
  393. bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
  394. if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
  395. use_proxy = 0;
  396. const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
  397. http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
  398. SetUserAgent(http);
  399. http->AddHeaderValue("X-Winamp-ID", winamp_id_str);
  400. http->AddHeaderValue("X-Winamp-Name", winamp_name);
  401. /* connect */
  402. http->connect(url, 0, "DELETE");
  403. /* retrieve reply */
  404. int ret;
  405. do
  406. {
  407. Sleep(55);
  408. ret = http->run();
  409. if (ret == -1) // connection failed
  410. break;
  411. // ---- check our reply code ----
  412. int status = http->get_status();
  413. switch (status)
  414. {
  415. case HTTPRECEIVER_STATUS_CONNECTING:
  416. case HTTPRECEIVER_STATUS_READING_HEADERS:
  417. break;
  418. case HTTPRECEIVER_STATUS_READING_CONTENT:
  419. {
  420. sf->releaseInterface(http);
  421. return 0;
  422. }
  423. break;
  424. case HTTPRECEIVER_STATUS_ERROR:
  425. default:
  426. sf->releaseInterface(http);
  427. return 1;
  428. }
  429. }
  430. while (ret == HTTPRECEIVER_RUN_OK);
  431. sf->releaseInterface(http);
  432. return 1;
  433. }