From 48d0b7bc967f4a8061aa36a82f3a1d8fa7aac7ba Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Mon, 24 May 2021 01:47:21 -0500 Subject: [PATCH] Create Conversation class, use it instead of Contact for chats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a commit with it's foot in a lot of places, but: The Conversation class was created as the abstraction of chats: All ImMessages that are relevant to a conversation get routed through it, meta-data on chats is stored in it (even if right now that's basically limited to the user list and ID). Server was given more methods to help accessing contacts― ContactById(BString) and AddContact(Contact*). This better allows Conversations to add and fetch Contacts as necessary. Right now, all users in chats are treated as Contacts, so in the future creating an independent userlist for Server (fUserMap?) would be useful. Server also now stores all Conversations (fChatMap) and has some convenience methods like for Contacts: Conversations(), ConversationById(BString), and AddConversation(Conversation*). CayaRenderView has been changed to not store user nicks, and will use the appropriate nick of any arbitrarily-numbered user. Users also have a map of all Conversations they are a part of (fChatMap). The Remove* methods of KeyMap now return the removed item. --- application/ChatWindow.cpp | 37 +++-- application/ChatWindow.h | 10 +- application/Contact.cpp | 78 +-------- application/Contact.h | 12 -- application/Conversation.cpp | 240 +++++++++++++++++++++++++++ application/Conversation.h | 74 +++++++++ application/MainWindow.cpp | 27 ++- application/MainWindow.h | 1 + application/Makefile | 1 + application/Notifier.h | 14 +- application/Server.cpp | 192 ++++++++++++--------- application/Server.h | 18 +- application/User.cpp | 24 +++ application/User.h | 24 ++- application/views/CayaRenderView.cpp | 12 +- application/views/CayaRenderView.h | 7 +- application/views/RosterListView.cpp | 4 +- libs/libsupport/KeyMap.h | 12 +- protocols/xmpp/JabberHandler.cpp | 25 +-- protocols/xmpp/Makefile | 6 +- 20 files changed, 587 insertions(+), 231 deletions(-) create mode 100644 application/Conversation.cpp create mode 100644 application/Conversation.h diff --git a/application/ChatWindow.cpp b/application/ChatWindow.cpp index b0d6cdf..7e9a863 100644 --- a/application/ChatWindow.cpp +++ b/application/ChatWindow.cpp @@ -31,6 +31,7 @@ #include "CayaMessages.h" #include "CayaProtocolMessages.h" #include "CayaPreferences.h" +#include "Conversation.h" #include "Contact.h" #include "EditingFilter.h" #include "CayaConstants.h" @@ -38,16 +39,16 @@ #include "NotifyMessage.h" -ChatWindow::ChatWindow(Contact* cl) +ChatWindow::ChatWindow(Conversation* cl) : BWindow(BRect(200, 200, 500, 500), cl->GetName().String(), B_TITLED_WINDOW, 0), - fContact(cl) + fConversation(cl), + fContact(cl->Users().ValueAt(0)) { fMessageCount = 0; fReceiveView = new CayaRenderView("fReceiveView"); - fReceiveView->SetOtherNick(cl->GetName()); BScrollView* scrollViewReceive = new BScrollView("scrollviewR", fReceiveView, B_WILL_DRAW, false, true); @@ -120,8 +121,8 @@ bool ChatWindow::QuitRequested() { BMessage msg(CAYA_CLOSE_CHAT_WINDOW); - msg.AddString("id", fContact->GetId()); - fContact->Messenger().SendMessage(&msg); + msg.AddString("chat_id", fConversation->GetId()); + fConversation->Messenger().SendMessage(&msg); return false; } @@ -140,7 +141,6 @@ ChatWindow::UpdateAvatar() void ChatWindow::UpdatePersonalMessage() { - if (fContact->GetNotifyPersonalStatus() != NULL) { LockLooper(); fPersonalMessage->SetText(fContact->GetNotifyPersonalStatus()); @@ -163,9 +163,9 @@ ChatWindow::MessageReceived(BMessage* message) BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_SEND_MESSAGE); - msg.AddString("id", fContact->GetId()); + msg.AddString("chat_id", fConversation->GetId()); msg.AddString("body", message); - fContact->Messenger().SendMessage(&msg); + fConversation->Messenger().SendMessage(&msg); fSendView->SetText(""); break; @@ -190,7 +190,11 @@ ChatWindow::ImMessage(BMessage* msg) case IM_MESSAGE_RECEIVED: { BString message = msg->FindString("body"); - fReceiveView->AppendOtherMessage(message.String()); + BString id = msg->FindString("user_id"); + User* sender = fConversation->UserById(id); + BString uname = sender->GetName(); + + fReceiveView->AppendOtherMessage(uname.String(), message.String()); // Message received, clear status anyway fStatus->SetText(""); @@ -202,9 +206,9 @@ ChatWindow::ImMessage(BMessage* msg) // Mark unread window if (CayaPreferences::Item()->MarkUnreadWindow) { BString title = "["; - title<GetName(); + title << fMessageCount; + title << "] "; + title << uname; SetTitle(title); } @@ -220,14 +224,14 @@ ChatWindow::ImMessage(BMessage* msg) } else { notify_message << " new messages from "; }; - notify_message << fContact->GetName().String(); + notify_message << uname; BNotification notification(B_INFORMATION_NOTIFICATION); notification.SetGroup(BString("Caya")); notification.SetTitle(BString("New message")); - notification.SetIcon(fAvatar->Bitmap()); + notification.SetIcon(sender->AvatarBitmap()); notification.SetContent(notify_message); - notification.SetMessageID(fContact->GetName()); + notification.SetMessageID(uname); notification.Send(); break; @@ -248,6 +252,7 @@ ChatWindow::ImMessage(BMessage* msg) } } + void ChatWindow::WindowActivated(bool active) { @@ -255,6 +260,7 @@ ChatWindow::WindowActivated(bool active) fMessageCount=0; } + void ChatWindow::ObserveString(int32 what, BString str) { @@ -262,7 +268,6 @@ ChatWindow::ObserveString(int32 what, BString str) case STR_CONTACT_NAME: if (Lock()) { SetTitle(str); - fReceiveView->SetOtherNick(str); Unlock(); } break; diff --git a/application/ChatWindow.h b/application/ChatWindow.h index 72c8ebf..0a6a77a 100644 --- a/application/ChatWindow.h +++ b/application/ChatWindow.h @@ -14,12 +14,14 @@ #include "CayaConstants.h" class BitmapView; -class Contact; +class Conversation; class CayaRenderView; +class Contact; + class ChatWindow : public BWindow, public Observer { public: - ChatWindow(Contact* cl); + ChatWindow(Conversation* cl); virtual void ShowWindow(); @@ -39,7 +41,8 @@ public: void AvoidFocus(bool avoid); private: BTextView* fSendView; - Contact* fContact; + Conversation* fConversation; + Contact* fContact; CayaRenderView* fReceiveView; BStringView* fStatus; BTextView* fPersonalMessage; @@ -49,3 +52,4 @@ private: }; #endif // _CHAT_WINDOW_H + diff --git a/application/Contact.cpp b/application/Contact.cpp index 8311d51..02778cd 100644 --- a/application/Contact.cpp +++ b/application/Contact.cpp @@ -9,83 +9,18 @@ */ #include "Contact.h" -#include "CayaPreferences.h" -#include "ChatWindow.h" #include "RosterItem.h" -#include "WindowsManager.h" Contact::Contact(BString id, BMessenger msgn) : - User::User(id, msgn), - fChatWindow(NULL), - fNewWindow(true) + User::User(id, msgn) { fRosterItem = new RosterItem(id.String(), this); RegisterObserver(fRosterItem); } -ChatWindow* -Contact::GetChatWindow() -{ - if (fChatWindow == NULL) - _CreateChatWindow(); - return fChatWindow; -} - - -void -Contact::DeleteWindow() -{ - if (fChatWindow != NULL) { - if (fChatWindow->Lock()) { - UnregisterObserver(fChatWindow); - fChatWindow->Quit(); - fChatWindow = NULL; - fNewWindow = true; - } - } -} - - -void -Contact::ShowWindow(bool typing, bool userAction) -{ - if (fChatWindow == NULL) - _CreateChatWindow(); - - fChatWindow->AvoidFocus(true); - - if (CayaPreferences::Item()->MoveToCurrentWorkspace) - fChatWindow->SetWorkspaces(B_CURRENT_WORKSPACE); - - if (fNewWindow || userAction) { - fChatWindow->AvoidFocus(false); - fChatWindow->ShowWindow(); - fNewWindow = false; - } else { - if (typing) { - if (CayaPreferences::Item()->RaiseUserIsTyping) - fChatWindow->ShowWindow(); - } else { - if (CayaPreferences::Item()->RaiseOnMessageReceived - || fChatWindow->IsHidden()) - fChatWindow->ShowWindow(); - } - } - fChatWindow->AvoidFocus(false); -} - - -void -Contact::HideWindow() -{ - if ((fChatWindow != NULL) && !fChatWindow->IsHidden()) - fChatWindow->Hide(); -} - - RosterItem* Contact::GetRosterItem() const { @@ -97,15 +32,8 @@ void Contact::SetNotifyAvatarBitmap(BBitmap* bitmap) { User::SetNotifyAvatarBitmap(bitmap); - if (fAvatarBitmap != NULL && fChatWindow != NULL) - fChatWindow->UpdateAvatar(); +// if (fAvatarBitmap != NULL && fChatWindow != NULL) +// fChatWindow->UpdateAvatar(); } -void -Contact::_CreateChatWindow() -{ - fChatWindow = new ChatWindow(this); - WindowsManager::Get()->RelocateWindow(fChatWindow); - RegisterObserver(fChatWindow); -} diff --git a/application/Contact.h b/application/Contact.h index ec9cbb8..8a29091 100644 --- a/application/Contact.h +++ b/application/Contact.h @@ -15,7 +15,6 @@ class BBitmap; -class ChatWindow; class ProtocolLooper; class RosterItem; @@ -24,23 +23,12 @@ class Contact : public User { public: Contact(BString id, BMessenger msgn); - ChatWindow* GetChatWindow(); - void DeleteWindow(); - - void ShowWindow(bool typing = false, bool userAction = false); - void HideWindow(); - RosterItem* GetRosterItem() const; void SetNotifyAvatarBitmap(BBitmap* bitmap); private: - void _CreateChatWindow(); - RosterItem* fRosterItem; - ChatWindow* fChatWindow; - - bool fNewWindow; }; #endif // _CONTACT_LINKER_H_ diff --git a/application/Conversation.cpp b/application/Conversation.cpp new file mode 100644 index 0000000..8d45373 --- /dev/null +++ b/application/Conversation.cpp @@ -0,0 +1,240 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "Conversation.h" + +#include "CayaPreferences.h" +#include "CayaProtocolMessages.h" +#include "ChatWindow.h" +#include "MainWindow.h" +#include "Server.h" +#include "TheApp.h" +#include "WindowsManager.h" + + +Conversation::Conversation(BString id, BMessenger msgn) + : + fID(id), + fName(id), + fMessenger(msgn), + fChatWindow(NULL), + fNewWindow(true), + fLooper(NULL) +{ +} + + +BString +Conversation::GetId() const +{ + return fID; +} + + +void +Conversation::ImMessage(BMessage* msg) +{ + int32 im_what = msg->FindInt32("im_what"); + + switch(im_what) + { + case IM_MESSAGE_RECEIVED: + { + _EnsureUser(msg); + + ChatWindow* win = GetChatWindow(); + ShowWindow(); + win->PostMessage(msg); + break; + } + default: + GetChatWindow()->PostMessage(msg); + } +} + + +void +Conversation::ObserveString(int32 what, BString str) +{ + if (fChatWindow != NULL) + fChatWindow->ObserveString(what, str); +} + + +void +Conversation::ObservePointer(int32 what, void* ptr) +{ + if (fChatWindow != NULL) + fChatWindow->ObservePointer(what, ptr); +} + + +void +Conversation::ObserveInteger(int32 what, int32 val) +{ + if (fChatWindow != NULL) + fChatWindow->ObserveInteger(what, val); +} + + +ChatWindow* +Conversation::GetChatWindow() +{ + if (fChatWindow == NULL) + _CreateChatWindow(); + return fChatWindow; +} + + +void +Conversation::DeleteWindow() +{ + if (fChatWindow != NULL) { + if (fChatWindow->Lock()) { + fChatWindow->Quit(); + fChatWindow = NULL; + fNewWindow = true; + } + } +} + + +void +Conversation::ShowWindow(bool typing, bool userAction) +{ + if (fChatWindow == NULL) + _CreateChatWindow(); + + fChatWindow->AvoidFocus(true); + + if (CayaPreferences::Item()->MoveToCurrentWorkspace) + fChatWindow->SetWorkspaces(B_CURRENT_WORKSPACE); + + if (fNewWindow || userAction) { + fChatWindow->AvoidFocus(false); + fChatWindow->ShowWindow(); + fNewWindow = false; + } else { + if (typing) { + if (CayaPreferences::Item()->RaiseUserIsTyping) + fChatWindow->ShowWindow(); + } else { + if (CayaPreferences::Item()->RaiseOnMessageReceived + || fChatWindow->IsHidden()) + fChatWindow->ShowWindow(); + } + } + fChatWindow->AvoidFocus(false); +} + + +void +Conversation::HideWindow() +{ + if ((fChatWindow != NULL) && !fChatWindow->IsHidden()) + fChatWindow->Hide(); +} + + +BMessenger +Conversation::Messenger() const +{ + return fMessenger; +} + + +void +Conversation::SetMessenger(BMessenger messenger) +{ + fMessenger = messenger; +} + + +ProtocolLooper* +Conversation::GetProtocolLooper() const +{ + return fLooper; +} + + +void +Conversation::SetProtocolLooper(ProtocolLooper* looper) +{ + fLooper = looper; +} + + +BString +Conversation::GetName() const +{ + return fName; +} + + +UserMap +Conversation::Users() +{ + return fUsers; +} + + +Contact* +Conversation::UserById(BString id) +{ + bool found = false; + return fUsers.ValueFor(id, &found); +} + + +void +Conversation::AddUser(User* user) +{ + BMessage msg; + msg.AddString("user_id", user->GetId()); + _EnsureUser(&msg); +} + + +void +Conversation::_CreateChatWindow() +{ + fChatWindow = new ChatWindow(this); + WindowsManager::Get()->RelocateWindow(fChatWindow); +} + + +Contact* +Conversation::_EnsureUser(BMessage* msg) +{ + BString id = msg->FindString("user_id"); + if (id.IsEmpty() == true) return NULL; + + Contact* user = UserById(id); + Contact* serverUser = _GetServer()->ContactById(id); + + if (user == NULL && serverUser != NULL) { + fUsers.AddItem(id, serverUser); + user = serverUser; + } + else if (user == NULL) { + user = new Contact(id, _GetServer()->Looper()); + user->SetProtocolLooper(fLooper); + + _GetServer()->AddContact(user); + fUsers.AddItem(id, user); + } + + user->RegisterObserver(this); + return user; +} + + +Server* +Conversation::_GetServer() +{ + return ((TheApp*)be_app)->GetMainWindow()->GetServer(); +} + + diff --git a/application/Conversation.h b/application/Conversation.h new file mode 100644 index 0000000..35c7703 --- /dev/null +++ b/application/Conversation.h @@ -0,0 +1,74 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef CONVERSATION_H +#define CONVERSATION_H + +#include + +#include + +#include "Notifier.h" +#include "User.h" + +class ChatWindow; +class Contact; +class ProtocolLooper; +class Server; + + +typedef KeyMap UserMap; + + +class Conversation : public Observer { +public: + Conversation(BString id, BMessenger msgn); + + BString GetId() const; + + // Handles required state changes from an IM message; forwards to ChatWindow + void ImMessage(BMessage* msg); + + // Observer inherits; just forwards to ChatWindow + void ObserveString(int32 what, BString str); + void ObserveInteger(int32 what, int32 value); + void ObservePointer(int32 what, void* ptr); + + ChatWindow* GetChatWindow(); + void DeleteWindow(); + + void ShowWindow(bool typing = false, bool userAction = false); + void HideWindow(); + + BMessenger Messenger() const; + void SetMessenger(BMessenger messenger); + + ProtocolLooper* GetProtocolLooper() const; + void SetProtocolLooper(ProtocolLooper* looper); + + BString GetName() const; + + UserMap Users(); + Contact* UserById(BString id); + void AddUser(User* user); + +private: + void _CreateChatWindow(); + Contact* _EnsureUser(BMessage* msg); + Server* _GetServer(); + + BMessenger fMessenger; + ProtocolLooper* fLooper; + ChatWindow* fChatWindow; + bool fNewWindow; + + BString fID; + BString fName; + + UserMap fUsers; +}; + + +#endif // CONVERSATION_H + diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 6d7a1a9..7f35620 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -161,7 +161,7 @@ MainWindow::MessageReceived(BMessage* message) if (searchBox == NULL) return; - RosterMap map = fServer->RosterItems(); + RosterMap map = fServer->Contacts(); for (uint32 i = 0; i < map.CountItems(); i++) { Contact* linker = map.ValueAt(i); RosterItem* item = linker->GetRosterItem(); @@ -187,10 +187,29 @@ MainWindow::MessageReceived(BMessage* message) } case CAYA_OPEN_CHAT_WINDOW: { + // This is only used by RosterList, so try to open a one-on-one chat + // if there is one― otherwise, creawte one. int index = message->FindInt32("index"); RosterItem* ritem = ItemAt(index); + User* user = ritem->GetContact(); if (ritem != NULL) - ritem->GetContact()->ShowWindow(false, true); + User* user = ritem->GetContact(); + ChatMap chats = user->Conversations(); + Conversation* chat; + + // TODO: Poor way of creating necessary chatroom + if (chats.CountItems() == 0) { + chat = new Conversation(user->GetId(), fServer->Looper()); + chat->SetProtocolLooper(user->GetProtocolLooper()); + chat->AddUser(user); + chat->ShowWindow(false, true); + + fServer->AddConversation(chat); + } + else + while (chat = chats.RemoveItemAt(0)) + if (chat->Users().CountItems() == 1) + chat->ShowWindow(false, true); break; } @@ -283,7 +302,7 @@ MainWindow::ImMessage(BMessage* msg) if (msg->FindInt32("status", &status) != B_OK) return; - RosterItem* rosterItem = fServer->RosterItemForId(msg->FindString("id")); + RosterItem* rosterItem = fServer->ContactById(msg->FindString("user_id"))->GetRosterItem(); if (rosterItem) { UpdateListItem(rosterItem); @@ -345,7 +364,7 @@ MainWindow::ImMessage(BMessage* msg) case IM_EXTENDED_CONTACT_INFO: { RosterItem* rosterItem - = fServer->RosterItemForId(msg->FindString("id")); + = fServer->ContactById(msg->FindString("user_id"))->GetRosterItem(); if (rosterItem) UpdateListItem(rosterItem); break; diff --git a/application/MainWindow.h b/application/MainWindow.h index 4265875..a3baba2 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -18,6 +18,7 @@ class StatusView; class RosterListView; class RosterItem; + class MainWindow: public BWindow, public Observer { public: MainWindow(); diff --git a/application/Makefile b/application/Makefile index 852d9f3..6ed6c22 100644 --- a/application/Makefile +++ b/application/Makefile @@ -39,6 +39,7 @@ SRCS = \ application/CayaUtils.cpp \ application/ChatWindow.cpp \ application/Contact.cpp \ + application/Conversation.cpp \ application/EditingFilter.cpp \ application/ImageCache.cpp \ application/Main.cpp \ diff --git a/application/Notifier.h b/application/Notifier.h index 2a24d2d..416a1e4 100644 --- a/application/Notifier.h +++ b/application/Notifier.h @@ -2,19 +2,18 @@ * Copyright 2009-2011, Andrea Anzani. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef Notifier_h_ -#define Notifier_h_ +#ifndef NOTIFIER_H +#define NOTIFIER_H #include - #include #include "Observer.h" + class Notifier { public: - void RegisterObserver(Observer*); void UnregisterObserver(Observer*); @@ -23,8 +22,9 @@ class Notifier void NotifyPointer(int32 what, void* ptr); private: - BObjectList fObserverList; - }; -#endif + + +#endif // NOTIFIER_H + diff --git a/application/Server.cpp b/application/Server.cpp index a1cd753..d75d60f 100644 --- a/application/Server.cpp +++ b/application/Server.cpp @@ -42,13 +42,18 @@ Server::Server() void Server::Quit() { - Contact* linker = NULL; + Contact* contact = NULL; + Conversation* conversation = NULL; - while ((linker = fRosterMap.ValueAt(0))) { - linker->DeleteWindow(); - linker->DeletePopUp(); + while (contact = fRosterMap.ValueAt(0)) { + contact->DeletePopUp(); fRosterMap.RemoveItemAt(0); } + + while (conversation = fChatMap.ValueAt(0)) { + conversation->DeleteWindow(); + fChatMap.RemoveItemAt(0); + } } @@ -121,27 +126,12 @@ Server::Filter(BMessage* message, BHandler **target) filter_result result = B_DISPATCH_MESSAGE; switch (message->what) { - case IM_MESSAGE_RECEIVED: - { - BString id = message->FindString("id"); - if (id.Length() > 0) { - bool found = false; - Contact* item = fRosterMap.ValueFor(id, &found); - if (found) { - ChatWindow* win = item->GetChatWindow(); - item->ShowWindow(); - win->PostMessage(message); - } - } - result = B_SKIP_MESSAGE; - break; - } case CAYA_CLOSE_CHAT_WINDOW: { - BString id = message->FindString("id"); + BString id = message->FindString("chat_id"); if (id.Length() > 0) { bool found = false; - Contact* item = fRosterMap.ValueFor(id, &found); + Conversation* item = fChatMap.ValueFor(id, &found); if (found) item->HideWindow(); @@ -181,18 +171,46 @@ Server::Filter(BMessage* message, BHandler **target) RosterMap -Server::RosterItems() const +Server::Contacts() const { return fRosterMap; } -RosterItem* -Server::RosterItemForId(BString id) +Contact* +Server::ContactById(BString id) { bool found = false; - Contact* item = fRosterMap.ValueFor(id, &found); - return item ? item->GetRosterItem() : NULL; + return fRosterMap.ValueFor(id, &found); +} + + +void +Server::AddContact(Contact* contact) +{ + fRosterMap.AddItem(contact->GetId(), contact); +} + + +ChatMap +Server::Conversations() const +{ + return fChatMap; +} + + +Conversation* +Server::ConversationById(BString id) +{ + bool found = false; + return fChatMap.ValueFor(id, &found); +} + + +void +Server::AddConversation(Conversation* chat) +{ + fChatMap.AddItem(chat->GetId(), chat); } @@ -207,7 +225,7 @@ Server::ImMessage(BMessage* msg) { int i = 0; BString id; - while (msg->FindString("id", i++, &id) == B_OK) { + while (msg->FindString("user_id", i++, &id) == B_OK) { bool found = false; Contact* item = fRosterMap.ValueFor(id, &found); @@ -223,7 +241,6 @@ Server::ImMessage(BMessage* msg) } case IM_OWN_STATUS_SET: { - //msg->PrintToStream(); int32 status; const char* protocol; if (msg->FindInt32("status", &status) != B_OK) @@ -243,104 +260,90 @@ Server::ImMessage(BMessage* msg) if (msg->FindInt32("status", &status) != B_OK) return B_SKIP_MESSAGE; - Contact* linker = _EnsureContact(msg); - if (!linker) + Contact* contact = _EnsureContact(msg); + if (!contact) break; - linker->SetNotifyStatus((CayaStatus)status); + contact->SetNotifyStatus((CayaStatus)status); BString statusMsg; if (msg->FindString("message", &statusMsg) == B_OK) { - linker->SetNotifyPersonalStatus(statusMsg); - linker->GetChatWindow()->UpdatePersonalMessage(); + contact->SetNotifyPersonalStatus(statusMsg); +// contact->GetChatWindow()->UpdatePersonalMessage(); } break; } case IM_CONTACT_INFO: { - Contact* linker = _EnsureContact(msg); - if (!linker) + Contact* contact = _EnsureContact(msg); + if (!contact) break; const char* name = NULL; if ((msg->FindString("name", &name) == B_OK) && (strcmp(name, "") != 0)) - linker->SetNotifyName(name); + contact->SetNotifyName(name); BString status; if (msg->FindString("message", &status) == B_OK) { - linker->SetNotifyPersonalStatus(status); - linker->GetChatWindow()->UpdatePersonalMessage(); + contact->SetNotifyPersonalStatus(status); +// contact->GetChatWindow()->UpdatePersonalMessage(); } break; } case IM_EXTENDED_CONTACT_INFO: { - Contact* linker = _EnsureContact(msg); - if (!linker) + Contact* contact = _EnsureContact(msg); + if (!contact) break; - if (linker->GetName().Length() > 0) + if (contact->GetName().Length() > 0) break; const char* name = NULL; if ((msg->FindString("full name", &name) == B_OK) && (strcmp(name, "") != 0)) - linker->SetNotifyName(name); + contact->SetNotifyName(name); break; } case IM_AVATAR_SET: { - Contact* linker = _EnsureContact(msg); - if (!linker) + Contact* contact = _EnsureContact(msg); + if (!contact) break; entry_ref ref; if (msg->FindRef("ref", &ref) == B_OK) { BBitmap* bitmap = BTranslationUtils::GetBitmap(&ref); - linker->SetNotifyAvatarBitmap(bitmap); + contact->SetNotifyAvatarBitmap(bitmap); } else - linker->SetNotifyAvatarBitmap(NULL); + contact->SetNotifyAvatarBitmap(NULL); break; } case IM_SEND_MESSAGE: { // Route this message through the appropriate ProtocolLooper - Contact* linker = _EnsureContact(msg); - if (linker->GetProtocolLooper()) - linker->GetProtocolLooper()->PostMessage(msg); + Conversation* conversation = _EnsureConversation(msg); + if (conversation->GetProtocolLooper()) + conversation->GetProtocolLooper()->PostMessage(msg); break; } case IM_MESSAGE_RECEIVED: { - BString id = msg->FindString("id"); - if (id.Length() > 0) { - bool found = false; - Contact* item = fRosterMap.ValueFor(id, &found); - if (found) { - ChatWindow* win = item->GetChatWindow(); - item->ShowWindow(); - win->PostMessage(msg); - } - } + Conversation* item = _EnsureConversation(msg); + item->ImMessage(msg); result = B_SKIP_MESSAGE; break; } case IM_CONTACT_STARTED_TYPING: case IM_CONTACT_STOPPED_TYPING: { - BString id = msg->FindString("id"); - if (id.Length() > 0) { - bool found = false; - Contact* item = fRosterMap.ValueFor(id, &found); - if (found) { - ChatWindow* win = item->GetChatWindow(); - item->ShowWindow(true); - win->PostMessage(msg); - } - } + BString id = msg->FindString("chat_id"); + Conversation* item = _EnsureConversation(msg); + item->ImMessage(msg); + result = B_SKIP_MESSAGE; break; } @@ -444,26 +447,59 @@ Server::_LooperFromMessage(BMessage* message) Contact* -Server::_EnsureContact(BMessage* message) +Server::_GetContact(BMessage* message) { if (!message) return NULL; - BString id = message->FindString("id"); + BString id = message->FindString("user_id"); Contact* item = NULL; - if (id.Length() > 0) { + if (id.IsEmpty() == false) { bool found = false; item = fRosterMap.ValueFor(id, &found); - - if (!found) { - item = new Contact(id.String(), Looper()); - item->SetProtocolLooper(_LooperFromMessage(message)); - fRosterMap.AddItem(id, item); - } } return item; } +Contact* +Server::_EnsureContact(BMessage* message) +{ + Contact* contact = _GetContact(message); + BString id = message->FindString("user_id"); + + if (contact == NULL && id.IsEmpty() == false) { + contact = new Contact(id, Looper()); + contact->SetProtocolLooper(_LooperFromMessage(message)); + fRosterMap.AddItem(id, contact); + } + + return contact; +} + + +Conversation* +Server::_EnsureConversation(BMessage* message) +{ + if (!message) + return NULL; + + BString chat_id = message->FindString("chat_id"); + Conversation* item = NULL; + + if (chat_id.IsEmpty() == false) { + bool found = false; + item = fChatMap.ValueFor(chat_id, &found); + + if (!found) { + item = new Conversation(chat_id, Looper()); + item->SetProtocolLooper(_LooperFromMessage(message)); + fChatMap.AddItem(chat_id, item); + } + } + return item; +} + + diff --git a/application/Server.h b/application/Server.h index aeb96e1..11e225e 100644 --- a/application/Server.h +++ b/application/Server.h @@ -13,12 +13,14 @@ #include "CayaConstants.h" #include "Contact.h" +#include "Conversation.h" class CayaProtocol; class RosterItem; class ProtocolLooper; typedef KeyMap RosterMap; +typedef KeyMap ChatMap; typedef KeyMap ProtocolLoopers; class Server: public BMessageFilter { @@ -39,20 +41,28 @@ public: void SendProtocolMessage(BMessage* msg); void SendAllProtocolMessage(BMessage* msg); - RosterMap RosterItems() const; - RosterItem* RosterItemForId(BString id); + RosterMap Contacts() const; + Contact* ContactById(BString id); + void AddContact(Contact* contact); + + ChatMap Conversations() const; + Conversation* ConversationById(BString id); + void AddConversation(Conversation* chat); // TODO: there should be a contact for each account. Contact* GetOwnContact(); private: ProtocolLooper* _LooperFromMessage(BMessage* message); - Contact* _EnsureContact(BMessage* message); + Contact* _GetContact(BMessage* message); + Contact* _EnsureContact(BMessage* message); + Conversation* _EnsureConversation(BMessage* message); void _ReplicantStatusNotify(CayaStatus status); RosterMap fRosterMap; + ChatMap fChatMap; ProtocolLoopers fLoopers; - Contact* fMySelf; + Contact* fMySelf; }; #endif // _SERVER_H diff --git a/application/User.cpp b/application/User.cpp index 92e6de8..bbc443c 100644 --- a/application/User.cpp +++ b/application/User.cpp @@ -14,6 +14,7 @@ #include "CayaProtocolAddOn.h" #include "CayaResources.h" #include "CayaUtils.h" +#include "Conversation.h" #include "NotifyMessage.h" #include "ProtocolLooper.h" #include "ProtocolManager.h" @@ -32,6 +33,22 @@ User::User(BString id, BMessenger msgn) } +void +User::RegisterObserver(Conversation* chat) +{ + Notifier::RegisterObserver(chat); + fConversations.AddItem(chat->GetId(), chat); +} + + +void +User::UnregisterObserver(Conversation* chat) +{ + Notifier::UnregisterObserver(chat); + fConversations.RemoveItemFor(chat->GetId()); +} + + void User::ShowPopUp(BPoint where) { @@ -190,3 +207,10 @@ User::SetNotifyPersonalStatus(BString personalStatus) } +ChatMap +User::Conversations() +{ + return fConversations; +} + + diff --git a/application/User.h b/application/User.h index ca434af..030ba6c 100644 --- a/application/User.h +++ b/application/User.h @@ -3,12 +3,15 @@ * Copyright 2012, Dario Casalinuovo. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef _USER_H_ -#define _USER_H_ +#ifndef USER_H +#define USER_H #include #include #include +#include + +#include #include "Notifier.h" #include "CayaConstants.h" @@ -16,14 +19,24 @@ class BBitmap; class ChatWindow; +class Conversation; class UserPopUp; class ProtocolLooper; class RosterItem; + +typedef KeyMap ChatMap; + + class User : public Notifier { public: User(BString id, BMessenger msgn); + void RegisterObserver(Conversation* chat); + void RegisterObserver(Observer* obs) { Notifier::RegisterObserver(obs); } + void UnregisterObserver(Conversation* chat); + void UnregisterObserver(Observer* obs) { Notifier::UnregisterObserver(obs); } + void ShowPopUp(BPoint where); void DeletePopUp(); void HidePopUp(); @@ -47,6 +60,8 @@ public: void SetNotifyStatus(CayaStatus status); void SetNotifyPersonalStatus(BString personalStatus); + ChatMap Conversations(); + protected: BMessenger fMessenger; ProtocolLooper* fLooper; @@ -58,6 +73,9 @@ protected: BBitmap* fAvatarBitmap; CayaStatus fStatus; UserPopUp* fPopUp; + ChatMap fConversations; }; -#endif // _USER_H_ + +#endif // USER_H + diff --git a/application/views/CayaRenderView.cpp b/application/views/CayaRenderView.cpp index 7874800..a0a55b4 100644 --- a/application/views/CayaRenderView.cpp +++ b/application/views/CayaRenderView.cpp @@ -26,20 +26,22 @@ CayaRenderView::CayaRenderView(const char *name, const char* smileyConfig) ScrollToBottom(); } + void -CayaRenderView::AppendOtherMessage(const char* message) +CayaRenderView::AppendOtherMessage(const char* otherNick, const char* message) { - Append(fOtherNick.String(), COL_OTHERNICK, COL_OTHERNICK, R_TEXT); + Append(otherNick, COL_OTHERNICK, COL_OTHERNICK, R_TEXT); Append(": ", COL_OTHERNICK, COL_OTHERNICK, R_TEXT); AddEmoticText(message, COL_TEXT, R_TEXT, COL_TEXT,R_EMOTICON); Append("\n", COL_TEXT, COL_TEXT, R_TEXT); ScrollToSelection(); } + void CayaRenderView::AppendOwnMessage(const char* message) { - Append("You say: ", COL_OWNNICK, COL_OWNNICK, R_TEXT); + Append("You: ", COL_OWNNICK, COL_OWNNICK, R_TEXT); AddEmoticText(message, COL_TEXT, R_TEXT,COL_TEXT,R_EMOTICON); Append("\n", COL_TEXT, COL_TEXT, R_TEXT); ScrollToSelection(); @@ -55,6 +57,7 @@ CayaRenderView::AddEmoticText(const char * txt, int16 cols , int16 font , int16 Emoticor::Get()->AddText(this, txt, cols, font, cols2, font2); } + void CayaRenderView::PrepareTheme(Theme *fTheme) { @@ -97,5 +100,6 @@ CayaRenderView::PrepareTheme(Theme *fTheme) fTheme->SetTextMargin(5.0); fTheme->WriteUnlock(); - } + + diff --git a/application/views/CayaRenderView.h b/application/views/CayaRenderView.h index 7e58be1..15d53ee 100644 --- a/application/views/CayaRenderView.h +++ b/application/views/CayaRenderView.h @@ -37,19 +37,14 @@ class CayaRenderView : public RunView public: CayaRenderView(const char* name, const char* smileyConfig = NULL); - void AppendOtherMessage(const char* message); + void AppendOtherMessage(const char* otherNick, const char* message); void AppendOwnMessage(const char* message); void AddEmoticText(const char * txt, int16 cols , int16 font , int16 cols2 , int16 font2); - void SetOwnNick(BString nick) { fOwnNick = nick; } - void SetOtherNick(BString nick) { fOtherNick = nick; } - protected: void PrepareTheme(Theme* theme); private: - BString fOwnNick; - BString fOtherNick; Theme* fTheme; SmileTextRender str; diff --git a/application/views/RosterListView.cpp b/application/views/RosterListView.cpp index 576fe65..2e722a2 100644 --- a/application/views/RosterListView.cpp +++ b/application/views/RosterListView.cpp @@ -116,8 +116,8 @@ RosterListView::MessageReceived(BMessage* msg) { if (ritem == NULL) return; - Contact* link = ritem->GetContact(); - link->ShowWindow(false, true); +// Contact* link = ritem->GetContact(); +// link->ShowWindow(false, true); break; } diff --git a/libs/libsupport/KeyMap.h b/libs/libsupport/KeyMap.h index 6c837ee..87cfd4a 100644 --- a/libs/libsupport/KeyMap.h +++ b/libs/libsupport/KeyMap.h @@ -18,8 +18,8 @@ public: TYPE ValueFor(KEY, bool* found = NULL) const; - void RemoveItemAt(int32 position); - void RemoveItemFor(KEY); + TYPE RemoveItemAt(int32 position); + TYPE RemoveItemFor(KEY); KEY KeyAt(uint32 position) const; TYPE ValueAt(uint32 position) const; @@ -69,20 +69,24 @@ KeyMap::ValueFor(KEY k, bool* found) const template -inline void +inline TYPE KeyMap::RemoveItemAt(int32 position) { + TYPE value = ValueAt(position); fIter i = fMap.begin(); std::advance(i, position); fMap.erase(i->first); + return value; } template -inline void +inline TYPE KeyMap::RemoveItemFor(KEY k) { + TYPE value = ValueFor(k); fMap.erase(k); + return value; } diff --git a/protocols/xmpp/JabberHandler.cpp b/protocols/xmpp/JabberHandler.cpp index a16c14e..288ae22 100644 --- a/protocols/xmpp/JabberHandler.cpp +++ b/protocols/xmpp/JabberHandler.cpp @@ -103,7 +103,7 @@ JabberHandler::Process(BMessage* msg) break; } case IM_SEND_MESSAGE: { - const char* id = msg->FindString("id"); + const char* id = msg->FindString("chat_id"); const char* subject = msg->FindString("subject"); const char* body = msg->FindString("body"); @@ -527,7 +527,8 @@ JabberHandler::_MessageSent(const char* id, const char* subject, { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_MESSAGE_SENT); - msg.AddString("id", id); + msg.AddString("user_id", id); + msg.AddString("chat_id", id); msg.AddString("subject", subject); msg.AddString("body", body); _SendMessage(&msg); @@ -662,7 +663,7 @@ JabberHandler::_AvatarChanged(const char* id, const char* filename) msg.AddInt32("im_what", IM_OWN_AVATAR_SET); else { msg.AddInt32("im_what", IM_AVATAR_SET); - msg.AddString("id", id); + msg.AddString("user_id", id); } msg.AddRef("ref", &ref); _SendMessage(&msg); @@ -803,12 +804,12 @@ JabberHandler::handleRoster(const gloox::Roster& roster) int32 subscription = (*it).second->subscription(); // Add jid to the server based contact list message - contactListMsg.AddString("id", jid); + contactListMsg.AddString("user_id", jid); // Contact information message BMessage infoMsg(IM_MESSAGE); infoMsg.AddInt32("im_what", IM_CONTACT_INFO); - infoMsg.AddString("id", jid); + infoMsg.AddString("user_id", jid); infoMsg.AddString("name", name); infoMsg.AddInt32("subscription", subscription); infoMsg.AddInt32("status", CAYA_OFFLINE); @@ -836,7 +837,7 @@ JabberHandler::handleRoster(const gloox::Roster& roster) std::list::iterator msgsIt; for (msgsIt = msgs.begin(); msgsIt != msgs.end(); ++msgsIt) { BMessage msg = (*msgsIt); - const char* jid = msg.FindString("id"); + const char* jid = msg.FindString("user_id"); _SendMessage(&msg); fVCardManager->fetchVCard(gloox::JID(jid), this); } @@ -879,7 +880,8 @@ JabberHandler::handleMessage(const gloox::Message& m, gloox::MessageSession*) // Notify that a chat message was received BMessage msg(IM_MESSAGE); - msg.AddString("id", m.from().bare().c_str()); + msg.AddString("user_id", m.from().bare().c_str()); + msg.AddString("chat_id", m.from().bare().c_str()); msg.AddInt32("im_what", IM_MESSAGE_RECEIVED); if (m.subject() != "") msg.AddString("subject", m.subject().c_str()); @@ -903,7 +905,8 @@ printf("------ %d\n", state); return; BMessage msg(IM_MESSAGE); - msg.AddString("id", from.bare().c_str()); + msg.AddString("user_id", from.bare().c_str()); + msg.AddString("chat_id", from.bare().c_str()); switch (state) { case gloox::ChatStateComposing: @@ -961,7 +964,7 @@ JabberHandler::handleRosterPresence(const gloox::RosterItem& item, { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_STATUS_SET); - msg.AddString("id", item.jidJID().full().c_str()); + msg.AddString("user_id", item.jidJID().full().c_str()); msg.AddInt32("status", _GlooxStatusToCaya(type)); msg.AddString("resource", resource.c_str()); msg.AddString("message", presenceMsg.c_str()); @@ -977,7 +980,7 @@ JabberHandler::handleSelfPresence(const gloox::RosterItem& item, const std::stri BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_OWN_CONTACT_INFO); msg.AddString("protocol", Signature()); - msg.AddString("id", item.jidJID().full().c_str()); + msg.AddString("user_id", item.jidJID().full().c_str()); msg.AddString("name", item.name().c_str()); msg.AddInt32("subscription", item.subscription()); msg.AddInt32("status", _GlooxStatusToCaya(type)); @@ -1047,7 +1050,7 @@ JabberHandler::handleVCard(const gloox::JID& jid, const gloox::VCard* card) BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_EXTENDED_CONTACT_INFO); - msg.AddString("id", jid.bare().c_str()); + msg.AddString("user_id", jid.bare().c_str()); msg.AddString("nick", card->nickname().c_str()); msg.AddString("family name", name.family.c_str()); msg.AddString("given name", name.given.c_str()); diff --git a/protocols/xmpp/Makefile b/protocols/xmpp/Makefile index e0f80b6..99b8983 100644 --- a/protocols/xmpp/Makefile +++ b/protocols/xmpp/Makefile @@ -32,9 +32,11 @@ APP_MIME_SIG = # same name (source.c or source.cpp) are included from different directories. # Also note that spaces in folder names do not work well with this Makefile. SRCS = \ + protocols/xmpp/FacebookProtocol.cpp \ + protocols/xmpp/GoogleTalkProtocol.cpp \ + protocols/xmpp/JabberHandler.cpp \ protocols/xmpp/JabberMain.cpp \ - protocols/xmpp/JabberProtocol.cpp \ - protocols/xmpp/JabberHandler.cpp + protocols/xmpp/JabberProtocol.cpp # Specify the resource definition files to use. Full or relative paths can be