about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command/command.c1
-rw-r--r--src/command/commands.c14
-rw-r--r--src/config/preferences.c4
-rw-r--r--src/config/preferences.h1
-rw-r--r--src/config/theme.c1
-rw-r--r--src/ui/console.c5
-rw-r--r--src/ui/rosterwin.c125
-rw-r--r--src/window_list.c29
-rw-r--r--src/window_list.h1
9 files changed, 181 insertions, 0 deletions
diff --git a/src/command/command.c b/src/command/command.c
index d2d7f4ab..97d2dfc6 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -2266,6 +2266,7 @@ cmd_init(void)
     autocomplete_add(roster_show_ac, "empty");
     autocomplete_add(roster_show_ac, "priority");
     autocomplete_add(roster_show_ac, "contacts");
+    autocomplete_add(roster_show_ac, "unsubscribed");
     autocomplete_add(roster_show_ac, "rooms");
 
     roster_by_ac = autocomplete_new();
diff --git a/src/command/commands.c b/src/command/commands.c
index 6570f13d..6a9972b6 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -2245,6 +2245,13 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args)
                 rosterwin_roster();
             }
             return TRUE;
+        } else if (g_strcmp0(args[1], "unsubscribed") == 0) {
+            cons_show("Roster unsubscribed enabled");
+            prefs_set_boolean(PREF_ROSTER_UNSUBSCRIBED, TRUE);
+            if (conn_status == JABBER_CONNECTED) {
+                rosterwin_roster();
+            }
+            return TRUE;
         } else {
             cons_bad_cmd_usage(command);
             return TRUE;
@@ -2313,6 +2320,13 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args)
                 rosterwin_roster();
             }
             return TRUE;
