fix userlist presence tracking; "version" command on all services
[srvx.git] / src / chanserv.c
index 32e7c0b48be1c331145d72bdcf7635e55b8622cd..a481a9e5507e1aaf3ec9fb45b34690f7143ed4e6 100644 (file)
@@ -747,25 +747,20 @@ int check_user_level(struct chanNode *channel, struct userNode *user, enum level
    user is optional, if not null, it skips checking that userNode
    (for the handle_part function) */
 static void
-scan_handle_presence(struct chanNode *channel, struct handle_info *handle, struct userNode *user)
+scan_user_presence(struct userData *uData, struct userNode *user)
 {
-    struct userData *uData;
-
-    if(!channel->channel_info || IsSuspended(channel->channel_info))
-        return;
+    struct modeNode *mn;
 
-    uData = GetTrueChannelAccess(channel->channel_info, handle);
-    if(uData)
+    if(IsSuspended(uData->channel)
+       || IsUserSuspended(uData)
+       || !(mn = find_handle_in_channel(uData->channel->channel, uData->handle, user)))
     {
-        struct modeNode *mn = find_handle_in_channel(channel, handle, user);
-
-       if(mn)
-       {
-           uData->present = 1;
-           uData->seen = now;
-       }
-       else
-           uData->present = 0;
+        uData->present = 0;
+    }
+    else
+    {
+        uData->present = 1;
+        uData->seen = now;
     }
 }
 
@@ -1723,8 +1718,7 @@ static CHANSERV_FUNC(cmd_register)
         channel = AddChannel(argv[1], now, NULL, NULL);
 
     cData = register_channel(channel, user->handle_info->handle);
-    add_channel_user(cData, handle, UL_OWNER, 0, NULL);
-    scan_handle_presence(channel, handle, NULL);
+    scan_user_presence(add_channel_user(cData, handle, UL_OWNER, 0, NULL), NULL);
     cData->modes = chanserv_conf.default_modes;
     change = mod_chanmode_dup(&cData->modes, 1);
     change->args[change->argc].mode = MODE_CHANOP;
@@ -2163,10 +2157,10 @@ static CHANSERV_FUNC(cmd_adduser)
        return 0;
     }
 
-    access = user_level_from_name(argv[1], UL_OWNER);
+    access = user_level_from_name(argv[2], UL_OWNER);
     if(!access)
     {
-       reply("CSMSG_INVALID_ACCESS", argv[1]);
+       reply("CSMSG_INVALID_ACCESS", argv[2]);
        return 0;
     }
 
@@ -2177,7 +2171,7 @@ static CHANSERV_FUNC(cmd_adduser)
        return 0;
     }
 
-    if(!(handle = modcmd_get_handle_info(user, argv[2])))
+    if(!(handle = modcmd_get_handle_info(user, argv[1])))
         return 0;
 
     if((actee = GetTrueChannelAccess(channel->channel_info, handle)))
@@ -2187,7 +2181,7 @@ static CHANSERV_FUNC(cmd_adduser)
     }
 
     actee = add_channel_user(channel->channel_info, handle, access, 0, NULL);
-    scan_handle_presence(channel, handle, NULL);
+    scan_user_presence(actee, NULL);
     reply("CSMSG_ADDED_USER", handle->handle, channel->name, access);
     return 1;
 }
@@ -3298,7 +3292,7 @@ static void
 zoot_list(struct listData *list)
 {
     struct userData *uData;
-    unsigned int start, curr;
+    unsigned int start, curr, highest, lowest;
     struct helpfile_table tmp_table;
     const char **temp, *msg;
 
@@ -3314,16 +3308,23 @@ zoot_list(struct listData *list)
     tmp_table.width = list->table.width;
     tmp_table.flags = list->table.flags;
     list->table.contents[0][0] = " ";
+    highest = list->highest;
+    if (list->lowest != 0)
+        lowest = list->lowest;
+    else if (highest < 100)
+        lowest = 1;
+    else
+        lowest = highest - 100;
     for(start = curr = 1; curr < list->table.length; )
     {
         uData = list->users[curr-1];
         list->table.contents[curr++][0] = " ";
-        if((curr == list->table.length) || (list->users[curr-1]->access != uData->access))
+        if((curr == list->table.length) || (list->users[curr-1]->access < lowest))
         {
             if(list->search)
-                send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER", list->channel->name, list->lowest, list->highest, list->search);
+                send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER", list->channel->name, lowest, highest, list->search);
             else
-                send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER", list->channel->name, list->lowest, list->highest);
+                send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER", list->channel->name, lowest, highest);
             temp = list->table.contents[--start];
             list->table.contents[start] = list->table.contents[0];
             tmp_table.contents = list->table.contents + start;
@@ -3331,6 +3332,8 @@ zoot_list(struct listData *list)
             table_send(list->bot, list->user->nick, 0, NULL, tmp_table);
             list->table.contents[start] = temp;
             start = curr;
+            highest = lowest - 1;
+            lowest = (highest < 100) ? 0 : (highest - 99);
         }
     }
 }
