#include "irc.h"
+#include "ircfmt.h"
struct dynarr databuf;
const char *hostname = "irc.patchysicp.xyz";
#define is_registered(cl) ((cl)->nick != 0)
-static void err_notregistered(struct client_data *client) {
- copy_strf(&databuf, ":%s 451 * :You have not registered\n", hostname);
+void sendbuf(struct client_data *client) {
send_log(client->FD, databuf.buf, databuf.len, 0);
}
int processPacket(struct client_data *client) {
if(strcmp(command, "PING") == 0) {
if (!args[0]) // FIXME: error message
return 0;
- copy_strf(&databuf, ":%s PONG %s :%s\n", hostname, hostname, args[0]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ msg_pong(args[0]);
+ sendbuf(client);
} else if(strcmp(command, "CAP") == 0) {
if (!args[0]) // FIXME: error message
return 0;
if (strcmp(args[0], "LS") == 0) {
// at least one client hangs if it doesn't see a known extension
copy_strf(&databuf, ":%s CAP * LS :multi-prefix\n", hostname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
if (client->regstate != REG_CAPEND || !client->nick || !client->username)
client->regstate = REG_CAPLS;
} else if (strcmp(args[0], "LIST") == 0) {
copy_strf(&databuf, ":%s CAP * LIST :\n", hostname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if (strcmp(args[0], "REQ") == 0) {
if (!args[1]) // FIXME: error message
return 0;
copy_strf(&databuf, ":%s CAP * NAK :%s\n", hostname, args[1]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if (strcmp(args[0], "END") == 0) {
if (client->regstate == REG_CAPLS && client->nick && client->username)
newUser(client);
if (!args[0]) // FIXME: error message
return 0;
setNick(client, args[0]);
- if (client->nick)
- printf("USER SET NICKNAME %s\n", client->nick);
- fflush(stdout);
if (client->regstate != REG_CAPLS && client->nick && client->username)
newUser(client);
} else if(strcmp(command, "USER") == 0) {
sendMOTD(client);
} else if(strcmp(command, "JOIN") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (!args[0]) // FIXME: error message
return 0;
if (!strcmp(args[0], "0")) {
channel_join(client, args[0], NULL);
} else if(strcmp(command, "PART") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (!args[0]) // FIXME: error message
return 0;
char *p = strchr(args[0], ','); // TODO: multiple channels
channel_part(client, chan, args[1] ? args[1] : "");
} else if(strcmp(command, "TOPIC") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (!args[0]) // FIXME: error message
return 0;
struct channel *chan = findChannel(args[0]);
if (!chan->topic_who) abort();
chan->topic_when = time(NULL);
}
- copy_strf(&databuf, ":%s!%s@%s TOPIC %s :%s\n", client->nick, client->username, client->hostname, chan->name, args[1]);
+ msg_topic(client, chan);
struct trie_find *f = NULL;
if (trie_findfirst(&f, &chan->members) == 1)
do {
struct client_data *cl = f->n->value;
- send_log(cl->FD, databuf.buf, databuf.len, 0);
+ sendbuf(cl);
} while (trie_findnext(&f) == 1);
}
} else if(strcmp(command, "PRIVMSG") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (argc < 2) // FIXME: error message
return 0;
- copy_strf(&databuf, ":%s!%s@%s PRIVMSG %s :%s\n", client->nick, client->username, client->hostname, args[0], args[1]);
+ (command[0] == 'P' ? msg_privmsg : msg_notice)(client, args[0], args[1]);
if (args[0][0] == '#' || args[0][0] == '&') {
- sendall_log(client->FD, databuf.buf, databuf.len, 0);
+ sendall_log(client->FD, databuf.buf, databuf.len, 0); // TODO: limit visibility
} else {
struct client_data *cl = findClient(args[0]);
if (!cl) {
copy_strf(&databuf, ":%s 401 %s %s :No such nick/channel\n", hostname, client->nick, args[0]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
} else {
- send_log(cl->FD, databuf.buf, databuf.len, 0);
+ sendbuf(cl);
if (cl->away) {
copy_strf(&databuf, ":%s 301 %s %s :%s\n", hostname, client->nick, cl->nick, cl->away);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
}
}
// Start GitHub Copilot - this shit actually be copy pasting my code lmao
} else if(strcmp(command, "QUIT") == 0) {
- copy_strf(&databuf, ":%s!%s@%s QUIT :%s\n", client->nick, client->username, client->hostname, args[0] ? args[0] : "Client Quit");
- sendall_log(client->FD, databuf.buf, databuf.len, 0);
+ msg_quit(client, "Quit: ", args[0] ? args[0] : "");
+ sendall_log(client->FD, databuf.buf, databuf.len, 0); // TODO: limit visibility
killConnection(client, true);
return 1;
} else if(strcmp(command, "PONG") == 0) {
// Do nothing
} else if(strcmp(command, "MODE") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (argc == 0) // FIXME: error message
return 0;
char *nick = args[0];
struct client_data *cl = findClient(nick);
if (!cl) {
copy_strf(&databuf, ":%s 401 %s %s :No such nick/channel\n", hostname, client->nick, nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
}
copy_strf(&databuf, ":%s 221 %s +", hostname, client->nick);
if (cl->umode & UMODE_REGISTERED) append_str(&databuf, "r");
if (cl->umode & UMODE_WALLOPS) append_str(&databuf, "w");
append_str(&databuf, "\r\n");
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else {
copy_strf(&databuf, ":%s 324 %s %s +nt\n", hostname, client->nick, nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
} else { // set mode
if (*nick != '#' && *nick != '&') {
struct client_data *cl = findClient(nick);
if (!cl) {
copy_strf(&databuf, ":%s 401 %s %s :No such nick/channel\n", hostname, client->nick, nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
}
if (client->FD != cl->FD) {
copy_strf(&databuf, ":%s 502 %s :Can't change mode for other users\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
}
int off;
copy_strf(&databuf, ":%s MODE %s +i\n", hostname, client->nick);
cl->umode |= UMODE_INVISIBLE;
}
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
break;
default:
copy_strf(&databuf, ":%s 501 %s :Unknown MODE flag\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
p++;
}
if (argc == 2) { // Type A channel modes
if (!strcmp(args[1], "+b")) {
copy_strf(&databuf, ":%s 368 %s %s :End of channel ban list\n", hostname, client->nick, args[1]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
}
if (!strcmp(args[1], "+e")) {
copy_strf(&databuf, ":%s 349 %s %s :End of channel exception list\n", hostname, client->nick, args[1]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
}
if (!strcmp(args[1], "+I")) {
copy_strf(&databuf, ":%s 347 %s %s :End of Channel Invite Exception List\n", hostname, client->nick, args[1]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return 0;
}
}
}
} else if(strcmp(command, "LIST") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
copy_strf(&databuf, ":%s 321 %s Channel :Users Name\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
struct trie_find *f = NULL;
if (trie_findfirst(&f, &channel_map) == 1)
do {
struct channel *chan = f->n->value;
copy_strf(&databuf, ":%s 322 %s %s %u :%s\n", hostname, client->nick,
chan->name, chan->member_count, chan->topic ? chan->topic : "");
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} while(trie_findnext(&f) == 1);
copy_strf(&databuf, ":%s 323 %s :End of /LIST\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if(strcmp(command, "NAMES") == 0) {
// TODO: actual channel support
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (argc == 0) // FIXME: error message
return 0;
struct trie_find *f = NULL;
do {
struct client_data *cl = f->n->value;
copy_strf(&databuf, ":%s 353 %s = %s :%s\n", hostname, client->nick, args[0], cl->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} while(trie_findnext(&f) == 1);
copy_strf(&databuf, ":%s 366 %s :End of /NAMES list\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if(strcmp(command, "USERHOST") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (argc == 0) // FIXME: error message
return 0;
copy_strf(&databuf, ":%s 302 %s", hostname, client->nick);
}
append_str(&databuf, "\r\n");
}
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if(strcmp(command, "WHO") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (argc == 0) // FIXME: error message
return 0;
struct client_data *cl = findClient(args[0]);
copy_strf(&databuf, ":%s 352 %s * %s %s %s %s %s%s :1 %s\n",
hostname, client->nick, cl->username, cl->hostname, hostname, cl->nick,
cl->away ? "G" : "H", cl->umode&UMODE_OPER ? "*" : "", cl->realname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
copy_strf(&databuf, ":%s 315 %s %s :End of WHO list\n", hostname, client->nick, args[0]);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if(strcmp(command, "WHOIS") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (argc == 0) // FIXME: error message
return 0;
char *nick = args[1] ? args[1] : args[0];
struct client_data *cl = findClient(nick);
if (cl) {
copy_strf(&databuf, ":%s 311 %s %s %s %s * :%s\n", hostname, client->nick, cl->nick, cl->username, cl->hostname, cl->realname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
copy_strf(&databuf, ":%s 312 %s %s %s :Patchy server\n", hostname, client->nick, cl->nick, hostname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
if (cl->umode & UMODE_OPER) {
copy_strf(&databuf, ":%s 313 %s %s :is an IRC operator\n", hostname, client->nick, cl->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
if (cl->away) {
copy_strf(&databuf, ":%s 301 %s %s :%s\n", hostname, client->nick, cl->nick, cl->away);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
copy_strf(&databuf, ":%s 318 %s %s :End of /WHOIS list\n", hostname, client->nick, cl->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else {
copy_strf(&databuf, ":%s 401 %s %s :No such nick/channel\n", hostname, client->nick, nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
} else if(strcmp(command, "AWAY") == 0) {
if (!is_registered(client))
- return err_notregistered(client), 0;
+ return err_notregistered(client), sendbuf(client), 0;
if (args[0]) {
free(client->away);
client->away = mystrdup(args[0]);
if (!client->away) abort();
copy_strf(&databuf, ":%s 306 %s :You have been marked as being away\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else {
free(client->away);
client->away = NULL;
copy_strf(&databuf, ":%s 305 %s :You are no longer marked as being away\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
} else {
unknown:
// Inform user of error
copy_strf(&databuf, ":%s 421 %s :Unknown command %s\n", hostname, client->nick, command);
- send_log(client->FD, databuf.buf, databuf.len, 0);
- fflush(stdout);
+ sendbuf(client);
}
return 0;
}
void newUser(struct client_data *client) {
client->regstate = REG_CAPEND;
- copy_strf(&databuf, ":%s 001 %s :Welcome to the Patchy Network, %s\n", hostname, client->nick, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
- copy_strf(&databuf, ":%s 002 %s :Your host is PatchyIRCD, running version 0.0.1\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
- copy_strf(&databuf, ":%s 003 %s :This server was created when I had cybersex with your mother.\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
- copy_strf(&databuf, ":%s 004 %s PatchyIRCD 0.0.1 i nt\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
- copy_strf(&databuf, ":%s 005 %s CASEMAPPING=rfc1459 NICKLEN=%u CHANTYPES=#& PREFIX=(ov)@+ :are supported by this server\n", hostname, client->nick, MAX_NICKLEN-1);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ rpl_welcome(client), sendbuf(client);
+ rpl_yourhost(client), sendbuf(client);
+ rpl_created(client), sendbuf(client);
+ rpl_myinfo(client), sendbuf(client);
+ rpl_isupport(client), sendbuf(client);
copy_strf(&databuf, ":%s 251 %s :This server exists\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
copy_strf(&databuf, ":%s 252 %s :Jannies don't exist\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
sendMOTD(client);
}
void sendMOTD(struct client_data *client) {
copy_strf(&databuf, ":%s 375 %s :PatchySICP /MOTD\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
copy_strf(&databuf, ":%s 372 %s :Welcome to Montreal!\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
copy_strf(&databuf, ":%s 372 %s :You are retarded and I will have cybersex with your mom.\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
copy_strf(&databuf, ":%s 376 %s :/MOTD over\n", hostname, client->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
void setNick(struct client_data *client, char* nickname) {
if (strlen(nickname) >= MAX_NICKLEN || nickname[0] == '\0') {
copy_strf(&databuf, ":%s 432 * %s :Erroneous nickname\n", hostname, nickname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return;
}
const char *forbidden = " ,*?!@$:#&.";
while (*forbidden)
if (strchr(nickname, *forbidden++)) {
copy_strf(&databuf, ":%s 432 * %s :Erroneous nickname\n", hostname, nickname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return;
}
if (trie_get(&client_map, key)) {
// Nickname is already taken
copy_strf(&databuf, ":%s 443 * %s :Nickname is already in use\n", hostname, nickname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
return;
}
// Update nickname
if(client->nick) {
copy_strf(&databuf, ":%s!%s@%s NICK %s\n", client->nick, client->username, client->hostname, nickname);
- send_log(client->FD, databuf.buf, databuf.len, 0);
- sendall_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
+ sendall_log(client->FD, databuf.buf, databuf.len, 0); // TODO: limit visibility
trie_set(&client_map, client->key, NULL, NULL);
free(client->nick);
free(client->key);
{
if (chan->topic) {
copy_strf(&databuf, ":%s 332 %s %s :%s\n", hostname, client->nick, chan->name, chan->topic);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
copy_strf(&databuf, ":%s 333 %s %s %s %u\n", hostname, client->nick, chan->name, chan->topic_who, (unsigned)chan->topic_when);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} else if (!joining) {
copy_strf(&databuf, ":%s 331 %s %s :No topic is set\n", hostname, client->nick, chan->name);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
}
void channel_join(struct client_data *client, const char *channel, const char *chankey)
abort();
chan->member_count++;
// send JOIN to everyone
- copy_strf(&databuf, ":%s!%s@%s JOIN :%s\n", client->nick, client->username, client->hostname, chan->name);
+ msg_join(client, chan);
struct trie_find *f = NULL;
if (trie_findfirst(&f, &chan->members) == 1)
do {
struct client_data *cl = f->n->value;
- send_log(cl->FD, databuf.buf, databuf.len, 0);
+ sendbuf(cl);
} while(trie_findnext(&f) == 1);
// send topic
channel_sendtopic(client, chan, 1);
else
prefix = "";
copy_strf(&databuf, ":%s 353 %s = %s :%s%s\n", hostname, client->nick, chan->name, prefix, cl->nick);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
} while(trie_findnext(&f) == 1);
copy_strf(&databuf, ":%s 366 %s %s :End of /NAMES list\n", hostname, client->nick, chan->name);
- send_log(client->FD, databuf.buf, databuf.len, 0);
+ sendbuf(client);
}
void channel_part(struct client_data *client, struct channel *chan, const char *reason)
{
if (reason) {
- if (*reason)
- copy_strf(&databuf, ":%s!%s@%s PART %s :%s\n", client->nick, client->username, client->hostname, chan->name, reason);
- else
- copy_strf(&databuf, ":%s!%s@%s PART %s\n", client->nick, client->username, client->hostname, chan->name);
+ msg_part(client, chan, *reason ? reason : NULL);
struct trie_find *f = NULL;
if (trie_findfirst(&f, &chan->members) == 1)
do {
struct client_data *cl = f->n->value;
- send_log(cl->FD, databuf.buf, databuf.len, 0);
+ sendbuf(cl);
} while (trie_findnext(&f) == 1);
}
trie_set(&client->channels, chan->key, NULL, NULL);
--- /dev/null
+#include "ircfmt.h"
+extern struct dynarr databuf;
+extern const char *hostname;
+void msg_nick(struct client_data *src, const char *newnick)
+{
+ copy_strf(&databuf, ":%s!%s@%s NICK %s\r\n",
+ src->nick, src->username, src->hostname,
+ newnick);
+}
+#if 0
+void msg_ping(const char *token)
+{
+ copy_strf(&databuf, ":%s PING :%s\r\n", hostname, token);
+}
+#endif
+void msg_pong(const char *token)
+{
+ copy_strf(&databuf, ":%s PONG %s :%s\r\n", hostname, hostname, token);
+}
+void msg_quit(struct client_data *src, const char *prefix, const char *reason)
+{
+ copy_strf(&databuf, ":%s!%s@%s QUIT :%s%s\r\n",
+ src->nick, src->username, src->hostname, prefix, reason);
+}
+void msg_error(const char *reason)
+{
+ copy_strf(&databuf, ":%s ERROR :%s\r\n", hostname, reason);
+}
+void msg_join(struct client_data *src, struct channel *chan)
+{
+ copy_strf(&databuf, ":%s!%s@%s JOIN %s\r\n",
+ src->nick, src->username, src->hostname, chan->name);
+}
+void msg_part(struct client_data *src, struct channel *chan, const char *reason)
+{
+ if (reason)
+ copy_strf(&databuf, ":%s!%s@%s PART %s :%s\r\n",
+ src->nick, src->username, src->hostname, chan->name, reason);
+ else
+ copy_strf(&databuf, ":%s!%s@%s PART %s\r\n",
+ src->nick, src->username, src->hostname, chan->name);
+}
+void msg_topic(struct client_data *src, struct channel *chan)
+{
+ copy_strf(&databuf, ":%s!%s@%s TOPIC %s :%s\r\n",
+ src->nick, src->username, src->hostname,
+ chan->name, chan->topic ? chan->topic : "");
+}
+#if 0
+void msg_invite(struct client_data *src, struct client_data *dst, struct channel *chan)
+{
+ copy_strf(&databuf, ":%s!%s@%s INVITE %s %s\r\n",
+ src->nick, src->username, src->hostname, dst->nick, chan->name);
+}
+void msg_kick(struct client_data *src, struct client_data *who, struct channel *chan, const char *reason)
+{
+ if (reason)
+ copy_strf(&databuf, ":%s!%s@%s KICK %s %s :%s\r\n",
+ src->nick, src->username, src->hostname, chan->name, who->nick, reason);
+ else
+ copy_strf(&databuf, ":%s!%s@%s KICK %s %s\r\n",
+ src->nick, src->username, src->hostname, chan->name, who->nick);
+}
+#endif
+void msg_privmsg(struct client_data *src, const char *dst, const char *msg)
+{
+ copy_strf(&databuf, ":%s!%s@%s PRIVMSG %s :%s\r\n",
+ src->nick, src->username, src->hostname, dst, msg);
+}
+void msg_notice(struct client_data *src, const char *dst, const char *msg)
+{
+ copy_strf(&databuf, ":%s!%s@%s NOTICE %s :%s\r\n",
+ src->nick, src->username, src->hostname, dst, msg);
+}
+#if 0
+void msg_kill(struct client_data *src, struct client_data *dst, const char *reason)
+{
+ copy_strf(&databuf, ":%s!%s@%s KILL %s :%s\r\n",
+ src->nick, src->username, src->hostname, dst->nick, msg);
+}
+void msg_wallops(struct client_data *src, const char *msg)
+{
+ copy_strf(&databuf, ":%s!%s@%s WALLOPS :%s\r\n",
+ src->nick, src->username, src->hostname, msg);
+}
+#endif
+void rpl_welcome(struct client_data *client) // 001
+{
+ copy_strf(&databuf, ":%s 001 %s :Welcome to the Patchy Network, %s\r\n", hostname, client->nick, client->nick);
+}
+void rpl_yourhost(struct client_data *client) // 002
+{
+ copy_strf(&databuf, ":%s 002 %s :Your host is PatchyIRCD, running version 0.0.1\r\n", hostname, client->nick);
+}
+void rpl_created(struct client_data *client) // 003
+{
+ copy_strf(&databuf, ":%s 003 %s :This server was created when I had cybersex with your mother.\n", hostname, client->nick);
+}
+void rpl_myinfo(struct client_data *client) // 004
+{
+ copy_strf(&databuf, ":%s 004 %s PatchyIRCD 0.0.1 i nt\n", hostname, client->nick);
+}
+void rpl_isupport(struct client_data *client) // 005
+{
+ copy_strf(&databuf, ":%s 005 %s CASEMAPPING=rfc1459 NICKLEN=%u CHANTYPES=#& PREFIX=(ov)@+ :are supported by this server\n", hostname, client->nick, MAX_NICKLEN-1);
+}
+// 010 RPL_BOUNC
+// 221 RPL_UMODEIS
+// 251 RPL_LUSERCLIENT
+// 252 RPL_LUSEROP
+// 253 RPL_LUSERUNKNOWN
+// 254 RPL_LUSERCHANNELS
+// 255 RPL_LUSERME
+// 256 RPL_ADMINME
+// 257 RPL_ADMINLOC1
+// 258 RPL_ADMINLOC2
+// 259 RPL_ADMINEMAIL
+// 263 RPL_TRYAGAIN
+// 265 RPL_LOCALUSERS
+// 266 RPL_GLOBALUSERS
+// 276 RPL_WHOISCERTFP
+// 300 RPL_NONE
+// 301 RPL_AWAY
+// 302 RPL_USERHOST
+// 305 RPL_UNAWAY
+// 306 RPL_NOWAWAY
+// 352 RPL_WHOREPLY
+// 315 RPL_ENDOFWHO
+// 307 RPL_WHOISREGNICK
+// 311 RPL_WHOISUSER
+// 312 RPL_WHOISSERVER
+// 313 RPL_WHOISOPERATOR
+// 314 RPL_WHOWASUSER
+// 317 RPL_WHOISIDLE
+// 318 RPL_ENDOFWHOIS
+// 319 RPL_WHOISCHANNELS
+// 320 RPL_WHOISSPECIAL
+// 321 RPL_LISTSTART
+// 322 RPL_LIST
+// 323 RPL_LISTEND
+// 324 RPL_CHANNELMODEIS
+// 329 RPL_CREATIONTIME
+// 330 RPL_WHOISACCOUNT
+// 331 RPL_NOTOPIC
+// 332 RPL_TOPIC
+// 333 RPL_TOPICWHOTIME
+// 336 RPL_INVITELIST
+// 337 RPL_ENDOFINVITELIST
+// 338 RPL_WHOISACTUALLY
+// 341 RPL_INVITING
+// 346 RPL_INVEXLIST
+// 347 RPL_ENDOFINVEXLIST
+// 348 RPL_EXCEPTLIST
+// 349 RPL_ENDOFEXCEPTLIST
+// 351 RPL_VERSION
+// 353 RPL_NAMREPLY
+// 366 RPL_ENDOFNAMES
+// 364 RPL_LINKS
+// 365 RPL_ENDOFLINKS
+// 367 RPL_BANLIST
+// 368 RPL_ENDOFBANLIST
+// 369 RPL_ENDOFWHOWAS
+// 371 RPL_INFO
+// 374 RPL_ENDOFINFO
+// 375 RPL_MOTDSTART
+// 372 RPL_MOTD
+// 376 RPL_ENDOFMOTD
+// 378 RPL_WHOISHOST
+// 379 RPL_WHOISMODES
+// 381 RPL_YOUREOPER
+// 382 RPL_REHASHING
+// 391 RPL_TIME
+// 400 ERR_UNKNOWNERROR
+// 401 ERR_NOSUCHNICK
+// 402 ERR_NOSUCHSERVER
+// 403 ERR_NOSUCHCHANNEL
+// 404 ERR_CANNOTSENDTOCHAN
+// 405 ERR_TOOMANYCHANNELS
+// 406 ERR_WASSNOSUCHNICK
+// 409 ERR_NOORIGIN
+// 417 ERR_INPUTTOOLONG
+// 421 ERR_UNKNOWNCOMMAND
+// 422 ERR_NOMOTD
+// 432 ERR_ERRONEUSNICKNAME
+// 433 ERR_NICKNAMEINUSE
+// 441 ERR_USERNOTINCHANNEL
+// 442 ERR_NOTONCHANNEL
+// 443 ERR_USERONCHANNEL
+void err_notregistered(struct client_data *client) // 451
+{
+ (void)client;
+ copy_strf(&databuf, ":%s 451 * :You have not registered\r\n", hostname);
+}
+// 461 ERR_NEEDMOREPARAMS
+// 462 ERR_ALREADYREGISTERED
+// 464 ERR_PASWDMISMATCH
+// 465 ERR_YOUREBANNEDCREEP
+// 471 ERR_CHANNELISFULL
+// 472 ERR_UNKNOWNMODE
+// 473 ERR_INVITEONLYCHAN
+// 474 ERR_BANNEDFROMCHAN
+// 475 ERR_BADCHANNELKEY
+// 476 ERR_BADCHANMASK
+// 481 ERR_NOPRIVILEGES
+// 482 ERR_CHANOPRIVSNEEDED
+// 483 ERR_CANTKILLSERVER
+// 491 ERR_NOOPERHOST
+// 501 ERR_UMODEUNKNOWNFLAG
+// 502 ERR_USERSDONTMATCH
+// 524 ERR_HELPNOTFOUND
+// 525 ERR_INVALIDKEY
+// 670 RPL_STARTTLS
+// 671 RPL_WHOISSECURE
+// 691 ERR_STARTTLS
+// 696 ERR_INVALIDMODEPARAM
+// 704 RPL_HELPSTART
+// 705 RPL_HELPTXT
+// 706 RPL_ENDOFHELP
+// 723 ERR_NOPRIVS
+// 900 RPL_LOGGEDIN
+// 901 RPL_LOGGEDOUT
+// 902 ERR_NICKLOCKED
+// 903 RPL_SASLSUCCESS
+// 904 ERR_SASLFAIL
+// 905 ERR_SASLTOOLONG
+// 906 ERR_SASLABORTED
+// 907 ERR_SASLALREADY
+// 908 RPL_SASLMECHS