Add fake host support (assuming your ircd supports it)
authorMichael Poole <mdpoole@troilus.org>
Sat, 22 May 2004 04:24:57 +0000 (04:24 +0000)
committerMichael Poole <mdpoole@troilus.org>
Sat, 22 May 2004 04:24:57 +0000 (04:24 +0000)
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.
git-archimport-id: srvx@srvx.net--2004-srvx/srvx--devo--1.3--patch-67

13 files changed:
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

index e1d040be11cd34c6699f13124d095648b16c4c5b..34364d6628dae4859ab43ddb7f0d2aef0fa84fdd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,25 @@
 # 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:
index b347a8c6003561a769e944104aaac4e45602f265..60f8991681d7778b00ba994e46a4de1b61368eaa 100644 (file)
@@ -3438,14 +3438,15 @@ cmd_list_users(struct userNode *user, struct chanNode *channel, unsigned int arg
     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;
        }
     }
 
index 21bfa5f1bccc35c5534255f3203e50bf8a535ea8..439b68d9d8c4cfbb82692941820e2c2619278966 100644 (file)
@@ -238,6 +238,14 @@ StampUser(struct userNode *user, const char *stamp)
     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;
 
index 41d3efdd2253ea6b03ba271d7f4f7f15466c6f4b..d10c35ea9467b3fc794213d9298e93843d01fed7 100644 (file)
@@ -58,7 +58,7 @@
 #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)
@@ -75,6 +75,7 @@
 #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
@@ -101,6 +102,7 @@ struct userNode {
     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;
@@ -206,6 +208,7 @@ typedef void (*account_func_t) (struct userNode *user, const char *stamp);
 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);
index 22804e84e233433cf30cfe2ed04d1c1360c6d2bc..f7457006c80dc00115a25d1c4eaac09e71ee60e1 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -244,7 +244,7 @@ find_severity(const char *text)
  *   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.
@@ -273,7 +273,8 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES])
         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 */
index 68e42fef31dd652946dd06374557dcedbe9f3fa1..4d7b374d8c9b8c178023dde6d2a2d4a301e47ea9 100644 (file)
@@ -47,6 +47,9 @@
 #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"
@@ -93,6 +96,7 @@
 #define KEY_TABLE_WIDTH "table_width"
 #define KEY_ANNOUNCEMENTS "announcements"
 #define KEY_MAXLOGINS "maxlogins"
+#define KEY_FAKEHOST "fakehost"
 
 #define NICKSERV_VALID_CHARS   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
 
