From 8512e9ad033a46d7bb30dad87de281adaae0696a Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Tue, 17 Aug 2021 13:22:20 -0500 Subject: [PATCH] New binary log format, with color/face support Binary logs are no longer stored as a single message with a list of strings and int64s ("body", "user_name", "user_id", "when"), but a message with sub-messages (IM_MESSAGE_RECEIVED) verbatim saved. This has the main benefit of preserving message formatting (coloring, bold, italics, etc). --- application/ChatProtocolMessages.h | 8 +-- application/Conversation.cpp | 78 ++++++++------------------ application/views/ConversationView.cpp | 75 ++++++------------------- application/views/ConversationView.h | 1 - 4 files changed, 45 insertions(+), 117 deletions(-) diff --git a/application/ChatProtocolMessages.h b/application/ChatProtocolMessages.h index 36508bc..63e5d34 100644 --- a/application/ChatProtocolMessages.h +++ b/application/ChatProtocolMessages.h @@ -76,9 +76,8 @@ enum im_what_code { If chat_id is ommitted, the message is sent to the protocol's system buffer, rather than a specific conversation. face_start and face_length specify the location of formatted text in - the body, and "face" is the desired font face. Unsupported in bulk, + the body, and "face" is the desired font face. color_* works much the same, but with colors. Not much else to say. - i.e., IM_LOGS_RECEIVED. Requires: String "body" Allows: String "chat_id", String "user_id", String "user_name", int32s "face_start", int32s "face_length", uint16s "face" @@ -87,9 +86,8 @@ enum im_what_code { IM_MESSAGE_RECEIVED = 22, /*! Logs received →App - Without "when" (a time_t), the logged message will lack a timestamp - Requires: Strings "chat_id", Strings "user_id", Strings "body" - Accepts: in64s "when" */ + Should be a message with several sub-messages of IM_MESSAGE_RECEIVED. + Requires: Messages "message" */ IM_LOGS_RECEIVED = 23, diff --git a/application/Conversation.cpp b/application/Conversation.cpp index 81a8f2c..d7864a9 100644 --- a/application/Conversation.cpp +++ b/application/Conversation.cpp @@ -123,7 +123,6 @@ Conversation::ImMessage(BMessage* msg) if (icon == NULL) icon = ProtocolBitmap(); - BNotification notification(B_INFORMATION_NOTIFICATION); notification.SetGroup(BString(APP_NAME)); notification.SetTitle(notifyTitle); @@ -402,7 +401,6 @@ Conversation::GetView() BMessage logMsg; if (_GetChatLogs(&logMsg) == B_OK) fChatView->MessageReceived(&logMsg); - return fChatView; } @@ -499,66 +497,42 @@ Conversation::_WarnUser(BString message) void Conversation::_LogChatMessage(BMessage* msg) { + // Binary logs + // TODO: Don't hardcode 31, expose maximum as a setting + const int32 MAX = 31; + + BMessage logMsg(IM_MESSAGE); + if (_GetChatLogs(&logMsg) != B_OK) { + logMsg.what = IM_MESSAGE; + logMsg.AddInt32("im_what", IM_LOGS_RECEIVED); + } + + BMessage last; + if (logMsg.FindMessage("message", MAX, &last) == B_OK) + logMsg.RemoveData("message", 0); + msg->AddInt64("when", time(NULL)); + logMsg.AddMessage("message", msg); + + BFile logFile(fCachePath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE); + WriteAttributeMessage(&logFile, "Chat:logs", &logMsg); + + // Plain-text logs + // Gotta make sure the formatting's pretty! BString date; fDateFormatter.Format(date, time(0), B_SHORT_DATE_FORMAT, B_MEDIUM_TIME_FORMAT); - BString id = msg->FindString("user_id"); BString name = msg->FindString("user_name"); BString body = msg->FindString("body"); - if (id.IsEmpty() == true) + if (id.IsEmpty() == true && name.IsEmpty() == true) return; - - if (name.IsEmpty() == true) { + else if (name.IsEmpty() == true) { User* user = UserById(id); - if (user == NULL) - name = id; - else - name = user->GetName(); + name = user ? user->GetName() : id; } - // Binary logs - // TODO: Don't hardcode 31, expose maximum as a setting - int32 max = 31; - BStringList user_ids, user_names, bodies; - int64 times[max] = { 0 }; - times[0] = (int64)time(NULL); - - BMessage logMsg; - if (_GetChatLogs(&logMsg) == B_OK) { - logMsg.FindStrings("body", &bodies); - logMsg.FindStrings("user_id", &user_ids); - logMsg.FindStrings("user_name", &user_names); - - int64 found; - for (int i = 0; i < max; i++) - if (logMsg.FindInt64("when", i, &found) == B_OK) - times[i + 1] = found; - - bodies.Remove(max); - user_ids.Remove(max); - user_names.Remove(max); - bodies.Add(body, 0); - user_ids.Add(id, 0); - user_names.Add(name, 0); - } - - BMessage newLogMsg(IM_MESSAGE); - newLogMsg.AddInt32("im_what", IM_LOGS_RECEIVED); - newLogMsg.AddStrings("body", bodies); - newLogMsg.AddStrings("user_id", user_ids); - newLogMsg.AddStrings("user_name", user_names); - newLogMsg.AddInt64("when", time(NULL)); - for (int i = 0; i < max; i++) - newLogMsg.AddInt64("when", times[i]); - - BFile logFile(fCachePath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE); - WriteAttributeMessage(&logFile, "Chat:logs", &newLogMsg); - - // Plain-text logs BString logLine("["); logLine << date << "] <" << name << "> " << body << "\n"; - logFile.Write(logLine.String(), logLine.Length()); } @@ -567,9 +541,7 @@ status_t Conversation::_GetChatLogs(BMessage* msg) { _EnsureCachePath(); - BFile logFile(fCachePath.Path(), B_READ_WRITE | B_CREATE_FILE); - return ReadAttributeMessage(&logFile, "Chat:logs", msg); } @@ -581,7 +553,6 @@ Conversation::_CacheRoomFlags() BFile cacheFile(fCachePath.Path(), B_READ_WRITE | B_CREATE_FILE); if (cacheFile.InitCheck() != B_OK) return; - cacheFile.WriteAttr("Chat:flags", B_INT32_TYPE, 0, &fRoomFlags, sizeof(int32)); } @@ -593,7 +564,6 @@ Conversation::_LoadRoomFlags() BFile cacheFile(fCachePath.Path(), B_READ_ONLY); if (cacheFile.InitCheck() != B_OK) return; - cacheFile.ReadAttr("Chat:flags", B_INT32_TYPE, 0, &fRoomFlags, sizeof(int32)); } diff --git a/application/views/ConversationView.cpp b/application/views/ConversationView.cpp index c6124d3..7ca860a 100644 --- a/application/views/ConversationView.cpp +++ b/application/views/ConversationView.cpp @@ -393,7 +393,16 @@ ConversationView::_AppendOrEnqueueMessage(BMessage* msg) // later [AttachedToWindow()], since you can't edit an unattached // RenderView. if (Window() == NULL) { - fMessageQueue.AddItem(new BMessage(*msg)); + // If contains multiple chat messages (e.g., IM_LOGS_RECEIVED), add all + int32 i = -1; + BMessage text; + while (msg->FindMessage("message", i + 1, &text) == B_OK) { + fMessageQueue.AddItem(new BMessage(text)); + i++; + } + // Else, add the lonely, lonely, single-messaged one + if (i == -1) + fMessageQueue.AddItem(new BMessage(*msg)); return false; } @@ -412,62 +421,7 @@ ConversationView::_AppendMessage(BMessage* msg) return; } - // … else we're jamming a message into this view no matter what it takes! - if (msg->HasInt32("face_start") || msg->HasInt32("color_start")) { - _AppendFormattedMessage(msg); - return; - } - - // For unformatted (normal or bulk) messages - BStringList user_ids, user_names, bodies; - if (msg->FindStrings("body", &bodies) != B_OK) - return; - msg->FindStrings("user_id", &user_ids); - msg->FindStrings("user_name", &user_names); - - for (int i = bodies.CountStrings(); i >= 0; i--) { - User* sender = NULL; - if (fConversation != NULL) - sender = fConversation->UserById(user_ids.StringAt(i)); - BString sender_id = user_ids.StringAt(i); - BString sender_name = user_names.StringAt(i); - BString body = bodies.StringAt(i); - rgb_color userColor = ui_color(B_PANEL_TEXT_COLOR); - int64 timeInt; - - if (msg->FindInt64("when", i, &timeInt) != B_OK) - timeInt = (int64)time(NULL); - - if (sender != NULL) { - sender_name = sender->GetName(); - userColor = sender->fItemColor; - } - - if (sender_name.IsEmpty() == true && sender_id.IsEmpty() == false) - sender_name = sender_id; - - if (sender_id.IsEmpty() == true && sender_name.IsEmpty() == true) { - fReceiveView->AppendGeneric(body.String()); - continue; - } - - if (body.StartsWith("/me ")) { - BString meMsg = "** "; - meMsg << sender_name.String() << " "; - meMsg << body.RemoveFirst("/me "); - fReceiveView->AppendGeneric(meMsg.String()); - continue; - } - - fReceiveView->AppendMessage(sender_name.String(), body.String(), - userColor, (time_t)timeInt); - } -} - - -void -ConversationView::_AppendFormattedMessage(BMessage* msg) -{ + // Otherwise, it's message time! int64 timeInt; BString user_id; BString user_name = msg->FindString("user_name"); @@ -496,6 +450,13 @@ ConversationView::_AppendFormattedMessage(BMessage* msg) return; } + if (body.StartsWith("/me ")) { + BString meMsg = "** "; + meMsg << user_name.String() << " "; + meMsg << body.RemoveFirst("/me "); + fReceiveView->AppendGeneric(meMsg.String()); + return; + } fReceiveView->AppendTimestamp(timeInt); fReceiveView->AppendUserstamp(user_name, userColor); diff --git a/application/views/ConversationView.h b/application/views/ConversationView.h index dd7a999..6a2d481 100644 --- a/application/views/ConversationView.h +++ b/application/views/ConversationView.h @@ -57,7 +57,6 @@ private: bool _AppendOrEnqueueMessage(BMessage* msg); void _AppendMessage(BMessage* msg); - void _AppendFormattedMessage(BMessage* msg); // Helper functions for _AppendFormattedMessage() void _EnableStartingFaces(BMessage* msg, int32 index,