Plan 9 from Bell Labs’s /usr/web/sources/contrib/anothy/src/cmd/irc7a/ircsrv.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <auth.h>

char *post;
char *file;
int ircfd = -1;	// the irc server
int logfd;
QLock lck;

char *server;
char *passwd;
char *nickname;
char *realname;
char *username;
char *mode = "foo";
char *unused = "bar";

void ircsrv(void);
void logger(void);
void die(void*, char*);
void reconnect(void);

void
usage(void)
{
	print("usage: ircsrv [-s service] [-p] [-f file] nickname [net!]ircserver\n");
	exits("usage");
}


void
killall(void)
{
	postnote(PNGROUP, getpid(), "quit");
	while(waitpid() != -1)
		;
	remove(post);
	exits(nil);
}

void
die(void *, char *)
{
	killall();
}

void
main(int argc, char *argv[])
{
	UserPasswd *creds;
	int p[2], fd, doauth = 0;

	ARGBEGIN{
	case 'f':
		file = ARGF();
		break;
	case 's':
		post = ARGF();
		break;
	case 'r':
		realname = ARGF();
		break;
	case 'p':
		doauth = 1;
		break;
	default:
		usage();
	}ARGEND;

	if(argc < 2)
		usage();

	nickname = argv[0];
	server = argv[1];
	if(doauth) {
		creds = auth_getuserpasswd(auth_getkey,
			"proto=pass service=irc server=%q user=%q", server, nickname);
		if(creds == nil)
			print("No pass, no auth\n");
		else
			passwd = creds->passwd;
	}


	username = getuser();

	if(post == nil)
		post = smprint("/srv/%sirc", username);
	else
		post = smprint("/srv/%s", post);

	if(file == nil)
		file = smprint("/tmp/%sirc", username);

	if((logfd = create(file, OWRITE, 0600 | DMAPPEND)) < 0)
		sysfatal("create(%s): %r", file);

	if((fd = create(post, OWRITE, 0600)) < 0)
		sysfatal("create(%s): %r", post);
	if(pipe(p) == -1)
		sysfatal("pipe: %r");
	fprint(fd, "%d", p[1]);
	close(fd);
	close(p[1]);
	close(0);
	close(1);
	close(2);
	dup(p[0], 0);

	if(rfork(RFMEM|RFFDG|RFPROC|RFNOTEG|RFCENVG|RFNOWAIT) == 0) {
		notify(die);
		reconnect();
		switch(rfork(RFPROC|RFMEM)){
		case -1:
			sysfatal("rfork: %r");
		case 0:
			notify(die);
			logger();
			break;
		default:
			ircsrv();
			break;
		}
	}
	exits(nil);
}

long
readln(int fd, void *vp, long len)
{
	char *b = vp;
	while(len > 0 && read(fd, b, 1) > 0){
		if(*b++ == '\n')
			break;
		len--;
	}
	return b - (char*)vp;
}

void
reregister(void)
{
	int n;
	char nbuf[32];

	strncpy(nbuf, nickname, sizeof(nbuf) - 2);
	switch(nbuf[strlen(nbuf) - 1]) {
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
		nbuf[strlen(nbuf) - 1]++;
		break;
	case '9':
		qlock(&lck);
		fprint(logfd, "can not register nick, bailing out\n");
		qunlock(&lck);
		die(nil, nil);
	default:
		n = strlen(nbuf);
		nbuf[n] = '0';
		nbuf[n+1] = '\0';
		break;
	}
	qlock(&lck);
	fprint(ircfd, "NICK %s\r\n", nbuf);
	fprint(logfd, "NICK %s\r\n", nickname);
	qunlock(&lck);
}

void
reconnect(void)
{
	if(ircfd >= 0)
		close(ircfd);
	if((ircfd = dial(netmkaddr(server, nil, "6667"), nil, nil, nil)) < 0)
		sysfatal("dial %r");
	if(passwd && strcmp(passwd, ""))
		fprint(ircfd, "PASS %s\r\n", passwd);
	fprint(ircfd, "USER %s %s %s :%s\r\n",
		username, mode, unused, realname);
	fprint(ircfd, "NICK %s\r\n", nickname);
}


void
logger(void)
{
	char buf[513];
	char *f[3];
	long n;

	for(;;){
		while((n = readln(ircfd, buf, sizeof(buf)-1)) > 0){
			write(logfd, buf, n);
			buf[n] = 0;
			n = tokenize(buf, f, nelem(f));
			if(n == 3 && *f[0] == ':' && !cistrcmp(f[1], "PING")){
				qlock(&lck);
				fprint(ircfd, "PONG %s\r\n", f[2]);
				fprint(logfd, "PONG %s\r\n", f[2]);
				qunlock(&lck);
			} else if(n == 2 && !cistrcmp(f[0], "PING")){
				qlock(&lck);
				fprint(ircfd, "PONG %s\r\n", f[1]);
				fprint(logfd, "PONG %s\r\n", f[1]);
				qunlock(&lck);
			} else if(n == 3 && atoi(f[1]) == 433) {
				reregister();
			}
		}
		reconnect();
	}
}


void
ircsrv(void)
{
	char buf[512];
	long n;

	while((n = readln(0, buf, sizeof(buf)-1)) > 0){
		qlock(&lck);


		if(!strncmp(buf,"MYNICK",5)) {
			fprint(logfd,"MYNICK %s\r\n",nickname);
			qunlock(&lck);
			continue;
		}
		if(!strncmp(buf,"NICK ",4)) {
			nickname = strdup(buf+5);
			nickname[strlen(nickname)-2] = '\0';
			fprint(logfd,"MYNICK %s\r\n",nickname);
		}
		if(write(logfd, buf, n) != n)
			fprint(2, "write to irclog: %r\n");
		if(write(ircfd, buf, n) != n)
			fprint(2, "write to ircserver: %r\n");

		memset(buf,0,sizeof(buf));
		qunlock(&lck);
	}
	killall();
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].