Conversation.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /*
  2. * Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
  3. * All rights reserved. Distributed under the terms of the MIT license.
  4. */
  5. #include "Conversation.h"
  6. #include <Beep.h>
  7. #include <Catalog.h>
  8. #include <DateTimeFormat.h>
  9. #include <Locale.h>
  10. #include <Notification.h>
  11. #include <StringFormat.h>
  12. #include "AppConstants.h"
  13. #include "AppPreferences.h"
  14. #include "ChatOMatic.h"
  15. #include "ChatProtocolMessages.h"
  16. #include "RenderView.h"
  17. #include "ChatCommand.h"
  18. #include "ConversationItem.h"
  19. #include "ConversationView.h"
  20. #include "Flags.h"
  21. #include "ImageCache.h"
  22. #include "MainWindow.h"
  23. #include "NotifyMessage.h"
  24. #include "ProtocolLooper.h"
  25. #include "ProtocolManager.h"
  26. #include "Server.h"
  27. #include "TheApp.h"
  28. #include "Utils.h"
  29. Conversation::Conversation(BString id, BMessenger msgn)
  30. :
  31. fID(id),
  32. fName(id),
  33. fMessenger(msgn),
  34. fChatView(NULL),
  35. fLooper(NULL),
  36. fIcon(ImageCache::Get()->GetImage("kOnePersonIcon")),
  37. fDateFormatter(),
  38. fRoomFlags(0),
  39. fDisallowedFlags(0),
  40. fNotifyMessageCount(0),
  41. fNotifyMentionCount(0),
  42. fUserIcon(false)
  43. {
  44. fConversationItem = new ConversationItem(fName.String(), this);
  45. RegisterObserver(fConversationItem);
  46. }
  47. Conversation::~Conversation()
  48. {
  49. ((TheApp*)be_app)->GetMainWindow()->RemoveConversation(this);
  50. if (fLooper != NULL)
  51. fLooper->RemoveConversation(this);
  52. delete fChatView;
  53. delete fConversationItem;
  54. }
  55. BString
  56. Conversation::GetId() const
  57. {
  58. return fID;
  59. }
  60. void
  61. Conversation::ImMessage(BMessage* msg)
  62. {
  63. int32 im_what = msg->FindInt32("im_what");
  64. switch(im_what)
  65. {
  66. case IM_MESSAGE_RECEIVED:
  67. {
  68. #undef B_TRANSLATION_CONTEXT
  69. #define B_TRANSLATION_CONTEXT "Conversation ― Notifications"
  70. _EnsureUser(msg);
  71. _LogChatMessage(msg);
  72. GetView()->MessageReceived(msg);
  73. BString text = msg->FindString("body");
  74. Contact* contact = GetOwnContact();
  75. BWindow* win = fChatView->Window();
  76. bool winFocus = (win != NULL &&
  77. (win->IsFront() && !(win->IsMinimized())));
  78. bool mentioned = ((contact->GetName().IsEmpty() == false
  79. && text.IFindFirst(contact->GetName()) != B_ERROR)
  80. || (text.IFindFirst(contact->GetId()) != B_ERROR));
  81. // Sound the bell, if appropriate
  82. if (winFocus == false) {
  83. if (mentioned == true
  84. && AppPreferences::Get()->SoundOnMention == true)
  85. system_beep(APP_MENTION_BEEP);
  86. else if (AppPreferences::Get()->SoundOnMessageReceived == true
  87. && ((fUsers.CountItems() <=2 && (fRoomFlags & ROOM_NOTIFY_DM))
  88. || (fRoomFlags & ROOM_NOTIFY_ALL)))
  89. system_beep(APP_MESSAGE_BEEP);
  90. }
  91. // Send a notification, if appropriate
  92. if (winFocus == false && AppPreferences::Get()->NotifyNewMessage) {
  93. BString notifyTitle = B_TRANSLATE("New mention");
  94. BString notifyText = B_TRANSLATE("You've been summoned from "
  95. "%source%.");
  96. if (mentioned == false) {
  97. fNotifyMessageCount++;
  98. notifyTitle.SetTo(B_TRANSLATE("New message"));
  99. notifyText.SetTo("");
  100. BStringFormat pmFormat(B_TRANSLATE("{0, plural,"
  101. "=1{You've got a new message from %source%.}"
  102. "other{You've got # new messages from %source%.}}"));
  103. pmFormat.Format(notifyText, fNotifyMessageCount);
  104. }
  105. else
  106. fNotifyMentionCount++;
  107. notifyText.ReplaceAll("%source%", GetName());
  108. if ((fUsers.CountItems() <= 2 && (fRoomFlags & ROOM_NOTIFY_DM))
  109. || (fRoomFlags & ROOM_NOTIFY_ALL) || mentioned == true)
  110. {
  111. BBitmap* icon = IconBitmap();
  112. if (icon == NULL)
  113. icon = ProtocolBitmap();
  114. BNotification notification(B_INFORMATION_NOTIFICATION);
  115. notification.SetGroup(BString(APP_NAME));
  116. notification.SetTitle(notifyTitle);
  117. notification.SetIcon(icon);
  118. notification.SetContent(notifyText);
  119. notification.SetMessageID(fID);
  120. notification.Send();
  121. }
  122. }
  123. // Misc. features Caya contributors planned on adding
  124. BWindow* mainWin = ((TheApp*)be_app)->GetMainWindow();
  125. if (win == NULL && AppPreferences::Get()->MarkUnreadWindow == true)
  126. mainWin->SetTitle(BString(mainWin->Title()).Prepend("[!]"));
  127. if (win == NULL && AppPreferences::Get()->MoveToCurrentWorkspace)
  128. mainWin->SetWorkspaces(B_CURRENT_WORKSPACE);
  129. if (win == NULL && AppPreferences::Get()->RaiseOnMessageReceived)
  130. mainWin->Activate(true);
  131. // If unattached, highlight the ConversationItem
  132. if (win == NULL && mentioned == true)
  133. NotifyInteger(INT_NEW_MENTION, fNotifyMentionCount);
  134. else if (win == NULL)
  135. NotifyInteger(INT_NEW_MESSAGE, fNotifyMessageCount);
  136. break;
  137. }
  138. case IM_MESSAGE_SENT:
  139. {
  140. _LogChatMessage(msg);
  141. GetView()->MessageReceived(msg);
  142. break;
  143. }
  144. case IM_SEND_MESSAGE:
  145. {
  146. #undef B_TRANSLATION_CONTEXT
  147. #define B_TRANSLATION_CONTEXT "Conversation ― Command info"
  148. BString body;
  149. if (msg->FindString("body", &body) != B_OK)
  150. break;
  151. if (IsCommand(body.String()) == false) {
  152. fMessenger.SendMessage(msg);
  153. break;
  154. }
  155. BString name = CommandName(body);
  156. BString args = CommandArgs(body);
  157. ChatCommand* cmd = _GetServer()->CommandById(name, fLooper->GetInstance());
  158. if (cmd == NULL) {
  159. if (name == "me")
  160. fMessenger.SendMessage(msg);
  161. else
  162. _WarnUser(BString(B_TRANSLATE("That isn't a valid command. "
  163. "Try /help for a list.")));
  164. break;
  165. }
  166. BString error("");
  167. if (cmd->Parse(args, &error, this) == false)
  168. _WarnUser(error);
  169. break;
  170. }
  171. case IM_ROOM_METADATA:
  172. {
  173. BString name;
  174. if (msg->FindString("chat_name", &name) == B_OK)
  175. SetNotifyName(name.String());
  176. BString subject;
  177. if (msg->FindString("subject", &subject) == B_OK)
  178. SetNotifySubject(subject.String());
  179. int32 defaultFlags;
  180. if (msg->FindInt32("room_default_flags", &defaultFlags) == B_OK)
  181. if (fRoomFlags == 0)
  182. fRoomFlags = defaultFlags;
  183. int32 disabledFlags;
  184. if (msg->FindInt32("room_disallowed_flags", &disabledFlags) == B_OK)
  185. fDisallowedFlags = disabledFlags;
  186. _CacheRoomFlags();
  187. break;
  188. }
  189. case IM_ROOM_PARTICIPANTS:
  190. {
  191. // Get rid of implicity-defined users rq
  192. for (int i = 0; i < fGuests.CountStrings(); i++) {
  193. RemoveUser(UserById(fGuests.StringAt(i)));
  194. fGuests.Remove(i);
  195. }
  196. BStringList ids;
  197. BStringList names;
  198. msg->FindStrings("user_name", &names);
  199. if (msg->FindStrings("user_id", &ids) != B_OK)
  200. break;
  201. for (int i = 0; i < ids.CountStrings(); i++) {
  202. BMessage user;
  203. user.AddString("user_name", names.StringAt(i));
  204. user.AddString("user_id", ids.StringAt(i));
  205. _EnsureUser(&user, false);
  206. }
  207. break;
  208. }
  209. case IM_ROOM_PARTICIPANT_JOINED:
  210. {
  211. BString user_id;
  212. if (msg->FindString("user_id", &user_id) != B_OK)
  213. break;
  214. if (UserById(user_id) == NULL) {
  215. _EnsureUser(msg, false);
  216. GetView()->MessageReceived(msg);
  217. }
  218. break;
  219. }
  220. case IM_ROOM_PARTICIPANT_LEFT:
  221. case IM_ROOM_PARTICIPANT_KICKED:
  222. case IM_ROOM_PARTICIPANT_BANNED:
  223. {
  224. BString user_id = msg->FindString("user_id");
  225. User* user;
  226. if (user_id.IsEmpty() == true || (user = UserById(user_id)) == NULL)
  227. break;
  228. GetView()->MessageReceived(msg);
  229. RemoveUser(user);
  230. break;
  231. }
  232. case IM_ROOM_ROLECHANGED:
  233. {
  234. BString user_id;
  235. Role* role = _GetRole(msg);
  236. if (msg->FindString("user_id", &user_id) != B_OK || role == NULL)
  237. break;
  238. SetRole(user_id, role);
  239. GetView()->MessageReceived(msg);
  240. break;
  241. }
  242. case IM_USER_NICKNAME_SET:
  243. {
  244. BString user_id = msg->FindString("user_id");
  245. BString user_name = msg->FindString("user_name");
  246. if (user_id.IsEmpty() == false && user_name.IsEmpty() == false) {
  247. User* user = UserById(user_id);
  248. BString text(B_TRANSLATE("** %old% has changed their nick to %new%."));
  249. text.ReplaceAll("%new%", user_name);
  250. if (user != NULL)
  251. text.ReplaceAll("%old%", user->GetName());
  252. else
  253. text.ReplaceAll("%old%", user_id);
  254. BMessage* notify = new BMessage(IM_MESSAGE);
  255. notify->AddInt32("im_what", IM_MESSAGE_RECEIVED);
  256. notify->AddString("body", text);
  257. GetView()->MessageReceived(notify);
  258. }
  259. break;
  260. }
  261. case IM_LOGS_RECEIVED:
  262. default:
  263. GetView()->MessageReceived(msg);
  264. }
  265. }
  266. void
  267. Conversation::ObserveString(int32 what, BString str)
  268. {
  269. GetView()->InvalidateUserList();
  270. }
  271. void
  272. Conversation::ObserveInteger(int32 what, int32 value)
  273. {
  274. if (what == INT_WINDOW_FOCUSED) {
  275. fNotifyMessageCount = 0;
  276. fNotifyMentionCount = 0;
  277. }
  278. else
  279. GetView()->InvalidateUserList();
  280. }
  281. void
  282. Conversation::ObservePointer(int32 what, void* ptr)
  283. {
  284. GetView()->InvalidateUserList();
  285. }
  286. void
  287. Conversation::SetNotifyName(const char* name)
  288. {
  289. if (BString(name) == fName)
  290. return;
  291. fName = name;
  292. NotifyString(STR_ROOM_NAME, fName.String());
  293. }
  294. void
  295. Conversation::SetNotifySubject(const char* subject)
  296. {
  297. if (BString(subject) == fSubject)
  298. return;
  299. fSubject = subject;
  300. NotifyString(STR_ROOM_SUBJECT, fSubject.String());
  301. }
  302. bool
  303. Conversation::SetNotifyIconBitmap(BBitmap* icon)
  304. {
  305. if (icon != NULL) {
  306. fIcon = icon;
  307. NotifyPointer(PTR_ROOM_BITMAP, (void*)icon);
  308. return true;
  309. }
  310. return false;
  311. }
  312. BMessenger
  313. Conversation::Messenger() const
  314. {
  315. return fMessenger;
  316. }
  317. void
  318. Conversation::SetMessenger(BMessenger messenger)
  319. {
  320. fMessenger = messenger;
  321. }
  322. ProtocolLooper*
  323. Conversation::GetProtocolLooper() const
  324. {
  325. return fLooper;
  326. }
  327. void
  328. Conversation::SetProtocolLooper(ProtocolLooper* looper)
  329. {
  330. fLooper = looper;
  331. _LoadRoomFlags();
  332. }
  333. BBitmap*
  334. Conversation::ProtocolBitmap() const
  335. {
  336. ChatProtocol* protocol = fLooper->Protocol();
  337. ChatProtocolAddOn* addOn
  338. = ProtocolManager::Get()->ProtocolAddOn(protocol->Signature());
  339. return addOn->ProtoIcon();
  340. }
  341. BBitmap*
  342. Conversation::IconBitmap() const
  343. {
  344. return fIcon;
  345. }
  346. BString
  347. Conversation::GetName() const
  348. {
  349. return fName;
  350. }
  351. BString
  352. Conversation::GetSubject() const
  353. {
  354. return fSubject;
  355. }
  356. ConversationView*
  357. Conversation::GetView()
  358. {
  359. if (fChatView != NULL)
  360. return fChatView;
  361. fChatView = new ConversationView(this);
  362. fChatView->RegisterObserver(fConversationItem);
  363. fChatView->RegisterObserver(this);
  364. RegisterObserver(fChatView);
  365. if (!(fRoomFlags & ROOM_POPULATE_LOGS))
  366. return fChatView;
  367. BMessage logMsg;
  368. if (_GetChatLogs(&logMsg) == B_OK)
  369. fChatView->MessageReceived(&logMsg);
  370. return fChatView;
  371. }
  372. void
  373. Conversation::ShowView(bool typing, bool userAction)
  374. {
  375. ((TheApp*)be_app)->GetMainWindow()->SetConversation(this);
  376. }
  377. ConversationItem*
  378. Conversation::GetListItem()
  379. {
  380. return fConversationItem;
  381. }
  382. UserMap
  383. Conversation::Users()
  384. {
  385. return fUsers;
  386. }
  387. User*
  388. Conversation::UserById(BString id)
  389. {
  390. bool found = false;
  391. return fUsers.ValueFor(id, &found);
  392. }
  393. void
  394. Conversation::AddUser(User* user)
  395. {
  396. if (user == NULL)
  397. return;
  398. BMessage msg;
  399. msg.AddString("user_id", user->GetId());
  400. msg.AddString("user_name", user->GetName());
  401. _EnsureUser(&msg, false);
  402. _SortConversationList();
  403. }
  404. void
  405. Conversation::RemoveUser(User* user)
  406. {
  407. if (user == NULL)
  408. return;
  409. fUsers.RemoveItemFor(user->GetId());
  410. user->UnregisterObserver(this);
  411. GetView()->UpdateUserList(fUsers);
  412. _SortConversationList();
  413. _UpdateIcon();
  414. NotifyInteger(INT_ROOM_MEMBERS, fUsers.CountItems());
  415. }
  416. Contact*
  417. Conversation::GetOwnContact()
  418. {
  419. return fLooper->GetOwnContact();
  420. }
  421. void
  422. Conversation::SetRole(BString id, Role* role)
  423. {
  424. Role* oldRole = fRoles.ValueFor(id);
  425. if (oldRole != NULL) {
  426. fRoles.RemoveItemFor(id);
  427. delete oldRole;
  428. }
  429. if (role != NULL)
  430. fRoles.AddItem(id, role);
  431. }
  432. Role*
  433. Conversation::GetRole(BString id)
  434. {
  435. return fRoles.ValueFor(id);
  436. }
  437. void
  438. Conversation::SetFlags(int32 flags)
  439. {
  440. fRoomFlags = flags;
  441. _CacheRoomFlags();
  442. }
  443. void
  444. Conversation::_WarnUser(BString message)
  445. {
  446. BMessage* warning = new BMessage(IM_MESSAGE);
  447. warning->AddInt32("im_what", IM_MESSAGE_RECEIVED);
  448. warning->AddString("body", message.Append('\n', 1).InsertChars("-- ", 0));
  449. GetView()->MessageReceived(warning);
  450. }
  451. void
  452. Conversation::_LogChatMessage(BMessage* msg)
  453. {
  454. // Binary logs
  455. // TODO: Don't hardcode 31, expose maximum as a setting
  456. const int32 MAX = 31;
  457. BMessage logMsg(IM_MESSAGE);
  458. if (_GetChatLogs(&logMsg) != B_OK) {
  459. logMsg.what = IM_MESSAGE;
  460. logMsg.AddInt32("im_what", IM_LOGS_RECEIVED);
  461. }
  462. BMessage last;
  463. if (logMsg.FindMessage("message", MAX, &last) == B_OK)
  464. logMsg.RemoveData("message", 0);
  465. msg->AddInt64("when", time(NULL));
  466. logMsg.AddMessage("message", msg);
  467. BFile logFile(fCachePath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE);
  468. WriteAttributeMessage(&logFile, "Chat:logs", &logMsg);
  469. // Plain-text logs
  470. // Gotta make sure the formatting's pretty!
  471. BString date;
  472. fDateFormatter.Format(date, time(0), B_SHORT_DATE_FORMAT, B_MEDIUM_TIME_FORMAT);
  473. BString id = msg->FindString("user_id");
  474. BString name = msg->FindString("user_name");
  475. BString body = msg->FindString("body");
  476. if (id.IsEmpty() == true && name.IsEmpty() == true)
  477. return;
  478. else if (name.IsEmpty() == true) {
  479. User* user = UserById(id);
  480. name = user ? user->GetName() : id;
  481. }
  482. BString logLine("[");
  483. logLine << date << "] <" << name << "> " << body << "\n";
  484. logFile.Write(logLine.String(), logLine.Length());
  485. }
  486. status_t
  487. Conversation::_GetChatLogs(BMessage* msg)
  488. {
  489. _EnsureCachePath();
  490. BFile logFile(fCachePath.Path(), B_READ_WRITE | B_CREATE_FILE);
  491. return ReadAttributeMessage(&logFile, "Chat:logs", msg);
  492. }
  493. void
  494. Conversation::_CacheRoomFlags()
  495. {
  496. _EnsureCachePath();
  497. BFile cacheFile(fCachePath.Path(), B_READ_WRITE | B_CREATE_FILE);
  498. if (cacheFile.InitCheck() != B_OK)
  499. return;
  500. cacheFile.WriteAttr("Chat:flags", B_INT32_TYPE, 0, &fRoomFlags, sizeof(int32));
  501. }
  502. void
  503. Conversation::_LoadRoomFlags()
  504. {
  505. _EnsureCachePath();
  506. BFile cacheFile(fCachePath.Path(), B_READ_ONLY);
  507. if (cacheFile.InitCheck() != B_OK)
  508. return;
  509. cacheFile.ReadAttr("Chat:flags", B_INT32_TYPE, 0, &fRoomFlags, sizeof(int32));
  510. }
  511. void
  512. Conversation::_EnsureCachePath()
  513. {
  514. if (fCachePath.InitCheck() == B_OK)
  515. return;
  516. fCachePath.SetTo(RoomCachePath(fLooper->Protocol()->GetName(),
  517. fID.String()));
  518. }
  519. User*
  520. Conversation::_EnsureUser(BMessage* msg, bool implicit)
  521. {
  522. BString id = msg->FindString("user_id");
  523. BString name = msg->FindString("user_name");
  524. if (id.IsEmpty() == true) return NULL;
  525. User* user = UserById(id);
  526. User* serverUser = fLooper->UserById(id);
  527. // Not here, but found in server
  528. if (user == NULL && serverUser != NULL)
  529. user = serverUser;
  530. // Not anywhere; create user
  531. else if (user == NULL) {
  532. user = new User(id, _GetServer()->Looper());
  533. user->SetProtocolLooper(fLooper);
  534. fLooper->AddUser(user);
  535. }
  536. // It's been implicitly defined (rather than explicit join), shame!
  537. if (UserById(id) == NULL && implicit == true) {
  538. fGuests.Add(id);
  539. // The response to this will be used to determine if this guest stays
  540. BMessage msg(IM_MESSAGE);
  541. msg.AddInt32("im_what", IM_GET_ROOM_PARTICIPANTS);
  542. msg.AddString("chat_id", fID);
  543. fLooper->MessageReceived(&msg);
  544. }
  545. if (UserById(id) == NULL) {
  546. fUsers.AddItem(id, user);
  547. fUsers.AddItem(id, user);
  548. GetView()->UpdateUserList(fUsers);
  549. _UpdateIcon(user);
  550. NotifyInteger(INT_ROOM_MEMBERS, fUsers.CountItems());
  551. }
  552. if (name.IsEmpty() == false && user->GetName() != name)
  553. user->SetNotifyName(name);
  554. user->RegisterObserver(this);
  555. return user;
  556. }
  557. Role*
  558. Conversation::_GetRole(BMessage* msg)
  559. {
  560. if (!msg)
  561. return NULL;
  562. BString title;
  563. int32 perms;
  564. int32 priority;
  565. if (msg->FindString("role_title", &title) != B_OK
  566. || msg->FindInt32("role_perms", &perms) != B_OK
  567. || msg->FindInt32("role_priority", &priority) != B_OK)
  568. return NULL;
  569. return new Role(title, perms, priority);
  570. }
  571. void
  572. Conversation::_UpdateIcon(User* user)
  573. {
  574. if (_IsDefaultIcon(fIcon) == false && fUserIcon == false)
  575. return;
  576. // If it's a one-on-one chat, try to use the other user's icon
  577. if (user != NULL && fUsers.CountItems() == 2
  578. && user->GetId() != GetOwnContact()->GetId()
  579. && _IsDefaultIcon(user->AvatarBitmap()) == false) {
  580. fUserIcon = SetNotifyIconBitmap(user->AvatarBitmap());
  581. return;
  582. }
  583. switch (fUsers.CountItems())
  584. {
  585. case 0:
  586. case 1:
  587. SetNotifyIconBitmap(ImageCache::Get()->GetImage("kOnePersonIcon"));
  588. break;
  589. case 2:
  590. SetNotifyIconBitmap(ImageCache::Get()->GetImage("kTwoPeopleIcon"));
  591. break;
  592. case 3:
  593. SetNotifyIconBitmap(ImageCache::Get()->GetImage("kThreePeopleIcon"));
  594. break;
  595. case 4:
  596. SetNotifyIconBitmap(ImageCache::Get()->GetImage("kFourPeopleIcon"));
  597. break;
  598. default:
  599. SetNotifyIconBitmap(ImageCache::Get()->GetImage("kMorePeopleIcon"));
  600. break;
  601. }
  602. fUserIcon = false;
  603. }
  604. bool
  605. Conversation::_IsDefaultIcon(BBitmap* icon)
  606. {
  607. return (icon == NULL
  608. || icon == ImageCache::Get()->GetImage("kPersonIcon")
  609. || icon == ImageCache::Get()->GetImage("kOnePersonIcon")
  610. || icon == ImageCache::Get()->GetImage("kTwoPeopleIcon")
  611. || icon == ImageCache::Get()->GetImage("kThreePeopleIcon")
  612. || icon == ImageCache::Get()->GetImage("kFourPeopleIcon")
  613. || icon == ImageCache::Get()->GetImage("kMorePeopleIcon"));
  614. }
  615. void
  616. Conversation::_SortConversationList()
  617. {
  618. if (fUsers.CountItems() <= 2 || fUsers.CountItems() == 3)
  619. ((TheApp*)be_app)->GetMainWindow()->SortConversation(this);
  620. }
  621. Server*
  622. Conversation::_GetServer()
  623. {
  624. return ((TheApp*)be_app)->GetMainWindow()->GetServer();
  625. }