# arch-tag: automatic-ChangeLog--srvx@srvx.net--2004-srvx/srvx--devo--1.3
#
+2004-05-22 04:24:57 GMT Michael Poole <mdpoole@troilus.org> patch-67
+
+ Summary:
+ Add fake host support (assuming your ircd supports it)
+ Revision:
+ srvx--devo--1.3--patch-67
+
+ Add definitions in various places to support assigning fake hosts to
+ users. We will not give you (or make for you) patches to make your
+ ircd support this feature, so please do not ask. You must set a
+ certain srvx.conf setting to be able to assign fakehosts; finding it
+ is left as an exercise to the reader.
+
+ modified files:
+ ChangeLog src/chanserv.c src/hash.c src/hash.h src/log.c
+ src/nickserv.c src/nickserv.h src/opserv.c src/proto-bahamut.c
+ src/proto-common.c src/proto-p10.c src/proto.h src/tools.c
+
+
2004-05-22 03:00:05 GMT Michael Poole <mdpoole@troilus.org> patch-66
Summary:
lData.lowest = lowest;
lData.highest = highest;
lData.search = (argc > 1) ? argv[1] : NULL;
- send_list = zoot_list;
+ send_list = def_list;
+ (void)zoot_list; /* since it doesn't show user levels */
if(user->handle_info)
{
switch(user->handle_info->userlist_style)
{
case HI_STYLE_DEF: send_list = def_list; break;
- case HI_STYLE_ZOOT: send_list = zoot_list; break;
+ case HI_STYLE_ZOOT: send_list = def_list; break;
}
}
user->modes |= FLAGS_STAMPED;
}
+void
+assign_fakehost(struct userNode *user, const char *host, int announce)
+{
+ safestrncpy(user->fakehost, host, sizeof(user->fakehost));
+ if (announce)
+ irc_fakehost(user, host);
+}
+
static new_channel_func_t *ncf_list;
static unsigned int ncf_size = 0, ncf_used = 0;
#define FLAGS_STAMPED 0x1000 /* for users who have been stamped */
#define FLAGS_HIDDEN_HOST 0x2000 /* user's host is masked by their account */
#define FLAGS_REGNICK 0x4000 /* user owns their current nick */
-#define FLAGS_REGISTERING 0x8000 /* user has issued accnt register command, is waiting for email cookie */
+#define FLAGS_REGISTERING 0x8000 /* user has issued account register command, is waiting for email cookie */
#define IsOper(x) ((x)->modes & FLAGS_OPER)
#define IsService(x) ((x)->modes & FLAGS_SERVICE)
#define IsHiddenHost(x) ((x)->modes & FLAGS_HIDDEN_HOST)
#define IsReggedNick(x) ((x)->modes & FLAGS_REGNICK)
#define IsRegistering(x) ((x)->modes & FLAGS_REGISTERING)
+#define IsFakeHost(x) ((x)->fakehost[0] != '\0')
#define IsLocal(x) ((x)->uplink == self)
#define NICKLEN 30
char ident[USERLEN + 1]; /* Per-host identification for user */
char info[REALLEN + 1]; /* Free form additional client information */
char hostname[HOSTLEN + 1]; /* DNS name or IP address */
+ char fakehost[HOSTLEN + 1]; /* Assigned fake host */
#ifdef WITH_PROTOCOL_P10
char numeric[COMBO_NUMERIC_LEN+1];
unsigned int num_local : 18;
void reg_account_func(account_func_t handler);
void call_account_func(struct userNode *user, const char *stamp);
void StampUser(struct userNode *user, const char *stamp);
+void assign_fakehost(struct userNode *user, const char *host, int announce);
typedef void (*new_channel_func_t) (struct chanNode *chan);
void reg_new_channel_func(new_channel_func_t handler);
* KEY := LOGSET '.' SEVSET
* LOGSET := LOGLIT | LOGLIT ',' LOGSET
* LOGLIT := a registered log type
- * SEVSET := '*' | SEVLIT | '=' SEVLIT | '<' SEVLIT | '<=' SEVLIT | '>' SEVLIT | '>=' SEVLIT | SEVLIT ',' SEVSET
+ * SEVSET := '*' | SEVLIT | '<' SEVLIT | '<=' SEVLIT | '>' SEVLIT | '>=' SEVLIT | SEVLIT ',' SEVSET
* SEVLIT := one of log_severity_names
* A KEY contains the Cartesian product of the logs in its LOGSET
* and the severities in its SEVSET.
int first;
cont = strchr(buffer, ',');
- if (cont) *cont++ = 0;
+ if (cont)
+ *cont++ = 0;
if (buffer[0] == '*' && buffer[1] == 0) {
for (bound = 0; bound < LOG_NUM_SEVERITIES; bound++) {
/* make people explicitly specify replay targets */
#define KEY_DB_BACKUP_FREQ "db_backup_freq"
#define KEY_MODOPER_LEVEL "modoper_level"
#define KEY_SET_EPITHET_LEVEL "set_epithet_level"
+#define KEY_SET_TITLE_LEVEL "set_title_level"
+#define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
+#define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
#define KEY_FLAG_LEVELS "flag_levels"
#define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
#define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
#define KEY_TABLE_WIDTH "table_width"
#define KEY_ANNOUNCEMENTS "announcements"
#define KEY_MAXLOGINS "maxlogins"
+#define KEY_FAKEHOST "fakehost"
#define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
{ "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
{ "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
{ "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
+ { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
+ { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
{ "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
{ "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
{ "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
{ "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
{ "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
{ "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
+ { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
{ "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
{ "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
{ "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
{ "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
{ "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
{ "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
+ { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
+ { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
{ "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
{ "NSEMAIL_ACTIVATION_BODY", "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n %2$s\nTo verify your email address and complete the account registration, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nThis command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n /msg %3$s@%4$s AUTH %5$s your-password\n Please remember to fill in 'your-password' with the actual password you gave to us when you registered.\n\nIf you did NOT request this account, you do not need to do anything. Please contact the %1$s staff if you have questions, and be sure to check our website." },
{ "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
unsigned long nochan_handle_expire_delay;
unsigned long modoper_level;
unsigned long set_epithet_level;
+ unsigned long set_title_level;
+ unsigned long set_fakehost_level;
unsigned long handles_per_email;
unsigned long email_search_level;
const char *network_name;
delete_nick(hi->nicks);
free(hi->infoline);
free(hi->epithet);
+ free(hi->fakehost);
if (hi->cookie) {
timeq_del(hi->cookie->expires, nickserv_free_cookie, hi->cookie, 0);
nickserv_free_cookie(hi->cookie);
rf_list[rf_list_used++] = func;
}
+static char *
+generate_fakehost(struct handle_info *handle)
+{
+ extern const char *hidden_host_suffix;
+ static char buffer[HOSTLEN+1];
+
+ if (!handle->fakehost) {
+ snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
+ return buffer;
+ } else if (handle->fakehost[0] == '.') {
+ /* A leading dot indicates the stored value is actually a title. */
+ snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, nickserv_conf.titlehost_suffix);
+ return buffer;
+ }
+ return handle->fakehost;
+}
+
+static void
+apply_fakehost(struct handle_info *handle)
+{
+ struct userNode *target;
+ char *fake;
+
+ if (!handle->users)
+ return;
+ fake = generate_fakehost(handle);
+ for (target = handle->users; target; target = target->next_authed)
+ assign_fakehost(target, fake, 1);
+}
+
static void
set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
{
if (IsHelper(user))
userList_append(&curr_helpers, user);
+ if (hi->fakehost || old_info)
+ apply_fakehost(hi);
+
if (stamp) {
#ifdef WITH_PROTOCOL_BAHAMUT
/* Stamp users with their account ID. */
reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none));
}
+ if (hi->fakehost)
+ reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE")));
+
if (hi->last_quit_host[0])
reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host);
else
/* Unauthenticated users might still have been stamped
previously and could therefore have a hidden host;
do not allow them to authenticate to an account. */
- send_message(target, nickserv, "NSMSG_USER_PREV_STAMP", target->nick);
+ reply("NSMSG_USER_PREV_STAMP", target->nick);
return 0;
}
if (argc == 2)
return 1;
}
+static OPTION_FUNC(opt_title)
+{
+ const char *title;
+
+ if (!override) {
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
+ }
+
+ if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) {
+ title = argv[1];
+ if (strchr(title, '.')) {
+ send_message(user, nickserv, "NSMSG_TITLE_INVALID");
+ return 0;
+ }
+ free(hi->fakehost);
+ if (!strcmp(title, "*")) {
+ hi->fakehost = NULL;
+ } else {
+ hi->fakehost = malloc(strlen(title)+2);
+ hi->fakehost[0] = '.';
+ strcpy(hi->fakehost+1, title);
+ }
+ apply_fakehost(hi);
+ } else if (hi->fakehost && (hi->fakehost[0] == '.'))
+ title = hi->fakehost + 1;
+ else
+ title = NULL;
+ if (!title)
+ title = user_find_message(user, "MSG_NONE");
+ send_message(user, nickserv, "NSMSG_SET_TITLE", title);
+ return 1;
+}
+
+static OPTION_FUNC(opt_fakehost)
+{
+ const char *fake;
+
+ if (!override) {
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
+ }
+
+ if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
+ fake = argv[1];
+ if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
+ send_message(user, nickserv, "NSMSG_FAKEHOST_INVALID");
+ return 0;
+ }
+ free(hi->fakehost);
+ if (!strcmp(fake, "*"))
+ hi->fakehost = NULL;
+ else
+ hi->fakehost = strdup(fake);
+ fake = hi->fakehost;
+ apply_fakehost(hi);
+ } else
+ fake = generate_fakehost(hi);
+ if (!fake)
+ fake = user_find_message(user, "MSG_NONE");
+ send_message(user, nickserv, "NSMSG_SET_FAKEHOST", fake);
+ return 1;
+}
+
static NICKSERV_FUNC(cmd_reclaim)
{
struct handle_info *hi;
saxdb_write_string(ctx, KEY_EMAIL_ADDR, hi->email_addr);
if (hi->epithet)
saxdb_write_string(ctx, KEY_EPITHET, hi->epithet);
+ if (hi->fakehost)
+ saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost);
if (hi->flags) {
int ii, flen;
str = database_get_data(obj, KEY_EPITHET, RECDB_QSTRING);
if (str)
hi->epithet = strdup(str);
+ str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING);
+ if (str)
+ hi->fakehost = strdup(str);
subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT);
if (subdb) {
const char *data, *type, *expires, *cookie_str;
str = database_get_data(conf_node, KEY_VALID_HANDLE_REGEX, RECDB_QSTRING);
if (!str)
str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING);
- if (nickserv_conf.valid_handle_regex_set) regfree(&nickserv_conf.valid_handle_regex);
+ if (nickserv_conf.valid_handle_regex_set)
+ regfree(&nickserv_conf.valid_handle_regex);
if (str) {
int err = regcomp(&nickserv_conf.valid_handle_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
nickserv_conf.valid_handle_regex_set = !err;
nickserv_conf.valid_handle_regex_set = 0;
}
str = database_get_data(conf_node, KEY_VALID_NICK_REGEX, RECDB_QSTRING);
- if (nickserv_conf.valid_nick_regex_set) regfree(&nickserv_conf.valid_nick_regex);
+ if (nickserv_conf.valid_nick_regex_set)
+ regfree(&nickserv_conf.valid_nick_regex);
if (str) {
int err = regcomp(&nickserv_conf.valid_nick_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
nickserv_conf.valid_nick_regex_set = !err;
nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900;
str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING);
nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1;
+ str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING);
+ nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900;
+ str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING);
+ nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000;
str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING);
if (!str)
str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
nickserv_conf.handles_per_email = str ? strtoul(str, NULL, 0) : 1;
str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING);
nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600;
+ str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
+ nickserv_conf.titlehost_suffix = str ? str : "example.net";
str = conf_get_data("server/network", RECDB_QSTRING);
nickserv_conf.network_name = str ? str : "some IRC network";
if (!nickserv_conf.auth_policer_params) {
dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
+ if (nickserv_conf.titlehost_suffix) {
+ dict_insert(nickserv_opt_dict, "TITLE", opt_title);
+ dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost);
+ }
dict_insert(nickserv_opt_dict, "ANNOUNCEMENTS", opt_announcements);
dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins);
dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language);
char *epithet;
char *infoline;
char *handle;
+ char *fakehost;
#ifdef WITH_PROTOCOL_BAHAMUT
unsigned long id;
#endif
{ "OSMSG_WHOIS_IDENT", "%s (%s@%s) from %d.%d.%d.%d" },
{ "OSMSG_WHOIS_NICK", "Nick : %s" },
{ "OSMSG_WHOIS_HOST", "Host : %s@%s" },
+ { "OSMSG_WHOIS_FAKEHOST", "Fakehost: %s" },
{ "OSMSG_WHOIS_IP", "Real IP : %s" },
{ "OSMSG_WHOIS_MODES", "Modes : +%s " },
{ "OSMSG_WHOIS_INFO", "Info : %s" },
struct mod_chanmode change;
struct userNode *victim;
- change.modes_set = change.modes_clear = 0;
+ mod_chanmode_init(&change);
change.argc = 1;
change.args[0].mode = MODE_BAN;
if (is_ircmask(argv[1]))
reply("OSMSG_NO_CHANNEL_MODES", channel->name);
return 0;
}
- change.modes_set = 0;
+ mod_chanmode_init(&change);
change.modes_clear = channel->modes;
- change.argc = 0;
modcmd_chanmode_announce(&change);
reply("OSMSG_CLEARMODES_DONE", channel->name);
return 1;
* channel, we have to join it in temporarily. */
if (!(inchan = GetUserMode(channel, bot) ? 1 : 0)) {
struct mod_chanmode change;
- memset(&change, 0, sizeof(change));
+ mod_chanmode_init(&change);
change.args[0].mode = MODE_CHANOP;
change.args[0].member = AddChannelUser(bot, channel);
modcmd_chanmode_announce(&change);
reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name);
return 0;
}
- change.modes_set = change.modes_clear = 0;
+ mod_chanmode_init(&change);
change.argc = 1;
change.args[0].mode = MODE_BAN;
change.args[0].hostmask = mask = generate_hostmask(target, 0);
}
reply("OSMSG_WHOIS_NICK", target->nick);
reply("OSMSG_WHOIS_HOST", target->ident, target->hostname);
+ if (IsFakeHost(target))
+ reply("OSMSG_WHOIS_FAKEHOST", target->fakehost);
reply("OSMSG_WHOIS_IP", inet_ntoa(target->ip));
if (target->modes) {
bpos = 0;
static MODCMD_FUNC(cmd_unban)
{
struct mod_chanmode change;
- change.modes_set = change.modes_clear = 0;
+ mod_chanmode_init(&change);
change.argc = 1;
change.args[0].mode = MODE_REMOVE | MODE_BAN;
change.args[0].hostmask = argv[1];
/* Don't moderate the channel unless it is activated and
the number of users in the channel is over the threshold. */
struct mod_chanmode change;
- change.modes_set = change.modes_clear = change.argc = 0;
+ mod_chanmode_init(&change);
channel->join_flooded = 1;
if (opserv_conf.join_flood_moderate && (channel->members.used > opserv_conf.join_flood_moderate_threshold)) {
if (!GetUserMode(channel, opserv)) {
reply("MSG_CHANNEL_UNKNOWN", argv[3]);
return 0;
}
- change.modes_set = change.modes_clear = 0;
+ mod_chanmode_init(&change);
change.argc = 1;
change.args[0].mode = MODE_CHANOP;
change.args[0].member = GetUserMode(channel, clone);
}
}
+void
+irc_fakehost(UNUSED_ARG(struct userNode *user), UNUSED_ARG(const char *host))
+{
+ /* not supported in bahamut */
+}
+
void
irc_regnick(struct userNode *user)
{
}
bn = calloc(1, sizeof(*bn));
safestrncpy(bn->ban, change->args[ii].hostmask, sizeof(bn->ban));
- safestrncpy(bn->who, who->nick, sizeof(bn->who));
+ if (who)
+ safestrncpy(bn->who, who->nick, sizeof(bn->who));
+ else
+ safestrncpy(bn->who, "<unknown>", sizeof(bn->who));
bn->set = now;
banList_append(&channel->banlist, bn);
break;
strcpy(ident+1, user->ident + ((*user->ident == '~')?1:0));
}
hostname = user->hostname;
- if (IsHiddenHost(user) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) {
+ if (IsFakeHost(user) && IsHiddenHost(user) && !(options & GENMASK_NO_HIDING)) {
+ hostname = user->fakehost;
+ } else if (IsHiddenHost(user) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) {
hostname = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2);
sprintf(hostname, "%s.%s", user->handle_info->handle, hidden_host_suffix);
} else if (options & GENMASK_STRICT_HOST) {
#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)
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))
{
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;
static CMD_FUNC(cmd_num_topic)
{
- static struct chanNode *cn;
+ struct chanNode *cn;
if (!argv[0])
return 0; /* huh? */
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 */
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
}
/* account maintenance */
void irc_account(struct userNode *user, const char *stamp);
void irc_regnick(struct userNode *user);
+void irc_fakehost(struct userNode *user, const char *host);
/* numeric messages */
void irc_numeric(struct userNode *user, unsigned int num, const char *format, ...);
return match_ircglob(inet_ntoa(user->ip), glob);
} else {
/* The host part of the mask isn't IP-based */
+ if (IsFakeHost(user) && match_ircglob(user->fakehost, glob))
+ return 1;
if (hidden_host_suffix && user->handle_info) {
char hidden_host[HOSTLEN+1];
snprintf(hidden_host, sizeof(hidden_host), "%s.%s", user->handle_info->handle, hidden_host_suffix);