@@ -3448,7 +3451,7 @@ cmd_list_users(struct userNode *user, struct chanNode *channel, unsigned int arg
 
 static CHANSERV_FUNC(cmd_users)
 {
-    return cmd_list_users(CSFUNC_ARGS, 0, UL_OWNER);
+    return cmd_list_users(CSFUNC_ARGS, 1, UL_OWNER);
 }
 
 static CHANSERV_FUNC(cmd_wlist)
@@ -3460,14 +3463,17 @@ static CHANSERV_FUNC(cmd_clist)
 {
     return cmd_list_users(CSFUNC_ARGS, UL_COOWNER, UL_OWNER-1);
 }
+
 static CHANSERV_FUNC(cmd_mlist)
 {
     return cmd_list_users(CSFUNC_ARGS, UL_MASTER, UL_COOWNER-1);
 }
+
 static CHANSERV_FUNC(cmd_olist)
 {
     return cmd_list_users(CSFUNC_ARGS, UL_OP, UL_MASTER-1);
 }
+
 static CHANSERV_FUNC(cmd_plist)
 {
     return cmd_list_users(CSFUNC_ARGS, 1, UL_OP-1);
@@ -4937,7 +4943,7 @@ channel_level_option(enum levelOption option, struct userNode *user, struct chan
         value = user_level_from_name(argv[1], UL_OWNER+1);
         if(!value && !isdigit(argv[1][0]))
        {
-           reply("CSMSG_INVALID_ACCESS", index);
+           reply("CSMSG_INVALID_ACCESS", argv[1]);
             return 0;
         }
         uData = GetChannelUser(cData, user->handle_info);
@@ -5806,7 +5812,9 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
     {
         struct chanNode *cn;
         struct modeNode *mn;
-        if(IsSuspended(channel->channel) || !(cn = channel->channel->channel))
+        if(IsUserSuspended(channel)
+           || IsSuspended(channel->channel)
+           || !(cn = channel->channel->channel))
             continue;
 
         mn = GetUserMode(cn, user);
@@ -5883,10 +5891,10 @@ handle_part(struct userNode *user, struct chanNode *channel, UNUSED_ARG(const ch
 {
     struct chanData *cData;
     struct userData *uData;
-    struct handle_info *handle;
 
     cData = channel->channel_info;
-    if(!cData || IsSuspended(cData) || IsLocal(user)) return;
+    if(!cData || IsSuspended(cData) || IsLocal(user))
+        return;
 
     if((cData->flags & CHANNEL_DYNAMIC_LIMIT) && !channel->join_flooded)
     {
@@ -5899,11 +5907,8 @@ handle_part(struct userNode *user, struct chanNode *channel, UNUSED_ARG(const ch
        }
     }
 
-    if((handle = user->handle_info) && (uData = GetTrueChannelAccess(cData, handle)))
-    {
-       uData->seen = now;
-       scan_handle_presence(channel, handle, user);
-    }
+    if((uData = GetTrueChannelAccess(cData, user->handle_info)))
+       scan_user_presence(uData, user);
 
     if(IsHelping(user) && IsSupportHelper(user))
     {
@@ -6185,7 +6190,8 @@ chanserv_conf_read(void)
     str = database_get_data(conf_node, KEY_MAX_CHAN_BANS, RECDB_QSTRING);
     chanserv_conf.max_chan_bans = str ? atoi(str) : 512;
     str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING);
-    if(str) NickChange(chanserv, str, 0);
+    if(chanserv && str)
+        NickChange(chanserv, str, 0);
     str = database_get_data(conf_node, KEY_REFRESH_PERIOD, RECDB_QSTRING);
     chanserv_conf.refresh_period = str ? ParseInterval(str) : 3*60*60;
     str = database_get_data(conf_node, KEY_CTCP_SHORT_BAN_DURATION, RECDB_QSTRING);
@@ -6453,7 +6459,7 @@ chanserv_channel_read(const char *key, struct record_data *hir)
                 continue;
             cData->chOpts[chOpt] = str[0];
         }
-        if((str = database_get_data(channel, KEY_FLAGS, RECDB_QSTRING)))
+        if((str = database_get_data(obj, KEY_FLAGS, RECDB_QSTRING)))
             cData->flags = atoi(str);
     }
     else if((str = database_get_data(channel, KEY_FLAGS, RECDB_QSTRING)))
@@ -6515,11 +6521,7 @@ chanserv_channel_read(const char *key, struct record_data *hir)
         cData->flags &= ~CHANNEL_SUSPENDED;
     }
 
-    if((cData->flags & CHANNEL_SUSPENDED) && (suspended->expires > now))
-    {
-        timeq_add(suspended->expires, chanserv_expire_suspension, suspended);
-    }
-    else
+    if(!(cData->flags & CHANNEL_SUSPENDED))
     {
         struct mod_chanmode change;
         change.modes_set = change.modes_clear = 0;
@@ -6528,6 +6530,10 @@ chanserv_channel_read(const char *key, struct record_data *hir)
         change.args[0].member = AddChannelUser(chanserv, cNode);
         mod_chanmode_announce(chanserv, cNode, &change);
     }
+    else if(suspended->expires > now)
+    {
+        timeq_add(suspended->expires, chanserv_expire_suspension, suspended);
+    }
 
     str = database_get_data(channel, KEY_REGISTERED, RECDB_QSTRING);
     cData->registered = str ? (time_t)strtoul(str, NULL, 0) : now;
@@ -6885,7 +6891,6 @@ chanserv_db_cleanup(void) {
 void
 init_chanserv(const char *nick)
 {
-    chanserv = AddService(nick, "Channel Services");
     CS_LOG = log_register_type("ChanServ", "file:chanserv.log");
     conf_register_reload(chanserv_conf_read);
 
@@ -6965,10 +6970,10 @@ init_chanserv(const char *nick)
     DEFINE_COMMAND(wipeinfo, 2, MODCMD_REQUIRE_CHANUSER, "access", "master", NULL);
     DEFINE_COMMAND(resync, 1, MODCMD_REQUIRE_CHANUSER, "access", "master", NULL);
 
-    DEFINE_COMMAND(events, 1, MODCMD_REQUIRE_REGCHAN, "flags", "+nolog", "access", "coowner", NULL);
-    DEFINE_COMMAND(addban, 2, MODCMD_REQUIRE_REGCHAN, "access", "master", NULL);
-    DEFINE_COMMAND(addtimedban, 3, MODCMD_REQUIRE_REGCHAN, "access", "master", NULL);
-    DEFINE_COMMAND(delban, 2, MODCMD_REQUIRE_REGCHAN, "access", "master", NULL);
+    DEFINE_COMMAND(events, 1, MODCMD_REQUIRE_REGCHAN, "flags", "+nolog", "access", "350", NULL);
+    DEFINE_COMMAND(addban, 2, MODCMD_REQUIRE_REGCHAN, "access", "250", NULL);
+    DEFINE_COMMAND(addtimedban, 3, MODCMD_REQUIRE_REGCHAN, "access", "250", NULL);
+    DEFINE_COMMAND(delban, 2, MODCMD_REQUIRE_REGCHAN, "access", "250", NULL);
     DEFINE_COMMAND(uset, 1, MODCMD_REQUIRE_CHANUSER, "access", "peon", NULL);
 
     DEFINE_COMMAND(bans, 1, MODCMD_REQUIRE_REGCHAN, "access", "peon", "flags", "+nolog", NULL);
@@ -7044,8 +7049,13 @@ init_chanserv(const char *nick)
 
     note_types = dict_new();
     dict_set_free_data(note_types, chanserv_deref_note_type);
+    if(nick)
+    {
+        chanserv = AddService(nick, "Channel Services");
+        service_register(chanserv, '!');
+        reg_chanmsg_func('\001', chanserv, chanserv_ctcp_check);
+    }
     saxdb_register("ChanServ", chanserv_saxdb_read, chanserv_saxdb_write);
-    reg_chanmsg_func('\001', chanserv, chanserv_ctcp_check);
 
     if(chanserv_conf.channel_expire_frequency)
        timeq_add(now + chanserv_conf.channel_expire_frequency, expire_channels, NULL);