summaryrefslogtreecommitdiff
path: root/protocols/MSN/src/msn_chat.cpp
diff options
context:
space:
mode:
authorPiotr Piastucki <leech.miranda@gmail.com>2015-05-14 15:24:53 +0000
committerPiotr Piastucki <leech.miranda@gmail.com>2015-05-14 15:24:53 +0000
commitb7a1174511c3b7fad5b81a54bb4647662d94031c (patch)
tree91b3f36fd78ae9b481cb11d8602e61a79c388d04 /protocols/MSN/src/msn_chat.cpp
parent01b66588ca510b49be5a06d2bfb5bd28b4416030 (diff)
Updated for partial MSNP24 protocol support, for detailed changes see MSNP24 branch.
git-svn-id: http://svn.miranda-ng.org/main/trunk@13589 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/MSN/src/msn_chat.cpp')
-rw-r--r--protocols/MSN/src/msn_chat.cpp351
1 files changed, 293 insertions, 58 deletions
diff --git a/protocols/MSN/src/msn_chat.cpp b/protocols/MSN/src/msn_chat.cpp
index 0c050204b3..e928f7f403 100644
--- a/protocols/MSN/src/msn_chat.cpp
+++ b/protocols/MSN/src/msn_chat.cpp
@@ -25,6 +25,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "msn_proto.h"
#include <m_history.h>
+static const TCHAR *m_ptszRoles[] = {
+ _T("admin"),
+ _T("user")
+};
+
MCONTACT CMsnProto::MSN_GetChatInernalHandle(MCONTACT hContact)
{
MCONTACT result = hContact;
@@ -38,14 +43,20 @@ MCONTACT CMsnProto::MSN_GetChatInernalHandle(MCONTACT hContact)
return result;
}
-int CMsnProto::MSN_ChatInit(ThreadData *info)
+int CMsnProto::MSN_ChatInit(GCThreadData *info, const char *pszID, const char *pszTopic)
{
- InterlockedIncrement(&m_chatID);
- _ltot(m_chatID, info->mChatID, 10);
+ char *szNet, *szEmail;
+
+ _tcsncpy(info->mChatID, _A2T(pszID), SIZEOF(info->mChatID));
+ parseWLID(NEWSTR_ALLOCA(pszID), &szNet, &szEmail, NULL);
+ info->netId = atoi(szNet);
+ strncpy(info->szEmail, szEmail, sizeof(info->szEmail));
TCHAR szName[512];
- mir_sntprintf(szName, SIZEOF(szName), _T("%s %s%s"),
- m_tszUserName, TranslateT("Chat #"), info->mChatID);
+ InterlockedIncrement(&m_chatID);
+ if (*pszTopic) _tcsncpy(szName, _A2T(pszTopic), SIZEOF(szName));
+ else mir_sntprintf(szName, SIZEOF(szName), _T("%s %s%d"),
+ m_tszUserName, TranslateT("Chat #"), m_chatID);
GCSESSION gcw = { sizeof(gcw) };
gcw.iType = GCW_CHATROOM;
@@ -56,19 +67,10 @@ int CMsnProto::MSN_ChatInit(ThreadData *info)
GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_ADDGROUP };
GCEVENT gce = { sizeof(gce), &gcd };
- gce.ptszStatus = TranslateT("Me");
- CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
-
- gcd.iType = GC_EVENT_JOIN;
- gce.ptszUID = mir_a2t(MyOptions.szEmail);
- gce.ptszNick = GetContactNameT(NULL);
- gce.time = 0;
- gce.bIsMe = TRUE;
- CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
-
- gcd.iType = GC_EVENT_ADDGROUP;
- gce.ptszStatus = TranslateT("Others");
- CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ for (int j = 0; j < SIZEOF(m_ptszRoles); j++) {
+ gce.ptszStatus = m_ptszRoles[j];
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ }
gcd.iType = GC_EVENT_CONTROL;
CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
@@ -79,35 +81,70 @@ int CMsnProto::MSN_ChatInit(ThreadData *info)
return 0;
}
-void CMsnProto::MSN_ChatStart(ThreadData* info)
+void CMsnProto::MSN_ChatStart(ezxml_t xmli)
{
- if (info->mChatID[0] != 0)
- return;
+ const char *pszID, *pszCreator;
+ GCThreadData* info;
+ int j;
+
+ if (!strcmp(xmli->txt, "thread")) return;
+
+ // If Chat ID already exists, don'T create a new one
+ pszID = ezxml_txt(ezxml_child(xmli, "id"));
+ if (!(*pszID && (info = MSN_GetThreadByChatId(_A2T(pszID)))))
+ {
+ info = new GCThreadData;
+ {
+ mir_cslock lck(m_csThreads);
+ m_arGCThreads.insert(info);
+ }
- MSN_StartStopTyping(info, false);
+ MSN_ChatInit(info, pszID, ezxml_txt(ezxml_get(xmli, "properties", 0, "topic", -1)));
+ MSN_StartStopTyping(info, false);
+ } else {
+ GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_CONTROL };
+ GCEVENT gce = { sizeof(gce), &gcd };
+ CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+ }
- MSN_ChatInit(info);
+ pszCreator = ezxml_txt(ezxml_get(xmli, "properties", 0, "creator", -1));
- // add all participants onto the list
- GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_JOIN };
- GCEVENT gce = { sizeof(gce), &gcd };
- gce.dwFlags = GCEF_ADDTOLOG;
- gce.ptszStatus = TranslateT("Others");
- gce.time = time(NULL);
- gce.bIsMe = FALSE;
+ for (ezxml_t memb = ezxml_get(xmli, "members", 0, "member", -1); memb != NULL; memb = ezxml_next(memb)) {
+ const char *mri = ezxml_txt(ezxml_child(memb, "mri"));
+ const char *role = ezxml_txt(ezxml_child(memb, "role"));
+ GCUserItem *gcu = NULL;
- for (int j = 0; j < info->mJoinedContactsWLID.getCount(); j++) {
- MCONTACT hContact = MSN_HContactFromEmail(info->mJoinedContactsWLID[j]);
- TCHAR *wlid = mir_a2t(info->mJoinedContactsWLID[j]);
-
- gce.ptszNick = GetContactNameT(hContact);
- gce.ptszUID = wlid;
- CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ for (j = 0; j < info->mJoinedContacts.getCount(); j++) {
+ if (!strcmp(info->mJoinedContacts[j]->WLID, mri)) {
+ gcu = info->mJoinedContacts[j];
+ break;
+ }
+ }
+ if (!gcu) {
+ gcu = new GCUserItem;
+ info->mJoinedContacts.insert(gcu);
+ strncpy(gcu->WLID, mri, sizeof(gcu->WLID));
+ }
+ _tcscpy(gcu->role, _A2T(role));
+
+ if (pszCreator && !strcmp(mri, pszCreator)) info->mCreator = gcu;
+ char* szEmail, *szNet;
+ parseWLID(NEWSTR_ALLOCA(mri), &szNet, &szEmail, NULL);
+ if (!stricmp(szEmail, GetMyUsername(atoi(szNet))))
+ info->mMe = gcu;
+ gcu->btag = 1;
+ }
- mir_free(wlid);
+ // Remove contacts not on list (not tagged)
+ for (j = 0; j < info->mJoinedContacts.getCount(); j++) {
+ if (!info->mJoinedContacts[j]->btag) {
+ info->mJoinedContacts.remove(j);
+ j--;
+ } else info->mJoinedContacts[j]->btag = 0;
}
}
+
void CMsnProto::MSN_KillChatSession(const TCHAR* id)
{
GCDEST gcd = { m_szModuleName, id, GC_EVENT_CONTROL };
@@ -117,17 +154,171 @@ void CMsnProto::MSN_KillChatSession(const TCHAR* id)
CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
}
-static void ChatInviteUser(ThreadData* info, const char* email)
+void CMsnProto::MSN_Kickuser(GCHOOK *gch)
{
- if (info->mJoinedContactsWLID.getCount()) {
- for (int j = 0; j < info->mJoinedContactsWLID.getCount(); j++) {
- if (_stricmp(info->mJoinedContactsWLID[j], email) == 0)
- return;
+ GCThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
+ msnNsThread->sendPacketPayload("DEL", "MSGR\\THREAD",
+ "<thread><id>%d:%s</id><members><member><mri>%s</mri></member></members></thread>",
+ thread->netId, thread->szEmail, _T2A(gch->ptszUID));
+}
+
+void CMsnProto::MSN_Promoteuser(GCHOOK *gch, const char *pszRole)
+{
+ GCThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
+ msnNsThread->sendPacketPayload("PUT", "MSGR\\THREAD",
+ "<thread><id>%d:%s</id><members><member><mri>%s</mri><role>%s</role></member></members></thread>",
+ thread->netId, thread->szEmail, _T2A(gch->ptszUID), pszRole);
+}
+
+const TCHAR *CMsnProto::MSN_GCGetRole(GCThreadData* thread, const char *pszWLID)
+{
+ if (thread) {
+ for (int j = 0; j < thread->mJoinedContacts.getCount(); j++) {
+ if (!strcmp(thread->mJoinedContacts[j]->WLID, pszWLID)) {
+ return thread->mJoinedContacts[j]->role;
+ }
}
+ }
+ return NULL;
+}
- info->sendPacket("CAL", email);
- info->proto->MSN_ChatStart(info);
+void CMsnProto::MSN_GCProcessThreadActivity(ezxml_t xmli, const TCHAR *mChatID)
+{
+ if (!strcmp(xmli->name, "topicupdate")) {
+ ezxml_t initiator = ezxml_child(xmli, "initiator");
+ GCDEST gcd = { m_szModuleName, mChatID, GC_EVENT_TOPIC};
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+ gce.time = MsnTSToUnixtime(ezxml_txt(ezxml_child(xmli, "eventtime")));
+ gce.ptszUID = initiator?mir_a2t(initiator->txt):NULL;
+ MCONTACT hContInitiator = MSN_HContactFromEmail(initiator->txt);
+ gce.ptszNick = GetContactNameT(hContInitiator);
+ gce.ptszText = mir_a2t(ezxml_txt(ezxml_child(xmli, "value")));
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ mir_free((TCHAR*)gce.ptszUID);
}
+ else if (ezxml_t target = ezxml_child(xmli, "target")) {
+ MCONTACT hContInitiator = NULL;
+ GCDEST gcd = { m_szModuleName, mChatID, 0};
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+
+ if (!strcmp(xmli->name, "deletemember")) {
+ gcd.iType = GC_EVENT_PART;
+ if (ezxml_t initiator = ezxml_child(xmli, "initiator")) {
+ if (strcmp(initiator->txt, target->txt)) {
+ hContInitiator = MSN_HContactFromEmail(initiator->txt);
+ gce.ptszStatus = GetContactNameT(hContInitiator);
+ gcd.iType = GC_EVENT_KICK;
+ }
+ }
+ }
+ else if (!strcmp(xmli->name, "addmember")) {
+ gcd.iType = GC_EVENT_JOIN;
+ }
+ else if (!strcmp(xmli->name, "roleupdate")) {
+ gcd.iType = GC_EVENT_ADDSTATUS;
+ if (ezxml_t initiator = ezxml_child(xmli, "initiator")) {
+ hContInitiator = MSN_HContactFromEmail(initiator->txt);
+ gce.ptszText= GetContactNameT(hContInitiator);
+ }
+ gce.ptszStatus = _T("admin");
+ }
+
+ if (gcd.iType) {
+ gce.time = MsnTSToUnixtime(ezxml_txt(ezxml_child(xmli, "eventtime")));
+ const char *pszTarget = NULL;
+
+ while (target) {
+ switch (gcd.iType)
+ {
+ case GC_EVENT_JOIN:
+ gce.ptszStatus = MSN_GCGetRole(MSN_GetThreadByChatId(mChatID), target->txt);
+ // ..fall through.. //
+ case GC_EVENT_KICK:
+ case GC_EVENT_PART:
+ pszTarget = target->txt;
+ break;
+ case GC_EVENT_ADDSTATUS:
+ case GC_EVENT_REMOVESTATUS:
+ gcd.iType = strcmp(ezxml_txt(ezxml_child(target, "role")), "admin")==0?GC_EVENT_ADDSTATUS:GC_EVENT_REMOVESTATUS;
+ pszTarget = ezxml_txt(ezxml_child(target, "id"));
+ break;
+ }
+ char* szEmail, *szNet;
+ parseWLID(NEWSTR_ALLOCA(pszTarget), &szNet, &szEmail, NULL);
+ gce.bIsMe = !stricmp(szEmail, GetMyUsername(atoi(szNet)));
+ gce.ptszUID = mir_a2t(pszTarget);
+ MCONTACT hContTarget = MSN_HContactFromEmail(pszTarget);
+ gce.ptszNick =GetContactNameT(hContTarget);
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ if ((gcd.iType == GC_EVENT_PART || gcd.iType == GC_EVENT_KICK) && gce.bIsMe) {
+ GCDEST gcd = { m_szModuleName, mChatID, GC_EVENT_CONTROL };
+ GCEVENT gce = { sizeof(gce), &gcd };
+ CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce);
+ break;
+ }
+ target = ezxml_next(target);
+ }
+ mir_free((TCHAR*)gce.ptszUID);
+ }
+ }
+}
+
+void CMsnProto::MSN_GCRefreshThreadsInfo(void)
+{
+ CMStringA buf;
+ MCONTACT hContact;
+ int nThreads = 0;
+
+ for (hContact = db_find_first(m_szModuleName); hContact;
+ hContact = db_find_next(hContact, m_szModuleName))
+ {
+ if (isChatRoom(hContact) != 0) {
+ DBVARIANT dbv;
+ if (getString(hContact, "ChatRoomID", &dbv) == 0) {
+ buf.AppendFormat("<thread><id>%s</id></thread>", dbv.pszVal);
+ nThreads++;
+ db_free(&dbv);
+ }
+ }
+ }
+ if (nThreads)
+ msnNsThread->sendPacketPayload("GET", "MSGR\\THREADS", "<threads>%s</threads>", buf);
+}
+
+void CMsnProto::MSN_GCAddMessage(TCHAR *mChatID, MCONTACT hContact, char *email, time_t ts, bool sentMsg, char *msgBody)
+{
+ GCDEST gcd = { m_szModuleName, mChatID, GC_EVENT_MESSAGE };
+ GCEVENT gce = { sizeof(gce), &gcd };
+ gce.dwFlags = GCEF_ADDTOLOG;
+ gce.ptszUID = mir_a2t(email);
+ gce.ptszNick = GetContactNameT(hContact);
+ gce.time = ts;
+ gce.bIsMe = sentMsg;
+
+ TCHAR* p = mir_utf8decodeT(msgBody);
+ gce.ptszText = EscapeChatTags(p);
+ mir_free(p);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ mir_free((void*)gce.ptszUID);
+ mir_free((void*)gce.ptszText);
+}
+
+
+
+static void ChatInviteUser(ThreadData *thread, GCThreadData* info, const char* wlid)
+{
+ if (info->mJoinedContacts.getCount()) {
+ for (int j = 0; j < info->mJoinedContacts.getCount(); j++) {
+ if (_stricmp(info->mJoinedContacts[j]->WLID, wlid) == 0)
+ return;
+ }
+ }
+ thread->sendPacketPayload("PUT", "MSGR\\THREAD",
+ "<thread><id>%d:%s</id><members><member><mri>%s</mri><role>user</role></member></members></thread>",
+ info->netId, info->szEmail, wlid);
}
static void ChatInviteSend(HANDLE hItem, HWND hwndList, STRLIST &str, CMsnProto *ppro)
@@ -151,7 +342,12 @@ static void ChatInviteSend(HANDLE hItem, HWND hwndList, STRLIST &str, CMsnProto
}
else {
MsnContact *msc = ppro->Lists_Get((MCONTACT)hItem);
- if (msc) str.insertn(msc->email);
+ if (msc) {
+ char szContact[MSN_MAX_EMAIL_LEN];
+
+ sprintf(szContact, "%d:%s", msc->netId, msc->email);
+ str.insertn(msc->email);
+ }
}
}
}
@@ -252,13 +448,13 @@ INT_PTR CALLBACK DlgInviteToChat(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM l
case IDOK:
char tEmail[MSN_MAX_EMAIL_LEN]; tEmail[0] = 0;
- ThreadData *info = NULL;
+ GCThreadData *info = NULL;
if (param->id)
info = param->ppro->MSN_GetThreadByChatId(param->id);
- else if (param->hContact) {
+ /*else if (param->hContact) {
if (!param->ppro->MSN_IsMeByContact(param->hContact, tEmail))
info = param->ppro->MSN_GetThreadByContact(tEmail);
- }
+ }*/
HWND hwndList = GetDlgItem(hwndDlg, IDC_CCLIST);
STRLIST *cont = new STRLIST;
@@ -266,14 +462,28 @@ INT_PTR CALLBACK DlgInviteToChat(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM l
if (info) {
for (int i = 0; i < cont->getCount(); ++i)
- ChatInviteUser(info, (*cont)[i]);
+ ChatInviteUser(param->ppro->msnNsThread, info, (*cont)[i]);
delete cont;
}
else {
+ /*
if (tEmail[0]) cont->insertn(tEmail);
param->ppro->MsgQueue_Add("chat", 'X', NULL, 0, NULL, 0, cont);
if (param->ppro->msnLoggedIn)
param->ppro->msnNsThread->sendPacket("XFR", "SB");
+ */
+ CMStringA buf;
+ int myNetId = param->ppro->GetMyNetID();
+
+ /* Group chats only work for Skype users */
+ buf.AppendFormat("<thread><id></id><members><member><mri>%d:%s</mri><role>admin</role></member>",
+ NETID_SKYPE, param->ppro->GetMyUsername(NETID_SKYPE));
+ for (int i = 0; i < cont->getCount(); ++i) {
+ // TODO: Add support for assigning role in invite dialog maybe?
+ buf.AppendFormat("<member><mri>%s</mri><role>user</role></member>", (*cont)[i]);
+ }
+ buf.Append("</members></thread>");
+ param->ppro->msnNsThread->sendPacketPayload("PUT", "MSGR\\THREAD", buf);
}
EndDialog(hwndDlg, IDOK);
@@ -294,19 +504,23 @@ int CMsnProto::MSN_GCEventHook(WPARAM, LPARAM lParam)
switch (gch->pDest->iType) {
case GC_SESSION_TERMINATE:
{
- ThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
- if (thread != NULL)
- thread->sendTerminate();
+ GCThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
+ if (thread != NULL) {
+ m_arGCThreads.remove(thread);
+ for (int i=0; i < thread->mJoinedContacts.getCount(); i++)
+ delete thread->mJoinedContacts[i];
+ delete thread;
+ }
}
break;
case GC_USER_MESSAGE:
if (gch->ptszText && gch->ptszText[0]) {
- ThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
+ GCThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
if (thread) {
TCHAR* pszMsg = UnEscapeChatTags(NEWTSTR_ALLOCA(gch->ptszText));
rtrimt(pszMsg); // remove the ending linebreak
- thread->sendMessage('N', NULL, NETID_MSN, UTF8(pszMsg), 0);
+ msnNsThread->sendMessage('N', thread->szEmail, thread->netId, UTF8(pszMsg), 0);
DBVARIANT dbv;
int bError = getTString("Nick", &dbv);
@@ -367,6 +581,16 @@ int CMsnProto::MSN_GCEventHook(WPARAM, LPARAM lParam)
CallService(MS_HISTORY_SHOWCONTACTHISTORY, hContact, 0);
break;
+ case 30:
+ MSN_Kickuser(gch);
+ break;
+
+ case 40:
+ {
+ const TCHAR *pszRole = MSN_GCGetRole(MSN_GetThreadByChatId(gch->pDest->ptszID), _T2A(gch->ptszUID));
+ MSN_Promoteuser(gch, (pszRole && !_tcscmp(pszRole, _T("admin")))?"user":"admin");
+ break;
+ }
case 110:
MSN_KillChatSession(gch->pDest->ptszID);
break;
@@ -408,7 +632,7 @@ int CMsnProto::MSN_GCMenuHook(WPARAM, LPARAM lParam)
}
else if (gcmi->Type == MENU_ON_NICKLIST) {
char *email = mir_t2a(gcmi->pszUID);
- if (!_stricmp(MyOptions.szEmail, email)) {
+ if (!_stricmp(GetMyUsername(NETID_SKYPE), email)) {
static const struct gc_item Items[] =
{
{ LPGENT("User &details"), 10, MENU_ITEM, FALSE },
@@ -420,11 +644,22 @@ int CMsnProto::MSN_GCMenuHook(WPARAM, LPARAM lParam)
gcmi->Item = (gc_item*)Items;
}
else {
- static const struct gc_item Items[] =
+ static struct gc_item Items[] =
{
{ LPGENT("User &details"), 10, MENU_ITEM, FALSE },
- { LPGENT("User &history"), 20, MENU_ITEM, FALSE }
+ { LPGENT("User &history"), 20, MENU_ITEM, FALSE },
+ { LPGENT("&Kick user") , 30, MENU_ITEM, FALSE },
+ { LPGENT("&Op user") , 40, MENU_ITEM, FALSE }
};
+ GCThreadData* thread = MSN_GetThreadByChatId(gcmi->pszID);
+ if (thread && thread->mMe && _tcsicmp(thread->mMe->role, _T("admin"))) {
+ Items[2].bDisabled = TRUE;
+ Items[3].bDisabled = TRUE;
+ } else {
+ const TCHAR *pszRole = MSN_GCGetRole(thread, email);
+ if (pszRole && !_tcsicmp(pszRole, _T("admin")))
+ Items[3].pszDesc = LPGENT("&Deop user");
+ }
gcmi->nItems = SIZEOF(Items);
gcmi->Item = (gc_item*)Items;
}