From 34d923a55939cdbb5265696b1e84b22eb3c0c95e Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Fri, 31 May 2013 10:50:56 +0000 Subject: second approach of a chats reworking. Note, new code may not work! git-svn-id: http://svn.miranda-ng.org/main/trunk@4847 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Skype/src/skype_account.cpp | 2 +- protocols/Skype/src/skype_chat.cpp | 585 ++++++++++++++++++++++++++-------- protocols/Skype/src/skype_chat.h | 78 ++++- protocols/Skype/src/skype_events.cpp | 2 +- protocols/Skype/src/skype_proto.cpp | 10 +- protocols/Skype/src/skype_proto.h | 13 + 6 files changed, 532 insertions(+), 158 deletions(-) (limited to 'protocols') diff --git a/protocols/Skype/src/skype_account.cpp b/protocols/Skype/src/skype_account.cpp index 30055b02e3..aa19ea233e 100644 --- a/protocols/Skype/src/skype_account.cpp +++ b/protocols/Skype/src/skype_account.cpp @@ -132,7 +132,7 @@ void CSkypeProto::LogOut() { this->account->SetAvailability(CContact::OFFLINE); this->Log(L"Logout from account"); - this->account->Logout(true); + //this->account->Logout(true); this->SetAllContactStatus(ID_STATUS_OFFLINE); } diff --git a/protocols/Skype/src/skype_chat.cpp b/protocols/Skype/src/skype_chat.cpp index 49ed6a806c..2d7a34fda7 100644 --- a/protocols/Skype/src/skype_chat.cpp +++ b/protocols/Skype/src/skype_chat.cpp @@ -36,6 +36,8 @@ void CSkypeProto::InitChat() this->HookEvent(ME_GC_EVENT, &CSkypeProto::OnGCEventHook); this->HookEvent(ME_GC_BUILDMENU, &CSkypeProto::OnGCMenuHook); + + this->chatList = new ChatList(this); } /// @@ -54,39 +56,47 @@ wchar_t *ChatRoom::Roles[] = //L"Ghost" // ??? }; -int ChatRoom::SortMembers(const ChatMember *p1, const ChatMember *p2) +ChatRoom::ChatRoom(const wchar_t *cid) : members(1, CompareMembers) { - return ::lstrcmpi(p1->sid, p2->sid); + this->cid = ::mir_wstrdup(cid); + this->name = NULL; + this->me = NULL; } -ChatRoom::ChatRoom(const wchar_t *cid) : members(1, SortMembers) +ChatRoom::ChatRoom(const wchar_t *cid, const wchar_t *name, CSkypeProto *ppro) : members(1, CompareMembers) { this->cid = ::mir_wstrdup(cid); + this->name = ::mir_wstrdup(name); + this->ppro = ppro; + // + this->me = new ChatMember(ppro->login); + this->me->nick = ::mir_wstrdup(::TranslateT("me")); + //::db_get_wsa(NULL, ppro->m_szModuleName, "Nick"); } -ChatRoom::ChatRoom(ChatMember *me) : members(1, SortMembers) +ChatRoom::~ChatRoom() { - this->me = me; + if (this->cid != NULL) + ::mir_free(this->cid); + if (this->name != NULL) + ::mir_free(this->name); + if (this->me != NULL) + delete this->me; } void ChatRoom::Start(bool showWindow) { SEString data; - //conversation->GetPropIdentity(data); - //mir_ptr cid( ::mir_utf8decodeW(data)); - - /*conversation->GetPropDisplayname(data); - mir_ptr chatName( ::mir_utf8decodeW(data));*/ - // start chat session GCSESSION gcw = {0}; gcw.cbSize = sizeof(gcw); gcw.iType = GCW_CHATROOM; gcw.dwFlags = GC_TCHAR; gcw.pszModule = ppro->m_szModuleName; - //gcw.ptszName = this->topic; - gcw.ptszID = cid; + gcw.ptszName = this->name; + gcw.ptszID = this->cid; + gcw.dwItemData = (DWORD)this; ::CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); GCDEST gcd = { ppro->m_szModuleName, { NULL }, GC_EVENT_ADDGROUP }; @@ -97,7 +107,7 @@ void ChatRoom::Start(bool showWindow) gce.cbSize = sizeof(GCEVENT); gce.dwFlags = GC_TCHAR; gce.pDest = &gcd; - for (int i = 1; i < SIZEOF(ChatRoom::Roles); i++) + for (int i = 1; i < SIZEOF(ChatRoom::Roles) - 3; i++) { gce.ptszStatus = ::TranslateW(ChatRoom::Roles[i]); ::CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); @@ -109,6 +119,34 @@ void ChatRoom::Start(bool showWindow) ::CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); } +void ChatRoom::Start(const ParticipantRefs &participants, bool showWindow) +{ + SEString data; + + this->Start(showWindow); + + for (uint i = 0; i < participants.size(); i++) + { + participants[i]->GetPropIdentity(data); + ptrW sid = ::mir_utf8decodeW(data); + + ChatMember *member = new ChatMember(sid); + member->rank = participants[i]->GetUintProp(Participant::P_RANK); + + Contact::Ref contact; + this->ppro->GetContact(data, contact); + + Contact::AVAILABILITY status; + contact->GetPropAvailability(status); + member->status = CSkypeProto::SkypeToMirandaStatus(status); + + contact->GetPropFullname(data); + member->nick = ::mir_utf8decodeW(data); + + this->AddMember(member); + } +} + void ChatRoom::LeaveChat() { GCDEST gcd = { ppro->m_szModuleName, { NULL }, GC_EVENT_CONTROL }; @@ -122,65 +160,170 @@ void ChatRoom::LeaveChat() ::CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce); } -void ChatRoom::SendChatEvent(const wchar_t *sid, int eventType, DWORD flags, DWORD itemData, const wchar_t *status, const wchar_t *message, DWORD timestamp) +void ChatRoom::SendEvent(ChatMember *member, int eventType, DWORD timestamp, DWORD flags, DWORD itemData, const wchar_t *status, const wchar_t *message) +{ + GCDEST gcd = { ppro->m_szModuleName, { NULL }, eventType }; + gcd.ptszID = this->cid; + + bool isMe = this->IsMe(member->sid); + + GCEVENT gce = {0}; + gce.cbSize = sizeof(gce); + gce.dwFlags = GC_TCHAR | flags; + gce.pDest = &gcd; + gce.ptszUID = member->sid; + gce.ptszNick = !isMe ? member->nick : ::TranslateT("me"); + gce.bIsMe = isMe; + gce.dwItemData = itemData; + gce.ptszStatus = status; + gce.ptszText = message; + gce.time = timestamp; + ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); +} + +//void ChatRoom::SendEvent(const wchar_t *sid, int eventType, DWORD timestamp, DWORD flags, DWORD itemData, const wchar_t *status, const wchar_t *message) +//{ +// if ( !this->IsMe(sid)) +// { +// ChatMember search(sid); +// ChatMember *member = this->members.find(&search); +// if (member != NULL) +// { +// this->SendEvent(member, eventType, timestamp, flags, itemData, status, message); +// } +// } +// else +// { +// ChatMember self(this->me); +// +// this->SendEvent(&self, eventType, timestamp, flags, itemData, status, message); +// } +//} + +void ChatRoom::AppendMessage(const wchar_t *sid, const wchar_t *message, DWORD timestamp, int eventType) +{ + //this->SendEvent(sid, eventType, timestamp, GCEF_ADDTOLOG, 0, NULL, message); +} + +bool ChatRoom::IsMe(const wchar_t *sid) const +{ + return ::lstrcmpi(this->me->sid, sid) == 0; +} + +bool ChatRoom::IsMe(ChatMember *member) const +{ + return this->IsMe(member->sid); +} + +ChatMember *ChatRoom::FindChatMember(ChatMember *item) +{ + return this->members.find(item); +} + +ChatMember *ChatRoom::FindChatMember(const wchar_t *sid) { ChatMember search(sid); - ChatMember *member = this->members.find(&search); - if (member != NULL) + return this->members.find(&search); +} + +void ChatRoom::AddMember(ChatMember *item, DWORD timestamp, int flags) +{ + if ( !this->IsMe(item)) + { + ChatMember *member = this->members.find(item); + if (member != NULL) + { + this->UpdateMember(item->sid, item->nick, item->rank, item->status, timestamp, flags); + member = item; + } + else + { + this->members.insert(item); + + this->SendEvent(item, GC_EVENT_JOIN, timestamp, flags, 0, ChatRoom::Roles[item->rank]); + this->SendEvent(item, GC_EVENT_SETCONTACTSTATUS, timestamp, 0, item->status); + } + } + else { - GCDEST gcd = { ppro->m_szModuleName, { NULL }, eventType }; - gcd.ptszID = this->cid; - - GCEVENT gce = {0}; - gce.cbSize = sizeof(gce); - gce.dwFlags = GC_TCHAR | flags; - gce.pDest = &gcd; - gce.ptszUID = member->sid; - gce.ptszNick = member->nick; - gce.bIsMe = member == this->me; - gce.dwItemData = itemData; - gce.ptszStatus = status; - gce.ptszText = message; - gce.time = timestamp; - ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); + if (this->me->rank != item->rank) + { + wchar_t *oldStatus = ::TranslateW(ChatRoom::Roles[item->rank]); + this->SendEvent(this->me, GC_EVENT_REMOVESTATUS, timestamp, 0, 0, oldStatus); + this->me->rank = item->rank; + wchar_t *newStatus = ::TranslateW(ChatRoom::Roles[item->rank]); + this->SendEvent(this->me, GC_EVENT_ADDSTATUS, timestamp, flags, 0, newStatus); + } } } -void ChatRoom::Add(ChatMember *item) +void ChatRoom::AddMember(ChatMember *item, DWORD timestamp) +{ + this->AddMember(item, timestamp, GCEF_ADDTOLOG); +} + +void ChatRoom::AddMember(ChatMember *item) +{ + this->AddMember(item, NULL, 0); +} + +void ChatRoom::UpdateMember(const wchar_t *sid, const wchar_t *nick, int rank, int status, DWORD timestamp, DWORD flags) { - ChatMember *member = this->members.find(item); + ChatMember search(sid); + ChatMember *member = this->members.find(&search); if (member != NULL) { - if (::lstrcmp(member->nick, item->nick) != 0) - this->SendChatEvent(member->sid, GC_EVENT_NICK, GCEF_ADDTOLOG, 0, 0, item->nick); - if (member->rank != item->rank) + if (::lstrcmp(member->nick, nick) != 0) + this->SendEvent(member, GC_EVENT_NICK, timestamp, flags, 0, nick); + if (member->rank != rank) { - // todo: real role instead "OWNER" ptrW oldStatus = ::TranslateW(ChatRoom::Roles[member->rank]); - this->SendChatEvent(member->sid, GC_EVENT_REMOVESTATUS, GCEF_ADDTOLOG, 0, oldStatus, L"OWNER"); - ptrW newStatus = ::TranslateW(ChatRoom::Roles[item->rank]); - this->SendChatEvent(member->sid, GC_EVENT_ADDSTATUS, GCEF_ADDTOLOG, 0, newStatus, L"OWNER"); + this->SendEvent(member, GC_EVENT_REMOVESTATUS, timestamp, 0, 0, oldStatus); + ptrW newStatus = ::TranslateW(ChatRoom::Roles[rank]); + this->SendEvent(member, GC_EVENT_ADDSTATUS, timestamp, flags, 0, newStatus); + } + if (member->status != status) + this->SendEvent(member, GC_EVENT_SETCONTACTSTATUS, timestamp, 0, status); + } +} + +void ChatRoom::KickMember(ChatMember *member, const ChatMember *kicker, DWORD timestamp) +{ + if ( !this->IsMe(member)) + { + if (this->members.getIndex(member) >= 0) + { + this->SendEvent(member, GC_EVENT_KICK, timestamp, GCEF_ADDTOLOG, 0, kicker->nick); + this->members.remove(member); } - if (member->status != item->status) - this->SendChatEvent(member->sid, GC_EVENT_SETCONTACTSTATUS, 0, item->status); - member = item; } else { - this->members.insert(item); - - this->SendChatEvent(item->sid, GC_EVENT_JOIN, GCEF_ADDTOLOG, GCEF_ADDTOLOG, ChatRoom::Roles[item->rank]); - this->SendChatEvent(item->sid, GC_EVENT_SETCONTACTSTATUS, 0, item->status); + this->SendEvent(this->me, GC_EVENT_KICK, timestamp, GCEF_ADDTOLOG, 0, kicker->nick); } } -void ChatRoom::Add(const wchar_t *sid, int rank, WORD status) +void ChatRoom::KickMember(const wchar_t *sid, const wchar_t *kickerSid, DWORD timestamp) { - ChatMember *member = new ChatMember(); - member->sid = ::mir_wstrdup(sid); - member->rank = rank; - member->status = status; - this->members.insert(member); + ChatMember member(sid); + this->KickMember(&member, this->FindChatMember(kickerSid), timestamp); +} + +void ChatRoom::RemoveMember(ChatMember *member, DWORD timestamp) +{ + if ( !this->IsMe(member)) + { + if (this->members.indexOf(member) >= 0) + this->SendEvent(member, GC_EVENT_QUIT, timestamp, GCEF_ADDTOLOG); + } + else + this->LeaveChat(); +} + +void ChatRoom::RemoveMember(const wchar_t *sid, DWORD timestamp) +{ + ChatMember member(sid); + this->RemoveMember(&member, timestamp); } int __cdecl ChatRoom::OnGCEventHook(WPARAM, LPARAM lParam) @@ -300,6 +443,62 @@ int __cdecl ChatRoom::OnGCMenuHook(WPARAM, LPARAM lParam) /// +ChatList::ChatList(CSkypeProto *ppro) : chatRooms(1, CompareChatRooms) +{ + this->ppro = ppro; +} + +ChatList::~ChatList() +{ + for (int i = 0; this->chatRooms.getCount(); i++) + delete this->chatRooms[i]; + this->chatRooms.destroy(); +} + +ChatRoom *ChatList::FindChatRoom(ChatRoom *item) +{ + return this->chatRooms.find(item); +} + +ChatRoom *ChatList::FindChatRoom(const wchar_t *cid) +{ + ChatRoom search(cid); + return this->chatRooms.find(&search); +} + +HANDLE ChatList::AddChatRoom(ChatRoom *item) +{ + ChatRoom search(item->cid); + ChatRoom *room = this->chatRooms.find(&search); + if (room == NULL) + room = item; + + this->chatRooms.insert(room); + + HANDLE hContact = ppro->GetChatRoomByCid(room->cid); + if ( !hContact) + { + hContact = (HANDLE)::CallService(MS_DB_CONTACT_ADD, 0, 0); + ::CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)ppro->m_szModuleName); + + ::db_set_b(hContact, ppro->m_szModuleName, "ChatRoom", 1); + ::db_set_ws(hContact, ppro->m_szModuleName, "ChatRoomID", room->cid); + ::db_set_ws(hContact, ppro->m_szModuleName, "Nick", room->name); + ::db_set_w(hContact, ppro->m_szModuleName, "Status", ID_STATUS_OFFLINE); + ::db_set_w(hContact, ppro->m_szModuleName, "ApparentMode", ID_STATUS_OFFLINE); + + ptrW defaultGroup = ::db_get_wsa(NULL, "Chat", "AddToGroup"); + if (defaultGroup != NULL) + { + ::db_set_ws(hContact, "CList", "Group", defaultGroup); + } + } + + return hContact; +} + +/// + void CSkypeProto::ChatValidateContact(HANDLE hItem, HWND hwndList, const StringList &contacts) { //HANDLE hContact = (HANDLE)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem); @@ -768,20 +967,25 @@ INT_PTR __cdecl CSkypeProto::OnJoinChat(WPARAM wParam, LPARAM) HANDLE hContact = (HANDLE)wParam; if (hContact) { - mir_ptr cid( ::db_get_wsa(hContact, this->m_szModuleName, "ChatRoomID")); + ptrW cid(::db_get_wsa(hContact, this->m_szModuleName, "ChatRoomID")); SEString data; CConversation::Ref conversation; - //todo: fixme this->GetConversationByIdentity(::mir_utf8encodeW(cid), conversation); - conversation->GetJoinBlob(data); - this->GetConversationByBlob(data, conversation, false); - conversation->Join(); - this->JoinToChat(conversation); - } + conversation->GetPropDisplayname(data); + ptrW name = ::mir_utf8decodeW(data); + + ChatRoom *room = new ChatRoom(cid, name, this); + this->chatList->AddChatRoom(room); + + Participant::Refs participants; + conversation->GetParticipants(participants, Conversation::ALL); + room->Start(participants, true); + } + return 0; } @@ -809,11 +1013,7 @@ int __cdecl CSkypeProto::OnGCEventHook(WPARAM, LPARAM lParam) switch (gch->pDest->iType) { case GC_SESSION_TERMINATE: if (this->GetConversationByIdentity(::mir_utf8encodeW(cid), conversation, false)) - { - Participant::Refs participants; - conversation->GetParticipants(participants, CConversation::MYSELF); - participants[0]->Retire(); - } + conversation->RetireFrom(); break; case GC_USER_MESSAGE: @@ -959,18 +1159,35 @@ void __cdecl CSkypeProto::LoadChatList(void*) CConversation::Refs conversations; this->GetConversationList(conversations); + SEString data; for (uint i = 0; i < conversations.size(); i++) { auto conversation = conversations[i]; uint convoType = conversation->GetUintProp(Conversation::P_TYPE); - - CConversation::MY_STATUS status; - conversation->GetPropMyStatus(status); - if (convoType == CConversation::CONFERENCE && status == CConversation::CONSUMER) + if (convoType == CConversation::CONFERENCE) { - this->AddChatRoom(conversation); - this->JoinToChat(conversation, false); + bool isBookmarked; + conversation->GetPropIsBookmarked(isBookmarked); + + CConversation::MY_STATUS status; + conversation->GetPropMyStatus(status); + if (status == Conversation::APPLICANT || status == Conversation::CONSUMER || isBookmarked) + { + conversation->GetPropIdentity(data); + ptrW cid = ::mir_utf8decodeW(data); + + conversation->GetPropDisplayname(data); + ptrW name = ::mir_utf8decodeW(data); + + ChatRoom *room = new ChatRoom(cid, name, this); + this->chatList->AddChatRoom(room); + + Participant::Refs participants; + conversation->GetParticipants(participants, Conversation::ALL); + + room->Start(participants); + } } } } @@ -985,13 +1202,13 @@ void CSkypeProto::OnChatMessageReceived(const ConversationRef &conversation, con message->GetPropTimestamp(timestamp); message->GetPropBodyXml(data); - char *text = CSkypeProto::RemoveHtml(data); + ptrA text = CSkypeProto::RemoveHtml(data); message->GetPropAuthor(data); - mir_ptr sid( ::mir_utf8decodeW(data)); + ptrW sid(::mir_utf8decodeW(data)); conversation->GetPropIdentity(data); - mir_ptr cid( ::mir_utf8decodeW(data)); + ptrW cid(::mir_utf8decodeW(data)); //this->SendChatMessage(cid, sid, mir_ptr(::mir_utf8decodeW(text))); this->RaiseChatEvent( @@ -1001,7 +1218,7 @@ void CSkypeProto::OnChatMessageReceived(const ConversationRef &conversation, con GCEF_ADDTOLOG, 0, NULL, - mir_ptr(::mir_utf8decodeW(text)), + ptrW(::mir_utf8decodeW(text)), timestamp); } @@ -1013,13 +1230,13 @@ void CSkypeProto::OnChatMessageSent(const ConversationRef &conversation, const M message->GetPropTimestamp(timestamp); message->GetPropBodyXml(data); - char *text = CSkypeProto::RemoveHtml(data); + ptrA text = CSkypeProto::RemoveHtml(data); conversation->GetPropIdentity(data); - mir_ptr cid( ::mir_utf8decodeW(data)); + ptrW cid(::mir_utf8decodeW(data)); message->GetPropAuthor(data); - mir_ptr sid( ::mir_utf8decodeW(data)); + ptrW sid(::mir_utf8decodeW(data)); //this->SendChatMessage(cid, nick, mir_ptr(::mir_utf8decodeW(text))); this->RaiseChatEvent( @@ -1029,7 +1246,7 @@ void CSkypeProto::OnChatMessageSent(const ConversationRef &conversation, const M GCEF_ADDTOLOG, 0, NULL, - mir_ptr(::mir_utf8decodeW(text)), + ptrW(::mir_utf8decodeW(text)), timestamp); } @@ -1046,115 +1263,190 @@ void CSkypeProto::OnChatEvent(const ConversationRef &conversation, const Message SEString author; message->GetPropAuthor(author); - if (::wcsicmp(mir_ptr(::mir_utf8decodeW(author)), this->login) == 0) + if (::wcsicmp(ptrW(::mir_utf8decodeW(author)), this->login) == 0) this->OnChatMessageSent(conversation, message, messageType); else this->OnChatMessageReceived(conversation, message, messageType); } break; - case CMessage::ADDED_CONSUMERS: + case Message::ADDED_CONSUMERS: + case Message::ADDED_APPLICANTS: { SEString data; conversation->GetPropIdentity(data); - wchar_t *cid = ::mir_utf8decodeW(data); + ptrW cid = ::mir_utf8decodeW(data); - HANDLE hContact = this->AddChatRoom(conversation); - if ( !this->IsContactOnline(hContact)) + ChatRoom *room = this->chatList->FindChatRoom(cid); + if (room == NULL) { - this->JoinToChat(conversation); + conversation->GetPropDisplayname(data); + ptrW name = ::mir_utf8decodeW(data); + + ChatRoom *room = new ChatRoom(cid, name, this); + this->chatList->AddChatRoom(room); + + Participant::Refs participants; + conversation->GetParticipants(participants, Conversation::ALL); + + room->Start(participants, true); } else { - StringList alreadyInChat(this->GetChatUsers(cid)); + uint timestamp; + message->GetPropTimestamp(timestamp); message->GetPropIdentities(data); - StringList needToAdd(::mir_utf8decodeW(data)); - - CParticipant::Refs participants; - conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); - for (uint i = 0; i < participants.size(); i++) + char *identities = ::mir_strdup(data); + if (identities) { - participants[i]->GetPropIdentity(data); - std::wstring sid = ::mir_utf8decodeW(data); - - if (needToAdd.contains(sid.c_str()) && !alreadyInChat.contains(sid.c_str())) + char *identity = ::strtok(identities, " "); + if (identity != NULL) { - CContact::Ref contact; - this->GetContact(std::string(::mir_utf8encodeW(sid.c_str())).c_str(), contact); + do + { + Contact::Ref contact; + this->GetContact(identity, contact); + + contact->GetIdentity(data); + ptrW sid = ::mir_utf8decodeW(data); + + ChatMember *member = new ChatMember(sid); + //todo: fix rank + + member->rank = + messageType == Message::ADDED_APPLICANTS ? + Participant::APPLICANT : + Participant::SPEAKER; + //conversation->GetUintProp(Conversation::P_OPT_ENTRY_LEVEL_RANK); + //participants[i]->GetUintProp(Participant::P_RANK); + + Contact::AVAILABILITY status; + contact->GetPropAvailability(status); + member->status = CSkypeProto::SkypeToMirandaStatus(status); + + contact->GetPropFullname(data); + member->nick = ::mir_utf8decodeW(data); + + room->AddMember(member, timestamp); + + identity = ::strtok(NULL, " "); + } + while (identity != NULL); + } + ::mir_free(identities); + } + } + } + break; - CContact::AVAILABILITY status; - contact->GetPropAvailability(status); + case Message::RETIRED_OTHERS: + { + SEString data; + + conversation->GetPropIdentity(data); + ptrW cid = ::mir_utf8decodeW(data); - CParticipant::RANK rank; - participants[i]->GetPropRank(rank); + ChatRoom *room = this->chatList->FindChatRoom(cid); + if (room != NULL) + { + uint timestamp; + message->GetPropTimestamp(timestamp); + + message->GetPropAuthor(data); + ptrW sid = ::mir_utf8decodeW(data); - this->AddChatContact( - cid, - sid.c_str(), - CSkypeProto::Roles[rank], - CSkypeProto::SkypeToMirandaStatus(status)); + message->GetPropIdentities(data); + char *identities = ::mir_strdup(data); + if (identities) + { + char *identity = ::strtok(identities, " "); + if (identity != NULL) + { + do + { + room->KickMember(ptrW(::mir_utf8decodeW(identity)), sid, timestamp); + + identity = ::strtok(NULL, " "); + } + while (identity != NULL); } + ::mir_free(identities); } } } break; - case CMessage::RETIRED: + case Message::RETIRED: { SEString data; conversation->GetPropIdentity(data); - wchar_t *cid = ::mir_utf8decodeW(data); + ptrW cid = ::mir_utf8decodeW(data); - StringList alreadyInChat(this->GetChatUsers(cid)); - - message->GetPropAuthor(data); - wchar_t *sid = ::mir_utf8decodeW(data); - if (::wcsicmp(sid, this->login) != 0) - if (alreadyInChat.contains(sid)) - this->RemoveChatContact(cid, sid); + ChatRoom *room = this->chatList->FindChatRoom(cid); + if (room != NULL) + { + uint timestamp; + message->GetPropTimestamp(timestamp); + + message->GetPropAuthor(data); + ptrW sid = ::mir_utf8decodeW(data); + + room->RemoveMember(sid, timestamp); + } } break; - case CMessage::RETIRED_OTHERS: + case CMessage::SPAWNED_CONFERENCE: { SEString data; conversation->GetPropIdentity(data); - mir_ptr cid( ::mir_utf8decodeW(data)); + ptrW cid = ::mir_utf8decodeW(data); - message->GetPropIdentities(data); + conversation->GetPropDisplayname(data); + ptrW name = ::mir_utf8decodeW(data); - StringList alreadyInChat(this->GetChatUsers(cid)); - StringList needToKick(::mir_utf8decodeW(data)); - - for (size_t i = 0; i < needToKick.size(); i++) - { - const wchar_t *sid = needToKick[i]; - if (::wcsicmp(sid, this->login) == 0) - { - HANDLE hContact = this->GetChatRoomByCid(cid); - this->ShowNotification(::TranslateT("You have been kicked from the chat room"), 0, hContact); - this->LeaveChat(cid); - } - else if ( !alreadyInChat.contains(sid)) - this->KickChatContact(cid, sid); - } + ChatRoom *room = new ChatRoom(cid, name, this); + this->chatList->AddChatRoom(room); + + CParticipant::Refs participants; + conversation->GetParticipants(participants, CConversation::ALL); + + room->Start(participants, true); } break; - case CMessage::SPAWNED_CONFERENCE: + case Message::SET_RANK: { SEString data; + message->GetPropBodyXml(data); + ptrA text = ::mir_strdup(data); + int i = 0; + conversation->GetPropIdentity(data); - char *cid = ::mir_strdup(data); + ptrW cid = ::mir_utf8decodeW(data); - HANDLE hContact = this->AddChatRoom(conversation); - if ( !this->IsContactOnline(hContact)) + ChatRoom *room = this->chatList->FindChatRoom(cid); + if (room != NULL) { - this->JoinToChat(conversation); + message->GetPropAuthor(data); + ptrW sid = ::mir_utf8decodeW(data); + + ChatMember search(sid); + ChatMember *member = room->FindChatMember(sid); + if (member != NULL) + { + uint timestamp; + message->GetPropTimestamp(timestamp); + + message->GetPropBodyXml(data); + ptrW rank = ::mir_utf8decodeW(data); + + member->rank = 0; + } } } break; @@ -1164,7 +1456,7 @@ void CSkypeProto::OnChatEvent(const ConversationRef &conversation, const Message SEString data; conversation->GetPropIdentity(data); - mir_ptr cid( ::mir_utf8decodeW(data)); + ptrW cid( ::mir_utf8decodeW(data)); HANDLE hContact = this->GetChatRoomByCid(cid); this->RaiseChatEvent( @@ -1183,7 +1475,7 @@ void CSkypeProto::OnChatEvent(const ConversationRef &conversation, const Message SEString data; conversation->GetPropIdentity(data); - mir_ptr cid( ::mir_utf8decodeW(data)); + ptrW cid( ::mir_utf8decodeW(data)); HANDLE hContact = this->GetChatRoomByCid(cid); this->RaiseChatEvent( @@ -1197,4 +1489,15 @@ void CSkypeProto::OnChatEvent(const ConversationRef &conversation, const Message } break; } +} + +void CSkypeProto::OnConversationListChange( + const ConversationRef& conversation, + const Conversation::LIST_TYPE& type, + const bool& added) +{ + uint convoType = conversation->GetUintProp(Conversation::P_TYPE); + if (convoType == Conversation::CONFERENCE && type == Conversation::INBOX_CONVERSATIONS && added) + { + } } \ No newline at end of file diff --git a/protocols/Skype/src/skype_chat.h b/protocols/Skype/src/skype_chat.h index ce72dd27b4..947b2324b1 100644 --- a/protocols/Skype/src/skype_chat.h +++ b/protocols/Skype/src/skype_chat.h @@ -14,17 +14,21 @@ public: ChatMember() { this->sid = NULL; + this->nick = NULL; } ChatMember(const wchar_t *sid) { this->sid = ::mir_wstrdup(sid); + this->nick = NULL; } ~ChatMember() { if (this->sid != NULL) ::mir_free(this->sid); + if (this->nick != NULL) + ::mir_free(this->nick); } bool operator==(const ChatMember &other) const @@ -37,24 +41,33 @@ public: return !(*this == other); } - /*ChatMember& operator=(const ChatMember& right) + ChatMember& operator=(const ChatMember& right) { if (this == &right) return *this; ::mir_free(this->sid); + ::mir_free(this->nick); this->sid = ::mir_wstrdup(right.sid); + this->nick = ::mir_wstrdup(right.nick); + this->rank = right.rank; + this->status = right.status; return *this; - }*/ + } }; class ChatRoom { -public: + friend class ChatList; + +private: wchar_t *cid; - wchar_t *topic; + wchar_t *name; + + HANDLE hContact; ChatMember *me; + LIST members; CSkypeProto *ppro; @@ -62,19 +75,62 @@ public: static wchar_t *Roles[]; ChatRoom(const wchar_t *cid); - ChatRoom(ChatMember *me); + + HANDLE AddChatRoom(); + + inline static int CompareMembers(const ChatMember *p1, const ChatMember *p2) { return ::lstrcmpi(p1->sid, p2->sid); } + + static int __cdecl OnGCEventHook(WPARAM, LPARAM lParam); + static int __cdecl OnGCMenuHook(WPARAM, LPARAM lParam); + + void AddMember(ChatMember *member, DWORD timestamp, int flag); + +public: + ChatRoom(const wchar_t *cid, const wchar_t *name, CSkypeProto *ppro); + ~ChatRoom(); void Start(bool showWindow = false); + void Start(const ParticipantRefs &participants, bool showWindow = false); + void LeaveChat(); - void SendChatEvent(const wchar_t *sid, int eventType, DWORD flags = GCEF_ADDTOLOG, DWORD itemData = 0, const wchar_t *status = NULL, const wchar_t *message = NULL, DWORD timestamp = time(NULL)); + void SendEvent(ChatMember *member, int eventType, DWORD timestamp = time(NULL), DWORD flags = GCEF_ADDTOLOG, DWORD itemData = 0, const wchar_t *status = NULL, const wchar_t *message = NULL); + //void SendEvent(const wchar_t *sid, int eventType, DWORD timestamp = time(NULL), DWORD flags = GCEF_ADDTOLOG, DWORD itemData = 0, const wchar_t *status = NULL, const wchar_t *message = NULL); - void Add(ChatMember *member); - void Add(const wchar_t *sid, int rank = 0, WORD status = ID_STATUS_OFFLINE); + void AppendMessage(const wchar_t *sid, const wchar_t *message, DWORD timestamp = time(NULL), int eventType = GC_EVENT_MESSAGE); + bool IsMe(const wchar_t *sid) const; + bool IsMe(ChatMember *member) const; + + ChatMember *FindChatMember(ChatMember *item); + ChatMember *FindChatMember(const wchar_t *sid); + + void AddMember(ChatMember *member, DWORD timestamp); + void AddMember(ChatMember *member); + + void UpdateMember(const wchar_t *sid, const wchar_t *nick, int rank, int status, DWORD timestamp = time(NULL), DWORD flags = GCEF_ADDTOLOG); + + void KickMember(ChatMember *member, const ChatMember *kicker, DWORD timestamp = time(NULL)); + void KickMember(const wchar_t *sid, const wchar_t *kicker, DWORD timestamp = time(NULL)); + + void RemoveMember(ChatMember *member, DWORD timestamp = time(NULL)); + void RemoveMember(const wchar_t *sid, DWORD timestamp = time(NULL)); +}; + +class ChatList +{ private: - static int SortMembers(const ChatMember *p1, const ChatMember *p2); + CSkypeProto *ppro; + LIST chatRooms; + + inline static int CompareChatRooms(const ChatRoom* p1, const ChatRoom* p2) { return ::lstrcmpi(p1->cid, p2->cid); } + +public: + ChatList(CSkypeProto *ppro); + ~ChatList(); + + ChatRoom *FindChatRoom(ChatRoom *item); + ChatRoom *FindChatRoom(const wchar_t *cid); - int __cdecl OnGCEventHook(WPARAM, LPARAM lParam); - int __cdecl OnGCMenuHook(WPARAM, LPARAM lParam); + HANDLE AddChatRoom(ChatRoom *item); }; \ No newline at end of file diff --git a/protocols/Skype/src/skype_events.cpp b/protocols/Skype/src/skype_events.cpp index b86782a875..86e275f691 100644 --- a/protocols/Skype/src/skype_events.cpp +++ b/protocols/Skype/src/skype_events.cpp @@ -60,7 +60,7 @@ int CSkypeProto::OnContactDeleted(WPARAM wParam, LPARAM lParam) { if (this->IsChatRoom(hContact)) { - mir_ptr chatID(::db_get_wsa(hContact, this->m_szModuleName, "ChatRoomID")); + ptrW chatID(::db_get_wsa(hContact, this->m_szModuleName, "ChatRoomID")); this->LeaveChat(chatID); CConversation::Ref conversation; diff --git a/protocols/Skype/src/skype_proto.cpp b/protocols/Skype/src/skype_proto.cpp index 587eb65735..af42905023 100644 --- a/protocols/Skype/src/skype_proto.cpp +++ b/protocols/Skype/src/skype_proto.cpp @@ -1,6 +1,8 @@ #include "skype_proto.h" -CSkypeProto::CSkypeProto(const char* protoName, const TCHAR* userName) : Skype(1), skypeKitPort(8963) +CSkypeProto::CSkypeProto(const char* protoName, const TCHAR* userName) : + Skype(1), + skypeKitPort(8963) { ::ProtoConstructor(this, protoName, userName); @@ -533,12 +535,12 @@ int __cdecl CSkypeProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM case EV_PROTO_ONEXIT: return this->OnPreShutdown(wParam, lParam); + case EV_PROTO_ONCONTACTDELETED: + return this->OnContactDeleted(wParam, lParam); + case EV_PROTO_ONMENU: this->OnInitStatusMenu(); break; - - case EV_PROTO_ONCONTACTDELETED: - return this->OnContactDeleted(wParam, lParam); } return 1; diff --git a/protocols/Skype/src/skype_proto.h b/protocols/Skype/src/skype_proto.h index e7681806b6..ae9bc979f4 100644 --- a/protocols/Skype/src/skype_proto.h +++ b/protocols/Skype/src/skype_proto.h @@ -82,8 +82,15 @@ struct PasswordChangeBoxParam } }; +class ChatMember; +class ChatRoom; +class ChatList; + struct CSkypeProto : public PROTO_INTERFACE, private Skype { + friend class ChatRoom; + friend class ChatList; + public: // PROTO_INTERFACE CSkypeProto(const char *protoName, const wchar_t *userName); @@ -179,6 +186,11 @@ private: const MessageRef & supersedesHistoryMessage, const ConversationRef & conversation); + void OnConversationListChange( + const ConversationRef& conversation, + const Conversation::LIST_TYPE& type, + const bool& added); + int skypeKitPort; PROCESS_INFORMATION skypeKitProcessInfo; @@ -254,6 +266,7 @@ protected: void OnTransferChanged(CTransfer::Ref transfer, int prop); // chat + ChatList *chatList; static wchar_t* Roles[]; bool IsChatRoom(HANDLE hContact); -- cgit v1.2.3