*
* x3 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
/* Full commands. */
#define CMD_ACCOUNT "ACCOUNT"
#define CMD_ADMIN "ADMIN"
+#define CMD_ALIST "ALIST"
#define CMD_ASLL "ASLL"
#define CMD_AWAY "AWAY"
#define CMD_BURST "BURST"
#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"
/* Tokenized commands. */
#define TOK_ACCOUNT "AC"
#define TOK_ADMIN "AD"
+#define TOK_ALIST "AL"
#define TOK_ASLL "LL"
#define TOK_AWAY "A"
#define TOK_BURST "B"
#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)
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)
{
}
}
+void
+irc_rpong(const char *from1, const char *from2, const char *pingtime, const char *clientinfo)
+{
+ putsock("%s " P10_RPONG " %s %s %s :%s", self->numeric, from1, from2, pingtime, clientinfo);
+}
+
void
irc_ping(const char *payload)
{
pos = base_len;
last_mode = -1;
}
+
memcpy(burst_line+pos, mn->user->numeric, strlen(mn->user->numeric));
pos += strlen(mn->user->numeric);
if (mn->modes && (mn->modes != last_mode)) {
}
}
+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);
putsock(":%s %03d %s %s", self->name, num, user->nick, buffer);
}
+void
+irc_mark(struct userNode *user, char *mark)
+{
+ char *host = user->hostname;
+
+ /* TODO: Allow mark overwrite. If they are marked, and their fakehost is oldmark.hostname, update it to newmark.hostname so mark can be called multiple times. Probably requires ircd modification also */
+ if(user->mark)
+ return;
+
+ /* if the mark will put us over the host length, clip some off the left hand side
+ * to make room...
+ */
+ if(strlen(host) + 1 + strlen(mark) > HOSTLEN)
+ host += 1 + ( (strlen(host) + 1 + strlen(mark)) - HOSTLEN );
+ putsock("%s " CMD_MARK " %s DNSBL +m %s.%s", self->numeric, user->nick, mark, host);
+ putsock("%s " CMD_MARK " %s DNSBL_DATA %s", self->numeric, user->nick, mark);
+
+ /* Save it in the user */
+ user->mark = strdup(mark);
+
+ /* If they are not otherwise marked, mark their host with fakehost */
+ if(!IsFakeHost(user) && !IsSetHost(user) && !(IsHiddenHost(user) && user->handle_info) )
+ {
+ struct modeNode *mn = NULL;
+ char fakehost[HOSTLEN];
+ unsigned int count = 0;
+ unsigned int n = 0;
+
+ putsock("%s " CMD_FAKEHOST " %s %s.%s", self->numeric, user->numeric, mark, host);
+ putsock("%s " CMD_MODE " %s +x", self->numeric, user->nick);
+
+ snprintf(fakehost, sizeof(fakehost), "%s.%s", mark, host);
+ safestrncpy(user->fakehost, fakehost, sizeof(user->fakehost));
+
+ for (n=count=0; n<user->channels.used; n++) {
+ mn = user->channels.list[n];
+ if (strlen(mn->channel->name) >= 1) /* Sanity */
+ check_bans(user, mn->channel->name);
+ }
+ }
+}
+
static void send_burst(void);
static void
/* 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_rping)
+{
+ struct server *dest;
+
+ if (!(dest = GetServerN(argv[1])))
+ return 0;
+
+ if (dest == self)
+ irc_rpong(argv[2], argv[3], argv[4], argv[5]);
+
+ return 1;
+}
+
static CMD_FUNC(cmd_ping)
{
struct server *srv;
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)
static char exemptlist[MAXLEN], banlist[MAXLEN];
unsigned int next = 3, res = 1;
int ctype = 0, echeck = 0, bcheck = 0;
+ struct chanData *cData;
struct chanNode *cNode;
struct userNode *un;
struct modeNode *mNode;
irc_burst(cNode);
}
cNode = AddChannel(argv[1], in_timestamp, modes, banlist, exemptlist);
+ cData = cNode->channel_info;
+
+ if (!cData) {
+ if (cNode->modes & MODE_REGISTERED) {
+ irc_join(opserv, cNode);
+ irc_mode(opserv, cNode, "-z");
+ irc_part(opserv, cNode, "");
+ }
+ }
/* Burst channel members in now. */
for (user = members, sep = *members, mode = 0; sep; user = end) {
return res;
}
+/* TODO:
+ * This is a stub that doesn't actually do anything. It should be completed
+ * so that bans on *!*@markname.* match users as it does in nefarious
+ */
+static CMD_FUNC(cmd_mark)
+{
+ struct userNode *target;
+ /*
+ * log_module(MAIN_LOG, LOG_ERROR, "DEBUG: mark, user %s, type %s, arg %s", argv[1], argv[2], argv[3]);
+ */
+
+ if(argc < 4)
+ return 0;
+ if(!strcasecmp(argv[2], "DNSBL")) {
+ /* DNSBL <modes> */
+ return 1;
+ }
+ else if(!strcasecmp(argv[2], "DNSBL_DATA")) {
+ /* DNSBL_DATA name */
+ target = GetUserH(argv[1]);
+ if(!target) {
+ log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose dnsbl mark is changing.", argv[1]);
+ return 0;
+ }
+ target->mark = strdup(argv[3]);
+ return 1;
+
+ }
+ else if(!strcasecmp(argv[2], "CVERSION")) {
+ /* DNSBL_DATA name */
+ target = GetUserH(argv[1]);
+ if(!target) {
+ log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose version mark is changing.", argv[1]);
+ return 0;
+ }
+
+ char *version = unsplit_string(argv + 3, argc - 3, NULL);
+ if(!version)
+ version = "";
+
+ target->version_reply = strdup(version);
+
+ if(match_ircglob(version, "WebTV;*"))
+ target->no_notice = true; /* webbies cant see notices */
+
+ return 1;
+ }
+ /* unknown type of mark */
+ return 1;
+}
+
static CMD_FUNC(cmd_mode)
{
struct chanNode *cn;
return 1;
}
+static CMD_FUNC(cmd_svspart)
+{
+ struct userNode *user;
+
+ if (argc < 3)
+ return 0;
+ user = GetUserN(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.is_notice = 0;
pd.text = argv[2];
parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
+
return 1;
}
dict_insert(irc_func_dict, TOK_EOB_ACK, cmd_eob_ack);
dict_insert(irc_func_dict, CMD_MODE, cmd_mode);
dict_insert(irc_func_dict, TOK_MODE, cmd_mode);
+ dict_insert(irc_func_dict, CMD_MARK, cmd_mark);
+ dict_insert(irc_func_dict, TOK_MARK, cmd_mark);
dict_insert(irc_func_dict, CMD_NICK, cmd_nick);
dict_insert(irc_func_dict, TOK_NICK, cmd_nick);
dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account);
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);
dict_insert(irc_func_dict, CMD_ADMIN, cmd_admin);
dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin);
+ dict_insert(irc_func_dict, CMD_RPING, cmd_rping);
+ dict_insert(irc_func_dict, TOK_RPING, cmd_rping);
+ dict_insert(irc_func_dict, CMD_RPONG, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_RPONG, cmd_dummy);
+
/* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
* Apparently to obliterate channels from any servers that think they
* exist?
dict_insert(irc_func_dict, TOK_WALLUSERS, cmd_dummy);
/* Ignore dnsbl exemptions */
dict_insert(irc_func_dict, TOK_EXEMPT, cmd_dummy);
- dict_insert(irc_func_dict, TOK_MARK, cmd_dummy);
dict_insert(irc_func_dict, CMD_PRIVS, cmd_privs);
dict_insert(irc_func_dict, TOK_PRIVS, cmd_privs);
+ /* ignore ALIST for now */
+ dict_insert(irc_func_dict, TOK_ALIST, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_ALIST, cmd_dummy);
/* 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
{
struct userNode *oldUser, *uNode;
unsigned int n, ignore_user;
+ char *tstr;
+ int type;
if ((strlen(numeric) < 3) || (strlen(numeric) > 5)) {
log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink, nick, numeric);
safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric));
irc_p10_pton(&uNode->ip, realip);
- if (irc_in_addr_is_ipv4(uNode->ip)) {
- make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
- make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
- } else if (irc_in_addr_is_ipv6(uNode->ip)) {
- make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ type = atoi(tstr);
+ if (type > 6) {
+ if (irc_in_addr_is_ipv4(uNode->ip)) {
+ make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
+ make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+ } else if (irc_in_addr_is_ipv6(uNode->ip)) {
+ 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;
}
modeList_clean(&user->channels);
+
+ /* Clean up version data */
+ if(user->version_reply) {
+ free(user->version_reply);
+ user->version_reply = NULL;
+ }
+
+ /* clean up mark */
+ if(user->mark) {
+ free(user->mark);
+ user->mark = 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.
// case 'h': do_user_mode(FLAGS_HELPER); break;
// I check if there's an 'h' in the first part, and if there,
// then everything after the space becomes their new host.
+ case 'C': do_user_mode(FLAGS_CLOAKHOST);
+ if (*word) {
+ char cloakhost[MAXLEN];
+ unsigned int ii;
+ for (ii=0; (*word != ' ') && (*word != '\0'); )
+ cloakhost[ii++] = *word++;
+ cloakhost[ii] = 0;
+ while (*word == ' ')
+ word++;
+ safestrncpy(user->crypthost, cloakhost, sizeof(user->crypthost));
+ }
+ break;
+ case 'c': do_user_mode(FLAGS_CLOAKIP);
+ if (*word) {
+ char cloakip[MAXLEN];
+ unsigned int ii;
+ for (ii=0; (*word != ' ') && (*word != '\0'); )
+ cloakip[ii++] = *word++;
+ cloakip[ii] = 0;
+ while (*word == ' ')
+ word++;
+ safestrncpy(user->cryptip, cloakip, sizeof(user->cryptip));
+ }
+ break;
case 'h': do_user_mode(FLAGS_SETHOST);
if (*word) {
char sethost[MAXLEN];