diff options
Diffstat (limited to 'miranda-wine/src/modules/netlib')
-rw-r--r-- | miranda-wine/src/modules/netlib/netlib.c | 503 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlib.h | 157 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibbind.c | 247 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibhttp.c | 729 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibhttpproxy.c | 610 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netliblog.c | 440 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibopenconn.c | 569 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibopts.c | 516 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibpktrecver.c | 85 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibsock.c | 166 | ||||
-rw-r--r-- | miranda-wine/src/modules/netlib/netlibupnp.c | 495 |
11 files changed, 4517 insertions, 0 deletions
diff --git a/miranda-wine/src/modules/netlib/netlib.c b/miranda-wine/src/modules/netlib/netlib.c new file mode 100644 index 0000000..72a0370 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlib.c @@ -0,0 +1,503 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+struct NetlibUser **netlibUser=NULL;
+int netlibUserCount=0;
+CRITICAL_SECTION csNetlibUser;
+HANDLE hConnectionHeaderMutex;
+DWORD g_LastConnectionTick; // protected by csNetlibUser
+
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings)
+{
+ if(settings->szIncomingPorts) mir_free(settings->szIncomingPorts);
+ if(settings->szOutgoingPorts) mir_free(settings->szOutgoingPorts);
+ if(settings->szProxyAuthPassword) mir_free(settings->szProxyAuthPassword);
+ if(settings->szProxyAuthUser) mir_free(settings->szProxyAuthUser);
+ if(settings->szProxyServer) mir_free(settings->szProxyServer);
+}
+
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ nlncs->dwOwningThreadId= 0;
+ nlncs->lockCount=0;
+ nlncs->hMutex=CreateMutex(NULL,FALSE,NULL);
+}
+
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ CloseHandle(nlncs->hMutex);
+}
+
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which)
+{
+ struct NetlibNestedCriticalSection *nlncs;
+ DWORD dwCurrentThreadId=GetCurrentThreadId();
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(nlc==NULL || nlc->handleType!=NLH_CONNECTION) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ nlncs=which==NLNCS_SEND?&nlc->ncsSend:&nlc->ncsRecv;
+ if(nlncs->lockCount && (nlc->ncsRecv.dwOwningThreadId==dwCurrentThreadId || nlc->ncsSend.dwOwningThreadId==dwCurrentThreadId)) {
+ nlncs->lockCount++;
+ ReleaseMutex(hConnectionHeaderMutex);
+ return 1;
+ }
+ InterlockedIncrement(&nlc->dontCloseNow);
+ ResetEvent(nlc->hOkToCloseEvent);
+ ReleaseMutex(hConnectionHeaderMutex);
+ WaitForSingleObject(nlncs->hMutex,INFINITE);
+ nlncs->dwOwningThreadId=dwCurrentThreadId;
+ nlncs->lockCount=1;
+ if(InterlockedDecrement(&nlc->dontCloseNow)==0)
+ SetEvent(nlc->hOkToCloseEvent);
+ return 1;
+}
+
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ if(--nlncs->lockCount==0) {
+ nlncs->dwOwningThreadId=0;
+ ReleaseMutex(nlncs->hMutex);
+ }
+}
+
+static int GetNetlibUserSettingInt(const char *szUserModule,const char *szSetting,int defValue)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv))
+ return defValue;
+ if(dbv.type==DBVT_BYTE) return dbv.bVal;
+ if(dbv.type==DBVT_WORD) return dbv.wVal;
+ return dbv.dVal;
+}
+
+static char *GetNetlibUserSettingString(const char *szUserModule,const char *szSetting,int decode)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv)) {
+ return NULL;
+ }
+ else {
+ char *szRet;
+ if(decode) CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM)dbv.pszVal);
+ szRet=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if(szRet==NULL) SetLastError(ERROR_OUTOFMEMORY);
+ return szRet;
+ }
+}
+
+static int NetlibRegisterUser(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSER *nlu=(NETLIBUSER*)lParam;
+ struct NetlibUser *thisUser;
+ int i;
+
+ if(nlu==NULL || nlu->cbSize!=sizeof(NETLIBUSER) || nlu->szSettingsModule==NULL
+ || (!(nlu->flags&NUF_NOOPTIONS) && nlu->szDescriptiveName==NULL)
+ || (nlu->flags&NUF_HTTPGATEWAY && (nlu->pfnHttpGatewayInit==NULL))) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0;i<netlibUserCount;i++)
+ if(!lstrcmpA(netlibUser[i]->user.szSettingsModule,nlu->szSettingsModule)) {
+ LeaveCriticalSection(&csNetlibUser);
+ SetLastError(ERROR_DUP_NAME);
+ return (int)(HANDLE)NULL;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+
+ thisUser=(struct NetlibUser*)mir_calloc(sizeof(struct NetlibUser));
+ thisUser->handleType=NLH_USER;
+ thisUser->user=*nlu;
+ if((thisUser->user.szSettingsModule=mir_strdup(nlu->szSettingsModule))==NULL
+ || (nlu->szDescriptiveName && (thisUser->user.szDescriptiveName=mir_strdup(nlu->szDescriptiveName))==NULL)
+ || (nlu->szHttpGatewayUserAgent && (thisUser->user.szHttpGatewayUserAgent=mir_strdup(nlu->szHttpGatewayUserAgent))==NULL)) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(HANDLE)NULL;
+ }
+ if (nlu->szHttpGatewayHello)
+ thisUser->user.szHttpGatewayHello=mir_strdup(nlu->szHttpGatewayHello);
+ else
+ thisUser->user.szHttpGatewayHello=NULL;
+
+ thisUser->settings.cbSize=sizeof(NETLIBUSERSETTINGS);
+ thisUser->settings.useProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxy",0);
+ thisUser->settings.proxyType=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyType",PROXYTYPE_SOCKS5);
+ if(thisUser->user.flags&NUF_NOHTTPSOPTION && thisUser->settings.proxyType==PROXYTYPE_HTTPS)
+ thisUser->settings.proxyType=PROXYTYPE_HTTP;
+ if(!(thisUser->user.flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) && thisUser->settings.proxyType==PROXYTYPE_HTTP) {
+ thisUser->settings.useProxy=0;
+ thisUser->settings.proxyType=PROXYTYPE_SOCKS5;
+ }
+ thisUser->settings.szProxyServer=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyServer",0);
+ thisUser->settings.wProxyPort=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyPort",1080);
+ thisUser->settings.useProxyAuth=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuth",0);
+ thisUser->settings.szProxyAuthUser=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthUser",0);
+ thisUser->settings.szProxyAuthPassword=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthPassword",1);
+ thisUser->settings.useProxyAuthNtlm=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuthNtlm",0);
+ thisUser->settings.dnsThroughProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLDnsThroughProxy",1);
+ thisUser->settings.specifyIncomingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyIncomingPorts",0);
+ thisUser->settings.szIncomingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLIncomingPorts",0);
+ thisUser->settings.specifyOutgoingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyOutgoingPorts",0);
+ thisUser->settings.szOutgoingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLOutgoingPorts",0);
+
+ EnterCriticalSection(&csNetlibUser);
+ netlibUser=(struct NetlibUser**)mir_realloc(netlibUser,sizeof(struct NetlibUser*)*++netlibUserCount);
+ netlibUser[netlibUserCount-1]=thisUser;
+ LeaveCriticalSection(&csNetlibUser);
+ return (int)thisUser;
+}
+
+static int NetlibGetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ *nlus=nlu->settings;
+ return 1;
+}
+
+static int NetlibSetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ NetlibSaveUserSettingsStruct(nlu->user.szSettingsModule,nlus);
+ return 1;
+}
+
+int NetlibCloseHandle(WPARAM wParam,LPARAM lParam)
+{
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_USER:
+ { struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ int i;
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0;i<netlibUserCount;i++)
+ if(!lstrcmpA(netlibUser[i]->user.szSettingsModule,nlu->user.szSettingsModule)) {
+ netlibUserCount--;
+ memmove(netlibUser+i,netlibUser+i+1,(netlibUserCount-i)*sizeof(struct NetlibUser*));
+ break;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ if(nlu->user.szSettingsModule) mir_free(nlu->user.szSettingsModule);
+ if(nlu->user.szDescriptiveName) mir_free(nlu->user.szDescriptiveName);
+ if(nlu->user.szHttpGatewayHello) mir_free(nlu->user.szHttpGatewayHello);
+ if(nlu->user.szHttpGatewayUserAgent) mir_free(nlu->user.szHttpGatewayUserAgent);
+ if(nlu->szStickyHeaders) mir_free(nlu->szStickyHeaders);
+ break;
+ }
+ case NLH_CONNECTION:
+ { struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ HANDLE waitHandles[4];
+ DWORD waitResult;
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if (nlc->usingHttpGateway) + { + struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue; + while (p != NULL) { + struct NetlibHTTPProxyPacketQueue *t = p; + + p = p->next; + + mir_free(t->dataBuffer); + mir_free(t); + } + } + else + { + if(nlc->handleType!=NLH_CONNECTION || nlc->s==INVALID_SOCKET) { + ReleaseMutex(hConnectionHeaderMutex); + SetLastError(ERROR_INVALID_PARAMETER); //already been closed + return 0; + } + closesocket(nlc->s); + nlc->s=INVALID_SOCKET; + }
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ waitHandles[0]=hConnectionHeaderMutex;
+ waitHandles[1]=nlc->hOkToCloseEvent;
+ waitHandles[2]=nlc->ncsRecv.hMutex;
+ waitHandles[3]=nlc->ncsSend.hMutex;
+ waitResult=WaitForMultipleObjects( SIZEOF(waitHandles),waitHandles,TRUE,INFINITE);
+ if(waitResult<WAIT_OBJECT_0 || waitResult >= WAIT_OBJECT_0 + SIZEOF(waitHandles)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER); //already been closed
+ return 0;
+ }
+ nlc->handleType=0;
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->dataBuffer) mir_free(nlc->dataBuffer);
+ if(nlc->hInstSecurityDll) FreeLibrary(nlc->hInstSecurityDll);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ ReleaseMutex(hConnectionHeaderMutex);
+ Netlib_Logf(nlc->nlu,"(%p:%u) Connection closed",nlc,nlc->s);
+ break;
+ }
+ case NLH_BOUNDPORT:
+ return NetlibFreeBoundPort((struct NetlibBoundPort*)wParam);
+ case NLH_PACKETRECVER:
+ { struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ mir_free(nlpr->packetRecver.buffer);
+ break;
+ }
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ mir_free((void*)wParam);
+ return 1;
+}
+
+static int NetlibGetSocket(WPARAM wParam,LPARAM lParam)
+{
+ SOCKET s;
+ if((void*)wParam==NULL) {
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else {
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_CONNECTION:
+ s=(int)((struct NetlibConnection*)wParam)->s;
+ break;
+ case NLH_BOUNDPORT:
+ s=(int)((struct NetlibBoundPort*)wParam)->s;
+ break;
+ default:
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ break;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ }
+ return s;
+}
+
+static char szHexDigits[]="0123456789ABCDEF";
+int NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam)
+{
+ unsigned char *szOutput,*szInput=(unsigned char*)lParam;
+ unsigned char *pszIn,*pszOut;
+ int outputLen;
+
+ if(szInput==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(char*)NULL;
+ }
+ for(outputLen=0,pszIn=szInput;*pszIn;pszIn++) {
+ if(isalnum(*pszIn) || *pszIn==' ') outputLen++;
+ else outputLen+=3;
+ }
+ szOutput=(unsigned char*)HeapAlloc(GetProcessHeap(),0,outputLen+1);
+ if(szOutput==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(unsigned char*)NULL;
+ }
+ for(pszOut=szOutput,pszIn=szInput;*pszIn;pszIn++) {
+ if(isalnum(*pszIn)) *pszOut++=*pszIn;
+ else if(*pszIn==' ') *pszOut++='+';
+ else {
+ *pszOut++='%';
+ *pszOut++=szHexDigits[*pszIn>>4];
+ *pszOut++=szHexDigits[*pszIn&0xF];
+ }
+ }
+ *pszOut='\0';
+ return (int)szOutput;
+}
+
+static char base64chars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+int NetlibBase64Encode(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ int iIn;
+ char *pszOut;
+ PBYTE pbIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded<Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded);
+ for(iIn=0,pbIn=nlb64->pbDecoded,pszOut=nlb64->pszEncoded;iIn<nlb64->cbDecoded;iIn+=3,pbIn+=3,pszOut+=4) {
+ pszOut[0]=base64chars[pbIn[0]>>2];
+ if(nlb64->cbDecoded-iIn==1) {
+ pszOut[1]=base64chars[(pbIn[0]&3)<<4];
+ pszOut[2]='=';
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[1]=base64chars[((pbIn[0]&3)<<4)|(pbIn[1]>>4)];
+ if(nlb64->cbDecoded-iIn==2) {
+ pszOut[2]=base64chars[(pbIn[1]&0xF)<<2];
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[2]=base64chars[((pbIn[1]&0xF)<<2)|(pbIn[2]>>6)];
+ pszOut[3]=base64chars[pbIn[2]&0x3F];
+ }
+ pszOut[0]='\0';
+ return 1;
+}
+
+static BYTE Base64CharToInt(char c)
+{
+ if(c>='A' && c<='Z') return c-'A';
+ if(c>='a' && c<='z') return c-'a'+26;
+ if(c>='0' && c<='9') return c-'0'+52;
+ if(c=='+') return 62;
+ if(c=='/') return 63;
+ if(c=='=') return 64;
+ return 255;
+}
+
+int NetlibBase64Decode(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ char *pszIn;
+ PBYTE pbOut;
+ BYTE b1,b2,b3,b4;
+ int iIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded&3) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(nlb64->cbDecoded<Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded);
+ for(iIn=0,pszIn=nlb64->pszEncoded,pbOut=nlb64->pbDecoded;iIn<nlb64->cchEncoded;iIn+=4,pszIn+=4,pbOut+=3) {
+ b1=Base64CharToInt(pszIn[0]);
+ b2=Base64CharToInt(pszIn[1]);
+ b3=Base64CharToInt(pszIn[2]);
+ b4=Base64CharToInt(pszIn[3]);
+ if(b1==255 || b1==64 || b2==255 || b2==64 || b3==255 || b4==255) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ pbOut[0]=(b1<<2)|(b2>>4);
+ if(b3==64) {nlb64->cbDecoded-=2; break;}
+ pbOut[1]=(b2<<4)|(b3>>2);
+ if(b4==64) {nlb64->cbDecoded--; break;}
+ pbOut[2]=b4|(b3<<6);
+ }
+ return 1;
+}
+
+static int NetlibShutdown(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ NetlibLogShutdown();
+ for(i=netlibUserCount;i>0;i--)
+ NetlibCloseHandle((WPARAM)netlibUser[i-1],0);
+ if(netlibUser) mir_free(netlibUser);
+ CloseHandle(hConnectionHeaderMutex);
+ DeleteCriticalSection(&csNetlibUser);
+ WSACleanup();
+ return 0;
+}
+
+static int NetlibModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,NetlibShutdown); // get shutdown hook _after_ all the other plugins
+ return 0;
+}
+
+int LoadNetlibModule(void)
+{
+ WSADATA wsadata;
+
+ //HookEvent(ME_SYSTEM_SHUTDOWN,NetlibShutdown); // hooked later to be called last after plugins
+ HookEvent(ME_SYSTEM_MODULESLOADED, NetlibModulesLoaded);
+ HookEvent(ME_OPT_INITIALISE,NetlibOptInitialise);
+ WSAStartup(MAKEWORD(1,1), &wsadata);
+ InitializeCriticalSection(&csNetlibUser);
+ hConnectionHeaderMutex=CreateMutex(NULL,FALSE,NULL);
+ g_LastConnectionTick=GetTickCount();
+ NetlibLogInit();
+ CreateServiceFunction(MS_NETLIB_REGISTERUSER,NetlibRegisterUser);
+ CreateServiceFunction(MS_NETLIB_GETUSERSETTINGS,NetlibGetUserSettings);
+ CreateServiceFunction(MS_NETLIB_SETUSERSETTINGS,NetlibSetUserSettings);
+ CreateServiceFunction(MS_NETLIB_CLOSEHANDLE,NetlibCloseHandle);
+ CreateServiceFunction(MS_NETLIB_BINDPORT,NetlibBindPort);
+ CreateServiceFunction(MS_NETLIB_OPENCONNECTION,NetlibOpenConnection);
+ CreateServiceFunction(MS_NETLIB_SETHTTPPROXYINFO,NetlibHttpGatewaySetInfo);
+ CreateServiceFunction(MS_NETLIB_SETSTICKYHEADERS,NetlibHttpSetSticky);
+ CreateServiceFunction(MS_NETLIB_GETSOCKET,NetlibGetSocket);
+ CreateServiceFunction(MS_NETLIB_URLENCODE,NetlibHttpUrlEncode);
+ CreateServiceFunction(MS_NETLIB_BASE64ENCODE,NetlibBase64Encode);
+ CreateServiceFunction(MS_NETLIB_BASE64DECODE,NetlibBase64Decode);
+ CreateServiceFunction(MS_NETLIB_SENDHTTPREQUEST,NetlibHttpSendRequest);
+ CreateServiceFunction(MS_NETLIB_RECVHTTPHEADERS,NetlibHttpRecvHeaders);
+ CreateServiceFunction(MS_NETLIB_FREEHTTPREQUESTSTRUCT,NetlibHttpFreeRequestStruct);
+ CreateServiceFunction(MS_NETLIB_HTTPTRANSACTION,NetlibHttpTransaction);
+ CreateServiceFunction(MS_NETLIB_SEND,NetlibSend);
+ CreateServiceFunction(MS_NETLIB_RECV,NetlibRecv);
+ CreateServiceFunction(MS_NETLIB_SELECT,NetlibSelect);
+ CreateServiceFunction(MS_NETLIB_SELECTEX,NetlibSelectEx);
+ CreateServiceFunction(MS_NETLIB_CREATEPACKETRECVER,NetlibPacketRecverCreate);
+ CreateServiceFunction(MS_NETLIB_GETMOREPACKETS,NetlibPacketRecverGetMore);
+ CreateServiceFunction(MS_NETLIB_SETPOLLINGTIMEOUT,NetlibHttpSetPollingTimeout);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/netlib/netlib.h b/miranda-wine/src/modules/netlib/netlib.h new file mode 100644 index 0000000..8314397 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlib.h @@ -0,0 +1,157 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#define GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID)
+#define NLH_INVALID 0
+#define NLH_USER 'USER'
+#define NLH_CONNECTION 'CONN'
+#define NLH_BOUNDPORT 'BIND'
+#define NLH_PACKETRECVER 'PCKT'
+
+struct NetlibUser {
+ int handleType;
+ NETLIBUSER user;
+ NETLIBUSERSETTINGS settings;
+ char * szStickyHeaders;
+};
+
+struct NetlibNestedCriticalSection {
+ HANDLE hMutex;
+ DWORD dwOwningThreadId;
+ int lockCount;
+};
+
+struct NetlibHTTPProxyPacketQueue {
+ struct NetlibHTTPProxyPacketQueue *next;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+};
+
+struct NetlibConnection {
+ int handleType;
+ SOCKET s;
+ int usingHttpGateway;
+ struct NetlibUser *nlu;
+ SOCKADDR_IN sinProxy;
+ NETLIBHTTPPROXYINFO nlhpi;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+ DWORD dwLastGetSentTime;
+ CRITICAL_SECTION csHttpSequenceNums;
+ HANDLE hOkToCloseEvent;
+ LONG dontCloseNow;
+ struct NetlibNestedCriticalSection ncsSend,ncsRecv;
+ HINSTANCE hInstSecurityDll;
+ struct NetlibHTTPProxyPacketQueue * pHttpProxyPacketQueue;
+ int pollingTimeout;
+};
+
+struct NetlibBoundPort {
+ int handleType;
+ SOCKET s;
+ WORD wPort;
+ WORD wExPort;
+ struct NetlibUser *nlu;
+ NETLIBNEWCONNECTIONPROC_V2 pfnNewConnectionV2;
+ HANDLE hThread;
+ void *pExtra;
+};
+
+struct NetlibPacketRecver {
+ int handleType;
+ struct NetlibConnection *nlc;
+ NETLIBPACKETRECVER packetRecver;
+};
+
+//netlib.c
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings);
+int NetlibCloseHandle(WPARAM wParam,LPARAM lParam);
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs);
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs);
+#define NLNCS_SEND 0
+#define NLNCS_RECV 1
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which);
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs);
+int NetlibBase64Encode(WPARAM wParam,LPARAM lParam);
+int NetlibBase64Decode(WPARAM wParam,LPARAM lParam);
+int NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam);
+
+//netlibbind.c
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp);
+int NetlibBindPort(WPARAM wParam,LPARAM lParam);
+int StringToPortsMask(const char *szPorts,BYTE *mask);
+
+//netlibhttp.c
+int NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam);
+int NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam);
+int NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam);
+int NetlibHttpTransaction(WPARAM wParam,LPARAM lParam);
+void NetlibHttpSetLastErrorUsingHttpResult(int result);
+
+//netlibhttpproxy.c
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc);
+int NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam);
+int NetlibHttpSetPollingTimeout(WPARAM wParam,LPARAM lParam);
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags);
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags);
+int NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam);
+
+//netliblog.c
+void NetlibLogShowOptions(void);
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags);
+void NetlibLogInit(void);
+void NetlibLogShutdown(void);
+
+//netlibopenconn.c
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost);
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout);
+int NetlibOpenConnection(WPARAM wParam,LPARAM lParam);
+
+//netlibopts.c
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam);
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings);
+
+//netlibpktrecver.c
+int NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam);
+int NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam);
+
+//netlibsock.c
+int NetlibSend(WPARAM wParam,LPARAM lParam);
+int NetlibRecv(WPARAM wParam,LPARAM lParam);
+int NetlibSelect(WPARAM wParam,LPARAM lParam);
+int NetlibSelectEx(WPARAM wParam,LPARAM lParam);
+
+//netlibupnp.c
+BOOL NetlibUPnPAddPortMapping(WORD intport, char *proto,
+ WORD *extport, DWORD *extip, BOOL search);
+void NetlibUPnPDeletePortMapping(WORD extport, char* proto);
+
+static __inline int NLSend(struct NetlibConnection *nlc,const char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={(char*)buf,len,flags};
+ return NetlibSend((WPARAM)nlc,(LPARAM)&nlb);
+}
+static __inline int NLRecv(struct NetlibConnection *nlc,char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={buf,len,flags};
+ return NetlibRecv((WPARAM)nlc,(LPARAM)&nlb);
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibbind.c b/miranda-wine/src/modules/netlib/netlibbind.c new file mode 100644 index 0000000..383159f --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibbind.c @@ -0,0 +1,247 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+//mask must be 8192 bytes, returns number of bits set
+#define PortInMask(mask,p) ((mask)[((p)&0xFFFF)>>3]&(1<<((p)&7)))
+int StringToPortsMask(const char *szPorts,BYTE *mask)
+{
+ const char *psz;
+ char *pszEnd;
+ int portMin,portMax,port;
+ int bitCount=0;
+
+ ZeroMemory(mask,8192);
+ for(psz=szPorts;*psz;) {
+ while(*psz==' ' && *psz==',') psz++;
+ portMin=strtol(psz,&pszEnd,0);
+ if(pszEnd==psz) break;
+ while(*pszEnd==' ') pszEnd++;
+ if(*pszEnd=='-') {
+ psz=pszEnd+1;
+ portMax=strtol(psz,&pszEnd,0);
+ if(pszEnd==psz) portMax=65535;
+ if(portMin>portMax) {
+ port=portMin;
+ portMin=portMax;
+ portMax=port;
+ }
+ }
+ else portMax=portMin;
+ if(portMax>=1) {
+ if(portMin<=0) portMin=1;
+ for(port=portMin;port<=portMax;port++) {
+ if(port>65535) break;
+ if((port&7)==0 && portMax-port>=7) {mask[port>>3]=0xFF; port+=7; bitCount+=8;}
+ else {mask[port>>3]|=1<<(port&7); bitCount++;}
+ }
+ }
+ psz=pszEnd;
+ }
+ return bitCount;
+}
+
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
+{
+ closesocket(nlbp->s);
+ WaitForSingleObject(nlbp->hThread,INFINITE);
+ CloseHandle(nlbp->hThread);
+ NetlibUPnPDeletePortMapping(nlbp->wExPort, "TCP");
+ mir_free(nlbp);
+ return 1;
+}
+
+static DWORD __stdcall NetlibBindAcceptThread(struct NetlibBoundPort *nlbp)
+{
+ SOCKET s;
+ SOCKADDR_IN sin;
+ int sinLen;
+ struct NetlibConnection *nlc;
+
+ srand((unsigned int)time(NULL));
+ Netlib_Logf(nlbp->nlu,"(%d) Port %u opened for incoming connections",nlbp->s,nlbp->wPort);
+ for(;;) {
+ sinLen=sizeof(sin);
+ s=accept(nlbp->s,(struct sockaddr*)&sin,&sinLen);
+ if(s==INVALID_SOCKET) break;
+ Netlib_Logf(nlbp->nlu,"New incoming connection on port %u from %s (%d)",nlbp->wPort, inet_ntoa(sin.sin_addr),s);
+ nlc=(struct NetlibConnection*)mir_alloc(sizeof(struct NetlibConnection));
+ memset(nlc,0,sizeof(struct NetlibConnection));
+ nlc->handleType=NLH_CONNECTION;
+ nlc->nlu=nlbp->nlu;
+ nlc->s=s;
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ nlbp->pfnNewConnectionV2((HANDLE)nlc,ntohl(sin.sin_addr.S_un.S_addr), nlbp->pExtra);
+ }
+ return 0;
+}
+
+int NetlibBindPort(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBIND *nlb=(NETLIBBIND*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibBoundPort *nlbp;
+ SOCKADDR_IN sin;
+ int foundPort=0;
+ DWORD dwThreadId;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_INCOMING) || nlb==NULL || nlb->pfnNewConnection==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+ if ( nlb->cbSize != sizeof(NETLIBBIND) &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V2 &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V1 )
+ {
+ return (int)(HANDLE)NULL;
+ }
+ nlbp=(struct NetlibBoundPort*)mir_alloc(sizeof(struct NetlibBoundPort));
+ nlbp->handleType=NLH_BOUNDPORT;
+ nlbp->nlu=nlu;
+ nlbp->pfnNewConnectionV2=nlb->pfnNewConnectionV2;
+ nlbp->s=socket(AF_INET,SOCK_STREAM,0);
+ nlbp->pExtra= (nlb->cbSize == sizeof(NETLIBBIND)) ? nlb->pExtra : NULL;
+ if(nlbp->s==INVALID_SOCKET) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=htonl(INADDR_ANY);
+ sin.sin_port=0;
+ /* if the netlib user wanted a free port given in the range, then
+ they better have given wPort==0, let's hope so */
+ if(nlu->settings.specifyIncomingPorts && nlb->wPort==0) {
+ int startPort,portNum,i,j;
+ BYTE portsMask[8192];
+ int portsCount;
+
+ portsCount=StringToPortsMask(nlu->settings.szIncomingPorts,portsMask);
+ if(portsCount==0) {
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ SetLastError(WSAEADDRINUSE);
+ return (int)(HANDLE)NULL;
+ }
+ startPort=rand()%portsCount;
+ for(i=0;i<8192;i++) {
+ if(portsMask[i]==0) continue;
+ if(portsMask[i]==0xFF && startPort>=8) {startPort-=8; continue;}
+ for(j=0;j<8;j++)
+ if(portsMask[i]&(1<<j))
+ if(startPort--==0) {
+ portNum=(i<<3)+j;
+ break;
+ }
+ if(startPort==-1) break;
+ }
+ if(i==8192) return (int)(HANDLE)NULL; //can't happen
+ startPort=portNum;
+ do
+ {
+ sin.sin_port=htons((WORD)portNum);
+ if(bind(nlbp->s,(SOCKADDR *)&sin,sizeof(sin))==0) {
+ foundPort=1;
+ break;
+ }
+ for(portNum++;!PortInMask(portsMask,portNum);portNum++)
+ if(portNum==65535) portNum=0;
+ } while(portNum!=startPort);
+ }
+ else {
+ /* if ->wPort==0 then they'll get any free port, otherwise they'll
+ be asking for whatever was in nlb->wPort*/
+ if (nlb->wPort!=0) {
+ Netlib_Logf(nlu,"%s %d: trying to bind port %d, this 'feature' can be abused, please be sure you want to allow it.",__FILE__,__LINE__,nlb->wPort);
+ sin.sin_port=htons(nlb->wPort);
+ }
+ if(bind(nlbp->s,(SOCKADDR *)&sin,sizeof(sin))==0) foundPort=1;
+ }
+ if(!foundPort) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"bind",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+
+ if(listen(nlbp->s,5)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+
+ { int len;
+ DWORD extIP;
+
+ ZeroMemory(&sin,sizeof(sin));
+ len=sizeof(sin);
+ if(getsockname(nlbp->s,(SOCKADDR *)&sin,&len)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"getsockname",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+ nlb->wPort=ntohs(sin.sin_port);
+ nlbp->wPort=nlb->wPort;
+ nlb->dwInternalIP=ntohl(sin.sin_addr.S_un.S_addr);
+
+ if (nlb->dwInternalIP == 0)
+ {
+ char hostname[64];
+ struct hostent *he;
+
+ gethostname(hostname,SIZEOF(hostname));
+ he=gethostbyname(hostname);
+ if(he->h_addr_list[0])
+ nlb->dwInternalIP=ntohl(*(PDWORD)he->h_addr_list[0]);
+ }
+ if (NetlibUPnPAddPortMapping(nlb->wPort, "TCP", &nlbp->wExPort,
+ &extIP, nlb->cbSize > NETLIBBIND_SIZEOF_V2))
+ {
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlbp->wExPort;
+ nlb->dwExternalIP = extIP;
+ }
+ }
+ else
+ {
+ nlbp->wExPort = 0;
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlb->wPort;
+ nlb->dwExternalIP = nlb->dwInternalIP;
+ }
+ }
+
+ }
+ nlbp->hThread=(HANDLE)forkthreadex(NULL,0,NetlibBindAcceptThread,nlbp,0,&dwThreadId);
+ return (int)nlbp;
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibhttp.c b/miranda-wine/src/modules/netlib/netlibhttp.c new file mode 100644 index 0000000..5e47116 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibhttp.c @@ -0,0 +1,729 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#define SECURITY_WIN32
+#include <security.h>
+#include "netlib.h"
+
+// Old versions of ssapi.h defines "FreeCredentialHandle()", but the
+// function has since then been redefined to "FreeCredentialsHandle()"
+#ifndef FreeCredentialsHandle
+#define FreeCredentialsHandle FreeCredentialHandle
+#endif
+
+#define HTTPRECVHEADERSTIMEOUT 60000 //in ms
+
+struct ResizableCharBuffer {
+ char *sz;
+ int iEnd,cbAlloced;
+};
+
+static void AppendToCharBuffer(struct ResizableCharBuffer *rcb,const char *fmt,...)
+{
+ va_list va;
+ int charsDone;
+
+ if(rcb->cbAlloced==0) {
+ rcb->cbAlloced=512;
+ rcb->sz=(char*)mir_alloc(rcb->cbAlloced);
+ }
+ va_start(va,fmt);
+ for(;;) {
+ charsDone=mir_vsnprintf(rcb->sz+rcb->iEnd,rcb->cbAlloced-rcb->iEnd,fmt,va);
+ if(charsDone>=0) break;
+ rcb->cbAlloced+=512;
+ rcb->sz=(char*)mir_realloc(rcb->sz,rcb->cbAlloced);
+ }
+ va_end(va);
+ rcb->iEnd+=charsDone;
+}
+
+
+static PSecurityFunctionTableA pSecurityFunctions=NULL;
+static PSecPkgInfoA ntlmSecurityPackageInfo=NULL;
+static CtxtHandle hNtlmClientContext;
+static CredHandle hNtlmClientCredential;
+//mir_free() the return value
+static void NtlmDestroy(void)
+{
+ if (pSecurityFunctions)
+ {
+ pSecurityFunctions->DeleteSecurityContext(&hNtlmClientContext);
+ pSecurityFunctions->FreeCredentialsHandle(&hNtlmClientCredential);
+ } //if
+ if(ntlmSecurityPackageInfo) pSecurityFunctions->FreeContextBuffer(ntlmSecurityPackageInfo);
+ ntlmSecurityPackageInfo=NULL;
+}
+
+static char *NtlmInitialiseAndGetDomainPacket(HINSTANCE hInstSecurityDll)
+{
+ PSecurityFunctionTableA (*MyInitSecurityInterface)(VOID);
+ SECURITY_STATUS securityStatus;
+ SecBufferDesc outputBufferDescriptor;
+ SecBuffer outputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64;
+
+ MyInitSecurityInterface=(PSecurityFunctionTableA (*)(VOID))GetProcAddress(hInstSecurityDll,"InitSecurityInterfaceA");
+ if(MyInitSecurityInterface==NULL) {NtlmDestroy(); return NULL;}
+ pSecurityFunctions=MyInitSecurityInterface();
+ if(pSecurityFunctions==NULL) {NtlmDestroy(); return NULL;}
+
+ securityStatus=pSecurityFunctions->QuerySecurityPackageInfoA("NTLM",&ntlmSecurityPackageInfo);
+ if(securityStatus!=SEC_E_OK) {NtlmDestroy(); return NULL;}
+ securityStatus=pSecurityFunctions->AcquireCredentialsHandleA(NULL,"NTLM",SECPKG_CRED_OUTBOUND,NULL,NULL,NULL,NULL,&hNtlmClientCredential,&tokenExpiration);
+ if(securityStatus!=SEC_E_OK) {NtlmDestroy(); return NULL;}
+
+ outputBufferDescriptor.cBuffers=1;
+ outputBufferDescriptor.pBuffers=&outputSecurityToken;
+ outputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ outputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer=ntlmSecurityPackageInfo->cbMaxToken;
+ outputSecurityToken.pvBuffer=mir_alloc(outputSecurityToken.cbBuffer);
+ if(outputSecurityToken.pvBuffer==NULL) {NtlmDestroy(); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ securityStatus=pSecurityFunctions->InitializeSecurityContextA(&hNtlmClientCredential,NULL,NULL,0,0,SECURITY_NATIVE_DREP,NULL,0,&hNtlmClientContext,&outputBufferDescriptor,&contextAttributes,&tokenExpiration);
+ if(securityStatus!=SEC_I_CONTINUE_NEEDED) {mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); return NULL;}
+
+ nlb64.cbDecoded=outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded=outputSecurityToken.pvBuffer;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL) {mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Encode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pszEncoded); mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); return NULL;}
+ mir_free(outputSecurityToken.pvBuffer);
+ return nlb64.pszEncoded;
+}
+
+//mir_free() the result value
+static char *NtlmCreateResponseFromChallenge(char *szChallenge)
+{
+ SECURITY_STATUS securityStatus;
+ SecBufferDesc outputBufferDescriptor,inputBufferDescriptor;
+ SecBuffer outputSecurityToken,inputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64;
+
+ nlb64.cchEncoded=lstrlenA(szChallenge);
+ nlb64.pszEncoded=szChallenge;
+ nlb64.cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
+ nlb64.pbDecoded=(PBYTE)mir_alloc(nlb64.cbDecoded);
+ if(nlb64.pbDecoded==NULL) {SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Decode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pbDecoded); return NULL;}
+
+ inputBufferDescriptor.cBuffers=1;
+ inputBufferDescriptor.pBuffers=&inputSecurityToken;
+ inputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ inputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ inputSecurityToken.cbBuffer=nlb64.cbDecoded;
+ inputSecurityToken.pvBuffer=nlb64.pbDecoded;
+ outputBufferDescriptor.cBuffers=1;
+ outputBufferDescriptor.pBuffers=&outputSecurityToken;
+ outputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ outputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer=ntlmSecurityPackageInfo->cbMaxToken;
+ outputSecurityToken.pvBuffer=mir_alloc(outputSecurityToken.cbBuffer);
+ if(outputSecurityToken.pvBuffer==NULL) {mir_free(nlb64.pbDecoded); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ securityStatus=pSecurityFunctions->InitializeSecurityContextA(&hNtlmClientCredential,&hNtlmClientContext,NULL,0,0,SECURITY_NATIVE_DREP,&inputBufferDescriptor,0,&hNtlmClientContext,&outputBufferDescriptor,&contextAttributes,&tokenExpiration);
+ mir_free(nlb64.pbDecoded);
+ if(securityStatus!=SEC_E_OK) {mir_free(outputSecurityToken.pvBuffer); return NULL;}
+
+ nlb64.cbDecoded=outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded=outputSecurityToken.pvBuffer;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL) {mir_free(outputSecurityToken.pvBuffer); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Encode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pszEncoded); mir_free(outputSecurityToken.pvBuffer); return NULL;}
+ mir_free(outputSecurityToken.pvBuffer);
+ return nlb64.pszEncoded;
+}
+
+static int RecvWithTimeoutTime(struct NetlibConnection *nlc,DWORD dwTimeoutTime,char *buf,int len,int flags)
+{
+ DWORD dwTimeNow;
+
+ dwTimeNow=GetTickCount();
+ if(dwTimeNow>=dwTimeoutTime
+ || !WaitUntilReadable(nlc->s,dwTimeoutTime-dwTimeNow)) {
+ if(dwTimeNow>=dwTimeoutTime) SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ return NLRecv(nlc,buf,len,flags);
+}
+
+static int HttpPeekFirstResponseLine(struct NetlibConnection *nlc,DWORD dwTimeoutTime,DWORD recvFlags,int *resultCode,char **ppszResultDescr,int *length)
+{
+ int bytesPeeked=0;
+ char buffer[1024];
+ char *peol;
+
+ for(;;) {
+ bytesPeeked=RecvWithTimeoutTime(nlc,dwTimeoutTime,buffer,SIZEOF(buffer)-1,MSG_PEEK|recvFlags);
+ if(bytesPeeked==0 || bytesPeeked==SOCKET_ERROR) {
+ if(bytesPeeked==0) SetLastError(ERROR_HANDLE_EOF);
+ return 0;
+ }
+ buffer[bytesPeeked]='\0';
+ peol=strchr(buffer,'\n');
+ if(peol==NULL) {
+ if(lstrlenA(buffer)<bytesPeeked) {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ if(bytesPeeked==SIZEOF(buffer)-1) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ Sleep(10);
+ continue;
+ }
+ if(peol==buffer || *--peol!='\r') {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ *peol='\0';
+ {
+ char *pResultCode,*pResultDescr,*pHttpMajor,*pHttpMinor;
+ int tokenLen;
+ int httpMajorVer,httpMinorVer;
+ if(peol==buffer
+ || _strnicmp(buffer,"http/",5)
+ || (httpMajorVer=strtol(pHttpMajor=buffer+5,&pHttpMinor,10))<0
+ || pHttpMajor==pHttpMinor
+ || httpMajorVer>1
+ || *pHttpMinor++!='.'
+ || (httpMinorVer=strtol(pHttpMinor,&pResultCode,10))<0
+ || pResultCode==pHttpMinor
+ || (tokenLen=strspn(pResultCode," \t"))==0
+ || (*resultCode=strtol(pResultCode+=tokenLen,&pResultDescr,10))==0
+ || pResultDescr==pResultCode
+ || (tokenLen=strspn(pResultDescr," \t"))==0
+ || *(pResultDescr+=tokenLen)=='\0') {
+ SetLastError(peol==buffer?ERROR_BAD_FORMAT:ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(ppszResultDescr) *ppszResultDescr=mir_strdup(pResultDescr);
+ if(length) *length=peol-buffer+2;
+ }
+ return 1;
+ }
+}
+
+static int SendHttpRequestAndData(struct NetlibConnection *nlc,struct ResizableCharBuffer *httpRequest,NETLIBHTTPREQUEST *nlhr,int sendContentLengthHeader)
+{
+ int bytesSent;
+
+ if((nlhr->requestType==REQUEST_POST)) {
+ if(sendContentLengthHeader)
+ AppendToCharBuffer(httpRequest,"Content-Length: %d\r\n\r\n",nlhr->dataLength);
+ else
+ AppendToCharBuffer(httpRequest,"\r\n");
+ bytesSent=NLSend(nlc,httpRequest->sz,httpRequest->iEnd,MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ mir_free(httpRequest->sz);
+ if (nlhr->dataLength) {
+ int sendResult;
+
+ if(bytesSent==SOCKET_ERROR
+ || SOCKET_ERROR==(sendResult=NLSend(nlc,nlhr->pData,nlhr->dataLength,(nlhr->flags&NLHRF_DUMPASTEXT?MSG_DUMPASTEXT:0)|(nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0))))) {
+ return SOCKET_ERROR;
+ }
+ bytesSent+=sendResult;
+ }
+ }
+ else {
+ AppendToCharBuffer(httpRequest,"\r\n");
+ bytesSent=NLSend(nlc,httpRequest->sz,httpRequest->iEnd,MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ mir_free(httpRequest->sz);
+ }
+ return bytesSent;
+}
+
+int NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+ struct ResizableCharBuffer httpRequest={0};
+ char *pszRequest,*szHost,*pszUrl;
+ char *pszProxyAuthorizationHeader;
+ int i,doneHostHeader,doneContentLengthHeader,doneProxyAuthHeader,usingNtlmAuthentication;
+ int useProxyHttpAuth,bytesSent;
+
+ if(nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl==NULL || nlhr->szUrl[0]=='\0') {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ switch(nlhr->requestType) {
+ case REQUEST_GET: pszRequest="GET"; break;
+ case REQUEST_POST: pszRequest="POST"; break;
+ case REQUEST_CONNECT: pszRequest="CONNECT"; break;
+ case REQUEST_HEAD:pszRequest="HEAD"; break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_SEND)) return SOCKET_ERROR;
+
+ //first line: "GET /index.html HTTP/1.0\r\n"
+ szHost=NULL;
+ if(nlhr->flags&(NLHRF_SMARTREMOVEHOST|NLHRF_REMOVEHOST|NLHRF_GENERATEHOST)){
+ char *ppath,*phost;
+ phost=strstr(nlhr->szUrl,"://");
+ if(phost==NULL) phost=nlhr->szUrl;
+ else phost+=3;
+ ppath=strchr(phost,'/');
+ if(ppath==NULL) ppath=phost+lstrlenA(phost);
+ if(nlhr->flags&NLHRF_GENERATEHOST) {
+ szHost=(char*)mir_alloc(ppath-phost+1);
+ lstrcpynA(szHost,phost,ppath-phost+1);
+ }
+ if(nlhr->flags&NLHRF_REMOVEHOST
+ || (nlhr->flags&NLHRF_SMARTREMOVEHOST
+ && (!nlc->nlu->settings.useProxy
+ || !(nlc->nlu->settings.proxyType==PROXYTYPE_HTTP || nlc->nlu->settings.proxyType==PROXYTYPE_HTTPS)))) {
+ pszUrl=ppath;
+ }
+ else pszUrl=nlhr->szUrl;
+ }
+ else pszUrl=nlhr->szUrl;
+ AppendToCharBuffer(&httpRequest, "%s %s HTTP/1.%d\r\n", pszRequest, pszUrl, (nlhr->flags & NLHRF_HTTP11) != 0); +
+ //if (nlhr->dataLength > 0)
+ // AppendToCharBuffer(&httpRequest,"Content-Length: %d\r\n",nlhr->dataLength);
+
+ //proxy auth initialization + useProxyHttpAuth=nlhr->flags&NLHRF_SMARTAUTHHEADER && nlc->nlu->settings.useProxy && nlc->nlu->settings.useProxyAuth && (nlc->nlu->settings.proxyType==PROXYTYPE_HTTP || nlc->nlu->settings.proxyType==PROXYTYPE_HTTPS);
+ usingNtlmAuthentication=0;
+ if(useProxyHttpAuth) {
+ if(nlc->nlu->settings.useProxyAuthNtlm) {
+ char *pszNtlmAuth;
+ pszNtlmAuth=NtlmInitialiseAndGetDomainPacket(nlc->hInstSecurityDll);
+ if(pszNtlmAuth==NULL) {useProxyHttpAuth=0; pszProxyAuthorizationHeader=NULL;}
+ else {
+ pszProxyAuthorizationHeader=(char*)mir_alloc(lstrlenA(pszNtlmAuth)+6);
+ lstrcpyA(pszProxyAuthorizationHeader,"NTLM ");
+ lstrcatA(pszProxyAuthorizationHeader,pszNtlmAuth);
+ mir_free(pszNtlmAuth);
+ usingNtlmAuthentication=1;
+ }
+ }
+ else {
+ NETLIBBASE64 nlb64;
+ char szAuth[512];
+ mir_snprintf(szAuth,SIZEOF(szAuth),"%s:%s",nlc->nlu->settings.szProxyAuthUser,nlc->nlu->settings.szProxyAuthPassword);
+ nlb64.cbDecoded=lstrlenA(szAuth);
+ nlb64.pbDecoded=szAuth;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ NetlibBase64Encode(0,(LPARAM)&nlb64);
+ pszProxyAuthorizationHeader=(char*)mir_alloc(lstrlenA(nlb64.pszEncoded)+7);
+ lstrcpyA(pszProxyAuthorizationHeader,"Basic ");
+ lstrcatA(pszProxyAuthorizationHeader,nlb64.pszEncoded);
+ mir_free(nlb64.pszEncoded);
+ }
+ }
+ else pszProxyAuthorizationHeader=NULL;
+
+ //HTTP headers
+ doneHostHeader=doneContentLengthHeader=doneProxyAuthHeader=0;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"Host")) doneHostHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Content-Length")) doneContentLengthHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Proxy-Authorization")) doneProxyAuthHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Connection") && usingNtlmAuthentication) continue;
+ if(nlhr->headers[i].szValue==NULL) continue;
+ AppendToCharBuffer(&httpRequest,"%s: %s\r\n",nlhr->headers[i].szName,nlhr->headers[i].szValue);
+ }
+ if(szHost && !doneHostHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Host",szHost);
+ if(pszProxyAuthorizationHeader) {
+ if(!doneProxyAuthHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Proxy-Authorization",pszProxyAuthorizationHeader);
+ mir_free(pszProxyAuthorizationHeader);
+ if(usingNtlmAuthentication) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Connection","Keep-Alive");
+ }
+
+ // Add Sticky Headers
+ if (nlc->nlu->szStickyHeaders != NULL) {
+ AppendToCharBuffer(&httpRequest,"%s\r\n", nlc->nlu->szStickyHeaders);
+ }
+
+ //send it
+ bytesSent=SendHttpRequestAndData(nlc,&httpRequest,nlhr,!doneContentLengthHeader);
+ if(bytesSent==SOCKET_ERROR) {
+ if(usingNtlmAuthentication) NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+
+ //ntlm reply
+ if(usingNtlmAuthentication) {
+ int resultCode=0;
+
+ if(!HttpPeekFirstResponseLine(nlc,GetTickCount()+5000,MSG_PEEK|MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)),&resultCode,NULL,NULL)
+ || ((resultCode<200 || resultCode>=300) && resultCode!=407)) {
+ NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ if(resultCode) NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ return SOCKET_ERROR;
+ }
+ if(resultCode==407) { //proxy auth required
+ NETLIBHTTPREQUEST *nlhrReply;
+ int i,error,contentLength=0;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0));
+ if(nlhrReply==NULL) {
+ NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ if(resultCode) NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ return SOCKET_ERROR;
+ }
+ pszProxyAuthorizationHeader=NULL;
+ error=ERROR_SUCCESS;
+ for(i=0;i<nlhrReply->headersCount;i++) {
+ if(!lstrcmpiA(nlhrReply->headers[i].szName,"Proxy-Authenticate")) {
+ if(!_strnicmp(nlhrReply->headers[i].szValue,"NTLM ",5))
+ pszProxyAuthorizationHeader=NtlmCreateResponseFromChallenge(nlhrReply->headers[i].szValue+5);
+ else error=ERROR_ACCESS_DENIED;
+ }
+ else if(!lstrcmpiA(nlhrReply->headers[i].szName,"Content-Length"))
+ contentLength=atoi(nlhrReply->headers[i].szValue);
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NtlmDestroy();
+ if(pszProxyAuthorizationHeader==NULL) {
+ if(error!=ERROR_SUCCESS) SetLastError(error);
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+
+ //receive content and throw away
+ { BYTE trashBuf[512];
+ int recvResult;
+
+ while(contentLength) {
+ recvResult=NLRecv(nlc,trashBuf,SIZEOF(trashBuf),nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:MSG_DUMPASTEXT|MSG_DUMPPROXY);
+ if(recvResult==0 || recvResult==SOCKET_ERROR) {
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+ contentLength-=recvResult;
+ }
+ }
+
+ httpRequest.cbAlloced=httpRequest.iEnd=0;
+ httpRequest.sz=NULL;
+ AppendToCharBuffer(&httpRequest,"%s %s HTTP/1.0\r\n",pszRequest,pszUrl);
+
+ //HTTP headers
+ doneHostHeader=doneContentLengthHeader=0;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"Host")) doneHostHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Content-Length")) doneContentLengthHeader=1;
+ if(nlhr->headers[i].szValue==NULL) continue;
+ AppendToCharBuffer(&httpRequest,"%s: %s\r\n",nlhr->headers[i].szName,nlhr->headers[i].szValue);
+ }
+ if(szHost) {
+ if(!doneHostHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Host",szHost);
+ mir_free(szHost); szHost=NULL;
+ }
+ AppendToCharBuffer(&httpRequest,"%s: NTLM %s\r\n","Proxy-Authorization",pszProxyAuthorizationHeader);
+
+ //send it
+ bytesSent=SendHttpRequestAndData(nlc,&httpRequest,nlhr,!doneContentLengthHeader);
+ if(bytesSent==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+ }
+ else NtlmDestroy();
+ }
+
+ //clean up
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return bytesSent;
+}
+
+int NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+
+ if(nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->requestType!=REQUEST_RESPONSE) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlhr->headers) {
+ int i;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(nlhr->headers[i].szName) mir_free(nlhr->headers[i].szName);
+ if(nlhr->headers[i].szValue) mir_free(nlhr->headers[i].szValue);
+ }
+ mir_free(nlhr->headers);
+ }
+ if(nlhr->pData) mir_free(nlhr->pData);
+ if(nlhr->szResultDescr) mir_free(nlhr->szResultDescr);
+ if(nlhr->szUrl) mir_free(nlhr->szUrl);
+ mir_free(nlhr);
+ return 1;
+}
+
+int NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr;
+ char buffer[4096];
+ int bytesPeeked;
+ DWORD dwRequestTimeoutTime;
+ char *peol,*pbuffer;
+ int headersDone=0,firstLineLength;
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV))
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ dwRequestTimeoutTime=GetTickCount()+HTTPRECVHEADERSTIMEOUT;
+ nlhr=(NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST));
+ nlhr->cbSize=sizeof(NETLIBHTTPREQUEST);
+ nlhr->nlc=nlc;
+ nlhr->requestType=REQUEST_RESPONSE;
+ if(!HttpPeekFirstResponseLine(nlc,dwRequestTimeoutTime,lParam|MSG_PEEK,&nlhr->resultCode,&nlhr->szResultDescr,&firstLineLength)) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr); + return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ bytesPeeked=NLRecv(nlc,buffer,firstLineLength,lParam|MSG_DUMPASTEXT);
+ if(bytesPeeked<firstLineLength) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(bytesPeeked!=SOCKET_ERROR) SetLastError(ERROR_HANDLE_EOF);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ for(;;) {
+ bytesPeeked=RecvWithTimeoutTime(nlc,dwRequestTimeoutTime,buffer,SIZEOF(buffer)-1,MSG_PEEK|lParam);
+ if(bytesPeeked==0 || bytesPeeked==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(bytesPeeked==0) SetLastError(ERROR_HANDLE_EOF);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ buffer[bytesPeeked]='\0';
+ for(pbuffer=buffer;;) {
+ peol=strchr(pbuffer,'\n');
+ if(peol==NULL) {
+ if(lstrlenA(buffer)<bytesPeeked) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_BAD_FORMAT);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ if((bytesPeeked == SIZEOF(buffer)-1 && pbuffer==buffer) //buffer overflow
+ || (pbuffer!=buffer && NLRecv(nlc,buffer,pbuffer-buffer,lParam|MSG_DUMPASTEXT)==SOCKET_ERROR)) { //error removing read bytes from buffer
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(pbuffer==buffer) SetLastError(ERROR_BUFFER_OVERFLOW);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ Sleep(100);
+ break;
+ }
+ if(peol==pbuffer || *--peol!='\r') {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_BAD_FORMAT);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ *peol='\0';
+ {
+ char *pColon;
+ int len;
+ if(peol==pbuffer) { //blank line: end of headers
+ if(NLRecv(nlc,buffer,peol+2-buffer,lParam|MSG_DUMPASTEXT)==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ headersDone=1;
+ break;
+ }
+ pColon=strchr(pbuffer,':');
+ if(pColon==NULL) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_INVALID_DATA);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ nlhr->headersCount++;
+ nlhr->headers=(NETLIBHTTPHEADER*)mir_realloc(nlhr->headers,sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ nlhr->headers[nlhr->headersCount-1].szName=(char*)mir_alloc(pColon-pbuffer+1);
+ lstrcpynA(nlhr->headers[nlhr->headersCount-1].szName,pbuffer,pColon-pbuffer+1);
+ len=lstrlenA(nlhr->headers[nlhr->headersCount-1].szName);
+ while(len && (nlhr->headers[nlhr->headersCount-1].szName[len-1]==' ' || nlhr->headers[nlhr->headersCount-1].szName[len-1]=='\t'))
+ nlhr->headers[nlhr->headersCount-1].szName[--len]='\0';
+ pColon++;
+ while(*pColon==' ' || *pColon=='\t') pColon++;
+ nlhr->headers[nlhr->headersCount-1].szValue=mir_strdup(pColon);
+ }
+ pbuffer=peol+2;
+ }
+ if(headersDone) break;
+ }
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ return (int)nlhr;
+}
+
+int NetlibHttpTransaction(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam,*nlhrReply;
+ HANDLE hConnection;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_OUTGOING) || nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl==NULL || nlhr->szUrl[0]=='\0') {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+
+ {
+ NETLIBOPENCONNECTION nloc={0};
+ char szHost[128];
+ char *ppath,*phost,*pcolon;
+
+ phost=strstr(nlhr->szUrl,"://");
+ if(phost==NULL) phost=nlhr->szUrl;
+ else phost+=3;
+ lstrcpynA(szHost,phost,SIZEOF(szHost));
+ ppath=strchr(szHost,'/');
+ if(ppath) *ppath='\0';
+ nloc.cbSize=sizeof(nloc);
+ nloc.szHost=szHost;
+ pcolon=strrchr(szHost,':');
+ if(pcolon) {
+ *pcolon='\0';
+ nloc.wPort=(WORD)strtol(pcolon+1,NULL,10);
+ }
+ else nloc.wPort=80;
+ nloc.flags=NLOCF_HTTP;
+ hConnection=(HANDLE)NetlibOpenConnection((WPARAM)nlu,(LPARAM)&nloc);
+ if(hConnection==NULL) return (int)(HANDLE)NULL;
+ }
+
+ {
+ NETLIBHTTPREQUEST nlhrSend;
+ int i,doneUserAgentHeader=0;
+ char szUserAgent[64];
+
+ nlhrSend=*nlhr;
+ nlhrSend.flags&=~NLHRF_REMOVEHOST;
+ nlhrSend.flags|=NLHRF_GENERATEHOST|NLHRF_SMARTREMOVEHOST|NLHRF_SMARTAUTHHEADER;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"User-Agent"))
+ doneUserAgentHeader=1;
+ }
+ if(!doneUserAgentHeader) {
+ char *pspace,szMirandaVer[32];
+
+ nlhrSend.headersCount++;
+ nlhrSend.headers=(NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhrSend.headersCount);
+ CopyMemory(nlhrSend.headers,nlhr->headers,sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ nlhrSend.headers[nlhrSend.headersCount-1].szName="User-Agent";
+ nlhrSend.headers[nlhrSend.headersCount-1].szValue=szUserAgent;
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szMirandaVer),(LPARAM)szMirandaVer);
+ pspace=strchr(szMirandaVer,' ');
+ if(pspace) {
+ *pspace++='\0';
+ mir_snprintf(szUserAgent,SIZEOF(szUserAgent),"Miranda/%s (%s)",szMirandaVer,pspace);
+ }
+ else mir_snprintf(szUserAgent,SIZEOF(szUserAgent),"Miranda/%s",szMirandaVer);
+ }
+ if(NetlibHttpSendRequest((WPARAM)hConnection,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ if(!doneUserAgentHeader) mir_free(nlhrSend.headers);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ if(!doneUserAgentHeader) mir_free(nlhrSend.headers);
+ }
+
+ {
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)hConnection,0);
+ if(nlhrReply==NULL) {
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ } }
+
+ if (nlhr->requestType != REQUEST_HEAD){
+ int recvResult;
+ int dataBufferAlloced=0;
+
+ for(;;) {
+ if(dataBufferAlloced-nlhrReply->dataLength<1024) {
+ dataBufferAlloced+=2048;
+ nlhrReply->pData=(PBYTE)mir_realloc(nlhrReply->pData,dataBufferAlloced);
+ if(nlhrReply->pData==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ recvResult=NLRecv((struct NetlibConnection*)hConnection,nlhrReply->pData+nlhrReply->dataLength,dataBufferAlloced-nlhrReply->dataLength-1,(nlhr->flags&NLHRF_DUMPASTEXT?MSG_DUMPASTEXT:0)|(nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ if(recvResult==0) break;
+ if(recvResult==SOCKET_ERROR) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ nlhrReply->dataLength+=recvResult;
+ //TODO: Keep-alive replies are measured by content-length, not by when the connection closes
+ }
+ nlhrReply->pData[nlhrReply->dataLength]='\0';
+ }
+
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)nlhrReply;
+}
+
+void NetlibHttpSetLastErrorUsingHttpResult(int result)
+{
+ if(result>=200 && result<300) {
+ SetLastError(ERROR_SUCCESS);
+ return;
+ }
+ switch(result) {
+ case 400: SetLastError(ERROR_BAD_FORMAT); break;
+ case 401:
+ case 402:
+ case 403:
+ case 407: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 404: SetLastError(ERROR_FILE_NOT_FOUND); break;
+ case 405:
+ case 406: SetLastError(ERROR_INVALID_FUNCTION); break;
+ case 408: SetLastError(ERROR_TIMEOUT); break;
+ default: SetLastError(ERROR_GEN_FAILURE); break;
+ }
+}
diff --git a/miranda-wine/src/modules/netlib/netlibhttpproxy.c b/miranda-wine/src/modules/netlib/netlibhttpproxy.c new file mode 100644 index 0000000..f3fc82e --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibhttpproxy.c @@ -0,0 +1,610 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+#define HTTPGETTIMEOUT 55000 //in ms. http GETs through most proxies will give up after a while so the request needs to be re-sent
+
+static int HttpGatewaySendGet(struct NetlibConnection *nlc)
+{
+ NETLIBHTTPREQUEST nlhrSend={0};
+ NETLIBHTTPHEADER httpHeaders[3];
+ char szUrl[512];
+ struct NetlibConnection nlcSend;
+
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ return 0;
+ }
+
+ if(connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy))==SOCKET_ERROR) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ return 0;
+ }
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+
+ /*
+ * Gena01 - one small change here, just in case there is a timeout or a problem and we died while
+ * receiving
+ */
+ nlhrSend.requestType=(nlc->nlhpi.szHttpGetUrl == NULL) ? REQUEST_POST : REQUEST_GET;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER; + if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11; +
+ /*
+ * Gena01 - fixing a possible crash, can't use GET Sequence if there is no GET URL
+ */
+ if ((nlc->nlhpi.flags&NLHPIF_USEGETSEQUENCE) && (nlc->nlhpi.szHttpGetUrl != NULL)) {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s%u",nlc->nlhpi.szHttpGetUrl,nlc->nlhpi.firstGetSequence);
+ nlc->nlhpi.firstGetSequence++;
+ if(nlc->nlhpi.flags&NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstPostSequence++;
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl=szUrl;
+ }
+ else nlhrSend.szUrl=(nlc->nlhpi.szHttpGetUrl == NULL) ? nlc->nlhpi.szHttpPostUrl : nlc->nlhpi.szHttpGetUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount= 3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlc->nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+
+ nlcSend=*nlc;
+ nlcSend.usingHttpGateway=0;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL) {
+
+ Netlib_Logf(nlc->nlu,"%s %d: Sending data.[ICQ GET] ",__FILE__,__LINE__);
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ nlc->usingHttpGateway=1;
+ return 0;
+ }
+ nlc->dwLastGetSentTime=GetTickCount();
+ return 1;
+ }
+
+ /*
+ * Gena01 - small addition here, if we doing a POST then insert our packet here
+ */
+ if (nlc->pHttpProxyPacketQueue != NULL) {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+
+ nlc->pHttpProxyPacketQueue = nlc->pHttpProxyPacketQueue->next;
+
+ nlhrSend.dataLength=p->dataBufferLen;
+ nlhrSend.pData=(char*)p->dataBuffer;
+
+ mir_free(p);
+ }
+
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ + mir_free(nlhrSend.pData); +
+ nlc->usingHttpGateway=1;
+
+ /*
+ * Gena01 - we need to drop ALL pending packets. Connection died!
+ */
+ while (p != NULL) {
+ struct NetlibHTTPProxyPacketQueue *t = p;
+
+ p = p->next;
+
+ mir_free(t->dataBuffer);
+ mir_free(t);
+ }
+
+ nlc->pHttpProxyPacketQueue = NULL; /* empty Queue */
+
+ return 0;
+ }
+ mir_free(nlhrSend.pData); + nlc->dwLastGetSentTime=GetTickCount();
+ return 1;
+}
+
+/*
+ * Gena01 - this is the old POST method, I renamed it and left it intact for ICQ support. it's called
+ * when we have both GET and POST URLs specified.
+ */
+int NetlibHttpGatewayOLDPost(struct NetlibConnection *nlc,const char *buf,int len,int flags)
+{
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply;
+ NETLIBHTTPHEADER httpHeaders[4];
+ char szUrl[512];
+ struct NetlibConnection nlcSend={0};
+
+ nlcSend.handleType=NLH_CONNECTION;
+ nlcSend.nlu=nlc->nlu;
+ nlcSend.hInstSecurityDll=nlc->hInstSecurityDll;
+ nlcSend.s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlcSend.s==INVALID_SOCKET) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ return SOCKET_ERROR;
+ }
+ nlcSend.hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlcSend.dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlcSend.ncsRecv);
+ NetlibInitializeNestedCS(&nlcSend.ncsSend);
+
+ if(connect(nlcSend.s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy))==SOCKET_ERROR) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return SOCKET_ERROR;
+ }
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+ nlhrSend.requestType=REQUEST_POST;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER;
+ if(flags&MSG_NODUMP) nlhrSend.flags|=NLHRF_NODUMP;
+ if(nlc->nlhpi.flags&NLHPIF_USEPOSTSEQUENCE) {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s%u",nlc->nlhpi.szHttpPostUrl,nlc->nlhpi.firstPostSequence);
+ nlc->nlhpi.firstPostSequence++;
+ if(nlc->nlhpi.flags&NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstGetSequence++;
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl=szUrl;
+ }
+ else nlhrSend.szUrl=nlc->nlhpi.szHttpPostUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlc->nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Connection";
+ httpHeaders[2].szValue="close";
+ httpHeaders[3].szName="Pragma";
+ httpHeaders[3].szValue="no-cache";
+ nlhrSend.dataLength=len;
+ nlhrSend.pData=(char*)buf;
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return SOCKET_ERROR;
+ }
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)&nlcSend,flags&MSG_NODUMP?MSG_NODUMP:MSG_DUMPPROXY);
+ if(nlhrReply==NULL
+ || nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ if(nlhrReply) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ }
+ return SOCKET_ERROR;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return len;
+}
+
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags)
+{
+ struct NetlibHTTPProxyPacketQueue *p;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL)
+ return NetlibHttpGatewayOLDPost(nlc, buf, len, flags);
+
+ /*
+ * Gena01 - many changes here, do compare against the other version.
+ *
+ * Change #1: simplify to use similar code to GET
+ * Change #2: we need to allow to parse POST reply if szHttpGetUrl is NULL
+ * Change #3: Keep connection open if we need to.
+ *
+ * Impact: NONE! Since currently miranda doesn't allow szHttpGetUrl to be NULL, it will not connect
+ * with the new plugins that use this code.
+ */
+
+ p = mir_alloc(sizeof(struct NetlibHTTPProxyPacketQueue));
+ p->dataBuffer = mir_alloc(len);
+ memcpy(p->dataBuffer, buf, len);
+ p->dataBufferLen = len;
+ p->next = NULL;
+
+ /*
+ * Now check to see where to insert this in our queue
+ */
+ if (nlc->pHttpProxyPacketQueue == NULL) {
+ nlc->pHttpProxyPacketQueue = p;
+ } else {
+ struct NetlibHTTPProxyPacketQueue *t = nlc->pHttpProxyPacketQueue;
+
+ while (t->next != NULL)
+ t = t->next;
+
+ t->next = p;
+ }
+
+
+ /*
+ * Gena01 - fake a Send!! tell 'em all is ok. We catch errors in Recv.
+ */
+ return len;
+}
+
+#define NETLIBHTTP_RETRYCOUNT 3
+#define NETLIBHTTP_RETRYTIMEOUT 5000
+
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags)
+{
+ DWORD dwTimeNow;
+ int timedout;
+ NETLIBHTTPREQUEST *nlhrReply;
+ PBYTE dataBuffer;
+ int contentLength,i,bytesRecved;
+ int recvResult;
+ int retryCount;
+
+ /*
+ * Gena01 - we need to send packet here, since we didn't do it before.
+ */
+ if ((nlc->nlhpi.szHttpGetUrl == NULL) && (nlc->s == INVALID_SOCKET) && nlc->dataBuffer == NULL ) {
+
+ if ( nlc->pollingTimeout == 0 )
+ nlc->pollingTimeout = 30;
+
+ /* We Need to sleep/wait for the data to send before we do receive */
+ for ( retryCount = 0; retryCount < nlc->pollingTimeout; retryCount++ )
+ {
+ if ( nlc->pHttpProxyPacketQueue != NULL )
+ break;
+
+ if ( SleepEx( 1000, TRUE ))
+ return SOCKET_ERROR;
+ }
+
+/* if ( retryCount == nlc->pollingTimeout )
+ { SetLastError( ERROR_TIMEOUT );
+ return SOCKET_ERROR;
+ }
+*/
+ if ( nlc->pHttpProxyPacketQueue == 0 && nlc->nlu->user.pfnHttpGatewayWrapSend != NULL )
+ nlc->nlu->user.pfnHttpGatewayWrapSend((HANDLE)nlc,"",0,MSG_NOHTTPGATEWAYWRAP,NetlibSend); +
+ if(!HttpGatewaySendGet(nlc)) {
+ return SOCKET_ERROR;
+ }
+ }
+ /********************/
+ if(nlc->dataBuffer) {
+ if(nlc->dataBufferLen<=len) {
+ contentLength=nlc->dataBufferLen;
+ CopyMemory(buf,nlc->dataBuffer,nlc->dataBufferLen);
+ if(!(flags&MSG_PEEK)) {
+ mir_free(nlc->dataBuffer);
+ nlc->dataBuffer=NULL;
+ nlc->dataBufferLen=0;
+ }
+ return contentLength;
+ }
+ CopyMemory(buf,nlc->dataBuffer,len);
+ if(!(flags&MSG_PEEK)) {
+ nlc->dataBufferLen-=len;
+ MoveMemory(nlc->dataBuffer,nlc->dataBuffer+len,nlc->dataBufferLen);
+ nlc->dataBuffer=(PBYTE)mir_realloc(nlc->dataBuffer,nlc->dataBufferLen);
+ }
+ return len;
+ }
+ for( retryCount = 0;;) {
+ timedout=0;
+ dwTimeNow=GetTickCount();
+ if(dwTimeNow>=nlc->dwLastGetSentTime+HTTPGETTIMEOUT) timedout=1;
+ else if(!WaitUntilReadable(nlc->s,nlc->dwLastGetSentTime+HTTPGETTIMEOUT-dwTimeNow)) {
+ if(GetLastError()==ERROR_TIMEOUT) timedout=1;
+ else return SOCKET_ERROR;
+ }
+ if(timedout) {
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+ if(!HttpGatewaySendGet(nlc)) return SOCKET_ERROR;
+ retryCount = 0;
+ continue;
+ }
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,flags|MSG_RAW|MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return SOCKET_ERROR;
+ // ignore 1xx result codes
+ if (nlhrReply->resultCode < 200)
+ { + NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply); + continue;
+ } + // 0.3.1+
+ // Attempt to retry NETLIBHTTP_RETRYCOUNT times if the result code is >300
+ if (nlhrReply->resultCode >= 300)
+ {
+ if (retryCount < NETLIBHTTP_RETRYCOUNT) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ Netlib_Logf(nlc->nlu, "Error received from proxy, retrying");
+ retryCount++;
+ closesocket(nlc->s);
+ nlc->s = INVALID_SOCKET;
+ Sleep(NETLIBHTTP_RETRYTIMEOUT); // wait 5 seconds
+ // retry the connection
+ Netlib_Logf(nlc->nlu,"%s %d: ResultCode?? Doing GET.",__FILE__,__LINE__);
+ if(HttpGatewaySendGet(nlc))
+ continue;
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+ }
+ }
+ retryCount = 0;
+ contentLength=-1;
+ for(i=0;i<nlhrReply->headersCount;i++)
+ { + if(!lstrcmpiA(nlhrReply->headers[i].szName,"Content-Length")) {
+ contentLength=atoi(nlhrReply->headers[i].szValue);
+ break;
+ }
+ } +
+ /*
+ if(contentLength<0) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_INVALID_DATA);
+ return SOCKET_ERROR;
+ }*/
+ if(contentLength==0 && nlc->nlu->user.szHttpGatewayHello != NULL)
+ { + NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply); + continue;
+ } +
+
+ if (contentLength < 0) {
+ /* create initial buffer */
+ contentLength = 2048;
+
+ dataBuffer=(PBYTE)mir_alloc(contentLength);
+
+ /* error and exit */
+ if(dataBuffer==NULL) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+
+ /* now we need to get the bytes and add them to our buffer */
+ bytesRecved = 0;
+
+ do {
+ recvResult=NLRecv(nlc,dataBuffer+bytesRecved,contentLength-bytesRecved,MSG_RAW|MSG_DUMPPROXY);
+ if(recvResult==SOCKET_ERROR) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ return SOCKET_ERROR;
+ }
+ bytesRecved+=recvResult;
+ } while (recvResult > 0);
+ contentLength = bytesRecved;
+ } else {
+ if(contentLength > 0) {
+ dataBuffer=(PBYTE)mir_alloc(contentLength);
+ if(dataBuffer==NULL) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+ for(bytesRecved=0;bytesRecved<contentLength;) {
+ recvResult=NLRecv(nlc,dataBuffer+bytesRecved,contentLength-bytesRecved,MSG_RAW|MSG_DUMPPROXY);
+ if(recvResult==0 || recvResult==SOCKET_ERROR) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ return SOCKET_ERROR;
+ }
+ bytesRecved+=recvResult;
+ } }
+ else dataBuffer = NULL;
+ }
+
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+
+ /*
+ * Gena01 - ok, ICQ does it here so that when we enter this function again we have reply
+ * pending. This is quite clever, since GET always gets replies from ICQ server
+ *
+ */
+ if (nlc->nlhpi.szHttpGetUrl != NULL) {
+ Netlib_Logf(nlc->nlu,"%s %d: Doing GET, Again????",__FILE__,__LINE__);
+
+ if(!HttpGatewaySendGet(nlc)) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ }
+
+ if(nlc->nlu->user.pfnHttpGatewayUnwrapRecv && !(flags&MSG_NOHTTPGATEWAYWRAP)) {
+ PBYTE newBuffer;
+ newBuffer=nlc->nlu->user.pfnHttpGatewayUnwrapRecv(nlhrReply,dataBuffer,contentLength,&contentLength,mir_realloc);
+ if(newBuffer==NULL) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ dataBuffer=newBuffer;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(contentLength>0) break;
+ if((contentLength==0)&&(nlc->nlhpi.szHttpGetUrl==NULL))
+ break;
+ mir_free(dataBuffer);
+ }
+ if(contentLength<=len) {
+ if(flags&MSG_PEEK) {
+ nlc->dataBuffer=dataBuffer;
+ nlc->dataBufferLen=contentLength;
+ }
+ CopyMemory(buf,dataBuffer,contentLength);
+ if(!(flags&MSG_PEEK)) mir_free(dataBuffer);
+ return contentLength;
+ }
+ CopyMemory(buf,dataBuffer,len);
+ if(!(flags&MSG_PEEK)) {
+ MoveMemory(dataBuffer,dataBuffer+len,contentLength-len);
+ dataBuffer=(PBYTE)mir_realloc(dataBuffer,contentLength-len);
+ nlc->dataBufferLen=contentLength-len;
+ }
+ else nlc->dataBufferLen=contentLength;
+ nlc->dataBuffer=dataBuffer;
+
+ Netlib_Logf(nlc->nlu,"%s %d: NetlibHTTPGatewayRecv EXIT!",__FILE__,__LINE__);
+ return len;
+}
+
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply=NULL;
+ NETLIBHTTPHEADER httpHeaders[3];
+
+ nlc->nlhpi.firstGetSequence=nlc->nlhpi.firstPostSequence=1;
+
+ /*
+ * Gena01 - ok we set nlhrReply to be null, also if the szHttpGatewayHello is NULL, then
+ * we don't send any requests/replies. We do have a socket open though. Could we
+ * re-use it maybe?
+ */
+ if (nlu->user.szHttpGatewayHello != NULL) {
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+ nlhrSend.requestType=REQUEST_GET;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER; + if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11; + + nlhrSend.szUrl=nlu->user.szHttpGatewayHello;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+ if(NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend)==SOCKET_ERROR)
+ return 0;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return 0;
+
+ if(nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ return 0;
+ }
+ }
+ if(!nlu->user.pfnHttpGatewayInit(nlc,nloc,nlhrReply)) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+
+ /*
+ * Gena01 - Ok, we should be able to use just POST. Needed for Yahoo, NO GET requests
+ */
+ if(nlc->nlhpi.szHttpPostUrl==NULL) {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+
+ nlc->usingHttpGateway=1;
+
+ /* don't send anything if only using POST? */
+ if(nlc->nlhpi.szHttpGetUrl!= NULL)
+ if(!HttpGatewaySendGet(nlc))
+ return 0;
+
+ //now properly connected
+ if(nlu->user.pfnHttpGatewayBegin)
+ if(!nlu->user.pfnHttpGatewayBegin(nlc,nloc))
+ return 0;
+ return 1;
+}
+
+int NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPPROXYINFO *nlhpi=(NETLIBHTTPPROXYINFO*)lParam;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || nlhpi==NULL || nlhpi->cbSize!=sizeof(NETLIBHTTPPROXYINFO) || nlhpi->szHttpPostUrl==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ nlc->nlhpi=*nlhpi;
+
+ if (nlc->nlhpi.szHttpGetUrl)
+ nlc->nlhpi.szHttpGetUrl=mir_strdup(nlc->nlhpi.szHttpGetUrl);
+
+ nlc->nlhpi.szHttpPostUrl=mir_strdup(nlc->nlhpi.szHttpPostUrl);
+ return 1;
+}
+
+int NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibUser * nu = (struct NetlibUser*)wParam;
+ if (GetNetlibHandleType(nu)!=NLH_USER) return ERROR_INVALID_PARAMETER;
+ if (nu->szStickyHeaders) { mir_free(nu->szStickyHeaders); nu->szStickyHeaders=NULL; }
+ if (lParam) {
+ nu->szStickyHeaders=mir_strdup((char*)lParam); // pointer is ours
+ }
+ return 0;
+}
+
+int NetlibHttpSetPollingTimeout(WPARAM wParam, LPARAM lParam)
+{
+ int oldTimeout;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ if (GetNetlibHandleType(nlc)!=NLH_CONNECTION) return -1;
+ oldTimeout = nlc->pollingTimeout;
+ nlc->pollingTimeout = lParam;
+ return oldTimeout;
+}
diff --git a/miranda-wine/src/modules/netlib/netliblog.c b/miranda-wine/src/modules/netlib/netliblog.c new file mode 100644 index 0000000..9d07f29 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netliblog.c @@ -0,0 +1,440 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+#include "netlib.h"
+
+#define MS_NETLIB_LOGWIN "Netlib/Log/Win"
+
+extern HANDLE hConnectionHeaderMutex;
+
+#define TIMEFORMAT_NONE 0
+#define TIMEFORMAT_HHMMSS 1
+#define TIMEFORMAT_MILLISECONDS 2
+#define TIMEFORMAT_MICROSECONDS 3
+struct {
+ HWND hwndOpts;
+ int toOutputDebugString;
+ int toFile;
+ TCHAR* szFile;
+ int timeFormat;
+ int showUser;
+ int dumpSent,dumpRecv,dumpProxy;
+ int textDumps,autoDetectText;
+ CRITICAL_SECTION cs;
+} logOptions;
+static __int64 mirandaStartTime,perfCounterFreq;
+
+static const TCHAR* szTimeFormats[] =
+{
+ _T( "No times" ),
+ _T( "Standard hh:mm:ss times" ),
+ _T( "Times in milliseconds" ),
+ _T( "Times in microseconds" )
+};
+
+static BOOL CALLBACK LogOptionsDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ logOptions.hwndOpts=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg,IDC_DUMPRECV,logOptions.dumpRecv?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPSENT,logOptions.dumpSent?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPPROXY,logOptions.dumpProxy?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TEXTDUMPS,logOptions.textDumps?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_AUTODETECTTEXT,logOptions.autoDetectText?BST_CHECKED:BST_UNCHECKED);
+ { int i;
+ for( i=0; i < SIZEOF(szTimeFormats); i++ )
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_ADDSTRING,0,(LPARAM)TranslateTS( szTimeFormats[i] ));
+ }
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_SETCURSEL,logOptions.timeFormat,0);
+ CheckDlgButton(hwndDlg,IDC_SHOWNAMES,logOptions.showUser?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOOUTPUTDEBUGSTRING,logOptions.toOutputDebugString?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOFILE,logOptions.toFile?BST_CHECKED:BST_UNCHECKED);
+ SetDlgItemText(hwndDlg,IDC_FILENAME,logOptions.szFile);
+ CheckDlgButton(hwndDlg,IDC_SHOWTHISDLGATSTART,DBGetContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",0)?BST_CHECKED:BST_UNCHECKED);
+ { DBVARIANT dbv;
+ if(!DBGetContactSetting(NULL,"Netlib","RunAtStart",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_RUNATSTART,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_DUMPRECV:
+ logOptions.dumpRecv=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_DUMPSENT:
+ logOptions.dumpSent=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_DUMPPROXY:
+ logOptions.dumpProxy=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TEXTDUMPS:
+ logOptions.textDumps=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_AUTODETECTTEXT:
+ logOptions.autoDetectText=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TIMEFORMAT:
+ logOptions.timeFormat=SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_GETCURSEL,0,0);
+ break;
+ case IDC_SHOWNAMES:
+ logOptions.showUser=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TOOUTPUTDEBUGSTRING:
+ logOptions.toOutputDebugString=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TOFILE:
+ logOptions.toFile=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_FILENAME:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ if((HWND)lParam==GetFocus()) {
+ CheckDlgButton(hwndDlg,IDC_TOFILE,BST_CHECKED);
+ logOptions.toFile=0;
+ }
+ EnterCriticalSection(&logOptions.cs);
+ if(logOptions.szFile) mir_free(logOptions.szFile);
+ { int len;
+ len=GetWindowTextLength((HWND)lParam);
+ logOptions.szFile = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 ));
+ GetWindowText((HWND)lParam, logOptions.szFile, len+1 );
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ break;
+ case IDC_FILENAMEBROWSE:
+ case IDC_RUNATSTARTBROWSE:
+ { TCHAR str[MAX_PATH+2];
+ OPENFILENAME ofn={0};
+ TCHAR filter[512],*pfilter;
+
+ GetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_HIDEREADONLY;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ ofn.lpstrTitle=TranslateT("Select where log file will be created");
+ } else {
+ ofn.Flags|=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;
+ ofn.lpstrTitle=TranslateT("Select program to be run");
+ }
+ _tcscpy(filter,TranslateT("All Files"));
+ _tcscat(filter,_T(" (*)"));
+ pfilter=filter+lstrlen(filter)+1;
+ _tcscpy(pfilter,_T("*"));
+ pfilter=pfilter+lstrlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str)-2;
+ ofn.nMaxFileTitle=MAX_PATH;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ if(!GetSaveFileName(&ofn)) return 1;
+ } else {
+ if(!GetOpenFileName(&ofn)) return 1;
+ }
+ if(LOWORD(wParam)==IDC_RUNATSTARTBROWSE && _tcschr(str,' ')!=NULL) {
+ MoveMemory(str+1,str,SIZEOF(str)-2);
+ str[0]='"';
+ lstrcat(str,_T("\""));
+ }
+ SetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str);
+ break;
+ }
+ case IDC_SHOWTHISDLGATSTART:
+ DBWriteContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",(BYTE)IsDlgButtonChecked(hwndDlg,LOWORD(wParam)));
+ break;
+ case IDC_RUNATSTART:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ { int len;
+ char *str;
+ len=GetWindowTextLength((HWND)lParam);
+ str=(char*)mir_alloc(len+1);
+ GetWindowTextA((HWND)lParam,str,len+1);
+ DBWriteContactSettingString(NULL,"Netlib","RunAtStart",str);
+ mir_free(str);
+ }
+ break;
+ case IDC_RUNNOW:
+ { int len;
+ char *str;
+ STARTUPINFOA si={0};
+ PROCESS_INFORMATION pi;
+ len=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_RUNATSTART));
+ str=(char*)mir_alloc(len+1);
+ GetDlgItemTextA(hwndDlg,IDC_RUNATSTART,str,len+1);
+ si.cb=sizeof(si);
+ if(str[0]) CreateProcessA(NULL,str,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ }
+ break;
+ case IDC_SAVE:
+ DBWriteContactSettingByte(NULL,"Netlib","DumpRecv",(BYTE)logOptions.dumpRecv);
+ DBWriteContactSettingByte(NULL,"Netlib","DumpSent",(BYTE)logOptions.dumpSent);
+ DBWriteContactSettingByte(NULL,"Netlib","DumpProxy",(BYTE)logOptions.dumpProxy);
+ DBWriteContactSettingByte(NULL,"Netlib","TextDumps",(BYTE)logOptions.textDumps);
+ DBWriteContactSettingByte(NULL,"Netlib","AutoDetectText",(BYTE)logOptions.autoDetectText);
+ DBWriteContactSettingByte(NULL,"Netlib","TimeFormat",(BYTE)logOptions.timeFormat);
+ DBWriteContactSettingByte(NULL,"Netlib","ShowUser",(BYTE)logOptions.showUser);
+ DBWriteContactSettingByte(NULL,"Netlib","ToOutputDebugString",(BYTE)logOptions.toOutputDebugString);
+ DBWriteContactSettingByte(NULL,"Netlib","ToFile",(BYTE)logOptions.toFile);
+ DBWriteContactSettingTString(NULL,"Netlib","File", logOptions.szFile ? logOptions.szFile: _T(""));
+ break;
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ logOptions.hwndOpts=NULL;
+ break;
+ }
+ return FALSE;
+}
+
+void NetlibLogShowOptions(void)
+{
+ if(logOptions.hwndOpts==NULL)
+ logOptions.hwndOpts=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_NETLIBLOGOPTS),NULL,LogOptionsDlgProc);
+ SetForegroundWindow(logOptions.hwndOpts);
+}
+
+static void CreateDirectoryTree( TCHAR* szDir)
+{
+ DWORD dwAttributes;
+ TCHAR* pszLastBackslash,szTestDir[MAX_PATH];
+
+ lstrcpyn(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributes(szTestDir))!=0xffffffff && dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ pszLastBackslash = _tcsrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL ) return;
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szTestDir );
+ CreateDirectory( szTestDir, NULL );
+}
+
+static int NetlibLog(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibUser nludummy;
+ const char *pszMsg=(const char*)lParam;
+ char *szLine;
+ char szTime[32];
+ LARGE_INTEGER liTimeNow;
+ DWORD dwOriginalLastError;
+
+ if( (nlu != NULL && GetNetlibHandleType(nlu)!=NLH_USER) || pszMsg==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if (nlu==NULL) { /* if the Netlib user handle is NULL, just pretend its not */
+ nlu=&nludummy;
+ nlu->user.szSettingsModule="(NULL)";
+ }
+ dwOriginalLastError=GetLastError();
+ QueryPerformanceCounter(&liTimeNow);
+ liTimeNow.QuadPart-=mirandaStartTime;
+ switch(logOptions.timeFormat) {
+ case TIMEFORMAT_HHMMSS:
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,NULL,NULL,szTime,SIZEOF(szTime)-1);
+ break;
+ case TIMEFORMAT_MILLISECONDS:
+ mir_snprintf(szTime,SIZEOF(szTime)-1,"%I64u.%03I64u",liTimeNow.QuadPart/perfCounterFreq,1000*(liTimeNow.QuadPart%perfCounterFreq)/perfCounterFreq);
+ break;
+ case TIMEFORMAT_MICROSECONDS:
+ mir_snprintf(szTime,SIZEOF(szTime)-1,"%I64u.%06I64u",liTimeNow.QuadPart/perfCounterFreq,1000000*(liTimeNow.QuadPart%perfCounterFreq)/perfCounterFreq);
+ break;
+ default:
+ szTime[0]='\0';
+ break;
+ }
+ EnterCriticalSection(&logOptions.cs);
+ if(logOptions.showUser) lstrcatA(szTime," ");
+ szLine=(char*)alloca(lstrlenA(pszMsg)+lstrlenA(nlu->user.szSettingsModule)+5+lstrlenA(szTime));
+ if(logOptions.timeFormat || logOptions.showUser)
+ sprintf(szLine,"[%s%s] %s\n",szTime,logOptions.showUser?nlu->user.szSettingsModule:"",pszMsg);
+ else
+ sprintf(szLine,"%s\n",pszMsg);
+ if(logOptions.toOutputDebugString) OutputDebugStringA(szLine);
+ if(logOptions.toFile && logOptions.szFile[0]) {
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ if(!fp) {
+ CreateDirectoryTree(logOptions.szFile);
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ }
+ if(fp) {
+ fputs(szLine,fp);
+ fclose(fp);
+ }
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ SetLastError(dwOriginalLastError);
+ return 1;
+}
+
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags)
+{
+ int isText=1;
+ char szTitleLine[128];
+ char *szBuf;
+ int titleLineLen;
+ struct NetlibUser *nlu;
+
+ // This section checks a number of conditions and aborts
+ // the dump if the data should not be written to the log
+
+ // Check packet flags
+ if ((flags&MSG_PEEK) || (flags&MSG_NODUMP))
+ return;
+
+ // Check user's log settings
+ if (!(logOptions.toOutputDebugString ||
+ (logOptions.toFile && logOptions.szFile[0])))
+ return;
+ if ((sent && !logOptions.dumpSent) ||
+ (!sent && !logOptions.dumpRecv))
+ return;
+ if ((flags&MSG_DUMPPROXY) && !logOptions.dumpProxy)
+ return;
+
+
+ if (!logOptions.textDumps)
+ isText = 0;
+ else if (!(flags&MSG_DUMPASTEXT)) {
+ if (logOptions.autoDetectText) {
+ int i;
+ for(i = 0; i<len; i++)
+ if ((buf[i]<' ' && buf[i]!='\t' && buf[i]!='\r' && buf[i]!='\n') || buf[i]>=0x80)
+ {
+ isText = 0;
+ break;
+ }
+ }
+ else
+ isText = 0;
+ }
+
+ WaitForSingleObject(hConnectionHeaderMutex, INFINITE);
+ nlu = nlc ? nlc->nlu : NULL;
+ titleLineLen = mir_snprintf(szTitleLine,SIZEOF(szTitleLine), "(%p:%u) Data %s%s\n", nlc, nlc?nlc->s:0, sent?"sent":"received", flags & MSG_DUMPPROXY?" (proxy)":"");
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ // Text data
+ if (isText)
+ {
+ szBuf = (char*)alloca(titleLineLen + len + 1);
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ CopyMemory(szBuf + titleLineLen, (const char*)buf, len);
+ szBuf[titleLineLen + len] = '\0';
+ }
+ // Binary data
+ else
+ {
+ int line, col, colsInLine;
+ char *pszBuf;
+
+ szBuf = (char*)alloca(titleLineLen + ((len+16)>>4) * 76 + 1);
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ pszBuf = szBuf + titleLineLen;
+ for (line = 0; ; line += 16)
+ {
+ colsInLine = min(16, len - line);
+ pszBuf += wsprintfA(pszBuf, "%08X: ", line);
+ // Dump data as hex
+ for (col = 0; col < colsInLine; col++)
+ pszBuf += wsprintfA(pszBuf, "%02X%c", buf[line + col], ((col&3)==3 && col != 15)?'-':' ');
+ // Fill out last line with blanks
+ for ( ; col<16; col++)
+ {
+ lstrcpyA(pszBuf, " ");
+ pszBuf += 3;
+ }
+ *pszBuf++ = ' ';
+ for (col = 0; col < colsInLine; col++)
+ *pszBuf++ = buf[line+col]<' '?'.':(char)buf[line+col];
+ if (len-line<=16)
+ break;
+ *pszBuf++ = '\n'; // End each line with a break
+ }
+ *pszBuf = '\0';
+ }
+
+ NetlibLog((WPARAM)nlu,(LPARAM)szBuf);
+
+}
+
+void NetlibLogInit(void)
+{
+ DBVARIANT dbv;
+ LARGE_INTEGER li;
+
+ CreateServiceFunction(MS_NETLIB_LOG,NetlibLog);
+ QueryPerformanceFrequency(&li);
+ perfCounterFreq=li.QuadPart;
+ QueryPerformanceCounter(&li);
+ mirandaStartTime=li.QuadPart;
+ InitializeCriticalSection(&logOptions.cs);
+ logOptions.dumpRecv=DBGetContactSettingByte(NULL,"Netlib","DumpRecv",1);
+ logOptions.dumpSent=DBGetContactSettingByte(NULL,"Netlib","DumpSent",1);
+ logOptions.dumpProxy=DBGetContactSettingByte(NULL,"Netlib","DumpProxy",0);
+ logOptions.textDumps=DBGetContactSettingByte(NULL,"Netlib","TextDumps",1);
+ logOptions.autoDetectText=DBGetContactSettingByte(NULL,"Netlib","AutoDetectText",1);
+ logOptions.timeFormat=DBGetContactSettingByte(NULL,"Netlib","TimeFormat",TIMEFORMAT_HHMMSS);
+ logOptions.showUser=DBGetContactSettingByte(NULL,"Netlib","ShowUser",1);
+ logOptions.toOutputDebugString=DBGetContactSettingByte(NULL,"Netlib","ToOutputDebugString",0);
+ logOptions.toFile=DBGetContactSettingByte(NULL,"Netlib","ToFile",0);
+
+ if(!DBGetContactSettingTString(NULL, "Netlib", "File", &dbv)) {
+ logOptions.szFile = mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ if(logOptions.toFile && logOptions.szFile[0]) {
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("wt"));
+ if(fp) fclose(fp);
+ }
+ if(DBGetContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",0))
+ NetlibLogShowOptions();
+ if(!DBGetContactSetting(NULL,"Netlib","RunAtStart",&dbv)) {
+ STARTUPINFOA si={0};
+ PROCESS_INFORMATION pi;
+ si.cb=sizeof(si);
+ if(dbv.pszVal[0]) CreateProcessA(NULL,dbv.pszVal,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ DBFreeVariant(&dbv);
+ }
+}
+
+void NetlibLogShutdown(void)
+{
+ if(IsWindow(logOptions.hwndOpts)) DestroyWindow(logOptions.hwndOpts);
+ DeleteCriticalSection(&logOptions.cs);
+ if(logOptions.szFile) mir_free(logOptions.szFile);
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibopenconn.c b/miranda-wine/src/modules/netlib/netlibopenconn.c new file mode 100644 index 0000000..6d19e1c --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibopenconn.c @@ -0,0 +1,569 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+extern CRITICAL_SECTION csNetlibUser;
+extern DWORD g_LastConnectionTick; // protected by csNetlibUser
+
+//returns in network byte order
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost)
+{
+ DWORD ip;
+ HOSTENT *host;
+
+ ip=inet_addr(szHost);
+ if(ip!=INADDR_NONE) return ip;
+ host=gethostbyname(szHost);
+ if(host) return *(u_long *)host->h_addr_list[0];
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"gethostbyname",WSAGetLastError());
+ return 0;
+}
+
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set readfd;
+ TIMEVAL tv;
+
+ tv.tv_sec=dwTimeout/1000;
+ tv.tv_usec=(dwTimeout%1000)*1000;
+ FD_ZERO(&readfd);
+ FD_SET(s,&readfd);
+ switch(select(0,&readfd,0,0,&tv)) {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+static int WaitUntilWritable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set writefd;
+ TIMEVAL tv;
+
+ tv.tv_sec=dwTimeout/1000;
+ tv.tv_usec=(dwTimeout%1000)*1000;
+ FD_ZERO(&writefd);
+ FD_SET(s,&writefd);
+ switch(select(0,0,&writefd,0,&tv)) {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+static int NetlibInitSocks4Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //http://www.socks.nec.com/protocol/socks4.protocol and http://www.socks.nec.com/protocol/socks4a.protocol
+ PBYTE pInit;
+ int nUserLen,nHostLen,len;
+ BYTE reply[8];
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nHostLen=lstrlenA(nloc->szHost);
+ pInit=(PBYTE)mir_alloc(10+nUserLen+nHostLen);
+ pInit[0]=4; //SOCKS4
+ pInit[1]=1; //connect
+ *(PWORD)(pInit+2)=htons(nloc->wPort);
+ if(nlu->settings.szProxyAuthUser==NULL) pInit[8]=0;
+ else lstrcpyA(pInit+8,nlu->settings.szProxyAuthUser);
+ if(nlu->settings.dnsThroughProxy) {
+ if((*(PDWORD)(pInit+4)=inet_addr(nloc->szHost))==INADDR_NONE) {
+ *(PDWORD)(pInit+4)=0x01000000;
+ lstrcpyA(pInit+9+nUserLen,nloc->szHost);
+ len=10+nUserLen+nHostLen;
+ }
+ else len=9+nUserLen;
+ }
+ else {
+ *(PDWORD)(pInit+4)=DnsLookup(nlu,nloc->szHost);
+ if(*(PDWORD)(pInit+4)==0) {
+ mir_free(pInit);
+ return 0;
+ }
+ len=9+nUserLen;
+ }
+ if(NLSend(nlc,pInit,len,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+
+ if(!WaitUntilReadable(nlc->s,30000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,reply,SIZEOF(reply),MSG_DUMPPROXY);
+ if(len < sizeof(reply) || reply[1]!=90) {
+ if(len != SOCKET_ERROR) {
+ if (len < SIZEOF(reply)) SetLastError(ERROR_BAD_FORMAT);
+ else switch(reply[1]) {
+ case 91: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 92: SetLastError(ERROR_CONNECTION_UNAVAIL); break;
+ case 93: SetLastError(ERROR_INVALID_ACCESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ //connected
+ return 1;
+}
+
+static int NetlibInitSocks5Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc1928
+ int len;
+ BYTE buf[256];
+
+ buf[0]=5; //yep, socks5
+ buf[1]=1; //one auth method
+ buf[2]=nlu->settings.useProxyAuth?2:0;
+ if(NLSend(nlc,buf,3,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ return 0;
+ }
+
+ if(!WaitUntilReadable(nlc->s,10000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,2,MSG_DUMPPROXY); //confirmation of auth method
+ if(len<2 || (buf[1]!=0 && buf[1]!=2)) {
+ if(len!=SOCKET_ERROR) {
+ if(len<2) SetLastError(ERROR_BAD_FORMAT);
+ else SetLastError(ERROR_INVALID_ID_AUTHORITY);
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+
+ if(buf[1]==2) { //rfc1929
+ int nUserLen,nPassLen;
+ PBYTE pAuthBuf;
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nPassLen=lstrlenA(nlu->settings.szProxyAuthPassword);
+ pAuthBuf=(PBYTE)mir_alloc(3+nUserLen+nPassLen);
+ pAuthBuf[0]=1; //auth version
+ pAuthBuf[1]=nUserLen;
+ memcpy(pAuthBuf+2,nlu->settings.szProxyAuthUser,nUserLen);
+ pAuthBuf[2+nUserLen]=nPassLen;
+ memcpy(pAuthBuf+3+nUserLen,nlu->settings.szProxyAuthPassword,nPassLen);
+ if(NLSend(nlc,pAuthBuf,3+nUserLen+nPassLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pAuthBuf);
+ return 0;
+ }
+ mir_free(pAuthBuf);
+
+ if(!WaitUntilReadable(nlc->s,10000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,SIZEOF(buf),MSG_DUMPPROXY);
+ if(len<2 || buf[1]) {
+ if(len!=SOCKET_ERROR) {
+ if(len<2) SetLastError(ERROR_BAD_FORMAT);
+ else SetLastError(ERROR_ACCESS_DENIED);
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ }
+
+ { PBYTE pInit;
+ int nHostLen;
+ DWORD hostIP;
+
+ if(nlu->settings.dnsThroughProxy) {
+ if((hostIP=inet_addr(nloc->szHost))==INADDR_NONE)
+ nHostLen=lstrlenA(nloc->szHost)+1;
+ else nHostLen=4;
+ }
+ else {
+ if((hostIP=DnsLookup(nlu,nloc->szHost))==0)
+ return 0;
+ nHostLen=4;
+ }
+ pInit=(PBYTE)mir_alloc(6+nHostLen);
+ pInit[0]=5; //SOCKS5
+ pInit[1]=1; //connect
+ pInit[2]=0; //reserved
+ if(hostIP==INADDR_NONE) { //DNS lookup through proxy
+ pInit[3]=3;
+ pInit[4]=nHostLen-1;
+ memcpy(pInit+5,nloc->szHost,nHostLen-1);
+ }
+ else {
+ pInit[3]=1;
+ *(PDWORD)(pInit+4)=hostIP;
+ }
+ *(PWORD)(pInit+4+nHostLen)=htons(nloc->wPort);
+ if(NLSend(nlc,pInit,6+nHostLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+ }
+
+ if(!WaitUntilReadable(nlc->s,30000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,SIZEOF(buf),MSG_DUMPPROXY);
+ if(len<7 || buf[0]!=5 || buf[1]) {
+ if(len!=SOCKET_ERROR) {
+ if(len<7 || buf[0]!=5) SetLastError(ERROR_BAD_FORMAT);
+ else switch(buf[1]) {
+ case 1: SetLastError(ERROR_GEN_FAILURE); break;
+ case 2: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 3: SetLastError(WSAENETUNREACH); break;
+ case 4: SetLastError(WSAEHOSTUNREACH); break;
+ case 5: SetLastError(WSAECONNREFUSED); break;
+ case 6: SetLastError(WSAETIMEDOUT); break;
+ case 7: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); break;
+ case 8: SetLastError(ERROR_INVALID_ADDRESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ //connected
+ return 1;
+}
+
+static int NetlibInitHttpsConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc2817
+ NETLIBHTTPHEADER httpHeaders[3];
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply;
+ char szUrl[512];
+
+ memset(httpHeaders,0,sizeof(httpHeaders));
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.requestType=REQUEST_CONNECT;
+ nlhrSend.flags=NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER|NLHRF_HTTP11; + if(nlu->settings.dnsThroughProxy) {
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s:%u",nloc->szHost,nloc->wPort);
+ if(inet_addr(nloc->szHost)==INADDR_NONE) {
+ httpHeaders[0].szName="Host";
+ httpHeaders[0].szValue=szUrl;
+ nlhrSend.headersCount++;
+ }
+ }
+ else {
+ struct in_addr addr;
+ DWORD ip=DnsLookup(nlu,nloc->szHost);
+ if(ip==0) return 0;
+ addr.S_un.S_addr=ip;
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s:%u",inet_ntoa(addr),nloc->wPort);
+ }
+ nlhrSend.szUrl=szUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=0;
+ if(NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend)==SOCKET_ERROR)
+ return 0;
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return 0;
+ if(nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ Netlib_Logf(nlu,"%s %d: %s request failed (%u %s)",__FILE__,__LINE__,nlu->settings.proxyType==PROXYTYPE_HTTP?"HTTP":"HTTPS",nlhrReply->resultCode,nlhrReply->szResultDescr);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ //connected
+ return 1;
+}
+
+static void FreePartiallyInitedConnection(struct NetlibConnection *nlc)
+{
+ DWORD dwOriginalLastError=GetLastError();
+
+ if(nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->hInstSecurityDll) FreeLibrary(nlc->hInstSecurityDll);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ mir_free(nlc);
+ SetLastError(dwOriginalLastError);
+}
+
+#define PortInMask(mask,p) ((mask)[((p)&0xFFFF)>>3]&(1<<((p)&7)))
+
+static int my_connect(SOCKET s, const struct sockaddr * name, int namelen, NETLIBOPENCONNECTION * nloc)
+{
+ int rc=0;
+ unsigned int dwTimeout=( nloc->cbSize==sizeof(NETLIBOPENCONNECTION) && nloc->flags&NLOCF_V2 ) ? nloc->timeout : 0;
+ u_long notblocking=1;
+ TIMEVAL tv;
+ DWORD lasterr = 0;
+ int waitdiff;
+ // if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
+ if ( dwTimeout == 0 )
+ dwTimeout += 60;
+ // return the socket to non blocking
+ if ( ioctlsocket(s, FIONBIO, ¬blocking) != 0 ) {
+ return SOCKET_ERROR;
+ }
+ // this is for XP SP2 where there is a default connection attempt limit of 10/second
+ EnterCriticalSection(&csNetlibUser);
+ waitdiff=GetTickCount() - g_LastConnectionTick;
+ g_LastConnectionTick=GetTickCount();
+ LeaveCriticalSection(&csNetlibUser);
+ if ( waitdiff < 1000 ) {
+ // last connection was less than 1 second ago, wait 1.2 seconds
+ SleepEx(1200,TRUE);
+ }
+ // might of died in between the wait
+ if ( Miranda_Terminated() ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ // try a connect
+ if ( connect(s, name, namelen) == 0 ) {
+ goto unblock;
+ }
+ // didn't work, was it cos of nonblocking?
+ if ( WSAGetLastError() != WSAEWOULDBLOCK ) {
+ rc=SOCKET_ERROR;
+ lasterr=WSAGetLastError();
+ goto unblock;
+ }
+ // setup select()
+ tv.tv_sec=1;
+ tv.tv_usec=0;
+ for (;;) {
+ fd_set r, w, e;
+ FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
+ FD_SET(s, &r);
+ FD_SET(s, &w);
+ FD_SET(s, &e);
+ if ( (rc=select(0, &r, &w, &e, &tv)) == SOCKET_ERROR ) {
+ break;
+ }
+ if ( rc > 0 ) {
+ if ( FD_ISSET(s, &r) ) {
+ // connection was closed
+ rc=SOCKET_ERROR;
+ lasterr=WSAECONNRESET;
+ }
+ if ( FD_ISSET(s, &w) ) {
+ // connection was successful
+ rc=0;
+ }
+ if ( FD_ISSET(s, &e) ) {
+ // connection failed.
+ int len=sizeof(lasterr);
+ rc=SOCKET_ERROR;
+ getsockopt(s,SOL_SOCKET,SO_ERROR,(char*)&lasterr,&len);
+ }
+ goto unblock;
+ } else if ( Miranda_Terminated() ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ } else if ( nloc->cbSize==sizeof(NETLIBOPENCONNECTION) && nloc->flags&NLOCF_V2 && nloc->waitcallback != NULL
+ && nloc->waitcallback(&dwTimeout) == 0) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ if ( --dwTimeout == 0 ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ }
+unblock:
+ notblocking=0;
+ ioctlsocket(s, FIONBIO, ¬blocking);
+ SetLastError(lasterr);
+ return rc;
+}
+
+int NetlibOpenConnection(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBOPENCONNECTION *nloc=(NETLIBOPENCONNECTION*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibConnection *nlc;
+ SOCKADDR_IN sin;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_OUTGOING) || nloc==NULL
+ || !(nloc->cbSize==NETLIBOPENCONNECTION_V1_SIZE||nloc->cbSize==sizeof(NETLIBOPENCONNECTION)) || nloc->szHost==NULL || nloc->wPort==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+ nlc=(struct NetlibConnection*)mir_calloc(sizeof(struct NetlibConnection));
+ nlc->handleType=NLH_CONNECTION;
+ nlc->nlu=nlu;
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ if (nlu->settings.specifyOutgoingPorts && nlu->settings.szOutgoingPorts)
+ {
+ BYTE portsMask[0x2000];
+ int startPort,portNum,i,j,portsCount;
+
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=htonl(INADDR_ANY);
+ sin.sin_port=0;
+
+ portsCount=StringToPortsMask(nlu->settings.szOutgoingPorts,portsMask);
+ if (portsCount) {
+ startPort=rand() % portsCount;
+ for (i=0;i<0x02000;i++) {
+ if(portsMask[i]==0) continue;
+ if(portsMask[i]==0xFF && startPort>=8) {startPort-=8; continue;}
+ for(j=0;j<8;j++)
+ if(portsMask[i]&(1<<j))
+ if(startPort--==0) {
+ portNum=(i<<3)+j;
+ break;
+ }
+ if(startPort==-1) break;
+ } //for
+ if (i!=0x2000) {
+ startPort=portNum;
+ do {
+ sin.sin_port=htons((WORD)portNum);
+ if(bind(nlc->s,(SOCKADDR*)&sin,sizeof(sin))==0) break;
+ for(portNum++;!PortInMask(portsMask,portNum);portNum++)
+ if(portNum==0xFFFF) portNum=0;
+ } while (portNum!=startPort);
+ } //if
+ } //if
+ }
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ if(nlu->settings.useProxy && (nlu->settings.proxyType==PROXYTYPE_HTTP || nlu->settings.proxyType==PROXYTYPE_HTTPS) && nlu->settings.useProxyAuth && nlu->settings.useProxyAuthNtlm)
+ nlc->hInstSecurityDll=LoadLibraryA("security.dll");
+
+ nlc->sinProxy.sin_family=AF_INET;
+ if(nlu->settings.useProxy) {
+ nlc->sinProxy.sin_port=htons((short)nlu->settings.wProxyPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nlu->settings.szProxyServer);
+ }
+ else {
+ nlc->sinProxy.sin_port=htons((short)nloc->wPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nloc->szHost);
+ }
+ if(nlc->sinProxy.sin_addr.S_un.S_addr==0
+ || my_connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy), nloc)==SOCKET_ERROR) {
+ if(nlc->sinProxy.sin_addr.S_un.S_addr)
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+
+ if(nlu->settings.useProxy
+ && !(nloc->flags&NLOCF_HTTP
+ && (nlu->settings.proxyType==PROXYTYPE_HTTP || nlu->settings.proxyType==PROXYTYPE_HTTPS)))
+ {
+ if(!WaitUntilWritable(nlc->s,30000)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+
+ switch(nlu->settings.proxyType) {
+ case PROXYTYPE_SOCKS4:
+ if(!NetlibInitSocks4Connection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_SOCKS5:
+ if(!NetlibInitSocks5Connection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_HTTPS:
+ if(!NetlibInitHttpsConnection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_HTTP:
+ if(!(nlu->user.flags&NUF_HTTPGATEWAY)) {
+ //NLOCF_HTTP not specified and no HTTP gateway available: try HTTPS
+ if(!NetlibInitHttpsConnection(nlc,nlu,nloc)) {
+ //can't do HTTPS: try direct
+ if(nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ nlc->sinProxy.sin_family=AF_INET;
+ nlc->sinProxy.sin_port=htons((short)nloc->wPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nloc->szHost);
+ if(nlc->sinProxy.sin_addr.S_un.S_addr==0
+ || my_connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy), nloc)==SOCKET_ERROR) {
+ if(nlc->sinProxy.sin_addr.S_un.S_addr)
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ }
+ else if(!NetlibInitHttpConnection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ Netlib_Logf(nlu,"(%d) Connected to %s:%d",nlc->s,nloc->szHost,nloc->wPort);
+ return (int)nlc;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibopts.c b/miranda-wine/src/modules/netlib/netlibopts.c new file mode 100644 index 0000000..918b940 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibopts.c @@ -0,0 +1,516 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+extern struct NetlibUser **netlibUser;
+extern int netlibUserCount;
+extern CRITICAL_SECTION csNetlibUser;
+
+struct NetlibTempSettings {
+ DWORD flags;
+ char *szSettingsModule;
+ NETLIBUSERSETTINGS settings;
+} static *tempSettings;
+static int tempSettingsCount;
+
+static const UINT outgoingConnectionsControls[]={
+ IDC_STATIC12,
+ IDC_USEPROXY,
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYAUTHNTLM,
+ IDC_PROXYDNS,
+ IDC_SPECIFYPORTSO,
+ IDC_STATIC53,IDC_PORTSRANGEO,
+ IDC_STATIC54};
+static const UINT useProxyControls[]={
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYAUTHNTLM,
+ IDC_PROXYDNS};
+static const UINT specifyOPortsControls[]={
+ IDC_STATIC53,IDC_PORTSRANGEO,
+ IDC_STATIC54
+};
+static const UINT incomingConnectionsControls[]={
+ IDC_STATIC43,
+ IDC_SPECIFYPORTS,
+ IDC_STATIC51,IDC_PORTSRANGE,
+ IDC_STATIC52};
+static const UINT specifyPortsControls[]={
+ IDC_STATIC51,IDC_PORTSRANGE,
+ IDC_STATIC52};
+static const TCHAR* szProxyTypes[]={_T("<mixed>"),_T("SOCKS4"),_T("SOCKS5"),_T("HTTP"),_T("HTTPS")};
+static const WORD oftenProxyPorts[]={1080,1080,1080,8080,8080};
+
+#define M_REFRESHALL (WM_USER+100)
+#define M_REFRESHENABLING (WM_USER+101)
+
+static void ShowMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) ShowWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void EnableMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) EnableWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void AddProxyTypeItem(HWND hwndDlg,int type,int selectType)
+{
+ int i;
+ i=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_ADDSTRING,0,(LPARAM)(type==0?TranslateTS(szProxyTypes[type]):szProxyTypes[type]));
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_SETITEMDATA,i,type);
+ if(type==selectType) SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_SETCURSEL,i,0);
+}
+
+static void CopySettingsStruct(NETLIBUSERSETTINGS *dest,NETLIBUSERSETTINGS *source)
+{
+ *dest=*source;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+}
+
+static void CombineSettingsStrings(char **dest,char **source)
+{
+ if(*dest!=NULL && (*source==NULL || lstrcmpiA(*dest,*source))) {mir_free(*dest); *dest=NULL;}
+}
+
+static void CombineSettingsStructs(NETLIBUSERSETTINGS *dest,DWORD *destFlags,NETLIBUSERSETTINGS *source,DWORD sourceFlags)
+{
+ if(sourceFlags&NUF_OUTGOING) {
+ if(*destFlags&NUF_OUTGOING) {
+ if(dest->useProxy!=source->useProxy) dest->useProxy=2;
+ if(dest->proxyType!=source->proxyType) dest->proxyType=0;
+ CombineSettingsStrings(&dest->szProxyServer,&source->szProxyServer);
+ if(dest->wProxyPort!=source->wProxyPort) dest->wProxyPort=0;
+ if(dest->useProxyAuth!=source->useProxyAuth) dest->useProxyAuth=2;
+ CombineSettingsStrings(&dest->szProxyAuthUser,&source->szProxyAuthUser);
+ CombineSettingsStrings(&dest->szProxyAuthPassword,&source->szProxyAuthPassword);
+ if(dest->useProxyAuthNtlm!=source->useProxyAuthNtlm) dest->useProxyAuthNtlm=2;
+ if(dest->dnsThroughProxy!=source->dnsThroughProxy) dest->dnsThroughProxy=2;
+ if(dest->specifyOutgoingPorts!=source->specifyOutgoingPorts) dest->specifyOutgoingPorts=2;
+ CombineSettingsStrings(&dest->szOutgoingPorts,&source->szOutgoingPorts);
+ }
+ else {
+ dest->useProxy=source->useProxy;
+ dest->proxyType=source->proxyType;
+ dest->szProxyServer=source->szProxyServer;
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+ dest->wProxyPort=source->wProxyPort;
+ dest->useProxyAuth=source->useProxyAuth;
+ dest->szProxyAuthUser=source->szProxyAuthUser;
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ dest->szProxyAuthPassword=source->szProxyAuthPassword;
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ dest->useProxyAuthNtlm=source->useProxyAuthNtlm;
+ dest->dnsThroughProxy=source->dnsThroughProxy;
+ dest->specifyOutgoingPorts=source->specifyOutgoingPorts;
+ dest->szOutgoingPorts=source->szOutgoingPorts;
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ }
+ }
+ if(sourceFlags&NUF_INCOMING) {
+ if(*destFlags&NUF_INCOMING) {
+ if(dest->specifyIncomingPorts!=source->specifyIncomingPorts) dest->specifyIncomingPorts=2;
+ CombineSettingsStrings(&dest->szIncomingPorts,&source->szIncomingPorts);
+ }
+ else {
+ dest->specifyIncomingPorts=source->specifyIncomingPorts;
+ dest->szIncomingPorts=source->szIncomingPorts;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ }
+ }
+ if((*destFlags&NUF_NOHTTPSOPTION)!=(sourceFlags&NUF_NOHTTPSOPTION))
+ *destFlags=(*destFlags|sourceFlags)&~NUF_NOHTTPSOPTION;
+ else *destFlags|=sourceFlags;
+}
+
+static void ChangeSettingIntByCheckbox(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int newValue,i;
+
+ newValue=IsDlgButtonChecked(hwndDlg,ctrlId)!=BST_CHECKED;
+ CheckDlgButton(hwndDlg,ctrlId,newValue?BST_CHECKED:BST_UNCHECKED);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS))
+ *(int*)(((PBYTE)&tempSettings[i].settings)+memberOffset)=newValue;
+ }
+ else *(int*)(((PBYTE)&tempSettings[iUser].settings)+memberOffset)=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+}
+
+static void ChangeSettingStringByEdit(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int i,newValueLen;
+ char *szNewValue,**ppszNew;
+
+ newValueLen=GetWindowTextLength(GetDlgItem(hwndDlg,ctrlId));
+ szNewValue=(char*)mir_alloc(newValueLen+1);
+ GetDlgItemTextA(hwndDlg,ctrlId,szNewValue,newValueLen+1);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS)) {
+ ppszNew=(char**)(((PBYTE)&tempSettings[i].settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=mir_strdup(szNewValue);
+ }
+ mir_free(szNewValue);
+ }
+ else {
+ ppszNew=(char**)(((PBYTE)&tempSettings[iUser].settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=szNewValue;
+ }
+}
+
+static void WriteSettingsStructToDb(const char *szSettingsModule,NETLIBUSERSETTINGS *settings,DWORD flags)
+{
+ if(flags&NUF_OUTGOING) {
+ char szEncodedPassword[512];
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxy",(BYTE)settings->useProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLProxyType",(BYTE)settings->proxyType);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyServer",settings->szProxyServer?settings->szProxyServer:"");
+ DBWriteContactSettingWord(NULL,szSettingsModule,"NLProxyPort",(WORD)settings->wProxyPort);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuth",(BYTE)settings->useProxyAuth);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthUser",settings->szProxyAuthUser?settings->szProxyAuthUser:"");
+ lstrcpynA(szEncodedPassword,settings->szProxyAuthPassword?settings->szProxyAuthPassword:"",SIZEOF(szEncodedPassword));
+ CallService(MS_DB_CRYPT_ENCODESTRING,SIZEOF(szEncodedPassword),(LPARAM)szEncodedPassword);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthPassword",szEncodedPassword);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuthNtlm",(BYTE)settings->useProxyAuthNtlm);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLDnsThroughProxy",(BYTE)settings->dnsThroughProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyOutgoingPorts",(BYTE)settings->specifyOutgoingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLOutgoingPorts",settings->szOutgoingPorts?settings->szOutgoingPorts:"");
+ }
+ if(flags&NUF_INCOMING) {
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyIncomingPorts",(BYTE)settings->specifyIncomingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLIncomingPorts",settings->szIncomingPorts?settings->szIncomingPorts:"");
+ }
+}
+
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings)
+{
+ int iUser,i;
+ NETLIBUSERSETTINGS combinedSettings={0};
+ DWORD flags;
+
+ EnterCriticalSection(&csNetlibUser);
+ for(iUser=0;iUser<netlibUserCount;iUser++)
+ if(!lstrcmpA(szSettingsModule,netlibUser[iUser]->user.szSettingsModule)) break;
+ if(iUser==netlibUserCount) {
+ LeaveCriticalSection(&csNetlibUser);
+ return;
+ }
+ NetlibFreeUserSettingsStruct(&netlibUser[iUser]->settings); + CopySettingsStruct(&netlibUser[iUser]->settings,settings);
+ WriteSettingsStructToDb(netlibUser[iUser]->user.szSettingsModule,&netlibUser[iUser]->settings,netlibUser[iUser]->user.flags);
+ combinedSettings.cbSize=sizeof(combinedSettings);
+ for(i=0,flags=0;i<netlibUserCount;i++) {
+ if(netlibUser[iUser]->user.flags&NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&combinedSettings,&flags,&netlibUser[iUser]->settings,netlibUser[iUser]->user.flags);
+ }
+ if(combinedSettings.useProxy==2) combinedSettings.useProxy=0;
+ if(combinedSettings.proxyType==0) combinedSettings.proxyType=PROXYTYPE_SOCKS5;
+ if(combinedSettings.useProxyAuth==2) combinedSettings.useProxyAuth=0;
+ if(combinedSettings.useProxyAuthNtlm==2) combinedSettings.useProxyAuthNtlm=0;
+ if(combinedSettings.dnsThroughProxy==2) combinedSettings.dnsThroughProxy=1;
+ if(combinedSettings.specifyIncomingPorts==2) combinedSettings.specifyIncomingPorts=0;
+ WriteSettingsStructToDb("Netlib",&combinedSettings,flags);
+ NetlibFreeUserSettingsStruct(&combinedSettings);
+ LeaveCriticalSection(&csNetlibUser);
+}
+
+static BOOL CALLBACK DlgProcNetlibOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int iUser,iItem;
+
+ TranslateDialogDefault(hwndDlg);
+ iItem=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)TranslateT("<All connections>"));
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,(LPARAM)-1);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETCURSEL,iItem,0);
+ EnterCriticalSection(&csNetlibUser);
+ tempSettingsCount=netlibUserCount;
+ tempSettings=(struct NetlibTempSettings*)mir_alloc(sizeof(struct NetlibTempSettings)*tempSettingsCount);
+ for(iUser=0;iUser<netlibUserCount;iUser++) {
+ tempSettings[iUser].flags=netlibUser[iUser]->user.flags;
+ tempSettings[iUser].szSettingsModule=mir_strdup(netlibUser[iUser]->user.szSettingsModule);
+ CopySettingsStruct(&tempSettings[iUser].settings,&netlibUser[iUser]->settings);
+ if(netlibUser[iUser]->user.flags&NUF_NOOPTIONS) continue;
+ iItem=SendDlgItemMessageA(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)netlibUser[iUser]->user.szDescriptiveName);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,iUser);
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return TRUE;
+ }
+ case M_REFRESHALL:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ NETLIBUSERSETTINGS settings={0};
+ DWORD flags;
+
+ if(iUser==-1) {
+ int i;
+ settings.cbSize=sizeof(settings);
+ for(i=0,flags=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&settings,&flags,&tempSettings[i].settings,tempSettings[i].flags);
+ }
+ }
+ else {
+ NetlibFreeUserSettingsStruct(&settings); + CopySettingsStruct(&settings,&tempSettings[iUser].settings);
+ flags=tempSettings[iUser].flags;
+ }
+ ShowMultipleControls(hwndDlg,outgoingConnectionsControls,SIZEOF(outgoingConnectionsControls),flags&NUF_OUTGOING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_USEPROXY,settings.useProxy);
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_RESETCONTENT,0,0);
+ if(settings.proxyType==0) AddProxyTypeItem(hwndDlg,0,settings.proxyType);
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_SOCKS4,settings.proxyType);
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_SOCKS5,settings.proxyType);
+ if(flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTP,settings.proxyType);
+ if(!(flags&NUF_NOHTTPSOPTION)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTPS,settings.proxyType);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYHOST,settings.szProxyServer?settings.szProxyServer:"");
+ if(settings.wProxyPort) SetDlgItemInt(hwndDlg,IDC_PROXYPORT,settings.wProxyPort,FALSE);
+ else SetDlgItemTextA(hwndDlg,IDC_PROXYPORT,"");
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTH,settings.useProxyAuth);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYUSER,settings.szProxyAuthUser?settings.szProxyAuthUser:"");
+ SetDlgItemTextA(hwndDlg,IDC_PROXYPASS,settings.szProxyAuthPassword?settings.szProxyAuthPassword:"");
+ CheckDlgButton(hwndDlg,IDC_PROXYDNS,settings.dnsThroughProxy);
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTHNTLM,settings.useProxyAuthNtlm);
+
+ ShowMultipleControls(hwndDlg,incomingConnectionsControls,SIZEOF(incomingConnectionsControls),flags&NUF_INCOMING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTS,settings.specifyIncomingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGE,settings.szIncomingPorts?settings.szIncomingPorts:"");
+
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTSO,settings.specifyOutgoingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGEO,settings.szOutgoingPorts?settings.szOutgoingPorts:"");
+
+ NetlibFreeUserSettingsStruct(&settings);
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ break;
+ }
+ case M_REFRESHENABLING:
+ { int selectedProxyType;
+ TCHAR str[80];
+
+ selectedProxyType=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ wsprintf(str,TranslateT("(often %d)"),oftenProxyPorts[selectedProxyType]);
+ SetDlgItemText(hwndDlg,IDC_STOFTENPORT,str);
+ if(IsDlgButtonChecked(hwndDlg,IDC_USEPROXY)!=BST_UNCHECKED) {
+ int enableAuth=0,enableUser=0,enablePass=0,enableNtlm=0;
+ EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),TRUE);
+ if(selectedProxyType==0) {
+ int i;
+ for(i=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS || !(tempSettings[i].flags&NUF_OUTGOING) || !tempSettings[i].settings.useProxy) continue;
+ if(tempSettings[i].settings.proxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else {
+ enableAuth=1;
+ if(tempSettings[i].settings.useProxyAuth) {
+ if(tempSettings[i].settings.proxyType==PROXYTYPE_HTTP || tempSettings[i].settings.proxyType==PROXYTYPE_HTTPS) {
+ enableNtlm=1;
+ if(!tempSettings[i].settings.useProxyAuthNtlm) enableUser=enablePass=1;
+ }
+ else enableUser=enablePass=1;
+ }
+ }
+ }
+ }
+ else {
+ if(selectedProxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else {
+ enableAuth=1;
+ if(IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTH)!=BST_UNCHECKED) {
+ if(selectedProxyType==PROXYTYPE_HTTP || selectedProxyType==PROXYTYPE_HTTPS) {
+ enableNtlm=1;
+ if(IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTHNTLM)!=BST_CHECKED) enableUser=enablePass=1;
+ }
+ else enableUser=enablePass=1;
+ }
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTH),enableAuth);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC31),enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYUSER),enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC32),enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYPASS),enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTHNTLM),enableNtlm);
+ }
+ else EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),FALSE);
+ EnableMultipleControls(hwndDlg,specifyPortsControls,SIZEOF(specifyPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTS)!=BST_UNCHECKED);
+ EnableMultipleControls(hwndDlg,specifyOPortsControls,SIZEOF(specifyOPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTSO)!=BST_UNCHECKED);
+ break;
+ }
+ case WM_COMMAND:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ switch(LOWORD(wParam)) {
+ case IDC_NETLIBUSERS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return 0;
+ case IDC_LOGOPTIONS:
+ NetlibLogShowOptions();
+ return 0;
+ case IDC_PROXYTYPE:
+ if(HIWORD(wParam)!=CBN_SELCHANGE) return 0;
+ { int newValue,i;
+ newValue=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ if(iUser==-1) {
+ if(newValue==0) return 0;
+ for(i=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS) continue;
+ if(newValue==PROXYTYPE_HTTP && !(tempSettings[i].flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)))
+ tempSettings[i].settings.proxyType=PROXYTYPE_HTTPS;
+ else if(newValue==PROXYTYPE_HTTPS && tempSettings[i].flags&NUF_NOHTTPSOPTION)
+ tempSettings[i].settings.proxyType=PROXYTYPE_HTTP;
+ else tempSettings[i].settings.proxyType=newValue;
+ }
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ }
+ else {
+ tempSettings[iUser].settings.proxyType=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ }
+ }
+ break;
+ case IDC_USEPROXY:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxy));
+ break;
+ case IDC_PROXYAUTH:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuth));
+ break;
+ case IDC_PROXYAUTHNTLM:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuthNtlm));
+ break;
+ case IDC_PROXYDNS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,dnsThroughProxy));
+ break;
+ case IDC_SPECIFYPORTS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyIncomingPorts));
+ break;
+ case IDC_SPECIFYPORTSO:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyOutgoingPorts));
+ break;
+ case IDC_PROXYHOST:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyServer));
+ break;
+ case IDC_PROXYPORT:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ { int newValue,i;
+ newValue=GetDlgItemInt(hwndDlg,LOWORD(wParam),NULL,FALSE);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS))
+ tempSettings[i].settings.wProxyPort=newValue;
+ }
+ else tempSettings[iUser].settings.wProxyPort=newValue;
+ }
+ break;
+ case IDC_PROXYUSER:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthUser));
+ break;
+ case IDC_PROXYPASS:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthPassword));
+ break;
+ case IDC_PORTSRANGE:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szIncomingPorts));
+ break;
+ case IDC_PORTSRANGEO:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szOutgoingPorts));
+ break;
+ }
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RECONNECTREQD),SW_SHOW);
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ break;
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { int iUser;
+ for(iUser=0;iUser<tempSettingsCount;iUser++)
+ NetlibSaveUserSettingsStruct(tempSettings[iUser].szSettingsModule,&tempSettings[iUser].settings);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int iUser;
+ for(iUser=0;iUser<tempSettingsCount;iUser++) {
+ mir_free(tempSettings[iUser].szSettingsModule);
+ NetlibFreeUserSettingsStruct(&tempSettings[iUser].settings);
+ }
+ mir_free(tempSettings);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_LOGOPTIONS};
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ int i,optionsCount;
+
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0,optionsCount=0;i<netlibUserCount;i++)
+ if(!(netlibUser[i]->user.flags&NUF_NOOPTIONS)) optionsCount++;
+ LeaveCriticalSection(&csNetlibUser);
+ if ( optionsCount == 0 )
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_NETLIB);
+ odp.pszTitle = "Network";
+ odp.pfnDlgProc = DlgProcNetlibOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibpktrecver.c b/miranda-wine/src/modules/netlib/netlibpktrecver.c new file mode 100644 index 0000000..7bc6eb4 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibpktrecver.c @@ -0,0 +1,85 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+int NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ struct NetlibPacketRecver *nlpr;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || lParam==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr=(struct NetlibPacketRecver*)mir_calloc(sizeof(struct NetlibPacketRecver));
+ if(nlpr==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr->handleType=NLH_PACKETRECVER;
+ nlpr->nlc=nlc;
+ nlpr->packetRecver.cbSize=sizeof(nlpr->packetRecver);
+ nlpr->packetRecver.bufferSize=lParam;
+ nlpr->packetRecver.buffer=(PBYTE)mir_alloc(nlpr->packetRecver.bufferSize);
+ nlpr->packetRecver.bytesUsed=0;
+ nlpr->packetRecver.bytesAvailable=0;
+ return (int)nlpr;
+}
+
+int NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ NETLIBPACKETRECVER *nlprParam=(NETLIBPACKETRECVER*)lParam;
+ int recvResult;
+
+ if(GetNetlibHandleType(nlpr)!=NLH_PACKETRECVER || nlprParam==NULL || nlprParam->cbSize!=sizeof(NETLIBPACKETRECVER) || nlprParam->bytesUsed>nlpr->packetRecver.bytesAvailable) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if (Miranda_Terminated()) { /* HACK: Lame, break while loops of protocols that can't kill their while loops, (cough, ICQ, cough) */
+ SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ nlpr->packetRecver.dwTimeout=nlprParam->dwTimeout;
+ if(nlprParam->bytesUsed==0) {
+ if(nlpr->packetRecver.bytesAvailable==nlpr->packetRecver.bufferSize) {
+ nlpr->packetRecver.bytesAvailable=0;
+ Netlib_Logf(nlpr->nlc->nlu,"Packet recver: packet overflowed buffer, ditching");
+ }
+ }
+ else {
+ MoveMemory(nlpr->packetRecver.buffer,nlpr->packetRecver.buffer+nlprParam->bytesUsed,nlpr->packetRecver.bytesAvailable-nlprParam->bytesUsed);
+ nlpr->packetRecver.bytesAvailable-=nlprParam->bytesUsed;
+ }
+ if(nlprParam->dwTimeout!=INFINITE) {
+ if(!WaitUntilReadable(nlpr->nlc->s,nlprParam->dwTimeout)) {
+ *nlprParam=nlpr->packetRecver;
+ return SOCKET_ERROR;
+ }
+ }
+ recvResult=NLRecv(nlpr->nlc,nlpr->packetRecver.buffer+nlpr->packetRecver.bytesAvailable,nlpr->packetRecver.bufferSize-nlpr->packetRecver.bytesAvailable,0);
+ if(recvResult>0) nlpr->packetRecver.bytesAvailable+=recvResult;
+ *nlprParam=nlpr->packetRecver;
+ return recvResult;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibsock.c b/miranda-wine/src/modules/netlib/netlibsock.c new file mode 100644 index 0000000..acedd8e --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibsock.c @@ -0,0 +1,166 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+extern CRITICAL_SECTION csNetlibCloseHandle;
+extern HANDLE hConnectionHeaderMutex;
+
+int NetlibSend(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ int result;
+
+ if(nlb==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_SEND)) return SOCKET_ERROR;
+ if(nlc->usingHttpGateway && !(nlb->flags&MSG_RAW)) {
+ if(!(nlb->flags&MSG_NOHTTPGATEWAYWRAP) && nlc->nlu->user.pfnHttpGatewayWrapSend) {
+ NetlibDumpData(nlc,nlb->buf,nlb->len,1,nlb->flags);
+ result=nlc->nlu->user.pfnHttpGatewayWrapSend((HANDLE)nlc,nlb->buf,nlb->len,nlb->flags|MSG_NOHTTPGATEWAYWRAP,NetlibSend);
+ }
+ else result=NetlibHttpGatewayPost(nlc,nlb->buf,nlb->len,nlb->flags);
+ }
+ else {
+ NetlibDumpData(nlc,nlb->buf,nlb->len,1,nlb->flags);
+ result=send(nlc->s,nlb->buf,nlb->len,nlb->flags&0xFFFF);
+ }
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return result;
+}
+
+int NetlibRecv(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ int recvResult;
+
+ if(nlb==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV)) return SOCKET_ERROR;
+ if(nlc->usingHttpGateway && !(nlb->flags&MSG_RAW))
+ recvResult=NetlibHttpGatewayRecv(nlc,nlb->buf,nlb->len,nlb->flags);
+ else
+ recvResult=recv(nlc->s,nlb->buf,nlb->len,nlb->flags&0xFFFF);
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ if(recvResult<=0) return recvResult;
+ NetlibDumpData(nlc,nlb->buf,recvResult,0,nlb->flags);
+ return recvResult;
+}
+
+static int ConnectionListToSocketList(HANDLE *hConns,fd_set *fd)
+{
+ struct NetlibConnection *nlcCheck;
+ int i;
+
+ FD_ZERO(fd);
+ for(i=0;hConns[i] && hConns[i]!=INVALID_HANDLE_VALUE && i<FD_SETSIZE;i++) {
+ nlcCheck=(struct NetlibConnection*)hConns[i];
+ if(nlcCheck->handleType!=NLH_CONNECTION && nlcCheck->handleType!=NLH_BOUNDPORT) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ FD_SET(nlcCheck->s,fd);
+ }
+ return 1;
+}
+
+int NetlibSelect(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECT *nls=(NETLIBSELECT*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+
+ if(nls==NULL || nls->cbSize!=sizeof(NETLIBSELECT)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(!ConnectionListToSocketList(nls->hReadConns,&readfd)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+}
+
+int NetlibSelectEx(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECTEX *nls=(NETLIBSELECTEX*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+ int rc=SOCKET_ERROR;
+ int j;
+ struct NetlibConnection *conn=NULL;
+
+ if(nls==NULL || nls->cbSize!=sizeof(NETLIBSELECTEX)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(!ConnectionListToSocketList(nls->hReadConns,&readfd)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ rc=select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ /* go thru each passed HCONN array and grab its socket handle, then give it to FD_ISSET()
+ to see if an event happened for that socket, if it has it will be returned as TRUE (otherwise not)
+ This happens for read/write/except */
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hReadConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+
+ if (conn->usingHttpGateway && conn->nlhpi.szHttpGetUrl == NULL && conn->dataBuffer == NULL)
+ nls->hReadStatus[j] = (conn->pHttpProxyPacketQueue != NULL);
+ else
+ nls->hReadStatus[j] = FD_ISSET(conn->s,&readfd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hWriteConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hWriteStatus[j] = FD_ISSET(conn->s,&writefd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hExceptConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hExceptStatus[j] = FD_ISSET(conn->s,&exceptfd);
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return rc;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibupnp.c b/miranda-wine/src/modules/netlib/netlibupnp.c new file mode 100644 index 0000000..c91de6c --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibupnp.c @@ -0,0 +1,495 @@ +/* +UPnP plugin for Miranda IM +Copyright (C) 2006 borkra + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* Main file for the Weather Protocol, includes loading, unloading, + upgrading, support for plugin uninsaller, and anything that doesn't + belong to any other file. +*/ + +#include "commonheaders.h" +#include "netlib.h" + +static char search_request_msg[] = + "M-SEARCH * HTTP/1.1\r\n" + "MX: 2\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "ST: urn:schemas-upnp-org:service:%s\r\n" + "\r\n"; + +static char xml_get_hdr[] = + "GET %s HTTP/1.1\r\n" + "Connection: close\r\n" + "Host: %s:%s\r\n\r\n"; + +static char soap_post_hdr[] = + "POST %s HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CONTENT-LENGTH: %u\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" + "SOAPACTION: \"%s#%s\"\r\n\r\n" + "%s"; + +static char soap_post_hdr_m[] = + "M-POST %s URL HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CONTENT-LENGTH: %u\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" + "MAN: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n" + "01-SOAPACTION: \"%s#%s\"\r\n\r\n" + "%s"; + +static char search_device[] = + "<serviceType>%s</serviceType>"; + +static char soap_action[] = + "<s:Envelope\r\n" + " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n" + " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" + " <s:Body>\r\n" + " <u:%s xmlns:u=\"%s\">\r\n" + "%s" + " </u:%s>\r\n" + " </s:Body>\r\n" + "</s:Envelope>\r\n"; + +static char add_port_mapping[] = + " <NewRemoteHost></NewRemoteHost>\r\n" + " <NewExternalPort>%i</NewExternalPort>\r\n" + " <NewProtocol>%s</NewProtocol>\r\n" + " <NewInternalPort>%i</NewInternalPort>\r\n" + " <NewInternalClient>%s</NewInternalClient>\r\n" + " <NewEnabled>1</NewEnabled>\r\n" + " <NewPortMappingDescription>Miranda</NewPortMappingDescription>\r\n" + " <NewLeaseDuration>0</NewLeaseDuration>\r\n"; + +static char delete_port_mapping[] = + " <NewRemoteHost></NewRemoteHost>\r\n" + " <NewExternalPort>%i</NewExternalPort>\r\n" + " <NewProtocol>%s</NewProtocol>\r\n"; + +static char default_http_port[] = "80"; + +static BOOL gatewayFound = FALSE; +static SOCKADDR_IN locIP; +static time_t lastDiscTime = 0; +static int expireTime = 120; + +static char szCtlUrl[256], szDev[256]; + + +static BOOL txtParseParam(char* szData, char* presearch, + char* start, char* finish, char* param, int size) +{ + char *cp, *cp1; + int len; + + *param = 0; + + if (presearch != NULL) + { + cp1 = strstr(szData, presearch); + if (cp1 == NULL) return FALSE; + } + else + cp1 = szData; + + cp = strstr(cp1, start); + if (cp == NULL) return FALSE; + cp += strlen(start); + while (*cp == ' ') ++cp; + + cp1 = strstr(cp, finish); + if (cp1 == NULL) return FALSE; + while (*(cp1-1) == ' ' && cp1 > cp) --cp1; + + len = min(cp1 - cp, size); + strncpy(param, cp, len); + param[len] = 0; + + return TRUE; +} + +static LongLog(char* szData) +{ + char* buf = szData; + int sz = strlen(szData); + + while ( sz > 1000) + { + char* nbuf = buf + 1000; + char t = *nbuf; + *nbuf = 0; + Netlib_Logf(NULL, buf); + *nbuf = t; + buf = nbuf; + sz -= 1000; + } + Netlib_Logf(NULL, buf); +} + + +static void discoverUPnP(char* szUrl, int sizeUrl) +{ + char* buf; + int buflen; + unsigned i, j, nip = 0; + char* szData = NULL; + unsigned* ips = NULL; + + static const unsigned any = INADDR_ANY; + fd_set readfd; + TIMEVAL tv = { 1, 0 }; + + char hostname[256]; + PHOSTENT he; + + SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + SOCKADDR_IN enetaddr; + enetaddr.sin_family = AF_INET; + enetaddr.sin_port = htons(1900); + enetaddr.sin_addr.s_addr = inet_addr("239.255.255.250"); + + FD_ZERO(&readfd); + FD_SET(sock, &readfd); + + szUrl[0] = 0; + + gethostname( hostname, sizeof( hostname )); + he = gethostbyname( hostname ); + + if (he) + { + while(he->h_addr_list[nip]) ++nip; + + ips = mir_alloc(nip * sizeof(unsigned)); + + for (j=0; j<nip; ++j) + ips[j] = *(unsigned*)he->h_addr_list[j]; + } + + buf = mir_alloc(1500); + + for(i = 3; --i && szUrl[0] == 0;) + { + for (j=0; j<nip; ++j) + { + if (ips) + setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ips[j], sizeof(unsigned)); + + buflen = mir_snprintf(buf, 1500, search_request_msg, "WANIPConnection:1"); + sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); + LongLog(buf); + + buflen = mir_snprintf(buf, 1500, search_request_msg, "WANPPPConnection:1"); + sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); + LongLog(buf); + } + + while (select(0, &readfd, NULL, NULL, &tv) == 1) + { + buflen = recv(sock, buf, 1500, 0); + if (buflen != SOCKET_ERROR) + { + buf[buflen] = 0; + LongLog(buf); + + if (txtParseParam(buf, NULL, "LOCATION:", "\r", szUrl, sizeUrl) || + txtParseParam(buf, NULL, "Location:", "\r", szUrl, sizeUrl)) + { + char age[30]; + txtParseParam(szUrl, NULL, "http://", "/", szCtlUrl, sizeof(szCtlUrl)); + txtParseParam(buf, NULL, "ST:", "\r", szDev, sizeof(szDev)); + txtParseParam(buf, "max-age", "=", "\r", age, sizeof(age)); + expireTime = atoi(age); + break; + } + } + } + } + + mir_free(buf); + mir_free(ips); + setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&any, sizeof(unsigned)); + closesocket(sock); +} + + +static int httpTransact (char* szUrl, char* szResult, int resSize, char* szActionName) +{ + // Parse URL + char *ppath, *phost, *pport, *szHost, *szPort, szRes[6]; + int sz, res = 0; + + char* szPostHdr = soap_post_hdr; + char* szData = mir_alloc(4096); + char* szReq = szActionName ? mir_strdup(szResult) : NULL; + szResult[0] = 0; + + + phost = strstr(szUrl,"://"); + if (phost == NULL) phost = szUrl; + else phost += 3; + + ppath = strchr(phost,'/'); + if (ppath == NULL) ppath = phost + strlen(phost); + + pport = strchr(phost,':'); + if (pport == NULL) pport = ppath; + + sz = pport - phost + 1; + szHost = _alloca(sz); + strncpy(szHost, phost, sz); + szHost[sz-1] = 0; + + sz = ppath - pport; + if (sz > 1) + { + szPort = _alloca(sz); + strncpy(szPort, pport+1, sz); + szPort[sz-1] = 0; + } + else + szPort = default_http_port; + + for (;;) + { + if (szActionName == NULL) + sz = mir_snprintf (szData, 4096, + xml_get_hdr, ppath, szHost, szPort); + else + { + char szData1[1024]; + + sz = mir_snprintf (szData1, sizeof(szData1), + soap_action, szActionName, szDev, szReq, szActionName); + + sz = mir_snprintf (szData, 4096, + szPostHdr, ppath, szHost, szPort, + sz, szDev, szActionName, szData1); + } + + { + static TIMEVAL tv = { 3, 0 }; + static unsigned ttl = 4; + fd_set readfd; + + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + SOCKADDR_IN enetaddr; + enetaddr.sin_family = AF_INET; + enetaddr.sin_port = htons((unsigned short)atol(szPort)); + enetaddr.sin_addr.s_addr = inet_addr(szHost); + + if (enetaddr.sin_addr.s_addr == INADDR_NONE) + { + PHOSTENT he = gethostbyname(szHost); + if (he) + enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0]; + } + + Netlib_Logf(NULL, "UPnP HTTP connection Host: %s Port: %s\n", szHost, szPort); + + FD_ZERO(&readfd); + FD_SET(sock, &readfd); + + setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned)); + + if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == 0) + { + if (send( sock, szData, sz, 0 ) != SOCKET_ERROR) + { + LongLog(szData); + sz = 0; + for(;;) + { + int bytesRecv; + char *hdrend; + + if (select(0, &readfd, NULL, NULL, &tv) != 1) + { + Netlib_Logf(NULL, "UPnP select timeout"); + break; + } + + bytesRecv = recv( sock, &szResult[sz], resSize-sz, 0 ); + if ( bytesRecv == 0 || bytesRecv == SOCKET_ERROR) + break; + else + sz += bytesRecv; + + if (sz >= (resSize-1)) + { + szResult[resSize-1] = 0; + break; + } + else + szResult[sz] = 0; + + hdrend = strstr(szResult, "\r\n\r\n"); + if (hdrend != NULL && + (txtParseParam(szResult, NULL, "Content-Length:", "\r", szRes, sizeof(szRes)) || + txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\r", szRes, sizeof(szRes)))) + { + int pktsz = atol(szRes) + (hdrend - szResult + 4); + if (sz >= pktsz) + { + szResult[pktsz] = 0; + break; + } + } + + } + LongLog(szResult); + } + else + Netlib_Logf(NULL, "UPnP send failed %d", WSAGetLastError()); + } + else + Netlib_Logf(NULL, "UPnP connect failed %d", WSAGetLastError()); + + if (szActionName == NULL) + { + int len = sizeof(locIP); + getsockname(sock, (SOCKADDR*)&locIP, &len); + } + + shutdown(sock, 2); + closesocket(sock); + } + txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes)); + res = atol(szRes); + if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr) + szPostHdr = soap_post_hdr_m; + else + break; + } + + mir_free(szData); + mir_free(szReq); + return res; +} + + +static void findUPnPGateway(void) +{ + time_t curTime = time(NULL); + + if ((curTime - lastDiscTime) >= expireTime) + { + char szUrl[256]; + char* szData = mir_alloc(8192); + + lastDiscTime = curTime; + + discoverUPnP(szUrl, sizeof(szUrl)); + gatewayFound = szUrl[0] != 0 && httpTransact(szUrl, szData, 8192, NULL) == 200; + + if (gatewayFound) + { + char szTemp[256]; + size_t ctlLen; + + txtParseParam(szData, NULL, "<URLBase>", "</URLBase>", szTemp, sizeof(szTemp)); + if (szTemp[0] != 0) strcpy(szCtlUrl, szTemp); + ctlLen = strlen(szCtlUrl); + if (ctlLen > 0 && szCtlUrl[ctlLen-1] == '/') + szCtlUrl[--ctlLen] = 0; + + mir_snprintf(szTemp, sizeof(szTemp), search_device, szDev); + txtParseParam(szData, szTemp, "<controlURL>", "</controlURL>", szUrl, sizeof(szUrl)); + switch (szUrl[0]) + { + case 0: + gatewayFound = FALSE; + break; + + case '/': + strncat(szCtlUrl, szUrl, sizeof(szCtlUrl) - ctlLen); + szCtlUrl[sizeof(szCtlUrl)-1] = 0; + break; + + default: + strncpy(szCtlUrl, szUrl, sizeof(szCtlUrl)); + szCtlUrl[sizeof(szCtlUrl)-1] = 0; + break; + } + } + Netlib_Logf(NULL, "UPnP Gateway detected %d, Control URL: %s\n", gatewayFound, szCtlUrl); + mir_free(szData); + } +} + + +BOOL NetlibUPnPAddPortMapping(WORD intport, char *proto, + WORD *extport, DWORD *extip, BOOL search) +{ + int res = 0; + + findUPnPGateway(); + + if (gatewayFound) + { + char* szData = mir_alloc(4096); + char szExtIP[30]; + + *extport = intport - 1; + *extip = ntohl(locIP.sin_addr.S_un.S_addr); + + do { + ++*extport; + mir_snprintf(szData, 4096, add_port_mapping, + *extport, proto, intport, inet_ntoa(locIP.sin_addr)); + res = httpTransact(szCtlUrl, szData, 4096, "AddPortMapping"); + } while (search && res == 718); + + if (res == 200) + { + szData[0] = 0; + res = httpTransact(szCtlUrl, szData, 4096, "GetExternalIPAddress"); + if (res == 200 && txtParseParam(szData, "<NewExternalIPAddress", ">", "<", szExtIP, sizeof(szExtIP))) + *extip = ntohl(inet_addr(szExtIP)); + } + mir_free(szData); + } + + return res == 200; +} + + +void NetlibUPnPDeletePortMapping(WORD extport, char* proto) +{ + if (extport != 0) + { +// findUPnPGateway(); + + if (gatewayFound) + { + char* szData = mir_alloc(4096); + + mir_snprintf(szData, 4096, delete_port_mapping, + extport, proto); + httpTransact(szCtlUrl, szData, 4096, "DeletePortMapping"); + + mir_free(szData); + } + } +} + |