about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2016-01-30 23:11:31 +0000
committerJames Booth <boothj5@gmail.com>2016-01-30 23:11:31 +0000
commit3f3182a7dea9a3f55d7c08da9f97cee5aaa27670 (patch)
tree90a6573a6fd199f8323edecf70e667cdd5e07ef9
parent20659b9841ec6e1728f192e80982556dcc130a16 (diff)
downloadprofani-tty-3f3182a7dea9a3f55d7c08da9f97cee5aaa27670.tar.gz
Reorganise rosterwin.c
-rw-r--r--src/ui/rosterwin.c839
1 files changed, 429 insertions, 410 deletions
diff --git a/src/ui/rosterwin.c b/src/ui/rosterwin.c
index 44c086d3..fe579442 100644
--- a/src/ui/rosterwin.c
+++ b/src/ui/rosterwin.c
@@ -49,6 +49,366 @@ typedef enum {
     ROSTER_CONTACT_UNREAD
 } roster_contact_theme_t;
 
+static void _rosterwin_contacts_all(ProfLayoutSplit *layout, gboolean newline);
+static void _rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const presence, char *title,
+    gboolean newline);
+static void _rosterwin_contacts_by_group(ProfLayoutSplit *layout, char *group, gboolean newline);
+
+static void _rosterwin_contact(ProfLayoutSplit *layout, PContact contact);
+static void _rosterwin_presence(ProfLayoutSplit *layout, theme_item_t colour, const char *presence, const char *status,
+    int current_indent);
+static void _rosterwin_resources(ProfLayoutSplit *layout, PContact contact, int current_indent,
+    roster_contact_theme_t theme_type, int unread);
+
+static void _rosterwin_rooms(ProfLayoutSplit *layout, gboolean newline);
+static void _rosterwin_room(ProfLayoutSplit *layout, ProfMucWin *mucwin);
+static void _rosterwin_private_chats(ProfLayoutSplit *layout);
+
+static theme_item_t _get_roster_theme(roster_contact_theme_t theme_type, const char *presence);
+static int _compare_rooms_name(ProfMucWin *a, ProfMucWin *b);
+static int _compare_rooms_unread(ProfMucWin *a, ProfMucWin *b);
+
+void
+rosterwin_roster(void)
+{
+    ProfWin *console = wins_get_console();
+    if (!console) {
+        return;
+    }
+
+    jabber_conn_status_t conn_status = jabber_get_connection_status();
+    if (conn_status != JABBER_CONNECTED) {
+        return;
+    }
+
+    ProfLayoutSplit *layout = (ProfLayoutSplit*)console->layout;
+    assert(layout->memcheck == LAYOUT_SPLIT_MEMCHECK);
+    werase(layout->subwin);
+
+    gboolean newline = FALSE;
+    char *roomspos = prefs_get_string(PREF_ROSTER_ROOMS_POS);
+    if (prefs_get_boolean(PREF_ROSTER_ROOMS) && (g_strcmp0(roomspos, "first") == 0)) {
+        _rosterwin_rooms(layout, newline);
+        newline = TRUE;
+    }
+
+    if (prefs_get_boolean(PREF_ROSTER_CONTACTS)) {
+        char *by = prefs_get_string(PREF_ROSTER_BY);
+        if (g_strcmp0(by, "presence") == 0) {
+            _rosterwin_contacts_by_presence(layout, "chat", "Available for chat", newline);
+            _rosterwin_contacts_by_presence(layout, "online", "Online", TRUE);
+            _rosterwin_contacts_by_presence(layout, "away", "Away", TRUE);
+            _rosterwin_contacts_by_presence(layout, "xa", "Extended Away", TRUE);
+            _rosterwin_contacts_by_presence(layout, "dnd", "Do not disturb", TRUE);
+            _rosterwin_contacts_by_presence(layout, "offline", "Offline", TRUE);
+        } else if (g_strcmp0(by, "group") == 0) {
+            GSList *groups = roster_get_groups();
+            GSList *curr_group = groups;
+            while (curr_group) {
+                _rosterwin_contacts_by_group(layout, curr_group->data, newline);
+                newline = TRUE;
+                curr_group = g_slist_next(curr_group);
+            }
+            g_slist_free_full(groups, free);
+            _rosterwin_contacts_by_group(layout, NULL, newline);
+        } else {
+            _rosterwin_contacts_all(layout, newline);
+        }
+        prefs_free_string(by);
+    }
+
+    if (prefs_get_boolean(PREF_ROSTER_ROOMS) && (g_strcmp0(roomspos, "last") == 0)) {
+        _rosterwin_rooms(layout, TRUE);
+    }
+
+    prefs_free_string(roomspos);
+}
+static void
+_rosterwin_contacts_all(ProfLayoutSplit *layout, gboolean newline)
+{
+    GSList *contacts = NULL;
+
+    char *order = prefs_get_string(PREF_ROSTER_ORDER);
+    gboolean offline = prefs_get_boolean(PREF_ROSTER_OFFLINE);
+    if (g_strcmp0(order, "presence") == 0) {
+        contacts = roster_get_contacts(ROSTER_ORD_PRESENCE, offline);
+    } else {
+        contacts = roster_get_contacts(ROSTER_ORD_NAME, offline);
+    }
+    prefs_free_string(order);
+
+    wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+    GString *title = g_string_new(" ");
+    char ch = prefs_get_roster_header_char();
+    if (ch) {
+        g_string_append_printf(title, "%c", ch);
+    }
+    if (newline) {
+        win_sub_newline_lazy(layout->subwin);
+    }
+
+    g_string_append(title, "Roster");
+
+    char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
+    if (g_strcmp0(countpref, "items") == 0) {
+        int itemcount = g_slist_length(contacts);
+        if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+            g_string_append_printf(title, " (%d)", itemcount);
+        } else {
+            g_string_append_printf(title, " (%d)", itemcount);
+        }
+    } else if (g_strcmp0(countpref, "unread") == 0) {
+        int unreadcount = 0;
+        GSList *curr = contacts;
+        while (curr) {
+            PContact contact = curr->data;
+            const char *barejid = p_contact_barejid(contact);
+            ProfChatWin *chatwin = wins_get_chat(barejid);
+            if (chatwin) {
+                unreadcount += chatwin->unread;
+            }
+            curr = g_slist_next(curr);
+        }
+        if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+            g_string_append_printf(title, " (%d)", unreadcount);
+        } else if (unreadcount > 0) {
+            g_string_append_printf(title, " (%d)", unreadcount);
+        }
+    }
+    prefs_free_string(countpref);
+
+    gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
+    win_sub_print(layout->subwin, title->str, FALSE, wrap, 1);
+    g_string_free(title, TRUE);
+    wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+
+    if (contacts) {
+        GSList *curr_contact = contacts;
+        while (curr_contact) {
+            PContact contact = curr_contact->data;
+            _rosterwin_contact(layout, contact);
+            curr_contact = g_slist_next(curr_contact);
+        }
+    }
+    g_slist_free(contacts);
+}
+
+static void
+_rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const presence, char *title, gboolean newline)
+{
+    if ((g_strcmp0(presence, "offline") == 0) && !prefs_get_boolean(PREF_ROSTER_OFFLINE)) {
+        return;
+    }
+
+    GSList *contacts = roster_get_contacts_by_presence(presence);
+
+    // if this group has contacts, or if we want to show empty groups
+    if (contacts || prefs_get_boolean(PREF_ROSTER_EMPTY)) {
+        if (newline) {
+            win_sub_newline_lazy(layout->subwin);
+        }
+        wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+        GString *title_str = g_string_new(" ");
+        char ch = prefs_get_roster_header_char();
+        if (ch) {
+            g_string_append_printf(title_str, "%c", ch);
+        }
+        g_string_append(title_str, title);
+
+        char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
+        if (g_strcmp0(countpref, "items") == 0) {
+            int itemcount = g_slist_length(contacts);
+            if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+                g_string_append_printf(title_str, " (%d)", itemcount);
+            } else if (itemcount > 0) {
+                g_string_append_printf(title_str, " (%d)", itemcount);
+            }
+        } else if (g_strcmp0(countpref, "unread") == 0) {
+            int unreadcount = 0;
+            GSList *curr = contacts;
+            while (curr) {
+                PContact contact = curr->data;
+                const char *barejid = p_contact_barejid(contact);
+                ProfChatWin *chatwin = wins_get_chat(barejid);
+                if (chatwin) {
+                    unreadcount += chatwin->unread;
+                }
+                curr = g_slist_next(curr);
+            }
+            if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+                g_string_append_printf(title_str, " (%d)", unreadcount);
+            } else if (unreadcount > 0) {
+                g_string_append_printf(title_str, " (%d)", unreadcount);
+            }
+        }
+        prefs_free_string(countpref);
+
+        gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
+        win_sub_print(layout->subwin, title_str->str, FALSE, wrap, 1);
+        g_string_free(title_str, TRUE);
+        wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+    }
+
+    if (contacts) {
+        GSList *curr_contact = contacts;
+        while (curr_contact) {
+            PContact contact = curr_contact->data;
+            _rosterwin_contact(layout, contact);
+            curr_contact = g_slist_next(curr_contact);
+        }
+    }
+    g_slist_free(contacts);
+}
+
+static void
+_rosterwin_contacts_by_group(ProfLayoutSplit *layout, char *group, gboolean newline)
+{
+    GSList *contacts = NULL;
+
+    char *order = prefs_get_string(PREF_ROSTER_ORDER);
+    gboolean offline = prefs_get_boolean(PREF_ROSTER_OFFLINE);
+    if (g_strcmp0(order, "presence") == 0) {
+        contacts = roster_get_group(group, ROSTER_ORD_PRESENCE, offline);
+    } else {
+        contacts = roster_get_group(group, ROSTER_ORD_NAME, offline);
+    }
+    prefs_free_string(order);
+
+    if (contacts || prefs_get_boolean(PREF_ROSTER_EMPTY)) {
+        if (newline) {
+            win_sub_newline_lazy(layout->subwin);
+        }
+        wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+        GString *title = g_string_new(" ");
+        char ch = prefs_get_roster_header_char();
+        if (ch) {
+            g_string_append_printf(title, "%c", ch);
+        }
+        if (group) {
+            g_string_append(title, group);
+        } else {
+            g_string_append(title, "no group");
+        }
+
+        char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
+        if (g_strcmp0(countpref, "items") == 0) {
+            int itemcount = g_slist_length(contacts);
+            if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+                g_string_append_printf(title, " (%d)", itemcount);
+            } else if (itemcount > 0) {
+                g_string_append_printf(title, " (%d)", itemcount);
+            }
+        } else if (g_strcmp0(countpref, "unread") == 0) {
+            int unreadcount = 0;
+            GSList *curr = contacts;
+            while (curr) {
+                PContact contact = curr->data;
+                const char *barejid = p_contact_barejid(contact);
+                ProfChatWin *chatwin = wins_get_chat(barejid);
+                if (chatwin) {
+                    unreadcount += chatwin->unread;
+                }
+                curr = g_slist_next(curr);
+            }
+            if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+                g_string_append_printf(title, " (%d)", unreadcount);
+            } else if (unreadcount > 0) {
+                g_string_append_printf(title, " (%d)", unreadcount);
+            }
+        }
+        prefs_free_string(countpref);
+
+        gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
+        win_sub_print(layout->subwin, title->str, FALSE, wrap, 1);
+        g_string_free(title, TRUE);
+        wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+
+        GSList *curr_contact = contacts;
+        while (curr_contact) {
+            PContact contact = curr_contact->data;
+            _rosterwin_contact(layout, contact);
+            curr_contact = g_slist_next(curr_contact);
+        }
+    }
+    g_slist_free(contacts);
+}
+
+static void
+_rosterwin_contact(ProfLayoutSplit *layout, PContact contact)
+{
+    const char *name = p_contact_name_or_jid(contact);
+    const char *presence = p_contact_presence(contact);
+    const char *status = p_contact_status(contact);
+    const char *barejid = p_contact_barejid(contact);
+    int unread = 0;
+
+    roster_contact_theme_t theme_type = ROSTER_CONTACT;
+    ProfChatWin *chatwin = wins_get_chat(barejid);
+    if (chatwin) {
+        if (chatwin->unread > 0) {
+            theme_type = ROSTER_CONTACT_UNREAD;
+            unread = chatwin->unread;
+        } else {
+            theme_type = ROSTER_CONTACT_ACTIVE;
+        }
+    }
+
+    theme_item_t presence_colour = _get_roster_theme(theme_type, presence);
+
+    wattron(layout->subwin, theme_attrs(presence_colour));
+    GString *msg = g_string_new(" ");
+    int indent = prefs_get_roster_contact_indent();
+    int current_indent = 0;
+    if (indent > 0) {
+        current_indent += indent;
+        while (indent > 0) {
+            g_string_append(msg, " ");
+            indent--;
+        }
+    }
+    char ch = prefs_get_roster_contact_char();
+    if (ch) {
+        g_string_append_printf(msg, "%c", ch);
+    }
+
+    char *unreadpos = prefs_get_string(PREF_ROSTER_UNREAD);
+    if ((g_strcmp0(unreadpos, "before") == 0) && unread > 0) {
+        g_string_append_printf(msg, "(%d) ", unread);
+        unread = 0;
+    }
+    g_string_append(msg, name);
+    if (g_strcmp0(unreadpos, "after") == 0) {
+        if (!prefs_get_boolean(PREF_ROSTER_RESOURCE)) {
+            if (unread > 0) {
+                g_string_append_printf(msg, " (%d)", unread);
+            }
+            unread = 0;
+        }
+    }
+    prefs_free_string(unreadpos);
+
+    win_sub_newline_lazy(layout->subwin);
+    gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
+    win_sub_print(layout->subwin, msg->str, FALSE, wrap, current_indent);
+    g_string_free(msg, TRUE);
+    wattroff(layout->subwin, theme_attrs(presence_colour));
+
+    if (prefs_get_boolean(PREF_ROSTER_RESOURCE)) {
+        _rosterwin_resources(layout, contact, current_indent, theme_type, unread);
+    } else if (prefs_get_boolean(PREF_ROSTER_PRESENCE) || prefs_get_boolean(PREF_ROSTER_STATUS)) {
+        if (unread > 0) {
+            GString *unreadmsg = g_string_new("");
+            g_string_append_printf(unreadmsg, " (%d)", unread);
+            wattron(layout->subwin, theme_attrs(presence_colour));
+            win_sub_print(layout->subwin, unreadmsg->str, FALSE, wrap, current_indent);
+            g_string_free(unreadmsg, TRUE);
+            wattroff(layout->subwin, theme_attrs(presence_colour));
+        }
+
+        _rosterwin_presence(layout, presence_colour, presence, status, current_indent);
+    }
+}
+
 static void
 _rosterwin_presence(ProfLayoutSplit *layout, theme_item_t colour, const char *presence, const char *status,
     int current_indent)