+        } else if (g_strcmp0(args[1], "unsubscribed") == 0) {
+            cons_show("Roster unsubscribed disabled");
+            prefs_set_boolean(PREF_ROSTER_UNSUBSCRIBED, FALSE);
+            if (conn_status == JABBER_CONNECTED) {
+                rosterwin_roster();
+            }
+            return TRUE;
         } else {
             cons_bad_cmd_usage(command);
             return TRUE;
diff --git a/src/config/preferences.c b/src/config/preferences.c
index 8642e20a..12870bb1 100644
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -1143,6 +1143,7 @@ _get_group(preference_t pref)
         case PREF_ROSTER_WRAP:
         case PREF_ROSTER_RESOURCE_JOIN:
         case PREF_ROSTER_CONTACTS:
+        case PREF_ROSTER_UNSUBSCRIBED:
         case PREF_ROSTER_ROOMS:
         case PREF_ROSTER_ROOMS_POS:
         case PREF_ROSTER_ROOMS_BY:
@@ -1351,6 +1352,8 @@ _get_key(preference_t pref)
             return "roster.resource.join";
         case PREF_ROSTER_CONTACTS:
             return "roster.contacts";
+        case PREF_ROSTER_UNSUBSCRIBED:
+            return "roster.unsubscribed";
         case PREF_ROSTER_ROOMS:
             return "roster.rooms";
         case PREF_ROSTER_ROOMS_POS:
@@ -1425,6 +1428,7 @@ _get_default_boolean(preference_t pref)
         case PREF_ROSTER_PRIORITY:
         case PREF_ROSTER_RESOURCE_JOIN:
         case PREF_ROSTER_CONTACTS:
+        case PREF_ROSTER_UNSUBSCRIBED:
         case PREF_ROSTER_ROOMS:
         case PREF_TLS_SHOW:
         case PREF_LASTACTIVITY:
diff --git a/src/config/preferences.h b/src/config/preferences.h
index 8afb2707..a89ee65b 100644
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -76,6 +76,7 @@ typedef enum {
     PREF_ROSTER_WRAP,
     PREF_ROSTER_RESOURCE_JOIN,
     PREF_ROSTER_CONTACTS,
+    PREF_ROSTER_UNSUBSCRIBED,
     PREF_ROSTER_ROOMS,
     PREF_ROSTER_ROOMS_POS,
     PREF_ROSTER_ROOMS_BY,
diff --git a/src/config/theme.c b/src/config/theme.c
index 1c4a3698..6a235f6d 100644
--- a/src/config/theme.c
+++ b/src/config/theme.c
@@ -391,6 +391,7 @@ _load_preferences(void)
     _set_boolean_preference("roster.count.zero", PREF_ROSTER_COUNT_ZERO);
     _set_boolean_preference("roster.priority", PREF_ROSTER_PRIORITY);
     _set_boolean_preference("roster.contacts", PREF_ROSTER_CONTACTS);
+    _set_boolean_preference("roster.unsubscribed", PREF_ROSTER_UNSUBSCRIBED);
     _set_boolean_preference("roster.rooms", PREF_ROSTER_ROOMS);
     _set_boolean_preference("privileges", PREF_MUC_PRIVILEGES);
     _set_boolean_preference("presence", PREF_PRESENCE);
diff --git a/src/ui/console.c b/src/ui/console.c
index be6246c8..55b1e25f 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -1410,6 +1410,11 @@ cons_roster_setting(void)
     else
         cons_show("Roster contacts (/roster)           : hide");
 
+    if (prefs_get_boolean(PREF_ROSTER_UNSUBSCRIBED))
+        cons_show("Roster unsubscribed (/roster)       : show");
+    else
+        cons_show("Roster unsubscribed (/roster)       : hide");
+
     char *count = prefs_get_string(PREF_ROSTER_COUNT);
     if (g_strcmp0(count, "off") == 0) {
         cons_show("Roster count (/roster)              : OFF");
diff --git a/src/ui/rosterwin.c b/src/ui/rosterwin.c
index 6d25b6ec..964b006c 100644
--- a/src/ui/rosterwin.c
+++ b/src/ui/rosterwin.c
@@ -53,9 +53,12 @@ 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 _rosteriwin_unsubscribed(ProfLayoutSplit *layout, gboolean newline);
 static void _rosterwin_contacts_header(ProfLayoutSplit *layout, const char *title, gboolean newline, GSList *contacts);
+static void _rosterwin_unsubscribed_header(ProfLayoutSplit *layout, gboolean newline, GList *wins);
 
 static void _rosterwin_contact(ProfLayoutSplit *layout, PContact contact);
+static void _rosterwin_unsubscribed_item(ProfLayoutSplit *layout, ProfChatWin *chatwin);
 static void _rosterwin_presence(ProfLayoutSplit *layout, const char *presence, const char *status,
     int current_indent);
 static void _rosterwin_resources(ProfLayoutSplit *layout, PContact contact, int current_indent,
@@ -149,6 +152,10 @@ rosterwin_roster(void)
         } else {
             _rosterwin_contacts_all(layout, newline);
         }
+
+        if (prefs_get_boolean(PREF_ROSTER_UNSUBSCRIBED)) {
+            _rosteriwin_unsubscribed(layout, newline);
+        }
         prefs_free_string(by);
     }
 
@@ -216,6 +223,24 @@ _rosterwin_contacts_all(ProfLayoutSplit *layout, gboolean newline)
 }
 
 static void
+_rosteriwin_unsubscribed(ProfLayoutSplit *layout, gboolean newline)
+{
+    GList *wins = wins_get_chat_unsubscribed();
+    if (wins) {
+        _rosterwin_unsubscribed_header(layout, newline, wins);
+    }
+
+    GList *curr = wins;
+    while (curr) {
+        ProfChatWin *chatwin = curr->data;
+        _rosterwin_unsubscribed_item(layout, chatwin);
+        curr = g_list_next(curr);
+    }
+
+    g_list_free(wins);
+}
+
+static void
 _rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char *const presence, char *title, gboolean newline)
 {
     GSList *contacts = roster_get_contacts_by_presence(presence);
@@ -272,6 +297,58 @@ _rosterwin_contacts_by_group(ProfLayoutSplit *layout, char *group, gboolean newl
 }
 
 static void
+_rosterwin_unsubscribed_item(ProfLayoutSplit *layout, ProfChatWin *chatwin)
+{
+    const char *const name = chatwin->barejid;
+    const char *const presence = "offline";
+    int unread = 0;
+
+    roster_contact_theme_t theme_type = ROSTER_CONTACT;
+    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) && 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));
+}
+
+static void
 _rosterwin_contact(ProfLayoutSplit *layout, PContact contact)
 {
     const char *name = p_contact_name_or_jid(contact);
@@ -889,6 +966,54 @@ _compare_rooms_unread(ProfMucWin *a, ProfMucWin *b)
 }
 
 static void
