9scripts/install/irc7/ircsrv.c

256 lines
4.3 KiB
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();
}