BOOL CJabberProto::OnIqRequestOOB(HXML, CJabberIqInfo *pInfo) { if (!pInfo->GetFrom() || !pInfo->GetHContact()) return TRUE; HXML n = XmlGetChild(pInfo->GetChildNode(), "url"); if (!n || !XmlGetText(n)) return TRUE; if (m_options.BsOnlyIBB) { // reject XmlNodeIq iq(_T("error"), pInfo); HXML e = XmlAddChild(iq, _T("error"), _T("File transfer refused")); XmlAddAttr(e, _T("code"), 406); m_ThreadInfo->send(iq); return TRUE; } filetransfer *ft = new filetransfer(this); ft->std.totalFiles = 1; ft->jid = mir_tstrdup(pInfo->GetFrom()); ft->std.hContact = pInfo->GetHContact(); ft->type = FT_OOB; ft->httpHostName = NULL; ft->httpPort = 80; ft->httpPath = NULL; // Parse the URL TCHAR *str = (TCHAR*)XmlGetText(n); // URL of the file to get if (!_tcsnicmp(str, _T("http://"), 7)) { TCHAR *p = str + 7, *q; if ((q = _tcschr(p, '/')) != NULL) { TCHAR text[1024]; if (q - p < _countof(text)) { _tcsncpy_s(text, p, q - p); text[q - p] = '\0'; if ((p = _tcschr(text, ':')) != NULL) { ft->httpPort = (WORD)_ttoi(p + 1); *p = '\0'; } ft->httpHostName = mir_t2a(text); } } } if (pInfo->GetIdStr()) ft->szId = JabberId2string(pInfo->GetIqId()); if (ft->httpHostName && ft->httpPath) { TCHAR *desc = NULL; debugLogA("Host=%s Port=%d Path=%s", ft->httpHostName, ft->httpPort, ft->httpPath); if ((n = XmlGetChild(pInfo->GetChildNode(), "desc")) != NULL) desc = (TCHAR*)XmlGetText(n); TCHAR *str2; debugLog(_T("description = %s"), desc); if ((str2 = _tcsrchr(ft->httpPath, '/')) != NULL) str2++; else str2 = ft->httpPath; str2 = mir_tstrdup(str2); JabberHttpUrlDecode(str2); PROTORECVFILET pre; pre.dwFlags = PRFF_TCHAR; pre.timestamp = time(NULL); pre.descr.t = desc; pre.files.t = &str2; pre.fileCount = 1; pre.lParam = (LPARAM)ft; ProtoChainRecvFile(ft->std.hContact, &pre); mir_free(str2); } else { // reject XmlNodeIq iq(_T("error"), pInfo); HXML e = XmlAddChild(iq, _T("error"), _T("File transfer refused")); XmlAddAttr(e, _T("code"), 406); m_ThreadInfo->send(iq); delete ft; } return TRUE; }
void __cdecl CJabberProto::FileServerThread(filetransfer *ft) { debugLogA("Thread started: type=file_send"); ThreadData info(this, NULL); ft->type = FT_OOB; NETLIBBIND nlb = { 0 }; nlb.cbSize = sizeof(NETLIBBIND); nlb.pfnNewConnectionV2 = JabberFileServerConnection; nlb.pExtra = this; nlb.wPort = 0; // Use user-specified incoming port ranges, if available info.s = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hNetlibUser, (LPARAM)&nlb); if (info.s == NULL) { debugLogA("Cannot allocate port to bind for file server thread, thread ended."); ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); delete ft; return; } ft->s = info.s; debugLogA("ft->s = %d", info.s); HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ft->hFileEvent = hEvent; TCHAR szPort[20]; mir_sntprintf(szPort, _countof(szPort), _T("%d"), nlb.wPort); JABBER_LIST_ITEM *item = ListAdd(LIST_FILE, szPort); item->ft = ft; TCHAR *ptszResource = ListGetBestClientResourceNamePtr(ft->jid); if (ptszResource != NULL) { ft->state = FT_CONNECTING; for (int i = 0; i < ft->std.totalFiles && ft->state != FT_ERROR && ft->state != FT_DENIED; i++) { ft->std.currentFileNumber = i; ft->state = FT_CONNECTING; if (ft->httpPath) mir_free(ft->httpPath); ft->httpPath = NULL; TCHAR *p; if ((p = _tcschr(ft->std.ptszFiles[i], '\\')) != NULL) p++; else p = ft->std.ptszFiles[i]; ptrA pFileName(mir_urlEncode(T2Utf(p))); if (pFileName != NULL) { ft->szId = JabberId2string(SerialNext()); ptrA myAddr; if (m_options.BsDirect && m_options.BsDirectManual) myAddr = getStringA("BsDirectAddr"); if (myAddr == NULL) myAddr = (char*)CallService(MS_NETLIB_ADDRESSTOSTRING, 1, nlb.dwExternalIP); char szAddr[256]; mir_snprintf(szAddr, _countof(szAddr), "http://%s:%d/%s", myAddr, nlb.wPort, pFileName); size_t len = mir_tstrlen(ptszResource) + mir_tstrlen(ft->jid) + 2; TCHAR *fulljid = (TCHAR *)alloca(sizeof(TCHAR) * len); mir_sntprintf(fulljid, len, _T("%s/%s"), ft->jid, ptszResource); XmlNodeIq iq(_T("set"), ft->szId, fulljid); HXML query = iq << XQUERY(JABBER_FEAT_OOB); query << XCHILD(_T("url"), _A2T(szAddr)); query << XCHILD(_T("desc"), ft->szDescription); m_ThreadInfo->send(iq); debugLogA("Waiting for the file to be sent..."); WaitForSingleObject(hEvent, INFINITE); } debugLogA("File sent, advancing to the next file..."); ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); } CloseHandle(hEvent); ft->hFileEvent = NULL; debugLogA("Finish all files"); } ft->s = NULL; debugLogA("ft->s is NULL"); ListRemove(LIST_FILE, szPort); switch (ft->state) { case FT_DONE: debugLogA("Finish successfully"); ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); break; case FT_DENIED: ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0); break; default: // FT_ERROR: debugLogA("Finish with errors"); ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); break; } debugLogA("Thread ended: type=file_send"); delete ft; }