Further giveownership confirmation fixes.
[srvx.git] / src / chanserv.c
index c0401d327b372f87031a7ed57e75cac026ef7308..458e75f232b15d95e911377aed6483fa7e22b297 100644 (file)
@@ -1,5 +1,5 @@
 /* chanserv.c - Channel service bot
- * Copyright 2000-2004 srvx Development Team
+ * Copyright 2000-2006 srvx Development Team
  *
  * This file is part of srvx.
  *
@@ -197,6 +197,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_MULTIPLE_OWNERS", "There is more than one owner in %s; please use $bCLVL$b, $bDELOWNER$b and/or $bADDOWNER$b instead." },
     { "CSMSG_TRANSFER_WAIT", "You must wait %s before you can give ownership of $b%s$b to someone else." },
     { "CSMSG_NO_TRANSFER_SELF", "You cannot give ownership to your own account." },
+    { "CSMSG_CONFIRM_GIVEOWNERSHIP", "To really give ownership to $b%1$s$b, you must use 'giveownership *%1$s %2$s'." },
     { "CSMSG_OWNERSHIP_GIVEN", "Ownership of $b%s$b has been transferred to account $b%s$b." },
 
 /* Ban management */
@@ -227,7 +228,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_TOPIC_SET", "Topic is now '%s'." },
     { "CSMSG_NO_TOPIC", "$b%s$b does not have a default topic." },
     { "CSMSG_TOPICMASK_CONFLICT1", "I do not know how to make that topic work with the current topic mask in $b%s$b, which is: %s" },
-    { "CSMSG_TOPICMASK_CONFLICT2", "Please make sure your topic at most %d characters and matches the topic mask pattern." },
+    { "CSMSG_TOPICMASK_CONFLICT2", "Please make sure your topic is at most %d characters and matches the topic mask pattern." },
     { "CSMSG_TOPIC_LOCKED", "The %s topic is locked." },
     { "CSMSG_MASK_BUT_NO_TOPIC", "Warning: $b%s$b does not have a default topic, but you just set the topic mask." },
     { "CSMSG_TOPIC_MISMATCH", "Warning: The default topic for $b%s$b does not match the topic mask; changing it anyway." },
@@ -420,6 +421,7 @@ static const struct message_entry msgtab[] = {
 
 /* Channel configuration */
     { "CSMSG_INVALID_OPTION", "$b%s$b is not a valid %s option." },
+    { "CSMSG_INVALID_CFLAG", "$b%s$b is not a recognized channel flag." },
     { "CSMSG_CHANNEL_OPTIONS", "Channel Options:" },
     { "CSMSG_GREETING_TOO_LONG", "Your greeting ($b%d$b characters) must be shorter than $b%d$b characters." },
 
@@ -786,7 +788,7 @@ scan_user_presence(struct userData *uData, struct userNode *user)
 }
 
 static void
