From a597717faf025d280206a03b582057b45c4b6f9f Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Wed, 19 Dec 2012 11:30:59 +0000 Subject: - second approach of group chat support git-svn-id: http://svn.miranda-ng.org/main/trunk@2766 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Skype/src/skype_chat.cpp | 269 +++++++++++++++++++++++++++--- protocols/Skype/src/skype_dialogs.cpp | 10 +- protocols/Skype/src/skype_events.cpp | 79 ++++++--- protocols/Skype/src/skype_proto.cpp | 3 + protocols/Skype/src/skype_proto.h | 22 ++- protocols/Skype/src/skype_subclassing.cpp | 9 + protocols/Skype/src/skype_subclassing.h | 12 +- 7 files changed, 345 insertions(+), 59 deletions(-) (limited to 'protocols/Skype/src') diff --git a/protocols/Skype/src/skype_chat.cpp b/protocols/Skype/src/skype_chat.cpp index 358c435cc9..25cd462268 100644 --- a/protocols/Skype/src/skype_chat.cpp +++ b/protocols/Skype/src/skype_chat.cpp @@ -1,5 +1,7 @@ #include "skype_proto.h" #include +#include +#include bool CSkypeProto::IsChatRoom(HANDLE hContact) { @@ -33,7 +35,7 @@ void CSkypeProto::ChatPrepare(HANDLE hItem, HWND hwndList) } } -void CSkypeProto::FillChatList(HANDLE hItem, HWND hwndList, SEStringList &chatTargets) +void CSkypeProto::GetInviteContacts(HANDLE hItem, HWND hwndList, SEStringList &chatTargets) { if (hItem == NULL) hItem = (HANDLE)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0); @@ -43,7 +45,7 @@ void CSkypeProto::FillChatList(HANDLE hItem, HWND hwndList, SEStringList &chatTa if (IsHContactGroup(hItem)) { HANDLE hItemT = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); - if (hItemT) this->FillChatList(hItemT, hwndList, chatTargets); + if (hItemT) this->GetInviteContacts(hItemT, hwndList, chatTargets); } else { @@ -70,11 +72,11 @@ void CSkypeProto::FillChatList(HANDLE hItem, HWND hwndList, SEStringList &chatTa static const COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; -void CSkypeProto::RegisterChat() +void CSkypeProto::InitChat() { GCREGISTER gcr = {0}; gcr.cbSize = sizeof(gcr); - gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR;// | GC_TCHAR; + gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR; gcr.iMaxText = 0; gcr.nColors = 16; gcr.pColors = (COLORREF*)crCols; @@ -82,26 +84,51 @@ void CSkypeProto::RegisterChat() gcr.pszModule = this->m_szModuleName; CallServiceSync(MS_GC_REGISTER, 0, (LPARAM)&gcr); - //YHookEvent(ME_GC_EVENT, &CYahooProto::OnGCEventHook); - //YHookEvent(ME_GC_BUILDMENU, &CYahooProto::OnGCMenuHook); + this->HookEvent(ME_GC_EVENT, &CSkypeProto::OnGCEventHook); + this->HookEvent(ME_GC_BUILDMENU, &CSkypeProto::OnGCMenuHook); } -void CSkypeProto::StartChat(SEStringList &chatTargets) +void CSkypeProto::StartChat(HANDLE hContact, SEStringList &chatTargets) { - CConversation::Ref conference; - g_skype->CreateConference(conference); - conference->AddConsumers(chatTargets); + char *chatID; + SEString data; + CConversation::Ref conversation; - SEString identity; - conference->GetPropIdentity(identity); - char *chatID = ::mir_strdup((const char *)identity); + if (hContact) + { + chatID = ::DBGetString(hContact, this->m_szModuleName, "ChatRoomID"); + g_skype->GetConversationByIdentity(chatID, conversation); + conversation->GetJoinBlob(data); + char *blob = ::mir_strdup((const char *)data); + g_skype->GetConversationByBlob(blob, conversation, false); + conversation->Join(); + + CParticipant::Refs participants; + conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); + for (uint i = 0; i < participants.size(); i++) + { + participants[i]->GetPropIdentity(data); + chatTargets.append(data); + } + } + else if ( !g_skype->GetConversationByParticipants(chatTargets, conversation)) + { + g_skype->CreateConference(conversation); + conversation->SetOption(CConversation::P_OPT_JOINING_ENABLED, true); + conversation->AddConsumers(chatTargets); + + conversation->GetPropIdentity(data); + chatID = ::mir_strdup((const char *)data); + } + + conversation->GetPropDisplayname(data); + char *chatName = ::mir_utf8decodeA((const char *)data); GCSESSION gcw = {0}; gcw.cbSize = sizeof(gcw); - //gcw.dwFlags = GC_TCHAR; gcw.iType = GCW_CHATROOM; - gcw.pszModule = m_szModuleName; - gcw.pszName = "Chat"; + gcw.pszModule = this->m_szModuleName; + gcw.pszName = chatName; gcw.pszID = chatID; ::CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); @@ -110,13 +137,12 @@ void CSkypeProto::StartChat(SEStringList &chatTargets) GCEVENT gce = {0}; gce.cbSize = sizeof(GCEVENT); - //gce.dwFlags = GC_TCHAR; gce.pDest = &gcd; - gce.pszStatus = Translate("Me"); + gce.pszStatus = ::Translate("Me"); ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); gcd.iType = GC_EVENT_ADDGROUP; - gce.pszStatus = Translate("Others"); + gce.pszStatus = ::Translate("Others"); ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); for (uint i = 0; i < chatTargets.size(); i++) @@ -133,5 +159,210 @@ void CSkypeProto::StartChat(SEStringList &chatTargets) ::CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); ::CallServiceSync(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce); + ::mir_free(chatName); ::mir_free(chatID); +} + +void CSkypeProto::ChatEvent(const char *chatID, const char *sid, int evt, const char *msg) +{ + char *idt = ::mir_strdup(chatID); + char *snt = ::mir_strdup(sid); + + HANDLE hContact = this->GetContactBySid(sid); + char *nick = hContact ? (char *)::CallService(MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM(hContact), 0) : snt; + + GCDEST gcd = { m_szModuleName, { NULL }, evt }; + gcd.pszID = idt; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(gce); + gce.dwFlags = GCEF_ADDTOLOG; + gce.pDest = &gcd; + gce.pszNick = nick; + gce.pszUID = snt; + gce.bIsMe = ::stricmp(sid, this->login) == 0; + gce.pszStatus = gce.bIsMe ? ::Translate("Me") : ::Translate("Others"); + gce.pszText = msg; + gce.time = time(NULL); + ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); + + ::mir_free(snt); + ::mir_free(idt); +} + +INT_PTR __cdecl CSkypeProto::OnJoinChat(WPARAM wParam, LPARAM) +{ + HANDLE hContact = (HANDLE)wParam; + SEStringList list; + this->StartChat(hContact, list); + + return 0; +} + +INT_PTR __cdecl CSkypeProto::OnLeaveChat(WPARAM wParam, LPARAM) +{ + HANDLE hContact = (HANDLE)wParam; + char *chatID = ::DBGetString(hContact, this->m_szModuleName, "ChatID"); + this->ChatLeave(chatID); + + return 0; +} + +void CSkypeProto::ChatLeave(const char *chatID) +{ + char *idt = ::mir_strdup(chatID); + + GCDEST gcd = { m_szModuleName, { NULL }, GC_EVENT_CONTROL }; + gcd.pszID = idt; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + //gce.dwFlags = GCEF_REMOVECONTACT; + gce.pDest = &gcd; + ::CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce); + ::CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce); + + ::mir_free(idt); +} + +int __cdecl CSkypeProto::OnGCEventHook(WPARAM, LPARAM lParam) +{ + GCHOOK *gch = (GCHOOK *)lParam; + if (!gch) return 1; + + if (::strcmp(gch->pDest->pszModule, this->m_szModuleName)) + return 0; + + char *chatID = ::mir_strdup(gch->pDest->pszID); + char *sid = ::mir_strdup(gch->pszUID); + + switch (gch->pDest->iType) + { + case GC_SESSION_TERMINATE: + { + CConversation::Ref conversation; + if (g_skype->GetConversationByIdentity(chatID, conversation, false)) + { + Participant::Refs participants; + conversation->GetParticipants(participants, CConversation::MYSELF); + participants[0]->Retire(); + } + } + break; + + case GC_USER_MESSAGE: + if (gch->pszText && gch->pszText[0]) + { + CConversation::Ref conversation; + if (g_skype->GetConversationByIdentity(chatID, conversation, false)) + { + CMessage::Ref message; + char *text = ::mir_utf8encode(gch->pszText); + conversation->PostText(text, message); + } + } + break; + + case GC_USER_CHANMGR: + DialogBoxParam( + g_hInstance, + MAKEINTRESOURCE(IDD_CHATROOM_INVITE), + NULL, + CSkypeProto::InviteToChatProc, + LPARAM(new InviteChatParam(chatID, NULL, this))); + break; + + case GC_USER_PRIVMESS: + ::CallService(MS_MSG_SENDMESSAGE, (WPARAM)this->GetContactBySid(sid), 0); + break; + + case GC_USER_LOGMENU: + switch(gch->dwData) + { + case 10: + ::DialogBoxParam( + g_hInstance, + MAKEINTRESOURCE(IDD_CHATROOM_INVITE), + NULL, + CSkypeProto::InviteToChatProc, + LPARAM(new InviteChatParam(chatID, NULL, this))); + break; + + case 20: + this->ChatLeave(chatID); + break; + } + break; + + case GC_USER_NICKLISTMENU: + switch (gch->dwData) + { + case 10: + ::CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)this->GetContactBySid(sid), 0); + break; + + case 20: + CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)this->GetContactBySid(sid), 0); + break; + + case 110: + this->ChatLeave(chatID); + break; + } + break; + + case GC_USER_TYPNOTIFY: + break; + } + ::mir_free(sid); + ::mir_free(chatID); + + return 0; +} + +int __cdecl CSkypeProto::OnGCMenuHook(WPARAM, LPARAM lParam) +{ + GCMENUITEMS *gcmi = (GCMENUITEMS*) lParam; + + if (gcmi == NULL || ::stricmp(gcmi->pszModule, this->m_szModuleName)) return 0; + + if (gcmi->Type == MENU_ON_LOG) + { + static const struct gc_item Items[] = + { + { TranslateT("&Invite user..."), 10, MENU_ITEM, FALSE }, + { TranslateT("&Leave chat session"), 20, MENU_ITEM, FALSE } + }; + gcmi->nItems = SIZEOF(Items); + gcmi->Item = (gc_item*)Items; + } + else if (gcmi->Type == MENU_ON_NICKLIST) + { + char* id = mir_t2a(gcmi->pszUID); + if (!::stricmp(this->login, id)) + { + static const struct gc_item Items[] = + { + { TranslateT("User &details"), 10, MENU_ITEM, FALSE }, + { TranslateT("User &history"), 20, MENU_ITEM, FALSE }, + { _T(""), 100, MENU_SEPARATOR, FALSE }, + { TranslateT("&Leave chat session"), 110, MENU_ITEM, FALSE } + }; + gcmi->nItems = SIZEOF(Items); + gcmi->Item = (gc_item*)Items; + } + else + { + static const struct gc_item Items[] = + { + { TranslateT("User &details"), 10, MENU_ITEM, FALSE }, + { TranslateT("User &history"), 20, MENU_ITEM, FALSE } + }; + gcmi->nItems = SIZEOF(Items); + gcmi->Item = (gc_item*)Items; + } + mir_free(id); + } + + return 0; } \ No newline at end of file diff --git a/protocols/Skype/src/skype_dialogs.cpp b/protocols/Skype/src/skype_dialogs.cpp index 1505a08c9f..a2464e6843 100644 --- a/protocols/Skype/src/skype_dialogs.cpp +++ b/protocols/Skype/src/skype_dialogs.cpp @@ -471,13 +471,13 @@ INT_PTR CALLBACK CSkypeProto::InviteToChatProc(HWND hwndDlg, UINT msg, WPARAM wP case CLN_NEWCONTACT: if (param && (nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0) { - param->ppro->ChatValidateContact(nmc->hItem, nmc->hdr.hwndFrom); + param->ppro->ChatValidateContact(nmc->hItem, nmc->hdr.hwndFrom); } break; case CLN_LISTREBUILT: if (param) - param->ppro->ChatPrepare(NULL, nmc->hdr.hwndFrom); + param->ppro->ChatPrepare(NULL, nmc->hdr.hwndFrom); break; } } @@ -514,9 +514,9 @@ INT_PTR CALLBACK CSkypeProto::InviteToChatProc(HWND hwndDlg, UINT msg, WPARAM wP char sid[SKYPE_SID_LIMIT] = ""; HWND hwndList = ::GetDlgItem(hwndDlg, IDC_CCLIST); - SEStringList chatTargets; - param->ppro->FillChatList(NULL, hwndList, chatTargets); - param->ppro->StartChat(chatTargets); + SEStringList inviteContacts; + param->ppro->GetInviteContacts(NULL, hwndList, inviteContacts); + param->ppro->StartChat(NULL, inviteContacts); } EndDialog(hwndDlg, IDOK); diff --git a/protocols/Skype/src/skype_events.cpp b/protocols/Skype/src/skype_events.cpp index 8ceb136173..a3a89b9a6e 100644 --- a/protocols/Skype/src/skype_events.cpp +++ b/protocols/Skype/src/skype_events.cpp @@ -2,7 +2,8 @@ int CSkypeProto::OnModulesLoaded(WPARAM, LPARAM) { - this->RegisterChat(); + this->InitChat(); + this->HookEvent(ME_OPT_INITIALISE, &CSkypeProto::OnOptionsInit); this->HookEvent(ME_USERINFO_INITIALISE, &CSkypeProto::OnUserInfoInit); @@ -28,10 +29,10 @@ int CSkypeProto::OnContactDeleted(WPARAM wParam, LPARAM lParam) void CSkypeProto::OnMessageSended(CConversation::Ref conversation, CMessage::Ref message) { - uint timestamp; - message->GetPropTimestamp(timestamp); + SEString data; - SEString data; + uint timestamp; + message->GetPropTimestamp(timestamp); message->GetPropAuthor(data); char *sid = ::mir_strdup((const char*)data); @@ -39,43 +40,67 @@ void CSkypeProto::OnMessageSended(CConversation::Ref conversation, CMessage::Ref message->GetPropBodyXml(data); char *text = ::mir_strdup((const char*)data); - Participant::Refs participants; - conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); + CConversation::TYPE type; + conversation->GetPropType(type); + if (type == CConversation::DIALOG) + { + CParticipant::Refs participants; + conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); - for (uint i = 0; i < participants.size(); i ++) - { - participants[i]->GetPropIdentity(data); - char *contactSid = ::mir_strdup((const char *)data); - //todo: get nickname - this->RaiseMessageSendedEvent( - timestamp, - contactSid, - contactSid, - text); + for (uint i = 0; i < participants.size(); i ++) + { + participants[i]->GetPropIdentity(data); + char *contactSid = ::mir_strdup((const char *)data); + //todo: get nickname + this->RaiseMessageSendedEvent( + timestamp, + contactSid, + contactSid, + text); + } + } + else + { + conversation->GetPropIdentity(data); + char *chatID = ::mir_utf8encode((const char*)data); + + this->ChatEvent(chatID, sid, /*GC_EVENT_MESSAGE*/0x0040, text); } } void CSkypeProto::OnMessageReceived(CConversation::Ref conversation, CMessage::Ref message) { + SEString data; + uint timestamp; message->GetPropTimestamp(timestamp); - SEString data; - message->GetPropAuthor(data); char *sid = ::mir_strdup((const char*)data); + + message->GetPropBodyXml(data); + char *text = ::mir_utf8decodeA((const char*)data); - message->GetPropAuthorDisplayname(data); - char *nick = ::mir_strdup((const char*)data); + CConversation::TYPE type; + conversation->GetPropType(type); + if (type == CConversation::DIALOG) + { + message->GetPropAuthorDisplayname(data); + char *nick = ::mir_strdup((const char*)data); - message->GetPropBodyXml(data); - char *text = ::mir_strdup((const char*)data); + this->RaiseMessageReceivedEvent( + (DWORD)timestamp, + sid, + nick, + text); + } + else + { + conversation->GetPropIdentity(data); + char *chatID = ::mir_strdup((const char*)data); - this->RaiseMessageReceivedEvent( - (DWORD)timestamp, - sid, - nick, - text); + this->ChatEvent(chatID, sid, /*GC_EVENT_MESSAGE*/ 0x0040, text); + } /*const char *msg = (const char*)propValues[2]; int len = ::strlen(msg) + 8; diff --git a/protocols/Skype/src/skype_proto.cpp b/protocols/Skype/src/skype_proto.cpp index aba0cc485b..1e33a9a5a7 100644 --- a/protocols/Skype/src/skype_proto.cpp +++ b/protocols/Skype/src/skype_proto.cpp @@ -18,6 +18,9 @@ CSkypeProto::CSkypeProto(const char* protoName, const TCHAR* userName) this->SetAllContactStatus(ID_STATUS_OFFLINE); this->CreateService(PS_CREATEACCMGRUI, &CSkypeProto::OnAccountManagerInit); + // Chat + this->CreateService(PS_JOINCHAT, &CSkypeProto::OnJoinChat); + this->CreateService(PS_LEAVECHAT, &CSkypeProto::OnLeaveChat); // Avatar API this->CreateService(PS_GETAVATARINFOT, &CSkypeProto::GetAvatarInfo); this->CreateService(PS_GETAVATARCAPS, &CSkypeProto::GetAvatarCaps); diff --git a/protocols/Skype/src/skype_proto.h b/protocols/Skype/src/skype_proto.h index 6d849abf35..ba35c31fa5 100644 --- a/protocols/Skype/src/skype_proto.h +++ b/protocols/Skype/src/skype_proto.h @@ -63,15 +63,15 @@ const SettingItem setting[]={ struct InviteChatParam { - TCHAR *id; + char *id; HANDLE hContact; CSkypeProto *ppro; - InviteChatParam(const TCHAR *id, HANDLE hContact, CSkypeProto *ppro) - : id(mir_tstrdup(id)), hContact(hContact), ppro(ppro) {} + InviteChatParam(const char *id, HANDLE hContact, CSkypeProto *ppro) + : id(::mir_strdup(id)), hContact(hContact), ppro(ppro) {} ~InviteChatParam() - { mir_free(id); } + { ::mir_free(id); } }; struct CSkypeProto : public PROTO_INTERFACE, public MZeroedObject @@ -197,10 +197,18 @@ protected: void ChatValidateContact(HANDLE hItem, HWND hwndList); void ChatPrepare(HANDLE hItem, HWND hwndList); - void FillChatList(HANDLE hItem, HWND hwndList, SEStringList &chatTargets); + void GetInviteContacts(HANDLE hItem, HWND hwndList, SEStringList &inviteContacts); - void RegisterChat(); - void StartChat(SEStringList &chatTargets); + void InitChat(); + void StartChat(HANDLE hContact, SEStringList &invitedContacts); + void ChatEvent(const char *chatID, const char *sid, int evt, const char* msg); + void ChatLeave(const char *chatID); + + INT_PTR __cdecl OnJoinChat(WPARAM wParam, LPARAM); + INT_PTR __cdecl OnLeaveChat(WPARAM wParam, LPARAM); + + int __cdecl OnGCMenuHook(WPARAM, LPARAM lParam); + int __cdecl OnGCEventHook(WPARAM, LPARAM lParam); // contacts void UpdateContactAboutText(HANDLE hContact, CContact::Ref contact); diff --git a/protocols/Skype/src/skype_subclassing.cpp b/protocols/Skype/src/skype_subclassing.cpp index d8843a800f..5eb2882e4d 100644 --- a/protocols/Skype/src/skype_subclassing.cpp +++ b/protocols/Skype/src/skype_subclassing.cpp @@ -28,6 +28,11 @@ CConversation* CSkype::newConversation(int oid) return new CConversation(oid, this); } +CParticipant* CSkype::newParticipant(int oid) +{ + return new CParticipant(oid, this); +} + CMessage* CSkype::newMessage(int oid) { return new CMessage(oid, this); @@ -163,6 +168,10 @@ void CContactSearch::SetOnContactFindedCallback(OnContactFinded callback) this->ContactFindedCallback = callback; } +// CParticipant + +CParticipant::CParticipant(unsigned int oid, SERootObject* root) : Participant(oid, root) { } + // CContact CContact::CContact(unsigned int oid, SERootObject* root) : Contact(oid, root) diff --git a/protocols/Skype/src/skype_subclassing.h b/protocols/Skype/src/skype_subclassing.h index f2d571ae98..b2798316e9 100644 --- a/protocols/Skype/src/skype_subclassing.h +++ b/protocols/Skype/src/skype_subclassing.h @@ -19,6 +19,15 @@ public: CMessage(unsigned int oid, SERootObject* root); }; +class CParticipant : public Participant +{ +public: + typedef DRef Ref; + typedef DRefs Refs; + + CParticipant(unsigned int oid, SERootObject* root); +}; + class CConversation : public Conversation { public: @@ -135,7 +144,8 @@ public: CContactGroup* newContactGroup(int oid); CConversation* newConversation(int oid); CContactSearch* newContactSearch(int oid); - CContact* newContact(int oid); + CParticipant* newParticipant(int oid); + CContact* newContact(int oid); CMessage* newMessage(int oid); CConversation::Refs inbox; -- cgit v1.2.3