} irc_command_t;
/* Local functions */
+static irc_channel_t *find_dest(irc_server_t *srv, const char *dest)
+{
+ irc_channel_t *chan;
+
+ /* Find existing channels */
+ for (channel_t *cur = channels; cur; cur = cur->next) {
+ if (cur->server != &srv->server)
+ continue;
+ chan = (irc_channel_t *)cur;
+ if (match(chan->dest, dest))
+ return chan;
+ }
+
+ /* Create a new channel */
+ chan = (irc_channel_t *)add_channel(dest, &srv->server);
+ chan->dest = strcopy(dest);
+ return chan;
+}
+
static void parse_line(irc_server_t *srv, const char *line,
irc_command_t *_cmd)
{
/* Receive messages */
if (srv->state == IRC_READY) {
- if (match(cmd, "PING"))
+ irc_channel_t *chan;
+ if (match(cmd, "PING")) {
net_print(&srv->net, "PING %s\n", msg);
- if (match(cmd, "PRIVMSG"))
- chat_recv(find_channel(dst), from, msg);
+ }
+ if (match(cmd, "PRIVMSG") && dst[0] == '#') {
+ chan = find_dest(srv, dst);
+ chat_recv(&chan->channel, from, msg);
+ }
+ if (match(cmd, "PRIVMSG") && dst[0] != '#') {
+ chan = find_dest(srv, from);
+ chat_recv(&chan->channel, from, msg);
+ }
}
/* Receive notices */
irc_channel_t *chan = (irc_channel_t*)msg->channel;
irc_server_t *srv = (irc_server_t*)msg->channel->server;
- net_print(&srv->net, "PRIVMSG %s :%s\n", chan->channel, msg);
+ net_print(&srv->net, "PRIVMSG %s :%s\n", chan->dest, msg->text);
+
+ msg->from = strcopy(srv->nick);
}
void irc_exit(void)
#include <signal.h>
#include <sys/signalfd.h>
#include <unistd.h>
+#include <regex.h>
#include "util.h"
#include "conf.h"
#define KEY_CTRL_L '\14'
#define KEY_CTRL_N '\16'
#define KEY_CTRL_P '\20'
+#define KEY_CTRL_X '\30'
#define KEY_RETURN '\12'
#define KEY_ESCAPE '\33'
+/* View types */
+typedef struct window_t window_t;
+
+typedef struct window_t {
+ char *name;
+ int flag;
+ char *filter;
+ regex_t regex;
+ channel_t *channel;
+ window_t *next;
+} window_t;
+
/* Local data */
static poll_t poll_in;
static poll_t poll_sig;
static int cmd_pos;
static int cmd_len;
-static channel_t *channel = NULL;
+static window_t *focus;
+static window_t *windows;
+
+/* Window functions */
+static int in_window(message_t *msg, window_t *win)
+{
+ channel_t *chan = msg->channel;
+ const char *name = chan ? chan->name : "";
+ if (win->filter)
+ return !regexec(&win->regex, name, 0, 0, 0);
+ else
+ return win->channel == chan;
+}
+
+static void add_window(window_t *win)
+{
+ window_t **last = &windows;
+ while (*last)
+ last = &(*last)->next;
+ *last = win;
+}
+
+static window_t *find_window(const char *name)
+{
+ window_t *win;
+ for (win = windows; win; win = win->next)
+ if (match(win->name, name))
+ break;
+ if (!win) {
+ win = new0(window_t);
+ win->name = strcopy(name);
+ add_window(win);
+ }
+ return win;
+}
+
+static void update_windows(void)
+{
+ static int seen = 0;
+ for (; seen < history; seen++) {
+ window_t *win = NULL;
+ message_t *msg = &messages[seen];
+ channel_t *chan = msg->channel;
+
+ /* Flag existing windows */
+ for (window_t *cur = windows; cur; cur = cur->next) {
+ if (in_window(msg, cur)) {
+ win = cur;
+ win->flag = 1;
+ }
+ }
+
+ /* No window, create a new one */
+ if (!win) {
+ win = new0(window_t);
+ win->channel = chan;
+ win->name = chan->name;
+ add_window(win);
+ }
+ }
+
+ /* Update focus */
+ if (!focus)
+ focus = windows;
+}
-/* Local functions */
+/* Print functions */
static void print_word(char **msg, int *row, int *col, int indent, int print)
{
char *start = *msg;
time_t timep = msg->when;
struct tm *tm = localtime(&timep);
- if (msg->channel && msg->channel != channel)
+ if (!in_window(msg, focus))
return;
- if (msg->channel && msg->from)
+ if (focus->filter && msg->channel && msg->from)
snprintf(buf, sizeof(buf), "%02d:%02d [%s] %s: ",
tm->tm_hour, tm->tm_min,
msg->channel->name, msg->from);
- else if (msg->channel)
+ else if (focus->filter && msg->channel)
snprintf(buf, sizeof(buf), "%02d:%02d [%s] *** ",
tm->tm_hour, tm->tm_min, msg->channel->name);
- else if (msg->from)
+ else if (focus->filter && msg->from)
snprintf(buf, sizeof(buf), "%02d:%02d *** %s: ",
tm->tm_hour, tm->tm_min, msg->from);
+ else if (msg->from)
+ snprintf(buf, sizeof(buf), "%02d:%02d %s: ",
+ tm->tm_hour, tm->tm_min, msg->from);
else
snprintf(buf, sizeof(buf), "%02d:%02d *** ",
tm->tm_hour, tm->tm_min);
-
while (*hdr)
print_word(&hdr, row, &col, indent, print);
indent = col;
attron(COLOR_PAIR(COLOR_TITLE));
mvhline(LINES-2, 0, ' ', COLS);
move(LINES-2, 0);
- printw("Channels:");
- if (!channels)
+ printw("Windows:");
+ if (!windows)
printw(" none");
- for (channel_t *cur = channels; cur; cur = cur->next) {
+ for (window_t *cur = windows; cur; cur = cur->next) {
printw(" ");
- if (cur == channel)
+ if (cur == focus)
attron(A_BOLD);
printw("[%s]", cur->name);
- if (cur == channel)
+ if (cur == focus)
attroff(A_BOLD);
}
attroff(COLOR_PAIR(COLOR_TITLE));
void draw_cmdline(void)
{
- const char *name = channel ? channel->name : "(none)";
+ const char *name;
+ if (focus && focus->name)
+ name = focus->name;
+ else if (focus)
+ name = "(system)";
+ else
+ name = "(none)";
move(LINES-1, 0);
clrtoeol();
/* View init */
void view_init(void)
{
+ const int flags = REG_EXTENDED|REG_NOSUB;
+
+ /* Setup windows */
+ for (window_t *win = windows; win; win = win->next)
+ if (win->filter)
+ regcomp(&win->regex, win->filter, flags);
+
/* Set default escape timeout */
if (!getenv("ESCDELAY"))
putenv("ESCDELAY=25");
/* Config parser */
void view_config(const char *group, const char *name, const char *key, const char *value)
{
+ window_t *win;
+
+ if (match(group, "window")) {
+ if (match(key, ""))
+ get_name(name);
+ win = find_window(name);
+ if (match(key, "channel"))
+ win->channel = find_channel(get_string(value));
+ if (match(key, "filter"))
+ win->filter = get_string(value);
+ }
}
/* View event */
/* View management */
else if (chr == KEY_CTRL_N) {
- if (channel && channel->next)
- channel = channel->next;
- else if (!channel)
- channel = channels;
+ if (focus && focus->next)
+ focus = focus->next;
+ else if (!focus)
+ focus = windows;
view_draw();
}
else if (chr == KEY_CTRL_P) {
- channel_t *cur = channels;
+ window_t *cur = windows;
for (; cur; cur = cur->next)
- if (cur->next == channel)
- channel = cur;
+ if (cur->next == focus)
+ focus = cur;
+ view_draw();
+ }
+ else if (chr == KEY_CTRL_X) {
view_draw();
}
/* Cmdline Input */
else if (chr == KEY_RETURN) {
- if (channel) {
+ if (focus) {
cmd_buf[cmd_len] = '\0';
cmd_pos = 0;
cmd_len = 0;
- chat_send(channel, cmd_buf);
+ chat_send(focus->channel, cmd_buf);
}
draw_chat();
draw_cmdline();
{
if (!running)
return;
- if (!channel)
- channel = channels;
+
+ update_windows();
draw_header();
draw_chat();