/*
Copyright (c) 2015-24 Miranda NG team (https://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"
void CSkypeProto::PollingThread(void *)
{
debugLogA(__FUNCTION__ ": entering");
int nErrors = 0;
m_iPollingId = -1;
while (true) {
if (m_isTerminated || m_szId == nullptr)
break;
std::unique_ptr request(new PollRequest(this));
request->nlc = m_hPollingConn;
NLHR_PTR response(DoSend(request.get()));
if (m_isTerminated || m_szId == nullptr)
break;
if (response == nullptr || response->resultCode != 200) {
if (nErrors < POLLING_ERRORS_LIMIT) {
nErrors++;
continue;
}
break;
}
m_hPollingConn = response->nlc;
if (!response->body.IsEmpty())
ParsePollData(response->body);
}
if (!m_isTerminated) {
debugLogA(__FUNCTION__ ": unexpected termination; switching protocol to offline");
SetStatus(ID_STATUS_OFFLINE);
}
m_hPollingConn = nullptr;
m_hPollingThread = nullptr;
debugLogA(__FUNCTION__ ": leaving");
}
void CSkypeProto::ParsePollData(const char *szData)
{
debugLogA(__FUNCTION__);
JSONNode data = JSONNode::parse(szData);
if (!data)
return;
for (auto &message : data["eventMessages"]) {
int eventId = message["id"].as_int();
if (eventId > m_iPollingId)
m_iPollingId = eventId;
const JSONNode &resource = message["resource"];
std::string resourceType = message["resourceType"].as_string();
if (resourceType == "NewMessage")
ProcessNewMessage(resource);
else if (resourceType == "UserPresence")
ProcessUserPresence(resource);
else if (resourceType == "EndpointPresence")
ProcessEndpointPresence(resource);
else if (resourceType == "ConversationUpdate")
ProcessConversationUpdate(resource);
else if (resourceType == "ThreadUpdate")
ProcessThreadUpdate(resource);
}
}
void CSkypeProto::ProcessEndpointPresence(const JSONNode &node)
{
debugLogA(__FUNCTION__);
std::string selfLink = node["selfLink"].as_string();
CMStringA skypename(UrlToSkypeId(selfLink.c_str()));
MCONTACT hContact = FindContact(skypename);
if (hContact == NULL)
return;
const JSONNode &publicInfo = node["publicInfo"];
const JSONNode &privateInfo = node["privateInfo"];
CMStringA MirVer;
if (publicInfo) {
std::string skypeNameVersion = publicInfo["skypeNameVersion"].as_string();
std::string version = publicInfo["version"].as_string();
std::string typ = publicInfo["typ"].as_string();
int iTyp = atoi(typ.c_str());
switch (iTyp) {
case 0:
case 1:
MirVer.Append("Skype (Web) " + ParseUrl(version.c_str(), "/"));
break;
case 10:
MirVer.Append("Skype (XBOX) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 17:
MirVer.Append("Skype (Android) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 16:
MirVer.Append("Skype (iOS) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 12:
MirVer.Append("Skype (WinRT) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 15:
MirVer.Append("Skype (WP) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 13:
MirVer.Append("Skype (OSX) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 11:
MirVer.Append("Skype (Windows) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 14:
MirVer.Append("Skype (Linux) " + ParseUrl(skypeNameVersion.c_str(), "/"));
break;
case 125:
MirVer.AppendFormat("Miranda NG Skype %s", version.c_str());
break;
default:
MirVer.Append("Skype (Unknown)");
}
}
if (privateInfo != NULL) {
std::string epname = privateInfo["epname"].as_string();
if (!epname.empty())
MirVer.AppendFormat(" [%s]", epname.c_str());
}
setString(hContact, "MirVer", MirVer);
}
void CSkypeProto::ProcessUserPresence(const JSONNode &node)
{
debugLogA(__FUNCTION__);
std::string selfLink = node["selfLink"].as_string();
std::string status = node["status"].as_string();
CMStringA skypename = UrlToSkypeId(selfLink.c_str());
if (!skypename.IsEmpty()) {
if (IsMe(skypename)) {
int iNewStatus = SkypeToMirandaStatus(status.c_str());
if (iNewStatus == ID_STATUS_OFFLINE) return;
int old_status = m_iStatus;
m_iDesiredStatus = iNewStatus;
m_iStatus = iNewStatus;
if (old_status != iNewStatus)
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, iNewStatus);
}
else {
MCONTACT hContact = FindContact(skypename);
if (hContact != NULL)
SetContactStatus(hContact, SkypeToMirandaStatus(status.c_str()));
}
}
}
void CSkypeProto::ProcessConversationUpdate(const JSONNode &) {}
void CSkypeProto::ProcessThreadUpdate(const JSONNode &) {}