shithub: ircd

Download patch

ref: 9922e90ae9072e72a7f61c8328ad1f71cee6cf0f
parent: 4161df5fd7487feaf4758b93a8d8371bec433471
author: sirjofri <sirjofri@sirjofri.de>
date: Sun Jul 20 10:46:33 EDT 2025

multiple user support

for wiring only, for now. You can test this by connecting with two separate clients (con -C multiple times)

user usera usera usera * :usera
whois

and in the second client, s/usera/userb/g

whois should report with usera and userb respectively

--- /dev/null
+++ b/client.c
@@ -1,0 +1,55 @@
+#include <u.h>
+#include <libc.h>
+#include <String.h>
+#include "dat.h"
+#include "fns.h"
+
+// TODO: generalize doubly linked list, or use other structure
+
+static Client *first = nil;
+
+Client*
+addclient(ulong fid)
+{
+	Client *n;
+	n = mallocz(sizeof(Client), 1);
+	n->fid = fid;
+	n->replies.reply = s_new();
+	
+	if (!first) {
+		first = n;
+		return n;
+	}
+	n->next = first;
+	first->prev = n;
+	first = n;
+	return n;
+}
+
+void
+delclient(Client *c)
+{
+	String *s;
+	if (!c->prev) {
+		first = c->next;
+		if (c->next)
+			c->next->prev = nil;
+	} else {
+		c->prev->next = c->next;
+		if (c->next)
+			c->next->prev = c->prev;
+	}
+	s = c->replies.reply;
+	s_free(s);
+	free(c);
+}
+
+Client*
+findclient(ulong fid)
+{
+	for (Client *c = first; c; c = c->next) {
+		if (fid == c->fid)
+			return c;
+	}
+	return nil;
+}
--- a/cmd.c
+++ b/cmd.c
@@ -6,36 +6,48 @@
 #include "version.h"
 
 static void
-cversion(User *u, Request *r)
+cversion(Client *c, Request *r)
 {
 	if (r->args[0]) {
 		fprint(2, "get version of '%s' (not implemented yet!)\n", r->args[0]);
-		reply(u, Enosuchserver, r->args[0]);
+		reply(c, Enosuchserver, r->args[0]);
 		return;
 	}
-	reply(u, Rversion, getversion());
+	reply(c, Rversion, getversion());
 }
 
 static void
-cuser(User *u, Request *r)
+cuser(Client *c, Request *r)
 {
-	// TODO: how to respond without knowing the user?
+	User *u;
 	if (!r->args[3]) {
 		fprint(2, "user without enough args%R\n", *r);
-		// reply(u, Eneedmoreparams, r->cmd.name);
+		reply(c, Eneedmoreparams, r->cmd->name);
 		return;
 	}
 	u = finduser(r->args[0]);
 	if (u) {
 		fprint(2, "user already registered%R\n", *r);
-		// reply(u, Ealreadyregistered);
+		reply(c, Ealreadyregistered);
 		return;
 	}
 	u = adduser(r->args[0]);
-	setuser(u);
+	c->user = u;
 }
 
+static void
+cwhois(Client *c, Request *r)
+{
+	if (!r->args[0]) {
+		/* information about self */
+		reply(c, Rwhoisuser, c->user->name, c->user->name, c->user->name, c->user->name);
+		return;
+		// TODO: fill with proper data!
+	}
+}
+
 static Command commands[] = {
+	{ "whois", cwhois },
 	{ "version", cversion },
 	{ "user", cuser },
 };
@@ -58,7 +70,7 @@
 }
 
 void
-execrequest(User *u, Request r)
+execrequest(Client *c, Request r)
 {
 	if (!(r.cmd && r.cmd->func)) {
 		fprint(2, "cannot execute request: no command\n");
@@ -66,5 +78,5 @@
 	}
 	if (debug)
 		fprint(2, "run command '%s'\n", r.cmd->name);
-	r.cmd->func(u, &r);
+	r.cmd->func(c, &r);
 }
