mcabber/mcabber/screen.c
changeset 2225 dc3b3ac1ba76
parent 2222 ce1043326bbc
child 2226 c1eb68306520
--- a/mcabber/mcabber/screen.c	Sat Nov 07 12:16:15 2015 +0100
+++ b/mcabber/mcabber/screen.c	Sat Nov 07 12:21:12 2015 +0100
@@ -100,10 +100,12 @@
 static GHashTable *winbufhash;
 
 typedef struct {
-  GList  *hbuf;
-  GList  *top;     // If top is NULL, we'll display the last lines
-  char    cleared; // For ex, user has issued a /clear command...
-  char    lock;
+  GList    *hbuf;
+  GList    *top;      // If top is NULL, we'll display the last lines
+  char      cleared;  // For ex, user has issued a /clear command...
+  char      lock;
+  char      refcount; // refcount > 0 if there are other users of this struct
+                      // e.g. with symlinked history
 } buffdata;
 
 typedef struct {
@@ -1038,6 +1040,7 @@
 static winbuf *scr_new_buddy(const char *title, int dont_show)
 {
   winbuf *tmp;
+  char *id;
 
   tmp = g_new0(winbuf, 1);
 
@@ -1055,30 +1058,34 @@
   update_panels();
 
   // If title is NULL, this is a special buffer
-  if (title) {
-    char *id;
-    id = hlog_get_log_jid(title);
-    if (id) {
-      winbuf *wb = scr_search_window(id, FALSE);
-      if (!wb)
-        wb = scr_new_buddy(id, TRUE);
-      tmp->bd=wb->bd;
-      g_free(id);
-    } else {  // Load buddy history from file (if enabled)
-      tmp->bd = g_new0(buffdata, 1);
-      hlog_read_history(title, &tmp->bd->hbuf,
-                        maxX - Roster_Width - scr_getprefixwidth());
-
-      // Set a readmark to separate new content
-      hbuf_set_readmark(tmp->bd->hbuf, TRUE);
-    }
-
-    id = g_strdup(title);
-    mc_strtolower(id);
-    g_hash_table_insert(winbufhash, id, tmp);
-  } else {
+  if (!title) {
     tmp->bd = g_new0(buffdata, 1);
+    return tmp;
   }
+
+  id = hlog_get_log_jid(title);
+  if (id) {
+    // This is a symlinked history log file.
+    // Let's check if the target JID buffer has already been created.
+    winbuf *wb = scr_search_window(id, FALSE);
+    if (!wb)
+      wb = scr_new_buddy(id, TRUE);
+    tmp->bd = wb->bd;
+    tmp->bd->refcount++;
+    g_free(id);
+  } else {  // Load buddy history from file (if enabled)
+    tmp->bd = g_new0(buffdata, 1);
+    hlog_read_history(title, &tmp->bd->hbuf,
+                      maxX - Roster_Width - scr_getprefixwidth());
+
+    // Set a readmark to separate new content
+    hbuf_set_readmark(tmp->bd->hbuf, TRUE);
+  }
+
+  id = g_strdup(title);
+  mc_strtolower(id);
+  g_hash_table_insert(winbufhash, id, tmp);
+
   return tmp;
 }
 
@@ -2867,7 +2874,9 @@
   gboolean retval = FALSE;
 
   // Delete the current hbuf
-  hbuf_free(&win_entry->bd->hbuf);
+  // unless we close the buffer *and* this is a shared bd structure
+  if (!(*p_closebuf && win_entry->bd->refcount))
+    hbuf_free(&win_entry->bd->hbuf);
 
   if (*p_closebuf) {
     GSList *roster_elt;
@@ -2876,6 +2885,12 @@
         ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
     if (roster_elt)
       buddy_setactiveresource(roster_elt->data, NULL);
+    if (win_entry->bd->refcount) {
+      win_entry->bd->refcount--;
+    } else {
+      g_free(win_entry->bd);
+      win_entry->bd = NULL;
+    }
   } else {
     win_entry->bd->cleared = FALSE;
     win_entry->bd->top = NULL;