Create Conversation class, use it instead of Contact for chats

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.
This commit is contained in:
Jaidyn Ann 2021-05-24 01:47:21 -05:00
parent 7822ec0449
commit 48d0b7bc96
20 changed files with 587 additions and 231 deletions

View File

@ -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("");
@ -204,7 +208,7 @@ ChatWindow::ImMessage(BMessage* msg)
BString title = "[";
title << fMessageCount;
title << "] ";
title<<fContact->GetName();
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;

View File

@ -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,6 +41,7 @@ public:
void AvoidFocus(bool avoid);
private:
BTextView* fSendView;
Conversation* fConversation;
Contact* fContact;
CayaRenderView* fReceiveView;
BStringView* fStatus;
@ -49,3 +52,4 @@ private:
};
#endif // _CHAT_WINDOW_H

View File

@ -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);
}

View File

@ -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_

View File

@ -0,0 +1,240 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* 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();
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef CONVERSATION_H
#define CONVERSATION_H
#include <Messenger.h>
#include <libsupport/KeyMap.h>
#include "Notifier.h"
#include "User.h"
class ChatWindow;
class Contact;
class ProtocolLooper;
class Server;
typedef KeyMap<BString, Contact*> 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

View File

@ -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;

View File

@ -18,6 +18,7 @@ class StatusView;
class RosterListView;
class RosterItem;
class MainWindow: public BWindow, public Observer {
public:
MainWindow();

View File

@ -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 \

View File

@ -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 <String.h>
#include <ObjectList.h>
#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<Observer> fObserverList;
};
#endif
#endif // NOTIFIER_H

View File

@ -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;
}

View File

@ -13,12 +13,14 @@
#include "CayaConstants.h"
#include "Contact.h"
#include "Conversation.h"
class CayaProtocol;
class RosterItem;
class ProtocolLooper;
typedef KeyMap<BString, Contact*> RosterMap;
typedef KeyMap<BString, Conversation*> ChatMap;
typedef KeyMap<bigtime_t, ProtocolLooper*> ProtocolLoopers;
class Server: public BMessageFilter {
@ -39,18 +41,26 @@ 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* _GetContact(BMessage* message);
Contact* _EnsureContact(BMessage* message);
Conversation* _EnsureConversation(BMessage* message);
void _ReplicantStatusNotify(CayaStatus status);
RosterMap fRosterMap;
ChatMap fChatMap;
ProtocolLoopers fLoopers;
Contact* fMySelf;
};

View File

@ -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;
}

View File

@ -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 <String.h>
#include <Message.h>
#include <Messenger.h>
#include <ObjectList.h>
#include <libsupport/KeyMap.h>
#include "Notifier.h"
#include "CayaConstants.h"
@ -16,14 +19,24 @@
class BBitmap;
class ChatWindow;
class Conversation;
class UserPopUp;
class ProtocolLooper;
class RosterItem;
typedef KeyMap<BString, Conversation*> 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

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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<KEY, TYPE>::ValueFor(KEY k, bool* found) const
template<class KEY, class TYPE>
inline void
inline TYPE
KeyMap<KEY, TYPE>::RemoveItemAt(int32 position)
{
TYPE value = ValueAt(position);
fIter i = fMap.begin();
std::advance(i, position);
fMap.erase(i->first);
return value;
}
template<class KEY, class TYPE>
inline void
inline TYPE
KeyMap<KEY, TYPE>::RemoveItemFor(KEY k)
{
TYPE value = ValueFor(k);
fMap.erase(k);
return value;
}

View File

@ -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<BMessage>::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());

View File

@ -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