ref: c86384b841687ea975571db934fb0e353ce5b5d4
dir: /cmd.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "fns.h" #include "cmd.h" #include "ll.h" #include "version.h" static char channelprefix[] = "&#+!"; typedef struct AuxArgs AuxArgs; struct AuxArgs { IChan *channel; Client *client; char *str; }; static void cversion(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.4.3) */ if (r->args[0]) { fprint(2, "get version of '%s' (not implemented yet!)\n", r->args[0]); reply(c, Enosuchserver, r->args[0]); return; } reply(c, Rversion, getversion()); } static void postconnect(Client *c) { reply(c, Rwelcome, c); reply(c, Ryourhost, sysnameb, Vversion); reply(c, Rcreated, "sometime"); // TODO reply(c, Rmyinfo, sysnameb, Vversion, "i", "ov"); reply(c, Rmotdstart, sysnameb); reply(c, Rmotd); reply(c, Rmotdend); } static void cuser(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.1.3) */ User *u; if (!r->args[3]) { reply(c, Eneedmoreparams, r->cmd->name); return; } u = finduser(r->args[0]); if (u) { reply(c, Ealreadyregistered); return; } u = adduser(r->args[0]); u->realname = strdup(r->args[3]); u->host = strdup(sysnameb); c->nick = strdup(r->args[0]); c->user = u; postconnect(c); } static void cnick(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.1.2) */ User *u; if (!r->args[0]) { reply(c, Enonicknamegiven); return; } if (findnick(r->args[0])) { reply(c, Enicknameinuse, r->args[0]); return; } c->nick = strdup(r->args[0]); u = finduser(r->args[0]); if (u) { reply(c, Enicknameinuse, r->args[0]); return; } u = adduser(r->args[0]); u->host = sysnameb; c->user = u; postconnect(c); } static void cwhois(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.6.2) */ // TODO: implement remaining replies: (/lib/rfc/rfc2812:/^3.6.2) int start = 0; char *server = nil; User *u; Client *cl; if (!r->args[0]) { reply(c, Enonicknamegiven); return; } if (r->args[1] && strcmp(r->args[1], ",")) { server = r->args[0]; start = 2; } for (int i = start; i < 15; i += 2) { /* args[i] is nick, args[i+1] is ',' */ if (!r->args[i]) break; if (!server) { cl = findnick(r->args[i]); if (cl) { u = cl->user; if (!u) goto Next; reply(c, Rwhoisuser, cl->nick, u->name, sysnameb, u->realname); } else reply(c, Enosuchnick, r->args[i]); } else { // TODO: forward to server: send message to server } Next: reply(c, Rendofwhois, r->args[i]); } } typedef struct A_privmsgsend A_privmsgsend; struct A_privmsgsend { char *msg; IChan *chan; Client *sender; }; static void acprivmsgsend(void *a, void *b) { Client *c = a; AuxArgs *args = b; if (c == args->client) return; ircsend(c, args->client, Sprivmsg, args->channel->name, args->str); } static void cprivmsg(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.3.1) */ Client *tgt; IChan *chan; AuxArgs args; if (!r->args[0] || r->args[0][0] == 0) { reply(c, Enorecipient, "PRIVMSG"); return; } if (!r->args[1] || r->args[1][0] == 0) { reply(c, Enotexttosend); return; } if (strchr(channelprefix, r->args[0][0])) { /* target is channel */ chan = findchannel(r->args[0]); if (!(chan && userinchannel(chan, c))) { reply(c, Ecannotsendtochan, r->args[0]); return; } args.channel = chan; args.str = r->args[1]; args.client = c; lforeach(&chan->users, acprivmsgsend, &args); return; } /* target is user */ tgt = findnick(r->args[0]); if (!tgt) { reply(c, Enosuchnick, r->args[0]); return; } if (tgt->away) { reply(c, Raway, r->args[0], tgt->away); return; } ircsend(tgt, c, Sprivmsg, r->args[0], r->args[1]); } static void caway(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^4.1) */ if (r->args[0]) { if (c->away) free(c->away); c->away = strdup(r->args[0]); reply(c, Rnowaway); return; } if (c->away) free(c->away); c->away = nil; reply(c, Runaway); } /* Aux Cmd function */ static void aclistnames(void *a, void *b) { Client *c = a; AuxArgs *ln = b; reply(ln->client, Rnamreply, '=', ln->channel->name, c->nick); } static void acsendjoin(void *cl, void *aux) { Client *c = cl; AuxArgs *a = aux; ircsend(c, a->client, Sjoin, a->channel->name); } static void cjoin(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.2.1) */ char *channel; IChan *ch; AuxArgs ln; char *chs[10]; int nch; if (!r->args[0] || r->args[0][0] == 0) { goto Err; } nch = getfields(r->args[0], chs, sizeof(chs), 1, ","); if (!nch) { goto Err; } for (int i = 0; i < nch; i++) { channel = chs[i]; ch = joinchannel(c, channel); ircsend(c, nil, Sjoin, channel); if (ch->topic) reply(c, Rtopic, channel, ch->topic); else reply(c, Rnotopic, channel); ln.client = c; ln.channel = ch; lforeach(&ch->users, aclistnames, &ln); reply(c, Rendofnames, channel); lforeach(&ch->users, acsendjoin, &ln); } return; Err: reply(c, Eneedmoreparams, "JOIN"); } static void acpart(void *a, void *b) { Client *c = a; AuxArgs *args = b; ircsend(c, args->client, Spart, args->str ? args->str : args->client->nick); } static void cpart(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.2.2) */ int i; char *msg; char *chs[10]; IChan *ch; int nch; AuxArgs args; if (!r->args[0] || r->args[0][0] == 0) { goto Err; } msg = nil; if (r->args[1] && r->args[1][0] != 0) msg = r->args[1]; nch = getfields(r->args[0], chs, sizeof(chs), 1, ","); if (!nch) { goto Err; } for (i = 0; i < nch; i++) { ch = findchannel(chs[i]); if (!ch) { reply(c, Enosuchchannel, chs[i]); } else { if (userinchannel(ch, c)) { args.channel = ch; args.client = c; args.str = msg; lforeach(&ch->users, acpart, &args); partchannel(ch, c); } else { reply(c, Enotonchannel, chs[i]); } } } return; Err: reply(c, Eneedmoreparams, "PART"); } static void cquit(Client *c, Request *r) { /* (/lib/rfc/rfc2812:/^3.1.7) */ USED(r); ircerror(c, "Bye"); if (c->user) deluser(c->user); if (c->nick) free(c->nick); if (c->away) free(c->away); c->nick = c->away = nil; c->user = nil; } static Command commands[] = { { "whois", cwhois }, { "version", cversion }, { "user", cuser }, { "nick", cnick }, { "privmsg", cprivmsg }, { "away", caway }, { "join", cjoin }, { "part", cpart }, { "quit", cquit }, }; int ncommands = sizeof(commands) / sizeof(Command); Command* findcommand(char *s) { for (int i = 0; i < ncommands; i++) { if (cistrcmp(commands[i].name, s) == 0) return &commands[i]; } return nil; } void execrequest(Client *c, Request r) { if (!(r.cmd && r.cmd->func)) { fprint(2, "cannot execute request: no command\n"); return; } if (debug) fprint(2, "run command '%s'\n", r.cmd->name); r.cmd->func(c, &r); }