From dc3fdd65c83e48f93d805c9763861c161cd98b75 Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Sun, 6 Jun 2021 12:02:26 -0500 Subject: [PATCH] Store chatlogs in binary and text formats If chat logs are stored in an endless plain-text file, they're going to be a pain to parse. If they're stored in a binary file, they're a pain for the user to `grep` or go through manually, but they're easier to parse. Why not both? Logs are now stored with a BMessage (with BStringLists) in the 'logs' attribute, and the plain-text logs in the file itself. The attribute will only store 20 messages, but the file itself will be appended to forever. The logs directory also changed, from ~/config/settings/Caya/Cache/Logs to ~/config/settings/Caya/Logs. Useful functions for reading/writing messages to and from an attribute were borrowed from BePodder's libfunky. :-) --- application/CayaUtils.cpp | 70 +++++++++++++++++++++++--- application/CayaUtils.h | 6 ++- application/Conversation.cpp | 60 ++++++++++++---------- application/Conversation.h | 2 +- application/views/ConversationView.cpp | 36 ++++++------- protocols/xmpp/JabberHandler.cpp | 2 +- 6 files changed, 119 insertions(+), 57 deletions(-) diff --git a/application/CayaUtils.cpp b/application/CayaUtils.cpp index 3a8d70b..c077ad3 100644 --- a/application/CayaUtils.cpp +++ b/application/CayaUtils.cpp @@ -1,11 +1,8 @@ /* * Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved. + * Copyright 2014, Funky Idea Software * Distributed under the terms of the MIT License. - * - * Authors: - * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com */ - #include #include @@ -15,6 +12,8 @@ #include #include +#include + #include "CayaUtils.h" @@ -129,8 +128,11 @@ CayaCachePath() const char* CayaLogPath(const char* signature, const char* subsignature) { - BPath path(CayaCachePath()); - path.Append("Logs"); + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return NULL; + + path.Append("Caya/Logs"); path.Append(signature); if (BString(signature) != BString(subsignature) @@ -175,6 +177,62 @@ CayaTintColor(rgb_color color, int severity) } +status_t +ReadAttributeData(BNode* node, const char* name, char** buffer, int32 *size) { + attr_info info; + status_t ret = node->GetAttrInfo(name, &info); + + if (ret == B_OK) { + *buffer = (char *)calloc(info.size, sizeof(char)); + ret = node->ReadAttr(name, info.type, 0, *buffer, info.size); + + if (ret > B_OK) { + *size = ret; + ret = B_OK; + } + else + free(*buffer); + } + + return ret; +} + + +status_t +WriteAttributeMessage(BNode* node, const char* name, BMessage* data) +{ + BMallocIO malloc; + status_t ret=data->Flatten(&malloc); + + if( ret == B_OK) { + ret = node->WriteAttr(name,B_ANY_TYPE,0,malloc.Buffer(),malloc.BufferLength()); + + if(ret > B_OK) + ret=B_OK; + } + + return ret; +} + + +status_t +ReadAttributeMessage(BNode* node, const char* name, BMessage* data) +{ + char *buffer = NULL; + int32 size = 0; + + status_t ret = ReadAttributeData(node,name,&buffer,&size); + + if(size>0 && buffer!=NULL) { + BMemoryIO mem(buffer,size); + ret = data->Unflatten(&mem); + free(buffer); + } + + return ret; +} + + extern "C" { status_t diff --git a/application/CayaUtils.h b/application/CayaUtils.h index d99f9b5..4935363 100644 --- a/application/CayaUtils.h +++ b/application/CayaUtils.h @@ -24,9 +24,13 @@ const char* CayaAccountPath(const char* signature, const char* subsignature); const char* CayaCachePath(); const char* CayaLogPath(const char* signature, const char* subsignature); -// Will return a tinted color― light or dark― based on brightness. rgb_color CayaTintColor(rgb_color color, int severity); +// Borrowed from BePodder's own libfunky +status_t ReadAttributeData(BNode* node, const char* name, char** buffer, int32 *size); +status_t WriteAttributeMessage(BNode* node, const char* name, BMessage* data); +status_t ReadAttributeMessage(BNode* node, const char* name, BMessage* data); + extern "C" status_t our_image(image_info& image); diff --git a/application/Conversation.cpp b/application/Conversation.cpp index 65f7306..e01581d 100644 --- a/application/Conversation.cpp +++ b/application/Conversation.cpp @@ -173,11 +173,9 @@ Conversation::GetView() if (fLooper->Protocol()->SaveLogs() == false) return fChatView; - BStringList logs = _GetChatLogs(); - BMessage logMsg(IM_MESSAGE); - logMsg.AddInt32("im_what", IM_LOGS_RECEIVED); - logMsg.AddStrings("body", logs); - fChatView->MessageReceived(&logMsg); + BMessage logMsg; + if (_GetChatLogs(&logMsg) == B_OK) + fChatView->MessageReceived(&logMsg); RegisterObserver(fChatView); return fChatView; @@ -266,8 +264,32 @@ Conversation::_LogChatMessage(BMessage* msg) fDateFormatter.Format(date, time(0), B_SHORT_DATE_FORMAT, B_MEDIUM_TIME_FORMAT); BString id = msg->FindString("user_id"); - BString uname; + BString body = msg->FindString("body"); + // Binary logs + // TODO: Don't hardcode 21, expose maximum as a setting + BStringList users, bodies; + + BMessage logMsg; + if (_GetChatLogs(&logMsg) == B_OK) { + logMsg.FindStrings("body", &bodies); + logMsg.FindStrings("user_id", &users); + bodies.Remove(21); + users.Remove(21); + bodies.Add(body, 0); + users.Add(id, 0); + } + + BMessage newLogMsg(IM_MESSAGE); + newLogMsg.AddInt32("im_what", IM_LOGS_RECEIVED); + newLogMsg.AddStrings("body", bodies); + newLogMsg.AddStrings("user_id", users); + + BFile logFile(fLogPath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE); + WriteAttributeMessage(&logFile, "logs", &newLogMsg); + + // Plain-text logs + BString uname; if (id.IsEmpty() == false) uname = UserById(id)->GetName(); else @@ -278,37 +300,21 @@ Conversation::_LogChatMessage(BMessage* msg) logLine << "] "; logLine << uname; logLine << ": "; - logLine << msg->FindString("body"); + logLine << body; logLine << "\n"; - - // TODO: Don't hardcode 21, expose maximum as a setting - BStringList logs = _GetChatLogs(); - logs.Remove(21); - logs.Add(logLine, 0); - - BMessage newLogMsg; - newLogMsg.AddStrings("log", logs); - - BFile logFile(fLogPath.Path(), B_READ_WRITE | B_CREATE_FILE); - newLogMsg.Flatten(&logFile); + logFile.Write(logLine.String(), logLine.Length()); } -BStringList -Conversation::_GetChatLogs() +status_t +Conversation::_GetChatLogs(BMessage* msg) { _EnsureLogPath(); BFile logFile(fLogPath.Path(), B_READ_WRITE | B_CREATE_FILE); - BMessage logMsg; - BStringList logs; - if (logMsg.Unflatten(&logFile) == B_OK) { - logMsg.FindStrings("log", &logs); - } - - return logs; + return ReadAttributeMessage(&logFile, "logs", msg); } diff --git a/application/Conversation.h b/application/Conversation.h index 324849c..a6ca147 100644 --- a/application/Conversation.h +++ b/application/Conversation.h @@ -68,7 +68,7 @@ public: private: void _LogChatMessage(BMessage* msg); - BStringList _GetChatLogs(); + status_t _GetChatLogs(BMessage* msg); void _EnsureLogPath(); User* _EnsureUser(BMessage* msg); diff --git a/application/views/ConversationView.cpp b/application/views/ConversationView.cpp index 3d830f6..eb9ef8a 100644 --- a/application/views/ConversationView.cpp +++ b/application/views/ConversationView.cpp @@ -275,31 +275,25 @@ ConversationView::_AppendOrEnqueueMessage(BMessage* msg) void ConversationView::_AppendMessage(BMessage* msg) { + BStringList users, bodies; + if (msg->FindStrings("body", &bodies) != B_OK + || msg->FindStrings("user_id", &users) != B_OK) + return; - BString message = msg->FindString("body"); - BString id = msg->FindString("user_id"); - BString uname = ""; + for (int i = bodies.CountStrings(); i >= 0; i--) { + User* sender = fConversation->UserById(users.StringAt(i)); + BString sender_name; + BString body = bodies.StringAt(i); - if (id.IsEmpty() == false) { - User* sender = fConversation->UserById(id); + if (sender != NULL) + sender_name = sender->GetName(); - if (sender == NULL || (uname = sender->GetName()) == NULL) - uname = id; - } + if (sender_name.IsEmpty() == true) { + fReceiveView->AppendGenericMessage(body.String()); + continue; + } - if (msg->FindInt32("im_what") == IM_MESSAGE_SENT) - fReceiveView->AppendOwnMessage(message.String()); - - else if (uname.IsEmpty() == false) - fReceiveView->AppendOtherMessage(uname.String(), message.String()); - - else { - BStringList bodies; - if (msg->FindStrings("body", &bodies) != B_OK) - return; - - for (int i = bodies.CountStrings(); i >= 0; i--) - fReceiveView->AppendGenericMessage(bodies.StringAt(i).String()); + fReceiveView->AppendOtherMessage(sender_name.String(), body.String()); } } diff --git a/protocols/xmpp/JabberHandler.cpp b/protocols/xmpp/JabberHandler.cpp index 3cc4ea0..eac5840 100644 --- a/protocols/xmpp/JabberHandler.cpp +++ b/protocols/xmpp/JabberHandler.cpp @@ -688,7 +688,7 @@ JabberHandler::_MessageSent(const char* id, const char* subject, { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_MESSAGE_SENT); - msg.AddString("user_id", id); + msg.AddString("user_id", fJid.bare().c_str()); msg.AddString("chat_id", id); msg.AddString("subject", subject); msg.AddString("body", body);