INT_PTR __cdecl CJabberProto::JabberServiceParseXmppURI(WPARAM, LPARAM lParam) { TCHAR *arg = (TCHAR *)lParam; if (arg == NULL) return 1; // skip leading prefix TCHAR szUri[ 1024 ]; _tcsncpy_s(szUri, SIZEOF(szUri), arg, _TRUNCATE); TCHAR *szJid = _tcschr(szUri, _T(':')); if (szJid == NULL) return 1; // skip // for (++szJid; *szJid == _T('/'); ++szJid); // empty jid? if (!*szJid) return 1; // command code TCHAR *szCommand = szJid; szCommand = _tcschr(szCommand, _T('?')); if (szCommand) *(szCommand++) = 0; // parameters TCHAR *szSecondParam = szCommand ? _tcschr(szCommand, _T(';')) : NULL; if (szSecondParam) *(szSecondParam++) = 0; // no command or message command if (!szCommand || (szCommand && !_tcsicmp(szCommand, _T("message")))) { // message if (!ServiceExists(MS_MSG_SENDMESSAGEW)) return 1; TCHAR *szMsgBody = NULL; HANDLE hContact = HContactFromJID(szJid, TRUE); if (hContact == NULL) hContact = DBCreateContact(szJid, szJid, TRUE, TRUE); if (hContact == NULL) return 1; if (szSecondParam) { //there are parameters to message szMsgBody = _tcsstr(szSecondParam, _T("body=")); if (szMsgBody) { szMsgBody += 5; TCHAR *szDelim = _tcschr(szMsgBody, _T(';')); if (szDelim) szDelim = 0; JabberHttpUrlDecode(szMsgBody); } } CallService(MS_MSG_SENDMESSAGEW, (WPARAM)hContact, (LPARAM)szMsgBody); return 0; } if (!_tcsicmp(szCommand, _T("roster"))) { if (!HContactFromJID(szJid)) { JABBER_SEARCH_RESULT jsr = { 0 }; jsr.hdr.cbSize = sizeof(JABBER_SEARCH_RESULT); jsr.hdr.flags = PSR_TCHAR; jsr.hdr.nick = szJid; jsr.hdr.id = szJid; _tcsncpy(jsr.jid, szJid, SIZEOF(jsr.jid) - 1); ADDCONTACTSTRUCT acs; acs.handleType = HANDLE_SEARCHRESULT; acs.szProto = m_szModuleName; acs.psr = &jsr.hdr; CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs); } return 0; } // chat join invitation if (!_tcsicmp(szCommand, _T("join"))) { GroupchatJoinRoomByJid(NULL, szJid); return 0; } // service discovery request if (!_tcsicmp(szCommand, _T("disco"))) { OnMenuHandleServiceDiscovery(0, (LPARAM)szJid); return 0; } // ad-hoc commands if (!_tcsicmp(szCommand, _T("command"))) { if (szSecondParam) { if (!_tcsnicmp(szSecondParam, _T("node="), 5)) { szSecondParam += 5; if (!*szSecondParam) szSecondParam = NULL; } else szSecondParam = NULL; } CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams(this, szJid, szSecondParam); ContactMenuRunCommands(0, (LPARAM)pStartupParams); return 0; } // send file if (!_tcsicmp(szCommand, _T("sendfile"))) { if (!ServiceExists(MS_FILE_SENDFILE)) return 1; HANDLE hContact = HContactFromJID(szJid, TRUE); if (hContact == NULL) hContact = DBCreateContact(szJid, szJid, TRUE, TRUE); if (hContact == NULL) return 1; CallService(MS_FILE_SENDFILE, (WPARAM)hContact, (LPARAM)NULL); return 0; } return 1; /* parse failed */ }
int CJabberProto::FileReceiveParse(filetransfer *ft, char* buffer, int datalen) { char* p, *q, *s, *eob; int num, code; eob = buffer + datalen; p = buffer; num = 0; while (true) { if (ft->state == FT_CONNECTING || ft->state == FT_INITIALIZING) { for (q = p; q + 1 < eob && (*q != '\r' || *(q + 1) != '\n'); q++); if (q + 1 >= eob) break; ptrA str(mir_strndup(p, size_t(q - p))); if (str == NULL) { ft->state = FT_ERROR; break; } debugLogA("FT Got: %s", str); if (ft->state == FT_CONNECTING) { // looking for "HTTP/1.1 200 OK" if (sscanf(str, "HTTP/%*d.%*d %d %*s", &code) == 1 && code == 200) { ft->state = FT_INITIALIZING; ft->std.currentFileSize = -1; debugLogA("Change to FT_INITIALIZING"); ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0); } } else { // FT_INITIALIZING if (str[0] == '\0') { TCHAR *s; if ((s = _tcsrchr(ft->httpPath, '/')) != NULL) s++; else s = ft->httpPath; ft->std.tszCurrentFile = mir_tstrdup(s); JabberHttpUrlDecode(ft->std.tszCurrentFile); if (ft->create() == -1) { ft->state = FT_ERROR; break; } ft->state = FT_RECEIVING; ft->std.currentFileProgress = 0; debugLogA("Change to FT_RECEIVING"); } else if ((s = strchr(str, ':')) != NULL) { *s = '\0'; if (!mir_strcmp(str, "Content-Length")) ft->std.totalBytes = ft->std.currentFileSize = _atoi64(s + 1); } } q += 2; num += (q - p); p = q; } else if (ft->state == FT_RECEIVING) { int bufferSize, writeSize; __int64 remainingBytes; if (ft->std.currentFileProgress < ft->std.currentFileSize) { bufferSize = eob - p; remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress; if (remainingBytes < bufferSize) writeSize = remainingBytes; else writeSize = bufferSize; if (_write(ft->fileId, p, writeSize) != writeSize) { debugLogA("_write() error"); ft->state = FT_ERROR; } else { ft->std.currentFileProgress += writeSize; ft->std.totalProgress += writeSize; ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std); if (ft->std.currentFileProgress == ft->std.currentFileSize) ft->state = FT_DONE; } } num = datalen; break; } else break; } return num; }
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; }
int CJabberProto::FileSendParse(JABBER_SOCKET s, filetransfer *ft, char* buffer, int datalen) { char* p, *q, *t, *eob; char* str; int num; int currentFile; int fileId; int numRead; eob = buffer + datalen; p = buffer; num = 0; while (ft->state == FT_CONNECTING || ft->state == FT_INITIALIZING) { for (q = p; q + 1 < eob && (*q != '\r' || *(q + 1) != '\n'); q++); if (q + 1 >= eob) break; if ((str = (char*)mir_alloc(q - p + 1)) == NULL) { ft->state = FT_ERROR; break; } strncpy_s(str, q - p, p, _TRUNCATE); str[q - p] = '\0'; debugLogA("FT Got: %s", str); if (ft->state == FT_CONNECTING) { // looking for "GET filename.ext HTTP/1.1" if (!strncmp(str, "GET ", 4)) { for (t = str + 4; *t != '\0' && *t != ' '; t++); *t = '\0'; for (t = str + 4; *t != '\0' && *t == '/'; t++); ft->httpPath = mir_a2t(t); JabberHttpUrlDecode(ft->httpPath); ft->state = FT_INITIALIZING; debugLogA("Change to FT_INITIALIZING"); } } else { // FT_INITIALIZING if (str[0] == '\0') { struct _stati64 statbuf; mir_free(str); num += 2; currentFile = ft->std.currentFileNumber; TCHAR *t = _tcsrchr(ft->std.ptszFiles[currentFile], '\\'); if (t != NULL) t++; else t = ft->std.ptszFiles[currentFile]; if (ft->httpPath == NULL || mir_tstrcmp(ft->httpPath, t)) { if (ft->httpPath == NULL) debugLogA("Requested file name does not matched (httpPath == NULL)"); else debugLog(_T("Requested file name does not matched ('%s' vs. '%s')"), ft->httpPath, t); ft->state = FT_ERROR; break; } debugLog(_T("Sending [%s]"), ft->std.ptszFiles[currentFile]); _tstati64(ft->std.ptszFiles[currentFile], &statbuf); // file size in statbuf.st_size if ((fileId = _topen(ft->std.ptszFiles[currentFile], _O_BINARY | _O_RDONLY)) < 0) { debugLogA("File cannot be opened"); ft->state = FT_ERROR; mir_free(ft->httpPath); ft->httpPath = NULL; break; } char fileBuffer[2048]; int bytes = mir_snprintf(fileBuffer, _countof(fileBuffer), "HTTP/1.1 200 OK\r\nContent-Length: %I64u\r\n\r\n", statbuf.st_size); WsSend(s, fileBuffer, bytes, MSG_DUMPASTEXT); ft->std.flags |= PFTS_SENDING; ft->std.currentFileProgress = 0; debugLogA("Sending file data..."); while ((numRead = _read(fileId, fileBuffer, 2048)) > 0) { if (Netlib_Send(s, fileBuffer, numRead, 0) != numRead) { ft->state = FT_ERROR; break; } ft->std.currentFileProgress += numRead; ft->std.totalProgress += numRead; ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std); } _close(fileId); if (ft->state != FT_ERROR) ft->state = FT_DONE; debugLogA("Finishing this file..."); mir_free(ft->httpPath); ft->httpPath = NULL; break; } } mir_free(str); q += 2; num += (q-p); p = q; } return num; }