The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

496 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. #ifndef INTERNET_FLAG_NEED_FILE
  22. #define INTERNET_FLAG_NEED_FILE 0x00000010
  23. #endif
  24. #ifndef INTERNET_OPTION_DISABLE_AUTODIAL
  25. #define INTERNET_OPTION_DISABLE_AUTODIAL 70
  26. #endif
  27. //==============================================================================
  28. #ifndef WORKAROUND_TIMEOUT_BUG
  29. //#define WORKAROUND_TIMEOUT_BUG 1
  30. #endif
  31. #if WORKAROUND_TIMEOUT_BUG
  32. // Required because of a Microsoft bug in setting a timeout
  33. class InternetConnectThread : public Thread
  34. {
  35. public:
  36. InternetConnectThread (URL_COMPONENTS& uc_, HINTERNET sessionHandle_, HINTERNET& connection_, const bool isFtp_)
  37. : Thread ("Internet"), uc (uc_), sessionHandle (sessionHandle_), connection (connection_), isFtp (isFtp_)
  38. {
  39. startThread();
  40. }
  41. ~InternetConnectThread()
  42. {
  43. stopThread (60000);
  44. }
  45. void run()
  46. {
  47. connection = InternetConnect (sessionHandle, uc.lpszHostName,
  48. uc.nPort, _T(""), _T(""),
  49. isFtp ? INTERNET_SERVICE_FTP
  50. : INTERNET_SERVICE_HTTP,
  51. 0, 0);
  52. notify();
  53. }
  54. private:
  55. URL_COMPONENTS& uc;
  56. HINTERNET sessionHandle;
  57. HINTERNET& connection;
  58. const bool isFtp;
  59. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternetConnectThread);
  60. };
  61. #endif
  62. //==============================================================================
  63. class WebInputStream : public InputStream
  64. {
  65. public:
  66. //==============================================================================
  67. WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
  68. URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
  69. const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
  70. : connection (0), request (0),
  71. address (address_), headers (headers_), postData (postData_), position (0),
  72. finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
  73. {
  74. createConnection (progressCallback, progressCallbackContext);
  75. if (responseHeaders != 0 && ! isError())
  76. {
  77. DWORD bufferSizeBytes = 4096;
  78. for (;;)
  79. {
  80. HeapBlock<char> buffer ((size_t) bufferSizeBytes);
  81. if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
  82. {
  83. StringArray headersArray;
  84. headersArray.addLines (reinterpret_cast <const WCHAR*> (buffer.getData()));
  85. for (int i = 0; i < headersArray.size(); ++i)
  86. {
  87. const String& header = headersArray[i];
  88. const String key (header.upToFirstOccurrenceOf (": ", false, false));
  89. const String value (header.fromFirstOccurrenceOf (": ", false, false));
  90. const String previousValue ((*responseHeaders) [key]);
  91. responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
  92. }
  93. break;
  94. }
  95. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  96. break;
  97. }
  98. }
  99. }
  100. ~WebInputStream()
  101. {
  102. close();
  103. }
  104. //==============================================================================
  105. bool isError() const { return request == 0; }
  106. bool isExhausted() { return finished; }
  107. int64 getPosition() { return position; }
  108. int64 getTotalLength()
  109. {
  110. if (! isError())
  111. {
  112. DWORD index = 0, result = 0, size = sizeof (result);
  113. if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
  114. return (int64) result;
  115. }
  116. return -1;
  117. }
  118. int read (void* buffer, int bytesToRead)
  119. {
  120. DWORD bytesRead = 0;
  121. if (! (finished || isError()))
  122. {
  123. InternetReadFile (request, buffer, bytesToRead, &bytesRead);
  124. position += bytesRead;
  125. if (bytesRead == 0)
  126. finished = true;
  127. }
  128. return (int) bytesRead;
  129. }
  130. bool setPosition (int64 wantedPos)
  131. {
  132. if (isError())
  133. return false;
  134. if (wantedPos != position)
  135. {
  136. finished = false;
  137. position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0);
  138. if (position == wantedPos)
  139. return true;
  140. if (wantedPos < position)
  141. {
  142. close();
  143. position = 0;
  144. createConnection (0, 0);
  145. }
  146. skipNextBytes (wantedPos - position);
  147. }
  148. return true;
  149. }
  150. private:
  151. //==============================================================================
  152. HINTERNET connection, request;
  153. String address, headers;
  154. MemoryBlock postData;
  155. int64 position;
  156. bool finished;
  157. const bool isPost;
  158. int timeOutMs;
  159. void close()
  160. {
  161. if (request != 0)
  162. {
  163. InternetCloseHandle (request);
  164. request = 0;
  165. }
  166. if (connection != 0)
  167. {
  168. InternetCloseHandle (connection);
  169. connection = 0;
  170. }
  171. }
  172. void createConnection (URL::OpenStreamProgressCallback* progressCallback,
  173. void* progressCallbackContext)
  174. {
  175. static HINTERNET sessionHandle = InternetOpen (_T("juce"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
  176. close();
  177. if (sessionHandle != 0)
  178. {
  179. // break up the url..
  180. TCHAR file[1024], server[1024];
  181. URL_COMPONENTS uc;
  182. zerostruct (uc);
  183. uc.dwStructSize = sizeof (uc);
  184. uc.dwUrlPathLength = sizeof (file);
  185. uc.dwHostNameLength = sizeof (server);
  186. uc.lpszUrlPath = file;
  187. uc.lpszHostName = server;
  188. if (InternetCrackUrl (address.toUTF16(), 0, 0, &uc))
  189. {
  190. int disable = 1;
  191. InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
  192. if (timeOutMs == 0)
  193. timeOutMs = 30000;
  194. else if (timeOutMs < 0)
  195. timeOutMs = -1;
  196. InternetSetOption (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT, &timeOutMs, sizeof (timeOutMs));
  197. const bool isFtp = address.startsWithIgnoreCase ("ftp:");
  198. #if WORKAROUND_TIMEOUT_BUG
  199. connection = 0;
  200. {
  201. InternetConnectThread connectThread (uc, sessionHandle, connection, isFtp);
  202. connectThread.wait (timeOutMs);
  203. if (connection == 0)
  204. {
  205. InternetCloseHandle (sessionHandle);
  206. sessionHandle = 0;
  207. }
  208. }
  209. #else
  210. connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort,
  211. _T(""), _T(""),
  212. isFtp ? INTERNET_SERVICE_FTP
  213. : INTERNET_SERVICE_HTTP,
  214. 0, 0);
  215. #endif
  216. if (connection != 0)
  217. {
  218. if (isFtp)
  219. {
  220. request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ,
  221. FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0);
  222. }
  223. else
  224. {
  225. const TCHAR* mimeTypes[] = { _T("*/*"), 0 };
  226. DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
  227. if (address.startsWithIgnoreCase ("https:"))
  228. flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
  229. // IE7 seems to automatically work out when it's https)
  230. request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"),
  231. uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0);
  232. if (request != 0)
  233. {
  234. INTERNET_BUFFERS buffers;
  235. zerostruct (buffers);
  236. buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
  237. buffers.lpcszHeader = headers.toUTF16();
  238. buffers.dwHeadersLength = headers.length();
  239. buffers.dwBufferTotal = (DWORD) postData.getSize();
  240. if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
  241. {
  242. int bytesSent = 0;
  243. for (;;)
  244. {
  245. const int bytesToDo = jmin (1024, (int) postData.getSize() - bytesSent);
  246. DWORD bytesDone = 0;
  247. if (bytesToDo > 0
  248. && ! InternetWriteFile (request,
  249. static_cast <const char*> (postData.getData()) + bytesSent,
  250. bytesToDo, &bytesDone))
  251. {
  252. break;
  253. }
  254. if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
  255. {
  256. if (HttpEndRequest (request, 0, 0, 0))
  257. return;
  258. break;
  259. }
  260. bytesSent += bytesDone;
  261. if (progressCallback != 0 && ! progressCallback (progressCallbackContext, bytesSent, postData.getSize()))
  262. break;
  263. }
  264. }
  265. }
  266. close();
  267. }
  268. }
  269. }
  270. }
  271. }
  272. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream);
  273. };
  274. InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
  275. OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
  276. const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
  277. {
  278. ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
  279. progressCallback, progressCallbackContext,
  280. headers, timeOutMs, responseHeaders));
  281. return wi->isError() ? 0 : wi.release();
  282. }
  283. //==============================================================================
  284. namespace MACAddressHelpers
  285. {
  286. void getViaGetAdaptersInfo (Array<MACAddress>& result)
  287. {
  288. DynamicLibraryLoader dll ("iphlpapi.dll");
  289. DynamicLibraryImport (GetAdaptersInfo, getAdaptersInfo, DWORD, dll, (PIP_ADAPTER_INFO, PULONG))
  290. if (getAdaptersInfo != 0)
  291. {
  292. ULONG len = sizeof (IP_ADAPTER_INFO);
  293. MemoryBlock mb;
  294. PIP_ADAPTER_INFO adapterInfo = (PIP_ADAPTER_INFO) mb.getData();
  295. if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
  296. {
  297. mb.setSize (len);
  298. adapterInfo = (PIP_ADAPTER_INFO) mb.getData();
  299. }
  300. if (getAdaptersInfo (adapterInfo, &len) == NO_ERROR)
  301. {
  302. for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != 0; adapter = adapter->Next)
  303. {
  304. if (adapter->AddressLength >= 6)
  305. result.addIfNotAlreadyThere (MACAddress (adapter->Address));
  306. }
  307. }
  308. }
  309. }
  310. void getViaNetBios (Array<MACAddress>& result)
  311. {
  312. DynamicLibraryLoader dll ("netapi32.dll");
  313. DynamicLibraryImport (Netbios, NetbiosCall, UCHAR, dll, (PNCB))
  314. if (NetbiosCall != 0)
  315. {
  316. NCB ncb;
  317. zerostruct (ncb);
  318. struct ASTAT
  319. {
  320. ADAPTER_STATUS adapt;
  321. NAME_BUFFER NameBuff [30];
  322. };
  323. ASTAT astat;
  324. zeromem (&astat, sizeof (astat)); // (can't use zerostruct here in VC6)
  325. LANA_ENUM enums;
  326. zerostruct (enums);
  327. ncb.ncb_command = NCBENUM;
  328. ncb.ncb_buffer = (unsigned char*) &enums;
  329. ncb.ncb_length = sizeof (LANA_ENUM);
  330. NetbiosCall (&ncb);
  331. for (int i = 0; i < enums.length; ++i)
  332. {
  333. zerostruct (ncb);
  334. ncb.ncb_command = NCBRESET;
  335. ncb.ncb_lana_num = enums.lana[i];
  336. if (NetbiosCall (&ncb) == 0)
  337. {
  338. zerostruct (ncb);
  339. memcpy (ncb.ncb_callname, "* ", NCBNAMSZ);
  340. ncb.ncb_command = NCBASTAT;
  341. ncb.ncb_lana_num = enums.lana[i];
  342. ncb.ncb_buffer = (unsigned char*) &astat;
  343. ncb.ncb_length = sizeof (ASTAT);
  344. if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
  345. result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
  346. }
  347. }
  348. }
  349. }
  350. }
  351. void MACAddress::findAllAddresses (Array<MACAddress>& result)
  352. {
  353. MACAddressHelpers::getViaGetAdaptersInfo (result);
  354. MACAddressHelpers::getViaNetBios (result);
  355. }
  356. //==============================================================================
  357. bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
  358. const String& emailSubject,
  359. const String& bodyText,
  360. const StringArray& filesToAttach)
  361. {
  362. HMODULE h = LoadLibraryA ("MAPI32.dll");
  363. typedef ULONG (WINAPI *MAPISendMailType) (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG);
  364. MAPISendMailType mapiSendMail = (MAPISendMailType) GetProcAddress (h, "MAPISendMail");
  365. bool ok = false;
  366. if (mapiSendMail != 0)
  367. {
  368. MapiMessage message;
  369. zerostruct (message);
  370. message.lpszSubject = (LPSTR) emailSubject.toCString();
  371. message.lpszNoteText = (LPSTR) bodyText.toCString();
  372. MapiRecipDesc recip;
  373. zerostruct (recip);
  374. recip.ulRecipClass = MAPI_TO;
  375. String targetEmailAddress_ (targetEmailAddress);
  376. if (targetEmailAddress_.isEmpty())
  377. targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
  378. recip.lpszName = (LPSTR) targetEmailAddress_.toCString();
  379. message.nRecipCount = 1;
  380. message.lpRecips = &recip;
  381. HeapBlock <MapiFileDesc> files;
  382. files.calloc (filesToAttach.size());
  383. message.nFileCount = filesToAttach.size();
  384. message.lpFiles = files;
  385. for (int i = 0; i < filesToAttach.size(); ++i)
  386. {
  387. files[i].nPosition = (ULONG) -1;
  388. files[i].lpszPathName = (LPSTR) filesToAttach[i].toCString();
  389. }
  390. ok = (mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS);
  391. }
  392. FreeLibrary (h);
  393. return ok;
  394. }
  395. #endif