Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / fe-common / core / fe-channels.c
index 67557b91e783acdd3632bfb2f76e432c1aa40e9c..6579e8b237985458af4051b245cfc1aa51952cb9 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "chat-protocols.h"
 #include "chatnets.h"
+#include "servers.h"
 #include "channels.h"
 #include "channels-setup.h"
 #include "nicklist.h"
@@ -66,24 +67,14 @@ static void signal_channel_destroyed(CHANNEL_REC *channel)
        window_item_destroy((WI_ITEM_REC *) channel);
 
        if (channel->joined && !channel->left &&
-           channel->server != NULL) {
+           !channel->server->disconnected) {
                /* kicked out from channel */
                window_bind_add(window, channel->server->tag,
-                               channel->name);
+                               channel->visible_name);
        } else if (!channel->joined || channel->left)
                window_auto_destroy(window);
 }
 
-static void signal_window_item_destroy(WINDOW_REC *window, WI_ITEM_REC *item)
-{
-       CHANNEL_REC *channel;
-
-       g_return_if_fail(window != NULL);
-
-       channel = CHANNEL(item);
-        if (channel != NULL) channel_destroy(channel);
-}
-
 static void sig_disconnected(SERVER_REC *server)
 {
        WINDOW_REC *window;
@@ -105,13 +96,21 @@ static void signal_window_item_changed(WINDOW_REC *window, WI_ITEM_REC *item)
        if (item == NULL) return;
 
        if (g_slist_length(window->items) > 1 && IS_CHANNEL(item)) {
-               printformat(item->server, item->name, MSGLEVEL_CLIENTNOTICE,
-                           TXT_TALKING_IN, item->name);
+               printformat(item->server, item->visible_name,
+                           MSGLEVEL_CLIENTNOTICE,
+                           TXT_TALKING_IN, item->visible_name);
                 signal_stop();
        }
 }
 
-static void cmd_wjoin_pre(const char *data)
+static void sig_channel_joined(CHANNEL_REC *channel)
+{
+       if (settings_get_bool("show_names_on_join") &&
+           !channel->session_rejoin)
+               fe_channels_nicklist(channel, CHANNEL_NICKLIST_FLAG_ALL);
+}
+
+static void cmd_wjoin_pre(const char *data, SERVER_REC *server)
 {
        GHashTable *optlist;
        char *nick;
@@ -122,6 +121,12 @@ static void cmd_wjoin_pre(const char *data)
                            "join", &optlist, &nick))
                 return;
 
+       /* kludge for /join -invite -window if there is no invite */
+       if (g_hash_table_lookup(optlist, "invite") &&
+            server != NULL && server->last_invite == NULL) {
+               cmd_params_free(free_arg);
+               return;
+        }                    
        if (g_hash_table_lookup(optlist, "window") != NULL) {
                signal_add("channel created",
                           (SIGNAL_FUNC) signal_channel_created_curwin);
@@ -133,29 +138,28 @@ static void cmd_join(const char *data, SERVER_REC *server)
 {
        WINDOW_REC *window;
         CHANNEL_REC *channel;
+       GHashTable *optlist;
+       char *channelname;
+       void *free_arg;
 
-        if (strchr(data, ' ') != NULL || strchr(data, ',') != NULL)
-                return;
-
-        channel = channel_find(server, data);
-       if (channel == NULL)
+       if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
+                           PARAM_FLAG_UNKNOWN_OPTIONS,
+                           "join", &optlist, &channelname))
                return;
 
-        window = window_item_window(channel);
-
-       if (window == active_win) {
-               /* channel is in active window, set it active */
-               window_item_set_active(active_win,
-                                      (WI_ITEM_REC *) channel);
-       } else {
-               /* notify user how to move the channel to active
-                  window. this was used to be done automatically
-                  but it just confused everyone who did it
-                  accidentally */
-               printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
-                                  TXT_CHANNEL_MOVE_NOTIFY, channel->name,
-                                  window->refnum);
+       /* -<server tag> */
+       server = cmd_options_get_server("join", optlist, server);
+       
+       channel = channel_find(server, channelname);
+       if (channel != NULL) {
+               /* already joined to channel, set it active */
+               window = window_item_window(channel);
+               if (window != active_win)
+                       window_set_active(window);
+
+               window_item_set_active(active_win, (WI_ITEM_REC *) channel);
        }
+       cmd_params_free(free_arg);
 }
 
 static void cmd_wjoin_post(const char *data)
