ref: c86384b841687ea975571db934fb0e353ce5b5d4
parent: 2716869c69ae007306e1b2bacfc0bf7adbccb0fc
author: sirjofri <sirjofri@sirjofri.de>
date: Sun Aug 3 18:38:30 EDT 2025
fixes test, implements PART, but actual parting doesn't work (bug)
--- a/chan.c
+++ b/chan.c
@@ -4,6 +4,8 @@
#include "fns.h"
#include "ll.h"
+#define DC (0x2)
+
static Linked *channels = nil;
static int
@@ -40,6 +42,10 @@
joinchannel(Client *cl, char *name)
{
IChan *c = lfind(&channels, findchanbyname, name);
+ if (c && userinchannel(c, cl)) {
+ fprint(2, "user %s already in channel %s\n", cl->nick, name);
+ goto Out;
+ }
if (!c) {
c = mallocz(sizeof(IChan), 1);
c->name = strdup(name);
@@ -47,10 +53,22 @@
}
ladd(&c->users, cl);
ladd(&cl->channels, c);
- if (debug > 2) {
+
+Out:
+ if (debug & DC) {
lforeach(&channels, printchannel, nil);
}
return c;
+}
+
+void
+partchannel(IChan *ch, Client *cl)
+{
+ ldel(ch->users, cl, nil);
+ ldel(cl->channels, ch, nil);
+ if (debug & DC) {
+ lforeach(&channels, printchannel, nil);
+ }
}
IChan*
--- a/cmd.c
+++ b/cmd.c
@@ -8,6 +8,13 @@
static char channelprefix[] = "&#+!";
+typedef struct AuxArgs AuxArgs;
+struct AuxArgs {
+ IChan *channel;
+ Client *client;
+ char *str;
+};
+
static void
cversion(Client *c, Request *r)
{
@@ -132,10 +139,11 @@
acprivmsgsend(void *a, void *b)
{
Client *c = a;
- A_privmsgsend *args = b;
- if (c == args->sender)
+ AuxArgs *args = b;
+
+ if (c == args->client)
return;
- ircsend(c, args->sender, Sprivmsg, args->chan->name, args->msg);
+ ircsend(c, args->client, Sprivmsg, args->channel->name, args->str);
}
static void
@@ -144,7 +152,7 @@
/* (/lib/rfc/rfc2812:/^3.3.1) */
Client *tgt;
IChan *chan;
- A_privmsgsend pmsg;
+ AuxArgs args;
if (!r->args[0] || r->args[0][0] == 0) {
reply(c, Enorecipient, "PRIVMSG");
@@ -161,10 +169,10 @@
reply(c, Ecannotsendtochan, r->args[0]);
return;
}
- pmsg.chan = chan;
- pmsg.msg = r->args[1];
- pmsg.sender = c;
- lforeach(&chan->users, acprivmsgsend, &pmsg);
+ args.channel = chan;
+ args.str = r->args[1];
+ args.client = c;
+ lforeach(&chan->users, acprivmsgsend, &args);
return;
}
/* target is user */
@@ -197,64 +205,117 @@
reply(c, Runaway);
}
-typedef struct A_listnames A_listnames;
-struct A_listnames {
- IChan *channel;
- Client *client;
-};
-
/* Aux Cmd function */
static void
aclistnames(void *a, void *b)
{
Client *c = a;
- A_listnames *ln = b;
+ AuxArgs *ln = b;
reply(ln->client, Rnamreply, '=', ln->channel->name, c->nick);
- ircsend(c, ln->client, Sjoin, ln->channel->name);
}
static void
+acsendjoin(void *cl, void *aux)
+{
+ Client *c = cl;
+ AuxArgs *a = aux;
+ ircsend(c, a->client, Sjoin, a->channel->name);
+}
+
+static void
cjoin(Client *c, Request *r)
{
/* (/lib/rfc/rfc2812:/^3.2.1) */
char *channel;
IChan *ch;
- A_listnames ln;
+ AuxArgs ln;
+ char *chs[10];
+ int nch;
+
if (!r->args[0] || r->args[0][0] == 0) {
- reply(c, Eneedmoreparams, "JOIN");
- return;
+ goto Err;
}
- for (int i = 0; i < 15;) {
- /* i is channel, i+1 is ',' */
- channel = r->args[i];
- if (!channel)
- break;
+
+ nch = getfields(r->args[0], chs, sizeof(chs), 1, ",");
+ if (!nch) {
+ goto Err;
+ }
+
+ for (int i = 0; i < nch; i++) {
+ channel = chs[i];
ch = joinchannel(c, channel);
ircsend(c, nil, Sjoin, channel);
- if (ch->topic) {
+ if (ch->topic)
reply(c, Rtopic, channel, ch->topic);
- } else {
+ else
reply(c, Rnotopic, channel);
- }
ln.client = c;
ln.channel = ch;
lforeach(&ch->users, aclistnames, &ln);
reply(c, Rendofnames, channel);
-
- if (r->args[i+1]) {
- if (!strcmp(r->args[i+1], ",")) {
- i += 2;
- continue;
+ lforeach(&ch->users, acsendjoin, &ln);
+ }
+ return;
+Err:
+ reply(c, Eneedmoreparams, "JOIN");
+}
+
+static void
+acpart(void *a, void *b)
+{
+ Client *c = a;
+ AuxArgs *args = b;
+
+ ircsend(c, args->client, Spart, args->str ? args->str : args->client->nick);
+}
+
+static void
+cpart(Client *c, Request *r)
+{
+ /* (/lib/rfc/rfc2812:/^3.2.2) */
+ int i;
+ char *msg;
+ char *chs[10];
+ IChan *ch;
+ int nch;
+ AuxArgs args;
+
+ if (!r->args[0] || r->args[0][0] == 0) {
+ goto Err;
+ }
+
+ msg = nil;
+ if (r->args[1] && r->args[1][0] != 0)
+ msg = r->args[1];
+
+ nch = getfields(r->args[0], chs, sizeof(chs), 1, ",");
+ if (!nch) {
+ goto Err;
+ }
+
+ for (i = 0; i < nch; i++) {
+ ch = findchannel(chs[i]);
+ if (!ch) {
+ reply(c, Enosuchchannel, chs[i]);
+ } else {
+ if (userinchannel(ch, c)) {
+ args.channel = ch;
+ args.client = c;
+ args.str = msg;
+ lforeach(&ch->users, acpart, &args);
+ partchannel(ch, c);
} else {
- // TODO: syntax error?
+ reply(c, Enotonchannel, chs[i]);
}
- } else
- break;
+ }
}
+ return;
+Err:
+ reply(c, Eneedmoreparams, "PART");
}
static void
@@ -261,6 +322,7 @@
cquit(Client *c, Request *r)
{
/* (/lib/rfc/rfc2812:/^3.1.7) */
+ USED(r);
ircerror(c, "Bye");
if (c->user)
deluser(c->user);
@@ -280,6 +342,7 @@
{ "privmsg", cprivmsg },
{ "away", caway },
{ "join", cjoin },
+ { "part", cpart },
{ "quit", cquit },
};
int ncommands = sizeof(commands) / sizeof(Command);
@@ -291,13 +354,6 @@
if (cistrcmp(commands[i].name, s) == 0)
return &commands[i];
}
- return nil;
-}
-
-Command*
-findcommandn(int n)
-{
- assert(0);
return nil;
}
--- a/cmd.h
+++ b/cmd.h
@@ -93,6 +93,11 @@
.msg = "%s :No such server",
};
+Reply Enosuchchannel = {
+ .nr = 403,
+ .msg = "%s :No such channel",
+};
+
Reply Ecannotsendtochan = {
.nr = 404,
.msg = "%s :Cannot send to channel",
@@ -118,6 +123,11 @@
.msg = "%s :Nickname is already in use",
};
+Reply Enotonchannel = {
+ .nr = 442,
+ .msg = "%s :You're not on that channel",
+};
+
Reply Eneedmoreparams = {
.nr = 461,
.msg = "%s :Not enough parameters",
@@ -139,4 +149,8 @@
Reply Sjoin = {
.msg = "JOIN %s",
+};
+
+Reply Spart = {
+ .msg = "PART :%s",
};
--- a/fns.h
+++ b/fns.h
@@ -1,7 +1,6 @@
Request parseline(char*);
Command* findcommand(char*);
-Command* findcommandn(int);
void execrequest(Client*, Request);
void clearrequest(Request);
@@ -26,4 +25,5 @@
IChan* joinchannel(Client*,char*);
IChan* findchannel(char*);
+void partchannel(IChan*,Client*);
int userinchannel(IChan*,Client*);
--- a/ircd.c
+++ b/ircd.c
@@ -191,7 +191,7 @@
mtpt = EARGF(usage());
break;
case 'd':
- debug++;
+ debug = atoi(EARGF(usage()));
break;
case 'D':
chatty9p++;
--- a/reply.c
+++ b/reply.c
@@ -65,7 +65,7 @@
snprint(&buf[i], sizeof(buf) - i, "\r\n");
if (debug > 1)
- fprint(2, "ircsend: '%s'\n", buf);
+ fprint(2, "ircsend (%s): '%s'\n", c->nick, buf);
qlock(&c->replies);
s = c->replies.reply;
--- a/test/mkfile
+++ b/test/mkfile
@@ -6,5 +6,5 @@
</sys/src/cmd/mktest
-$O.parsetest: ../parse.$O ../cmd.$O ../fmt.$O
+$O.parsetest: ../parse.$O ../cmd.$O ../fmt.$O ../ll.$O
$O.lltest: ../ll.$O
--- a/test/parsetest.c
+++ b/test/parsetest.c
@@ -2,10 +2,20 @@
#include <libc.h>
#include "../dat.h"
#include "../fns.h"
+#include "../ll.h"
int debug;
char *sysnameb;
char *welcome;
+
+void ircsend(Client*, Client*, Reply, ...) {}
+void ircerror(Client*, char*, ...) {}
+IChan* joinchannel(Client*, char*) { return nil; }
+IChan* findchannel(char*) { return nil; }
+void partchannel(IChan*, Client*) {}
+int userinchannel(IChan*, Client*) { return 0; }
+void deluser(User*) {}
+
char*
getversion(void)
--
⑨