aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Murphy <alec@checksum.fail>2019-09-30 14:37:23 -0400
committerAlec Murphy <alec@checksum.fail>2019-09-30 14:37:23 -0400
commit8c13bc31adec38de0a4752791054c7301c80fe1b (patch)
tree32192878fa18916e1caa2d95a8db6ef3022884c6
parenteba0f00d965464e4153fdef15a1563c5a7fd5bb9 (diff)
Add files to repository
-rw-r--r--.gitignore2
-rw-r--r--Arg.HC62
-rw-r--r--Channel.HC327
-rw-r--r--Client.HC468
-rw-r--r--Command.HC237
-rw-r--r--Gihon.HC53
-rw-r--r--Motd.HC38
-rw-r--r--Motd.TXT2
-rw-r--r--README.md6
-rw-r--r--Service.HC7
-rw-r--r--preview.pngbin0 -> 35019 bytes
11 files changed, 1202 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e89346a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+uncrustify.cfg
+.vscode/
diff --git a/Arg.HC b/Arg.HC
new file mode 100644
index 0000000..ed99c0a
--- /dev/null
+++ b/Arg.HC
@@ -0,0 +1,62 @@
+U0 FreeArgs(I64 argc, U8 **argv)
+{
+ I64 i;
+ for (i = 0; i < argc; i++)
+ {
+ Free(argv[i]);
+ }
+ if (argv)
+ {
+ Free(argv);
+ }
+}
+
+U8 **ParseArgs(U8 *str, I64 *argc)
+{ // Return argc, argv from str.
+ Bool quoted = FALSE;
+ I64 _argc = 0;
+ U8 **_argv = NULL;
+ U8 **_tmp = CAlloc(sizeof(U64) * StrLen(str));
+ I64 i = 0;
+ I64 s = 0;
+ I64 len;
+ while (i < StrLen(str) + 1)
+ {
+ switch (str[i])
+ {
+ case 0:
+ case ' ':
+ if (!quoted)
+ {
+ len = (str + i)-(str + s - 1);
+ if (str[i - 1] == '"')
+ {
+ len--;
+ }
+ if (len - 1)
+ {
+ _tmp[_argc] = CAlloc(len);
+ MemCpy(_tmp[_argc], str + s, len-1);
+ _argc++;
+ }
+ s = i + 1;
+ }
+ break;
+ case '"':
+ quoted = !quoted;
+ if (quoted)
+ {
+ s = i + 1;
+ }
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+ *argc = _argc;
+ _argv = CAlloc(sizeof(U64) * _argc);
+ MemCpy(_argv, _tmp, sizeof(U64) * _argc);
+ Free(_tmp);
+ return _argv;
+} \ No newline at end of file
diff --git a/Channel.HC b/Channel.HC
new file mode 100644
index 0000000..78aa812
--- /dev/null
+++ b/Channel.HC
@@ -0,0 +1,327 @@
+U0 IrcChannelAdd(U8 *name)
+{
+ IrcChannel *channel = CAlloc(sizeof(IrcChannel));
+ channel->name = StrNew(name);
+ channel->topic = CAlloc(2048);
+ channel->users = CAlloc(sizeof(IrcUser));
+ IrcChannel *channels = channel_head;
+ while (channels->next)
+ {
+ channels = channels->next;
+ }
+ channel->prev = channels;
+ channels->next = channel;
+ ircd_chans_total++;
+}
+
+U0 IrcChannelDel(IrcChannel *channel)
+{
+ IrcChannel *prev = channel->prev;
+ IrcChannel *next = channel->next;
+ prev->next = next;
+ next->prev = prev;
+ //free ircuser list
+ Free(channel->name);
+ Free(channel);
+ ircd_chans_total--;
+}
+
+IrcChannel *IrcGetChanByName(U8 *channame)
+{
+ IrcChannel *channel = channel_head;
+ while (channel)
+ {
+ if (!StrCmp(channel->name, channame)) return channel;
+ channel = channel->next;
+ }
+ return NULL;
+}
+
+U0 IrcChannelUserAdd(IrcChannel *channel, IrcClient *client, U64 flags=NULL)
+{
+ IrcUser *user = CAlloc(sizeof(IrcUser));
+ IrcUser *users = channel->users;
+ while (users->next)
+ {
+ users = users->next;
+ }
+ user->client = client;
+ user->flags = flags;
+ user->prev = users;
+ users->next = user;
+}
+
+U0 IrcChannelUserDel(IrcChannel *channel, IrcClient *client)
+{
+ IrcUser *users = channel->users->next;
+ IrcUser *prev = NULL;
+ IrcUser *next = NULL;
+ while (users)
+ {
+ if (users->client==client)
+ {
+ prev=users->prev;
+ next=users->next;
+ prev->next = next;
+ next->prev = prev;
+ Free(users);
+ return;
+ }
+ users = users->next;
+ }
+}
+
+U0 IrcChannelTopic(U8 *channame, IrcClient *client, U8 *topic)
+{
+ U8 *buf = CAlloc(2048);
+ IrcChannel *channel = IrcGetChanByName(channame);
+ IrcUser *user;
+ IrcUser *users;
+ if (channel)
+ {
+ user = channel->users->next;
+ while (user)
+ {
+ if (user->client==client)
+ {
+ if (user->flags >= IRCD_USERMODE_o)
+ {
+ StrPrint(channel->topic, topic);
+ users = channel->users->next;
+ while (users)
+ {
+ StrPrint(buf, ":%s!%s@%s TOPIC %s :%s\r\n", client->nick, client->username,
+ client->host, channame, channel->topic);
+ FifoI64Ins(users->client->msgs, StrNew(buf));
+ users = users->next;
+ }
+ }
+ else
+ {
+ StrPrint(buf, ":%s 482 %s %s :You do not have access to change the topic on this channel\r\n",
+ ircd_hostname, client->username, channame);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ }
+ Free(buf);
+ return;
+ }
+ user = user->next;
+ }
+ }
+ Free(buf);
+}
+
+U0 IrcChannelJoin(U8 *channame, IrcClient *client)
+{
+ U64 flags = NULL;
+ if (channame[0]==':') channame++; // Fix for Revolution IRC client?
+ IrcChannel *channel = IrcGetChanByName(channame);
+ if (!channel)
+ {
+ IrcChannelAdd(channame);
+ channel = IrcGetChanByName(channame);
+ flags = IRCD_USERMODE_q;
+ }
+ if (channel)
+ {
+ IrcChannelUserAdd(channel, client, flags);
+ IrcClientJoin(channame, client);
+ }
+}
+
+U0 IrcChannelKick(U8 *channame, IrcClient *client, U8 *nick, U8 *reason=NULL)
+{
+ U8 *buf = CAlloc(2048);
+ IrcChannel *channel = IrcGetChanByName(channame);
+ IrcClient *kick_client = IrcGetClientByNick(nick);
+ IrcUser *user;
+ IrcUser *users;
+ if (channel && kick_client)
+ {
+ user = channel->users->next;
+ while (user)
+ {
+ if (user->client==client)
+ {
+ if (user->flags >= IRCD_USERMODE_h)
+ {
+ users = channel->users->next;
+ while (users)
+ {
+ StrPrint(buf, ":%s!%s@%s KICK %s %s :%s\r\n", client->nick, client->username,
+ client->host, channame, nick, reason);
+ FifoI64Ins(users->client->msgs, StrNew(buf));
+ users = users->next;
+ }
+ IrcChannelUserDel(channel, kick_client);
+ }
+ else
+ {
+ StrPrint(buf, ":%s 482 %s %s :You must be a channel half-operator\r\n",
+ ircd_hostname, client->username, channame);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ }
+ Free(buf);
+ return;
+ }
+ user = user->next;
+ }
+ }
+ Free(buf);
+}
+
+U0 IrcChannelMode(U8 *channame, IrcClient *client, U8 *mode, U8 *nick=NULL)
+{
+ U64 res = 0;
+ Bool set = FALSE;
+ U8 *buf = CAlloc(2048);
+ IrcChannel *channel = IrcGetChanByName(channame);
+ IrcClient *mode_client = NULL;
+ IrcUser *user;
+ IrcUser *users;
+ if (nick)
+ { // Set user mode
+ mode_client = IrcGetClientByNick(nick);
+ if (!mode_client)
+ {
+ // nick does not exist?
+ Free(buf);
+ return;
+ }
+ else
+ {
+ user = channel->users->next;
+ while (user)
+ {
+ if (user->client==client)
+ {
+ if ((!StrCmp("-v", mode) || !StrCmp("+v", mode)))
+ {
+ set = TRUE;
+ if (user->flags < IRCD_USERMODE_h)
+ {
+ res = IRCD_USERMODE_h;
+ }
+ }
+ if ((!StrCmp("-h", mode) || !StrCmp("+h", mode)))
+ {
+ set = TRUE;
+ if (user->flags < IRCD_USERMODE_o)
+ {
+ res = IRCD_USERMODE_o;
+ }
+ }
+ if ((!StrCmp("-o", mode) || !StrCmp("+o", mode)))
+ {
+ set = TRUE;
+ if (user->flags < IRCD_USERMODE_q)
+ {
+ res = IRCD_USERMODE_q;
+ }
+ }
+
+ if (set)
+ {
+ if (!res)
+ {
+ users = channel->users->next;
+ while (users)
+ {
+ if (users->client==mode_client)
+ {
+ if (mode[0]=='-')
+ {
+ if (user->flags > users->flags)
+ {
+ users->flags = NULL;
+ }
+ }
+ if (mode[0]=='+')
+ {
+ switch (mode[1])
+ {
+ case 'v':
+ users->flags = Max(users->flags, IRCD_USERMODE_v);
+ break;
+ case 'h':
+ users->flags = Max(users->flags, IRCD_USERMODE_h);
+ break;
+ case 'o':
+ users->flags = Max(users->flags, IRCD_USERMODE_o);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ StrPrint(buf, ":%s!%s@%s MODE %s %s %s\r\n", client->nick, client->username,
+ client->host, channame, mode, nick);
+ FifoI64Ins(users->client->msgs, StrNew(buf));
+ users = users->next;
+ }
+ }
+ else
+ {
+ switch (res)
+ {
+ case IRCD_USERMODE_h:
+ StrPrint(buf, ":%s 482 %s %s :You must have channel halfop access or above to set channel mode #\r\n",
+ ircd_hostname, client->username, channame);
+ buf[StrLen(buf)-3] = mode[1];
+ FifoI64Ins(client->msgs, StrNew(buf));
+ break;
+ case IRCD_USERMODE_o:
+ StrPrint(buf, ":%s 482 %s %s :You must have channel op access or above to set channel mode #\r\n",
+ ircd_hostname, client->username, channame);
+ buf[StrLen(buf)-3] = mode[1];
+ FifoI64Ins(client->msgs, StrNew(buf));
+ break;
+ case IRCD_USERMODE_q:
+ StrPrint(buf, ":%s 482 %s %s :You must be the channel owner to set channel mode #\r\n",
+ ircd_hostname, client->username, channame);
+ buf[StrLen(buf)-3] = mode[1];
+ FifoI64Ins(client->msgs, StrNew(buf));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ Free(buf);
+ return;
+ }
+ user = user->next;
+ }
+ }
+ }
+ else
+ { // TODO: Set channel mode
+ if (channel)
+ {
+
+ }
+
+ }
+ Free(buf);
+}
+
+U0 IrcChannelPart(U8 *channame, IrcClient *client, U8 *msg=NULL)
+{
+ IrcChannel *channel = IrcGetChanByName(channame);
+ if (channel)
+ {
+ IrcChannelUserDel(channel, client);
+ IrcClientPart(channame, client, msg);
+ }
+}
+
+U0 IrcChannelsQuit(IrcClient *client, U8 *msg=NULL)
+{
+ IrcChannel *channel = channel_head->next;
+ while (channel)
+ {
+ IrcChannelUserDel(channel, client);
+ IrcClientQuit(channel->name, client, msg);
+ channel = channel->next;
+ }
+} \ No newline at end of file
diff --git a/Client.HC b/Client.HC
new file mode 100644
index 0000000..bc8d561
--- /dev/null
+++ b/Client.HC
@@ -0,0 +1,468 @@
+#define IRCD_USERMODE_v 0x1
+#define IRCD_USERMODE_h 0x2
+#define IRCD_USERMODE_o 0x4
+#define IRCD_USERMODE_a 0x8
+#define IRCD_USERMODE_q 0x10
+
+class IrcClient
+{
+IrcClient *prev;
+IrcClient *next;
+CTcpSocket *s;
+U8 *nick;
+U8 *username;
+U8 *realname;
+U8 *server;
+U8 *host;
+U32 ip;
+U8 *vhost;
+CFifoI64 *msgs;
+I64 idle;
+I64 limit;
+Bool disconnected;
+};
+
+class IrcUser
+{
+IrcUser *prev;
+IrcUser *next;
+IrcClient *client;
+U64 flags;
+};
+
+class IrcChannel
+{
+IrcChannel *prev;
+IrcChannel *next;
+U8 *name;
+U8 *topic;
+IrcUser *users;
+};
+
+extern U0 IrcParseCommand(IrcClient *client, U8 *str);
+extern U0 IrcChannelsQuit(IrcClient *client, U8 *msg=NULL);
+
+IrcClient *client_head = CAlloc(sizeof(IrcClient));
+IrcChannel *channel_head = CAlloc(sizeof(IrcChannel));
+
+U0 IrcClientAdd(IrcClient *client)
+{
+ IrcClient *clients = client_head;
+ while (clients->next)
+ {
+ clients = clients->next;
+ }
+ client->prev = clients;
+ clients->next = client;
+ ircd_clients_total++;
+}
+
+U0 IrcClientDel(IrcClient *client)
+{
+ IrcClient *prev = client->prev;
+ IrcClient *next = client->next;
+ prev->next = next;
+ next->prev = prev;
+ FifoI64Del(client->msgs);
+ Free(client);
+ ircd_clients_total--;
+}
+
+IrcClient *IrcGetClientByNick(U8 *nick)
+{
+ IrcClient *client = client_head->next;
+ while (client)
+ {
+ if (!StrCmp(client->nick, nick)) return client;
+ client = client->next;
+ }
+ return NULL;
+}
+
+U0 IrcClientSetNick(IrcClient *client, U8 *nick)
+{
+ I64 i;
+ U8 *buf = CAlloc(2048);
+ IrcClient *chk_client = client_head->next;
+
+ // check if in use, owned, forbidden, etc..
+ while (chk_client)
+ {
+ if (!StrICmp(chk_client->nick, nick))
+ {
+ StrPrint(buf, ":%s 433 %s %s :Nickname is already in use.\r\n", ircd_hostname, client->username,
+ nick);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(buf);
+ return;
+ }
+ chk_client = chk_client->next;
+ }
+ for (i=0; i<service_cnt; i++)
+ {
+ if (!StrICmp(service_nick[i], nick))
+ {
+ StrPrint(buf, ":%s 432 %s %s :Invalid nickname: Reserved for Services\r\n", ircd_hostname, client->username,
+ nick);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(buf);
+ return;
+ }
+ }
+
+ client->nick = StrNew(nick);
+ AdamLog("** Gihon - log: nick: %s\n", client->nick);
+ Free(buf);
+}
+
+U0 IrcClientSetUser(IrcClient *client, U8 *username, U8 *host, U8 *server, U8 *realname)
+{
+ // check user params
+ client->username = StrNew(username);
+ client->host = StrNew(host);
+ client->realname = StrNew(realname);
+ client->server = StrNew(server);
+ AdamLog("** Gihon - log: username: %s, host: %s, realname: %s\n", client->username, client->host, client->realname);
+}
+
+U0 IrcClientMotd(IrcClient *client)
+{
+ I64 i;
+ U8 *buf = CAlloc(2048);
+ StrPrint(buf, ":%s 375 %s :-\r\n", ircd_hostname, client->username);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ for (i=0; i<motd_line_cnt; i++)
+ {
+ StrPrint(buf, ":%s 372 %s :%s\r\n", ircd_hostname, client->username, motd_lines[i]);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ }
+ StrPrint(buf, ":%s 376 %s :>\r\n", ircd_hostname, client->username);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(buf);
+}
+
+U0 IrcClientNotice(IrcClient *client, U8 *msg)
+{
+ U8 *buf = CAlloc(2048);
+ StrPrint(buf, ":%s NOTICE Auth :%s\r\n", ircd_hostname, msg);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(buf);
+}
+
+U0 IrcClientJoin(U8 *dst, IrcClient *tx_client)
+{
+ U8 *buf = CAlloc(2048);
+ IrcClient *rx_client = client_head->next;
+ IrcChannel *rx_channel = channel_head->next;
+ IrcUser *rx_user;
+ while (rx_channel)
+ {
+ if (!StrCmp(rx_channel->name, dst))
+ { //PRIVMSG to channel
+ rx_user = rx_channel->users->next;
+ while (rx_user)
+ {
+ rx_client = rx_user->client;
+ StrPrint(buf, ":%s!%s@%s JOIN :%s\r\n", tx_client->nick, tx_client->username,
+ tx_client->host, dst);
+ FifoI64Ins(rx_client->msgs, StrNew(buf));
+ rx_user = rx_user->next;
+ }
+ return;
+ }
+ rx_channel = rx_channel->next;
+ }
+ Free(buf);
+}
+
+U0 IrcClientNames(IrcClient *client, U8 *dst)
+{
+ U8 *buf = CAlloc(2048);
+ U8 *mode = CAlloc(16);
+ IrcChannel *channel = channel_head->next;
+ IrcUser *user;
+ StrPrint(buf, ":%s 353 %s = %s :", ircd_hostname, client->username, dst);
+ while (channel)
+ {
+ if (!StrCmp(channel->name, dst))
+ {
+ user = channel->users->next;
+ while (user)
+ {
+ StrPrint(mode, "");
+ if (user->flags & IRCD_USERMODE_q) StrPrint(mode, "@");
+ if (user->flags & IRCD_USERMODE_o) StrPrint(mode, "@");
+ if (user->flags & IRCD_USERMODE_h) StrPrint(mode, "\%");
+ if (user->flags & IRCD_USERMODE_v) StrPrint(mode, "+");
+ StrPrint(buf+StrLen(buf), "%s%s ", mode, user->client->nick);
+ user = user->next;
+ }
+ StrPrint(buf+StrLen(buf), "\r\n");
+ FifoI64Ins(client->msgs, StrNew(buf));
+ StrPrint(buf, ":%s 366 %s %s :End of /NAMES list.\r\n", ircd_hostname, client->username, dst);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(mode);
+ Free(buf);
+ return;
+ }
+ channel = channel->next;
+ }
+ Free(mode);
+ Free(buf);
+}
+
+U0 IrcClientTopic(IrcClient *client, U8 *dst)
+{
+ U8 *buf = CAlloc(2048);
+ IrcChannel *channel = channel_head->next;
+ while (channel)
+ {
+ if (!StrCmp(channel->name, dst))
+ {
+ if (StrLen(channel->topic))
+ {
+ StrPrint(buf, ":%s 332 %s %s :%s\r\n", ircd_hostname, client->username, dst, channel->topic);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ }
+ Free(buf);
+ return;
+ }
+ channel = channel->next;
+ }
+ Free(buf);
+}
+
+U0 IrcClientPart(U8 *dst, IrcClient *tx_client, U8 *msg=NULL)
+{
+ U8 *buf = CAlloc(2048);
+ IrcClient *rx_client = client_head->next;
+ IrcChannel *rx_channel = channel_head->next;
+ IrcUser *rx_user;
+ while (rx_channel)
+ {
+ if (!StrCmp(rx_channel->name, dst))
+ { //PRIVMSG to channel
+ rx_user = rx_channel->users->next;
+ while (rx_user)
+ {
+ rx_client = rx_user->client;
+ if (msg)
+ {
+ StrPrint(buf, ":%s!%s@%s PART %s :%s\r\n", tx_client->nick, tx_client->username,
+ tx_client->host, dst, msg);
+ }
+ else
+ {
+ StrPrint(buf, ":%s!%s@%s PART %s\r\n", tx_client->nick, tx_client->username,
+ tx_client->host, dst);
+ }
+ FifoI64Ins(rx_client->msgs, StrNew(buf));
+ rx_user = rx_user->next;
+ }
+ return;
+ }
+ rx_channel = rx_channel->next;
+ }
+ Free(buf);
+}
+
+U0 IrcClientPing(IrcClient *client, U8 *msg)
+{
+ U8 *buf = CAlloc(2048);
+ StrPrint(buf, ":%s PONG %s :%s\r\n", ircd_hostname, ircd_hostname, msg);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(buf);
+}
+
+U0 IrcClientPrivMsg(IrcClient *tx_client, U8 *dst, U8 *msg)
+{
+ U8 *buf = CAlloc(2048);
+ IrcClient *rx_client = client_head->next;
+ while (rx_client)
+ {
+ if (!StrCmp(rx_client->nick, dst))
+ { //PRIVMSG to nick
+ StrPrint(buf, ":%s!%s@%s PRIVMSG %s :%s\r\n", tx_client->nick, tx_client->username,
+ tx_client->host, dst, msg);
+ FifoI64Ins(rx_client->msgs, StrNew(buf));
+ Free(buf);
+ return;
+ }
+ rx_client = rx_client->next;
+ }
+ IrcChannel *rx_channel = channel_head->next;
+ IrcUser *rx_user;
+ while (rx_channel)
+ {
+ if (!StrCmp(rx_channel->name, dst))
+ { //PRIVMSG to channel
+ rx_user = rx_channel->users->next;
+ while (rx_user)
+ {
+ rx_client = rx_user->client;
+ if (!!StrCmp(rx_client->nick, tx_client->nick))
+ {
+ StrPrint(buf, ":%s!%s@%s PRIVMSG %s :%s\r\n", tx_client->nick, tx_client->username,
+ tx_client->host, dst, msg);
+ FifoI64Ins(rx_client->msgs, StrNew(buf));
+ }
+ rx_user = rx_user->next;
+ }
+ Free(buf);
+ return;
+ }
+ rx_channel = rx_channel->next;
+ }
+ Free(buf);
+}
+
+U0 IrcClientQuit(U8 *dst, IrcClient *tx_client, U8 *msg=NULL)
+{
+ U8 *buf = CAlloc(2048);
+ IrcClient *rx_client = client_head->next;
+ IrcChannel *rx_channel = channel_head->next;
+ IrcUser *rx_user;
+ while (rx_channel)
+ {
+ if (!StrCmp(rx_channel->name, dst))
+ { //PRIVMSG to channel
+ rx_user = rx_channel->users->next;
+ while (rx_user)
+ {
+ rx_client = rx_user->client;
+ if (msg)
+ {
+ StrPrint(buf, ":%s!%s@%s QUIT :%s\r\n", tx_client->nick, tx_client->username,
+ tx_client->host, msg);
+ }
+ else
+ {
+ StrPrint(buf, ":%s!%s@%s QUIT\r\n", tx_client->nick, tx_client->username,
+ tx_client->host);
+ }
+ FifoI64Ins(rx_client->msgs, StrNew(buf));
+ rx_user = rx_user->next;
+ }
+ return;
+ }
+ rx_channel = rx_channel->next;
+ }
+ Free(buf);
+}
+
+U0 IrcClientWho(IrcClient *client, U8 *dst)
+{
+ U8 *buf = CAlloc(2048);
+ IrcChannel *channel = channel_head->next;
+ IrcUser *user;
+ while (channel)
+ {
+ if (!StrCmp(channel->name, dst))
+ {
+ user = channel->users->next;
+ while (user)
+ {
+ StrPrint(buf, ":%s 352 %s %s %s %s * %s H :0 %s\r\n", ircd_hostname, client->username, dst,
+ user->client->username, user->client->host, user->client->nick,
+ user->client->realname);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ user = user->next;
+ }
+ StrPrint(buf, ":%s 315 %s %s :End of /WHO list.\r\n", ircd_hostname, client->username, dst);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ Free(buf);
+ return;
+ }
+ channel = channel->next;
+ }
+ Free(buf);
+}
+
+U0 IrcClientRxHandler(CTcpSocket *s)
+{
+ IrcClient *client = CAlloc(sizeof(IrcClient));
+ client->s = s;
+ client->ip = s->local_addr;
+ client->limit = IRCD_LIMIT_MAX;
+ client->msgs = FifoI64New(IRCD_TXFIFO_SIZE);
+ client->idle = cnts.jiffies;
+ IrcClientAdd(client);
+
+ AdamLog("** Gihon - Client connected: %16X\n", client);
+ IrcClientNotice(client, "Welcome to Gihon IRC Server!");
+ IrcClientNotice(client, "This server is running Gihon, an IRCd for TempleOS");
+ I64 err = NULL;
+ U8 *rxbuf = CAlloc(IRCD_RXBUF_SIZE);
+ while (err > -1)
+ {
+ err = recvLine(s, rxbuf, IRCD_RXBUF_SIZE, 0);
+ //AdamLog(rxbuf);
+ //AdamLog("\n");
+ client->limit--;
+ if (client->limit)
+ {
+ IrcParseCommand(client, rxbuf);
+ }
+ else
+ {
+ IrcChannelsQuit(client, "Excess flood");
+ err = -1;
+ }
+ }
+ client->disconnected = TRUE;
+ close(client->s);
+ Free(rxbuf);
+ AdamLog("** Gihon - Client disconnected: %16X\n", client);
+}
+
+U0 IrcClientTxHandler()
+{
+ I64 sec = NULL;
+ CDateStruct ds;
+ U8 *buf = CAlloc(2048);
+ I64 msg = NULL;
+ IrcClient *client;
+ while (1)
+ {
+ client = client_head->next;
+ while (client)
+ {
+ if (client->disconnected)
+ {
+ IrcClientDel(client);
+ client = client_head;
+ }
+ client = client->next;
+ }
+
+ if (sec != ds.sec)
+ {
+ client = client_head->next;
+ while (client)
+ {
+ client->limit = Min(IRCD_LIMIT_MAX, client->limit+1);
+ client = client->next;
+ }
+ sec = ds.sec;
+ }
+
+ client = client_head->next;
+ while (client)
+ {
+ if (client->idle+IRCD_PING_INTERVAL == cnts.jiffies)
+ {
+ StrPrint(buf, "PING :%s\r\n", ircd_hostname);
+ FifoI64Ins(client->msgs, StrNew(buf));
+ }
+ while (FifoI64Cnt(client->msgs))
+ {
+ FifoI64Rem(client->msgs, &msg);
+ sendString(client->s, msg, 0);
+ Free(msg);
+ }
+ client = client->next;
+ }
+ Date2Struct(&ds, Now);
+ Sleep(1);
+ }
+} \ No newline at end of file
diff --git a/Command.HC b/Command.HC
new file mode 100644
index 0000000..e4b6788
--- /dev/null
+++ b/Command.HC
@@ -0,0 +1,237 @@
+#define IRCD_CMD_ADMIN 0
+#define IRCD_CMD_AWAY 1
+#define IRCD_CMD_CNOTICE 2
+#define IRCD_CMD_CPRIVMSG 3
+#define IRCD_CMD_CONNECT 4
+#define IRCD_CMD_DIE 5
+#define IRCD_CMD_ENCAP 6
+#define IRCD_CMD_ERROR 7
+#define IRCD_CMD_HELP 8
+#define IRCD_CMD_INFO 9
+#define IRCD_CMD_INVITE 10
+#define IRCD_CMD_ISON 11
+#define IRCD_CMD_JOIN 12
+#define IRCD_CMD_KICK 13
+#define IRCD_CMD_KILL 14
+#define IRCD_CMD_KNOCK 15
+#define IRCD_CMD_LINKS 16
+#define IRCD_CMD_LIST 17
+#define IRCD_CMD_LUSERS 18
+#define IRCD_CMD_MODE 19
+#define IRCD_CMD_MOTD 20
+#define IRCD_CMD_NAMES 21
+#define IRCD_CMD_NAMESX 22
+#define IRCD_CMD_NICK 23
+#define IRCD_CMD_NOTICE 24
+#define IRCD_CMD_OPER 25
+#define IRCD_CMD_PART 26
+#define IRCD_CMD_PASS 27
+#define IRCD_CMD_PING 28
+#define IRCD_CMD_PONG 29
+#define IRCD_CMD_PRIVMSG 30
+#define IRCD_CMD_QUIT 31
+#define IRCD_CMD_REHASH 32
+#define IRCD_CMD_RESTART 33
+#define IRCD_CMD_RULES 34
+#define IRCD_CMD_SERVER 35
+#define IRCD_CMD_SERVICE 36
+#define IRCD_CMD_SERVLIST 37
+#define IRCD_CMD_SQUERY 38
+#define IRCD_CMD_SQUIT 39
+#define IRCD_CMD_SETNAME 40
+#define IRCD_CMD_SILENCE 41
+#define IRCD_CMD_STATS 42
+#define IRCD_CMD_SUMMON 43
+#define IRCD_CMD_TIME 44
+#define IRCD_CMD_TOPIC 45
+#define IRCD_CMD_TRACE 46
+#define IRCD_CMD_UHNAMES 47
+#define IRCD_CMD_USER 48
+#define IRCD_CMD_USERHOST 49
+#define IRCD_CMD_USERIP 50
+#define IRCD_CMD_USERS 51
+#define IRCD_CMD_VERSION 52
+#define IRCD_CMD_WALLOPS 53
+#define IRCD_CMD_WATCH 54
+#define IRCD_CMD_WHO 55
+#define IRCD_CMD_WHOIS 56
+#define IRCD_CMD_WHOWAS 57
+
+#define IRCD_CMDS_MAX 58
+
+U8 **ircd_commands = CAlloc(sizeof(U64) * IRCD_CMDS_MAX);
+
+ircd_commands[IRCD_CMD_ADMIN] = "ADMIN";
+ircd_commands[IRCD_CMD_AWAY] = "AWAY";
+ircd_commands[IRCD_CMD_CNOTICE] = "CNOTICE";
+ircd_commands[IRCD_CMD_CPRIVMSG] = "CPRIVMSG";
+ircd_commands[IRCD_CMD_CONNECT] = "CONNECT";
+ircd_commands[IRCD_CMD_DIE] = "DIE";
+ircd_commands[IRCD_CMD_ENCAP] = "ENCAP";
+ircd_commands[IRCD_CMD_ERROR] = "ERROR";
+ircd_commands[IRCD_CMD_HELP] = "HELP";
+ircd_commands[IRCD_CMD_INFO] = "INFO";
+ircd_commands[IRCD_CMD_INVITE] = "INVITE";
+ircd_commands[IRCD_CMD_ISON] = "ISON";
+ircd_commands[IRCD_CMD_JOIN] = "JOIN";
+ircd_commands[IRCD_CMD_KICK] = "KICK";
+ircd_commands[IRCD_CMD_KILL] = "KILL";
+ircd_commands[IRCD_CMD_KNOCK] = "KNOCK";
+ircd_commands[IRCD_CMD_LINKS] = "LINKS";
+ircd_commands[IRCD_CMD_LIST] = "LIST";
+ircd_commands[IRCD_CMD_LUSERS] = "LUSERS";
+ircd_commands[IRCD_CMD_MODE] = "MODE";
+ircd_commands[IRCD_CMD_MOTD] = "MOTD";
+ircd_commands[IRCD_CMD_NAMES] = "NAMES";
+ircd_commands[IRCD_CMD_NAMESX] = "NAMESX";
+ircd_commands[IRCD_CMD_NICK] = "NICK";
+ircd_commands[IRCD_CMD_NOTICE] = "NOTICE";
+ircd_commands[IRCD_CMD_OPER] = "OPER";
+ircd_commands[IRCD_CMD_PART] = "PART";
+ircd_commands[IRCD_CMD_PASS] = "PASS";
+ircd_commands[IRCD_CMD_PING] = "PING";
+ircd_commands[IRCD_CMD_PONG] = "PONG";
+ircd_commands[IRCD_CMD_PRIVMSG] = "PRIVMSG";
+ircd_commands[IRCD_CMD_QUIT] = "QUIT";
+ircd_commands[IRCD_CMD_REHASH] = "REHASH";
+ircd_commands[IRCD_CMD_RESTART] = "RESTART";
+ircd_commands[IRCD_CMD_RULES] = "RULES";
+ircd_commands[IRCD_CMD_SERVER] = "SERVER";
+ircd_commands[IRCD_CMD_SERVICE] = "SERVICE";
+ircd_commands[IRCD_CMD_SERVLIST] = "SERVLIST";
+ircd_commands[IRCD_CMD_SQUERY] = "SQUERY";
+ircd_commands[IRCD_CMD_SQUIT] = "SQUIT";
+ircd_commands[IRCD_CMD_SETNAME] = "SETNAME";
+ircd_commands[IRCD_CMD_SILENCE] = "SILENCE";
+ircd_commands[IRCD_CMD_STATS] = "STATS";
+ircd_commands[IRCD_CMD_SUMMON] = "SUMMON";
+ircd_commands[IRCD_CMD_TIME] = "TIME";
+ircd_commands[IRCD_CMD_TOPIC] = "TOPIC";
+ircd_commands[IRCD_CMD_TRACE] = "TRACE";
+ircd_commands[IRCD_CMD_UHNAMES] = "UHNAMES";
+ircd_commands[IRCD_CMD_USER] = "USER";
+ircd_commands[IRCD_CMD_USERHOST] = "USERHOST";
+ircd_commands[IRCD_CMD_USERIP] = "USERIP";
+ircd_commands[IRCD_CMD_USERS] = "USERS";
+ircd_commands[IRCD_CMD_VERSION] = "VERSION";
+ircd_commands[IRCD_CMD_WALLOPS] = "WALLOPS";
+ircd_commands[IRCD_CMD_WATCH] = "WATCH";
+ircd_commands[IRCD_CMD_WHO] = "WHO";
+ircd_commands[IRCD_CMD_WHOIS] = "WHOIS";
+ircd_commands[IRCD_CMD_WHOWAS] = "WHOWAS";
+
+I64 IrcMatchCommand(U8 *str)
+{
+ I64 i;
+ for (i=0; i<IRCD_CMDS_MAX; i++)
+ {
+ if (!StrICmp(str, ircd_commands[i])) return i;
+ }
+ return -1;
+}
+
+U0 IrcParseCommand(IrcClient *client, U8 *str)
+{
+ U8 **argv;
+ I64 argc = NULL;
+ I64 cmd = -1;
+ argv = ParseArgs(str, &argc);
+ if (argc)
+ {
+ AdamLog("** Gihon - Command: %s from Client %16X\n", argv[0], client);
+ cmd = IrcMatchCommand(argv[0]);
+ switch (cmd)
+ {
+ case IRCD_CMD_JOIN:
+ if (argc==2)
+ {
+ IrcChannelJoin(argv[1], client);
+ IrcClientTopic(client, argv[1]);
+ IrcClientNames(client, argv[1]);
+ }
+ break;
+ case IRCD_CMD_KICK:
+ if (argc>3)
+ {
+ IrcChannelKick(argv[1], client, argv[2], StrFirstOcc(str, ":")+1);
+ }
+ else
+ {
+ IrcChannelKick(argv[1], client, argv[2], argv[2]);
+ }
+ break;
+ case IRCD_CMD_MODE:
+ if (argc==3)
+ {
+ IrcChannelMode(argv[1], client, argv[2]);
+ }
+ if (argc==4)
+ {
+ IrcChannelMode(argv[1], client, argv[2], argv[3]);
+ }
+ break;
+ case IRCD_CMD_NICK:
+ if (argc==2)
+ {
+ IrcClientSetNick(client, argv[1]);
+ }
+ break;
+ case IRCD_CMD_PART:
+ if (argc==2)
+ {
+ IrcChannelPart(argv[1], client);
+ }
+
+ if (argc>2)
+ {
+ IrcChannelPart(argv[1], client, StrFirstOcc(str, ":")+1);
+ }
+ break;
+ case IRCD_CMD_PING:
+ if (argc==2)
+ {
+ IrcClientPing(client, argv[1]);
+ }
+ break;
+ case IRCD_CMD_PRIVMSG:
+ if (argc>2)
+ {
+ IrcClientPrivMsg(client, argv[1], StrFirstOcc(str, ":")+1);
+ }
+ break;
+ case IRCD_CMD_QUIT:
+ if (argc==1)
+ {
+ IrcChannelsQuit(client);
+ }
+ if (argc>1)
+ {
+ IrcChannelsQuit(client, StrFirstOcc(str, ":")+1);
+ }
+ break;
+ case IRCD_CMD_TOPIC:
+ if (argc>2)
+ {
+ IrcChannelTopic(argv[1], client, StrFirstOcc(str, ":")+1);
+ }
+ break;
+ case IRCD_CMD_USER:
+ if (argc>4)
+ {
+ IrcClientSetUser(client, argv[1], argv[2], argv[3], StrFirstOcc(str, ":")+1); // for now
+ IrcClientMotd(client);
+ }
+ break;
+ case IRCD_CMD_WHO:
+ if (argc==2)
+ {
+ IrcClientWho(client, argv[1]);
+ }
+ break;
+ default:
+ break;
+ }
+ FreeArgs(argc, argv);
+ }
+ client->idle = cnts.jiffies;
+} \ No newline at end of file
diff --git a/Gihon.HC b/Gihon.HC
new file mode 100644
index 0000000..e70ee2e
--- /dev/null
+++ b/Gihon.HC
@@ -0,0 +1,53 @@
+#define IRCD_LIMIT_MAX 20
+#define IRCD_PING_INTERVAL 60000
+#define IRCD_PORT 6667
+#define IRCD_RXBUF_SIZE 4096
+#define IRCD_TXBUF_SIZE 4096
+#define IRCD_TXFIFO_SIZE 128
+
+U8 *ircd_hostname = "irc.gihon.local";
+I64 ircd_chans_total = 0;
+I64 ircd_clients_total = 0;
+
+#include "Motd";
+#include "Service";
+#include "Arg";
+#include "Client";
+#include "Channel";
+#include "Command";
+
+I64 Gihon()
+{
+ DocClear(adam_task->put_doc);
+ DocMax(adam_task->put_doc);
+ WinToTop(adam_task);
+ while (!my_ip) { Sleep(1); }; // Wait for Netcfg
+ CTcpSocket *sock = socket(AF_INET, SOCK_STREAM);
+ if (sock < 0)
+ return -1;
+ sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(IRCD_PORT);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, &addr, sizeof(addr)) < 0) {
+ close(sock); /* Failed to bind to port */
+ return -1;
+ }
+ I64 error = listen(sock, 1);
+ if (error < 0) { /* listen: error */
+ return -1;
+ }
+ Spawn(&IrcClientTxHandler,, "Gihon ClientTxHandler");
+ AdamLog("** Gihon - Server started\n");
+ while (1)
+ {
+ I64 client = accept(sock, 0, 0);
+ Spawn(&IrcClientRxHandler, client, "Gihon ClientRxHandler");
+ Sleep(1);
+ }
+ close(sock);
+ AdamLog("** Gihon - Server exited\n");
+ return 0;
+}
+
+Spawn(&Gihon,,"Gihon Server"); \ No newline at end of file
diff --git a/Motd.HC b/Motd.HC
new file mode 100644
index 0000000..55c6906
--- /dev/null
+++ b/Motd.HC
@@ -0,0 +1,38 @@
+U8 **ParseMotd(U8 *str, I64 *argc)
+{
+ I64 _argc = 0;
+ U8 **_argv = NULL;
+ U8 **_tmp = CAlloc(sizeof(U64) * StrLen(str));
+ I64 i = 0;
+ I64 s = 0;
+ I64 len;
+ while (i < StrLen(str) + 1)
+ {
+ switch (str[i])
+ {
+ case 0:
+ case '\n':
+ len = (str + i)-(str + s - 1);
+ if (len - 1)
+ {
+ _tmp[_argc] = CAlloc(len);
+ MemCpy(_tmp[_argc], str + s, len-1);
+ _argc++;
+ }
+ s = i + 1;
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+ *argc = _argc;
+ _argv = CAlloc(sizeof(U64) * _argc);
+ MemCpy(_argv, _tmp, sizeof(U64) * _argc);
+ Free(_tmp);
+ Free(str);
+ return _argv;
+}
+
+I64 motd_line_cnt;
+U8 **motd_lines = ParseMotd(FileRead("Motd.TXT"), &motd_line_cnt); \ No newline at end of file
diff --git a/Motd.TXT b/Motd.TXT
new file mode 100644
index 0000000..69e114d
--- /dev/null
+++ b/Motd.TXT
@@ -0,0 +1,2 @@
+This is an example file.
+You can edit this file to display the message of the day. \ No newline at end of file
diff --git a/README.md b/README.md
index 2a81f6f..93871c1 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,8 @@
# gihon
IRC Server for TempleOS
+
+![Gihon](https://raw.githubusercontent.com/obecebo/gihon/master/preview.png?)
+
+# details
+
+This is a work in progress. If you know what you're doing (or even if you don't) feel free to clone the repo and mess around.
diff --git a/Service.HC b/Service.HC
new file mode 100644
index 0000000..85acc30
--- /dev/null
+++ b/Service.HC
@@ -0,0 +1,7 @@
+I64 service_cnt = 5;
+U8 **service_nick = CAlloc(sizeof(U64)*service_cnt);
+service_nick[0] = "NickServ";
+service_nick[1] = "ChanServ";
+service_nick[2] = "MemoServ";
+service_nick[3] = "BotServ";
+service_nick[4] = "HostServ"; \ No newline at end of file
diff --git a/preview.png b/preview.png
new file mode 100644
index 0000000..6f25e7a
--- /dev/null
+++ b/preview.png
Binary files differ