shithub: ircd

Download patch

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)
--