123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 |
- #include "JnetCOM.h"
- #include "main.h"
- #include "../nu/AutoChar.h"
- #include "../nu/AutoWide.h"
- #include <algorithm>
- #include <map>
- #include "config.h"
- #include <time.h>
- #include "../nu/MediaLibraryInterface.h"
- #include "api__ml_online.h"
- #include <api/service/waServiceFactory.h>
- #include <strsafe.h>
- extern C_Config *g_config;
- BufferMap buffer_map;
- enum
- {
- DISP_JNET_INIT = 9323,
- DISP_JNET_DOWNLOAD,
- DISP_JNET_STATUS,
- DISP_JNET_SIZE,
- DISP_JNET_BUFFER,
- DISP_JNET_BUFFER_RAW,
- DISP_JNET_POST,
- };
- HANDLE DuplicateCurrentThread()
- {
- HANDLE fakeHandle = GetCurrentThread();
- HANDLE copiedHandle = 0;
- HANDLE processHandle = GetCurrentProcess();
- DuplicateHandle(processHandle, fakeHandle, processHandle, &copiedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
- return copiedHandle;
- }
- #define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; }
- HRESULT JnetCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
- {
- bool unknowns = false;
- for (unsigned int i = 0;i != cNames;i++)
- {
- CHECK_ID("Init", DISP_JNET_INIT)
- CHECK_ID("Download", DISP_JNET_DOWNLOAD)
- CHECK_ID("Status", DISP_JNET_STATUS)
- CHECK_ID("Buffer", DISP_JNET_BUFFER)
- CHECK_ID("BufferRaw", DISP_JNET_BUFFER_RAW)
- CHECK_ID("Size", DISP_JNET_SIZE)
- CHECK_ID("Post", DISP_JNET_POST)
- rgdispid[i] = DISPID_UNKNOWN;
- unknowns = true;
- }
- if (unknowns)
- return DISP_E_UNKNOWNNAME;
- else
- return S_OK;
- }
- HRESULT JnetCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
- {
- return E_NOTIMPL;
- }
- HRESULT JnetCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
- {
- return E_NOTIMPL;
- }
- HRESULT JnetCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
- {
- switch (dispid)
- {
- case DISP_JNET_INIT:
- {
- if (!active && NULL == callback)
- {
- finalSize = 0;
- isBlocking = true;
- if ( pdispparams->cArgs == 2 )
- {
- isBlocking = false;
- htmldiv = SysAllocString(pdispparams->rgvarg[0].bstrVal); // HTML DIV
- callback = pdispparams->rgvarg[1].pdispVal; // callback object;
- if (NULL != callback)
- callback->AddRef();
- }
- }
- else
- {
- if (pvarResult)
- {
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_I4;
- V_I4(pvarResult) = -1;
- }
- }
- return S_OK;
- }
- break;
- case DISP_JNET_DOWNLOAD:
- if (pdispparams->cArgs == 1 || pdispparams->cArgs == 2)
- {
- int result = -1;
- if ( !active )
- {
- time_t ret = 0;
- active = 1;
- DownloadURL(pdispparams);
- result = 1;
- }
- else result = -1;
- if (pvarResult)
- {
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_I4;
- V_I4(pvarResult) = result;
- }
- return S_OK;
- }
- break;
- case DISP_JNET_POST:
- if (pdispparams->cArgs == 2)
- {
- int result = -1;
- if ( !active )
- {
- time_t ret = 0;
- active = 1;
- PostURL(pdispparams);
- result = 1;
- }
- else result = -1;
- if (pvarResult)
- {
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_I4;
- V_I4(pvarResult) = result;
- }
- return S_OK;
- }
- break;
- case DISP_JNET_STATUS:
- {
- if (pvarResult && errorstr && active )
- {
- AutoWide result(errorstr);
- BSTR tag = SysAllocString(result);
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_BSTR;
- V_BSTR(pvarResult) = tag;
- }
- return S_OK;
- }
- break;
- case DISP_JNET_SIZE:
- {
- if (pvarResult && active )
- {
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_I4;
- V_I4(pvarResult) = (INT)finalSize;
- }
- return S_OK;
- }
- break;
- case DISP_JNET_BUFFER_RAW:
- {
- if (pvarResult && jnetbuf->get() && active)
- {
- char dummy[1]={0};
- size_t len = jnetbuf->getlen();
- char *source = (char *)jnetbuf->get();
- if (!len || !source)
- {
- source=dummy;
- len=1;
- }
- else
- {
- while (*(source+len-1) == 0 && len)
- len--;
- }
- SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, (ULONG)len);
- void *data;
- SafeArrayAccessData(bufferArray, &data);
- memcpy(data, source, len);
- SafeArrayUnaccessData(bufferArray);
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_ARRAY|VT_UI1;
- V_ARRAY(pvarResult) = bufferArray;
- }
- return S_OK;
- }
- case DISP_JNET_BUFFER:
- {
- if (pvarResult && jnetbuf->get() && active )
- {
- AutoWide result((char *)jnetbuf->get());
- BSTR tag = SysAllocString(result);
- VariantInit(pvarResult);
- V_VT(pvarResult) = VT_BSTR;
- V_BSTR(pvarResult) = tag;
- }
- return S_OK;
- }
- break;
- }
- return DISP_E_MEMBERNOTFOUND;
- }
- STDMETHODIMP JnetCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
- else if (IsEqualIID(riid, IID_IDispatch))
- *ppvObject = (IDispatch *)this;
- else if (IsEqualIID(riid, IID_IUnknown))
- *ppvObject = this;
- else
- {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
- ULONG JnetCOM::AddRef(void)
- {
- return ++refCount;
- }
- ULONG JnetCOM::Release(void)
- {
- if (--refCount)
- return refCount;
- threadexit = 1; // exit the thread if active
- if (!isBlocking)
- { // Only if a callback was associated would the thread be running
- while (getter) // If there no getter, the thread is gone
- Sleep(10);
- }
- if (!finalSize)
- {
- BufferMap::iterator buffer_it = buffer_map.find(url);
- if (buffer_it != buffer_map.end())
- {
- jnetbuf = buffer_it->second;
- buffer_map.erase(buffer_it->first);
- delete jnetbuf;
- jnetbuf = NULL;
- }
- }
- Plugin_FreeString(url);
- url=0;
- if (postData)
- {
- free(postData);
- postData=0;
- }
-
- if (NULL != callback)
- {
- callback->Release();
- callback = NULL;
- }
-
- delete this;
- return 0;
- }
- static VOID CALLBACK CallbackAPC(ULONG_PTR param)
- {
- VARIANT arguments[2];
- DISPPARAMS params;
- unsigned int ret;
- JnetCOM *jnet = (JnetCOM *)param;
- if (NULL == jnet || NULL == jnet->callback)
- return;
- VariantInit(&arguments[0]);
- VariantInit(&arguments[1]);
- V_VT(&arguments[0]) = VT_DISPATCH;
- V_DISPATCH(&arguments[0]) = jnet;
- V_VT(&arguments[1]) = VT_BSTR;
- V_BSTR(&arguments[1]) = jnet->htmldiv;
- params.cArgs = ARRAYSIZE(arguments);
- params.cNamedArgs = 0;
- params.rgdispidNamedArgs = NULL;
- params.rgvarg = arguments;
- jnet->callback->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, NULL, &ret);
- V_DISPATCH(&arguments[0]) = NULL;
- V_BSTR(&arguments[1]) = NULL;
- VariantClear(&arguments[0]);
- VariantClear(&arguments[1]);
- jnet->Release();
- }
- void JnetCOM::callBack()
- {
- AddRef();
- if (GetCurrentThreadId() == callingThreadId)
- CallbackAPC((ULONG_PTR)this);
- else
- {
- if (NULL == callingThreadHandle ||
- 0 == QueueUserAPC(CallbackAPC, callingThreadHandle, (ULONG_PTR)this))
- {
- Release();
- }
- }
- }
- #define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/)
- void SetUserAgent(api_httpreceiver *http)
- {
- char user_agent[USER_AGENT_SIZE] = {0};
- int bigVer = ((winampVersion & 0x0000FF00) >> 12);
- int smallVer = ((winampVersion & 0x000000FF));
- StringCchPrintfA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/%01x.%02x", bigVer, smallVer);
- http->addheader(user_agent);
- }
- int JnetCOM::JthreadProc()
- {
- int ret;
- char temp[WORKSIZE] = {0};
- char *proxy = mediaLibrary.GetProxy();
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
- if (sf) getter = (api_httpreceiver *)sf->getInterface();
- // we're keying off of 'getter' to know if the thread is running or not, so we can release now
- Release();
- if (!getter)
- return -1;
- getter->AllowCompression();
- getter->open(API_DNS_AUTODNS, WORKSIZE, proxy);
- SetUserAgent(getter);
- getter->connect(AutoChar(url));
- BOOL bDone = FALSE;
- while (!bDone && !threadexit)
- {
- Sleep(10);
- ret = getter->run();
- if (ret == -1 || ret == 1)
- bDone = TRUE;
- int bytesReceived = getter->get_bytes(temp, WORKSIZE);
- if (bytesReceived)
- jnetbuf->add(temp, bytesReceived);
- }
- if (!threadexit)
- {
- if (ret == -1) StringCchCopyA(errorstr, 2048, getter->geterrorstr());
- else
- {
- int bytesReceived;
- do // flush out the socket
- {
- bytesReceived = getter->get_bytes(temp, WORKSIZE);
- if (bytesReceived)
- jnetbuf->add(temp, bytesReceived);
- }
- while (bytesReceived);
- temp[0] = 0;
- jnetbuf->add(temp, 1);
- }
- finalSize = jnetbuf->getlen();
- callBack();
- }
- sf->releaseInterface(getter);
- threadexit = 0;
- if (callingThreadHandle)
- CloseHandle(callingThreadHandle);
- getter = NULL;
- return ret;
- }
- int JnetCOM::PostProcedure()
- {
- int ret;
- char temp[WORKSIZE] = {0};
- char *proxy = mediaLibrary.GetProxy();
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
- if (sf) getter = (api_httpreceiver *)sf->getInterface();
- // we're keying off of 'getter' to know if the thread is running or not, so we can release now
- Release();
- if (!getter)
- return -1;
- getter->AllowCompression();
- getter->open(API_DNS_AUTODNS, WORKSIZE, proxy);
- SetUserAgent(getter);
- getter->addheader("Content-Type: application/x-www-form-urlencoded");
- size_t contentLength = strlen(postData);
- char contentLengthHeader[256] = {0};
- StringCchPrintfA(contentLengthHeader, 256, "Content-Length: %u", contentLength);
- getter->addheader(contentLengthHeader);
- char *dataIndex = postData;
- bool done=false;
- getter->connect(AutoChar(url), 0, "POST");
- // time to post data!
- api_connection *connection = getter->GetConnection();
- while (contentLength && !threadexit)
- {
- Sleep(1);
- getter->run();
- size_t lengthToSend = min(contentLength, connection->GetSendBytesAvailable());
- if (lengthToSend)
- {
- connection->send(dataIndex, (int)lengthToSend);
- dataIndex+=lengthToSend;
- contentLength-=lengthToSend;
- }
- }
- while (!threadexit && !done)
- {
- Sleep(10);
- ret = getter->run();
- if (ret == -1)
- break;
- // ---- check our reply code ----
- int replycode = getter->getreplycode();
- switch (replycode)
- {
- case 0:
- break;
- case 100:
- break;
- case 200:
- {
- int bytesReceived = getter->get_bytes(temp, WORKSIZE);
- if (bytesReceived)
- jnetbuf->add(temp, bytesReceived);
- do
- {
- Sleep(10);
- ret = getter->run();
- bytesReceived = getter->get_bytes(temp, WORKSIZE);
- if (bytesReceived)
- jnetbuf->add(temp, bytesReceived);
- }
- while (ret == HTTPRECEIVER_RUN_OK);
- done=true; // just in case
- }
- break;
- default:
- done=true;
- break;
- }
- if (ret != HTTPRECEIVER_RUN_OK)
- break;
- }
- if (!threadexit)
- {
- if (ret == -1)
- StringCchCopyA(errorstr, 2048, getter->geterrorstr());
- else
- {
- int bytesReceived;
- do // flush out the socket
- {
- bytesReceived = getter->get_bytes(temp, WORKSIZE);
- if (bytesReceived)
- jnetbuf->add(temp, bytesReceived);
- }
- while (bytesReceived && !threadexit);
- temp[0] = 0;
- jnetbuf->add(temp, 1);
- }
- if ( !threadexit )
- {
- finalSize = jnetbuf->getlen();
- callBack();
- }
- }
- sf->releaseInterface(getter);
- threadexit = 0;
- if (callingThreadHandle)
- CloseHandle(callingThreadHandle);
- getter = NULL;
- return ret;
- }
- void JnetCOM::DownloadURL(DISPPARAMS FAR *pdispparams)
- {
- Plugin_FreeString(url);
- url = Plugin_CopyString(pdispparams->rgvarg[pdispparams->cArgs - 1].bstrVal);
- callingThreadId = GetCurrentThreadId();
- callingThreadHandle = DuplicateCurrentThread();
- BufferMap::iterator buffer_it = buffer_map.find(url);
- if (buffer_it != buffer_map.end())
- {
- time_t check = time(NULL);
- jnetbuf = buffer_it->second;
- if ( check >= jnetbuf->expire_time)
- {
- buffer_map.erase(buffer_it->first);
- delete jnetbuf;
- jnetbuf = NULL;
- }
- else
- {
- finalSize = jnetbuf->getlen();
- callBack();
- }
- }
- if (!jnetbuf)
- {
- time_t now = 0;
- jnetbuf = buffer_map[url] = new Buffer_GrowBuf;
- if ( pdispparams->cArgs == 2 ) // passed in a time from Javascript, or 0 to not cache
- {
- if ( pdispparams->rgvarg[0].iVal )
- {
- now = time(NULL);
- jnetbuf->expire_time = now + pdispparams->rgvarg[0].iVal;
- }
- }
- else // Use winamp config cache time
- {
- int when = 0, x = 0;
- x = g_config->ReadInt("radio_upd_freq", 0);
- switch ( x )
- {
- case 0:
- {
- when = 3600; // One Hour
- }
- break;
- case 1:
- {
- when = 3600 * 24; // One Day aka 24 hours
- }
- break;
- case 2:
- {
- when = 3600 * 24 * 7; // One week (weak)
- }
- break;
- default:
- break;
- }
- if (when)
- now = time(NULL);
- jnetbuf->expire_time = now + when;
- }
- if (isBlocking)
- {
- AddRef(); // need to call this because JthreadProc does a Release
- JthreadProc(); // Call it directly, block until done.
- }
- else
- {
- // Launch the thread
- DWORD threadId;
- AddRef(); // make sure jnetcom object doesn't die while the thread is launching.
- jnetThread = CreateThread(NULL, NULL, JThreadProc, (void *)this, NULL, &threadId);
- }
- }
- }
- void JnetCOM::PostURL(DISPPARAMS FAR *pdispparams)
- {
- postData = AutoCharDup(pdispparams->rgvarg[0].bstrVal);
- Plugin_FreeString(url);
- url = Plugin_CopyString(pdispparams->rgvarg[1].bstrVal);
- callingThreadId = GetCurrentThreadId();
- callingThreadHandle = DuplicateCurrentThread();
- if (!jnetbuf)
- {
- time_t now = 0;
- jnetbuf = buffer_map[url] = new Buffer_GrowBuf;
- if (isBlocking)
- {
- AddRef(); // need to do this beacuse PostProcedure calls Release
- PostProcedure(); // Call it directly, block until done.
- }
- else
- {
- // Launch the thread
- DWORD threadId;
- AddRef(); // make sure the jnetcom doesn't get deleted before the thread launches
- jnetThread = CreateThread(NULL, NULL, jnetPostProcedure, (void *)this, NULL, &threadId);
- }
- }
- }
|