#include "nickserv.h"
#include "chanserv.h"
+#include "hash.h"
+#include "helpfile.h"
#include "hosthiding.h"
#include "proto-common.c"
#include "opserv.h"
#define CMD_SQUERY "SQUERY"
#define CMD_SQUIT "SQUIT"
#define CMD_STATS "STATS"
+#define CMD_SVSJOIN "SVSJOIN"
#define CMD_SVSNICK "SVSNICK"
+#define CMD_SVSPART "SVSPART"
#define CMD_SWHOIS "SWHOIS"
#define CMD_TIME "TIME"
#define CMD_TOPIC "TOPIC"
#define TOK_SQUERY "SQUERY"
#define TOK_SQUIT "SQ"
#define TOK_STATS "R"
+#define TOK_SVSJOIN "SJ"
#define TOK_SVSNICK "SN"
+#define TOK_SVSPART "SP"
#define TOK_SWHOIS "SW"
#define TOK_TIME "TI"
#define TOK_TOPIC "T"
#define P10_SQUERY TYPE(SQUERY)
#define P10_SQUIT TYPE(SQUIT)
#define P10_STATS TYPE(STATS)
+#define P10_SVSJOIN TYPE(SVSJOIN)
#define P10_SVSNICK TYPE(SVSNICK)
+#define P10_SVSPART TYPE(SVSPART)
#define P10_SWHOIS TYPE(SWHOIS)
#define P10_TIME TYPE(TIME)
#define P10_TOPIC TYPE(TOPIC)
*/
#define PREHISTORY 780000000
+#define MODELEN 40 + KEYLEN
+
static struct server *servers_num[64*64];
static privmsg_func_t *privmsg_funcs;
static unsigned int num_privmsg_funcs;
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;
+extern int DefConLevel;
+extern int DefConTimeOut;
+extern char *DefConChanModes;
static int parse_oplevel(char *str);
+char privbuf[512] = "";
+
/* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
* server and Y's indentifying the client on that server. */
struct server*
return un;
}
+extern struct userNode *opserv;
+static void
+check_ctcp(struct userNode *user, struct userNode *bot, char *text, UNUSED_ARG(int server_qualified))
+{
+ char *cmd;
+ /* if its a version reply, do an alert check (only alerts with version=something) */
+ if(bot == opserv) {
+ if(text[0] == '\001') {
+ text++;
+ cmd = mysep(&text, " ");
+ if(!irccasecmp(cmd, "VERSION")) {
+ char *version = mysep(&text, "\n");
+ if(!version)
+ version = "";
+ /* opserv_debug("Opserv got CTCP VERSION Notice from %s: %s", user->nick, version); */
+ /* TODO: setup a ctcp_funcs thing to handle this and other CTCPS properly */
+ user->version_reply = strdup(version);
+ /* TODO: put this in the db */
+ if(match_ircglob(version, "WebTV;*"))
+ user->no_notice = true; /* webbies cant see notices */
+ }
+ }
+ }
+}
+
+
static void
privmsg_user_helper(struct userNode *un, void *data)
{
}
} else {
if ((num < num_notice_funcs) && notice_funcs[num]) {
+ check_ctcp(pd->user, un, pd->text, pd->is_qualified);
notice_funcs[num](pd->user, un, pd->text, pd->is_qualified);
}
}
putsock("%s " P10_WALLOPS " :%s", self->numeric, buffer);
}
+
void
irc_notice(struct userNode *from, const char *to, const char *message)
{
putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message);
}
+void
+irc_privmsg_user(struct userNode *from, struct userNode *to, const char *message)
+{
+ putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to->numeric, message);
+}
+
+void
+irc_version_user(struct userNode *from, struct userNode *to)
+{
+ irc_privmsg_user(from, to, "\001VERSION\001");
+}
+
void
irc_eob(void)
{
irc_eob_ack(void)
{
putsock("%s " P10_EOB_ACK, self->numeric);
+
+ char *nick;
+ const char *str;
+ str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
+ nick = strdup(str);
+
+ if (nick && (DefConLevel < 5)) {
+ DefConProcess(GetUserH(nick));
+
+ if (DefConTimeOut > 0)
+ timeq_add(now + DefConTimeOut, defcon_timeout, NULL);
+ }
}
void
}
}
+void
+irc_svsjoin(struct userNode *from, struct userNode *who, struct chanNode *to)
+{
+ putsock("%s " P10_SVSJOIN " %s %s "FMT_TIME_T, from->uplink->numeric, who->numeric, to->name, now);
+}
+
+void
+irc_svspart(struct userNode *from, struct userNode *who, struct chanNode *to)
+{
+ putsock("%s " P10_SVSPART " %s %s", from->uplink->numeric, who->numeric, to->name);
+}
+
void
irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel, const char *msg)
{
host_in_topic = atoi(hstr);
}
- if (type == 5) {
+ if (type >= 5) {
putsock("%s " P10_TOPIC " %s %s%s%s%s%s " FMT_TIME_T " " FMT_TIME_T " :%s", service->numeric, what->name,
who->nick, host_in_topic ? "!" : "", host_in_topic ? (IsSetHost(who) ? sident : who->ident) : "",
host_in_topic ? "@" : "", host_in_topic ? shost : "", what->timestamp, now, topic);
/* now that we know who our uplink is,
* we can center the routing map and activate auto-routing.
*/
- activate_routing(NULL, NULL, NULL);
+ //activate_routing(NULL, NULL, NULL);
+ routing_init();
}
sender->self_burst = 0;
recalc_bursts(sender);
return 1;
}
+static CMD_FUNC(cmd_svsjoin)
+{
+ struct create_desc cd;
+
+ if (!(cd.user = GetUserH(argv[1])))
+ return 0;
+ if (argc < 3)
+ return 0;
+ else if (argc < 4)
+ cd.when = now;
+ else
+ cd.when = atoi(argv[3]);
+ parse_foreach(argv[2], join_helper, create_helper, NULL, NULL, &cd);
+ return 1;
+}
+
static CMD_FUNC(cmd_pong)
{
if (argc < 3)
NickChange(user, argv[1], 1);
} else {
struct server *serv;
+ struct userNode *nuser;
char modes[MAXLEN];
/* new nick */
if (argc < 9)
unsplit_string(argv+6, argc-9, modes);
else
strcpy(modes, "+");
- AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]);
+ nuser = AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]);
}
return 1;
}
return 1;
}
+static struct {
+ char *name;
+ unsigned int priv;
+} privtab[] = {
+#define P(priv) { #priv, PRIV_ ## priv }
+ P(CHAN_LIMIT), P(MODE_LCHAN), P(WALK_LCHAN), P(DEOP_LCHAN),
+ P(SHOW_INVIS), P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL),
+ P(LOCAL_KILL), P(REHASH), P(RESTART), P(DIE),
+ P(GLINE), P(LOCAL_GLINE), P(JUPE), P(LOCAL_JUPE),
+ P(OPMODE), P(LOCAL_OPMODE), P(SET), P(WHOX),
+ P(BADCHAN), P(LOCAL_BADCHAN), P(SEE_CHAN), P(PROPAGATE),
+ P(DISPLAY), P(SEE_OPERS), P(WIDE_GLINE), P(FORCE_OPMODE),
+ P(FORCE_LOCAL_OPMODE), P(REMOTEREHASH), P(CHECK), P(SEE_SECRET_CHAN),
+ P(SHUN), P(LOCAL_SHUN), P(WIDE_SHUN),
+#undef P
+ { 0, 0 }
+};
+
+char *client_report_privs(struct userNode *client)
+{
+ int i;
+
+ privbuf[0] = '\0';
+ for (i = 0; privtab[i].name; i++) {
+ if (HasPriv(client, privtab[i].priv)) {
+ strcat(privbuf, privtab[i].name);
+ strcat(privbuf, " ");
+ }
+ }
+
+ privbuf[strlen(privbuf)] = 0;
+
+ return privbuf;
+}
+
+int client_modify_priv_by_name(struct userNode *who, char *priv, int what) {
+ int i = 0;
+ assert(0 != priv);
+ assert(0 != who);
+
+ for (i = 0; privtab[i].name; i++) {
+ if (0 == strcmp(privtab[i].name, priv)) {
+ if (what == PRIV_ADD)
+ GrantPriv(who, privtab[i].priv);
+ else if (what == PRIV_DEL) {
+ RevokePriv(who, privtab[i].priv);
+ }
+ }
+ }
+ return 0;
+}
+
+int check_priv(char *priv)
+{
+ int i;
+
+ for (i = 0; privtab[i].name; i++) {
+ if (0 == strcmp(privtab[i].name, priv)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+irc_privs(struct userNode *target, char *flag, int add)
+{
+ client_modify_priv_by_name(target, flag, add);
+ putsock("%s " P10_PRIVS " %s %s%s", self->numeric, target->numeric, (add == PRIV_ADD) ? "+" : "-", flag);
+}
+
+static CMD_FUNC(cmd_privs)
+{
+ char *tstr = NULL;
+ int type = 0;
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+
+ if (type < 6)
+ return 1; /* silently ignore */
+
+ struct userNode *user = argc > 1 ? GetUserN(argv[1]) : NULL;
+ char buf[512] = "";
+ int what = PRIV_ADD;
+ char *p = 0;
+ char *tmp;
+ unsigned int i;
+
+ if (argc < 3)
+ return 0;
+
+ if (!user)
+ return 0;
+
+ for (i=1; i<argc; i++) {
+ strcat(buf, argv[i]);
+ strcat(buf, " ");
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (*argv[i] == '+') { what = PRIV_ADD; argv[i]++; }
+ if (*argv[i] == '-') { what = PRIV_DEL; argv[i]++; }
+ for (tmp = x3_strtok(&p, argv[i], ","); tmp;
+ tmp = x3_strtok(&p, NULL, ",")) {
+ client_modify_priv_by_name(user, tmp, what);
+ }
+ }
+ return 1;
+}
+
static CMD_FUNC(cmd_burst)
{
extern int rel_age;
cn->timestamp = atoi(argv[argc-1]);
}
+ if (checkDefCon(DEFCON_NO_MODE_CHANGE) && !IsOper(un)) {
+ const char *str;
+ str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
+ if (str) {
+ char modes[MODELEN];
+ struct userNode *opserv = GetUserH(str);
+
+ send_message_type(4, un, opserv, "Channel modes cannot be changed due to DefCon level %d in effect, please try again soon", DefConLevel);
+ irc_make_chanmode(cn, modes);
+ irc_mode(opserv, cn, modes);
+ irc_mode(opserv, cn, DefConChanModes);
+ }
+ return 1;
+ }
+
+
return mod_chanmode(un, cn, argv+2, argc-2, MCP_ALLOW_OVB|MCP_FROM_SERVER|(un ? MC_NOTIFY : 0));
}
return 1;
}
+static CMD_FUNC(cmd_svspart)
+{
+ struct userNode *user;
+
+ if (argc < 3)
+ return 0;
+ user = GetUserH(argv[1]);
+ if (!user)
+ return 0;
+ parse_foreach(argv[2], part_helper, NULL, NULL, NULL, user);
+ return 1;
+}
+
static CMD_FUNC(cmd_silence)
{
struct userNode *user;
pd.user = GetUserH(origin);
if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user)))
return 1;
+
+ if (checkDefCon(DEFCON_OPER_ONLY) && !IsOper(pd.user)) {
+ const char *str;
+ str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
+ if (str)
+ send_message_type(4, pd.user, GetUserH(str), "Services are currently not available, please try again soon");
+ return 1;
+ }
+
+ if (checkDefCon(DEFCON_SILENT_OPER_ONLY) && !IsOper(pd.user))
+ return 1; /* Silently Ignore */
+
pd.is_notice = 0;
pd.text = argv[2];
parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
dict_insert(irc_func_dict, TOK_NOTICE, cmd_notice);
dict_insert(irc_func_dict, CMD_STATS, cmd_stats);
dict_insert(irc_func_dict, TOK_STATS, cmd_stats);
+ dict_insert(irc_func_dict, CMD_SVSJOIN, cmd_svsjoin);
+ dict_insert(irc_func_dict, TOK_SVSJOIN, cmd_svsjoin);
dict_insert(irc_func_dict, CMD_SVSNICK, cmd_svsnick);
dict_insert(irc_func_dict, TOK_SVSNICK, cmd_svsnick);
+ dict_insert(irc_func_dict, CMD_SVSPART, cmd_svspart);
+ dict_insert(irc_func_dict, TOK_SVSPART, cmd_svspart);
dict_insert(irc_func_dict, CMD_SWHOIS, cmd_dummy);
dict_insert(irc_func_dict, TOK_SWHOIS, cmd_dummy);
dict_insert(irc_func_dict, CMD_WHOIS, cmd_whois);
/* Ignore dnsbl exemptions */
dict_insert(irc_func_dict, TOK_EXEMPT, cmd_dummy);
dict_insert(irc_func_dict, TOK_MARK, cmd_dummy);
- /* Ignore privs */
- dict_insert(irc_func_dict, TOK_PRIVS, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_PRIVS, cmd_privs);
+ dict_insert(irc_func_dict, TOK_PRIVS, cmd_privs);
/* Ignore remote luser */
dict_insert(irc_func_dict, TOK_LUSERS, cmd_dummy);
/* We have reliable clock! Always! Wraaa! */
userList_init(&dead_users);
reg_del_channel_func(remove_unbursted_channel);
reg_exit_func(parse_cleanup);
+ // reg_notice_func(opserv, check_ctcp);
}
int
make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
}
+ if (!uNode->crypthost && uNode->cryptip)
+ snprintf(uNode->crypthost, sizeof(uNode->crypthost), "%s", strdup(uNode->cryptip));
+
uNode->timestamp = timestamp;
modeList_init(&uNode->channels);
uNode->uplink = uplink;
uNode->num_local = base64toint(numeric+strlen(uNode->uplink->numeric), 3) & uNode->uplink->num_mask;
uNode->uplink->users[uNode->num_local] = uNode;
mod_usermode(uNode, modes);
+
+ set_geoip_info(uNode);
+
if (ignore_user)
return uNode;
}
modeList_clean(&user->channels);
+
+ /* Clean up version data */
+ if(user->version_reply) {
+ free(user->version_reply);
+ user->version_reply = NULL;
+ }
+
+ /* clean up geoip data if any */
+ if(user->country_code) free(user->country_code);
+ if(user->city) free(user->city);
+ if(user->region) free(user->region);
+ if(user->postal_code) free(user->postal_code);
+
/* We don't free them, in case we try to privmsg them or something
* (like when a stupid oper kills themself). We just put them onto
* a list of clients that get freed after processing each line.