diff options
author | George Hazan <ghazan@miranda.im> | 2019-12-23 22:00:48 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-12-23 22:00:48 +0300 |
commit | 18374c1f27249cd2edd87fe6f4fb8af5d5dcdcc4 (patch) | |
tree | 95765f13ec2ea996a17c7fe6add533703c297ebb | |
parent | 7fdb247a350f7a966d6f81954a2ee40f1600d224 (diff) |
Facebook:
- added presence processing;
- added contacts processing;
- code cleaning and restructurizing
-rw-r--r-- | protocols/Facebook/src/mqtt.cpp | 41 | ||||
-rw-r--r-- | protocols/Facebook/src/proto.cpp | 17 | ||||
-rw-r--r-- | protocols/Facebook/src/proto.h | 23 | ||||
-rw-r--r-- | protocols/Facebook/src/server.cpp | 131 | ||||
-rw-r--r-- | protocols/Facebook/src/thrift.cpp | 2 |
5 files changed, 141 insertions, 73 deletions
diff --git a/protocols/Facebook/src/mqtt.cpp b/protocols/Facebook/src/mqtt.cpp index c80544176b..8731e2bcd8 100644 --- a/protocols/Facebook/src/mqtt.cpp +++ b/protocols/Facebook/src/mqtt.cpp @@ -31,16 +31,9 @@ uint8_t *FacebookProto::doZip(size_t cbData, const void *pData, size_t &cbRes) zStreamOut.next_in = (uint8_t *)pData; zStreamOut.avail_out = (unsigned)dataSize; zStreamOut.next_out = (uint8_t *)pRes; - - switch (deflate(&zStreamOut, Z_FINISH)) { - case Z_STREAM_END: debugLogA("Deflate: Z_STREAM_END"); break; - case Z_OK: debugLogA("Deflate: Z_OK"); break; - case Z_BUF_ERROR: debugLogA("Deflate: Z_BUF_ERROR"); break; - case Z_DATA_ERROR: debugLogA("Deflate: Z_DATA_ERROR"); break; - case Z_MEM_ERROR: debugLogA("Deflate: Z_MEM_ERROR"); break; - } - + deflate(&zStreamOut, Z_FINISH); deflateEnd(&zStreamOut); + cbRes = dataSize - zStreamOut.avail_out; return pRes; } @@ -56,16 +49,9 @@ uint8_t *FacebookProto::doUnzip(size_t cbData, const void *pData, size_t &cbRes) zStreamOut.next_in = (uint8_t *)pData; zStreamOut.avail_out = (unsigned)dataSize; zStreamOut.next_out = (uint8_t *)pRes; - - switch (inflate(&zStreamOut, Z_FINISH)) { - case Z_STREAM_END: debugLogA("Deflate: Z_STREAM_END"); break; - case Z_OK: debugLogA("Deflate: Z_OK"); break; - case Z_BUF_ERROR: debugLogA("Deflate: Z_BUF_ERROR"); break; - case Z_DATA_ERROR: debugLogA("Deflate: Z_DATA_ERROR"); break; - case Z_MEM_ERROR: debugLogA("Deflate: Z_MEM_ERROR"); break; - } - + inflate(&zStreamOut, Z_FINISH); inflateEnd(&zStreamOut); + cbRes = dataSize - zStreamOut.avail_out; return pRes; } @@ -99,28 +85,13 @@ char* MqttMessage::readStr(const uint8_t *&pData) const void MqttMessage::writeStr(const char *str) { size_t len = mir_strlen(str); - writeInt16((int)len); + writeInt16((uint16_t)len); writeBuf(str, len); } ///////////////////////////////////////////////////////////////////////////////////////// // MQTT functions -bool FacebookProto::MqttConnect() -{ - NETLIBOPENCONNECTION nloc = {}; - nloc.szHost = "mqtt.facebook.com"; - nloc.wPort = 443; - nloc.flags = NLOCF_SSL | NLOCF_V2; - m_mqttConn = Netlib_OpenConnection(m_hNetlibUser, &nloc); - if (m_mqttConn == nullptr) { - debugLogA("connection failed, exiting"); - return false; - } - - return true; -} - bool FacebookProto::MqttParse(const MqttMessage &payload) { auto *pData = (const uint8_t *)payload.data(), *pBeg = pData; @@ -213,7 +184,7 @@ void FacebookProto::MqttSend(const MqttMessage &payload) ///////////////////////////////////////////////////////////////////////////////////////// // creates initial MQTT will and sends initialization packet -void FacebookProto::MqttOpen() +void FacebookProto::MqttLogin() { uint8_t zeroByte = 0; Utils_GetRandom(&m_iMqttId, sizeof(m_iMqttId) / 2); diff --git a/protocols/Facebook/src/proto.cpp b/protocols/Facebook/src/proto.cpp index 0f60c7c420..31b99b2100 100644 --- a/protocols/Facebook/src/proto.cpp +++ b/protocols/Facebook/src/proto.cpp @@ -20,9 +20,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" +static int CompareUsers(const FacebookUser *p1, const FacebookUser *p2) +{ + if (p1->id == p2->id) + return 0; + + return (p1->id < p2->id) ? -1 : 1; +} + FacebookProto::FacebookProto(const char *proto_name, const wchar_t *username) : - PROTO<FacebookProto>(proto_name, username) + PROTO<FacebookProto>(proto_name, username), + m_users(50, CompareUsers) { + for (auto &cc : AccContacts()) { + CMStringA szId(getMStringA(cc, DBKEY_ID)); + if (!szId.IsEmpty()) + m_users.insert(new FacebookUser(_atoi64(szId), cc)); + } + // to upgrade previous settings if (getByte("Compatibility") < 1) { setByte("Compatibility", 1); diff --git a/protocols/Facebook/src/proto.h b/protocols/Facebook/src/proto.h index ad46f4c454..7d5bedc911 100644 --- a/protocols/Facebook/src/proto.h +++ b/protocols/Facebook/src/proto.h @@ -337,6 +337,17 @@ public: __forceinline int error() const { return m_errorCode; } }; +struct FacebookUser +{ + FacebookUser(__int64 _p1, MCONTACT _p2) : + id(_p1), + hContact(_p2) + {} + + __int64 id; + MCONTACT hContact; +}; + class FacebookProto : public PROTO<FacebookProto> { uint8_t *doZip(size_t cbData, const void *pData, size_t &cbRes); @@ -347,8 +358,7 @@ class FacebookProto : public PROTO<FacebookProto> NETLIBHTTPREQUEST *ExecuteRequest(AsyncHttpRequest *pReq); // MQTT functions - bool MqttConnect(); - void MqttOpen(); + void MqttLogin(); void MqttPing(); void MqttPublish(const char *topic, const char *value); @@ -376,9 +386,18 @@ class FacebookProto : public PROTO<FacebookProto> CMStringA m_szAuthToken; // calculated + OBJLIST<FacebookUser> m_users; + FacebookUser *FindUser(__int64 id) + { + return m_users.find((FacebookUser *)&id); + } + void OnLoggedIn(); void OnLoggedOut(); + bool RefreshToken(); + bool RefreshContacts(); + void __cdecl ServerThread(void *); public: diff --git a/protocols/Facebook/src/server.cpp b/protocols/Facebook/src/server.cpp index 573f7a2c85..33d6b69f4a 100644 --- a/protocols/Facebook/src/server.cpp +++ b/protocols/Facebook/src/server.cpp @@ -41,59 +41,116 @@ void FacebookProto::OnLoggedOut() m_bOnline = false; } -///////////////////////////////////////////////////////////////////////////////////////// +bool FacebookProto::RefreshContacts() +{ + auto *pReq = CreateRequestGQL(FB_API_QUERY_CONTACTS); + pReq << CHAR_PARAM("query_params", "{\"0\":[\"user\"],\"1\":\"" FB_API_CONTACTS_COUNT "\"}"); + pReq->CalcSig(); -void FacebookProto::ServerThread(void *) + JsonReply reply(ExecuteRequest(pReq)); + if (reply.error()) + return false; + + for (auto &it : reply.data()["viewer"]["messenger_contacts"]["nodes"]) { + auto &n = it["represented_profile"]; + CMStringW wszId(n["id"].as_mstring()); + __int64 id = _wtoi64(wszId); + + MCONTACT hContact; + if (id != m_uid) { + auto *pUser = FindUser(id); + if (pUser == nullptr) { + hContact = db_add_contact(); + Proto_AddToContact(hContact, m_szModuleName); + setWString(hContact, DBKEY_ID, wszId); + + m_users.insert(new FacebookUser(id, hContact)); + } + else hContact = pUser->hContact; + } + else hContact = 0; + + if (auto &nName = n["structured_name"]) { + CMStringW wszName(nName["text"].as_mstring()); + setWString(hContact, DBKEY_NICK, wszName); + for (auto &nn : nName["parts"]) { + CMStringW wszPart(nn["part"].as_mstring()); + int offset = nn["offset"].as_int(), length = nn["length"].as_int(); + if (wszPart == L"first") + setWString(hContact, DBKEY_FIRST_NAME, wszName.Mid(offset, length)); + else if (wszPart == L"last") + setWString(hContact, DBKEY_LAST_NAME, wszName.Mid(offset, length)); + } + } + + if (auto &nBirth = n["birthdate"]) { + setDword(hContact, "BirthDay", nBirth["day"].as_int()); + setDword(hContact, "BirthMonth", nBirth["month"].as_int()); + } + + if (auto &nCity = n["current_city"]) + setDword(hContact, "City", nCity["name"].as_int()); + + if (auto &nAva = n["smallPictureUrl"]) + setWString(hContact, "Avatar", nAva["uri"].as_mstring()); + } + return true; +} + +bool FacebookProto::RefreshToken() { - m_szAuthToken = getMStringA(DBKEY_TOKEN); + auto *pReq = CreateRequest("authenticate", "auth.login"); + pReq->m_szUrl = FB_API_URL_AUTH; + pReq << CHAR_PARAM("email", getMStringA(DBKEY_LOGIN)); + pReq << CHAR_PARAM("password", getMStringA(DBKEY_PASS)); + pReq->CalcSig(); - if (m_szAuthToken.IsEmpty()) { - auto *pReq = CreateRequest("authenticate", "auth.login"); - pReq->m_szUrl = FB_API_URL_AUTH; + JsonReply reply(ExecuteRequest(pReq)); + if (reply.error()) + return false; - pReq << CHAR_PARAM("email", getMStringA(DBKEY_LOGIN)); - pReq << CHAR_PARAM("password", getMStringA(DBKEY_PASS)); + m_szAuthToken = reply.data()["access_token"].as_mstring(); + setString(DBKEY_TOKEN, m_szAuthToken); - pReq->CalcSig(); + m_uid = reply.data()["uid"].as_int(); + CMStringA m_szUid = reply.data()["uid"].as_mstring(); + setString(DBKEY_ID, m_szUid); + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// - JsonReply reply(ExecuteRequest(pReq)); +void FacebookProto::ServerThread(void *) +{ + m_szAuthToken = getMStringA(DBKEY_TOKEN); - if (reply.error()) { + if (m_szAuthToken.IsEmpty()) { + if (!RefreshToken()) { +FAIL: ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)m_iStatus, m_iDesiredStatus); m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); return; } - - m_szAuthToken = reply.data()["access_token"].as_mstring(); - setString(DBKEY_TOKEN, m_szAuthToken); - - m_uid = reply.data()["uid"].as_int(); - CMStringA m_szUid = reply.data()["uid"].as_mstring(); - setString(DBKEY_ID, m_szUid); } - auto *pReq = CreateRequestGQL(FB_API_QUERY_CONTACTS); - pReq << CHAR_PARAM("query_params", "{\"0\":[\"user\"],\"1\":\"" FB_API_CONTACTS_COUNT "\"}"); - pReq->CalcSig(); - - JsonReply reply(ExecuteRequest(pReq)); - if (reply.error()) { -FAIL: - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)m_iStatus, m_iDesiredStatus); - - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); - return; - } + if (!RefreshContacts()) + goto FAIL; // connect to MQTT server - if (!MqttConnect()) + NETLIBOPENCONNECTION nloc = {}; + nloc.szHost = "mqtt.facebook.com"; + nloc.wPort = 443; + nloc.flags = NLOCF_SSL | NLOCF_V2; + m_mqttConn = Netlib_OpenConnection(m_hNetlibUser, &nloc); + if (m_mqttConn == nullptr) { + debugLogA("connection failed, exiting"); goto FAIL; + } // send initial packet - MqttOpen(); + MqttLogin(); __int64 startTime = GetTickCount64(); @@ -200,7 +257,13 @@ void FacebookProto::OnPublishP(FbThriftReader &rdr) assert(fieldId == 1); assert(rdr.readInt32(u32)); - debugLogA("Presence from user %lld => %d", userId, u32); + auto *pUser = FindUser(userId); + if (pUser == nullptr) + debugLogA("Skipping presence from unknown user %lld", userId); + else { + debugLogA("Presence from user %lld => %d", userId, u32); + setWord(pUser->hContact, "Status", (u32 != 0) ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); + } assert(rdr.readField(fieldType, fieldId)); assert(fieldType == FB_THRIFT_TYPE_I64); diff --git a/protocols/Facebook/src/thrift.cpp b/protocols/Facebook/src/thrift.cpp index c9b520aa90..202eb31569 100644 --- a/protocols/Facebook/src/thrift.cpp +++ b/protocols/Facebook/src/thrift.cpp @@ -235,7 +235,7 @@ bool FbThriftReader::readIntV(uint64_t &val) if (!readByte(b)) return false; - val |= ((b & 0x7F) << i); + val |= (uint64_t(b & 0x7F) << i); i += 7; } while ((b & 0x80) != 0); |