@@ -132,19 +492,9 @@ _rosterwin_presence(ProfLayoutSplit *layout, theme_item_t colour, const char *pr
     }
 }
 
-theme_item_t
-_get_roster_theme(roster_contact_theme_t theme_type, const char *presence)
-{
-    switch (theme_type) {
-    case ROSTER_CONTACT:        return theme_roster_presence_attrs(presence);
-    case ROSTER_CONTACT_ACTIVE: return theme_roster_active_presence_attrs(presence);
-    case ROSTER_CONTACT_UNREAD: return theme_roster_unread_presence_attrs(presence);
-    default:                    return theme_roster_presence_attrs(presence);
-    }
-}
-
 static void
-_rosterwin_resources(ProfLayoutSplit *layout, PContact contact, int current_indent, roster_contact_theme_t theme_type, int unread)
+_rosterwin_resources(ProfLayoutSplit *layout, PContact contact, int current_indent, roster_contact_theme_t theme_type,
+    int unread)
 {
     gboolean join = prefs_get_boolean(PREF_ROSTER_RESOURCE_JOIN);
 
@@ -276,92 +626,30 @@ _rosterwin_resources(ProfLayoutSplit *layout, PContact contact, int current_inde
 }
 
 static void
-_rosterwin_contact(ProfLayoutSplit *layout, PContact contact)
+_rosterwin_rooms(ProfLayoutSplit *layout, gboolean newline)
 {
-    const char *name = p_contact_name_or_jid(contact);
-    const char *presence = p_contact_presence(contact);
-    const char *status = p_contact_status(contact);
-    const char *barejid = p_contact_barejid(contact);
     int unread = 0;
-
-    roster_contact_theme_t theme_type = ROSTER_CONTACT;
-    ProfChatWin *chatwin = wins_get_chat(barejid);
-    if (chatwin) {
-        if (chatwin->unread > 0) {
-            theme_type = ROSTER_CONTACT_UNREAD;
-            unread = chatwin->unread;
-        } else {
-            theme_type = ROSTER_CONTACT_ACTIVE;
-        }
-    }
-
-    theme_item_t presence_colour = _get_roster_theme(theme_type, presence);
-
-    wattron(layout->subwin, theme_attrs(presence_colour));
-    GString *msg = g_string_new(" ");
-    int indent = prefs_get_roster_contact_indent();
-    int current_indent = 0;
-    if (indent > 0) {
-        current_indent += indent;
-        while (indent > 0) {
-            g_string_append(msg, " ");
-            indent--;
-        }
-    }
-    char ch = prefs_get_roster_contact_char();
-    if (ch) {
-        g_string_append_printf(msg, "%c", ch);
-    }
-
-    char *unreadpos = prefs_get_string(PREF_ROSTER_UNREAD);
-    if ((g_strcmp0(unreadpos, "before") == 0) && unread > 0) {
-        g_string_append_printf(msg, "(%d) ", unread);
-        unread = 0;
-    }
-    g_string_append(msg, name);
-    if (g_strcmp0(unreadpos, "after") == 0) {
-        if (!prefs_get_boolean(PREF_ROSTER_RESOURCE)) {
-            if (unread > 0) {
-                g_string_append_printf(msg, " (%d)", unread);
+    GList *rooms = muc_rooms();
+    GList *rooms_sorted = NULL;
+    GList *curr_room = rooms;
+    while (curr_room) {
+        ProfMucWin *mucwin = wins_get_muc(curr_room->data);
+        if (mucwin) {
+            char *order = prefs_get_string(PREF_ROSTER_ROOMS_ORDER);
+            if (g_strcmp0(order, "unread") == 0) {
+                rooms_sorted = g_list_insert_sorted(rooms_sorted, mucwin, (GCompareFunc)_compare_rooms_unread);
+            } else {
+                rooms_sorted = g_list_insert_sorted(rooms_sorted, mucwin, (GCompareFunc)_compare_rooms_name);
             }
-            unread = 0;
-        }
-    }
-    prefs_free_string(unreadpos);
-
-    win_sub_newline_lazy(layout->subwin);
-    gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
-    win_sub_print(layout->subwin, msg->str, FALSE, wrap, current_indent);
-    g_string_free(msg, TRUE);
-    wattroff(layout->subwin, theme_attrs(presence_colour));
-
-    if (prefs_get_boolean(PREF_ROSTER_RESOURCE)) {
-        _rosterwin_resources(layout, contact, current_indent, theme_type, unread);
-    } else if (prefs_get_boolean(PREF_ROSTER_PRESENCE) || prefs_get_boolean(PREF_ROSTER_STATUS)) {
-        if (unread > 0) {
-            GString *unreadmsg = g_string_new("");
-            g_string_append_printf(unreadmsg, " (%d)", unread);
-            wattron(layout->subwin, theme_attrs(presence_colour));
-            win_sub_print(layout->subwin, unreadmsg->str, FALSE, wrap, current_indent);
-            g_string_free(unreadmsg, TRUE);
-            wattroff(layout->subwin, theme_attrs(presence_colour));
+            prefs_free_string(order);
+            unread += mucwin->unread;
         }
-
-        _rosterwin_presence(layout, presence_colour, presence, status, current_indent);
-    }
-}
-
-static void
-_rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const presence, char *title, gboolean newline)
-{
-    if ((g_strcmp0(presence, "offline") == 0) && !prefs_get_boolean(PREF_ROSTER_OFFLINE)) {
-        return;
+        curr_room = g_list_next(curr_room);
     }
+    g_list_free(rooms);
 
-    GSList *contacts = roster_get_contacts_by_presence(presence);
-
-    // if this group has contacts, or if we want to show empty groups
-    if (contacts || prefs_get_boolean(PREF_ROSTER_EMPTY)) {
+    // if there are active rooms, or if we want to show empty groups
+    if (rooms_sorted || prefs_get_boolean(PREF_ROSTER_EMPTY)) {
         if (newline) {
             win_sub_newline_lazy(layout->subwin);
         }
@@ -371,32 +659,33 @@ _rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const prese
         if (ch) {
             g_string_append_printf(title_str, "%c", ch);
         }
-        g_string_append(title_str, title);
+        g_string_append(title_str, "Rooms");
 
         char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
         if (g_strcmp0(countpref, "items") == 0) {
-            int itemcount = g_slist_length(contacts);
-            if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-                g_string_append_printf(title_str, " (%d)", itemcount);
-            } else if (itemcount > 0) {
-                g_string_append_printf(title_str, " (%d)", itemcount);
+            int count = g_list_length(rooms_sorted);
+            if (count == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+                g_string_append_printf(title_str, " (%d)", count);
+            } else if (count > 0) {
+                g_string_append_printf(title_str, " (%d)", count);
             }
         } else if (g_strcmp0(countpref, "unread") == 0) {
-            int unreadcount = 0;
-            GSList *curr = contacts;
-            while (curr) {
-                PContact contact = curr->data;
-                const char *barejid = p_contact_barejid(contact);
-                ProfChatWin *chatwin = wins_get_chat(barejid);
-                if (chatwin) {
-                    unreadcount += chatwin->unread;
+            char *prefpriv = prefs_get_string(PREF_ROSTER_PRIVATE);
+            if (g_strcmp0(prefpriv, "room") == 0) {
+                GList *privwins = wins_get_private_chats(NULL);
+                GList *curr = privwins;
+                while (curr) {
+                    ProfPrivateWin *privwin = curr->data;
+                    unread += privwin->unread;
+                    curr = g_list_next(curr);
                 }
-                curr = g_slist_next(curr);
+                g_list_free(privwins);
             }
-            if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-                g_string_append_printf(title_str, " (%d)", unreadcount);
-            } else if (unreadcount > 0) {
-                g_string_append_printf(title_str, " (%d)", unreadcount);
+            prefs_free_string(prefpriv);
+            if (unread == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+                g_string_append_printf(title_str, " (%d)", unread);
+            } else if (unread > 0) {
+                g_string_append_printf(title_str, " (%d)", unread);
             }
         }
         prefs_free_string(countpref);
@@ -405,93 +694,24 @@ _rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const prese
         win_sub_print(layout->subwin, title_str->str, FALSE, wrap, 1);
         g_string_free(title_str, TRUE);
         wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
-    }
 
-    if (contacts) {
-        GSList *curr_contact = contacts;
-        while (curr_contact) {
-            PContact contact = curr_contact->data;
-            _rosterwin_contact(layout, contact);
-            curr_contact = g_slist_next(curr_contact);
+        GList *curr_room = rooms_sorted;
+        while (curr_room) {
+            _rosterwin_room(layout, curr_room->data);
+            curr_room = g_list_next(curr_room);
         }
     }
-    g_slist_free(contacts);
-}
-
-static void
-_rosterwin_contacts_by_group(ProfLayoutSplit *layout, char *group, gboolean newline)
-{
-    GSList *contacts = NULL;
 
-    char *order = prefs_get_string(PREF_ROSTER_ORDER);
-    gboolean offline = prefs_get_boolean(PREF_ROSTER_OFFLINE);
-    if (g_strcmp0(order, "presence") == 0) {
-        contacts = roster_get_group(group, ROSTER_ORD_PRESENCE, offline);
-    } else {
-        contacts = roster_get_group(group, ROSTER_ORD_NAME, offline);
-    }
-    prefs_free_string(order);
-
-    if (contacts || prefs_get_boolean(PREF_ROSTER_EMPTY)) {
-        if (newline) {
-            win_sub_newline_lazy(layout->subwin);
-        }
-        wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
-        GString *title = g_string_new(" ");
-        char ch = prefs_get_roster_header_char();
-        if (ch) {
-            g_string_append_printf(title, "%c", ch);
-        }
-        if (group) {
-            g_string_append(title, group);
-        } else {
-            g_string_append(title, "no group");
-        }
-
-        char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
-        if (g_strcmp0(countpref, "items") == 0) {
-            int itemcount = g_slist_length(contacts);
-            if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-                g_string_append_printf(title, " (%d)", itemcount);
-            } else if (itemcount > 0) {
-                g_string_append_printf(title, " (%d)", itemcount);
-            }
-        } else if (g_strcmp0(countpref, "unread") == 0) {
-            int unreadcount = 0;
-            GSList *curr = contacts;
-            while (curr) {
-                PContact contact = curr->data;
-                const char *barejid = p_contact_barejid(contact);
-                ProfChatWin *chatwin = wins_get_chat(barejid);
-                if (chatwin) {
-                    unreadcount += chatwin->unread;
-                }
-                curr = g_slist_next(curr);
-            }
-            if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-                g_string_append_printf(title, " (%d)", unreadcount);
-            } else if (unreadcount > 0) {
-                g_string_append_printf(title, " (%d)", unreadcount);
-            }
-        }
-        prefs_free_string(countpref);
-
-        gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
-        win_sub_print(layout->subwin, title->str, FALSE, wrap, 1);
-        g_string_free(title, TRUE);
-        wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+    g_list_free(rooms_sorted);
 
-        GSList *curr_contact = contacts;
-        while (curr_contact) {
-            PContact contact = curr_contact->data;
-            _rosterwin_contact(layout, contact);
-            curr_contact = g_slist_next(curr_contact);
-        }
+    char *privpref = prefs_get_string(PREF_ROSTER_PRIVATE);
+    if (g_strcmp0(privpref, "group") == 0) {
+        _rosterwin_private_chats(layout);
     }
-    g_slist_free(contacts);
+    prefs_free_string(privpref);
 }
 
-void
+static void
 _rosterwin_room(ProfLayoutSplit *layout, ProfMucWin *mucwin)
 {
     GString *msg = g_string_new(" ");
@@ -615,25 +835,7 @@ _rosterwin_room(ProfLayoutSplit *layout, ProfMucWin *mucwin)
     prefs_free_string(privpref);
 }
 
-static int
-_compare_rooms_name(ProfMucWin *a, ProfMucWin *b)
-{
-    return g_strcmp0(a->roomjid, b->roomjid);
-}
-
-static int
-_compare_rooms_unread(ProfMucWin *a, ProfMucWin *b)
-{
-    if (a->unread > b->unread) {
-        return -1;
-    } else if (a->unread == b->unread) {
-        return g_strcmp0(a->roomjid, b->roomjid);
-    } else {
-        return 1;
-    }
-}
-
-void
+static void
 _rosterwin_private_chats(ProfLayoutSplit *layout)
 {
     GList *privs = wins_get_private_chats(NULL);
@@ -731,214 +933,31 @@ _rosterwin_private_chats(ProfLayoutSplit *layout)
     }
 }
 
-void
-_rosterwin_rooms(ProfLayoutSplit *layout, gboolean newline)
+static theme_item_t
+_get_roster_theme(roster_contact_theme_t theme_type, const char *presence)
 {
-    int unread = 0;
-    GList *rooms = muc_rooms();
-    GList *rooms_sorted = NULL;
-    GList *curr_room = rooms;
-    while (curr_room) {
-        ProfMucWin *mucwin = wins_get_muc(curr_room->data);
-        if (mucwin) {
-            char *order = prefs_get_string(PREF_ROSTER_ROOMS_ORDER);
-            if (g_strcmp0(order, "unread") == 0) {
-                rooms_sorted = g_list_insert_sorted(rooms_sorted, mucwin, (GCompareFunc)_compare_rooms_unread);
-            } else {
-                rooms_sorted = g_list_insert_sorted(rooms_sorted, mucwin, (GCompareFunc)_compare_rooms_name);
-            }
-            prefs_free_string(order);
-            unread += mucwin->unread;
-        }
-        curr_room = g_list_next(curr_room);
-    }
-    g_list_free(rooms);
-
-    // if there are active rooms, or if we want to show empty groups
-    if (rooms_sorted || prefs_get_boolean(PREF_ROSTER_EMPTY)) {
-        if (newline) {
-            win_sub_newline_lazy(layout->subwin);
-        }
-        wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
-        GString *title_str = g_string_new(" ");
-        char ch = prefs_get_roster_header_char();
-        if (ch) {
-            g_string_append_printf(title_str, "%c", ch);
-        }
-        g_string_append(title_str, "Rooms");
-
-        char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
-        if (g_strcmp0(countpref, "items") == 0) {
-            int count = g_list_length(rooms_sorted);
-            if (count == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-                g_string_append_printf(title_str, " (%d)", count);
-            } else if (count > 0) {
-                g_string_append_printf(title_str, " (%d)", count);
-            }
-        } else if (g_strcmp0(countpref, "unread") == 0) {
-            char *prefpriv = prefs_get_string(PREF_ROSTER_PRIVATE);
-            if (g_strcmp0(prefpriv, "room") == 0) {
-                GList *privwins = wins_get_private_chats(NULL);
-                GList *curr = privwins;
-                while (curr) {
-                    ProfPrivateWin *privwin = curr->data;
-                    unread += privwin->unread;
-                    curr = g_list_next(curr);
-                }
-                g_list_free(privwins);
-            }
-            prefs_free_string(prefpriv);
-            if (unread == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-                g_string_append_printf(title_str, " (%d)", unread);
-            } else if (unread > 0) {
-                g_string_append_printf(title_str, " (%d)", unread);
-            }
-        }
-        prefs_free_string(countpref);
-
-        gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
-        win_sub_print(layout->subwin, title_str->str, FALSE, wrap, 1);
-        g_string_free(title_str, TRUE);
-        wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
-
-        GList *curr_room = rooms_sorted;
-        while (curr_room) {
-            _rosterwin_room(layout, curr_room->data);
-            curr_room = g_list_next(curr_room);
-        }
-    }
-
-    g_list_free(rooms_sorted);
-
-    char *privpref = prefs_get_string(PREF_ROSTER_PRIVATE);
-    if (g_strcmp0(privpref, "group") == 0) {
-        _rosterwin_private_chats(layout);
+    switch (theme_type) {
+    case ROSTER_CONTACT:        return theme_roster_presence_attrs(presence);
+    case ROSTER_CONTACT_ACTIVE: return theme_roster_active_presence_attrs(presence);
+    case ROSTER_CONTACT_UNREAD: return theme_roster_unread_presence_attrs(presence);
+    default:                    return theme_roster_presence_attrs(presence);
     }
-    prefs_free_string(privpref);
 }
 
-void
-_rosterwin_contacts_all(ProfLayoutSplit *layout, gboolean newline)
+static int
+_compare_rooms_name(ProfMucWin *a, ProfMucWin *b)
 {
-    GSList *contacts = NULL;
-
-    char *order = prefs_get_string(PREF_ROSTER_ORDER);
-    gboolean offline = prefs_get_boolean(PREF_ROSTER_OFFLINE);
-    if (g_strcmp0(order, "presence") == 0) {
-        contacts = roster_get_contacts(ROSTER_ORD_PRESENCE, offline);
-    } else {
-        contacts = roster_get_contacts(ROSTER_ORD_NAME, offline);
-    }
-    prefs_free_string(order);
-
-    wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
-    GString *title = g_string_new(" ");
-    char ch = prefs_get_roster_header_char();
-    if (ch) {
-        g_string_append_printf(title, "%c", ch);
-    }
-    if (newline) {
-        win_sub_newline_lazy(layout->subwin);
-    }
-
-    g_string_append(title, "Roster");
-
-    char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
-    if (g_strcmp0(countpref, "items") == 0) {
-        int itemcount = g_slist_length(contacts);
-        if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-            g_string_append_printf(title, " (%d)", itemcount);
-        } else {
-            g_string_append_printf(title, " (%d)", itemcount);
-        }
-    } else if (g_strcmp0(countpref, "unread") == 0) {
-        int unreadcount = 0;
-        GSList *curr = contacts;
-        while (curr) {
-            PContact contact = curr->data;
-            const char *barejid = p_contact_barejid(contact);
-            ProfChatWin *chatwin = wins_get_chat(barejid);
-            if (chatwin) {
-                unreadcount += chatwin->unread;
-            }
-            curr = g_slist_next(curr);
-        }
-        if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
-            g_string_append_printf(title, " (%d)", unreadcount);
-        } else if (unreadcount > 0) {
-            g_string_append_printf(title, " (%d)", unreadcount);
-        }
-    }
-    prefs_free_string(countpref);
-
-    gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
-    win_sub_print(layout->subwin, title->str, FALSE, wrap, 1);
-    g_string_free(title, TRUE);
-    wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
-
-    if (contacts) {
-        GSList *curr_contact = contacts;
-        while (curr_contact) {
-            PContact contact = curr_contact->data;
-            _rosterwin_contact(layout, contact);
-            curr_contact = g_slist_next(curr_contact);
-        }
-    }
-    g_slist_free(contacts);
+    return g_strcmp0(a->roomjid, b->roomjid);
 }
 
-void
-rosterwin_roster(void)
+static int
+_compare_rooms_unread(ProfMucWin *a, ProfMucWin *b)
 {
-    ProfWin *console = wins_get_console();
-    if (!console) {
-        return;
-    }
-
-    jabber_conn_status_t conn_status = jabber_get_connection_status();
-    if (conn_status != JABBER_CONNECTED) {
-        return;
-    }
-
-    ProfLayoutSplit *layout = (ProfLayoutSplit*)console->layout;
-    assert(layout->memcheck == LAYOUT_SPLIT_MEMCHECK);
-    werase(layout->subwin);
-
-    gboolean newline = FALSE;
-    char *roomspos = prefs_get_string(PREF_ROSTER_ROOMS_POS);
-    if (prefs_get_boolean(PREF_ROSTER_ROOMS) && (g_strcmp0(roomspos, "first") == 0)) {
-        _rosterwin_rooms(layout, newline);
-        newline = TRUE;
-    }
-
-    if (prefs_get_boolean(PREF_ROSTER_CONTACTS)) {
-        char *by = prefs_get_string(PREF_ROSTER_BY);
-        if (g_strcmp0(by, "presence") == 0) {
-            _rosterwin_contacts_by_presence(layout, "chat", "Available for chat", newline);
-            _rosterwin_contacts_by_presence(layout, "online", "Online", TRUE);
-            _rosterwin_contacts_by_presence(layout, "away", "Away", TRUE);
-            _rosterwin_contacts_by_presence(layout, "xa", "Extended Away", TRUE);
-            _rosterwin_contacts_by_presence(layout, "dnd", "Do not disturb", TRUE);
-            _rosterwin_contacts_by_presence(layout, "offline", "Offline", TRUE);
-        } else if (g_strcmp0(by, "group") == 0) {
-            GSList *groups = roster_get_groups();
-            GSList *curr_group = groups;
-            while (curr_group) {
-                _rosterwin_contacts_by_group(layout, curr_group->data, newline);
-                newline = TRUE;
-                curr_group = g_slist_next(curr_group);
-            }
-            g_slist_free_full(groups, free);
-            _rosterwin_contacts_by_group(layout, NULL, newline);
-        } else {
-            _rosterwin_contacts_all(layout, newline);
-        }
-        prefs_free_string(by);
-    }
-
-    if (prefs_get_boolean(PREF_ROSTER_ROOMS) && (g_strcmp0(roomspos, "last") == 0)) {
-        _rosterwin_rooms(layout, TRUE);
+    if (a->unread > b->unread) {
+        return -1;
+    } else if (a->unread == b->unread) {
+        return g_strcmp0(a->roomjid, b->roomjid);
+    } else {
+        return 1;
     }
-
-    prefs_free_string(roomspos);
 }