summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/VKontakte/src/vk_chats.cpp196
-rw-r--r--protocols/VKontakte/src/vk_proto.cpp1
-rw-r--r--protocols/VKontakte/src/vk_proto.h6
-rw-r--r--protocols/VKontakte/src/vk_thread.cpp49
4 files changed, 197 insertions, 55 deletions
diff --git a/protocols/VKontakte/src/vk_chats.cpp b/protocols/VKontakte/src/vk_chats.cpp
index d7865e3f00..ce530670be 100644
--- a/protocols/VKontakte/src/vk_chats.cpp
+++ b/protocols/VKontakte/src/vk_chats.cpp
@@ -75,16 +75,15 @@ void CVkProto::RetrieveChatInfo(CVkChatInfo *cc)
{
CMStringA szQuery("return { ");
- // retrieve title if empty
- if (!lstrlen(cc->m_tszTitle))
- szQuery.AppendFormat("\"info\": API.messages.getChat({\"chat_id\":%d}),", cc->m_chatid);
+ // retrieve title & owner id
+ szQuery.AppendFormat("\"info\": API.messages.getChat({\"chat_id\":%d}),", cc->m_chatid);
// retrieve users
- szQuery.AppendFormat("\"users\": API.messages.getChatUsers({\"chat_id\":%d, \"fields\":\"uid,first_name,last_name,photo\"})", cc->m_chatid);
+ szQuery.AppendFormat("\"users\": API.messages.getChatUsers({\"chat_id\":%d, \"fields\":\"uid,first_name,last_name\"})", cc->m_chatid);
if (!cc->m_bHistoryRead) {
cc->m_bHistoryRead = true;
- szQuery.AppendFormat(",\"msgs\": API.messages.getHistory({\"chat_id\":%d, \"count\":\"20\", \"rev\":\"0\"})", cc->m_chatid);
+ szQuery.AppendFormat(",\"msgs\": API.messages.getHistory({\"chat_id\":%d, \"count\":\"20\", \"rev\":\"1\"})", cc->m_chatid);
}
szQuery.Append("};");
@@ -117,26 +116,23 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe
JSONNODE *info = json_get(pResponse, "info");
if (info != NULL) {
ptrT tszTitle(json_as_string(json_get(info, "title")));
- cc->m_tszTitle = mir_tstrdup(tszTitle);
+ if (lstrcmp(tszTitle, cc->m_tszTitle)) {
+ cc->m_tszTitle = mir_tstrdup(tszTitle);
- cc->m_admin_id = json_as_int(json_get(info, "admin_id"));
-
- JSONNODE *userids = json_as_array(json_get(info, "users"));
- if (userids) {
- for (int i = 0;; i++) {
- int uid = json_as_int(json_at(userids, i));
- if (uid == 0)
- break;
-
- CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid);
- if (cu == NULL)
- cc->m_users.insert(cu = new CVkChatUser(uid));
- }
+ GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_TOPIC };
+ GCEVENT gce = { sizeof(GCEVENT), &gcd };
+ gce.ptszText = tszTitle;
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
}
+
+ cc->m_admin_id = json_as_int(json_get(info, "admin_id"));
}
JSONNODE *users = json_as_array(json_get(pResponse, "users"));
if (users != NULL) {
+ for (int i = 0; i < cc->m_users.getCount(); i++)
+ cc->m_users[i].m_bDel = true;
+
for (int i = 0;; i++) {
JSONNODE *pUser = json_at(users, i);
if (pUser == NULL)
@@ -146,9 +142,13 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe
TCHAR tszId[20];
_itot(uid, tszId, 10);
+ bool bNew = false;
CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid);
- if (cu == NULL)
+ if (cu == NULL) {
cc->m_users.insert(cu = new CVkChatUser(uid));
+ bNew = true;
+ }
+ cu->m_bDel = false;
ptrT fName(json_as_string(json_get(pUser, "first_name")));
ptrT lName(json_as_string(json_get(pUser, "last_name")));
@@ -157,13 +157,29 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe
cu->m_tszImage = json_as_string(json_get(pUser, "photo"));
- GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_JOIN };
+ if (bNew) {
+ GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_JOIN };
+ GCEVENT gce = { sizeof(GCEVENT), &gcd };
+ gce.bIsMe = uid == m_myUserId;
+ gce.ptszUID = tszId;
+ gce.ptszNick = tszNick;
+ gce.ptszStatus = TranslateTS(sttStatuses[uid == cc->m_admin_id]);
+ gce.dwItemData = (INT_PTR)cu;
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ }
+ }
+
+ for (int i = cc->m_users.getCount() - 1; i >= 0; i--) {
+ CVkChatUser &cu = cc->m_users[i];
+ if (!cu.m_bDel)
+ continue;
+
+ TCHAR tszId[20];
+ _itot(cu.m_uid, tszId, 10);
+
+ GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_PART };
GCEVENT gce = { sizeof(GCEVENT), &gcd };
- gce.bIsMe = uid == m_myUserId;
gce.ptszUID = tszId;
- gce.ptszNick = tszNick;
- gce.ptszStatus = TranslateTS(sttStatuses[uid == cc->m_admin_id]);
- gce.dwItemData = (INT_PTR)cu;
CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
}
}
@@ -175,31 +191,119 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe
if (pMsg == NULL)
break;
- int uid = json_as_int(json_get(pMsg, "from_id"));
- TCHAR tszId[20];
- _itot(uid, tszId, 10);
+ AppendChatMessage(cc->m_chatid, pMsg, true);
+ }
+ }
+}
- CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid);
- if (cu == NULL) {
- cc->m_users.insert(cu = new CVkChatUser(uid));
- cu->m_tszTitle = mir_tstrdup(TranslateT("Uknown"));
- }
+/////////////////////////////////////////////////////////////////////////////////////////
- int iDate = json_as_int(json_get(pMsg, "date"));
- ptrT tszBody(json_as_string(json_get(pMsg, "body")));
+void CVkProto::AppendChatMessage(int id, JSONNODE *pMsg, bool bIsHistory)
+{
+ CVkChatInfo *cc = AppendChat(id, NULL);
+ if (cc == NULL)
+ return;
- JSONNODE *pAttachments = json_get(pMsg, "attachments");
- if (pAttachments != NULL)
- tszBody = mir_tstrdup(CMString(tszBody) + GetAttachmentDescr(pAttachments));
+ int mid = json_as_int(json_get(pMsg, "mid"));
+ int isOut = json_as_int(json_get(pMsg, "out"));
+ if (mid && isOut)
+ m_sendIds.insert((void*)mid);
- GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_MESSAGE };
- GCEVENT gce = { sizeof(GCEVENT), &gcd };
- gce.bIsMe = uid == m_myUserId;
- gce.ptszUID = tszId;
- gce.time = iDate;
- gce.ptszNick = cu->m_tszTitle;
- gce.ptszText = tszBody;
- CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ int uid = json_as_int(json_get(pMsg, "uid"));
+ TCHAR tszId[20];
+ _itot(uid, tszId, 10);
+
+ int msgTime = json_as_int(json_get(pMsg, "date"));
+ time_t now = time(NULL);
+ if (!msgTime || msgTime > now)
+ msgTime = now;
+
+ CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid);
+ if (cu == NULL) {
+ cc->m_users.insert(cu = new CVkChatUser(uid));
+ cu->m_tszTitle = mir_tstrdup(TranslateT("Unknown"));
+ }
+
+ ptrT tszBody(json_as_string(json_get(pMsg, "body")));
+ JSONNODE *pAttachments = json_get(pMsg, "attachments");
+ if (pAttachments != NULL)
+ tszBody = mir_tstrdup(CMString(tszBody) + GetAttachmentDescr(pAttachments));
+
+ GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_MESSAGE };
+ GCEVENT gce = { sizeof(GCEVENT), &gcd };
+ gce.bIsMe = uid == m_myUserId;
+ gce.ptszUID = tszId;
+ gce.time = msgTime;
+ gce.dwFlags = (bIsHistory) ? GCEF_NOTNOTIFY : GCEF_ADDTOLOG;
+ gce.ptszNick = cu->m_tszTitle;
+ gce.ptszText = tszBody;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TCHAR* UnEscapeChatTags(TCHAR* str_in)
+{
+ TCHAR *s = str_in, *d = str_in;
+ while (*s) {
+ if (*s == '%' && s[1] == '%')
+ s++;
+ *d++ = *s++;
+ }
+ *d = 0;
+ return str_in;
+}
+
+int CVkProto::OnChatEvent(WPARAM, LPARAM lParam)
+{
+ GCHOOK* gch = (GCHOOK*)lParam;
+ if (gch == NULL)
+ return 0;
+
+ if (lstrcmpiA(gch->pDest->pszModule, m_szModuleName))
+ return 0;
+
+ CVkChatInfo *cc = NULL;
+ for (int i = 0; i < m_chats.getCount(); i++)
+ if (!lstrcmp(m_chats[i].m_tszId, gch->pDest->ptszID)) {
+ cc = &m_chats[i];
+ break;
+ }
+ if (cc == NULL)
+ return 0;
+
+ switch (gch->pDest->iType) {
+ case GC_USER_MESSAGE:
+ if (m_bOnline && lstrlen(gch->ptszText) > 0) {
+ TCHAR *buf = NEWTSTR_ALLOCA(gch->ptszText);
+ rtrimt(buf);
+ UnEscapeChatTags(buf);
+ ptrA szMsg(mir_utf8encodeT(buf));
+
+ char szId[20];
+ _itoa(cc->m_chatid, szId, 10);
+
+ HttpParam params[] = {
+ { "type", "1" },
+ { "chat_id", szId },
+ { "message", szMsg },
+ { "access_token", m_szAccessToken }
+ };
+ PushAsyncHttpRequest(REQUEST_GET, "/method/messages.send.json", true, &CVkProto::OnSendChatMsg, SIZEOF(params), params);
}
+ break;
+ }
+ return 0;
+}
+
+void CVkProto::OnSendChatMsg(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
+{
+ debugLogA("CVkProto::OnSendChatMsg %d", reply->resultCode);
+ if (reply->resultCode == 200) {
+ JSONROOT pRoot;
+ JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot);
+ if (pResponse != NULL)
+ m_sendIds.insert((HANDLE)json_as_int(pResponse));
}
}
+
diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp
index 65d43eed8c..29740038fd 100644
--- a/protocols/VKontakte/src/vk_proto.cpp
+++ b/protocols/VKontakte/src/vk_proto.cpp
@@ -32,6 +32,7 @@ CVkProto::CVkProto(const char *szModuleName, const TCHAR *ptszUserName) :
CreateProtoService(PS_GETAVATARCAPS, &CVkProto::SvcGetAvatarCaps);
HookProtoEvent(ME_OPT_INITIALISE, &CVkProto::OnOptionsInit);
+ HookProtoEvent(ME_GC_EVENT, &CVkProto::OnChatEvent);
TCHAR descr[512];
mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName);
diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h
index 1cff543e4f..e34bc41fcf 100644
--- a/protocols/VKontakte/src/vk_proto.h
+++ b/protocols/VKontakte/src/vk_proto.h
@@ -31,11 +31,12 @@ struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject
void *pUserInfo;
};
-struct CVkChatUser
+struct CVkChatUser : public MZeroedObject
{
CVkChatUser(int _id) : m_uid(_id) {}
int m_uid;
+ bool m_bDel;
ptrT m_tszTitle, m_tszImage;
};
@@ -227,8 +228,11 @@ private:
OBJLIST<CVkChatInfo> m_chats;
CVkChatInfo* AppendChat(int id, JSONNODE *pNode);
+ void AppendChatMessage(int id, JSONNODE *pMsg, bool bIsHistory);
void RetrieveChatInfo(CVkChatInfo*);
void OnReceiveChatInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ int __cdecl OnChatEvent(WPARAM, LPARAM);
+ void OnSendChatMsg(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
CMString GetAttachmentDescr(JSONNODE*);
};
diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp
index 6df0321fd2..d4f48740c8 100644
--- a/protocols/VKontakte/src/vk_thread.cpp
+++ b/protocols/VKontakte/src/vk_thread.cpp
@@ -432,6 +432,12 @@ void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe
if (pMsg == NULL)
continue;
+ int chat_id = json_as_int(json_get(pMsg, "chat_id"));
+ if (chat_id != 0) {
+ AppendChatMessage(chat_id, pMsg, false);
+ continue;
+ }
+
char szMid[40];
int mid = json_as_int(json_get(pMsg, "mid"));
_itoa(mid, szMid, 10);
@@ -521,12 +527,39 @@ void CVkProto::PollUpdates(JSONNODE *pUpdates)
for (int i=0; (pChild = json_at(pUpdates, i)) != NULL; i++) {
switch (json_as_int( json_at(pChild, 0))) {
case VKPOLL_MSG_ADDED: // new message
- msgid = json_as_int( json_at(pChild, 1));
- flags = json_as_int( json_at(pChild, 2));
+ msgid = json_as_int(json_at(pChild, 1));
+ flags = json_as_int(json_at(pChild, 2));
// skip outgoing messages sent from a client
- if ((flags & VKFLAG_MSGOUTBOX) && !(flags & VKFLAG_MSGCHAT))
- break;
+ if (flags & VKFLAG_MSGOUTBOX) {
+ if (!(flags & VKFLAG_MSGCHAT))
+ break;
+
+ // my chat message
+ int from_id = json_as_int(json_at(pChild, 3));
+ if (from_id > 2000000000) {
+ from_id -= 2000000000;
+ CVkChatInfo *cc = m_chats.find((CVkChatInfo*)&from_id);
+ if (cc != NULL) {
+ TCHAR tszId[20];
+ _itot(m_myUserId, tszId, 10);
+ ptrT tszBody(json_as_string(json_at(pChild, 6)));
+
+ CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&m_myUserId);
+ LPCTSTR ptszNick = (cu) ? cu->m_tszTitle : TranslateT("me");
+
+ GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_MESSAGE };
+ GCEVENT gce = { sizeof(GCEVENT), &gcd };
+ gce.bIsMe = true;
+ gce.ptszUID = tszId;
+ gce.time = time(0);
+ gce.dwFlags = GCEF_ADDTOLOG;
+ gce.ptszNick = ptszNick;
+ gce.ptszText = tszBody;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ }
+ }
+ }
if ( !CheckMid(msgid)) {
if ( !mids.IsEmpty())
@@ -554,10 +587,10 @@ void CVkProto::PollUpdates(JSONNODE *pUpdates)
break;
case VKPOLL_CHAT_CHANGED:
- int chatid = json_as_int(json_at(pChild, 1));
- int isSelf = json_as_int(json_at(pChild, 2));
- if (!isSelf)
- AppendChat(chatid, NULL);
+ int chat_id = json_as_int(json_at(pChild, 1));
+ CVkChatInfo *cc = m_chats.find((CVkChatInfo*)&chat_id);
+ if (cc)
+ RetrieveChatInfo(cc);
break;
}
}