+_rosterwin_unsubscribed_header(ProfLayoutSplit *layout, gboolean newline, GList *wins)
+{
+    if (newline) {
+        win_sub_newline_lazy(layout->subwin);
+    }
+
+    GString *header = g_string_new(" ");
+    char ch = prefs_get_roster_header_char();
+    if (ch) {
+        g_string_append_printf(header, "%c", ch);
+    }
+
+    g_string_append(header, "Unsubscribed");
+
+    char *countpref = prefs_get_string(PREF_ROSTER_COUNT);
+    if (g_strcmp0(countpref, "items") == 0) {
+        int itemcount = g_list_length(wins);
+        if (itemcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+            g_string_append_printf(header, " (%d)", itemcount);
+        } else {
+            g_string_append_printf(header, " (%d)", itemcount);
+        }
+    } else if (g_strcmp0(countpref, "unread") == 0) {
+        int unreadcount = 0;
+        GList *curr = wins;
+        while (curr) {
+            ProfChatWin *chatwin = curr->data;
+            unreadcount += chatwin->unread;
+            curr = g_list_next(curr);
+        }
+        if (unreadcount == 0 && prefs_get_boolean(PREF_ROSTER_COUNT_ZERO)) {
+            g_string_append_printf(header, " (%d)", unreadcount);
+        } else if (unreadcount > 0) {
+            g_string_append_printf(header, " (%d)", unreadcount);
+        }
+    }
+    prefs_free_string(countpref);
+
+    gboolean wrap = prefs_get_boolean(PREF_ROSTER_WRAP);
+
+    wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+    win_sub_print(layout->subwin, header->str, FALSE, wrap, 1);
+    wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER));
+
+    g_string_free(header, TRUE);
+}
+
+static void
 _rosterwin_contacts_header(ProfLayoutSplit *layout, const char *const title, gboolean newline, GSList *contacts)
 {
     if (newline) {
diff --git a/src/window_list.c b/src/window_list.c
index 97155294..b275fe63 100644
--- a/src/window_list.c
+++ b/src/window_list.c
@@ -106,6 +106,35 @@ wins_get_chat(const char *const barejid)
     return NULL;
 }
 
+static gint
+_cmp_unsubscribed_wins(ProfChatWin *a, ProfChatWin *b)
+{
+    return g_strcmp0(a->barejid, b->barejid);
+}
+
+GList*
+wins_get_chat_unsubscribed(void)
+{
+    GList *result = NULL;
+    GList *values = g_hash_table_get_values(windows);
+    GList *curr = values;
+
+    while (curr) {
+        ProfWin *window = curr->data;
+        if (window->type == WIN_CHAT) {
+            ProfChatWin *chatwin = (ProfChatWin*)window;
+            PContact contact = roster_get_contact(chatwin->barejid);
+            if (contact == NULL) {
+                result = g_list_insert_sorted(result, chatwin, (GCompareFunc)_cmp_unsubscribed_wins);
+            }
+        }
+        curr = g_list_next(curr);
+    }
+
+    g_list_free(values);
+    return result;
+}
+
 ProfMucConfWin*
 wins_get_muc_conf(const char *const roomjid)
 {
diff --git a/src/window_list.h b/src/window_list.h
index 46bac234..767dce1f 100644
--- a/src/window_list.h
+++ b/src/window_list.h
@@ -53,6 +53,7 @@ void wins_remove_nick(const char *const barejid, const char *const oldnick);
 
 ProfWin* wins_get_console(void);
 ProfChatWin* wins_get_chat(const char *const barejid);
+GList* wins_get_chat_unsubscribed(void);
 ProfMucWin* wins_get_muc(const char *const roomjid);
 ProfMucConfWin* wins_get_muc_conf(const char *const roomjid);
 ProfPrivateWin* wins_get_private(const char *const fulljid);