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