1
0

PCastURIHandler.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "main.h"
  2. #include "./pcasturihandler.h"
  3. #include "./Feeds.h"
  4. #include "./FeedUtil.h"
  5. #include "../nu/AutoLock.h"
  6. #include "./wire.h"
  7. #include "./errors.h"
  8. //#include "../Agave/URIHandler/svc_urihandler.h"
  9. //#include <api/service/waservicefactory.h>
  10. #include "api__ml_wire.h"
  11. #include "./cloud.h"
  12. #include "./SubscriptionView.h"
  13. #include "./resource.h"
  14. #include "navigation.h"
  15. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  16. #include <strsafe.h>
  17. using namespace Nullsoft::Utility;
  18. extern ChannelList channels;
  19. extern Cloud cloud;
  20. static uint8_t quickhex(wchar_t c)
  21. {
  22. int hexvalue = c;
  23. if (hexvalue & 0x10)
  24. hexvalue &= ~0x30;
  25. else
  26. {
  27. hexvalue &= 0xF;
  28. hexvalue += 9;
  29. }
  30. return hexvalue;
  31. }
  32. static uint8_t DecodeEscape(const wchar_t *&str)
  33. {
  34. uint8_t a = quickhex(*++str);
  35. uint8_t b = quickhex(*++str);
  36. str++;
  37. return a * 16 + b;
  38. }
  39. static void DecodeEscapedUTF8(wchar_t *&output, const wchar_t *&input)
  40. {
  41. uint8_t utf8_data[1024] = {0}; // hopefully big enough!!
  42. int num_utf8_words=0;
  43. bool error=false;
  44. while (input && *input == '%' && num_utf8_words < sizeof(utf8_data))
  45. {
  46. if (iswxdigit(input[1]) && iswxdigit(input[2]))
  47. {
  48. utf8_data[num_utf8_words++]=DecodeEscape(input);
  49. }
  50. else if (input[1] == '%')
  51. {
  52. input+=2;
  53. utf8_data[num_utf8_words++]='%';
  54. }
  55. else
  56. {
  57. error = true;
  58. break;
  59. }
  60. }
  61. int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, 0, 0);
  62. MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, output, len);
  63. output += len;
  64. if (error)
  65. {
  66. *output++ = *input++;
  67. }
  68. }
  69. static void UrlDecode(const wchar_t *input, wchar_t *output, size_t len)
  70. {
  71. const wchar_t *stop = output+len-4; // give ourself a cushion large enough to hold a full UTF-16 sequence
  72. const wchar_t *itr = input;
  73. while (itr && *itr)
  74. {
  75. if (output >= stop)
  76. {
  77. *output=0;
  78. return;
  79. }
  80. switch (*itr)
  81. {
  82. case '%':
  83. DecodeEscapedUTF8(output, itr);
  84. break;
  85. case '&':
  86. *output = 0;
  87. return;
  88. default:
  89. *output++ = *itr++;
  90. break;
  91. }
  92. }
  93. *output = 0;
  94. }
  95. // first parameter has param name either null or = terminated, second is null terminated
  96. static bool ParamCompare(const wchar_t *url_param, const wchar_t *param_name)
  97. {
  98. while (url_param && *url_param && *param_name && *url_param!=L'=')
  99. {
  100. if (*url_param++ != *param_name++)
  101. return false;
  102. }
  103. return true;
  104. }
  105. static bool get_request_parm(const wchar_t *params, const wchar_t *param_name, wchar_t *value, size_t value_len)
  106. {
  107. size_t param_name_len = wcslen(param_name);
  108. const wchar_t *t=params;
  109. while (t && *t && *t != L'?') // find start of parameters
  110. t++;
  111. while (t && *t)
  112. {
  113. t++; // skip ? or &
  114. if (ParamCompare(t, param_name))
  115. {
  116. while (t && *t && *t != L'=' && *t != '&') // find start of value
  117. t++;
  118. switch(*t)
  119. {
  120. case L'=':
  121. UrlDecode(++t, value, value_len);
  122. return true;
  123. case 0:
  124. case L'&': // no value
  125. *value=0;
  126. return true;
  127. default: // shouldn't get here
  128. return false;
  129. }
  130. }
  131. while (t && *t && *t != L'&') // find next parameter
  132. t++;
  133. }
  134. return false;
  135. }
  136. int PCastURIHandler::ProcessFilename(const wchar_t *filename)
  137. {
  138. if (
  139. (wcsnicmp(filename, L"pcast://", 8)) == 0 ||
  140. (wcsnicmp(filename, L"feed://", 7) == 0) ||
  141. (wcsnicmp(filename, L"winamp://Podcast/Subscribe", 26) == 0) ||
  142. (wcsnicmp(filename, L"winamp://Podcast/Search", 23) == 0)
  143. )
  144. {
  145. wchar_t *tempFilename = NULL;
  146. wchar_t url[1024] = {0};
  147. if (wcsnicmp(filename, L"winamp://Podcast/Subscribe", 26) == 0)
  148. {
  149. // extract/decode and use the url= parameter
  150. if (get_request_parm(filename, L"url", url, 1024) && url[0])
  151. {
  152. tempFilename = wcsdup(url);
  153. }
  154. else
  155. {
  156. // did not find a url parameter
  157. return NOT_HANDLED;
  158. }
  159. }
  160. else if (wcsnicmp(filename, L"winamp://Podcast/Search", 23) == 0)
  161. {
  162. // TODO: maybe: if (get_request_parm(filename, L"url", url, 1024) && url[0])
  163. {
  164. HNAVITEM hItem = Navigation_FindService(SERVICE_PODCAST, NULL, NULL);
  165. MLNavItem_Select(plugin.hwndLibraryParent, hItem);
  166. return HANDLED;
  167. }
  168. /*
  169. else
  170. {
  171. // did not find a url parameter
  172. return NOT_HANDLED;
  173. }
  174. */
  175. }
  176. else
  177. {
  178. // Use the full filename
  179. tempFilename = wcsdup(filename);
  180. }
  181. // subscription confirmation
  182. WCHAR szText[1024] = {0}, szBuffer[1024] = {0};
  183. WASABI_API_LNGSTRINGW_BUF(IDS_PODCAST_SUBSCRIPTION_PROMP, szBuffer, ARRAYSIZE(szBuffer));
  184. StringCchPrintf(szText, ARRAYSIZE(szText), szBuffer, tempFilename);
  185. WASABI_API_LNGSTRINGW_BUF(IDS_PODCAST_SUBSCRIPTION_HEADER, szBuffer, ARRAYSIZE(szBuffer));
  186. if (IDYES == MessageBox(plugin.hwndLibraryParent, szText, szBuffer, MB_YESNO | MB_ICONQUESTION | MB_TOPMOST | MB_SETFOREGROUND) )
  187. {
  188. // add feed to channels, pulse the cloud, refresh the UI pane.
  189. Channel newFeed;
  190. newFeed.SetURL(tempFilename);
  191. if (DownloadFeedInformation(newFeed)==DOWNLOAD_SUCCESS)
  192. {
  193. channels.channelGuard.Lock();
  194. channels.AddChannel(newFeed);
  195. channels.channelGuard.Unlock();
  196. cloud.Pulse();
  197. HWND hView = SubscriptionView_FindWindow();
  198. if (NULL != hView)
  199. {
  200. SubscriptionView_RefreshChannels(hView, TRUE);
  201. }
  202. else
  203. {
  204. HNAVITEM myItem = Navigation_FindService(SERVICE_PODCAST, NULL, NULL);
  205. HNAVITEM podcastItem = MLNavItem_GetChild(plugin.hwndLibraryParent, myItem);
  206. HNAVITEM subscriptionItem = Navigation_FindService(SERVICE_SUBSCRIPTION, podcastItem, NULL);
  207. MLNavItem_Select(plugin.hwndLibraryParent, subscriptionItem);
  208. }
  209. }
  210. free(tempFilename);
  211. return HANDLED;
  212. }
  213. else
  214. free(tempFilename);
  215. }
  216. return NOT_HANDLED;
  217. }
  218. int PCastURIHandler::IsMine(const wchar_t *filename)
  219. {
  220. int i = 0;
  221. if (
  222. (wcsnicmp(filename, L"pcast://", 8)) == 0 ||
  223. (wcsnicmp(filename, L"feed://", 7) == 0) ||
  224. (wcsnicmp(filename, L"winamp://Podcast/Subscribe", 26) == 0) ||
  225. (wcsnicmp(filename, L"winamp://Podcast/Search", 23) == 0)
  226. )
  227. return HANDLED;
  228. else
  229. return NOT_HANDLED;
  230. }
  231. #define CBCLASS PCastURIHandler
  232. START_DISPATCH;
  233. CB(PROCESSFILENAME, ProcessFilename);
  234. CB(ISMINE, IsMine);
  235. END_DISPATCH;
  236. #undef CBCLASS