# UNDF: UNDF-2026-000000719
# weechat-0003 — irc_channel_search O(C) linked-list scan — no hash index

## Ecosystem
weechat (C)

## Severity
MEDIUM — hot path: irc_channel_search() is called ~30+ times per IRC protocol
message in irc-protocol.c (JOIN, PART, KICK, MODE, TOPIC, PRIVMSG, etc.)

## Location
`src/plugins/irc/irc-channel.c`
- Function: `irc_channel_search` (~line 92): O(C) linear walk of `server->channels`

`src/plugins/irc/irc-protocol.c`
- ~30+ call sites including: JOIN (~line 1560, 1587), PART (~line 1753),
  KICK (~line 1928), MODE (~line 2180), NICK (~line 2297), PRIVMSG (~line 3112),
  numeric 353/366/332 handlers, etc.

## Description

`irc_channel_search` scans a linked list of all channels on a server to find
a channel by name:

```c
// irc-channel.c:92
struct t_irc_channel *
irc_channel_search (struct t_irc_server *server, const char *channel_name)
{
    struct t_irc_channel *ptr_channel;

    if (!server || !channel_name)
        return NULL;

    for (ptr_channel = server->channels; ptr_channel;
         ptr_channel = ptr_channel->next_channel)      // O(C) walk
    {
        if (irc_server_strcasecmp (server, ptr_channel->name, channel_name) == 0)
            return ptr_channel;
    }
    return NULL;
}
```

With C channels on a server, each call is O(C). In `irc-protocol.c`, this
function is called ~30+ times across different protocol message handlers,
each of which processes one message. The cost per message is O(C) per
`irc_channel_search` call.

In extreme cases (e.g., a bot joined to thousands of channels, or an IRC
network with large JOIN parameter lists), the cumulative cost per protocol
event grows significantly.

The NICK handler at line ~2297 calls `irc_channel_search` once, then
iterates over all C channels calling `irc_nick_search` (O(N) each) — that
O(C×N) pattern is weechat-0001. The standalone `irc_channel_search` O(C)
cost itself is weechat-0003.

## Fix

Add a `channels_hashtable` to `struct t_irc_server` (channel_name → `t_irc_channel*`),
mirroring the `nicks_hashtable` fix from weechat-0001:

```c
--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ struct t_irc_server {
    struct t_irc_channel *channels;
+   struct t_hashtable *channels_hashtable; /* channel_name(lower) → t_irc_channel* */

--- a/src/plugins/irc/irc-channel.c
+++ b/src/plugins/irc/irc-channel.c
 struct t_irc_channel *
 irc_channel_search (struct t_irc_server *server, const char *channel_name)
 {
-    for (ptr_channel = server->channels; ptr_channel; ...)
-        if (irc_server_strcasecmp (...) == 0) return ptr_channel;
+    if (server->channels_hashtable) {
+        char lower[512];
+        snprintf(lower, sizeof(lower), "%s", channel_name);
+        /* lowercase using irc_server_casemapping */
+        return weechat_hashtable_get(server->channels_hashtable, lower);
+    }
+    /* fallback to linear scan */
+    ...
}
```

## Complexity

| Variant | Cost per lookup |
|---------|----------------|
| Before  | O(C) — linear scan through all channels |
| After   | O(1) — hash table lookup |
| Speedup | C× — at C=1000 channels: 1000× |

## Notes
- IRC servers typically allow users to join 100-2000 channels
- Bots joining many channels (monitoring, bridging) are common and hit this hard
- The `t_irc_server.channels` list is modified on JOIN/PART; the hashtable
  must be kept in sync in `irc_channel_new()` and `irc_channel_free()`
- weechat-0001 fixed `nicks_hashtable`; this defect is the parallel issue
  for channel lookup on the server
