2 * Copyright (C) 2017 Andy Spencer <andy753421@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41 typedef struct irc_server_t {
56 struct irc_server_t *next;
59 typedef struct irc_channel_t {
64 struct irc_channel_t *next;
68 static irc_server_t *servers;
69 static irc_channel_t *channels;
72 static irc_server_t *find_server(const char *name, int create)
74 irc_server_t *cur = NULL, *last = NULL;
75 for (cur = servers; cur; last = cur, cur = cur->next)
76 if (match(cur->name, name))
79 cur = new0(irc_server_t);
80 cur->name = get_name(name);
89 static irc_channel_t *find_channel(const char *name, int create)
91 irc_channel_t *cur = NULL, *last = NULL;
92 for (cur = channels; cur; last = cur, cur = cur->next)
93 if (match(cur->name, name))
96 cur = new0(irc_channel_t);
97 cur->name = get_name(name);
106 static void recv_line(irc_server_t *srv, const char *line)
108 static char src[IRC_LINE]; // (:([^ ]+) +)?
109 static char cmd[IRC_LINE]; // (([A-Z0-9]+) +)
110 static char dst[IRC_LINE]; // (([^ ]+)[= ]+)?
111 static char arg[IRC_LINE]; // (([^: ]+) *)?
112 static char msg[IRC_LINE]; // (:(.*))?
113 static char from[IRC_LINE];
116 const char *c = line;
119 src[0] = cmd[0] = dst[0] = arg[0] = msg[0] = from[0] = '\0';
124 for (i = 0; *c && *c != ' '; i++)
129 for (i = 0; src[i] && src[i] != '!' && src[i] != ' '; i++)
135 for (i = 0; isalnum(*c); i++)
142 if ((*c && *c != ' ') &&
143 (strchr(c+1, ' ') || strchr(c+1, '='))) {
144 for (i = 0; *c && *c != ' '; i++)
146 while (*c == '=' || *c == ' ')
152 if (*c && *c != ':' && *c != ' ') {
153 for (i = 0; *c && *c != ' '; i++)
168 debug("got line: %s", line);
169 //debug(" src %s", src);
170 //debug(" cmd %s", cmd);
171 //debug(" dst %s", dst);
172 //debug(" arg %s", arg);
173 //debug(" msg %s", msg);
176 if (match(cmd, "001") || strstr(msg, "Welcome"))
177 srv->state = IRC_JOIN;
178 if (match(cmd, "PING"))
179 net_print(&srv->net, "PING %s\n", msg);
180 if (match(cmd, "PRIVMSG"))
181 chat_recv(dst, from, msg);
184 if (match(cmd, "NOTICE") ||
189 chat_notice(from, NULL, "%s", msg);
192 static void on_recv(void *_srv, char *buf, int len)
194 irc_server_t *srv = _srv;
197 for (int i = 0; i < len; i++) {
198 if (srv->pos < IRC_LINE) {
199 srv->line[srv->pos] = buf[i];
202 if (buf[i] == '\n' || buf[i] == '\r') {
203 srv->line[srv->pos-1] = '\0';
205 recv_line(srv, srv->line);
211 if (srv->state == IRC_USER) {
212 if (net_print(&srv->net, "USER %s %s %s :%s\n",
213 getenv("USER") ?: "lameuser",
214 get_hostname(), srv->host, srv->nick))
215 srv->state = IRC_NICK;
217 if (srv->state == IRC_NICK) {
218 if (net_print(&srv->net, "NICK %s\n", srv->nick))
219 srv->state = IRC_READY;
221 if (srv->state == IRC_JOIN) {
222 for (irc_channel_t *chan = channels; chan; chan = chan->next)
224 net_print(&srv->net, "JOIN %s\n", chan->channel);
225 srv->state = IRC_READY;
229 static void irc_connect(irc_server_t *srv)
232 srv->net.recv = on_recv;
234 net_open(&srv->net, srv->host, srv->port);
237 srv->state = IRC_USER;
243 for (irc_server_t *cur = servers; cur; cur = cur->next) {
244 if (!match(cur->protocol, "irc"))
249 cur->nick = strcopy(getenv("USER"));
251 cur->nick = strcopy("lameuser");
257 void irc_config(const char *group, const char *name, const char *key, const char *value)
262 if (match(group, "server")) {
263 srv = find_server(name, 1);
264 if (match(key, "protocol") &&
266 srv->protocol = get_string(value);
267 if (match(srv->protocol, "irc")) {
268 if (match(key, "connect"))
269 srv->connect = get_bool(value);
270 else if (match(key, "host"))
271 srv->host = get_string(value);
272 else if (match(key, "port"))
273 srv->port = get_number(value);
274 else if (match(key, "nick"))
275 srv->nick = get_string(value);
276 else if (match(key, "auth"))
277 srv->auth = get_string(value);
278 else if (match(key, "pass"))
279 srv->pass = get_string(value);
281 } else if (match(group, "channel")) {
282 chan = find_channel(name, 1);
283 if (match(key, "server") &&
284 find_server(value, 0))
285 chan->server = get_string(value);
287 if (match(key, "channel"))
288 chan->channel = get_string(value);
289 else if (match(key, "join"))
290 chan->join = get_bool(value);
295 void irc_send(const char *channel, const char *msg)
297 irc_channel_t *chan = find_channel(channel, 0);
300 irc_server_t *srv = find_server(chan->server, 0);
303 net_print(&srv->net, "PRIVMSG %s :%s\n", chan->channel, msg);