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);
}
--
⑨