#include #include #include #include "hash.h" #include "client.h" #include "channel.h" #include "hermes.h" #include "msg.h" #include "handler.h" static int handlenick(Client *c, Msg *m) { int i, j; HashItem *hi, *hj; Hash *inform; char oldnick[128]; IrcChannel *ch; Client *to; if(m->nargs != 1) return -1; if(findnick(m->args[0]) != nil){ csend(c->io, c, ":%s 433 %s :%s", myname, m->args[0], "nickname already in use"); return -1; } qlock(c); strcpy(oldnick, c->nick); strncpy(c->nick, m->args[0], sizeof(c->nick)-1); if(c->nick[0] != 0 && c->user[0] != 0){ if(oldnick[0] != 0){ csend(c->io, c, ":%s!%s@%s NICK :%s", oldnick, c->user, c->info->rsys, c->nick); inform = newhash(); /* gather list of people to inform about nick change */ qlock(chanhash); for(i = 0; i < chanhash->sz; i++){ for(hi = chanhash->items[i]; hi != nil; hi = hi->next){ ch = (IrcChannel*)hi; qlock(ch); /* if the user isn't on the channel, skip */ if(gethash(ch->users, c->nick) == nil){ qunlock(ch); continue; } for(j = 0; j < ch->users->sz; j++){ for(hj = ch->users->items[j]; hj != nil; hj = hj->next){ to = (Client*)hj; /* if it's us, skip */ if(to == c) continue; /* puthash( qlock(to); csend(c->io, to, ":%s!%s@%s NICK :%s", oldnick, c->user, c->info->rsys, c->nick); qunlock(to); */ } } qunlock(ch); } } qunlock(chanhash); freehash(inform); } if(c->greeted == 0){ qlock(clnthash); if(gethash(clnthash, c->nick) != nil) delhash(clnthash, c->nick); puthash(clnthash, c->nick, c); qunlock(clnthash); cmotd(c); c->greeted++; dbg("connected"); } } qunlock(c); return 0; } static int handleuser(Client *c, Msg *m) { if(m->nargs != 4) return -1; qlock(c); strncpy(c->user, m->args[0], sizeof(c->user)-1); strncpy(c->real, m->args[3], sizeof(c->real)-1); if(c->nick[0] != 0 && c->user[0] != 0 && c->greeted == 0){ qlock(clnthash); if(gethash(clnthash, c->nick) != nil) delhash(clnthash, c->nick); puthash(clnthash, c->nick, c); qunlock(clnthash); cmotd(c); c->greeted++; dbg("connected"); } qunlock(c); return 0; } static int handleping(Client *c, Msg *m) { if(m->nargs != 1) return -1; csend(c->io, c, ":%s PONG %s %s", myname, myname, m->args[0]); return 0; } static int handleprivmsg(Client *c, Msg *m) { int i; HashItem *hi; Client *to; IrcChannel *ch; if(m->nargs != 2) return -1; to = findnick(m->args[0]); if(to != nil){ qlock(c); csend(c->io, to, ":%s!%s@%s PRIVMSG %s :%s", c->nick, c->user, c->info->rsys, m->args[0], m->args[1]); qunlock(c); return 0; } ch = findchannel(m->args[0]); if(ch != nil){ qlock(ch); for(i = 0; i < ch->users->sz; i++){ for(hi = ch->users->items[i]; hi != nil; hi = hi->next){ to = (Client*)hi; if(to == c) continue; qlock(c); csend(c->io, to, ":%s!%s@%s PRIVMSG %s :%s", c->nick, c->user, c->info->rsys, m->args[0], m->args[1]); qunlock(c); } } qunlock(ch); return 0; } qlock(c); csend(c->io, c, ":%s 401 %s %s :no such nick/channel", myname, c->nick, m->args[0]); qunlock(c); return -1; } static int handlejoin(Client *c, Msg *m) { int i, nuser; char cnick[128], userlist[512]; HashItem *hi; IrcChannel *ch; Client *to; if(m->nargs != 1) return -1; if(strlen(m->args[0]) < 2 || m->args[0][0] != '#') return -1; qlock(c); strcpy(cnick, c->nick); qunlock(c); qlock(chanhash); ch = gethash(chanhash, m->args[0]); if(ch == nil){ ch = mkircchannel(m->args[0]); puthash(chanhash, ch->name, ch); } qlock(ch); qunlock(chanhash); if(gethash(ch->users, cnick) != nil){ // already on channel qunlock(ch); return -1; } puthash(ch->users, cnick, c); nuser = 0; userlist[0] = 0; for(i = 0; i < ch->users->sz; i++){ for(hi = ch->users->items[i]; hi != nil; hi = hi->next){ if(nuser > 0 && nuser < ch->users->sz - 1) strcat(userlist, " "); to = (Client*)hi; qlock(to); strcat(userlist, to->nick); qunlock(to); nuser++; } } qlock(c); for(i = 0; i < ch->users->sz; i++){ for(hi = ch->users->items[i]; hi != nil; hi = hi->next){ to = (Client*)hi; csend(c->io, to, ":%s!%s@%s JOIN %s", c->nick, c->user, c->info->rsys, m->args[0]); } } csend(c->io, c, ":%s 353 = %s :%s", myname, m->args[0], userlist); csend(c->io, c, ":%s 366 %s :end of names", myname, m->args[0]); puthash(c->channels, m->args[0], ch); qunlock(c); qunlock(ch); return 0; } static int handlepart(Client *c, Msg *m) { int i; char cnick[128]; HashItem *hi; IrcChannel *ch; Client *to; if(m->nargs != 2) return -1; if(strlen(m->args[0]) < 2 || m->args[0][0] != '#') return -1; qlock(c); strcpy(cnick, c->nick); qunlock(c); qlock(chanhash); ch = gethash(chanhash, m->args[0]); if(ch == nil){ qunlock(chanhash); return -1; } qlock(ch); qunlock(chanhash); if(gethash(ch->users, cnick) == nil){ qunlock(ch); return -1; } qlock(c); for(i = 0; i < ch->users->sz; i++){ for(hi = ch->users->items[i]; hi != nil; hi = hi->next){ to = (Client*)hi; csend(c->io, to, ":%s!%s@%s PART %s :%s", c->nick, c->user, c->info->rsys, m->args[0], m->args[1]); } } delhash(c->channels, m->args[0]); qunlock(c); delhash(ch->users, cnick); qunlock(ch); return 0; } static struct { char *cmd; msghandler handle; } handlers[] = { {"nick", handlenick}, {"user", handleuser}, {"ping", handleping}, {"privmsg", handleprivmsg}, {"join", handlejoin}, {"part", handlepart}, }; int handlemsg(Client *c, Msg *m) { int i; for(i = 0; i < nelem(handlers); i++){ if(strcmp(m->cmd, handlers[i].cmd) == 0){ dbg("%s %s -> %s", c->nick, m->cmd, m->args[0]); return handlers[i].handle(c, m); } } return -1; }