-chanserv_ctcp_check(struct userNode *user, struct chanNode *channel, char *text, UNUSED_ARG(struct userNode *bot))
+chanserv_ctcp_check(struct userNode *user, struct chanNode *channel, const char *text, UNUSED_ARG(struct userNode *bot))
 {
     unsigned int eflags, argc;
     char *argv[4];
@@ -803,7 +805,7 @@ chanserv_ctcp_check(struct userNode *user, struct chanNode *channel, char *text,
         return;
     /* We need to enforce against them; do so. */
     eflags = 0;
-    argv[0] = text;
+    argv[0] = (char*)text;
     argv[1] = user->nick;
     argc = 2;
     if(GetUserMode(channel, user))
@@ -3592,23 +3594,37 @@ static CHANSERV_FUNC(cmd_plist)
 
 static CHANSERV_FUNC(cmd_bans)
 {
+    struct userNode *search_u = NULL;
     struct helpfile_table tbl;
-    unsigned int matches = 0, timed = 0, ii;
+    unsigned int matches = 0, timed = 0, search_wilds = 0, ii;
     char t_buffer[INTERVALLEN], e_buffer[INTERVALLEN], *search;
     const char *msg_never, *triggered, *expires;
     struct banData *ban, **bans;
 
-    if(argc > 1)
-       search = argv[1];
-    else
+    if(argc < 2)
         search = NULL;
+    else if(strchr(search = argv[1], '!'))
+    {
+       search = argv[1];
+        search_wilds = search[strcspn(search, "?*")];
+    }
+    else if(!(search_u = GetUserH(search)))
+        reply("MSG_NICK_UNKNOWN", search);
 
     bans = alloca(channel->channel_info->banCount * sizeof(struct banData *));
 
     for(ban = channel->channel_info->bans; ban; ban = ban->next)
     {
-       if(search && !match_ircglobs(search, ban->mask))
-           continue;
+        if(search_u)
+        {
+            if(!user_matches_glob(search_u, ban->mask, MATCH_USENICK | MATCH_VISIBLE))
+                continue;
+        }
+       else if(search)
+        {
+            if(search_wilds ? !match_ircglobs(search, ban->mask) : !match_ircglob(search, ban->mask))
+                continue;
+        }
        bans[matches++] = ban;
        if(ban->expires)
             timed = 1;
@@ -5481,9 +5497,12 @@ static CHANSERV_FUNC(cmd_uset)
 static CHANSERV_FUNC(cmd_giveownership)
 {
     struct handle_info *new_owner_hi;
-    struct userData *new_owner, *curr_user;
+    struct userData *new_owner;
+    struct userData *curr_user;
+    struct userData *invoker;
     struct chanData *cData = channel->channel_info;
     struct do_not_register *dnr;
+    const char *confirm;
     unsigned int force;
     unsigned short co_access;
     char reason[MAXLEN];
@@ -5509,7 +5528,7 @@ static CHANSERV_FUNC(cmd_giveownership)
         }
         curr_user = owner;
     }
-    else if (!force && (now < (time_t)(cData->ownerTransfer + chanserv_conf.giveownership_period)))
+    else if(!force && (now < (time_t)(cData->ownerTransfer + chanserv_conf.giveownership_period)))
     {
         char delay[INTERVALLEN];
         intervalString(delay, cData->ownerTransfer + chanserv_conf.giveownership_period - now, user->handle_info);
@@ -5548,6 +5567,16 @@ static CHANSERV_FUNC(cmd_giveownership)
             chanserv_show_dnrs(user, cmd, NULL, new_owner_hi->handle);
         return 0;
     }
+    invoker = GetChannelUser(cData, user->handle_info);
+    if(invoker->access <= UL_OWNER)
+    {
+        confirm = make_confirmation_string(curr_user);
+        if((argc < 3) || strcmp(argv[2], confirm))
+        {
+            reply("CSMSG_CONFIRM_GIVEOWNERSHIP", new_owner_hi->handle, confirm);
+            return 0;
+        }
+    }
     if(new_owner->access >= UL_COOWNER)
         co_access = new_owner->access;
     else
@@ -5894,7 +5923,7 @@ handle_join(struct modeNode *mNode)
         unsigned int ii;
         for(ii = 0; ii < channel->banlist.used; ii++)
         {
-            if(user_matches_glob(user, channel->banlist.list[ii]->ban, MATCH_USENICK | MATCH_VISIBLE))
+            if(user_matches_glob(user, channel->banlist.list[ii]->ban, MATCH_USENICK))
             {
                 /* Riding a netburst.  Naughty. */
                 KickChannelUser(user, channel, chanserv, "User from far side of netsplit should have been banned - bye.");
@@ -5909,7 +5938,7 @@ handle_join(struct modeNode *mNode)
     {
         /* Not joining through a ban. */
         for(bData = cData->bans;
-            bData && !user_matches_glob(user, bData->mask, MATCH_USENICK | MATCH_VISIBLE);
+            bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
             bData = bData->next);
 
         if(bData)
@@ -6010,6 +6039,10 @@ handle_join(struct modeNode *mNode)
             uData->present = 1;
         }
     }
+
+    /* If user joining normally (not during burst), apply op or voice,
+     * and send greeting/userinfo as appropriate.
+     */
     if(!user->uplink->burst)
     {
         if(modes)
@@ -6020,7 +6053,7 @@ handle_join(struct modeNode *mNode)
             change.args[0].u.member = mNode;
             mod_chanmode_announce(chanserv, channel, &change);
         }
-        if(greeting && !user->uplink->burst)
+        if(greeting)
             send_message_type(4, user, chanserv, "(%s) %s", channel->name, greeting);
         if(uData && info)
             send_target_message(5, channel->name, chanserv, "[%s] %s", user->nick, uData->info);
@@ -6091,7 +6124,7 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
            || IsSuspended(channel->channel_info))
             continue;
         for(jj = 0; jj < channel->banlist.used; ++jj)
-            if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK | MATCH_VISIBLE))
+            if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK))
                 break;
         if(jj < channel->banlist.used)
             continue;
@@ -6148,6 +6181,8 @@ handle_part(struct modeNode *mn, UNUSED_ARG(const char *reason))
     {
        scan_user_presence(uData, mn->user);
         uData->seen = now;
+        if (uData->access >= UL_PRESENT)
+            cData->visited = now;
     }
 
     if(IsHelping(mn->user) && IsSupportHelper(mn->user))
@@ -6311,7 +6346,7 @@ handle_nick_change(struct userNode *user, UNUSED_ARG(const char *old_nick))
             continue;
         /* Look for a matching ban already on the channel. */
         for(jj = 0; jj < channel->banlist.used; ++jj)
-            if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK | MATCH_VISIBLE))
+            if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK))
                 break;
         /* Need not act if we found one. */
         if(jj < channel->banlist.used)
@@ -7178,17 +7213,19 @@ init_chanserv(const char *nick)
     CS_LOG = log_register_type("ChanServ", "file:chanserv.log");
     conf_register_reload(chanserv_conf_read);
 
-    reg_server_link_func(handle_server_link);
-
-    reg_new_channel_func(handle_new_channel);
-    reg_join_func(handle_join);
-    reg_part_func(handle_part);
-    reg_kick_func(handle_kick);
-    reg_topic_func(handle_topic);
-    reg_mode_change_func(handle_mode);
-    reg_nick_change_func(handle_nick_change);
+    if(nick)
+    {
+        reg_server_link_func(handle_server_link);
+        reg_new_channel_func(handle_new_channel);
+        reg_join_func(handle_join);
+        reg_part_func(handle_part);
+        reg_kick_func(handle_kick);
+        reg_topic_func(handle_topic);
+        reg_mode_change_func(handle_mode);
+        reg_nick_change_func(handle_nick_change);
+        reg_auth_func(handle_auth);
+    }
 
-    reg_auth_func(handle_auth);
     reg_handle_rename_func(handle_rename);
     reg_unreg_func(handle_unreg);
 
@@ -7339,7 +7376,7 @@ init_chanserv(const char *nick)
     if(nick)
     {
         const char *modes = conf_get_data("services/chanserv/modes", RECDB_QSTRING);
-        chanserv = AddService(nick, modes ? modes : NULL, "Channel Services", NULL);
+        chanserv = AddLocalUser(nick, nick, NULL, "Channel Services", modes);
         service_register(chanserv)->trigger = '!';
         reg_chanmsg_func('\001', chanserv, chanserv_ctcp_check);
     }