#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();
}
|