--- a/cmd.h
+++ b/cmd.h
@@ -1,3 +1,8 @@
+Reply Rwhoisuser = {
+	.nr = 311,
+	.msg = "%s %s %s * :%s",
+};
+
 Reply Rversion = {
 	.nr = 351,
 	.msg = "%s",
--- a/dat.h
+++ b/dat.h
@@ -5,6 +5,7 @@
 typedef struct User User;
 typedef struct Replybuffer Replybuffer;
 typedef struct Userlist Userlist;
+typedef struct Client Client;
 
 #pragma varargck type "R" Request
 
@@ -25,7 +26,7 @@
 struct Command
 {
 	char *name;
-	void (*func)(User*,Request*);
+	void (*func)(Client*,Request*);
 };
 
 struct Reply
@@ -43,7 +44,6 @@
 struct User
 {
 	char *name;
-	Replybuffer replies;
 	
 	User *prev;
 	User *next;
@@ -52,6 +52,16 @@
 struct Userlist
 {
 	User *first;
+};
+
+struct Client
+{
+	ulong fid;
+	Replybuffer replies;
+	User *user;
+	
+	Client *next;
+	Client *prev;
 };
 
 extern int debug;
--- a/fns.h
+++ b/fns.h
@@ -2,13 +2,13 @@
 
 Command* findcommand(char*);
 Command* findcommandn(int);
-void execrequest(User*, Request);
+void execrequest(Client*, Request);
 void clearrequest(Request);
 
 void setuser(User*);
-void reply(User*, Reply, ...);
-char *getreplies(User*);
-void flushreplies(User*);
+void reply(Client*, Reply, ...);
+char *getreplies(Client*);
+void flushreplies(Client*);
 
 int Rfmt(Fmt *f);
 char *getversion(void);
@@ -16,3 +16,7 @@
 User* adduser(char*);
 void deluser(User*);
 User* finduser(char*);
+
+Client* addclient(ulong);
+Client* findclient(ulong);
+void delclient(Client*);
--- a/ircd.c
+++ b/ircd.c
@@ -4,7 +4,7 @@
 #include <fcall.h>
 #include <thread.h>
 #include <9p.h>
-#include <bio.h>
+#include <String.h>
 #include "dat.h"
 #include "fns.h"
 #include "version.h"
@@ -16,7 +16,10 @@
 	threadexitsall("usage");
 }
 
-static Biobuf *bio;
+enum {
+	Firc,
+};
+
 char *sysnameb = "nil";
 static char *versionstring = nil;
 int debug = 0;
@@ -34,12 +37,22 @@
 char *mtpt = "/mnt/ircd";
 char *srvname = "ircd";
 Reqqueue *reqqueue = nil;
-User *ircuser = nil;
 
+Client*
+getclient(Req *r)
+{
+	Client *c;
+	c = findclient(r->fid->fid);
+	if (c)
+		return c;
+	c = addclient(r->fid->fid);
+	return c;
+}
+
 void
 setuser(User *u)
 {
-	ircuser = u;
+	;
 }
 
 static void
@@ -46,24 +59,29 @@
 readproc(Req *r)
 {
 	char *repl;
+	Client *c;
 	
 	threadsetname("readproc");
 	
-	if (!ircuser) {
-		respond(r, nil);
+	c = findclient(r->fid->fid);
+	
+	if (!c) {
+		respond(r, "client not connected!");
 		return;
 	}
 	
 	while (1) {
-		qlock(&ircuser->replies);
-		repl = getreplies(ircuser);
+		qlock(&c->replies);
+		repl = getreplies(c);
 		if (repl) {
+			r->ifcall.offset = 0;
 			readstr(r, repl);
-			qunlock(&ircuser->replies);
+			flushreplies(c);
+			qunlock(&c->replies);
 			respond(r, nil);
 			return;
 		}
-		qunlock(&ircuser->replies);
+		qunlock(&c->replies);
 	}
 }
 
@@ -70,6 +88,11 @@
 static void
 fsread(Req *r)
 {
+	if (r->fid->file->aux != Firc) {
+		respond(r, "file not found");
+		return;
+	}
+	getclient(r);
 	reqqueuepush(reqqueue, r, readproc);
 }
 
@@ -79,7 +102,14 @@
 	char line[512];
 	char *c;
 	Request parsed;
+	Client *cl;
 	
+	if (r->fid->file->aux != Firc) {
+		respond(r, "file not found");
+		return;
+	}
+	
+	cl = getclient(r);
 	if (r->ifcall.count > 512) {
 		respond(r, "too many bytes");
 		return;
@@ -88,14 +118,18 @@
 	r->ofcall.count = r->ifcall.count;
 	line[r->ifcall.count-1] = 0; /* last char is either \n or \r */
 	
-	c = strchr(line, '
');
-	if (c)
+	c = strchr(line, '\n');
+	if (c) {
 		*c = 0;
+		c--;
+		if (*c == '
')
+			*c = 0;
+	}
 	
 	parsed = parseline(line);
 	if (debug > 1)
 		fprint(2, "request:%R", parsed);
-	execrequest(ircuser, parsed);
+	execrequest(cl, parsed);
 	
 	respond(r, nil);
 }
@@ -118,7 +152,7 @@
 {
 	File *f;
 	
-	if ((f = createfile(root, "irc", nil, 0666, nil)) != nil) {
+	if ((f = createfile(root, "irc", nil, 0666, Firc)) != nil) {
 		f->length = 0;
 	}
 }
--- a/mkfile
+++ b/mkfile
@@ -8,6 +8,7 @@
 	fmt.$O\
 	reply.$O\
 	users.$O\
+	client.$O\
 
 HFILES=fns.h dat.h cmd.h
 
--- a/reply.c
+++ b/reply.c
@@ -5,36 +5,35 @@
 #include "fns.h"
 
 char*
-getreplies(User *u)
+getreplies(Client *c)
 {
-	return u->replies.reply;
+	return s_to_c((String*)c->replies.reply);
 }
 
 void
-flushreplies(User *u)
+flushreplies(Client *c)
 {
-	if (!u->replies.reply)
+	String *s;
+	if (!c->replies.reply)
 		return;
-	free(u->replies.reply);
-	u->replies.reply = nil;
+	s = c->replies.reply;
+	s_reset(s);
 }
 
 void
-reply(User *u, Reply repl, ...)
+reply(Client *c, Reply repl, ...)
 {
-	char buf[511];
+	char buf[1024];
+	int i;
 	va_list arg;
-	String *s = u->replies.reply;
+	String *s = c->replies.reply;
 	
-	snprint(buf, sizeof buf, "%s %03d ", sysnameb, repl.nr);
-	s_append(s, buf);
+	i = snprint(buf, sizeof buf, ":%s %03d ", sysnameb, repl.nr);
 	
 	va_start(arg, repl);
-	vsnprint(buf, sizeof buf, repl.msg, arg);
+	i += vsnprint(&buf[i], sizeof(buf) - i, repl.msg, arg);
 	va_end(arg);
 	
+	snprint(&buf[i], sizeof(buf) - i, "\r\n");
 	s_append(s, buf);
-	s_append(s, "\r\n");
-	
-	fprint(2, ":%s %03d %s\r\n", sysnameb, repl.nr, buf);
 }
--- a/users.c
+++ b/users.c
@@ -1,6 +1,5 @@
 #include <u.h>
 #include <libc.h>
-#include <String.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -12,7 +11,6 @@
 	User *n;
 	n = mallocz(sizeof(User), 1);
 	n->name = strdup(name);
-	n->replies.reply = s_new();
 	
 	if (!users.first) {
 		users.first = n;
@@ -27,7 +25,6 @@
 void
 deluser(User *user)
 {
-	String *s;
 	if (!user->prev) {
 		users.first = user->next;
 		if (user->next)
@@ -37,8 +34,6 @@
 		if (user->next)
 			user->next->prev = user->prev;
 	}
-	s = user->replies.reply;
-	s_free(s);
 	free(user->name);
 	free(user);
 }
--