fix possible crash on user deletion
[srvx.git] / patches / srvx-successor.diff
1 diff -upr srvx-1.2rc4/src/chanserv.c Services/src/chanserv.c
2 --- src/chanserv.c      Mon Jul  7 18:29:34 2003
3 +++ src/chanserv.c      Mon Jul  7 19:17:00 2003
4 @@ -82,6 +82,7 @@
5  /* Channel data */
6  #define KEY_REGISTERED         "registered"
7  #define KEY_REGISTRAR          "registrar"
8 +#define KEY_SUCCESSOR        "successor"
9  #define KEY_SUSPENDED           "suspended"
10  #define KEY_PREVIOUS            "previous"
11  #define KEY_SUSPENDER          "suspender"
12 @@ -247,6 +248,9 @@
13  #define CSMSG_NO_BANS          "No channel bans found on $b%s$b."
14  #define CSMSG_BANS_REMOVED     "Removed all channel bans from $b%s$b."
15  
16 +#define CSMSG_SET_SUCCESSOR     "$b%s$b is now the successor of $b%s$b"
17 +#define CSMSG_ONLY_CO_SUCCESSOR "Only Coowners can be set as a successor."
18 +
19  /* Channel userlist */
20  #define CSMSG_ACCESS_SEARCH_HDR        "%s $b%ss$b matching %s:"
21  #define CSMSG_ACCESS_HEADER    "%s $b%ss$b:"
22 @@ -321,6 +325,7 @@
23  #define CSMSG_CHANNEL_BANS     "$bBan Count:           $b%i"
24  #define CSMSG_CHANNEL_USERS    "$b%s Count:%*s$b%i"
25  #define CSMSG_CHANNEL_REGISTRAR "$bRegistrar:           $b%s"
26 +#define CSMSG_CHANNEL_SUCCESSOR  "$bSuccessor:            $b%s"
27  #define CSMSG_CHANNEL_SUSPENDED "$b%s$b is suspended:"
28  #define CSMSG_CHANNEL_HISTORY   "Suspension history for $b%s$b:"
29  #define CSMSG_CHANNEL_SUSPENDED_0 " by %s: %s"
30 @@ -400,6 +405,8 @@
31  #define CSMSG_KICK_FORMAT      "%s (%s)"
32  #define CSMSG_PROTECT_REASON   "That user is protected."
33  
34 +#define CSMSG_SUCCESSOR "$bSuccessor:$b %s"
35 +
36  #define CSFUNC_ARGS            user, channel, argc, argv, cmd
37  
38  static unsigned char *CHANSERV_DEFAULT_MODES = "+nt";
39 @@ -1505,8 +1512,9 @@ expire_channels(void *data)
40      struct chanData *channel, *next;
41      struct chanNode *save;
42      struct userData *user;
43 -    char delay[INTERVALLEN], reason[INTERVALLEN + 64];
44 -    int suspended;
45 +    struct handle_info *successor_handle;
46 +    char delay[INTERVALLEN], reason[INTERVALLEN + 64];
47 +    int suspended, ownerfound = 0;
48      (void)data;
49  
50      intervalString(delay, chanserv_conf.channel_expire_delay);
51 @@ -1514,11 +1522,36 @@ expire_channels(void *data)
52  
53      for(channel = channelList; channel; channel = next)
54      {
55 -       next = channel->next;
56 -
57 +          next = channel->next;
58 +
59 +       /* Check for a successor, see if there's an owner first */
60 +       for(user = channel->users; user; user=user->next)
61 +       {
62 +          if(user->present && (user->access >= ulOwner)) 
63 +          {
64 +             ownerfound = 1;
65 +             break;
66 +          }
67 +       }
68 +       if(channel->successor && !ownerfound) 
69 +       {
70 +          if((successor_handle = get_handle_info(channel->successor)))
71 +          {
72 +              if((user = GetTrueChannelAccess(channel, successor_handle)))
73 +              {
74 +                  channel->userCount[user->access]--;
75 +                  userCount[user->access]--;
76 +
77 +                   user->access = ulOwner;
78 +
79 +                   channel->userCount[user->access]++;
80 +                   userCount[user->access]++;
81 +               }
82 +           }
83 +        }
84          /* See if the channel can be expired. */
85          if((now - channel->visited) <= chanserv_conf.channel_expire_delay) continue;
86 -       if(IsProtected(channel)) continue;
87 +           if(IsProtected(channel)) continue;
88  
89          /* Make sure there are no high-ranking users still in the channel. */
90          for(user=channel->users; user; user=user->next)
91 @@ -4322,6 +4355,11 @@ static CHANSERV_FUNC(cmd_info)
92          }
93      }
94  
95 +    if(cData->successor)
96 +    {
97 +       chanserv_notice(user, CSMSG_CHANNEL_SUCCESSOR, cData->successor);
98 +    }
99 +
100      if(privileged)
101      {
102         if((dnr = chanserv_is_dnr(chan_name, NULL)))
103 @@ -5224,6 +5262,58 @@ static CHANNEL_OPTION_FUNC(opt_topicmask
104      return 1;
105  }
106  
107 +static CHANNEL_OPTION_FUNC(opt_successor)
108 +{
109 +   struct userNode *target;
110 +   struct chanData *cData;
111 +   struct userData *uData;
112 +   struct handle_info *target_handle;
113 +
114 +   REQUIRE_PARAMS(2);
115 +
116 +   if(!(cData = channel->channel_info)) 
117 +   {
118 +      return 0;
119 +   }
120 +   if((argv[1][0] == '?') || (argv[1][0] == 0)) {
121 +      chanserv_notice(user, CSMSG_SUCCESSOR, (cData->successor ? cData->successor : "None."));
122 +      return 1;
123 +   }
124 +   if((target = GetUserH(argv[1])))
125 +   {
126 +      target_handle = target->handle_info;
127 +   }
128 +   else if(argv[1][0] == '*')
129 +   {
130 +      if(!(target_handle = get_handle_info(argv[1]+1)))
131 +      {
132 +          chanserv_notice(user, MSG_HANDLE_UNKNOWN, argv[1]+1);
133 +          return 0;
134 +      }
135 +   }
136 +   else
137 +   {
138 +      chanserv_notice(user, MSG_NICK_UNKNOWN, argv[1]);
139 +      return 0;
140 +   }
141 +   if((uData = GetTrueChannelAccess(channel->channel_info, target_handle)))
142 +   {
143 +      if(uData->access != ulCoowner) 
144 +      {
145 +         chanserv_notice(user, CSMSG_ONLY_CO_SUCCESSOR);
146 +         return 0;
147 +      }
148 +      cData->successor = strdup(uData->handle->handle);
149 +      chanserv_notice(user, CSMSG_SET_SUCCESSOR, uData->handle->handle, channel->name);
150 +      return 1;
151 +   }
152 +   else
153 +   {
154 +      chanserv_notice(user, CSMSG_USER_NO_ACCESS, target_handle->handle, channel->name);
155 +      return 0;
156 +   }  
157 +}
158 +
159  int opt_greeting_common(struct userNode *user, struct chanNode *channel, int argc, unsigned char *argv[], char *name, char **data)
160  {
161      (void)channel;
162 @@ -6934,6 +7024,8 @@ chanserv_channel_read(const char *key, s
163      }
164  
165      if((cData->suspended = suspended)) suspended->cData = cData;
166 +    str = database_get_data(channel, KEY_SUCCESSOR, RECDB_QSTRING);
167 +    if(str) cData->successor = strdup(str);
168      str = database_get_data(channel, KEY_REGISTERED, RECDB_QSTRING);
169      cData->registered = str ? (time_t)strtoul(str, NULL, 0) : now;
170      str = database_get_data(channel, KEY_VISITED, RECDB_QSTRING);
171 @@ -7127,6 +7219,7 @@ chanserv_write_channel(struct saxdb_cont
172      saxdb_write_int(ctx, KEY_MAX, channel->max);
173      if(channel->topic[0]) saxdb_write_string(ctx, KEY_TOPIC, channel->topic);
174      if(channel->registrar) saxdb_write_string(ctx, KEY_REGISTRAR, channel->registrar);
175 +    if(channel->successor) saxdb_write_string(ctx, KEY_SUCCESSOR, channel->successor);
176      if(channel->greeting) saxdb_write_string(ctx, KEY_GREETING, channel->greeting);
177      if(channel->user_greeting) saxdb_write_string(ctx, KEY_USER_GREETING, channel->user_greeting);
178      if(channel->topic_mask) saxdb_write_string(ctx, KEY_TOPIC_MASK, channel->topic_mask);
179 @@ -7412,6 +7505,7 @@ init_chanserv(const char *nick)
180      DEFINE_CHANNEL_OPTION(ctcpusers);
181      DEFINE_CHANNEL_OPTION(ctcpreaction);
182      DEFINE_CHANNEL_OPTION(peoninvite);
183 +    DEFINE_CHANNEL_OPTION(successor);
184  
185      /* Alias set topic to set defaulttopic for compatibility. */
186      modcmd_register(chanserv_module, "set topic", chan_opt_defaulttopic, 1, 0, NULL);
187 diff -upr srvx-1.2rc4/src/chanserv.h Services/src/chanserv.h
188 --- src/chanserv.h      Mon Jul  7 18:29:34 2003
189 +++ src/chanserv.h      Mon Jul  7 19:16:55 2003
190 @@ -95,6 +95,7 @@ struct chanData
191      char               *greeting;
192      char               *user_greeting;
193      char               *registrar;
194 +    char        *successor;
195      char                *topic_mask;
196  
197      unsigned int       limit;
198 diff -upr srvx-1.2rc4/src/chanserv.help Services/src/chanserv.help
199 --- src/chanserv.help   Wed Jun 18 01:53:36 2003
200 +++ src/chanserv.help   Mon Jul  7 19:15:06 2003
201 @@ -322,6 +322,7 @@
202          "DYNLIMIT:     Adjusts user limit (+l channel mode) to prevent join floods.",
203          "TOPICSNARF:   Topics set manually (by /TOPIC #channel ...) change default $C topic",
204          "PEONINVITE:   Indicates whether peons may use the $bINVITEME$b command.",
205 +        "SUCCESSOR:     Determines if a coowner gets ownership of a channel when the owner's handle expires.",
206          "$bIRCOP ONLY$b:",
207          "NODELETE:  Prevents channel deletion.",
208          "$uSee Also:$u set pubcmd, set strictop, set autoop, set enfmodes, set enftopic, set protect, set toys, set setters, set topicrefresh, set ctcpusers, set ctcpreaction");
209 @@ -427,6 +428,8 @@
210          "$b2$b  Short timed ban (defaults to 3 minutes) on disallowed CTCPs.",
211          "$b3$b  Long timed ban (defaults to 1 hour) on disallowed CTCPs.",
212          "$uSee Also:$u set, set ctcpusers");
213 +"SET SUCCESSOR" ("/msg $C SET <#channel> SUCCESSOR <nick|*account>",
214 +        "This is a setting to determine who will be the next owner of a channel when the current owner's handle expires.");
215  "SETINFO" ("/msg $C SETINFO <#channel> <info>",
216          "This command will set a user defined information message to be displayed when you join the channel. By setting the message to '*', you will clear your message.",
217          "$uSee Also:$u access");