ref: dd77de7a509fa0e8273e3395161e691549edca52
dir: /install/irc7/ircsrv.c/
#include <u.h> #include <libc.h> #include <auth.h> #include <libsec.h> char *post; char *file; int ircfd = -1; // the irc server int logfd; int enctls = 0; // ssl/tls 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) { fprint(2, "usage: %s [-e] [-s service] [-f file] [-p pass] nickname [net!]ircserver[!port]\n", argv0); 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[]) { char *tmp; int p[2], fd; ARGBEGIN{ case 'f': file = EARGF(usage()); break; case 's': post = EARGF(usage()); break; case 'r': realname = EARGF(usage()); break; case 'e': enctls = 1; break; case 'p': passwd = EARGF(usage()); /* try to obfuscate the password so ps -a won't see it */ tmp = passwd; passwd = smprint("%s", tmp); if(passwd) memset(tmp, '\0', strlen(tmp)); else passwd = tmp; break; default: usage(); }ARGEND; if(argc < 2) usage(); nickname = argv[0]; server = argv[1]; username = getuser(); if(strlen(username) > 4) username[4] = '\0'; 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|RFREND|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, "%ld can not register nick, bailing out\n", time(0)); 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, "%ld NICK %s\r\n", time(0), nickname); qunlock(&lck); } void reconnect(void) { TLSconn *conn; if(ircfd >= 0) close(ircfd); if((ircfd = dial(netmkaddr(server, "tcp", "6667"), nil, nil, nil)) < 0) sysfatal("dial %r"); if(enctls > 0) { conn = (TLSconn *)mallocz(sizeof *conn, 1); ircfd = tlsClient(ircfd, conn); if (ircfd < 0) { sysfatal ("tls: %r"); } } if(passwd && strcmp(passwd, "")) fprint(ircfd, "PASS %s\r\n", passwd); fprint(ircfd, "USER %s %s %s :%s\r\n", nickname, 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){ fprint(logfd, "%ld ", time(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, "%ld PONG %s\r\n", time(0), f[2]); qunlock(&lck); } else if(n == 2 && !cistrcmp(f[0], "PING")){ qlock(&lck); fprint(ircfd, "PONG %s\r\n", f[1]); fprint(logfd, "%ld PONG %s\r\n", time(0), 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); fprint(logfd, "%ld ", time(0)); 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"); qunlock(&lck); } killall(); }