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