jcs
/wallops
/amendments
/42
*: Large reorganization in preparation for multiple chat windows
Each channel belongs to a connection, and each channel belongs to
a chatter. Right now they're all the same chatter, but eventually
they'll be different windows or different TE buffers on the same
window.
The connection and channel are passed to chatter_printf so it can
eventually determine where to print the text.
jcs made amendment 42 about 1 year ago
--- chatter.c Thu Dec 1 21:49:35 2022
+++ chatter.c Sun Dec 11 20:55:24 2022
@@ -28,7 +28,8 @@ static Handle scrp_rec_h = NULL;
void chatter_layout(struct chatter *chatter, bool init, Rect *init_bounds);
void chatter_draw_grow_icon(struct chatter *chatter);
-void chatter_autoscroll(struct chatter *chatter);
+void chatter_autoscroll(struct chatter *chatter, TEHandle te,
+ ControlHandle scroller);
short chatter_wait_type(struct focusable *focusable);
void chatter_key_down(struct focusable *focusable, EventRecord *event);
void chatter_mouse_down(struct focusable *focusable, EventRecord *event);
@@ -41,10 +42,8 @@ void chatter_close(struct focusable *focusable, EventR
bool chatter_quit(struct focusable *focusable);
void chatter_atexit(struct focusable *focusable);
-void
-chatter_init(const char *server, const unsigned short port,
- const char *password, const char *nick, const char *ident,
- const char *realname, const char *channel)
+struct chatter *
+chatter_init(void)
{
struct focusable *focusable;
struct chatter *chatter;
@@ -56,16 +55,6 @@ chatter_init(const char *server, const unsigned short
panic("TCPInit failed");
chatter = xmalloczero(sizeof(struct chatter), "chatter");
- chatter->irc_state = IRC_STATE_UNINITED;
- chatter->irc_hostname = xstrdup(server, "server");
- chatter->irc_port = port;
- if (password && password[0])
- chatter->irc_password = xstrdup(password, "password");
- chatter->irc_nick = xstrdup(nick, "nick");
- chatter->irc_ident = xstrdup(ident, "ident");
- chatter->irc_realname = xstrdup(realname, "realname");
- if (channel && channel[0])
- chatter->irc_channel_autojoin = xstrdup(channel, "chan");
bounds.left = padding;
bounds.top = screenBits.bounds.top + padding +
@@ -104,16 +93,104 @@ chatter_init(const char *server, const unsigned short
focusable->resume = chatter_resume;
add_focusable(focusable);
chatter->focusable = focusable;
+
+ chatter_printf(chatter, NULL, NULL,
+ "$B***$0 Welcome to %s",
+ PROGRAM_NAME);
+
+ return chatter;
}
+void
+chatter_connect(struct chatter *chatter, const char *server,
+ const unsigned short port, const char *password, const char *nick,
+ const char *ident, const char *realname, const char *channel)
+{
+ struct irc_connection *conn;
+
+ chatter->nconns++;
+ chatter->conns = xreallocarray(chatter->conns, chatter->nconns,
+ sizeof(struct irc_connection));
+ conn = &chatter->conns[chatter->nconns - 1];
+ chatter->cur_conn = conn;
+ memset(conn, 0, sizeof(struct irc_connection));
+
+ conn->chatter = chatter;
+ conn->state = IRC_STATE_UNINITED;
+ conn->hostname = xstrdup(server, "server");
+ conn->port = port;
+ if (password && password[0])
+ conn->password = xstrdup(password, "password");
+ conn->nick = xstrdup(nick, "nick");
+ conn->ident = xstrdup(ident, "ident");
+ conn->realname = xstrdup(realname, "realname");
+ if (channel && channel[0])
+ conn->channel_autojoin = xstrdup(channel, "chan");
+
+ /* chatter_idle() will call irc_process() to kick off connection */
+}
+
+void
+chatter_dealloc_connection(struct chatter *chatter,
+ struct irc_connection *conn)
+{
+ short n;
+
+ if (conn->hostname != NULL)
+ xfree(&conn->hostname);
+ if (conn->password != NULL)
+ xfree(&conn->password);
+ if (conn->nick != NULL)
+ xfree(&conn->nick);
+ if (conn->ident != NULL)
+ xfree(&conn->ident);
+ if (conn->realname != NULL)
+ xfree(&conn->realname);
+ if (conn->channel_autojoin != NULL)
+ xfree(&conn->channel_autojoin);
+
+ chatter->cur_conn = NULL;
+
+ if (chatter->nconns == 1) {
+ chatter->nconns = 0;
+ xfree(&chatter->conns);
+ } else {
+ for (n = 0; n < chatter->nconns; n++) {
+ if (conn != &chatter->conns[n])
+ continue;
+
+ if (n == chatter->nconns - 1) {
+ /* just lop it off */
+ } else {
+ /* move the conn at the last place to here */
+ memcpy(&chatter->conns[n],
+ &chatter->conns[chatter->nconns - 1],
+ sizeof(struct irc_connection));
+ }
+ break;
+ }
+ chatter->nconns--;
+
+ xreallocarray(chatter->conns, chatter->nconns,
+ sizeof(struct irc_connection));
+ chatter->cur_conn = &chatter->conns[0];
+ }
+
+ chatter_update_titlebar(chatter);
+}
+
short
chatter_wait_type(struct focusable *focusable)
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
+ short n;
- if (chatter->irc_ibuflen)
- return WAIT_TYPE_URGENT;
- else if (!focusable->visible)
+ for (n = 0; n < chatter->nconns; n++) {
+ if (chatter->conns[n].ibuflen)
+ return WAIT_TYPE_URGENT;
+ }
+
+ if (!focusable->visible)
return WAIT_TYPE_BACKGROUND;
return WAIT_TYPE_FOREGROUND;
@@ -199,7 +276,8 @@ chatter_layout(struct chatter *chatter, bool init, Rec
(*(chatter->messages_te))->destRect = bounds;
TECalText(chatter->messages_te);
- chatter_autoscroll(chatter);
+ chatter_autoscroll(chatter, chatter->messages_te,
+ chatter->messages_scroller);
}
InvalRect(&win_bounds);
@@ -221,10 +299,12 @@ chatter_close(struct focusable *focusable, EventRecord
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
- if (chatter->irc_state < IRC_STATE_CONNECTED) {
+#if 0
+ if (chatter->conn->state < IRC_STATE_CONNECTED) {
irc_abort(chatter);
destroy_focusable(focusable);
} else
+#endif
hide_focusable(focusable);
}
@@ -232,12 +312,12 @@ bool
chatter_quit(struct focusable *focusable)
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
-
- if (chatter->irc_state < IRC_STATE_CONNECTED)
- irc_abort(chatter);
- else
- irc_close(chatter);
+ short n;
+ /* chatter->nconns will change as we dealloc, so we can't walk it */
+ while (chatter->nconns > 0)
+ irc_dealloc_connection(&chatter->conns[0]);
+
destroy_focusable(focusable);
return true;
}
@@ -246,8 +326,10 @@ void
chatter_atexit(struct focusable *focusable)
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
-
- irc_abort(chatter);
+ short n;
+
+ for (n = 0; n < chatter->nconns; n++)
+ irc_dealloc_connection(&chatter->conns[n]);
}
void
@@ -256,18 +338,19 @@ chatter_update_titlebar(struct chatter *chatter)
Str255 curtitle;
char title[64];
- if (chatter->irc_state <= IRC_STATE_DISCONNECTED)
+ if (!chatter->cur_conn ||
+ chatter->cur_conn->state <= IRC_STATE_DISCONNECTED)
snprintf(title, sizeof(title), "%s: Disconnected", PROGRAM_NAME);
- else if (chatter->irc_state == IRC_STATE_CONNECTING)
+ else if (chatter->cur_conn->state == IRC_STATE_CONNECTING)
snprintf(title, sizeof(title), "%s: Connecting to %s",
- PROGRAM_NAME, chatter->irc_hostname);
- else if (chatter->irc_channel)
+ PROGRAM_NAME, chatter->cur_conn->hostname);
+ else if (chatter->cur_channel)
snprintf(title, sizeof(title), "%s: %s@%s: %s", PROGRAM_NAME,
- chatter->irc_nick, chatter->irc_hostname,
- chatter->irc_channel->name);
+ chatter->cur_conn->nick, chatter->cur_conn->hostname,
+ chatter->cur_channel->name);
else
snprintf(title, sizeof(title), "%s: %s@%s", PROGRAM_NAME,
- chatter->irc_nick, chatter->irc_hostname);
+ chatter->cur_conn->nick, chatter->cur_conn->hostname);
GetWTitle(chatter->win, &curtitle);
PtoCstr(curtitle);
@@ -280,9 +363,14 @@ void
chatter_idle(struct focusable *focusable, EventRecord *event)
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
+ short n;
TEIdle(chatter->input_te);
- irc_process(chatter);
+ for (n = 0; n < chatter->nconns; n++) {
+ if (!irc_process(&chatter->conns[n]))
+ /* conn list might have changed */
+ return;
+ }
}
void
@@ -398,7 +486,7 @@ chatter_mouse_down(struct focusable *focusable, EventR
if (selected.v != now.v) {
LSetSelect(false, selected, chatter->nick_list);
- /* TODO */
+ /* TODO: detect double-click, open query window? */
}
return;
@@ -527,7 +615,12 @@ chatter_key_down(struct focusable *focusable, EventRec
TEIdle(chatter->input_te);
HUnlock(te->hText);
HUnlock(chatter->input_te);
- irc_process_input(chatter, input);
+ if (chatter->cur_conn)
+ irc_process_input(chatter->cur_conn, chatter->cur_channel,
+ input);
+ else
+ chatter_printf(chatter, NULL, NULL,
+ "$B*!*$0 Not connected");
xfree(&input);
} else {
TEKey(k, chatter->input_te);
@@ -536,7 +629,8 @@ chatter_key_down(struct focusable *focusable, EventRec
}
size_t
-chatter_printf(struct chatter *chatter, const char *format, ...)
+chatter_printf(struct chatter *chatter, struct irc_connection *conn,
+ struct irc_channel *channel, const char *format, ...)
{
static char buf[600], buf_out[600];
StScrpRec *scrp_rec;
@@ -551,6 +645,8 @@ chatter_printf(struct chatter *chatter, const char *fo
len = 0;
+ /* TODO: find correct TE based on conn+channel or just conn */
+
if ((*(chatter->messages_te))->teLength > 0) {
buf[0] = '\r';
len++;
@@ -678,38 +774,72 @@ no_overflow:
HUnlock(scrp_rec_h);
HUnlock(chatter->messages_te);
- chatter_autoscroll(chatter);
+ chatter_autoscroll(chatter, chatter->messages_te,
+ chatter->messages_scroller);
return buf_out_len;
}
void
-chatter_autoscroll(struct chatter *chatter)
+chatter_autoscroll(struct chatter *chatter, TEHandle te,
+ ControlHandle scroller)
{
- TEPinScroll(0, -INT_MAX, chatter->messages_te);
- SetCtlValue(chatter->messages_scroller,
- GetCtlMax(chatter->messages_scroller));
- UpdateScrollbarForTE(chatter->win, chatter->messages_scroller,
- chatter->messages_te, false);
+ TEPinScroll(0, -INT_MAX, te);
+ SetCtlValue(scroller, GetCtlMax(scroller));
+ UpdateScrollbarForTE(chatter->win, scroller, te, false);
}
+struct chatter *
+chatter_add_channel(struct irc_channel *channel)
+{
+ struct chatter *chatter;
+
+ /* XXX: for now put everything in the same TE as the connection */
+ chatter = channel->connection->chatter;
+ chatter->cur_conn = channel->connection;
+ chatter->cur_channel = channel;
+
+ chatter_sync_nick_list(chatter, channel, false);
+ chatter_update_titlebar(chatter);
+
+ return chatter;
+}
+
void
-chatter_sync_nick_list(struct chatter *chatter, bool just_summary)
+chatter_remove_channel(struct chatter *chatter,
+ struct irc_channel *channel)
{
+ short n;
+
+ /* TODO: change active channel, update nick list, etc. */
+
+ /*
+ * Don't bother updating titlebar because we should be inside
+ * irc_dealloc_channel which will then call chatter_update_titlebar
+ */
+ LDelRow(0, 0, chatter->nick_list);
+ InvalRect(&(*(chatter->nick_list))->rView);
+}
+
+void
+chatter_sync_nick_list(struct chatter *chatter, struct irc_channel *channel,
+ bool just_summary)
+{
size_t n, i, j, tj, ops, voices;
short ret, cellv;
struct irc_channel_nick *nick = NULL;
- if (!just_summary) {
+ /* TODO: find correct nick list for channel */
+
+ if (!just_summary && channel == chatter->cur_channel) {
LDoDraw(false, chatter->nick_list);
LDelRow(0, 0, chatter->nick_list);
}
- if (chatter->irc_channel) {
+ if (channel) {
cellv = 0;
ops = voices = 0;
- nick = &chatter->irc_channel->nicks[
- chatter->irc_channel->first_nick];
+ nick = &channel->nicks[channel->first_nick];
while (nick) {
if (nick->flags & IRC_NICK_FLAG_OP)
ops++;
@@ -717,20 +847,21 @@ chatter_sync_nick_list(struct chatter *chatter, bool j
voices++;
if (!just_summary)
- chatter_insert_to_nick_list(chatter, nick, cellv);
+ chatter_insert_to_nick_list(chatter, channel, nick, cellv);
cellv++;
if (nick->next_nick == -1)
break;
- nick = &chatter->irc_channel->nicks[nick->next_nick];
+ nick = &channel->nicks[nick->next_nick];
}
if (just_summary)
- chatter_printf(chatter, "$B%s$0: Total of $B%ld$0 nick%s $B("
- "%ld$0 op%s, $B%ld$0 voice%s$B)$0",
- chatter->irc_channel->name, chatter->irc_channel->nnicks,
- chatter->irc_channel->nnicks == 1 ? "" : "s",
+ chatter_printf(chatter, NULL, channel,
+ "$B%s$0: Total of $B%ld$0 nick%s $B(%ld$0 op%s, $B%ld$0 "
+ "voice%s$B)$0",
+ channel->name, channel->nnicks,
+ channel->nnicks == 1 ? "" : "s",
ops, ops == 1 ? "" : "s",
voices, voices == 1 ? "" : "s");
}
@@ -743,12 +874,15 @@ chatter_sync_nick_list(struct chatter *chatter, bool j
void
chatter_insert_to_nick_list(struct chatter *chatter,
- struct irc_channel_nick *nick, short pos)
+ struct irc_channel *channel, struct irc_channel_nick *nick, short pos)
{
Cell cell = { 0, 0 };
struct irc_channel_nick tnick;
- short j = 0;
+ ListHandle nick_list;
+ short j = 0;
+ nick_list = chatter->nick_list;
+
if (nick->flags & IRC_NICK_FLAG_OP) {
tnick.nick[0] = '@';
j++;
@@ -759,6 +893,6 @@ chatter_insert_to_nick_list(struct chatter *chatter,
cell.v = pos;
j += strlcpy(tnick.nick + j, nick->nick, sizeof(tnick.nick) - j);
- LAddRow(1, cell.v, chatter->nick_list);
- LSetCell(&tnick.nick, j, cell, chatter->nick_list);
+ LAddRow(1, cell.v, nick_list);
+ LSetCell(&tnick.nick, j, cell, nick_list);
}
--- chatter.h Wed Nov 30 23:19:19 2022
+++ chatter.h Sun Dec 11 15:01:04 2022
@@ -21,7 +21,6 @@
#include "focusable.h"
#include "irc.h"
-#include "tcp.h"
#include "util.h"
#define PROGRAM_NAME "Wallops"
@@ -81,38 +80,30 @@ struct chatter {
TEHandle input_te;
ListHandle nick_list;
- short irc_state;
- char *irc_hostname;
- short irc_port;
- char *irc_password;
- char *irc_nick;
- char *irc_ident;
- char *irc_realname;
- char *irc_channel_autojoin;
- struct irc_channel *irc_channel;
- TCPiopb irc_rcv_pb, irc_send_pb, irc_close_pb;
- TCPStatusPB irc_status_pb;
- StreamPtr irc_stream;
- wdsEntry irc_wds[2];
- char irc_obuf[512];
- char irc_ibuf[512]; /* RFC2812 says max line will be 512 */
- char irc_line[512];
- short irc_ibuflen;
- short irc_linelen;
- /* docs say 4*MTU+1024, but MTU will probably be <1500 */
- unsigned char irc_tcp_buf[(4 * 1500) + 1024];
+ short nconns;
+ struct irc_connection *conns;
+ struct irc_connection *cur_conn;
+ struct irc_channel *cur_channel;
};
void notify(void);
void cancel_notification(void);
-void chatter_init(const char *server, const unsigned short port,
- const char *nick, const char *password, const char *ident,
- const char *realname, const char *channel);
+struct chatter * chatter_init(void);
+void chatter_connect(struct chatter *chatter, const char *server,
+ const unsigned short port, const char *password, const char *nick,
+ const char *ident, const char *realname, const char *channel);
+void chatter_dealloc_connection(struct chatter *chatter,
+ struct irc_connection *conn);
void chatter_update_titlebar(struct chatter *chatter);
-size_t chatter_printf(struct chatter *chatter, const char *format, ...);
+size_t chatter_printf(struct chatter *chatter, struct irc_connection *conn,
+ struct irc_channel *channel, const char *format, ...);
void chatter_insert_to_nick_list(struct chatter *chatter,
- struct irc_channel_nick *nick, short pos);
-void chatter_sync_nick_list(struct chatter *chatter, bool just_summary);
+ struct irc_channel *channel, struct irc_channel_nick *nick, short pos);
+void chatter_sync_nick_list(struct chatter *chatter,
+ struct irc_channel *channel, bool just_summary);
+struct chatter * chatter_add_channel(struct irc_channel *channel);
+void chatter_remove_channel(struct chatter *chatter,
+ struct irc_channel *channel);
#endif
--- irc.c Thu Dec 1 21:49:44 2022
+++ irc.c Sun Dec 11 21:35:36 2022
@@ -22,61 +22,72 @@
#include "irc.h"
#include "strnatcmp.h"
-void irc_init(struct chatter *chatter);
-short irc_verify_state(struct chatter *chatter, int state);
-short irc_recv(struct chatter *chatter);
-size_t irc_send(struct chatter *chatter, char *line, size_t size);
-size_t irc_printf(struct chatter *chatter, const char *format, ...);
-char * irc_get_line(struct chatter *chatter, size_t *retsize);
+void irc_connect(struct irc_connection *conn);
+short irc_verify_state(struct irc_connection *conn, short state);
+short irc_recv(struct irc_connection *conn);
+size_t irc_send(struct irc_connection *conn, char *line, size_t size);
+size_t irc_printf(struct irc_connection *conn, const char *format, ...);
+char * irc_get_line(struct irc_connection *conn, size_t *retsize);
struct irc_user * irc_parse_user(char *str);
-bool irc_can_send(struct chatter *chatter);
-void irc_login(struct chatter *chatter);
-bool irc_process_server(struct chatter *chatter);
-void irc_set_active_channel(struct chatter *chatter, char *channame);
-void irc_parse_names(struct chatter *chatter, char *line);
-void irc_add_nick_to_channel(struct chatter *chatter, char *nick,
+bool irc_can_send(struct irc_connection *conn);
+void irc_login(struct irc_connection *conn);
+struct irc_channel * irc_find_channel(struct irc_connection *conn,
+ char *channame);
+bool irc_process_server(struct irc_connection *conn);
+struct irc_channel * irc_create_channel(struct irc_connection *conn,
+ char *channame);
+void irc_dealloc_channel(struct irc_channel *channel);
+void irc_set_active_channel(struct irc_connection *conn, char *channame);
+void irc_parse_names(struct irc_channel *channel, char *line);
+void irc_add_nick_to_channel(struct irc_channel *channel, char *nick,
short flags);
-void irc_remove_nick_from_channel(struct chatter *chatter, char *nick);
-void irc_change_user_nick(struct chatter *chatter, struct irc_user *user,
- char *nick);
-void irc_parse_channel_mode_change(struct chatter *chatter, char *mode,
+void irc_remove_nick_from_channel(struct irc_channel *channel, char *nick);
+bool irc_nick_is_in_channel(struct irc_channel *channel, char *nick);
+void irc_change_user_nick(struct irc_channel *channel,
+ struct irc_user *user, char *nick);
+void irc_parse_channel_mode_change(struct irc_channel *channel, char *mode,
char *args);
-void
-irc_process(struct chatter *chatter)
+#define IRC_CAN_SEND(conn) ((conn)->send_pb.ioResult <= 0)
+
+bool
+irc_process(struct irc_connection *conn)
{
short oldstate;
- if (chatter->irc_state >= IRC_STATE_CONNECTED)
- irc_recv(chatter);
-
- oldstate = chatter->irc_state;
+ if (conn->state >= IRC_STATE_CONNECTED) {
+ if (irc_recv(conn) < 0)
+ return false;
+ }
- switch (chatter->irc_state) {
+ oldstate = conn->state;
+
+ switch (conn->state) {
case IRC_STATE_UNINITED:
- chatter_printf(chatter, "$B***$0 Welcome to %s", PROGRAM_NAME);
- chatter->irc_state = IRC_STATE_CONNECTING;
- irc_init(chatter);
+ conn->state = IRC_STATE_CONNECTING;
+ irc_connect(conn);
break;
case IRC_STATE_CONNECTED:
- irc_login(chatter);
+ irc_login(conn);
break;
case IRC_STATE_IDLE:
- irc_process_server(chatter);
+ if (!irc_process_server(conn))
+ return false;
break;
}
- if (chatter->irc_state != oldstate)
- chatter_update_titlebar(chatter);
+ if (conn->state != oldstate)
+ chatter_update_titlebar(conn->chatter);
+
+ return true;
}
short
-irc_verify_state(struct chatter *chatter, int state)
+irc_verify_state(struct irc_connection *conn, short state)
{
- if (chatter->irc_state != state) {
- warn("Bad IRC state (in %d, expected %d)", chatter->irc_state,
- state);
- chatter->irc_state = IRC_STATE_DISCONNECTED;
+ if (conn->state != state) {
+ warn("Bad IRC state (in %d, expected %d)", conn->state, state);
+ conn->state = IRC_STATE_DISCONNECTED;
return 0;
}
@@ -84,7 +95,7 @@ irc_verify_state(struct chatter *chatter, int state)
}
void
-irc_init(struct chatter *chatter)
+irc_connect(struct irc_connection *conn)
{
char ip_str[] = "255.255.255.255";
char *retname;
@@ -92,140 +103,138 @@ irc_init(struct chatter *chatter)
ip_port port, local_port = 0;
short err;
- if (!irc_verify_state(chatter, IRC_STATE_CONNECTING))
+ if (!irc_verify_state(conn, IRC_STATE_CONNECTING))
return;
- chatter_printf(chatter, "$B***$0 Connecting to $B%s:%d$0...",
- chatter->irc_hostname, chatter->irc_port);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 Connecting to $B%s:%d$0...", conn->hostname, conn->port);
- if ((err = _TCPCreate(&chatter->irc_send_pb, &chatter->irc_stream,
- (Ptr)chatter->irc_tcp_buf, sizeof(chatter->irc_tcp_buf),
- nil, nil, nil, false)) != noErr) {
- chatter_printf(chatter, "%B*!* TCPCreate failed: %d$0", err);
- chatter->irc_state = IRC_STATE_DISCONNECTED;
+ if ((err = _TCPCreate(&conn->send_pb, &conn->stream,
+ (Ptr)conn->tcp_buf, sizeof(conn->tcp_buf), nil, nil, nil,
+ false)) != noErr) {
+ chatter_printf(conn->chatter, conn, NULL,
+ "%B*!* TCPCreate failed: %d$0", err);
+ conn->state = IRC_STATE_DISCONNECTED;
return;
}
- if ((err = TCPResolveName(&chatter->irc_hostname, &ip)) != 0) {
- chatter_printf(chatter, "$B*!* Couldn't resolve host %s (%d)$0",
- chatter->irc_hostname, err);
- chatter->irc_state = IRC_STATE_DISCONNECTED;
+ if ((err = TCPResolveName(conn->hostname, &ip)) != 0) {
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* Couldn't resolve host %s (%d)$0", conn->hostname, err);
+ conn->state = IRC_STATE_DISCONNECTED;
return;
}
long2ip(ip, ip_str);
- if ((err = _TCPActiveOpen(&chatter->irc_send_pb, chatter->irc_stream,
- ip, chatter->irc_port, &local_ip, &local_port, nil, nil,
- false)) != noErr) {
- chatter_printf(chatter, "$B*!* Failed connecting to %s (%s) "
- "port %d: %d$0", chatter->irc_hostname, ip_str,
- chatter->irc_port, err);
- chatter->irc_state = IRC_STATE_DISCONNECTED;
+ if ((err = _TCPActiveOpen(&conn->send_pb, conn->stream, ip,
+ conn->port, &local_ip, &local_port, nil, nil, false)) != noErr) {
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* Failed connecting to %s (%s) port %d: %d$0",
+ conn->hostname, ip_str, conn->port, err);
+ conn->state = IRC_STATE_DISCONNECTED;
return;
}
- chatter_printf(chatter, "$B***$0 Connected to $B%s$0 (%s) port %d",
- chatter->irc_hostname, ip_str, chatter->irc_port);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 Connected to $B%s$0 (%s) port %d", conn->hostname, ip_str,
+ conn->port);
- chatter->irc_state = IRC_STATE_CONNECTED;
+ conn->state = IRC_STATE_CONNECTED;
}
void
-irc_abort(struct chatter *chatter)
+irc_dealloc_connection(struct irc_connection *conn)
{
- chatter->irc_state = IRC_STATE_DISCONNECTED;
- irc_set_active_channel(chatter, NULL);
+ short n;
- _TCPClose(&chatter->irc_close_pb, chatter->irc_stream, nil, nil,
- false);
- _TCPAbort(&chatter->irc_close_pb, chatter->irc_stream, nil, nil,
- false);
- _TCPRelease(&chatter->irc_close_pb, chatter->irc_stream, nil, nil,
- false);
+ while (conn->nchannels > 0)
+ irc_dealloc_channel(&conn->channels[0]);
- chatter->irc_ibuflen = 0;
+ _TCPClose(&conn->close_pb, conn->stream, nil, nil, false);
+ _TCPAbort(&conn->close_pb, conn->stream, nil, nil, false);
+ _TCPRelease(&conn->close_pb, conn->stream, nil, nil, false);
+
+ chatter_dealloc_connection(conn->chatter, conn);
}
void
-irc_close(struct chatter *chatter)
+irc_close(struct irc_connection *conn)
{
- if (chatter->irc_state == IRC_STATE_DISCONNECTED)
+ if (conn->state == IRC_STATE_DISCONNECTED)
return;
- chatter_printf(chatter, "$B***$0 Disconnecting");
- if (chatter->irc_state == IRC_STATE_IDLE)
- irc_printf(chatter, "QUIT :Cmd+Q\r\n");
- irc_abort(chatter);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 Disconnecting");
+ if (conn->state == IRC_STATE_IDLE)
+ irc_printf(conn, "QUIT :Cmd+Q\r\n");
+ irc_dealloc_connection(conn);
}
short
-irc_recv(struct chatter *chatter)
+irc_recv(struct irc_connection *conn)
{
unsigned short rlen;
short error, rerror, n;
- error = _TCPStatus(&chatter->irc_rcv_pb, chatter->irc_stream,
- &chatter->irc_status_pb, nil, nil, false);
+ error = _TCPStatus(&conn->rcv_pb, conn->stream, &conn->status_pb, nil,
+ nil, false);
- if (chatter->irc_status_pb.amtUnreadData > 0 &&
- chatter->irc_ibuflen < sizeof(chatter->irc_ibuf)) {
- rlen = chatter->irc_status_pb.amtUnreadData;
- if (chatter->irc_ibuflen + rlen > sizeof(chatter->irc_ibuf))
- rlen = sizeof(chatter->irc_ibuf) - chatter->irc_ibuflen;
+ if (conn->status_pb.amtUnreadData > 0 &&
+ conn->ibuflen < sizeof(conn->ibuf)) {
+ rlen = conn->status_pb.amtUnreadData;
+ if (conn->ibuflen + rlen > sizeof(conn->ibuf))
+ rlen = sizeof(conn->ibuf) - conn->ibuflen;
- rerror = _TCPRcv(&chatter->irc_rcv_pb, chatter->irc_stream,
- (Ptr)(chatter->irc_ibuf + chatter->irc_ibuflen), &rlen, nil, nil,
- false);
+ rerror = _TCPRcv(&conn->rcv_pb, conn->stream,
+ (Ptr)(conn->ibuf + conn->ibuflen), &rlen, nil, nil, false);
if (rerror) {
- chatter_printf(chatter, "$B*!* TCPRecv failed: %d$0", error);
- irc_abort(chatter);
- return 0;
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* TCPRecv failed (%d), disconnecting$0", error);
+ irc_dealloc_connection(conn);
+ return -1;
}
- chatter->irc_ibuflen += rlen;
+ conn->ibuflen += rlen;
}
if (error) {
/* let already-consumed buffer finish processing */
- while (irc_process_server(chatter))
- ;
- chatter_printf(chatter, "$B*!* TCPStatus failed: %d$0", error);
- irc_abort(chatter);
- return 0;
+ while (irc_process_server(conn))
+ SystemTask();
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* TCPStatus failed: %d$0",
+ error);
+ irc_dealloc_connection(conn);
+ return -1;
}
return rlen;
}
-bool
-irc_can_send(struct chatter *chatter)
-{
- return (chatter->irc_send_pb.ioResult <= 0);
-}
-
size_t
-irc_send(struct chatter *chatter, char *line, size_t size)
+irc_send(struct irc_connection *conn, char *line, size_t size)
{
short error;
- if (size > sizeof(chatter->irc_obuf))
+ if (size > sizeof(conn->obuf))
panic("irc_send: too much data %lu", size);
- if (chatter->irc_state == IRC_STATE_DISCONNECTED)
+ if (conn->state == IRC_STATE_DISCONNECTED)
return 0;
- while (!irc_can_send(chatter))
+ while (!IRC_CAN_SEND(conn))
SystemTask();
- if (chatter->irc_send_pb.ioResult < 0) {
- chatter_printf(chatter, "$B*!* TCPSend failed: %d$0",
- chatter->irc_send_pb.ioResult);
- irc_abort(chatter);
+ if (conn->send_pb.ioResult < 0) {
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* TCPSend failed: %d$0",
+ conn->send_pb.ioResult);
+ irc_dealloc_connection(conn);
return 0;
}
- memcpy(&chatter->irc_obuf, line, size);
+ memcpy(&conn->obuf, line, size);
/*
* _TCPSend only knows how many wds pointers were passed in when it
@@ -233,15 +242,16 @@ irc_send(struct chatter *chatter, char *line, size_t s
* even though we're only sending one wds, memory after wds[0]
* has to be zeroed out.
*/
- memset(&chatter->irc_wds, 0, sizeof(chatter->irc_wds));
- chatter->irc_wds[0].ptr = (Ptr)&chatter->irc_obuf;
- chatter->irc_wds[0].length = size;
+ memset(&conn->wds, 0, sizeof(conn->wds));
+ conn->wds[0].ptr = (Ptr)&conn->obuf;
+ conn->wds[0].length = size;
- error = _TCPSend(&chatter->irc_send_pb, chatter->irc_stream,
- chatter->irc_wds, nil, nil, true);
+ error = _TCPSend(&conn->send_pb, conn->stream, conn->wds, nil, nil,
+ true);
if (error) {
- chatter_printf(chatter, "$B*!* TCPSend failed: %d$0", error);
- irc_abort(chatter);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* TCPSend failed: %d$0", error);
+ irc_dealloc_connection(conn);
return 0;
}
@@ -249,7 +259,7 @@ irc_send(struct chatter *chatter, char *line, size_t s
}
size_t
-irc_printf(struct chatter *chatter, const char *format, ...)
+irc_printf(struct irc_connection *conn, const char *format, ...)
{
static char buf[512];
va_list argptr;
@@ -265,43 +275,37 @@ irc_printf(struct chatter *chatter, const char *format
buf[len - 1] = '\0';
}
- irc_send(chatter, buf, len);
+ irc_send(conn, buf, len);
return len;
}
void
-irc_login(struct chatter *chatter)
+irc_login(struct irc_connection *conn)
{
size_t len;
- if (!irc_verify_state(chatter, IRC_STATE_CONNECTED))
+ if (!irc_verify_state(conn, IRC_STATE_CONNECTED))
return;
- if (!irc_can_send(chatter))
+ if (!IRC_CAN_SEND(conn))
return;
- if (chatter->irc_password && chatter->irc_password[0]) {
- len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
- "PASS %s\r\n", chatter->irc_password);
- irc_send(chatter, chatter->irc_line, len);
+ if (conn->password && conn->password[0]) {
+ len = snprintf(conn->line, sizeof(conn->line),
+ "PASS %s\r\n", conn->password);
+ irc_send(conn, conn->line, len);
}
- len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
- "NICK %s\r\n", chatter->irc_nick);
- irc_send(chatter, chatter->irc_line, len);
+ len = snprintf(conn->line, sizeof(conn->line),
+ "NICK %s\r\n", conn->nick);
+ irc_send(conn, conn->line, len);
- len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
- "USER %s 8 * :%s\r\n", chatter->irc_ident, chatter->irc_realname);
- irc_send(chatter, chatter->irc_line, len);
+ len = snprintf(conn->line, sizeof(conn->line),
+ "USER %s 0 * :%s\r\n", conn->ident, conn->realname);
+ irc_send(conn, conn->line, len);
- if (chatter->irc_channel_autojoin && chatter->irc_channel_autojoin[0]) {
- len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
- "JOIN %s\r\n", chatter->irc_channel_autojoin);
- irc_send(chatter, chatter->irc_line, len);
- }
-
- chatter->irc_state = IRC_STATE_IDLE;
+ conn->state = IRC_STATE_IDLE;
}
struct irc_user *
@@ -323,59 +327,77 @@ irc_parse_user(char *str)
}
char *
-irc_get_line(struct chatter *chatter, size_t *retsize)
+irc_get_line(struct irc_connection *conn, size_t *retsize)
{
size_t n;
- if (chatter->irc_ibuflen == 0) {
+ if (conn->ibuflen == 0) {
if (retsize != NULL)
*retsize = 0;
return NULL;
}
- for (n = 0; n < chatter->irc_ibuflen - 1; n++) {
- if (chatter->irc_ibuf[n] != '\r')
+ for (n = 0; n < conn->ibuflen - 1; n++) {
+ if (conn->ibuf[n] != '\r')
continue;
- if (chatter->irc_ibuf[n + 1] != '\n')
+ if (conn->ibuf[n + 1] != '\n')
continue;
- memcpy(chatter->irc_line, chatter->irc_ibuf, n + 1);
- chatter->irc_line[n] = '\0';
+ memcpy(conn->line, conn->ibuf, n + 1);
+ conn->line[n] = '\0';
if (retsize != NULL)
*retsize = n + 1;
- if (n == chatter->irc_ibuflen - 2) {
- chatter->irc_ibuflen = 0;
+ if (n == conn->ibuflen - 2) {
+ conn->ibuflen = 0;
} else {
- chatter->irc_ibuflen -= n + 2;
- if (chatter->irc_ibuflen < 0)
- panic("bogus irc_ibuflen %d", chatter->irc_ibuflen);
- memmove(chatter->irc_ibuf, chatter->irc_ibuf + n + 2,
- chatter->irc_ibuflen);
+ conn->ibuflen -= n + 2;
+ if (conn->ibuflen < 0)
+ panic("bogus ibuflen %d", conn->ibuflen);
+ memmove(conn->ibuf, conn->ibuf + n + 2, conn->ibuflen);
}
- return chatter->irc_line;
+ return conn->line;
}
return NULL;
}
+struct irc_channel *
+irc_find_channel(struct irc_connection *conn, char *channame)
+{
+ short n;
+
+ if (channame == NULL || channame[0] == '\0')
+ return NULL;
+
+ for (n = 0; n < conn->nchannels; n++) {
+ if (strcasecmp(conn->channels[n].name, channame) == 0)
+ return &conn->channels[n];
+ }
+
+ return NULL;
+}
+
bool
-irc_process_server(struct chatter *chatter)
+irc_process_server(struct irc_connection *conn)
{
struct irc_msg msg;
struct irc_user *user;
+ struct irc_channel *channel;
char *line, *word;
size_t size, n, lastbreak;
short state, curarg;
- line = irc_get_line(chatter, &size);
+ line = irc_get_line(conn, &size);
if (size == 0 || line == NULL)
return false;
-
+
memset(&msg, 0, sizeof(msg));
- if (strstr(line, "services"))
+#if 0 /* XXX: what is this for? */
+ if (strstr(line, "services") != 0)
msg.code = 1;
+#endif
word = strsep(&line, " ");
@@ -428,22 +450,26 @@ irc_process_server(struct chatter *chatter)
if (strcmp(msg.cmd, "PRIVMSG") == 0) {
user = irc_parse_user(msg.source);
size = strlen(msg.msg);
+ channel = irc_find_channel(conn, msg.arg[0]);
if (msg.msg[0] == '\1' && msg.msg[size - 1] == '\1') {
/* CTCP or a /me action */
msg.msg[size - 1] = '\0';
if (strncmp(msg.msg + 1, "ACTION", 6) == 0) {
- chatter_printf(chatter, "* %s$/ %s", user->nick,
- msg.msg + 8);
+ chatter_printf(channel ? channel->chatter :
+ conn->chatter, conn, channel,
+ "* %s$/ %s",
+ user->nick, msg.msg + 8);
} else if (strncmp(msg.msg + 1, "VERSION", 7) == 0) {
- chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0 "
- "requested CTCP $BVERSION$0 from $B%s$0",
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** %s ($0%s@%s$B)$0 requested CTCP $BVERSION$0 "
+ "from $B%s$0",
user->nick, user->username, user->hostname,
msg.arg[0]);
/* only respond if it was sent directly to us */
- if (strcmp(msg.arg[0], chatter->irc_nick) == 0) {
- irc_printf(chatter,
+ if (strcmp(msg.arg[0], conn->nick) == 0) {
+ irc_printf(conn,
"NOTICE %s :\1VERSION %s %s on a %s\1\r\n",
user->nick, PROGRAM_NAME, get_version(false),
gestalt_machine_type());
@@ -451,74 +477,96 @@ irc_process_server(struct chatter *chatter)
} else {
goto unknown;
}
- } else if (strcmp(msg.arg[0], chatter->irc_nick) == 0) {
- chatter_printf(chatter, "$B[$0%s$B($0%s@%s$B)]$0$/ %s",
+ } else if (strcmp(msg.arg[0], conn->nick) == 0) {
+ chatter_printf(channel ? channel->chatter : conn->chatter,
+ conn, channel,
+ "$B[%s($0%s@%s$B)]$0$/ %s",
user->nick, user->username, user->hostname, msg.msg);
- } else if (chatter->irc_channel &&
- strcmp(msg.arg[0], chatter->irc_channel->name) == 0) {
- size = strlen(chatter->irc_nick);
- if (strncmp(msg.msg, chatter->irc_nick, size) == 0 &&
+ } else if (channel != NULL) {
+ size = strlen(conn->nick);
+ if (strncmp(msg.msg, conn->nick, size) == 0 &&
(msg.msg[size] == ' ' || msg.msg[size] == ':' ||
msg.msg[size] == ',' || msg.msg[size] == '\0')) {
/* highlight message */
- chatter_printf(chatter, "<$U%s$0>$/ %s", user->nick,
+ chatter_printf(channel->chatter, conn, channel,
+ "<$U%s$0>$/ %s", user->nick,
msg.msg);
- if (!chatter->focusable->visible)
+ if (!conn->chatter->focusable->visible)
notify();
} else
- chatter_printf(chatter, "$/<%s> %s", user->nick,
- msg.msg);
+ chatter_printf(channel->chatter, conn, channel,
+ "$/<%s> %s",
+ user->nick, msg.msg);
} else
- chatter_printf(chatter, "$B[%s($0%s@%s$B):%s]$0$/ %s",
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B[%s($0%s@%s$B):%s]$0$/ %s",
user->nick, user->username, user->hostname, msg.arg[0],
msg.msg);
return true;
}
if (strcmp(msg.cmd, "ERROR") == 0) {
- chatter_printf(chatter, "$B*!* Disconnected$0 from $B%s$0:$/ %s",
- chatter->irc_hostname, msg.msg);
- irc_abort(chatter);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*!* Disconnected$0 from $B%s$0:$/ %s",
+ conn->hostname, msg.msg);
+ irc_dealloc_connection(conn);
return true;
}
if (strcmp(msg.cmd, "JOIN") == 0) {
user = irc_parse_user(msg.source);
- chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0 has joined "
- "$B%s$0", user->nick, user->username, user->hostname,
- msg.arg[0]);
- if (strcmp(user->nick, chatter->irc_nick) == 0)
- irc_set_active_channel(chatter, msg.arg[0]);
- else
- irc_add_nick_to_channel(chatter, user->nick, 0);
+ if (strcmp(user->nick, conn->nick) == 0)
+ channel = irc_create_channel(conn, msg.arg[0]);
+ else {
+ channel = irc_find_channel(conn, msg.arg[0]);
+ irc_add_nick_to_channel(channel, user->nick, 0);
+ }
+ chatter_printf(channel->chatter, conn, channel,
+ "$B*** %s ($0%s@%s$B)$0 has joined $B%s$0",
+ user->nick, user->username, user->hostname, msg.arg[0]);
return true;
}
if (strcmp(msg.cmd, "KICK") == 0) {
user = irc_parse_user(msg.source);
- chatter_printf(chatter, "$B*** %s$0 was kicked "
- "from $B%s$0 by $B%s%0:$/ %s", msg.arg[1], msg.arg[0],
- user->nick, msg.msg);
- if (strcmp(msg.arg[1], chatter->irc_nick) == 0)
- irc_set_active_channel(chatter, NULL);
- else
- irc_remove_nick_from_channel(chatter, msg.arg[1]);
+ channel = irc_find_channel(conn, msg.arg[0]);
+ if (strcmp(msg.arg[1], conn->nick) == 0) {
+ irc_dealloc_channel(channel);
+ channel = NULL;
+ } else
+ irc_remove_nick_from_channel(channel, msg.arg[1]);
+ chatter_printf(channel ? channel->chatter : conn->chatter,
+ conn, channel,
+ "$B*** %s$0 was kicked from $B%s$0 by $B%s%0:$/ %s",
+ msg.arg[1], msg.arg[0], user->nick, msg.msg);
return true;
}
if (strcmp(msg.cmd, "KILL") == 0) {
user = irc_parse_user(msg.source);
- chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0 has been "
- "killed:$/ %s", user->nick, user->username, user->hostname,
- msg.msg);
- if (strcmp(user->nick, chatter->irc_nick) == 0)
- irc_set_active_channel(chatter, NULL);
- else
- irc_remove_nick_from_channel(chatter, user->nick);
+ if (strcmp(user->nick, conn->nick) == 0) {
+ /* we died :( */
+ warn("%s (%s@%s) has been killed: %s",
+ user->nick, user->username, user->hostname, msg.msg);
+ irc_dealloc_connection(conn);
+ return false;
+ }
+ for (n = 0; n < conn->nchannels; n++) {
+ if (!irc_nick_is_in_channel(&conn->channels[n],
+ user->nick))
+ continue;
+
+ chatter_printf(conn->chatter, conn, &conn->channels[n],
+ "$B*** %s ($0%s@%s$B)$0 has been killed:$/ %s",
+ user->nick, user->username, user->hostname, msg.msg);
+ irc_remove_nick_from_channel(channel, user->nick);
+ }
return true;
}
if (strcmp(msg.cmd, "MODE") == 0) {
- if (strcmp(msg.arg[0], chatter->irc_nick) == 0)
- chatter_printf(chatter, "$B***$0 Mode change ($B%s$0) "
- "for user $B%s$0", msg.msg, msg.arg[0]);
+ if (strcmp(msg.arg[0], conn->nick) == 0)
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 Mode change ($B%s$0) for user $B%s$0",
+ msg.msg, msg.arg[0]);
else {
user = irc_parse_user(msg.source);
+ channel = irc_find_channel(conn, msg.arg[0]);
/* concatenate nicks */
msg.msg[0] = '\0';
if (msg.arg[2][0] != '\0')
@@ -535,51 +583,75 @@ irc_process_server(struct chatter *chatter)
strlcat(msg.msg, " ", sizeof(msg.msg));
strlcat(msg.msg, msg.arg[5], sizeof(msg.msg));
}
- chatter_printf(chatter, "$B***$0 Mode change ($B%s %s$0) "
- "on $B%s$0 by $B%s%0", msg.arg[1], msg.msg, msg.arg[0],
- user->nick);
- irc_parse_channel_mode_change(chatter, msg.arg[1],
- msg.msg);
+ chatter_printf(channel ? channel->chatter : conn->chatter,
+ conn, channel,
+ "$B***$0 Mode change ($B%s %s$0) on $B%s$0 by $B%s%0",
+ msg.arg[1], msg.msg, msg.arg[0], user->nick);
+ if (channel)
+ irc_parse_channel_mode_change(channel, msg.arg[1],
+ msg.msg);
}
return true;
}
if (strcmp(msg.cmd, "NICK") == 0) {
user = irc_parse_user(msg.source);
- chatter_printf(chatter, "$B*** %s$0 is now known as $B%s$0",
- user->nick, msg.msg);
- irc_change_user_nick(chatter, user, msg.msg);
+ for (n = 0; n < conn->nchannels; n++) {
+ channel = &conn->channels[n];
+ if (!irc_nick_is_in_channel(channel, user->nick))
+ continue;
+
+ chatter_printf(channel->chatter, conn, channel,
+ "$B*** %s$0 is now known as $B%s$0",
+ user->nick, msg.msg);
+ irc_change_user_nick(channel, user, msg.msg);
+ }
return true;
}
if (strcmp(msg.cmd, "NOTICE") == 0) {
if (strncmp(msg.msg, "*** ", 4) == 0)
- chatter_printf(chatter, "$B***$0 $/%s", msg.msg + 4);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 $/%s",
+ msg.msg + 4);
else
- chatter_printf(chatter, "$/%s", msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$/%s",
+ msg.msg);
return true;
}
if (strcmp(msg.cmd, "PART") == 0) {
user = irc_parse_user(msg.source);
- chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0 has left "
- "$B%s$0", user->nick, user->username, user->hostname,
- msg.arg[0]);
- if (strcmp(user->nick, chatter->irc_nick) == 0)
- irc_set_active_channel(chatter, NULL);
- else
- irc_remove_nick_from_channel(chatter, user->nick);
+ channel = irc_find_channel(conn, msg.arg[0]);
+ if (strcmp(user->nick, conn->nick) == 0) {
+ irc_dealloc_channel(channel);
+ channel = NULL;
+ } else
+ irc_remove_nick_from_channel(channel, user->nick);
+ chatter_printf(channel ? channel->chatter : conn->chatter,
+ conn, channel,
+ "$B*** %s ($0%s@%s$B)$0 has left $B%s$0",
+ user->nick, user->username, user->hostname, msg.arg[0]);
return true;
}
if (strcmp(msg.cmd, "PING") == 0) {
- irc_printf(chatter, "PONG :%s\r\n", msg.msg);
+ irc_printf(conn, "PONG :%s\r\n", msg.msg);
return true;
}
if (strcmp(msg.cmd, "QUIT") == 0) {
user = irc_parse_user(msg.source);
- chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0 has quit:$/ %s",
- user->nick, user->username, user->hostname, msg.msg);
- if (strcmp(user->nick, chatter->irc_nick) == 0)
- irc_set_active_channel(chatter, NULL);
- else
- irc_remove_nick_from_channel(chatter, user->nick);
+ for (n = 0; n < conn->nchannels; n++) {
+ channel = &conn->channels[n];
+ if (!irc_nick_is_in_channel(channel, user->nick))
+ continue;
+
+ irc_remove_nick_from_channel(channel, user->nick);
+ chatter_printf(conn->chatter, conn, channel,
+ "$B*** %s ($0%s@%s$B)$0 has quit:$/ %s",
+ user->nick, user->username, user->hostname, msg.msg);
+ }
+ if (strcmp(user->nick, conn->nick) == 0) {
+ irc_dealloc_connection(conn);
+ return false;
+ }
return true;
}
goto unknown;
@@ -607,59 +679,73 @@ irc_process_server(struct chatter *chatter)
return true;
case 307:
/* WHOIS regnick */
- chatter_printf(chatter, "$B*** |$0 Authenticated:$/ %s", msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Authenticated:$/ %s",
+ msg.msg);
return true;
case 311:
/* WHOIS nick: "nick :ident hostname * :name" */
- chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0", msg.arg[1],
- msg.arg[2], msg.arg[3]);
- chatter_printf(chatter, "$B*** |$0 Name:$/ %s", msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** %s ($0%s@%s$B)$0",
+ msg.arg[1], msg.arg[2], msg.arg[3]);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Name:$/ %s",
+ msg.msg);
return true;
case 312:
/* WHOIS server */
- chatter_printf(chatter, "$B*** |$0 Server:$/ %s (%s)", msg.arg[2],
- msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Server:$/ %s (%s)",
+ msg.arg[2], msg.msg);
return true;
case 671:
/* WHOIS server */
- chatter_printf(chatter, "$B*** |$0 Connection:$/ %s", msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Connection:$/ %s",
+ msg.msg);
return true;
case 317:
/* WHOIS idle */
- chatter_printf(chatter, "$B*** |$0 Idle:$/ %s %s", msg.arg[2],
- msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Idle:$/ %s %s",
+ msg.arg[2], msg.msg);
return true;
case 318:
/* WHOIS end */
- chatter_printf(chatter, "$B*** `-------$0");
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** `-------$0");
return true;
case 319:
/* WHOIS channels */
- chatter_printf(chatter, "$B*** |$0 Channels:$/ %s", msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Channels:$/ %s",
+ msg.msg);
return true;
case 330:
/* WHOIS account */
- chatter_printf(chatter, "$B*** |$0 Account:$/ %s %s", msg.msg,
- msg.arg[2]);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Account:$/ %s %s",
+ msg.msg, msg.arg[2]);
return true;
case 338:
case 378:
/* WHOIS host */
- chatter_printf(chatter, "$B*** |$0 Host:$/ %s %s", msg.msg,
- msg.arg[2]);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B*** |$0 Host:$/ %s %s",
+ msg.msg, msg.arg[2]);
return true;
case 328:
/* channel URL, we probably can't do anything with it anyway */
return true;
case 332:
/* TOPIC */
- chatter_printf(chatter, "$B***$0 Topic for $B%s$0:$/ %s",
+ channel = irc_find_channel(conn, msg.arg[1]);
+ chatter_printf(channel ? channel->chatter : conn->chatter, conn,
+ channel,
+ "$B***$0 Topic for $B%s$0:$/ %s",
msg.arg[1], msg.msg);
- if (chatter->irc_channel &&
- strcmp(chatter->irc_channel->name, msg.arg[1]) == 0) {
- strlcpy(chatter->irc_channel->topic, msg.msg,
- sizeof(chatter->irc_channel->topic));
- }
+ if (channel)
+ strlcpy(channel->topic, msg.msg, sizeof(channel->topic));
return true;
case 333:
/* TOPIC creator */
@@ -672,40 +758,51 @@ irc_process_server(struct chatter *chatter)
goto unknown;
case 353:
/* NAMES output */
- if (chatter->irc_channel &&
- strcmp(msg.arg[2], chatter->irc_channel->name) == 0)
- irc_parse_names(chatter, msg.msg);
+ channel = irc_find_channel(conn, msg.arg[2]);
+ if (channel)
+ irc_parse_names(channel, msg.msg);
return true;
case 366:
/* end of NAMES output */
- if (chatter->irc_channel &&
- strcmp(msg.arg[1], chatter->irc_channel->name) == 0)
- chatter_sync_nick_list(chatter, true);
+ channel = irc_find_channel(conn, msg.arg[1]);
+ if (channel)
+ chatter_sync_nick_list(channel->chatter, channel, true);
return true;
case 372:
case 375:
- case 376:
/* MOTD */
goto print_msg;
+ case 376:
+ /* end of MOTD */
+ if (conn->channel_autojoin && conn->channel_autojoin[0] &&
+ !conn->did_autojoin) {
+ irc_printf(conn, "JOIN %s\r\n", conn->channel_autojoin);
+ conn->did_autojoin = true;
+ }
+ goto print_msg;
case 396:
/* Cloak */
- chatter_printf(chatter, "$B***$0$/ %s %s", msg.arg[1], msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0$/ %s %s",
+ msg.arg[1], msg.msg);
return true;
case 433: {
/* Nick in use, try appending a _ */
- char *new_nick = xmalloc(strlen(chatter->irc_nick) + 2, "new nick");
+ char *new_nick = xmalloc(strlen(conn->nick) + 2, "new nick");
size_t len;
- chatter_printf(chatter, "$B***$0$/ %s: %s", msg.arg[1], msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0$/ %s: %s",
+ msg.arg[1], msg.msg);
- sprintf(new_nick, "%s_", chatter->irc_nick);
- xfree(&chatter->irc_nick);
- chatter->irc_nick = new_nick;
- chatter_update_titlebar(chatter);
+ sprintf(new_nick, "%s_", conn->nick);
+ xfree(&conn->nick);
+ conn->nick = new_nick;
+ chatter_update_titlebar(conn->chatter);
- len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
- "NICK %s\r\n", chatter->irc_nick);
- irc_send(chatter, chatter->irc_line, len);
+ len = snprintf(conn->line, sizeof(conn->line),
+ "NICK %s\r\n", conn->nick);
+ irc_send(conn, conn->line, len);
return true;
}
default:
@@ -713,29 +810,34 @@ irc_process_server(struct chatter *chatter)
}
print_msg:
- chatter_printf(chatter, "$B***$0$/ %s", msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0$/ %s",
+ msg.msg);
return true;
unknown:
- chatter_printf(chatter, "$B[?]$0$/ code:%d cmd:%s source:%s "
- "arg0:%s arg1:%s arg2:%s arg3:%s arg4:%s msg:%s", msg.code, msg.cmd,
- msg.source, msg.arg[0], msg.arg[1], msg.arg[2], msg.arg[3],
- msg.arg[4], msg.msg);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B[?]$0$/ code:%d cmd:%s source:%s arg0:%s arg1:%s arg2:%s arg3:%s "
+ "arg4:%s msg:%s",
+ msg.code, msg.cmd, msg.source, msg.arg[0], msg.arg[1], msg.arg[2],
+ msg.arg[3], msg.arg[4], msg.msg);
return true;
}
void
-irc_process_input(struct chatter *chatter, char *str)
+irc_process_input(struct irc_connection *conn, struct irc_channel *channel,
+ char *str)
{
char *arg0, *arg1;
size_t n;
if (str[0] != '/') {
- if (chatter->irc_channel == NULL)
+ if (channel == NULL)
goto not_in_channel;
- irc_printf(chatter, "PRIVMSG %s :%s\r\n",
- chatter->irc_channel->name, str);
- chatter_printf(chatter, "<$B%s$0>$/ %s", chatter->irc_nick, str);
+ irc_printf(conn, "PRIVMSG %s :%s\r\n", channel->name, str);
+ chatter_printf(conn->chatter, conn, channel,
+ "<$B%s$0>$/ %s",
+ conn->nick, str);
return;
}
@@ -747,101 +849,168 @@ irc_process_input(struct chatter *chatter, char *str)
if (strcmp(arg0, "join") == 0) {
if (str == NULL)
goto not_enough_params;
- irc_printf(chatter, "JOIN %s\r\n", str);
+ /*
+ * If we're already in this channel, we won't get any response
+ * from the server to switch channels.
+ */
+ channel = irc_find_channel(conn, str);
+ if (channel)
+ /* this won't actually create, it'll just switch for us */
+ irc_create_channel(conn, str);
+ else
+ irc_printf(conn, "JOIN %s\r\n", str);
return;
}
if (strcmp(arg0, "me") == 0) {
if (str == NULL)
goto not_enough_params;
- if (chatter->irc_channel == NULL)
+ if (channel == NULL)
goto not_in_channel;
- chatter_printf(chatter, "* %s$/ %s", chatter->irc_nick, str);
- irc_printf(chatter, "PRIVMSG %s :\1ACTION %s\1\r\n",
- chatter->irc_channel->name, str);
+ chatter_printf(conn->chatter, conn, channel,
+ "* %s$/ %s",
+ conn->nick, str);
+ irc_printf(conn, "PRIVMSG %s :\1ACTION %s\1\r\n", channel->name,
+ str);
return;
}
if (strcmp(arg0, "msg") == 0) {
arg1 = strsep(&str, " ");
if (arg1 == NULL || str == NULL)
goto not_enough_params;
- chatter_printf(chatter, "$B[$0msg$B($0%s$B)]$0$/ %s", arg1, str);
- irc_printf(chatter, "PRIVMSG %s :%s\r\n", arg1, str);
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B[$0msg$B($0%s$B)]$0$/ %s",
+ arg1, str);
+ irc_printf(conn, "PRIVMSG %s :%s\r\n", arg1, str);
return;
}
if (strcmp(arg0, "nick") == 0) {
if (str == NULL)
goto not_enough_params;
- irc_printf(chatter, "NICK %s\r\n", str);
+ irc_printf(conn, "NICK %s\r\n", str);
return;
}
if (strcmp(arg0, "part") == 0) {
- if (str == NULL && chatter->irc_channel)
- irc_printf(chatter, "PART %s\r\n", chatter->irc_channel->name);
+ if (str == NULL && channel)
+ irc_printf(conn, "PART %s\r\n", channel->name);
+ else if (str)
+ irc_printf(conn, "PART %s\r\n", str);
else
- irc_printf(chatter, "PART %s\r\n", str);
+ goto not_in_channel;
return;
}
if (strcmp(arg0, "quit") == 0) {
- irc_printf(chatter, "QUIT :%s\r\n", str == NULL ? "&" : str);
+ irc_printf(conn, "QUIT :%s\r\n", str == NULL ? "Quitting" : str);
return;
}
if (strcmp(arg0, "quote") == 0) {
if (str == NULL)
goto not_enough_params;
- irc_printf(chatter, "%s\r\n", str);
+ irc_printf(conn, "%s\r\n", str);
return;
}
if (strcmp(arg0, "whois") == 0) {
if (str == NULL)
goto not_enough_params;
- irc_printf(chatter, "WHOIS %s\r\n", str);
+ irc_printf(conn, "WHOIS %s\r\n", str);
return;
}
- chatter_printf(chatter, "unrecognized command \"$B%s$0\"", arg0);
+ chatter_printf(conn->chatter, conn, NULL,
+ "unrecognized command \"$B%s$0\"",
+ arg0);
return;
not_enough_params:
- chatter_printf(chatter, "$B***$0 Not enough parameters given");
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 Not enough parameters given");
return;
not_in_channel:
- chatter_printf(chatter, "$B*** Cannot send (not in channel)$0");
+ chatter_printf(conn->chatter, conn, NULL,
+ "$B***$0 Cannot send (not in a channel)");
return;
}
-void
-irc_set_active_channel(struct chatter *chatter, char *channame)
+struct irc_channel *
+irc_create_channel(struct irc_connection *conn, char *channame)
{
- if (chatter->irc_channel) {
- if (chatter->irc_channel->nicks)
- xfree(&chatter->irc_channel->nicks);
- xfree(&chatter->irc_channel);
- chatter->irc_channel = NULL;
+ struct irc_channel *channel = NULL;
+ short n;
+
+ for (n = 0; n < conn->nchannels; n++) {
+ channel = &conn->channels[n];
+
+ if (strcasecmp(channel->name, channame) == 0) {
+ channel->chatter->cur_conn = channel->connection;
+ channel->chatter->cur_channel = channel;
+ chatter_sync_nick_list(channel->chatter, channel, false);
+ chatter_update_titlebar(channel->chatter);
+ return channel;
+ }
}
- if (channame == NULL)
- chatter_sync_nick_list(chatter, false);
- else {
- chatter->irc_channel = xmalloczero(sizeof(struct irc_channel),
- "channel");
- strlcpy(chatter->irc_channel->name, channame,
- sizeof(chatter->irc_channel->name));
+ conn->nchannels++;
+ conn->channels = xreallocarray(conn->channels, conn->nchannels,
+ sizeof(struct irc_channel));
+ channel = &conn->channels[conn->nchannels - 1];
+ memset(channel, 0, sizeof(struct irc_channel));
+
+ channel->connection = conn;
+ strlcpy(channel->name, channame, sizeof(channel->name));
+ channel->chatter = chatter_add_channel(channel);
+
+ return channel;
+}
+
+void
+irc_dealloc_channel(struct irc_channel *channel)
+{
+ struct irc_connection *conn = channel->connection;
+ struct chatter *chatter = channel->chatter;
+ short n;
+
+ chatter_remove_channel(chatter, channel);
+
+ if (channel->nicks)
+ xfree(&channel->nicks);
+
+ chatter->cur_channel = NULL;
+
+ if (conn->nchannels == 1) {
+ conn->nchannels = 0;
+ xfree(&conn->channels);
+ } else {
+ for (n = 0; n < conn->nchannels; n++) {
+ if (channel != &conn->channels[n])
+ continue;
+
+ if (n == conn->nchannels - 1) {
+ /* just lop it off */
+ } else {
+ /* move the channel at the last place to here */
+ memcpy(&conn->channels[n],
+ &conn->channels[conn->nchannels - 1],
+ sizeof(struct irc_channel));
+ }
+ break;
+ }
+ conn->nchannels--;
+
+ xreallocarray(conn->channels, conn->nchannels,
+ sizeof(struct irc_channel));
+ chatter->cur_channel = &conn->channels[0];
}
chatter_update_titlebar(chatter);
}
void
-irc_parse_names(struct chatter *chatter, char *line)
+irc_parse_names(struct irc_channel *channel, char *line)
{
size_t n;
char *nick;
bool last = false;
short flags;
- if (!chatter->irc_channel)
- return;
-
- LDoDraw(false, chatter->nick_list);
+ LDoDraw(false, channel->chatter->nick_list);
for (;;) {
nick = strsep(&line, " ");
@@ -858,58 +1027,56 @@ irc_parse_names(struct chatter *chatter, char *line)
} else
flags = 0;
- irc_add_nick_to_channel(chatter, nick, flags);
+ irc_add_nick_to_channel(channel, nick, flags);
if (line == NULL)
break;
}
- LDoDraw(true, chatter->nick_list);
- InvalRect(&(*(chatter->nick_list))->rView);
+ LDoDraw(true, channel->chatter->nick_list);
+ InvalRect(&(*(channel->chatter->nick_list))->rView);
}
void
-irc_add_nick_to_channel(struct chatter *chatter, char *nick, short flags)
+irc_add_nick_to_channel(struct irc_channel *channel, char *nick,
+ short flags)
{
struct irc_channel_nick *anick, *cnick, *pnick;
short aidx, cidx, ret;
- if (chatter->irc_channel->nnicks >= chatter->irc_channel->nicks_size) {
+ if (channel->nnicks >= channel->nicks_size) {
/* allocate a chunk at a time so we don't do this every iteration */
- chatter->irc_channel->nicks_size += 5;
- chatter->irc_channel->nicks =
- xreallocarray(chatter->irc_channel->nicks,
+ channel->nicks_size += 5;
+ channel->nicks = xreallocarray(channel->nicks,
sizeof(struct irc_channel_nick),
- chatter->irc_channel->nicks_size);
- memset(&chatter->irc_channel->nicks[chatter->irc_channel->nnicks],
- 0,
+ channel->nicks_size);
+ memset(&channel->nicks[channel->nnicks], 0,
sizeof(struct irc_channel_nick) *
- (chatter->irc_channel->nicks_size - chatter->irc_channel->nnicks));
- aidx = chatter->irc_channel->nnicks;
+ (channel->nicks_size - channel->nnicks));
+ aidx = channel->nnicks;
} else {
/* find an open slot */
- for (aidx = 0; aidx < chatter->irc_channel->nicks_size; aidx++) {
- if (chatter->irc_channel->nicks[aidx].nick[0] == '\0')
+ for (aidx = 0; aidx < channel->nicks_size; aidx++) {
+ if (channel->nicks[aidx].nick[0] == '\0')
break;
}
- if (aidx >= chatter->irc_channel->nicks_size)
+ if (aidx >= channel->nicks_size)
panic("irc_add_nick_to_channel overflow");
}
- chatter->irc_channel->nnicks++;
- anick = &chatter->irc_channel->nicks[aidx];
+ channel->nnicks++;
+ anick = &channel->nicks[aidx];
strlcpy(anick->nick, nick, sizeof(anick->nick));
anick->flags = flags;
- if (chatter->irc_channel->nnicks == 1) {
+ if (channel->nnicks == 1) {
anick->next_nick = -1;
- chatter->irc_channel->first_nick = 0;
+ channel->first_nick = 0;
cidx = 0;
} else {
/* sort it in the right place by flags descending, then by nick */
- cnick = &chatter->irc_channel->nicks[
- chatter->irc_channel->first_nick];
+ cnick = &channel->nicks[channel->first_nick];
pnick = NULL;
cidx = 0;
while (cnick) {
@@ -928,8 +1095,8 @@ irc_add_nick_to_channel(struct chatter *chatter, char
anick->next_nick = pnick->next_nick;
pnick->next_nick = aidx;
} else {
- anick->next_nick = chatter->irc_channel->first_nick;
- chatter->irc_channel->first_nick = aidx;
+ anick->next_nick = channel->first_nick;
+ channel->first_nick = aidx;
}
break;
}
@@ -944,24 +1111,24 @@ irc_add_nick_to_channel(struct chatter *chatter, char
}
pnick = cnick;
- cnick = &chatter->irc_channel->nicks[cnick->next_nick];
+ cnick = &channel->nicks[cnick->next_nick];
}
}
- chatter_insert_to_nick_list(chatter, anick, cidx);
+ chatter_insert_to_nick_list(channel->chatter, channel, anick, cidx);
}
void
-irc_remove_nick_from_channel(struct chatter *chatter, char *nick)
+irc_remove_nick_from_channel(struct irc_channel *channel, char *nick)
{
struct irc_channel_nick *cnick, *pnick;
short cidx;
- if (chatter->irc_channel->first_nick == -1)
+ if (channel->first_nick == -1)
return;
pnick = NULL;
- cnick = &chatter->irc_channel->nicks[chatter->irc_channel->first_nick];
+ cnick = &channel->nicks[channel->first_nick];
cidx = 0;
while (cnick) {
if (strcmp(cnick->nick, nick) != 0) {
@@ -969,7 +1136,7 @@ irc_remove_nick_from_channel(struct chatter *chatter,
cidx++;
if (cnick->next_nick == -1)
return;
- cnick = &chatter->irc_channel->nicks[cnick->next_nick];
+ cnick = &channel->nicks[cnick->next_nick];
continue;
}
@@ -977,26 +1144,48 @@ irc_remove_nick_from_channel(struct chatter *chatter,
if (pnick)
pnick->next_nick = cnick->next_nick;
else
- chatter->irc_channel->first_nick = cnick->next_nick;
+ channel->first_nick = cnick->next_nick;
- chatter->irc_channel->nnicks--;
+ channel->nnicks--;
cnick->nick[0] = '\0';
- LDelRow(1, cidx, chatter->nick_list);
+ LDelRow(1, cidx, channel->chatter->nick_list);
return;
}
}
+bool
+irc_nick_is_in_channel(struct irc_channel *channel, char *nick)
+{
+ struct irc_channel_nick *cnick, *pnick;
+
+ if (channel->first_nick == -1)
+ return;
+
+ pnick = NULL;
+ cnick = &channel->nicks[channel->first_nick];
+ while (cnick) {
+ if (strcmp(cnick->nick, nick) == 0)
+ return true;
+
+ pnick = cnick;
+ if (cnick->next_nick == -1)
+ break;
+ cnick = &channel->nicks[cnick->next_nick];
+ }
+
+ return false;
+}
+
void
-irc_change_user_nick(struct chatter *chatter, struct irc_user *user,
+irc_change_user_nick(struct irc_channel *channel, struct irc_user *user,
char *nick)
{
struct irc_channel_nick *cnick;
short n, flags;
- if (chatter->irc_channel && chatter->irc_channel->first_nick > -1) {
+ if (channel && channel->first_nick > -1) {
/* preserve flags */
- cnick = &chatter->irc_channel->nicks[
- chatter->irc_channel->first_nick];
+ cnick = &channel->nicks[channel->first_nick];
while (cnick) {
if (strcmp(cnick->nick, user->nick) == 0) {
flags = cnick->flags;
@@ -1004,22 +1193,22 @@ irc_change_user_nick(struct chatter *chatter, struct i
}
if (cnick->next_nick == -1)
break;
- cnick = &chatter->irc_channel->nicks[cnick->next_nick];
+ cnick = &channel->nicks[cnick->next_nick];
}
- irc_remove_nick_from_channel(chatter, user->nick);
- irc_add_nick_to_channel(chatter, nick, flags);
+ irc_remove_nick_from_channel(channel, user->nick);
+ irc_add_nick_to_channel(channel, nick, flags);
}
- if (strcmp(chatter->irc_nick, user->nick) == 0) {
- xfree(&chatter->irc_nick);
- chatter->irc_nick = xstrdup(nick, "nick");
- chatter_update_titlebar(chatter);
+ if (strcmp(channel->connection->nick, user->nick) == 0) {
+ xfree(&channel->connection->nick);
+ channel->connection->nick = xstrdup(nick, "nick");
+ chatter_update_titlebar(channel->chatter);
}
}
void
-irc_parse_channel_mode_change(struct chatter *chatter, char *mode,
+irc_parse_channel_mode_change(struct irc_channel *channel, char *mode,
char *args)
{
size_t len;
@@ -1045,13 +1234,12 @@ irc_parse_channel_mode_change(struct chatter *chatter,
if (user == NULL)
user = args;
- cnick = &chatter->irc_channel->nicks[
- chatter->irc_channel->first_nick];
+ cnick = &channel->nicks[channel->first_nick];
while (cnick) {
if (strcmp(cnick->nick, user) != 0) {
if (cnick->next_nick == -1)
break;
- cnick = &chatter->irc_channel->nicks[cnick->next_nick];
+ cnick = &channel->nicks[cnick->next_nick];
continue;
}
@@ -1068,9 +1256,9 @@ irc_parse_channel_mode_change(struct chatter *chatter,
flags &= ~IRC_NICK_FLAG_VOICE;
}
- irc_remove_nick_from_channel(chatter, cnick->nick);
+ irc_remove_nick_from_channel(channel, cnick->nick);
/* cnick is probably invalid now */
- irc_add_nick_to_channel(chatter, user, flags);
+ irc_add_nick_to_channel(channel, user, flags);
break;
}
--- irc.h Tue Sep 6 12:23:57 2022
+++ irc.h Sun Dec 11 16:33:59 2022
@@ -17,6 +17,9 @@
#ifndef __IRC_H__
#define __IRC_H__
+#include "chatter.h"
+#include "tcp.h"
+
enum {
IRC_STATE_UNINITED = 0,
IRC_STATE_DISCONNECTED,
@@ -51,6 +54,8 @@ struct irc_channel_nick {
struct irc_channel {
char name[64];
+ struct chatter *chatter;
+ struct irc_connection *connection;
struct irc_channel_nick *nicks;
size_t nnicks;
size_t nicks_size;
@@ -58,9 +63,40 @@ struct irc_channel {
char topic[400];
};
-void irc_process(struct chatter *chatter);
-void irc_abort(struct chatter *chatter);
-void irc_close(struct chatter *chatter);
-void irc_process_input(struct chatter *chatter, char *input);
+struct irc_connection {
+ short state;
+ struct chatter *chatter;
+ char *hostname;
+ short port;
+ char *password;
+ char *nick;
+ char *ident;
+ char *realname;
+ char *channel_autojoin;
+ bool did_autojoin;
+ struct irc_channel *channels;
+ short nchannels;
+ TCPiopb rcv_pb, send_pb, close_pb;
+ TCPStatusPB status_pb;
+ StreamPtr stream;
+ wdsEntry wds[2];
+ char obuf[512];
+ char ibuf[512]; /* RFC2812 says max line will be 512 */
+ char line[512];
+ short ibuflen;
+ short linelen;
+ /* docs say 4*MTU+1024, but MTU will probably be <1500 */
+ unsigned char tcp_buf[(4 * 1500) + 1024];
+};
+
+bool irc_process(struct irc_connection *conn);
+void irc_abort(struct irc_connection *conn);
+void irc_close(struct irc_connection *conn);
+void irc_process_input(struct irc_connection *conn,
+ struct irc_channel *channel, char *input);
+void irc_dealloc_connection(struct irc_connection *conn);
+
+short strcasecmp(const char *s1, const char *s2);
+short strncasecmp(const char *s1, const char *s2, size_t n);
#endif
--- main.c Thu Dec 1 13:53:21 2022
+++ main.c Fri Dec 2 15:44:51 2022
@@ -233,6 +233,7 @@ short
show_connect_dialog(void)
{
Str255 txt, server, ports, nick, ident, realname, channel, password;
+ struct chatter *chatter;
StringHandle h;
DialogTHndl dlgh;
DialogPtr dlg;
@@ -383,8 +384,9 @@ verify:
DisposeDialog(dlg);
ReleaseResource(dlgh);
- chatter_init((char *)&server, port, (char *)&password, (char *)&nick,
- (char *)&ident, (char *)&realname, (char *)&channel);
+ chatter = chatter_init();
+ chatter_connect(chatter, (char *)&server, port, (char *)&password,
+ (char *)&nick, (char *)&ident, (char *)&realname, (char *)&channel);
}
bool
--- tcp.c Tue Sep 6 12:24:08 2022
+++ tcp.c Fri Dec 2 16:05:38 2022
@@ -392,7 +392,7 @@ StrToAddrMarkDone(struct hostInfo *hi, char *data)
}
OSErr
-TCPResolveName(char **name, unsigned long *ipAddress)
+TCPResolveName(char *name, unsigned long *ipAddress)
{
OSErr osErr;
struct hostInfo aHostInfo;
@@ -402,7 +402,7 @@ TCPResolveName(char **name, unsigned long *ipAddress)
if (osErr)
return osErr;
- osErr = StrToAddr(*name, &aHostInfo, (ResultProcPtr)StrToAddrMarkDone,
+ osErr = StrToAddr(name, &aHostInfo, (ResultProcPtr)StrToAddrMarkDone,
(char *)&done);
if (osErr == cacheFault) {
--- tcp.h Tue Sep 6 12:24:11 2022
+++ tcp.h Fri Dec 2 16:06:56 2022
@@ -49,7 +49,7 @@ OSErr _TCPRelease(TCPiopb *pb, StreamPtr stream, Ptr u
OSErr _UDPMaxMTUSize(UDPiopb *pb, short *mtu);
-OSErr TCPResolveName(char **name, unsigned long *ipAddress);
+OSErr TCPResolveName(char *name, unsigned long *ipAddress);
long ip2long(char *ip);
void long2ip(unsigned long num, char *ip);