@@ -190,7 +194,8 @@ static void cmd_channel_list_joined(void)
        /* print active channel */
        channel = CHANNEL(active_win->active);
        if (channel != NULL)
-               printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CURRENT_CHANNEL, channel->name);
+               printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+                           TXT_CURRENT_CHANNEL, channel->visible_name);
 
        /* print list of all channels, their modes, server tags and nicks */
        printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_CHANLIST_HEADER);
@@ -207,7 +212,8 @@ static void cmd_channel_list_joined(void)
 
                if (nicks->len > 1) g_string_truncate(nicks, nicks->len-1);
                printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_CHANLIST_LINE,
-                           channel->name, channel->mode, channel->server->tag, nicks->str);
+                           channel->visible_name, channel->mode,
+                           channel->server->tag, nicks->str);
 
                g_slist_free(nicklist);
                g_string_free(nicks, TRUE);
@@ -246,12 +252,15 @@ static void cmd_channel(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
 {
        if (*data == '\0')
                cmd_channel_list_joined();
-       else
+       else if (server != NULL && server_ischannel(server, data)) {
+               signal_emit("command join", 3, data, server, item);
+       } else {
                command_runsub("channel", data, server, item);
+       }
 }
 
 /* SYNTAX: CHANNEL ADD [-auto | -noauto] [-bots <masks>] [-botcmd <command>]
-                       <channel> <chatnet> [<password>] */
+                       <channel> <network> [<password>] */
 static void cmd_channel_add(const char *data)
 {
        GHashTable *optlist;
@@ -303,7 +312,7 @@ static void cmd_channel_add(const char *data)
        cmd_params_free(free_arg);
 }
 
-/* SYNTAX: CHANNEL REMOVE <channel> <chatnet> */
+/* SYNTAX: CHANNEL REMOVE <channel> <network> */
 static void cmd_channel_remove(const char *data)
 {
        CHANNEL_SETUP_REC *rec;
@@ -336,18 +345,18 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
        TEXT_DEST_REC dest;
        GString *str;
        GSList *tmp;
-        char *format, *stripped;
+        char *format, *stripped, *prefix_format;
        char *linebuf, nickmode[2] = { 0, 0 };
        int *columns, cols, rows, last_col_rows, col, row, max_width;
-        int item_extra, linebuf_size;
+        int item_extra, linebuf_size, formatnum;
 
-       window = window_find_closest(channel->server, channel->name,
+       window = window_find_closest(channel->server, channel->visible_name,
                                     MSGLEVEL_CLIENTCRAP);
         max_width = window->width;
 
         /* get the length of item extra stuff ("[ ] ") */
        format = format_get_text(MODULE_NAME, NULL,
-                                channel->server, channel->name,
+                                channel->server, channel->visible_name,
                                 TXT_NAMES_NICK, " ", "");
        stripped = strip_codes(format);
        item_extra = strlen(stripped);
@@ -355,11 +364,11 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
        g_free(format);
 
        if (settings_get_int("names_max_width") > 0 &&
-           max_width > settings_get_int("names_max_width"))
+           settings_get_int("names_max_width") < max_width)
                max_width = settings_get_int("names_max_width");
 
-        /* remove width of timestamp from max_width */
-       format_create_dest(&dest, channel->server, channel->name,
+        /* remove width of the timestamp from max_width */
+       format_create_dest(&dest, channel->server, channel->visible_name,
                           MSGLEVEL_CLIENTCRAP, NULL);
        format = format_get_line_start(current_theme, &dest, time(NULL));
        if (format != NULL) {
@@ -369,6 +378,23 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
                g_free(format);
        }
 
+        /* remove width of the prefix from max_width */
+       prefix_format = format_get_text(MODULE_NAME, NULL,
+                                       channel->server, channel->visible_name,
+                                       TXT_NAMES_PREFIX,
+                                       channel->visible_name);
+       if (prefix_format != NULL) {
+               stripped = strip_codes(prefix_format);
+               max_width -= strlen(stripped);
+               g_free(stripped);
+       }
+
+       if (max_width <= 0) {
+               /* we should always have at least some space .. if we
+                  really don't, it won't show properly anyway. */
+               max_width = 10;
+       }
+
        /* calculate columns */
        cols = get_max_column_count(nicklist, get_nick_length, max_width,
                                    settings_get_int("names_max_columns"),
@@ -380,15 +406,24 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
        if (last_col_rows == 0)
                 last_col_rows = rows;
 
-       str = g_string_new(NULL);
+       str = g_string_new(prefix_format);
        linebuf_size = max_width+1; linebuf = g_malloc(linebuf_size);
 
         col = 0; row = 0;
        for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
                NICK_REC *rec = tmp->data;
 
-               nickmode[0] = rec->op ? '@' : rec->voice ? '+' : ' ';
-
+               if (rec->other)
+                       nickmode[0] = rec->other;
+               else if (rec->op)
+                       nickmode[0] = '@';
+               else if (rec->halfop)
+                       nickmode[0] = '%';
+               else if (rec->voice)
+                       nickmode[0] = '+';
+               else
+                       nickmode[0] = ' ';
+               
                if (linebuf_size < columns[col]-item_extra+1) {
                        linebuf_size = (columns[col]-item_extra+1)*2;
                         linebuf = g_realloc(linebuf, linebuf_size);
@@ -397,16 +432,23 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
                linebuf[columns[col]-item_extra] = '\0';
                memcpy(linebuf, rec->nick, strlen(rec->nick));
 
+               formatnum = rec->op ? TXT_NAMES_NICK_OP :
+                       rec->halfop ? TXT_NAMES_NICK_HALFOP :
+                       rec->voice ? TXT_NAMES_NICK_VOICE :
+                        TXT_NAMES_NICK;
                format = format_get_text(MODULE_NAME, NULL,
-                                        channel->server, channel->name,
-                                        TXT_NAMES_NICK, nickmode, linebuf);
+                                        channel->server,
+                                        channel->visible_name,
+                                        formatnum, nickmode, linebuf);
                g_string_append(str, format);
                g_free(format);
 
                if (++col == cols) {
-                       printtext(channel->server, channel->name,
+                       printtext(channel->server, channel->visible_name,
                                  MSGLEVEL_CLIENTCRAP, "%s", str->str);
                        g_string_truncate(str, 0);
+                       if (prefix_format != NULL)
+                                g_string_assign(str, prefix_format);
                        col = 0; row++;
 
                        if (row == last_col_rows)
@@ -414,14 +456,15 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
                }
        }
 
-       if (str->len != 0) {
-               printtext(channel->server, channel->name,
+       if (str->len > strlen(prefix_format)) {
+               printtext(channel->server, channel->visible_name,
                          MSGLEVEL_CLIENTCRAP, "%s", str->str);
        }
 
        g_slist_free(nicklist);
        g_string_free(str, TRUE);
        g_free_not_null(columns);
+       g_free_not_null(prefix_format);
        g_free(linebuf);
 }
 
@@ -429,13 +472,15 @@ void fe_channels_nicklist(CHANNEL_REC *channel, int flags)
 {
        NICK_REC *nick;
        GSList *tmp, *nicklist, *sorted;
-       int nicks, normal, voices, ops;
+       int nicks, normal, voices, halfops, ops;
+       const char *nick_flags;
 
-       nicks = normal = voices = ops = 0;
+       nicks = normal = voices = halfops = ops = 0;
        nicklist = nicklist_getnicks(channel);
        sorted = NULL;
+       nick_flags = channel->server->get_nick_flags(channel->server);
 
-       /* sort the nicklist */
+       /* filter (for flags) and count ops, halfops, voices */
        for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
                nick = tmp->data;
 
@@ -445,6 +490,7 @@ void fe_channels_nicklist(CHANNEL_REC *channel, int flags)
                        if ((flags & CHANNEL_NICKLIST_FLAG_OPS) == 0)
                                 continue;
                } else if (nick->halfop) {
+                       halfops++;
                        if ((flags & CHANNEL_NICKLIST_FLAG_HALFOPS) == 0)
                                continue;
                } else if (nick->voice) {
@@ -457,23 +503,34 @@ void fe_channels_nicklist(CHANNEL_REC *channel, int flags)
                                continue;
                }
 
-               sorted = g_slist_insert_sorted(sorted, nick, (GCompareFunc)
-                                              nicklist_compare);
+               sorted = g_slist_prepend(sorted, nick);
        }
        g_slist_free(nicklist);
 
+       /* sort the nicklist */
+#if GLIB_MAJOR_VERSION < 2
+       /* glib1 doesn't have g_slist_sort_with_data, so non-standard prefixes won't be sorted correctly */
+       sorted = g_slist_sort(sorted, (GCompareFunc)nicklist_compare_glib1);
+#else
+       sorted = g_slist_sort_with_data(sorted, (GCompareDataFunc) nicklist_compare, (void *)nick_flags);
+#endif
+
        /* display the nicks */
-       printformat(channel->server, channel->name,
-                   MSGLEVEL_CRAP, TXT_NAMES, channel->name, "");
-       display_sorted_nicks(channel, sorted);
+        if ((flags & CHANNEL_NICKLIST_FLAG_COUNT) == 0) {
+               printformat(channel->server, channel->visible_name,
+                           MSGLEVEL_CLIENTCRAP, TXT_NAMES,
+                           channel->visible_name,
+                           nicks, ops, halfops, voices, normal);
+               display_sorted_nicks(channel, sorted);
+       }
        g_slist_free(sorted);
 
-       printformat(channel->server, channel->name,
-                   MSGLEVEL_CRAP, TXT_ENDOFNAMES,
-                   channel->name, nicks, ops, voices, normal);
+       printformat(channel->server, channel->visible_name,
+                   MSGLEVEL_CLIENTNOTICE, TXT_ENDOFNAMES,
+                   channel->visible_name, nicks, ops, halfops, voices, normal);
 }
 
-/* SYNTAX: NAMES [-ops -halfops -voices -normal] [<channels> | **] */
+/* SYNTAX: NAMES [-count | -ops -halfops -voices -normal] [<channels> | **] */
 static void cmd_names(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
 {
        CHANNEL_REC *chanrec;
@@ -495,7 +552,7 @@ static void cmd_names(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
                if (!IS_CHANNEL(item))
                         cmd_param_error(CMDERR_NOT_JOINED);
 
-               channel = item->name;
+               channel = CHANNEL(item)->name;
        }
 
        flags = 0;
@@ -507,6 +564,8 @@ static void cmd_names(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
                flags |= CHANNEL_NICKLIST_FLAG_VOICES;
        if (g_hash_table_lookup(optlist, "normal") != NULL)
                flags |= CHANNEL_NICKLIST_FLAG_NORMAL;
+       if (g_hash_table_lookup(optlist, "count") != NULL)
+               flags |= CHANNEL_NICKLIST_FLAG_COUNT;
 
         if (flags == 0) flags = CHANNEL_NICKLIST_FLAG_ALL;
 
@@ -556,7 +615,14 @@ static void cmd_cycle(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
        joindata = chanrec->get_join_data(chanrec);
        window_bind_add(window_item_window(chanrec),
                        chanrec->server->tag, chanrec->name);
-        channel_destroy(chanrec);
+
+       /* FIXME: kludgy kludgy... */
+       signal_emit("command part", 3, data, server, item);
+
+       if (g_slist_find(channels, chanrec) != NULL) {
+               chanrec->left = TRUE;
+               channel_destroy(chanrec);
+       }
 
        server->channels_join(server, joindata, FALSE);
        g_free(joindata);
@@ -567,14 +633,15 @@ static void cmd_cycle(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
 void fe_channels_init(void)
 {
        settings_add_bool("lookandfeel", "autoclose_windows", TRUE);
+       settings_add_bool("lookandfeel", "show_names_on_join", TRUE);
        settings_add_int("lookandfeel", "names_max_columns", 6);
        settings_add_int("lookandfeel", "names_max_width", 0);
 
        signal_add("channel created", (SIGNAL_FUNC) signal_channel_created);
        signal_add("channel destroyed", (SIGNAL_FUNC) signal_channel_destroyed);
-       signal_add_last("window item destroy", (SIGNAL_FUNC) signal_window_item_destroy);
        signal_add_last("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
        signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
+       signal_add_last("channel joined", (SIGNAL_FUNC) sig_channel_joined);
 
        command_bind_first("join", NULL, (SIGNAL_FUNC) cmd_wjoin_pre);
        command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
@@ -587,7 +654,7 @@ void fe_channels_init(void)
        command_bind("cycle", NULL, (SIGNAL_FUNC) cmd_cycle);
 
        command_set_options("channel add", "auto noauto -bots -botcmd");
-       command_set_options("names", "ops halfops voices normal");
+       command_set_options("names", "count ops halfops voices normal");
        command_set_options("join", "window");
 }
 
@@ -595,9 +662,9 @@ void fe_channels_deinit(void)
 {
        signal_remove("channel created", (SIGNAL_FUNC) signal_channel_created);
        signal_remove("channel destroyed", (SIGNAL_FUNC) signal_channel_destroyed);
-       signal_remove("window item destroy", (SIGNAL_FUNC) signal_window_item_destroy);
        signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
        signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
+       signal_remove("channel joined", (SIGNAL_FUNC) sig_channel_joined);
 
        command_unbind("join", (SIGNAL_FUNC) cmd_wjoin_pre);
        command_unbind("join", (SIGNAL_FUNC) cmd_join);