summaryrefslogtreecommitdiff
path: root/protocols/MSN/src/msn_ftold.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/MSN/src/msn_ftold.cpp')
-rw-r--r--protocols/MSN/src/msn_ftold.cpp395
1 files changed, 395 insertions, 0 deletions
diff --git a/protocols/MSN/src/msn_ftold.cpp b/protocols/MSN/src/msn_ftold.cpp
new file mode 100644
index 0000000000..db1ba3de66
--- /dev/null
+++ b/protocols/MSN/src/msn_ftold.cpp
@@ -0,0 +1,395 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+
+Copyright (c) 2012-2014 Miranda NG Team
+Copyright (c) 2006-2012 Boris Krasnovskiy.
+Copyright (c) 2003-2005 George Hazan.
+Copyright (c) 2002-2003 Richard Hughes (original version).
+
+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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "msn_global.h"
+#include "msn_proto.h"
+
+
+void CMsnProto::msnftp_sendAcceptReject(filetransfer *ft, bool acc)
+{
+ ThreadData* thread = MSN_GetThreadByContact(ft->p2p_dest);
+ if (thread == NULL) return;
+
+ if (acc)
+ {
+ thread->sendPacket("MSG",
+ "U %d\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Launch-Application: FALSE\r\n"
+ "Request-Data: IP-Address:\r\n\r\n",
+ 172+4+strlen(ft->szInvcookie), ft->szInvcookie);
+ }
+ else
+ {
+ thread->sendPacket("MSG",
+ "U %d\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: CANCEL\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Cancel-Code: REJECT\r\n\r\n",
+ 172-33+4+strlen(ft->szInvcookie), ft->szInvcookie);
+ }
+}
+
+void CMsnProto::msnftp_invite(filetransfer *ft)
+{
+ bool isOffline;
+ ThreadData* thread = MSN_StartSB(ft->p2p_dest, isOffline);
+ if (isOffline) return;
+ if (thread != NULL) thread->mMsnFtp = ft;
+
+ TCHAR* pszFiles = _tcsrchr(ft->std.ptszFiles[0], '\\');
+ if (pszFiles)
+ pszFiles++;
+ else
+ pszFiles = *ft->std.ptszFiles;
+
+ char msg[1024];
+ mir_snprintf(msg, SIZEOF(msg),
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Application-Name: File Transfer\r\n"
+ "Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n"
+ "Invitation-Command: INVITE\r\n"
+ "Invitation-Cookie: %i\r\n"
+ "Application-File: %s\r\n"
+ "Application-FileSize: %I64u\r\n\r\n",
+ MSN_GenRandom(), UTF8(pszFiles), ft->std.currentFileSize);
+
+ if (thread == NULL)
+ MsgQueue_Add(ft->p2p_dest, 'S', msg, -1, ft);
+ else
+ thread->sendMessage('S', NULL, NETID_MSN, msg, MSG_DISABLE_HDR);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN File Transfer Protocol commands processing
+
+int CMsnProto::MSN_HandleMSNFTP(ThreadData *info, char *cmdString)
+{
+ char* params = "";
+ filetransfer* ft = info->mMsnFtp;
+
+ if (cmdString[3])
+ params = cmdString+4;
+
+ switch((*(PDWORD)cmdString&0x00FFFFFF)|0x20000000)
+ {
+ case ' EYB': //********* BYE
+ {
+ ft->complete();
+ return 1;
+ }
+ case ' LIF': //********* FIL
+ {
+ char filesize[30];
+ if (sscanf(params, "%s", filesize) < 1)
+ goto LBL_InvalidCommand;
+
+ info->mCaller = 1;
+ info->send("TFR\r\n", 5);
+ break;
+ }
+ case ' RFT': //********* TFR
+ {
+ char* sendpacket = (char*)alloca(2048);
+ filetransfer* ft = info->mMsnFtp;
+
+ info->mCaller = 3;
+
+ while (ft->std.currentFileProgress < ft->std.currentFileSize)
+ {
+ if (ft->bCanceled)
+ {
+ sendpacket[0] = 0x01;
+ sendpacket[1] = 0x00;
+ sendpacket[2] = 0x00;
+ info->send(sendpacket, 3);
+ return 0;
+ }
+
+ int wPlace = 0;
+ sendpacket[wPlace++] = 0x00;
+ unsigned __int64 packetLen = ft->std.currentFileSize - ft->std.currentFileProgress;
+ if (packetLen > 2045) packetLen = 2045;
+
+ sendpacket[wPlace++] = (char)(packetLen & 0x00ff);
+ sendpacket[wPlace++] = (char)((packetLen & 0xff00) >> 8);
+ _read(ft->fileId, &sendpacket[wPlace], packetLen);
+
+ info->send(&sendpacket[0], packetLen+3);
+
+ ft->std.totalProgress += packetLen;
+ ft->std.currentFileProgress += packetLen;
+
+ ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
+ }
+
+ ft->complete();
+ break;
+ }
+ case ' RSU': //********* USR
+ {
+ char email[130],authcookie[14];
+ if (sscanf(params,"%129s %13s",email,authcookie) < 2)
+ {
+ debugLogA("Invalid USR OK command, ignoring");
+ break;
+ }
+
+ char tCommand[30];
+ mir_snprintf(tCommand, sizeof(tCommand), "FIL %i\r\n", info->mMsnFtp->std.totalBytes);
+ info->send(tCommand, strlen(tCommand));
+ break;
+ }
+ case ' REV': //********* VER
+ {
+ char protocol1[7];
+ if (sscanf(params, "%6s", protocol1) < 1)
+ {
+LBL_InvalidCommand:
+ debugLogA("Invalid %.3s command, ignoring", cmdString);
+ break;
+ }
+
+ if (strcmp(protocol1, "MSNFTP") != 0)
+ {
+ int tempInt;
+ int tFieldCount = sscanf(params, "%d %6s", &tempInt, protocol1);
+ if (tFieldCount != 2 || strcmp(protocol1, "MSNFTP") != 0)
+ {
+ debugLogA("Another side requested the unknown protocol (%s), closing thread", params);
+ return 1;
+ }
+ }
+
+ if (info->mCaller == 0) //receive
+ {
+ char tCommand[MSN_MAX_EMAIL_LEN + 50];
+ mir_snprintf(tCommand, sizeof(tCommand), "USR %s %s\r\n", MyOptions.szEmail, info->mCookie);
+ info->send(tCommand, strlen(tCommand));
+ }
+ else if (info->mCaller == 2) //send
+ {
+ static const char sttCommand[] = "VER MSNFTP\r\n";
+ info->send(sttCommand, strlen(sttCommand));
+ }
+ break;
+ }
+ default: // receiving file
+ {
+ HReadBuffer tBuf(info, int(cmdString - info->mData));
+
+ for (;;)
+ {
+ if (ft->bCanceled)
+ { info->send("CCL\r\n", 5);
+ ft->close();
+ return 1;
+ }
+
+ BYTE* p = tBuf.surelyRead(3);
+ if (p == NULL)
+ {
+LBL_Error:
+ ft->close();
+ MSN_ShowError("file transfer is canceled by remote host");
+ return 1;
+ }
+
+ BYTE tIsTransitionFinished = *p++;
+ WORD dataLen = *p++;
+ dataLen |= (*p++ << 8);
+
+ if (tIsTransitionFinished)
+ {
+LBL_Success:
+ static const char sttCommand[] = "BYE 16777989\r\n";
+ info->send(sttCommand, strlen(sttCommand));
+ return 1;
+ }
+
+ p = tBuf.surelyRead(dataLen);
+ if (p == NULL)
+ goto LBL_Error;
+
+ _write(ft->fileId, p, dataLen);
+ ft->std.totalProgress += dataLen;
+ ft->std.currentFileProgress += dataLen;
+
+ ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
+
+ if (ft->std.currentFileProgress == ft->std.totalBytes)
+ {
+ ft->complete();
+ goto LBL_Success;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// ft_startFileSend - sends a file using the old f/t protocol
+
+void __cdecl CMsnProto::msnftp_sendFileThread(void* arg)
+{
+ ThreadData* info = (ThreadData*)arg;
+
+ debugLogA("Waiting for an incoming connection to '%s'...", info->mServer);
+
+ switch(WaitForSingleObject(info->hWaitEvent, 60000))
+ {
+ case WAIT_TIMEOUT:
+ case WAIT_FAILED:
+ debugLogA("Incoming connection timed out, closing file transfer");
+ return;
+ }
+
+ info->mBytesInData = 0;
+
+ for (;;)
+ {
+ int recvResult = info->recv(info->mData+info->mBytesInData, 1000 - info->mBytesInData);
+ if (recvResult == SOCKET_ERROR || !recvResult)
+ break;
+
+ info->mBytesInData += recvResult;
+
+ //pull off each line for parsing
+ if (info->mCaller == 3 && info->mType == SERVER_FILETRANS)
+ {
+ if (MSN_HandleMSNFTP(info, info->mData))
+ break;
+ }
+ else // info->mType!=SERVER_FILETRANS
+ {
+ for (;;)
+ {
+ char* peol = strchr(info->mData,'\r');
+ if (peol == NULL)
+ break;
+
+ if (info->mBytesInData < peol - info->mData + 2)
+ break; //wait for full line end
+
+ char msg[sizeof(info->mData)];
+ memcpy(msg, info->mData, peol - info->mData); msg[peol - info->mData] = 0;
+ if (*++peol != '\n')
+ debugLogA("Dodgy line ending to command: ignoring");
+ else
+ peol++;
+
+ info->mBytesInData -= peol - info->mData;
+ memmove(info->mData, peol, info->mBytesInData);
+
+ debugLogA("RECV:%s", msg);
+
+ if (!isalnum(msg[0]) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' '))
+ {
+ debugLogA("Invalid command name");
+ continue;
+ }
+
+ if (MSN_HandleMSNFTP(info, msg))
+ break;
+ }
+ }
+
+ if (info->mBytesInData == sizeof(info->mData))
+ {
+ debugLogA("sizeof(data) is too small: the longest line won't fit");
+ break;
+ }
+ }
+
+ debugLogA("Closing file transfer thread");
+}
+
+void CMsnProto::msnftp_startFileSend(ThreadData* info, const char* Invcommand, const char* Invcookie)
+{
+ if (_stricmp(Invcommand, "ACCEPT"))
+ return;
+
+ NETLIBBIND nlb = {0};
+ HANDLE sb = NULL;
+
+ filetransfer* ft = info->mMsnFtp; info->mMsnFtp = NULL;
+ if (ft != NULL && MyConnection.extIP)
+ {
+ nlb.cbSize = sizeof(nlb);
+ nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
+ nlb.pExtra = this;
+
+ sb = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hNetlibUser, (LPARAM)&nlb);
+ if (sb == NULL)
+ debugLogA("Unable to bind the port for incoming transfers");
+ }
+
+ char hostname[256] = "";
+ gethostname(hostname, sizeof(hostname));
+ PHOSTENT he = gethostbyname(hostname);
+
+ const PIN_ADDR addr = (PIN_ADDR)he->h_addr_list[0];
+ if (addr)
+ strcpy(hostname, inet_ntoa(*addr));
+ else
+ hostname[0] = 0;
+
+ char command[1024];
+ int nBytes = mir_snprintf(command, sizeof(command),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: %s\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "IP-Address: %s\r\n"
+ "IP-Address-Internal: %s\r\n"
+ "Port: %i\r\n"
+ "PortX: %i\r\n"
+ "PortX-Internal: %i\r\n"
+ "AuthCookie: %i\r\n"
+ "Launch-Application: FALSE\r\n"
+ "Request-Data: IP-Address:\r\n\r\n",
+ sb && MyConnection.extIP ? "ACCEPT" : "CANCEL",
+ Invcookie, MyConnection.GetMyExtIPStr(), hostname,
+ nlb.wExPort, nlb.wExPort ^ 0x3141, nlb.wPort ^ 0x3141,
+ MSN_GenRandom());
+
+ info->sendPacket("MSG", "N %d\r\n%s", nBytes, command);
+
+ if (sb)
+ {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_FILETRANS;
+ newThread->mCaller = 2;
+ newThread->mMsnFtp = ft;
+ newThread->mIncomingBoundPort = sb;
+ newThread->mIncomingPort = nlb.wPort;
+ newThread->startThread(&CMsnProto::msnftp_sendFileThread, this);
+ }
+ else
+ delete ft;
+}