@@ -174,6 +178,8 @@ static const struct message_entry msgtab[] = {
     { "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" },
@@ -189,6 +195,7 @@ static const struct message_entry msgtab[] = {
     { "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" },
@@ -278,6 +285,8 @@ static const struct message_entry msgtab[] = {
     { "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" },
@@ -327,6 +336,8 @@ static struct {
     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;
@@ -494,6 +505,7 @@ free_handle_info(void *vhi)
         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);
@@ -815,6 +827,36 @@ reg_handle_rename_func(handle_rename_func_t func)
     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)
 {
@@ -871,6 +913,9 @@ 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. */
@@ -1300,6 +1345,9 @@ static NICKSERV_FUNC(cmd_handleinfo)
         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
@@ -1623,7 +1671,7 @@ static NICKSERV_FUNC(cmd_allowauth)
         /* 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)
@@ -2380,6 +2428,70 @@ static OPTION_FUNC(opt_epithet)
     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;
@@ -2580,6 +2692,8 @@ nickserv_saxdb_write(struct saxdb_context *ctx) {
             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;
 
@@ -3166,6 +3280,9 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
     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;
@@ -3319,7 +3436,8 @@ nickserv_conf_read(void)
     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;
@@ -3328,7 +3446,8 @@ nickserv_conf_read(void)
         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;
@@ -3358,6 +3477,10 @@ nickserv_conf_read(void)
     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);
@@ -3432,6 +3555,8 @@ nickserv_conf_read(void)
     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) {
@@ -3678,6 +3803,10 @@ init_nickserv(const char *nick)
     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);
index 97d3fb3dbcca7a40ce471012ba41e9920b092e18..9c1f6e930d291239ff202042b1107329e577c67b 100644 (file)
@@ -86,6 +86,7 @@ struct handle_info {
     char *epithet;
     char *infoline;
     char *handle;
+    char *fakehost;
 #ifdef WITH_PROTOCOL_BAHAMUT
     unsigned long id;
 #endif
index a38d836f9762c0b418932c7fc25a4a0c3a94890e..a63c0e148141ec2dd45c3823c7f87f386a6d4d1d 100644 (file)
@@ -115,6 +115,7 @@ static const struct message_entry msgtab[] = {
     { "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" },
@@ -397,7 +398,7 @@ static MODCMD_FUNC(cmd_ban)
     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]))
@@ -537,9 +538,8 @@ static MODCMD_FUNC(cmd_clearmodes)
        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;
@@ -966,7 +966,7 @@ static MODCMD_FUNC(cmd_kickall)
      * 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);
@@ -1015,7 +1015,7 @@ static MODCMD_FUNC(cmd_kickban)
        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);
@@ -1169,6 +1169,8 @@ static MODCMD_FUNC(cmd_whois)
     }
     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;
@@ -1206,7 +1208,7 @@ static MODCMD_FUNC(cmd_whois)
 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];
@@ -1875,7 +1877,7 @@ opserv_join_check(struct modeNode *mNode)
         /* 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)) {
@@ -2280,7 +2282,7 @@ static MODCMD_FUNC(cmd_clone)
            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);
index d0828f1c0c2c86b72064750be33672a3a66f968f..84531b0859eeaeaac9f2cc5f3fd6ba1b779d27fe 100644 (file)
@@ -271,6 +271,12 @@ irc_account(struct userNode *user, const char *stamp)
     }
 }
 
+void
+irc_fakehost(UNUSED_ARG(struct userNode *user), UNUSED_ARG(const char *host))
+{
+    /* not supported in bahamut */
+}
+
 void
 irc_regnick(struct userNode *user)
 {
index 8f5f1b9a791fd0f5d43a2a3815f1c0d038fb825b..35fc9bde2dbe7e5298db7dc812c8e9916625f357 100644 (file)
@@ -576,7 +576,10 @@ mod_chanmode_apply(struct userNode *who, struct chanNode *channel, struct mod_ch
             }
             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;
@@ -668,7 +671,9 @@ generate_hostmask(struct userNode *user, int options)
         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) {
index 046030ade02dcef2ea8ef79e85cfdda6dee0713b..b2aa696fdd7e1ec0376db60ad64ffd906d9cfb1c 100644 (file)
@@ -39,6 +39,7 @@
 #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)
@@ -418,6 +421,12 @@ irc_account(struct userNode *user, const char *stamp)
     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))
 {
@@ -1006,6 +1015,18 @@ static CMD_FUNC(cmd_account)
     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;
@@ -1184,7 +1205,7 @@ static CMD_FUNC(cmd_topic)
 
 static CMD_FUNC(cmd_num_topic)
 {
-    static struct chanNode *cn;
+    struct chanNode *cn;
 
     if (!argv[0])
         return 0; /* huh? */
@@ -1469,6 +1490,8 @@ init_parse(void)
     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);
@@ -1545,6 +1568,7 @@ init_parse(void)
     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 */
@@ -2008,6 +2032,18 @@ void mod_usermode(struct userNode *user, const char *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
     }
index 23f76e60531207d90364be169aeece5d34f929fa..d95144f4e5649f34cda6f31f67090e720795d5b4 100644 (file)
@@ -152,6 +152,7 @@ void irc_svsnick(struct userNode *from, struct userNode *target, const char *new
 /* 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, ...);
index 219d0afdc91ede210005662e444a5bbf42bb8a65..161e9d2bd9e4e2b8bbe9cded2fa7d20fdc461792 100644 (file)
@@ -340,6 +340,8 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick
         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);