/* Copyright (c) 2015 Miranda NG project (http://miranda-ng.org) 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 version 2 of the License. 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 . */ #include "stdafx.h" /* HISTORY SYNC */ void CSkypeProto::OnGetServerHistory(const NETLIBHTTPREQUEST *response) { if (response == NULL) return; JSONNode root = JSONNode::parse(response->pData); if (!root) return; const JSONNode &metadata = root["_metadata"]; const JSONNode &conversations = root["messages"].as_array(); int totalCount = metadata["totalCount"].as_int(); std::string syncState = metadata["syncState"].as_string(); bool markAllAsUnread = getBool("MarkMesUnread", true); if (totalCount >= 99 || conversations.size() >= 99) PushRequest(new GetHistoryOnUrlRequest(syncState.c_str(), m_szRegToken), &CSkypeProto::OnGetServerHistory); for (int i = (int)conversations.size(); i >= 0; i--) { const JSONNode &message = conversations.at(i); std::string clientMsgId = message["clientmessageid"].as_string(); std::string skypeEditedId = message["skypeeditedid"].as_string(); std::string messageType = message["messagetype"].as_string(); std::string from = message["from"].as_string(); std::string content = message["content"].as_string(); std::string conversationLink = message["conversationLink"].as_string(); int emoteOffset = message["skypeemoteoffset"].as_int(); time_t timestamp = IsoToUnixTime(message["composetime"].as_string().c_str()); CMStringA skypename(ContactUrlToName(from.c_str())); bool isEdited = message["skypeeditedid"]; MCONTACT hContact = FindContact(ContactUrlToName(conversationLink.c_str())); if (timestamp > db_get_dw(hContact, m_szModuleName, "LastMsgTime", 0)) db_set_dw(hContact, m_szModuleName, "LastMsgTime", (DWORD)timestamp); int flags = DBEF_UTF; if (!markAllAsUnread) flags |= DBEF_READ; if (IsMe(skypename)) flags |= DBEF_SENT; if (strstr(conversationLink.c_str(), "/8:")) { if (!mir_strcmpi(messageType.c_str(), "Text") || !mir_strcmpi(messageType.c_str(), "RichText")) { ptrA message(RemoveHtml(content.c_str())); MEVENT dbevent = GetMessageFromDb(hContact, skypeEditedId.c_str()); if (isEdited && dbevent != NULL) { DBEVENTINFO dbei = { sizeof(dbei) }; dbei.cbBlob = db_event_getBlobSize(dbevent); mir_ptr blob((PBYTE)mir_alloc(dbei.cbBlob)); dbei.pBlob = blob; db_event_get(dbevent, &dbei); time_t dbEventTimestamp = dbei.timestamp; char *dbMsgText = NEWSTR_ALLOCA((char *)dbei.pBlob); TCHAR time[64]; _locale_t locale = _create_locale(LC_ALL, ""); _tcsftime_l(time, sizeof(time), L"%X %x", localtime(×tamp), locale); _free_locale(locale); CMStringA msg(FORMAT, "%s\n%s %s:\n%s", mir_utf8decodeA(dbMsgText), Translate("Edited at"), T2Utf(time), mir_utf8decodeA(message)); db_event_delete(hContact, dbevent); AddMessageToDb(hContact, dbEventTimestamp, flags, clientMsgId.c_str(), mir_utf8encode(msg.GetBuffer()), emoteOffset); } else AddMessageToDb(hContact, timestamp, flags, clientMsgId.c_str(), message, emoteOffset); } else if (!mir_strcmpi(messageType.c_str(), "Event/Call")) { //content=user name6 //Echo / Sound Test Service6 //content=user name int iType = 3, iDuration = 0; CMStringA skypename(ContactUrlToName(from.c_str())); HXML xml = xi.parseString(ptrT(mir_a2t(content.c_str())), 0, _T("partlist")); if (xml != NULL) { ptrA type(mir_t2a(xi.getAttrValue(xml, _T("type")))); if (!mir_strcmpi(type, "ended")) iType = 0; else if (!mir_strcmpi(type, "started")) iType = 1; HXML xmlNode = xi.getChildByPath(xml, _T("part"), 0); HXML duration = xmlNode == NULL ? NULL : xi.getChildByPath(xmlNode, _T("duration"), 0); iDuration = duration != NULL ? atoi(mir_t2a(xi.getText(duration))) : NULL; xi.destroyNode(xml); } CMStringA text = ""; if (iType == 1) text.Append(Translate("Call started")); else if (iType == 0) { CMStringA chours = "", cmins = "", csec = ""; int hours = 0, mins = 0, sec = 0; if (iDuration != NULL) { hours = iDuration / 3600; mins = iDuration / 60; sec = iDuration % 60; } else hours = mins = sec = 0; chours.AppendFormat(hours < 10 ? "0%d" : "%d", hours); cmins.AppendFormat(mins < 10 ? "0%d" : "%d", mins); csec.AppendFormat(sec < 10 ? "0%d" : "%d", sec); text.AppendFormat("%s\n%s: %s:%s:%s", Translate("Call ended"), Translate("Duration"), chours, cmins, csec); } AddCallInfoToDb(hContact, timestamp, flags, clientMsgId.c_str(), text.GetBuffer()); } else if (!mir_strcmpi(messageType.c_str(), "RichText/Files")) { //content=run.bat HXML xml = xi.parseString(ptrT(mir_a2t(content.c_str())), 0, _T("files")); if (xml != NULL) { for (int i = 0; i < xi.getChildCount(xml); i++) { int fileSize; CMStringA msg = ""; HXML xmlNode = xi.getNthChild(xml, L"file", i); if (xmlNode == NULL) break; fileSize = atoi(_T2A(xi.getAttrValue(xmlNode, L"size"))); ptrA fileName(mir_t2a(xi.getText(xmlNode))); if (fileName == NULL || fileSize == NULL) continue; msg.Empty(); msg.AppendFormat("%s:\n\t%s: %s\n\t%s: %d %s", Translate("File transfer"), Translate("File name"), fileName, Translate("Size"), fileSize, Translate("bytes")); AddMessageToDb(hContact, timestamp, flags, clientMsgId.c_str(), msg.GetBuffer()); } } } else if (!mir_strcmpi(messageType.c_str(), "RichText/UriObject")) { //content=Для просмотра этого общего фото перейдите по ссылке: https://api.asm.skype.com/s/i?0-weu-d1-262f0a1ee256d03b8e4b8360d9208834 HXML xml = xi.parseString(ptrT(mir_a2t(content.c_str())), 0, _T("URIObject")); if (xml != NULL) { CMStringA object(ParseUrl(_T2A(xi.getAttrValue(xml, L"uri")), "/objects/")); CMStringA data(FORMAT, "%s: https://api.asm.skype.com/s/i?%s", Translate("Image"), object.c_str()); AddMessageToDb(hContact, timestamp, flags, clientMsgId.c_str(), data.GetBuffer()); } } //Picture } else if (conversationLink.find("/19:") != -1) { CMStringA chatname(ChatUrlToName(conversationLink.c_str())); if (!mir_strcmpi(messageType.c_str(), "Text") || !mir_strcmpi(messageType.c_str(), "RichText")) AddMessageToChat(_A2T(chatname), _A2T(skypename), content.c_str(), emoteOffset != NULL, emoteOffset, timestamp, true); } } } INT_PTR CSkypeProto::GetContactHistory(WPARAM hContact, LPARAM) { PushRequest(new GetHistoryRequest(m_szRegToken, ptrA(db_get_sa(hContact, m_szModuleName, SKYPE_SETTINGS_ID)), 100, false, 0, m_szServer), &CSkypeProto::OnGetServerHistory); return 0; } void CSkypeProto::OnSyncHistory(const NETLIBHTTPREQUEST *response) { if (response == NULL || response->pData == NULL) return; JSONNode root = JSONNode::parse(response->pData); if (!root) return; const JSONNode &metadata = root["_metadata"]; const JSONNode &conversations = root["conversations"].as_array(); int totalCount = metadata["totalCount"].as_int(); std::string syncState = metadata["syncState"].as_string(); if (totalCount >= 99 || conversations.size() >= 99) PushRequest(new SyncHistoryFirstRequest(syncState.c_str(), (char*)m_szRegToken), &CSkypeProto::OnSyncHistory); for (size_t i = 0; i < conversations.size(); i++) { const JSONNode &conversation = conversations.at(i); const JSONNode &lastMessage = conversation["lastMessage"]; if (!lastMessage) continue; std::string conversationLink = lastMessage["conversationLink"].as_string(); time_t composeTime(IsoToUnixTime(lastMessage["composetime"].as_string().c_str())); if (conversationLink.find("/8:") != -1) { CMStringA skypename(ContactUrlToName(conversationLink.c_str())); MCONTACT hContact = FindContact(skypename); if (hContact == NULL) continue; if (db_get_dw(hContact, m_szModuleName, "LastMsgTime", 0) < composeTime) { PushRequest(new GetHistoryRequest(m_szRegToken, skypename, 100, false, 0, m_szServer), &CSkypeProto::OnGetServerHistory); } } } HistorySynced = true; }