added neindaw script
This commit is contained in:
parent
907105032b
commit
dd77de7a50
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/rc
|
||||||
|
mkdir -p $home/code
|
||||||
|
cd $home/code
|
||||||
|
git/clone https://git@git.sr.ht/~ft/neindaw
|
||||||
|
cd neindaw
|
||||||
|
mk install
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
default
|
|
@ -0,0 +1,2 @@
|
||||||
|
ac16a1e78cdfc12ffd5af66949e50846e580c5e5 1
|
||||||
|
ac16a1e78cdfc12ffd5af66949e50846e580c5e5 default
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
[paths]
|
||||||
|
default = https://code.9front.org/hg/irc7
|
|
@ -0,0 +1,3 @@
|
||||||
|
revlogv1
|
||||||
|
store
|
||||||
|
fncache
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
||||||
|
data/irc.c.i
|
||||||
|
data/irc.h.i
|
||||||
|
data/irc.man.i
|
||||||
|
data/ircsrv.c.i
|
||||||
|
data/mkfile.i
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
default
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,854 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <draw.h>
|
||||||
|
|
||||||
|
char help[] =
|
||||||
|
"cmd explanation/example\n"
|
||||||
|
"--------------------------------------------\n"
|
||||||
|
"/m privmsg #chan/nick message\n"
|
||||||
|
"/M mode #chan +nt\n"
|
||||||
|
"/j join #chan\n"
|
||||||
|
"/p part #chan\n"
|
||||||
|
"/q send parameters raw to the server\n"
|
||||||
|
"/l list #chan\n"
|
||||||
|
"/n nick newnick\n"
|
||||||
|
"/N notice #chan/nick message\n"
|
||||||
|
"/t set victim\n"
|
||||||
|
"/T topic #chan newtopic\n"
|
||||||
|
"/W whois nick\n"
|
||||||
|
"/w who nick (a shorter whois)\n";
|
||||||
|
|
||||||
|
#define NPAR 14
|
||||||
|
|
||||||
|
enum state { Time, Cmd, Prefix, Middle, Trail, Ok };
|
||||||
|
|
||||||
|
typedef struct handler Handler;
|
||||||
|
|
||||||
|
struct handler {
|
||||||
|
char *cmd;
|
||||||
|
int (*fun)(int fd, char *time, char *pre, char *cmd, char *par[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
QLock lck;
|
||||||
|
int server_in;
|
||||||
|
int server_out;
|
||||||
|
int scr;
|
||||||
|
char *victim;
|
||||||
|
char *nick;
|
||||||
|
int inacme; /* running in acme? */
|
||||||
|
int linewidth; /* terminal width in # of characters */
|
||||||
|
|
||||||
|
int replay; /* just print the log ma'am */
|
||||||
|
|
||||||
|
void setwintitle(char *chan);
|
||||||
|
|
||||||
|
int rtcs(int fd, char *cset);
|
||||||
|
int wtcs(int fd, char *cset);
|
||||||
|
int follow(int fd);
|
||||||
|
void getwidth(void); /* establish the width of the terminal, from mc.c */
|
||||||
|
|
||||||
|
int pmsg(int fd, char *time, char *pre, char *cmd, char *par[]);
|
||||||
|
int ntc(int fd, char *time, char *pre, char *cmd, char *par[]);
|
||||||
|
int generic(int fd, char *time, char *pre, char *cmd, char *par[]);
|
||||||
|
int misc(int fd, char *time, char *pre, char *cmd, char *par[]);
|
||||||
|
int numeric(int fd, char *time, char *pre, char *cmd, char *par[]);
|
||||||
|
|
||||||
|
Handler handlers[] = {
|
||||||
|
{"PRIVMSG", pmsg},
|
||||||
|
{"NOTICE", ntc},
|
||||||
|
{"JOIN", misc},
|
||||||
|
{"PART", misc},
|
||||||
|
{"MODE", misc},
|
||||||
|
{"QUIT", misc},
|
||||||
|
{"TOPIC", misc},
|
||||||
|
{"332", numeric},
|
||||||
|
{"333", numeric},
|
||||||
|
{"352", numeric},
|
||||||
|
{"315", numeric},
|
||||||
|
{"311", numeric},
|
||||||
|
{"319", numeric},
|
||||||
|
{"312", numeric},
|
||||||
|
{"320", numeric},
|
||||||
|
{"317", numeric},
|
||||||
|
{"318", numeric},
|
||||||
|
{nil, nil}
|
||||||
|
};
|
||||||
|
|
||||||
|
int srvparse(char *line, char **time, char **pre, char **cmd, char *par[], int npar);
|
||||||
|
int usrparse(char *ln, char *cmd, char *par[], int npar);
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
char usage[] = "usage: irc [-c charset] [-t victim] [-b lines] [-r file] [/srv/irc [/tmp/irc]]\n";
|
||||||
|
write(1, usage, sizeof(usage)-1);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setwintitle(char *chan)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if ((fd = open("/dev/label", OWRITE)) >= 0) {
|
||||||
|
fprint(fd, "%s", chan);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
if ((fd = open("/dev/acme/ctl", OWRITE)) >= 0) {
|
||||||
|
fprint(fd, "name -IRC/%s\n", chan);
|
||||||
|
close(fd);
|
||||||
|
inacme = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to find out whether we're running in acme's win -e */
|
||||||
|
int
|
||||||
|
testacme(void)
|
||||||
|
{
|
||||||
|
return access("/dev/acme", OREAD) >= 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usrin(void)
|
||||||
|
{
|
||||||
|
char *line, *p;
|
||||||
|
char *par[2];
|
||||||
|
char cmd;
|
||||||
|
int n, i;
|
||||||
|
|
||||||
|
Biobuf kbd;
|
||||||
|
Binit(&kbd, 0, OREAD);
|
||||||
|
while ((line = Brdstr(&kbd, '\n', 0)) != nil) {
|
||||||
|
n = utflen(line);
|
||||||
|
if(!inacme) {
|
||||||
|
p = malloc(n);
|
||||||
|
for (i = 0; i < n; ++i)
|
||||||
|
p[i] = '\b';
|
||||||
|
write(scr, p, i);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
qlock(&lck);
|
||||||
|
if (!usrparse(line, &cmd, par, 2)) {
|
||||||
|
switch(cmd) {
|
||||||
|
case 'q': /* quote, just send the params ... */
|
||||||
|
if(par[0]) {
|
||||||
|
fprint(server_out, "%s %s\r\n", par[0], par[1] ? par[1] : "");
|
||||||
|
} else {
|
||||||
|
fprint(scr, "/q %s %s: not enough arguments\n", par[0], par[1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
if(par[0] && par[1]) {
|
||||||
|
fprint(server_out, "MODE %s %s\r\n", par[0], par[1]);
|
||||||
|
} else {
|
||||||
|
fprint(scr, "/M %s %s: not enough arguments\n", par[0], par[1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if(par[0] && par[1]) {
|
||||||
|
fprint(server_out, "PRIVMSG %s :%s\r\n", par[0], par[1]);
|
||||||
|
} else {
|
||||||
|
fprint(scr, "/m %s %s: not enough arguments\n", par[0], par[1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if(par[0] != nil) {
|
||||||
|
free(victim);
|
||||||
|
victim = strdup(par[0]);
|
||||||
|
setwintitle(par[0]);
|
||||||
|
}
|
||||||
|
fprint(scr, "*** default victim set to '%s'\n", par[0]);
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
if(par[0] == nil)
|
||||||
|
fprint(server_out, "TOPIC %s\r\n", victim);
|
||||||
|
else if(par[1] == nil)
|
||||||
|
fprint(server_out, "TOPIC %s\r\n", par[0]);
|
||||||
|
else
|
||||||
|
fprint(server_out, "TOPIC %s :%s\r\n", par[0], par[1]);
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
fprint(server_out, "JOIN %s\r\n", par[0] == nil ? victim : par[0]);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
fprint(server_out, "PART %s\r\n", par[0] == nil ? victim : par[0]);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
if(par[0] != nil) {
|
||||||
|
fprint(server_out, "NICK %s\r\n", par[0]);
|
||||||
|
free(nick);
|
||||||
|
nick = strdup(par[0]);
|
||||||
|
} else {
|
||||||
|
fprint(scr, "%s", help);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
if(par[1] != nil)
|
||||||
|
fprint(server_out, "NOTICE %s :%s\r\n", par[0] == nil ? victim : par[0], par[1]);
|
||||||
|
break;
|
||||||
|
case 'W':
|
||||||
|
fprint(server_out, "WHOIS %s %s\r\n", par[0] == nil ? victim : par[0], par[0]);
|
||||||
|
case 'w':
|
||||||
|
fprint(server_out, "WHO %s\r\n", par[0] == nil ? victim : par[0]);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
fprint(server_out, "LIST %s\r\n", par[0] == nil ? victim : par[0]);
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
fprint(server_out, "NAMES %s\r\n", par[0] == nil ? victim : par[0]);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
fprint(scr, "%s", help);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprint(scr, "%s", help);
|
||||||
|
}
|
||||||
|
qunlock(&lck);
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timestamp(char *logtime, char *scrtime, int maxlen)
|
||||||
|
{
|
||||||
|
static char *wday[] = {
|
||||||
|
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
|
||||||
|
};
|
||||||
|
static char *mon[] = {
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||||
|
};
|
||||||
|
static int day = 0;
|
||||||
|
Tm *t;
|
||||||
|
|
||||||
|
t = localtime(atol(logtime));
|
||||||
|
|
||||||
|
if (t->mday != day) {
|
||||||
|
day = t->mday;
|
||||||
|
fprint(scr, "-- %s, %02d %s %d --\n",
|
||||||
|
wday[t->wday], t->mday, mon[t->mon],
|
||||||
|
t->year + 1900);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprint(scrtime, maxlen, "%02d:%02d:%02d",
|
||||||
|
t->hour, t->min, t->sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
srvin(void)
|
||||||
|
{
|
||||||
|
char *line;
|
||||||
|
char *time, *pre, *cmd, *par[NPAR];
|
||||||
|
char scrtime[32];
|
||||||
|
Biobuf srv;
|
||||||
|
Binit(&srv, server_in, OREAD);
|
||||||
|
|
||||||
|
while ((line = Brdstr(&srv, '\n', 0)) != nil) {
|
||||||
|
if (!srvparse(line, &time, &pre, &cmd, par, NPAR)) {
|
||||||
|
Handler *hp = handlers;
|
||||||
|
qlock(&lck);
|
||||||
|
timestamp(time, scrtime, sizeof(scrtime));
|
||||||
|
while (hp->cmd != nil) {
|
||||||
|
if (!strcmp(hp->cmd, cmd)) {
|
||||||
|
hp->fun(server_out, scrtime, pre, cmd, par);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++hp;
|
||||||
|
}
|
||||||
|
if (hp->cmd == nil)
|
||||||
|
generic(server_out, scrtime, pre, cmd, par);
|
||||||
|
qunlock(&lck);
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
replayfile(void)
|
||||||
|
{
|
||||||
|
char *line;
|
||||||
|
char *time, *pre, *cmd, *par[NPAR];
|
||||||
|
char scrtime[32];
|
||||||
|
Biobuf srv;
|
||||||
|
Binit(&srv, server_in, OREAD);
|
||||||
|
|
||||||
|
while ((line = Brdstr(&srv, '\n', 0)) != nil) {
|
||||||
|
if (!srvparse(line, &time, &pre, &cmd, par, NPAR)) {
|
||||||
|
Handler *hp = handlers;
|
||||||
|
qlock(&lck);
|
||||||
|
timestamp(time, scrtime, sizeof(scrtime));
|
||||||
|
while (hp->cmd != nil) {
|
||||||
|
if (!strcmp(hp->cmd, cmd)) {
|
||||||
|
hp->fun(server_out, scrtime, pre, cmd, par);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++hp;
|
||||||
|
}
|
||||||
|
if (hp->cmd == nil)
|
||||||
|
generic(server_out, scrtime, pre, cmd, par);
|
||||||
|
qunlock(&lck);
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* display the last N lines from the conversation
|
||||||
|
* if we have a default target only the conversation with
|
||||||
|
* that target will be shown
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
seekback(int fd, int lines)
|
||||||
|
{
|
||||||
|
Biobuf srv;
|
||||||
|
int found = 0, off;
|
||||||
|
char c, *line;
|
||||||
|
|
||||||
|
if(lines < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Binit(&srv, fd, OREAD);
|
||||||
|
|
||||||
|
Bseek(&srv, -2, 2);
|
||||||
|
while(((off = Boffset(&srv)) > 0) && found < lines) {
|
||||||
|
c = Bgetc(&srv);
|
||||||
|
Bungetc(&srv);
|
||||||
|
if(c == '\n') {
|
||||||
|
Bseek(&srv, 1, 1);
|
||||||
|
line = Brdstr(&srv, '\n', '\0');
|
||||||
|
if(victim) {
|
||||||
|
if(cistrstr(line, victim))
|
||||||
|
found++;
|
||||||
|
} else {
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
Bseek(&srv, off-1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bterm(&srv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *charset = nil;
|
||||||
|
char buf[32], buf2[32], *out = nil, *in = nil;
|
||||||
|
char *arg;
|
||||||
|
int sb = 10; /* how many lines are we displaying initially */
|
||||||
|
int uipid;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 't':
|
||||||
|
victim = strdup(EARGF(usage()));
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
arg = ARGF();
|
||||||
|
if(arg != nil && arg[0] != '-')
|
||||||
|
sb = atoi(arg);
|
||||||
|
else
|
||||||
|
sb = 0; /* show all text */
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
charset = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
replay = 1;
|
||||||
|
sb = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND;
|
||||||
|
|
||||||
|
switch(argc) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(replay)
|
||||||
|
in = argv[0];
|
||||||
|
else
|
||||||
|
out = argv[0];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
out = argv[0];
|
||||||
|
in = argv[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(out == nil) {
|
||||||
|
out = getuser();
|
||||||
|
if(strlen(out) > 4)
|
||||||
|
out[4] = 0;
|
||||||
|
snprint(buf, sizeof buf, "/srv/%sirc", out);
|
||||||
|
out = buf;
|
||||||
|
}
|
||||||
|
if(in == nil) {
|
||||||
|
in = getuser();
|
||||||
|
if(strlen(in) > 4)
|
||||||
|
in[4] = 0;
|
||||||
|
snprint(buf2, sizeof buf2, "/tmp/%sirc", in);
|
||||||
|
in = buf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!replay && (server_out = open(out, OWRITE)) < 0)
|
||||||
|
sysfatal("open write: %s %r", out);
|
||||||
|
if ((server_in = open(in, OREAD)) < 0)
|
||||||
|
sysfatal("open read: %s %r", in);
|
||||||
|
|
||||||
|
inacme = testacme();
|
||||||
|
getwidth();
|
||||||
|
|
||||||
|
if(sb)
|
||||||
|
seekback(server_in, sb);
|
||||||
|
|
||||||
|
while(read(server_in, buf, 1) > 0)
|
||||||
|
if(*buf == '\n')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(victim && cistrncmp(victim, "MSGS", 4)){
|
||||||
|
setwintitle(victim);
|
||||||
|
fprint(server_out, "JOIN %s\r\n", victim);
|
||||||
|
}
|
||||||
|
scr = 1;
|
||||||
|
|
||||||
|
server_in = follow(server_in);
|
||||||
|
|
||||||
|
if (charset != nil && strcmp(charset, "utf")) {
|
||||||
|
server_out = wtcs(server_out, charset);
|
||||||
|
server_in = rtcs(server_in, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(replay) {
|
||||||
|
replayfile();
|
||||||
|
} else {
|
||||||
|
if ((uipid = rfork(RFPROC|RFFDG|RFMEM)) == 0)
|
||||||
|
srvin();
|
||||||
|
|
||||||
|
usrin();
|
||||||
|
|
||||||
|
postnote(PNPROC, uipid, "kill");
|
||||||
|
while (waitpid() != uipid);
|
||||||
|
}
|
||||||
|
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wtcs(int fd, char *cset)
|
||||||
|
{
|
||||||
|
int totcs[2];
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
pipe(totcs);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
dup(totcs[0], 0);
|
||||||
|
dup(fd, 1);
|
||||||
|
close(totcs[1]);
|
||||||
|
execl("/bin/tcs", "tcs", "-f", "utf", "-t", cset, nil);
|
||||||
|
exits("execfailure");
|
||||||
|
}
|
||||||
|
close(totcs[0]);
|
||||||
|
|
||||||
|
return totcs[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rtcs(int fd, char *cset)
|
||||||
|
{
|
||||||
|
int fromtcs[2];
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
pipe(fromtcs);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
|
||||||
|
if (pid == 0){
|
||||||
|
dup(fromtcs[1], 1);
|
||||||
|
dup(fd, 0);
|
||||||
|
close(fromtcs[0]);
|
||||||
|
execl("/bin/tcs", "tcs", "-f", cset, "-t", "utf", nil);
|
||||||
|
exits("execfailure");
|
||||||
|
}
|
||||||
|
close(fromtcs[1]);
|
||||||
|
|
||||||
|
return fromtcs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
follow(int fd)
|
||||||
|
{
|
||||||
|
int p[2], pid;
|
||||||
|
long n;
|
||||||
|
char buf[1024];
|
||||||
|
Dir *dp;
|
||||||
|
|
||||||
|
pipe(p);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == 0){
|
||||||
|
dup(p[1], 1);
|
||||||
|
dup(fd, 0);
|
||||||
|
close(p[0]);
|
||||||
|
for(;;){
|
||||||
|
while((n = read(0, buf, sizeof(buf))) > 0)
|
||||||
|
write(1, buf, n);
|
||||||
|
sleep(1000);
|
||||||
|
dp = dirfstat(0);
|
||||||
|
free(dp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(p[1]);
|
||||||
|
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
prenick(char *p)
|
||||||
|
{
|
||||||
|
char *n = p;
|
||||||
|
if (p != nil) {
|
||||||
|
while (*p != '\0' && *p != '!') ++p;
|
||||||
|
if (*p != '!')
|
||||||
|
n = nil;
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pmsg(int, char *time, char *pre, char *, char *par[])
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
char *buf;
|
||||||
|
char *c, *tc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if sent to victim, or comes from victim to non-channel, print.
|
||||||
|
* otherwise bail out.
|
||||||
|
*/
|
||||||
|
pre = prenick(pre);
|
||||||
|
if(victim) {
|
||||||
|
if((cistrncmp(victim, "MSGS", 4) == 0) && *par[0] != '#') {
|
||||||
|
/* catch-all for messages, fall through */
|
||||||
|
|
||||||
|
} else if(cistrcmp(par[0], victim))
|
||||||
|
if(!pre || cistrcmp(pre, victim) || *par[0] == '#')
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!pre)
|
||||||
|
buf = smprint("%s (%s) ⇐ %s\n", time, par[0], par[1]);
|
||||||
|
else if(*par[0] != '#')
|
||||||
|
buf = smprint("%s (%s) ⇒ %s\n", time, pre, par[1]);
|
||||||
|
else
|
||||||
|
buf = smprint("%s %s → %s\n", time, pre, par[1]);
|
||||||
|
|
||||||
|
if(!buf)
|
||||||
|
sysfatal("failed to allocate space for message: %r\n");
|
||||||
|
|
||||||
|
c = buf;
|
||||||
|
again:
|
||||||
|
if(strlen(c) >= linewidth) {
|
||||||
|
for(tc = c + linewidth; tc > c; tc--) {
|
||||||
|
switch(*tc) {
|
||||||
|
case ' ':
|
||||||
|
*tc = '\0';
|
||||||
|
n += fprint(scr, "%s\n", c);
|
||||||
|
c = tc+1;
|
||||||
|
goto again;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n += fprint(scr, "%s", c);
|
||||||
|
free(buf);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ntc(int, char *time, char *pre, char *, char *par[])
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if sent to victim, or comes from victim to non-channel, print.
|
||||||
|
* otherwise bail out.
|
||||||
|
*/
|
||||||
|
pre = prenick(pre);
|
||||||
|
if(victim && cistrcmp(par[0], victim))
|
||||||
|
if(!pre || cistrcmp(pre, victim) || *par[0] == '#')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!pre)
|
||||||
|
n = fprint(scr, "%s [%s] ⇐\t%s\n", time, par[0], par[1]);
|
||||||
|
else if(*par[0] != '#')
|
||||||
|
n = fprint(scr, "%s [%s] ⇒\t%s\n", time, pre, par[1]);
|
||||||
|
else
|
||||||
|
n = fprint(scr, "%s [%s] %s →\t%s\n", time, par[0], pre, par[1]);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
generic(int, char *time, char *pre, char *cmd, char *par[])
|
||||||
|
{
|
||||||
|
int i = 0, r;
|
||||||
|
char *nick = prenick(pre);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't print crud on screens with victim set
|
||||||
|
*/
|
||||||
|
if(victim)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (nick != nil)
|
||||||
|
r = fprint(scr, "%s %s (%s)\t", time, cmd, nick);
|
||||||
|
else
|
||||||
|
r = fprint(scr, "%s %s (%s)\t", time, cmd, par[i++]);
|
||||||
|
|
||||||
|
for (; par[i] != nil; ++i)
|
||||||
|
r += fprint(scr, " %s", par[i]);
|
||||||
|
|
||||||
|
r += fprint(scr, "\n");
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
misc(int, char *time, char *pre, char *cmd, char *par[])
|
||||||
|
{
|
||||||
|
int i = 0, r;
|
||||||
|
char *nick = prenick(pre);
|
||||||
|
|
||||||
|
if(cistrcmp(cmd,"QUIT"))
|
||||||
|
if(victim && par[0] && cistrcmp(par[0], victim))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (nick != nil)
|
||||||
|
r = fprint(scr, "%s %s (%s)\t", time, cmd, nick);
|
||||||
|
else
|
||||||
|
r = fprint(scr, "%s %s %s\t", time, cmd, par[i++]);
|
||||||
|
|
||||||
|
for (; par[i] != nil; ++i)
|
||||||
|
r += fprint(scr, " %s", par[i]);
|
||||||
|
|
||||||
|
r += fprint(scr, "\n");
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
numeric(int, char *time, char *pre, char *cmd, char *par[])
|
||||||
|
{
|
||||||
|
int i = 0, r;
|
||||||
|
char *nick = prenick(pre);
|
||||||
|
|
||||||
|
if(victim && par[1] && cistrcmp(par[1], victim))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (nick != nil)
|
||||||
|
r = fprint(scr, "%s %s (%s)\t", time, cmd, nick);
|
||||||
|
else
|
||||||
|
r = fprint(scr, "%s %s (%s)\t", time, cmd, par[i++]);
|
||||||
|
|
||||||
|
for (; par[i] != nil; ++i)
|
||||||
|
r += fprint(scr, " %s", par[i]);
|
||||||
|
|
||||||
|
r += fprint(scr, "\n");
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
usrparse(char *ln, char *cmd, char *par[], int npar)
|
||||||
|
{
|
||||||
|
enum state st = Cmd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < npar; i++)
|
||||||
|
par[i] = nil;
|
||||||
|
|
||||||
|
if (ln[0] == '/' && npar >= 2) {
|
||||||
|
*cmd = ln[1];
|
||||||
|
for (i = 1; ln[i] != '\0'; ++i) {
|
||||||
|
switch(st) {
|
||||||
|
case Cmd:
|
||||||
|
if (ln[i] == ' ') {
|
||||||
|
ln[i] = '\0';
|
||||||
|
par[0] = ln+i+1;
|
||||||
|
st = Middle;
|
||||||
|
} else if(ln[i] == '\n') {
|
||||||
|
/* enable commands with no arguments */
|
||||||
|
ln[i] = '\0';
|
||||||
|
par[0] = nil;
|
||||||
|
par[1] = nil;
|
||||||
|
st = Ok;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Middle:
|
||||||
|
if (ln[i] == '\r' || ln[i] == '\n') {
|
||||||
|
ln[i] = '\0';
|
||||||
|
st = Ok;
|
||||||
|
}
|
||||||
|
if (ln[i] == ' ') {
|
||||||
|
ln[i] = '\0';
|
||||||
|
par[1] = ln+i+1;
|
||||||
|
st = Trail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Trail:
|
||||||
|
if (ln[i] == '\r' || ln[i] == '\n') {
|
||||||
|
ln[i] = '\0';
|
||||||
|
st = Ok;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Ok:
|
||||||
|
if (ln[i] == '\r' || ln[i] == '\n')
|
||||||
|
ln[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { /* send line to victim by default */
|
||||||
|
st = Ok;
|
||||||
|
*cmd = 'm';
|
||||||
|
for (i = 0; ln[i] != '\0'; ++i)
|
||||||
|
if (ln[i] == '\r' || ln[i] == '\n')
|
||||||
|
ln[i] = '\0';
|
||||||
|
par[0] = victim;
|
||||||
|
par[1] = ln;
|
||||||
|
}
|
||||||
|
return st == Ok ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
srvparse(char *line, char **time, char **pre, char **cmd, char *par[], int npar)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
enum state st = Time;
|
||||||
|
|
||||||
|
*time = *pre = *cmd = nil;
|
||||||
|
|
||||||
|
for (*time = p = line, i = 0; *p != '\0'; ++p) {
|
||||||
|
switch (st) {
|
||||||
|
case Time:
|
||||||
|
if (*p == ' ') {
|
||||||
|
*p = '\0';
|
||||||
|
*cmd = p + 1;
|
||||||
|
st = Cmd;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Cmd:
|
||||||
|
if (*p == ':') {
|
||||||
|
*p = '\0';
|
||||||
|
*pre = p + 1;
|
||||||
|
st = Prefix;
|
||||||
|
} else if (*p == ' ') {
|
||||||
|
*p = '\0';
|
||||||
|
par[i] = p + 1;
|
||||||
|
st = Middle;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Prefix:
|
||||||
|
if (*p == ' ') {
|
||||||
|
*p = '\0';
|
||||||
|
*cmd = p + 1;
|
||||||
|
st = Cmd;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Middle:
|
||||||
|
if (*p == '\r' || *p == '\n') {
|
||||||
|
*p = '\0';
|
||||||
|
st = Ok;
|
||||||
|
} else if (*p == ':') {
|
||||||
|
*p = '\0';
|
||||||
|
par[i] = p + 1;
|
||||||
|
st = Trail;
|
||||||
|
} else if (*p == ' ') {
|
||||||
|
*p = '\0';
|
||||||
|
i = (i + 1) % npar;
|
||||||
|
par[i] = p + 1;
|
||||||
|
st = Middle;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Trail:
|
||||||
|
if (*p == '\r' || *p == '\n') {
|
||||||
|
*p = '\0';
|
||||||
|
st = Ok;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Ok:
|
||||||
|
*p = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
par[(i + 1) % npar] = nil;
|
||||||
|
return st == Ok ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
getwidth(void)
|
||||||
|
{
|
||||||
|
Font *font;
|
||||||
|
int n, fd, mintab;
|
||||||
|
char buf[128], *f[10], *p;
|
||||||
|
|
||||||
|
if(inacme){
|
||||||
|
if((fd = open("/dev/acme/ctl", OREAD)) < 0)
|
||||||
|
return;
|
||||||
|
n = read(fd, buf, sizeof buf-1);
|
||||||
|
close(fd);
|
||||||
|
if(n <= 0)
|
||||||
|
return;
|
||||||
|
buf[n] = 0;
|
||||||
|
n = tokenize(buf, f, nelem(f));
|
||||||
|
if(n < 7)
|
||||||
|
return;
|
||||||
|
if((font = openfont(nil, f[6])) == nil)
|
||||||
|
return;
|
||||||
|
mintab = stringwidth(font, "0");
|
||||||
|
linewidth = atoi(f[5]);
|
||||||
|
linewidth = linewidth/mintab;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((p = getenv("font")) == nil)
|
||||||
|
return;
|
||||||
|
if((font = openfont(nil, p)) == nil)
|
||||||
|
return;
|
||||||
|
if((fd = open("/dev/window", OREAD)) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
n = read(fd, buf, 5*12);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if(n < 5*12)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf[n] = 0;
|
||||||
|
|
||||||
|
/* window stucture:
|
||||||
|
4 bit left edge
|
||||||
|
1 bit gap
|
||||||
|
12 bit scrollbar
|
||||||
|
4 bit gap
|
||||||
|
text
|
||||||
|
4 bit right edge
|
||||||
|
*/
|
||||||
|
linewidth = atoi(buf+3*12) - atoi(buf+1*12) - (4+1+12+4+4);
|
||||||
|
mintab = stringwidth(font, "0");
|
||||||
|
linewidth = linewidth/mintab;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
enum {
|
||||||
|
Pmsg, /* private message */
|
||||||
|
Smsg, /* server message */
|
||||||
|
Nmsg, /* notice */
|
||||||
|
Lmsg, /* message sent by the client to server */
|
||||||
|
Cmd, /* some other event such as a quit/join */
|
||||||
|
Err = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Line Line;
|
||||||
|
struct Line
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
char *from; /* who sent the message, can be nil for server messages */
|
||||||
|
char *uhost; /* host where the message came from */
|
||||||
|
int mid; /* message id for server messages
|
||||||
|
char *to; /* target for the message */
|
||||||
|
char *cmd; /* JOIN/QUIT, etc. may be nil */
|
||||||
|
char *text; /* message text */
|
||||||
|
};
|
||||||
|
#pragma varargck type "L" Line*
|
||||||
|
|
||||||
|
void setwintitle(char *chan);
|
||||||
|
|
||||||
|
int rtcs(int fd, char *cset);
|
||||||
|
int wtcs(int fd, char *cset);
|
||||||
|
int follow(int fd);
|
||||||
|
|
||||||
|
int pmsg(int fd, char *pre, char *cmd, char *par[]);
|
||||||
|
int ntc(int fd, char *pre, char *cmd, char *par[]);
|
||||||
|
int generic(int fd, char *pre, char *cmd, char *par[]);
|
||||||
|
int misc(int fd, char *pre, char *cmd, char *par[]);
|
||||||
|
int numeric(int fd, char *pre, char *cmd, char *par[]);
|
||||||
|
|
||||||
|
#define dprint if(debug) print
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
.TH IRC 1
|
||||||
|
.SH NAME
|
||||||
|
ircsrv, irc \- internet relay chat client and ui
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B ircsrv
|
||||||
|
[
|
||||||
|
.I -s serv
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I -f file
|
||||||
|
]
|
||||||
|
.I nickname
|
||||||
|
.I [tcp!]irc.server.org
|
||||||
|
.br
|
||||||
|
.B irc
|
||||||
|
[
|
||||||
|
.I -e
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I -c charset
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I -t victim
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I -b lines
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I -r file
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I -p password
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I /srv/serv
|
||||||
|
[
|
||||||
|
.I /tmp/file
|
||||||
|
]]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.I Ircsrv
|
||||||
|
makes a connection to an irc server and reconnects if the connection
|
||||||
|
gets broken. It posts a service to /srv and creates (if necessary) an
|
||||||
|
append mode log file to /tmp. Default file and service name is a
|
||||||
|
concatenation of 4 first letters of username and the string
|
||||||
|
.I irc
|
||||||
|
.
|
||||||
|
.PP
|
||||||
|
.I Irc
|
||||||
|
is a client program that makes use of the service provided by
|
||||||
|
.I ircsrv
|
||||||
|
and provides a user interface for sending and receiving
|
||||||
|
messages.
|
||||||
|
.PP
|
||||||
|
The command language understood by
|
||||||
|
.I irc
|
||||||
|
is as follows
|
||||||
|
.EX
|
||||||
|
/h this message
|
||||||
|
/H this message
|
||||||
|
/m privmsg #chan/nick message
|
||||||
|
/M mode #chan +nt
|
||||||
|
/j join [ #chan ]
|
||||||
|
/p part [ #chan ]
|
||||||
|
/q send parameters raw to the server
|
||||||
|
/l list [ #chan ]
|
||||||
|
/n nick newnick
|
||||||
|
/N notice #chan/nick message
|
||||||
|
/t set [ victim ]
|
||||||
|
/T topic [ #chan [ newtopic ]]
|
||||||
|
/W whois nick
|
||||||
|
/w who nick (a shorter whois)
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.I -e
|
||||||
|
flag enables SSL, the
|
||||||
|
.I -c
|
||||||
|
flag sets character set conversion using
|
||||||
|
.IR tcs (1),
|
||||||
|
the
|
||||||
|
.I -r
|
||||||
|
flag will cause irc to replay the conversation from the raw file supplied as argument without user interaction,
|
||||||
|
the
|
||||||
|
.I -b
|
||||||
|
flag causes the client to display the last n lines of the default target or
|
||||||
|
conversations if no target is set. Without any arguments
|
||||||
|
.I -b
|
||||||
|
prints the conversation from the very beginning.
|
||||||
|
The
|
||||||
|
.I -t
|
||||||
|
flag sets the default target to which the messages are
|
||||||
|
sent by default if a line written to
|
||||||
|
.I irc
|
||||||
|
does not begin with /. Irc also prints messages to/from
|
||||||
|
the target exclusively if one is set. Irc prints only private messages if the target is set to "MSGS", useful for being notified when a message is sent to your nick without having to monitor all the status information.
|
||||||
|
.SH EXAMPLES
|
||||||
|
To start up ircsrv on a remote cpu server
|
||||||
|
.EX
|
||||||
|
cpu -c ircsrv glenda irc.freenode.net
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
To use ircsrv started earlier on a cpu server
|
||||||
|
.EX
|
||||||
|
import $cpu /srv
|
||||||
|
import $cpu /tmp
|
||||||
|
irc
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
To start/see/continue a conversation with a specific target (can be #chan or nick)
|
||||||
|
.EX
|
||||||
|
irc -t \'#plan9\'
|
||||||
|
irc -t f2f
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
To run irc within acme start irc inside
|
||||||
|
"win -e":
|
||||||
|
.EX
|
||||||
|
win -e
|
||||||
|
irc -t f2f
|
||||||
|
.EE
|
||||||
|
.SH SOURCE
|
||||||
|
/sys/src/cmd/ircsrv.c
|
||||||
|
.br
|
||||||
|
/sys/src/cmd/irc.c
|
||||||
|
.SH SEE ALSO
|
||||||
|
.IR tcs (1),
|
||||||
|
.IR faces (1),
|
||||||
|
.IR nedmail (1)
|
||||||
|
.SH BUGS
|
||||||
|
Probably. Missing functionality includes opening new windows when a
|
||||||
|
message from a new target arrives.
|
Binary file not shown.
|
@ -0,0 +1,255 @@
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
</$objtype/mkfile
|
||||||
|
MAN=/sys/man/1
|
||||||
|
|
||||||
|
TARG=\
|
||||||
|
irc\
|
||||||
|
ircsrv\
|
||||||
|
|
||||||
|
BIN=/$objtype/bin
|
||||||
|
|
||||||
|
</sys/src/cmd/mkmany
|
||||||
|
|
||||||
|
ircman:V:
|
||||||
|
cp irc.man /sys/man/1/irc
|
||||||
|
|
||||||
|
install: ircman
|
Loading…
Reference in New Issue