#define CMD_EOB "END_OF_BURST"
#define CMD_EOB_ACK "EOB_ACK"
#define CMD_ERROR "ERROR"
+#define CMD_FAKEHOST "FAKE"
#define CMD_GET "GET"
#define CMD_GLINE "GLINE"
#define CMD_HASH "HASH"
#define TOK_EOB "EB"
#define TOK_EOB_ACK "EA"
#define TOK_ERROR "Y"
+#define TOK_FAKEHOST "FA"
#define TOK_GET "GET"
#define TOK_GLINE "GL"
#define TOK_HASH "HASH"
#define P10_EOB TYPE(EOB)
#define P10_EOB_ACK TYPE(EOB_ACK)
#define P10_ERROR TYPE(ERROR)
+#define P10_FAKEHOST TYPE(FAKEHOST)
#define P10_GET TYPE(GET)
#define P10_GLINE TYPE(GLINE)
#define P10_HASH TYPE(HASH)
static privmsg_func_t *notice_funcs;
static unsigned int num_notice_funcs;
static struct dict *unbursted_channels;
+static char *his_servername;
+static char *his_servercomment;
static struct userNode *AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip);
+extern int off_channel;
+
/* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
* server and Y's indentifying the client on that server. */
struct server*
putsock("%s " P10_ACCOUNT " %s %s", self->numeric, user->numeric, stamp);
}
+void
+irc_fakehost(struct userNode *user, const char *host)
+{
+ putsock("%s " P10_FAKEHOST " %s %s", self->numeric, user->numeric, host);
+}
+
void
irc_regnick(UNUSED_ARG(struct userNode *user))
{
putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message);
}
+void
+irc_notice_user(struct userNode *from, struct userNode *to, const char *message)
+{
+ putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message);
+}
+
void
irc_privmsg(struct userNode *from, const char *to, const char *message)
{
long last_mode=-1;
unsigned int n;
- if (!chan->members.used)
- return;
base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ",
self->numeric, chan->name, chan->timestamp);
len = irc_make_chanmode(chan, burst_line+base_len);
{
const char *numeric;
struct modeNode *mn = GetUserMode(channel, who);
- numeric = (mn && (mn->modes & MODE_CHANOP)) ? who->numeric : self->numeric;
+ numeric = ((mn && (mn->modes & MODE_CHANOP)) || off_channel) ? who->numeric : self->numeric;
putsock("%s " P10_KICK " %s %s :%s",
numeric, channel->name, target->numeric, msg);
}
}
}
+static CMD_FUNC(cmd_whois)
+{
+ struct userNode *from;
+ struct userNode *who;
+
+ if (argc < 3)
+ return 0;
+ if (!(from = GetUserH(origin))) {
+ log_module(MAIN_LOG, LOG_ERROR, "Could not find WHOIS origin user %s", origin);
+ return 0;
+ }
+ if(!(who = GetUserH(argv[2]))) {
+ irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name);
+ return 1;
+ }
+ if (IsHiddenHost(who) && !IsOper(from)) {
+ /* Just stay quiet. */
+ return 1;
+ }
+ irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
+ if (his_servername && his_servercomment)
+ irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
+ else
+ irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description);
+ if (IsOper(who))
+ irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick);
+ irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick);
+ return 1;
+}
+
static CMD_FUNC(cmd_server)
{
struct server *srv;
if (argc < 8)
return 0;
- if (origin) {
+ if (self->uplink) {
/* another server introduced us */
srv = AddServer(GetServerH(origin), argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), argv[6], argv[argc-1]);
if (!srv)
return 1;
}
+static CMD_FUNC(cmd_fakehost)
+{
+ struct userNode *user;
+
+ if ((argc < 3) || !origin || !GetServerH(origin))
+ return 0;
+ if (!(user = GetUserN(argv[1])))
+ return 1;
+ assign_fakehost(user, argv[2], 0);
+ return 1;
+}
+
static CMD_FUNC(cmd_burst)
{
extern int rel_age;
mode |= MODE_CHANOP;
else if (sep == 'v')
mode |= MODE_VOICE;
- else
+ else if (isdigit(sep)) {
+ mode |= MODE_CHANOP;
+ while (isdigit(*end)) end++;
+ } else
break;
}
if (rel_age < 0)
static CMD_FUNC(cmd_num_topic)
{
- static struct chanNode *cn;
+ struct chanNode *cn;
if (!argv[0])
return 0; /* huh? */
inttobase64(numer, (numnick << 12) + (usermask & 0x00fff), 3);
else
inttobase64(numer, (numnick << 18) + (usermask & 0x3ffff), 5);
+
+ str = conf_get_data("server/his_servername", RECDB_QSTRING);
+ his_servername = str ? strdup(str) : NULL;
+ str = conf_get_data("server/his_servercomment", RECDB_QSTRING);
+ his_servercomment = str ? strdup(str) : NULL;
+
str = conf_get_data("server/hostname", RECDB_QSTRING);
desc = conf_get_data("server/description", RECDB_QSTRING);
if (!str || !desc) {
dict_insert(irc_func_dict, TOK_NICK, cmd_nick);
dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account);
dict_insert(irc_func_dict, TOK_ACCOUNT, cmd_account);
+ dict_insert(irc_func_dict, CMD_FAKEHOST, cmd_fakehost);
+ dict_insert(irc_func_dict, TOK_FAKEHOST, cmd_fakehost);
dict_insert(irc_func_dict, CMD_PASS, cmd_pass);
dict_insert(irc_func_dict, TOK_PASS, cmd_pass);
dict_insert(irc_func_dict, CMD_PING, cmd_ping);
dict_insert(irc_func_dict, "331", cmd_num_topic);
dict_insert(irc_func_dict, "332", cmd_num_topic);
dict_insert(irc_func_dict, "333", cmd_num_topic);
+ dict_insert(irc_func_dict, "345", cmd_dummy); /* blah has been invited to blah */
dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */
/* ban list resetting */
/* "stats g" responses */
dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
dict_insert(irc_func_dict, "461", cmd_dummy); /* Not enough parameters (after TOPIC w/ 0 args) */
+ dict_insert(irc_func_dict, "467", cmd_dummy); /* Channel key already set */
num_privmsg_funcs = 16;
privmsg_funcs = malloc(sizeof(privmsg_func_t)*num_privmsg_funcs);
}
struct userNode *
-AddService(const char *nick, const char *desc)
+AddService(const char *nick, const char *modes, const char *desc, const char *hostname)
{
char numeric[COMBO_NUMERIC_LEN+1];
int local_num = get_local_numeric();
log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for service %s", nick);
return 0;
}
+ if (!hostname)
+ hostname = self->name;
make_numeric(self, local_num, numeric);
- return AddUser(self, nick, nick, self->name, "+oik", numeric, desc, now, "AAAAAA");
+ return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA");
}
struct userNode *
if (!user || !mode_change)
return;
- while (*word != ' ' && *word) word++;\
- while (*word == ' ') word++; \
+ while (*word != ' ' && *word) word++;
+ while (*word == ' ') word++;
while (1) {
#define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
switch (*mode_change++) {
call_account_func(user, tag);
}
break;
+ case 'f':
+ if (*word) {
+ char host[MAXLEN];
+ unsigned int ii;
+ for (ii=0; (*word != ' ') && (*word != '\0'); )
+ host[ii++] = *word++;
+ host[ii] = 0;
+ while (*word == ' ')
+ word++;
+ assign_fakehost(user, host, 0);
+ }
+ break;
}
#undef do_user_mode
}
change->args[ch_arg].mode = MODE_BAN;
if (!add)
change->args[ch_arg].mode |= MODE_REMOVE;
- change->args[ch_arg++].hostmask = modes[in_arg++];
+ change->args[ch_arg++].u.hostmask = modes[in_arg++];
break;
case 'o': case 'v':
{
victim = GetUserH(modes[in_arg++]);
if (!victim)
continue;
- if ((change->args[ch_arg].member = GetUserMode(channel, victim)))
+ if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
ch_arg++;
break;
}
chbuf.channel = channel;
chbuf.actor = who;
chbuf.chname_len = strlen(channel->name);
- if ((mn = GetUserMode(channel, who)) && (mn->modes & MODE_CHANOP))
+
+ mn = GetUserMode(channel, who);
+ if ((mn && (mn->modes & MODE_CHANOP)) || off_channel)
chbuf.is_chanop = 1;
/* First remove modes */
chbuf.modes[chbuf.modes_used++] = mode = '-';
switch (change->args[arg].mode & ~MODE_REMOVE) {
case MODE_BAN:
- mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask);
+ mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
break;
default:
if (change->args[arg].mode & MODE_CHANOP)
- mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
if (change->args[arg].mode & MODE_VOICE)
- mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
break;
}
}
chbuf.modes[chbuf.modes_used++] = mode = '+';
switch (change->args[arg].mode) {
case MODE_BAN:
- mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask);
+ mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
break;
default:
if (change->args[arg].mode & MODE_CHANOP)
- mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
if (change->args[arg].mode & MODE_VOICE)
- mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
break;
}
}
case 'b': remove |= MODE_BAN; break;
case 'D': remove |= MODE_DELAYJOINS; break;
case 'r': remove |= MODE_REGONLY; break;
- case 'c': remove |= MODE_NOCOLORS;
+ case 'c': remove |= MODE_NOCOLORS; break;
case 'C': remove |= MODE_NOCTCPS; break;
}
}
privmsg_funcs[numeric] = handler;
}
+void
+unreg_privmsg_func(struct userNode *user, privmsg_func_t handler)
+{
+ unsigned int x;
+
+ if (!user || handler)
+ return; /* this really only works with users */
+
+ memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t));
+
+ for (x = user->num_local+1; x < num_privmsg_funcs; x++)
+ memmove(privmsg_funcs+x-1, privmsg_funcs+x, sizeof(privmsg_func_t));
+
+ privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t));
+ num_privmsg_funcs--;
+}
+
+
void
reg_notice_func(struct userNode *user, privmsg_func_t handler)
{
notice_funcs[numeric] = handler;
}
+void
+unreg_notice_func(struct userNode *user, privmsg_func_t handler)
+{
+ unsigned int x;
+
+ if (!user || handler)
+ return; /* this really only works with users */
+
+ memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
+
+ for (x = user->num_local+1; x < num_notice_funcs; x++)
+ memmove(notice_funcs+x-1, notice_funcs+x, sizeof(privmsg_func_t));
+
+ memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
+ notice_funcs = realloc(notice_funcs, num_notice_funcs*sizeof(privmsg_func_t));
+ num_notice_funcs--;
+}
+
void
reg_oper_func(oper_func_t handler)
{