1 /* chanserv.c - Channel service bot
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 #include "opserv.h" /* for opserv_bad_channel() */
33 #define CHANSERV_CONF_NAME "services/chanserv"
35 /* ChanServ options */
36 #define KEY_SUPPORT_CHANNEL "support_channel"
37 #define KEY_SUPPORT_CHANNEL_MODES "support_channel_modes"
38 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
39 #define KEY_INFO_DELAY "info_delay"
40 #define KEY_MAX_GREETLEN "max_greetlen"
41 #define KEY_ADJUST_THRESHOLD "adjust_threshold"
42 #define KEY_ADJUST_DELAY "adjust_delay"
43 #define KEY_CHAN_EXPIRE_FREQ "chan_expire_freq"
44 #define KEY_CHAN_EXPIRE_DELAY "chan_expire_delay"
45 #define KEY_BAN_TIMEOUT_FREQ "ban_timeout_freq"
46 #define KEY_MAX_CHAN_USERS "max_chan_users"
47 #define KEY_MAX_CHAN_BANS "max_chan_bans"
48 #define KEY_NICK "nick"
49 #define KEY_OLD_CHANSERV_NAME "old_chanserv_name"
50 #define KEY_8BALL_RESPONSES "8ball"
51 #define KEY_OLD_BAN_NAMES "old_ban_names"
52 #define KEY_REFRESH_PERIOD "refresh_period"
53 #define KEY_CTCP_SHORT_BAN_DURATION "ctcp_short_ban_duration"
54 #define KEY_CTCP_LONG_BAN_DURATION "ctcp_long_ban_duration"
55 #define KEY_MAX_OWNED "max_owned"
56 #define KEY_IRC_OPERATOR_EPITHET "irc_operator_epithet"
57 #define KEY_NETWORK_HELPER_EPITHET "network_helper_epithet"
58 #define KEY_SUPPORT_HELPER_EPITHET "support_helper_epithet"
59 #define KEY_NODELETE_LEVEL "nodelete_level"
60 #define KEY_MAX_USERINFO_LENGTH "max_userinfo_length"
61 #define KEY_GIVEOWNERSHIP_PERIOD "giveownership_timeout"
63 /* ChanServ database */
64 #define KEY_VERSION_CONTROL "version_control"
65 #define KEY_CHANNELS "channels"
66 #define KEY_NOTE_TYPES "note_types"
68 /* version control paramiter */
69 #define KEY_VERSION_NUMBER "version_number"
71 /* Note type parameters */
72 #define KEY_NOTE_OPSERV_ACCESS "opserv_access"
73 #define KEY_NOTE_CHANNEL_ACCESS "channel_access"
74 #define KEY_NOTE_SETTER_ACCESS "setter_access"
75 #define KEY_NOTE_VISIBILITY "visibility"
76 #define KEY_NOTE_VIS_PRIVILEGED "privileged"
77 #define KEY_NOTE_VIS_CHANNEL_USERS "channel_users"
78 #define KEY_NOTE_VIS_ALL "all"
79 #define KEY_NOTE_MAX_LENGTH "max_length"
80 #define KEY_NOTE_SETTER "setter"
81 #define KEY_NOTE_NOTE "note"
83 /* Do-not-register channels */
85 #define KEY_DNR_SET "set"
86 #define KEY_DNR_SETTER "setter"
87 #define KEY_DNR_REASON "reason"
90 #define KEY_REGISTERED "registered"
91 #define KEY_REGISTRAR "registrar"
92 #define KEY_SUSPENDED "suspended"
93 #define KEY_PREVIOUS "previous"
94 #define KEY_SUSPENDER "suspender"
95 #define KEY_ISSUED "issued"
96 #define KEY_REVOKED "revoked"
97 #define KEY_SUSPEND_EXPIRES "suspend_expires"
98 #define KEY_SUSPEND_REASON "suspend_reason"
99 #define KEY_GIVEOWNERSHIP "giveownership"
100 #define KEY_STAFF_ISSUER "staff_issuer"
101 #define KEY_OLD_OWNER "old_owner"
102 #define KEY_TARGET "target"
103 #define KEY_TARGET_ACCESS "target_access"
104 #define KEY_VISITED "visited"
105 #define KEY_TOPIC "topic"
106 #define KEY_GREETING "greeting"
107 #define KEY_USER_GREETING "user_greeting"
108 #define KEY_MODES "modes"
109 #define KEY_FLAGS "flags"
110 #define KEY_OPTIONS "options"
111 #define KEY_USERS "users"
112 #define KEY_BANS "bans" /* for lamers */
113 #define KEY_MAX "max"
114 #define KEY_NOTES "notes"
115 #define KEY_TOPIC_MASK "topic_mask"
116 #define KEY_OWNER_TRANSFER "owner_transfer"
117 #define KEY_MAXSETINFO "maxsetinfo"
120 #define KEY_LEVEL "level"
121 #define KEY_INFO "info"
122 #define KEY_SEEN "seen"
123 #define KEY_ACCESSEXPIRY "accessexpiry"
124 #define KEY_CLVLEXPIRY "clvlexpiry"
125 #define KEY_LASTLEVEL "lastlevel"
128 #define KEY_OWNER "owner"
129 #define KEY_REASON "reason"
130 #define KEY_SET "set"
131 #define KEY_DURATION "duration"
132 #define KEY_EXPIRES "expires"
133 #define KEY_TRIGGERED "triggered"
135 #define KEY_GOD_TIMEOUT "god_timeout"
137 #define CHANNEL_DEFAULT_FLAGS (CHANNEL_OFFCHANNEL)
138 #define CHANNEL_DEFAULT_OPTIONS "lmoooanpcnat"
140 /* Administrative messages */
141 static const struct message_entry msgtab
[] = {
142 { "CSMSG_CHANNELS_EXPIRED", "%i channels expired." },
144 /* Channel registration */
145 { "CSMSG_REG_SUCCESS", "You now have ownership of $b%s$b." },
146 { "CSMSG_PROXY_SUCCESS", "%s now has ownership of $b%s$b." },
147 { "CSMSG_ALREADY_REGGED", "$b%s$b is registered to someone else." },
148 { "CSMSG_MUST_BE_OPPED", "You must be a channel operator (+o) in $b%s$b to register it." },
149 { "CSMSG_PROXY_FORBIDDEN", "You may not register a channel for someone else." },
150 { "CSMSG_OWN_TOO_MANY", "%s already owns more than the limit of %d channels. Use FORCE to override." },
151 { "CSMSG_YOU_OWN_TOO_MANY", "You already own more than the limit of %d channels. Ask a staff member for help." },
152 { "CSMSG_ANOTHER_SERVICE", "Another service bot is in that channel already. Ask a staff member for help." },
154 /* Do-not-register channels */
155 { "CSMSG_NOT_DNR", "$b%s$b is not a valid channel name or *account." },
156 { "CSMSG_DNR_SEARCH_RESULTS", "$bDo-Not-Register Channels$b" },
157 { "CSMSG_DNR_INFO", "$b%s$b (set by $b%s$b): %s" },
158 { "CSMSG_DNR_INFO_SET", "$b%s$b (set %s ago by $b%s$b): %s" },
159 { "CSMSG_MORE_DNRS", "%d more do-not-register entries skipped." },
160 { "CSMSG_DNR_CHANNEL", "Only network staff may register $b%s$b." },
161 { "CSMSG_DNR_CHANNEL_MOVE", "Only network staff may move $b%s$b." },
162 { "CSMSG_DNR_ACCOUNT", "Only network staff may register channels to $b%s$b." },
163 { "CSMSG_NOREGISTER_CHANNEL", "$b%s$b has been added to the do-not-register list." },
164 { "CSMSG_NO_SUCH_DNR", "$b%s$b is not in the do-not-register list." },
165 { "CSMSG_DNR_REMOVED", "$b%s$b has been removed from the do-not-register list." },
167 /* Channel unregistration */
168 { "CSMSG_UNREG_SUCCESS", "$b%s$b has been unregistered." },
169 { "CSMSG_UNREG_NODELETE", "$b%s$b is protected from unregistration." },
170 { "CSMSG_CHAN_SUSPENDED", "$b$C$b access to $b%s$b has been temporarily suspended (%s)." },
171 { "CSMSG_CONFIRM_UNREG", "To confirm this unregistration, you must use 'unregister %s %s'." },
174 { "CSMSG_MOVE_SUCCESS", "Channel registration has been moved to $b%s$b." },
175 { "CSMSG_MOVE_NODELETE", "$b%s$b is protected from unregistration, and cannot be moved." },
177 /* Channel merging */
178 { "CSMSG_MERGE_SUCCESS", "Channel successfully merged into $b%s$b." },
179 { "CSMSG_MERGE_SELF", "Merging cannot be performed if the source and target channels are the same." },
180 { "CSMSG_MERGE_NODELETE", "You may not merge a channel that is marked NoDelete." },
181 { "CSMSG_MERGE_SUSPENDED", "Merging cannot be performed if the source or target channel is suspended." },
182 { "CSMSG_MERGE_NOT_OWNER", "You must be the owner of the target channel (or a helper) to merge into the channel." },
184 /* Handle unregistration */
185 { "CSMSG_HANDLE_UNREGISTERED", "As a result of your account unregistration, you have been deleted from all of your channels' userlists." },
188 { "CSMSG_NOT_USER", "You lack access to $b%s$b." },
189 { "CSMSG_NO_CHAN_USER", "%s lacks access to $b%s$b." },
190 { "CSMSG_NO_ACCESS", "You lack sufficient access to use this command." },
191 { "CSMSG_NOT_REGISTERED", "$b%s$b has not been registered with $b$C$b." },
192 { "CSMSG_MAXIMUM_LAMERS", "This channel has reached the lamer count limit of $b%d$b." },
193 { "CSMSG_MAXIMUM_USERS", "This channel has reached the user count limit of $b%d$b." },
194 { "CSMSG_ILLEGAL_CHANNEL", "$b%s$b is an illegal channel, and cannot be registered." },
195 { "CSMSG_GODMODE_UP", "You may not use $b%s$b to op yourself unless you are on the user list. Use the $bop$b command instead." },
196 { "CSMSG_ALREADY_OPPED", "You are already opped in $b%s$b." },
197 { "CSMSG_ALREADY_HALFOPPED", "You are already halfopped in $b%s$b." },
198 { "CSMSG_ALREADY_VOICED", "You are already voiced in $b%s$b." },
199 { "CSMSG_ALREADY_DOWN", "You are not opped, halfopped, or voiced in $b%s$b." },
200 { "CSMSG_ALREADY_OPCHANNED", "There has been no net.join since the last opchan in $b%s$b." },
201 { "CSMSG_OPCHAN_DONE", "I have (re-)opped myself in $b%s$b." },
203 /* Removing yourself from a channel. */
204 { "CSMSG_NO_OWNER_DELETEME", "You cannot delete your owner access in $b%s$b." },
205 { "CSMSG_CONFIRM_DELETEME", "To really remove yourself, you must use 'deleteme %s'." },
206 { "CSMSG_DELETED_YOU", "Your $b%d$b access has been deleted from $b%s$b." },
208 /* User management */
209 { "CSMSG_AUTO_DELETED", "Your %s access has expired in %s." },
210 { "CSMSG_CLVL_EXPIRED", "Your CLVL access has expired in %s." },
211 { "CSMSG_ADDED_USER", "Added %s to the %s user list with access %s (%d)." },
212 { "CSMSG_DELETED_USER", "Deleted %s (with access %d) from the %s user list." },
213 { "CSMSG_BAD_RANGE", "Invalid access range; minimum (%d) must be greater than maximum (%d)." },
214 { "CSMSG_DELETED_USERS", "Deleted accounts matching $b%s$b with access from $b%d$b to $b%d$b from the %s user list." },
215 { "CSMSG_TRIMMED_USERS", "Trimmed $b%d users$b with access from %d to %d from the %s user list who were inactive for at least %s." },
216 { "CSMSG_INCORRECT_ACCESS", "%s has access $b%s$b, not %s." },
217 { "CSMSG_USER_EXISTS", "%s is already on the $b%s$b user list (with %s access)." },
218 { "CSMSG_ADDUSER_PENDING", "I have sent him/her a message letting them know, and if they auth or register soon, I will finish adding them automatically." },
219 { "CSMSG_ADDUSER_PENDING_ALREADY", "He or she is already pending addition to %s once he/she auths with $b$N$b." },
220 { "CSMSG_ADDUSER_PENDING_HEADER", "Users to add to channels pending logins:" }, /* Remove after testing? */
221 { "CSMSG_ADDUSER_PENDING_LIST", "Channel %s user %s" }, /* Remove after testing? */
222 { "CSMSG_ADDUSER_PENDING_FOOTER", "--------- End of pending list ----------" }, /* Remove after testing? */
223 /*{ "CSMSG_ADDUSER_PENDING_NOTINCHAN", "That user is not in %s, and is not auth'd." }, */
224 { "CSMSG_ADDUSER_PENDING_TARGET", "Channel Services bot here: %s would like to add you to my userlist in channel %s, but you are not authenticated to $b$N$b. Please authenticate now and you will be added. If you do not have an account, type /msg $N help register" },
225 { "CSMSG_CANNOT_TRIM", "You must include a minimum inactivity duration of at least 60 seconds to trim." },
227 { "CSMSG_NO_SELF_CLVL", "You cannot change your own access." },
228 { "CSMSG_NO_BUMP_ACCESS", "You cannot give users access greater than or equal to your own." },
229 { "CSMSG_NO_BUMP_EXPIRY", "You cannot give users timed $bCLVL$b's when they already have timed access." },
230 { "CSMSG_MULTIPLE_OWNERS", "There is more than one owner in %s; please use $bCLVL$b, $bDELOWNER$b and/or $bADDOWNER$b instead." },
231 { "CSMSG_NO_OWNER", "There is no owner for %s; please use $bCLVL$b and/or $bADDOWNER$b instead." },
232 { "CSMSG_TRANSFER_WAIT", "You must wait %s before you can give ownership of $b%s$b to someone else." },
233 { "CSMSG_NO_TRANSFER_SELF", "You cannot give ownership to your own account." },
234 { "CSMSG_OWNERSHIP_GIVEN", "Ownership of $b%s$b has been transferred to account $b%s$b." },
237 { "CSMSG_LAMER_ADDED", "Added $b%s$b to %s LAMERs." },
238 { "CSMSG_TIMED_LAMER_ADDED", "LAMERed $b%s$b on %s for %s." },
239 { "CSMSG_KICK_BAN_DONE", "Kickbanned $b%s$b from %s." },
240 { "CSMSG_BAN_DONE", "Banned $b%s$b from %s." },
241 { "CSMSG_REASON_CHANGE", "Reason for LAMER $b%s$b changed." },
242 { "CSMSG_LAMER_EXTENDED", "Extended LAMER for $b%s$b, now expires in %s." },
243 { "CSMSG_BAN_REMOVED", "Ban(s) and LAMER(s) matching $b%s$b were removed." },
244 { "CSMSG_TRIMMED_LAMERS", "Trimmed $b%d LAMERs$b from the %s LAMER list that were inactive for at least %s." },
245 { "CSMSG_REDUNDANT_BAN", "$b%s$b is already banned in %s." },
246 { "CSMSG_REDUNDANT_LAMER", "$b%s$b is already LAMER'd in %s." },
247 { "CSMSG_DURATION_TOO_LOW", "Timed bans must last for at least 15 seconds." },
248 { "CSMSG_DURATION_TOO_HIGH", "Timed bans must last for less than 2 years." },
249 { "CSMSG_LAME_MASK", "$b%s$b is a little too general. Try making it more specific." },
250 { "CSMSG_MASK_PROTECTED", "Sorry, ban for $b%s$b conflicts with a protected user's hostmask." },
251 { "CSMSG_NO_MATCHING_USERS", "No one in $b%s$b has a hostmask matching $b%s$b." },
252 { "CSMSG_BAN_NOT_FOUND", "Sorry, no ban or LAMER found: $b%s$b." },
253 { "CSMSG_BANLIST_FULL", "The $b%s$b channel ban list is $bfull$b." },
255 { "CSMSG_INVALID_TRIM", "$b%s$b isn't a valid trim target." },
257 /* Channel management */
258 { "CSMSG_CHANNEL_OPENED", "$b%s$b has been opened." },
259 { "CSMSG_WIPED_INFO_LINE", "Removed $b%s$b's infoline in $b%s$b." },
260 { "CSMSG_RESYNCED_USERS", "Synchronized users in $b%s$b with the userlist." },
262 { "CSMSG_TOPIC_SET", "Topic is now '%s'." },
263 { "CSMSG_NO_TOPIC", "$b%s$b does not have a default topic." },
264 { "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" },
265 { "CSMSG_TOPICMASK_CONFLICT2", "Please make sure your topic is at most %d characters and matches the topic mask pattern." },
266 { "CSMSG_TOPIC_LOCKED", "The %s topic is locked." },
267 { "CSMSG_MASK_BUT_NO_TOPIC", "Warning: $b%s$b does not have a default topic, but you just set the topic mask." },
268 { "CSMSG_TOPIC_MISMATCH", "Warning: The default topic for $b%s$b does not match the topic mask; changing it anyway." },
270 { "CSMSG_MODES_SET", "Channel modes are now $b%s$b." },
271 { "CSMSG_DEFAULTED_MODES", "Channel modes for $b%s$b are set to their defaults." },
272 { "CSMSG_NO_MODES", "$b%s$b does not have any default modes." },
273 { "CSMSG_MODE_LOCKED", "Modes conflicting with $b%s$b are not allowed in %s." },
274 { "CSMSG_CANNOT_SET", "That setting is above your current level, so you cannot change it." },
275 { "CSMSG_OWNER_DEFAULTS", "You must have access 500 in %s to reset it to the default options." },
276 { "CSMSG_CONFIRM_DEFAULTS", "To reset %s's settings to the defaults, you must use 'set defaults %s'." },
277 { "CSMSG_SETTINGS_DEFAULTED", "All settings for %s have been reset to default values." },
278 { "CSMSG_BAD_SETLEVEL", "You cannot change any setting to above your level." },
279 { "CSMSG_BAD_SETTERS", "You cannot change Setters to above your level." },
280 { "CSMSG_INVALID_MODE_LOCK", "$b%s$b is an invalid mode lock." },
281 { "CSMSG_INVALID_NUMERIC", "$b%d$b is not a valid choice. Choose one:" },
282 { "CSMSG_SET_DEFAULT_TOPIC", "$bDefaultTopic$b %s" },
283 { "CSMSG_SET_TOPICMASK", "$bTopicMask $b %s" },
284 { "CSMSG_SET_GREETING", "$bGreeting $b %s" },
285 { "CSMSG_SET_USERGREETING", "$bUserGreeting$b %s" },
286 { "CSMSG_SET_MODES", "$bModes $b %s" },
287 { "CSMSG_SET_NODELETE", "$bNoDelete $b %s" },
288 { "CSMSG_SET_DYNLIMIT", "$bDynLimit $b %s - +l joinflood protection." },
289 { "CSMSG_SET_OFFCHANNEL", "$bOffChannel $b %s" },
290 { "CSMSG_SET_USERINFO", "$bUserInfo $b %d - and above userinfos are shown." },
291 { "CSMSG_SET_TOPICSNARF", "$bTopicSnarf $b %d" },
292 { "CSMSG_SET_INVITEME", "$bInviteMe $b %d - Userlevel required to invite self." },
293 { "CSMSG_SET_ENFOPS", "$bEnfOps $b %d - level and above can op unknown users." },
294 { "CSMSG_SET_ENFHALFOPS", "$bEnfHalfOps $b %d - level and above can hop unknown users." },
295 { "CSMSG_SET_ENFMODES", "$bEnfModes $b %d - and above can change channel modes." },
296 { "CSMSG_SET_ENFTOPIC", "$bEnfTopic $b %d - and above can set the topic." },
297 { "CSMSG_SET_PUBCMD", "$bPubCmd $b %d - and above can use public commands." },
298 { "CSMSG_SET_SETTERS", "$bSetters $b %d - and above can change these settings." },
299 { "CSMSG_SET_AUTOMODE", "$bAutoMode $b %d - %s" },
300 { "CSMSG_SET_PROTECT", "$bProtect $b %d - %s" },
301 { "CSMSG_SET_TOYS", "$bToys $b %d - %s" },
302 { "CSMSG_SET_CTCPREACTION", "$bCTCPReaction$b %d - %s" },
303 { "CSMSG_SET_TOPICREFRESH", "$bTopicRefresh$b %d - %s" },
304 { "CSMSG_SET_RESYNC", "$bResync $b %d - %s" },
305 { "CSMSG_SET_BANTIMEOUT", "$bBanTimeout $b %d - %s" },
306 { "CSMSG_SET_MAXSETINFO", "$bMaxSetInfo $b %d - maximum characters in a setinfo line." },
308 { "CSMSG_USET_AUTOOP", "$bAutoOp $b %s" },
309 { "CSMSG_USET_AUTOVOICE", "$bAutoVoice $b %s" },
310 { "CSMSG_USET_AUTOINVITE", "$bAutoInvite $b %s" },
311 { "CSMSG_USET_AUTOJOIN", "$bAutoJoin $b %s" },
312 { "CSMSG_USET_INFO", "$bInfo $b %s" },
314 { "CSMSG_USER_PROTECTED", "Sorry, $b%s$b is protected." },
315 { "CSMSG_USER_PROTECTED_KICK", "That user is protected." }, /* No $ or %s replacements! */
316 { "CSMSG_OPBY_LOCKED", "You may not op users who lack op or greater access." },
317 { "CSMSG_HOPBY_LOCKED", "You may not halfop users who lack halfop or greater access." },
318 { "CSMSG_PROCESS_FAILED", "$b$C$b could not process some of the nicks you provided." },
319 { "CSMSG_OPPED_USERS", "Opped users in $b%s$b." },
320 { "CSMSG_HALFOPPED_USERS", "Halfopped users in $b%s$b." },
321 { "CSMSG_DEOPPED_USERS", "Deopped users in $b%s$b." },
322 { "CSMSG_DEHALFOPPED_USERS", "DeHalfopped users in $b%s$b." },
323 { "CSMSG_VOICED_USERS", "Voiced users in $b%s$b." },
324 { "CSMSG_DEVOICED_USERS", "Devoiced users in $b%s$b." },
326 { "CSMSG_AUTOMODE_NONE", "Noone will be automatically oped, half-oped, or voiced." },
327 { "CSMSG_AUTOMODE_NORMAL", "Give voice to peons, half-op to halfops, and op to ops." },
328 { "CSMSG_AUTOMODE_VOICE", "#1 plus give voice to everyone." },
329 { "CSMSG_AUTOMODE_HOP", "#1 plus give halfops to everyone." },
330 { "CSMSG_AUTOMODE_OP", "#1 plus give ops to everyone (not advised)" },
331 { "CSMSG_AUTOMODE_MUTE", "Give half-op to halfops, and op to ops only." },
332 { "CSMSG_AUTOMODE_ONLYVOICE", "Just voice everyone with access." },
334 { "CSMSG_PROTECT_ALL", "Non-users and users will be protected from those of equal or lower access." },
335 { "CSMSG_PROTECT_EQUAL", "Users will be protected from those of equal or lower access." },
336 { "CSMSG_PROTECT_LOWER", "Users will be protected from those of lower access." },
337 { "CSMSG_PROTECT_NONE", "No users will be protected." },
338 { "CSMSG_TOYS_DISABLED", "Toys are completely disabled." },
339 { "CSMSG_TOYS_PRIVATE", "Toys will only reply privately." },
340 { "CSMSG_TOYS_PUBLIC", "Toys will reply publicly." },
342 { "CSMSG_TOPICREFRESH_NEVER", "Never refresh topic." },
343 { "CSMSG_TOPICREFRESH_3_HOURS", "Refresh every 3 hours." },
344 { "CSMSG_TOPICREFRESH_6_HOURS", "Refresh every 6 hours." },
345 { "CSMSG_TOPICREFRESH_12_HOURS", "Refresh every 12 hours." },
346 { "CSMSG_TOPICREFRESH_24_HOURS", "Refresh every 24 hours." },
348 { "CSMSG_RESYNC_NEVER", "Never automaticly resync userlist." },
349 { "CSMSG_RESYNC_3_HOURS", "Resync userlist every 3 hours." },
350 { "CSMSG_RESYNC_6_HOURS", "Resync userlist every 6 hours." },
351 { "CSMSG_RESYNC_12_HOURS", "Resync userlist every 12 hours." },
352 { "CSMSG_RESYNC_24_HOURS", "Resync userlist every 24 hours." },
354 { "CSMSG_CTCPREACTION_NONE", "CTCPs are allowed" },
355 { "CSMSG_CTCPREACTION_KICK", "Kick on disallowed CTCPs" },
356 { "CSMSG_CTCPREACTION_KICKBAN", "Kickban on disallowed CTCPs" },
357 { "CSMSG_CTCPREACTION_SHORTBAN", "Short timed ban on disallowed CTCPs" },
358 { "CSMSG_CTCPREACTION_LONGBAN", "Long timed ban on disallowed CTCPs" },
360 { "CSMSG_BANTIMEOUT_NONE", "Bans will not be removed automatically."},
361 { "CSMSG_BANTIMEOUT_10M", "Bans will be removed after 10 minutes."},
362 { "CSMSG_BANTIMEOUT_2H", "Bans will be removed after 2 hours."},
363 { "CSMSG_BANTIMEOUT_4H", "Bans will be removed after 4 hours."},
364 { "CSMSG_BANTIMEOUT_1D", "Bans will be removed after 24 hours."},
365 { "CSMSG_BANTIMEOUT_1W", "Bans will be removed after 1 week."},
367 { "CSMSG_INVITED_USER", "Invited $b%s$b to join %s." },
368 { "CSMSG_INVITING_YOU_REASON", "$b%s$b invites you to join %s: %s" },
369 { "CSMSG_INVITING_YOU", "$b%s$b invites you to join %s." },
370 { "CSMSG_CANNOT_INVITE", "You cannot invite %s to %s." },
371 { "CSMSG_ALREADY_PRESENT", "%s is already in $b%s$b." },
372 { "CSMSG_YOU_ALREADY_PRESENT", "You are already in $b%s$b." },
373 { "CSMSG_LOW_CHANNEL_ACCESS", "You lack sufficient access in %s to use this command." },
374 { "CSMSG_INFOLINE_TOO_LONG", "Your infoline may not exceed %u characters." },
375 { "CSMSG_BAD_INFOLINE", "You may not use the character \\%03o in your infoline." },
377 { "CSMSG_KICK_DONE", "Kicked $b%s$b from %s." },
378 { "CSMSG_NO_BANS", "No bans found on $b%s$b." },
379 { "CSMSG_BANS_REMOVED", "Removed all channel bans from $b%s$b." },
381 /* Channel userlist */
382 { "CSMSG_ACCESS_ALL_HEADER_NORMAL", "$b%s Users From Level %s To %s$b" },
383 { "CSMSG_ACCESS_SEARCH_HEADER_NORMAL", "$b%s Users From Level %s To %s Matching %s$b" },
384 /* uncomment if needed to adujust styles (and change code below)
385 { "CSMSG_ACCESS_ALL_HEADER_CLEAN", "$b%s Users From Level %s To %s$b" },
386 { "CSMSG_ACCESS_SEARCH_HEADER_CLEAN", "$b%s Users From Level %s To %s Matching %s$b" },
387 { "CSMSG_ACCESS_ALL_HEADER_ADVANCED", "$b%s Users From Level %s To %s$b" },
388 { "CSMSG_ACCESS_SEARCH_HEADER_ADVANCED", "$b%s Users From Level %s To %s Matching %s$b" },
389 { "CSMSG_ACCESS_ALL_HEADER_CLASSIC", "$b%s Users From Level %s To %s$b" },
390 { "CSMSG_ACCESS_SEARCH_HEADER_CLASSIC", "$b%s Users From Level %s To %s Matching %s$b" },
392 { "CSMSG_INVALID_ACCESS", "$b%s$b is an invalid access level." },
393 { "CSMSG_CHANGED_ACCESS", "%s now has access $b%s$b (%u) in %s." },
394 { "CSMSG_LAMERS_HEADER", "$bLamers in %s$b" },
396 /* Channel note list */
397 { "CSMSG_NOTELIST_HEADER", "Notes for $b%s$b:" },
398 { "CSMSG_REPLACED_NOTE", "Replaced old $b%s$b note on %s (set by %s): %s" },
399 { "CSMSG_NOTE_FORMAT", "%s (set by %s): %s" },
400 { "CSMSG_NOTELIST_END", "End of notes for $b%s$b." },
401 { "CSMSG_NOTELIST_EMPTY", "There are no (visible) notes for $b%s$b." },
402 { "CSMSG_NO_SUCH_NOTE", "Channel $b%s$b does not have a note named $b%s$b." },
403 { "CSMSG_BAD_NOTE_TYPE", "Note type $b%s$b does not exist." },
404 { "CSMSG_NOTE_SET", "Note $b%s$b set in channel $b%s$b." },
405 { "CSMSG_NOTE_REMOVED", "Note $b%s$b removed in channel $b%s$b." },
406 { "CSMSG_BAD_NOTE_ACCESS", "$b%s$b is not a valid note access type." },
407 { "CSMSG_BAD_MAX_LENGTH", "$b%s$b is not a valid maximum length (must be between 20 and 450 inclusive)." },
408 { "CSMSG_NOTE_MODIFIED", "Note type $b%s$b modified." },
409 { "CSMSG_NOTE_CREATED", "Note type $b%s$b created." },
410 { "CSMSG_NOTE_TYPE_USED", "Note type $b%s$b is in use; give the FORCE argument to delete it." },
411 { "CSMSG_NOTE_DELETED", "Note type $b%s$b deleted." },
413 /* Channel [un]suspension */
414 { "CSMSG_ALREADY_SUSPENDED", "$b%s$b is already suspended." },
415 { "CSMSG_NOT_SUSPENDED", "$b%s$b is not suspended." },
416 { "CSMSG_SUSPENDED", "$b$C$b access to $b%s$b has been temporarily suspended." },
417 { "CSMSG_UNSUSPENDED", "$b$C$b access to $b%s$b has been restored." },
418 { "CSMSG_SUSPEND_NODELETE", "$b%s$b is protected from unregistration, and cannot be suspended." },
419 { "CSMSG_USER_SUSPENDED", "$b%s$b's access to $b%s$b has been suspended." },
420 { "CSMSG_USER_UNSUSPENDED", "$b%s$b's access to $b%s$b has been restored." },
422 /* Access information */
423 { "CSMSG_IS_CHANSERV", "$b$C$b is the $bchannel service bot$b." },
424 { "CSMSG_MYACCESS_SELF_ONLY", "You may only see the list of infolines for yourself (by using $b%s$b with no arguments)." },
425 { "CSMSG_SQUAT_ACCESS", "$b%s$b does not have access to any channels." },
426 { "CSMSG_INFOLINE_LIST", "Showing all channel entries for account $b%s$b:" },
427 { "CSMSG_USER_NO_ACCESS", "%s lacks access to %s." },
428 { "CSMSG_USER_HAS_ACCESS", "%s has $b%s$b access (%d) in %s." },
429 { "CSMSG_HELPER_NO_ACCESS", "%s lacks access to %s but has $bsecurity override$b enabled." },
430 { "CSMSG_HELPER_HAS_ACCESS", "%s has $b%s$b access (%d) in %s and has $bsecurity override$b enabled." },
431 { "CSMSG_LAZY_SMURF_TARGET", "%s is %s ($bIRCOp$b; not logged in)." },
432 { "CSMSG_SMURF_TARGET", "%s is %s ($b%s$b)." },
433 { "CSMSG_LAME_SMURF_TARGET", "%s is an IRC operator." },
435 /* Seen information */
436 { "CSMSG_NEVER_SEEN", "%s has never been seen in $b%s$b." },
437 { "CSMSG_USER_SEEN", "%s was last seen in $b%s$b %s ago." },
438 { "CSMSG_USER_VACATION", "%s is currently on vacation." },
439 { "CSMSG_USER_PRESENT", "%s is in the channel $bright now$b." },
441 /* Names information */
442 { "CSMSG_CHANNEL_NAMES", "Users in $b%s$b:%s" },
443 { "CSMSG_END_NAMES", "End of names in $b%s$b" },
445 /* Channel information */
446 { "CSMSG_CHANNEL_INFO", "$bInformation About %s$b" },
447 { "CSMSG_BAR", "----------------------------------------"},
448 { "CSMSG_CHANNEL_TOPIC", "$bDefault Topic: $b%s" },
449 { "CSMSG_CHANNEL_MODES", "$bMode Lock: $b%s" },
450 { "CSMSG_CHANNEL_NOTE", "$b%s:%*s$b%s" },
451 { "CSMSG_CHANNEL_MAX", "$bRecord Visitors: $b%i" },
452 { "CSMSG_CHANNEL_OWNER", "$bOwner: $b%s" },
453 { "CSMSG_CHANNEL_LAMERS", "$bLamer Count: $b%i" },
454 { "CSMSG_CHANNEL_USERS", "$bTotal User Count: $b%i" },
455 { "CSMSG_CHANNEL_REGISTRAR", "$bRegistrar: $b%s" },
456 { "CSMSG_CHANNEL_SUSPENDED", "$b%s$b is suspended:" },
457 { "CSMSG_CHANNEL_HISTORY", "Suspension history for $b%s$b:" },
458 { "CSMSG_CHANNEL_SUSPENDED_0", " by %s: %s" },
459 { "CSMSG_CHANNEL_SUSPENDED_1", " by %s; expires in %s: %s" },
460 { "CSMSG_CHANNEL_SUSPENDED_2", " by %s; expired %s ago: %s" },
461 { "CSMSG_CHANNEL_SUSPENDED_3", " by %s; revoked %s ago: %s" },
462 { "CSMSG_CHANNEL_SUSPENDED_4", " %s ago by %s: %s" },
463 { "CSMSG_CHANNEL_SUSPENDED_5", " %s ago by %s; expires in %s: %s" },
464 { "CSMSG_CHANNEL_SUSPENDED_6", " %s ago by %s; expired %s ago: %s" },
465 { "CSMSG_CHANNEL_SUSPENDED_7", " %s ago by %s; revoked %s ago: %s" },
466 { "CSMSG_CHANNEL_REGISTERED", "$bRegistered: $b%s ago." },
467 { "CSMSG_CHANNEL_VISITED", "$bVisited: $b%s ago." },
468 { "CSMSG_CHANNEL_OWNERSHIP_HISTORY", "Ownership transfer history for $b%s$b" },
469 { "CSMSG_CHANNEL_OWNERSHIP_NORMAL", "from %s to %s (%d access) on %s" },
470 { "CSMSG_CHANNEL_OWNERSHIP_STAFF_REASON", "from %s to %s (%d access) by %s on %s reason: %s" },
471 { "CSMSG_CHANNEL_OWNERSHIP_STAFF", "from %s to %s (%d access) by %s on %s" },
472 { "CSMSG_CHANNEL_END", "---------------End of Info--------------"},
473 { "CSMSG_CHANNEL_END_CLEAN", "End of Info"},
475 { "CSMSG_PEEK_INFO", "$bStatus of %s$b" },
476 { "CSMSG_PEEK_TOPIC", "$bTopic: $b%s" },
477 { "CSMSG_PEEK_MODES", "$bModes: $b%s" },
478 { "CSMSG_PEEK_USERS", "$bTotal users: $b%d" },
479 { "CSMSG_PEEK_OPS", "$bOps:$b" },
480 { "CSMSG_PEEK_NO_OPS", "$bOps: $bNone present" },
481 { "CSMSG_PEEK_END", "-------------End of Status--------------" },
483 /* Network information */
484 { "CSMSG_NETWORK_INFO", "Network Information:" },
485 { "CSMSG_NETWORK_SERVERS", "$bServers: $b%i" },
486 { "CSMSG_NETWORK_USERS", "$bTotal Users: $b%i" },
487 { "CSMSG_NETWORK_LAMERS", "$bTotal Lamer Count: $b%i" },
488 { "CSMSG_NETWORK_CHANUSERS", "$bTotal User Count: $b%i" },
489 { "CSMSG_NETWORK_OPERS", "$bIRC Operators: $b%i" },
490 { "CSMSG_NETWORK_CHANNELS","$bRegistered Channels: $b%i" },
491 { "CSMSG_SERVICES_UPTIME", "$bServices Uptime: $b%s" },
492 { "CSMSG_BURST_LENGTH", "$bLast Burst Length: $b%s" },
495 { "CSMSG_NETWORK_STAFF", "$bOnline Network Staff:$b" },
496 { "CSMSG_STAFF_OPERS", "$bIRC Operators:$b" },
497 { "CSMSG_STAFF_HELPERS", "$bHelpers:$b" },
499 /* Channel searches */
500 { "CSMSG_ACTION_INVALID", "$b%s$b is not a recognized search action." },
501 { "CSMSG_UNVISITED_HEADER", "Showing a maximum of %d channels unvisited for $b%s$b:" },
502 { "CSMSG_UNVISITED_DATA", "%s: $b%s$b" },
503 { "CSMSG_CHANNEL_SEARCH_RESULTS", "$bChannels Found Matching Search$b" },
505 /* Channel configuration */
506 { "CSMSG_INVALID_OPTION", "$b%s$b is not a valid %s option." },
507 { "CSMSG_CHANNEL_OPTIONS", "$bChannel Options for %s$b" },
508 { "CSMSG_CHANNEL_OPTIONS_END", "-------------End of Options-------------" },
509 { "CSMSG_GREETING_TOO_LONG", "Your greeting ($b%d$b characters) must be shorter than $b%d$b characters." },
512 { "CSMSG_USER_OPTIONS", "User Options:" },
513 // { "CSMSG_USER_PROTECTED", "That user is protected." },
516 { "CSMSG_UNF_RESPONSE", "I don't want to be part of your sick fantasies!" },
517 { "CSMSG_PING_RESPONSE", "Pong!" },
518 { "CSMSG_WUT_RESPONSE", "wut" },
519 { "CSMSG_BAD_NUMBER", "$b%s$b is an invalid number. Please use a number greater than 1 with this command." },
520 { "CSMSG_BAD_DIE_FORMAT", "I do not understand $b%s$b. Please use either a single number or standard 4d6+3 format." },
521 { "CSMSG_BAD_DICE_COUNT", "%lu is too many dice. Please use at most %lu." },
522 { "CSMSG_DICE_ROLL", "The total is $b%lu$b from rolling %lud%lu+%lu." },
523 { "CSMSG_DIE_ROLL", "A $b%lu$b shows on the %lu-sided die." },
524 { "CSMSG_HUGGLES_HIM", "\001ACTION huggles %s\001" },
525 { "CSMSG_HUGGLES_YOU", "\001ACTION huggles you\001" },
526 { "CSMSG_ROULETTE_LOADS", "\001ACTION loads the gun and sets it on the table\001" },
527 { "CSMSG_ROULETTE_NEW", "Please type .roulette to start a new round" } ,
528 { "CSMSG_ROULETTE_BETTER_LUCK", "Better luck next time, %s" },
529 { "CSMSG_ROULETTE_BANG", "Bang!!!" } ,
530 { "CSMSG_ROULETTE_CLICK", "Click" } ,
532 { "CSMSG_SPIN_WHEEL1", "\001ACTION spins the wheel of misfortune for: %s\001" } ,
533 { "CSMSG_SPIN_WHEEL2", "Round and round she goes, where she stops, nobody knows...!" } ,
534 { "CSMSG_SPIN_WHEEL3", "The wheel of misfortune has stopped on..." } ,
536 { "CSMSG_SPIN_1", "1: Peer's gonna eat you!!!!" } ,
537 { "CSMSG_SPIN_2", "2: Part all channels" } ,
538 { "CSMSG_SPIN_3", "3: Part all channels" } ,
539 { "CSMSG_SPIN_4", "4: /gline for random amount of time" } ,
540 { "CSMSG_SPIN_5", "5: /shun for random amount of time" } ,
541 { "CSMSG_SPIN_6", "6: Absolutely nothing" } ,
542 { "CSMSG_SPIN_7", "7: Join a bunch of random channels, then /part all of 'em several times" } ,
543 { "CSMSG_SPIN_8", "8: Abuse line added to /whois info" } ,
544 { "CSMSG_SPIN_9", "9: /kick from each channel you're in" } ,
545 { "CSMSG_SPIN_10", "10: Random Nick Change" } ,
546 { "CSMSG_SPIN_11", "11: /kill" } ,
547 { "CSMSG_SPIN_12", "12: Services ignore for random amount of time" } ,
548 { "CSMSG_SPIN_13", "13: /kick and ban from each channel your're in" } ,
551 { "CSMSG_EVENT_SEARCH_RESULTS", "$bChannel Events for %s$b" },
552 { "CSMSG_LAST_INVALID", "Invalid argument. must be 1-200" },
553 { "CSMSG_DEFCON_NO_NEW_CHANNELS", "You cannot register new channels at this time, please try again soon." },
554 { "CSMSG_DEFCON_NO_MODE_CHANGE", "You cannot change the MODE at this time, please try again soon." },
558 /* eject_user and unban_user flags */
559 #define ACTION_KICK 0x0001
560 #define ACTION_BAN 0x0002
561 #define ACTION_ADD_LAMER 0x0004
562 #define ACTION_ADD_TIMED_LAMER 0x0008
563 #define ACTION_UNBAN 0x0010
564 #define ACTION_DEL_LAMER 0x0020
566 /* The 40 allows for [+-ntlksimprD] and lots of fudge factor. */
567 #define MODELEN 40 + KEYLEN
571 #define CSFUNC_ARGS user, channel, argc, argv, cmd
573 #define CHANSERV_FUNC(NAME) MODCMD_FUNC(NAME)
574 #define CHANSERV_SYNTAX() svccmd_send_help_brief(user, chanserv, cmd)
575 #define REQUIRE_PARAMS(N) if(argc < (N)) { \
576 reply("MSG_MISSING_PARAMS", argv[0]); \
580 DECLARE_LIST(dnrList
, struct do_not_register
*);
581 DEFINE_LIST(dnrList
, struct do_not_register
*);
583 static int eject_user(struct userNode
*user
, struct chanNode
*channel
, unsigned int argc
, char *argv
[], struct svccmd
*cmd
, int action
);
585 struct userNode
*chanserv
;
588 extern struct string_list
*autojoin_channels
;
589 static dict_t plain_dnrs
, mask_dnrs
, handle_dnrs
;
590 static struct log_type
*CS_LOG
;
591 struct adduserPending
* adduser_pendings
= NULL
;
592 unsigned int adduser_pendings_count
= 0;
593 unsigned long god_timeout
;
597 struct channelList support_channels
;
598 struct mod_chanmode default_modes
;
600 unsigned long db_backup_frequency
;
601 unsigned long channel_expire_frequency
;
602 unsigned long ban_timeout_frequency
;
605 unsigned int adjust_delay
;
606 long channel_expire_delay
;
607 unsigned int nodelete_level
;
609 unsigned int adjust_threshold
;
610 int join_flood_threshold
;
612 unsigned int greeting_length
;
613 unsigned int refresh_period
;
614 unsigned int giveownership_period
;
616 unsigned int max_owned
;
617 unsigned int max_chan_users
;
618 unsigned int max_chan_bans
; /* lamers */
619 unsigned int max_userinfo_length
;
621 struct string_list
*set_shows
;
622 struct string_list
*eightball
;
623 struct string_list
*old_ban_names
;
625 const char *ctcp_short_ban_duration
;
626 const char *ctcp_long_ban_duration
;
628 const char *irc_operator_epithet
;
629 const char *network_helper_epithet
;
630 const char *support_helper_epithet
;
635 struct userNode
*user
;
636 struct userNode
*bot
;
637 struct chanNode
*channel
;
639 unsigned short lowest
;
640 unsigned short highest
;
641 struct userData
**users
;
642 struct helpfile_table table
;
645 enum note_access_type
647 NOTE_SET_CHANNEL_ACCESS
,
648 NOTE_SET_CHANNEL_SETTER
,
652 enum note_visible_type
655 NOTE_VIS_CHANNEL_USERS
,
659 struct io_fd
*socket_io_fd
;
660 extern struct cManagerNode cManager
;
664 enum note_access_type set_access_type
;
666 unsigned int min_opserv
;
667 unsigned short min_ulevel
;
669 enum note_visible_type visible_type
;
670 unsigned int max_length
;
677 struct note_type
*type
;
678 char setter
[NICKSERV_HANDLE_LEN
+1];
682 static unsigned int registered_channels
;
683 static unsigned int banCount
;
685 static const struct {
688 unsigned short level
;
690 } accessLevels
[] = { /* MUST be orderd less to most! */
691 { "peon", "Peon", UL_PEON
, '+' },
692 { "halfop", "HalfOp", UL_HALFOP
, '%' },
693 { "op", "Op", UL_OP
, '@' },
694 { "manager", "Manager", UL_MANAGER
, '%' },
695 { "coowner", "Coowner", UL_COOWNER
, '*' },
696 { "owner", "Owner", UL_OWNER
, '!' },
697 { "helper", "BUG:", UL_HELPER
, 'X' }
700 /* If you change this, change the enum in chanserv.h also, or stack smashing will commence. */
701 static const struct {
704 unsigned short default_value
;
705 unsigned int old_idx
;
706 unsigned int old_flag
;
707 unsigned short flag_value
;
709 { "CSMSG_SET_ENFOPS", "enfops", 300, 1, 0, 0 },
710 { "CSMSG_SET_ENFHALFOPS", "enfhalfops", 300, 1, 0, 0 },
711 { "CSMSG_SET_ENFMODES", "enfmodes", 200, 3, 0, 0 },
712 { "CSMSG_SET_ENFTOPIC", "enftopic", 200, 4, 0, 0 },
713 { "CSMSG_SET_PUBCMD", "pubcmd", 0, 5, 0, 0 },
714 { "CSMSG_SET_SETTERS", "setters", 400, 7, 0, 0 },
715 { "CSMSG_SET_USERINFO", "userinfo", 1, ~0, CHANNEL_INFO_LINES
, 1 },
716 { "CSMSG_SET_INVITEME", "inviteme", 1, ~0, CHANNEL_PEON_INVITE
, 200 },
717 { "CSMSG_SET_TOPICSNARF", "topicsnarf", 501, ~0, CHANNEL_TOPIC_SNARF
, 1 }
720 struct charOptionValues
{
723 } automodeValues
[] = {
724 { 'n', "CSMSG_AUTOMODE_NONE" },
725 { 'y', "CSMSG_AUTOMODE_NORMAL" },
726 { 'v', "CSMSG_AUTOMODE_VOICE" },
727 { 'h', "CSMSG_AUTOMODE_HOP" },
728 { 'o', "CSMSG_AUTOMODE_OP" },
729 { 'm', "CSMSG_AUTOMODE_MUTE" },
730 { 'l', "CSMSG_AUTOMODE_ONLYVOICE" }
731 }, protectValues
[] = {
732 { 'a', "CSMSG_PROTECT_ALL" },
733 { 'e', "CSMSG_PROTECT_EQUAL" },
734 { 'l', "CSMSG_PROTECT_LOWER" },
735 { 'n', "CSMSG_PROTECT_NONE" }
737 { 'd', "CSMSG_TOYS_DISABLED" },
738 { 'n', "CSMSG_TOYS_PRIVATE" },
739 { 'p', "CSMSG_TOYS_PUBLIC" }
740 }, topicRefreshValues
[] = {
741 { 'n', "CSMSG_TOPICREFRESH_NEVER" },
742 { '1', "CSMSG_TOPICREFRESH_3_HOURS" },
743 { '2', "CSMSG_TOPICREFRESH_6_HOURS" },
744 { '3', "CSMSG_TOPICREFRESH_12_HOURS" },
745 { '4', "CSMSG_TOPICREFRESH_24_HOURS" }
746 }, ctcpReactionValues
[] = {
747 { 'n', "CSMSG_CTCPREACTION_NONE" },
748 { 'k', "CSMSG_CTCPREACTION_KICK" },
749 { 'b', "CSMSG_CTCPREACTION_KICKBAN" },
750 { 't', "CSMSG_CTCPREACTION_SHORTBAN" },
751 { 'T', "CSMSG_CTCPREACTION_LONGBAN" }
752 }, banTimeoutValues
[] = {
753 { '0', "CSMSG_BANTIMEOUT_NONE" },
754 { '1', "CSMSG_BANTIMEOUT_10M" },
755 { '2', "CSMSG_BANTIMEOUT_2H" },
756 { '3', "CSMSG_BANTIMEOUT_4H" },
757 { '4', "CSMSG_BANTIMEOUT_1D" },
758 { '5', "CSMSG_BANTIMEOUT_1W" }
761 { 'n', "CSMSG_RESYNC_NEVER" },
762 { '1', "CSMSG_RESYNC_3_HOURS" },
763 { '2', "CSMSG_RESYNC_6_HOURS" },
764 { '3', "CSMSG_RESYNC_12_HOURS" },
765 { '4', "CSMSG_RESYNC_24_HOURS" }
768 static const struct {
772 unsigned int old_idx
;
774 struct charOptionValues
*values
;
776 { "CSMSG_SET_AUTOMODE", "automode", 'y', 99, ArrayLength(automodeValues
), automodeValues
},
777 { "CSMSG_SET_PROTECT", "protect", 'l', 0, ArrayLength(protectValues
), protectValues
},
778 { "CSMSG_SET_TOYS", "toys", 'p', 6, ArrayLength(toysValues
), toysValues
},
779 { "CSMSG_SET_TOPICREFRESH", "topicrefresh", 'n', 8, ArrayLength(topicRefreshValues
), topicRefreshValues
},
780 { "CSMSG_SET_CTCPREACTION", "ctcpreaction", 'n', 10, ArrayLength(ctcpReactionValues
), ctcpReactionValues
},
781 { "CSMSG_SET_BANTIMEOUT", "bantimeout", '0', 11, ArrayLength(banTimeoutValues
), banTimeoutValues
},
782 { "CSMSG_SET_RESYNC", "resync", 'n', 12, ArrayLength(resyncValues
), resyncValues
},
785 struct userData
*helperList
;
786 struct chanData
*channelList
;
787 static struct module *chanserv_module
;
788 static unsigned int userCount
;
789 unsigned int chanserv_read_version
= 0; /* db version control */
791 #define CHANSERV_DB_VERSION 2
793 #define GetChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 0)
794 #define GetTrueChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 1)
796 void sputsock(const char *text
, ...) PRINTF_LIKE(1, 2);
799 sputsock(const char *text
, ...)
805 if (!cManager
.uplink
|| cManager
.uplink
->state
== DISCONNECTED
) return;
807 va_start(arg_list
, text
);
808 pos
= vsnprintf(buffer
, MAXLEN
- 2, text
, arg_list
);
810 if (pos
< 0 || pos
> (MAXLEN
- 2)) pos
= MAXLEN
- 2;
812 log_replay(MAIN_LOG
, true, buffer
);
813 buffer
[pos
++] = '\n';
815 ioset_write(socket_io_fd
, buffer
, pos
);
819 user_level_from_name(const char *name
, unsigned short clamp_level
)
821 unsigned int level
= 0, ii
;
823 level
= strtoul(name
, NULL
, 10);
824 else for(ii
= 0; (ii
< ArrayLength(accessLevels
)) && !level
; ++ii
)
825 if(!irccasecmp(name
, accessLevels
[ii
].name
))
826 level
= accessLevels
[ii
].level
;
827 if(level
> clamp_level
)
833 user_level_name_from_level(int level
)
841 for(ii
= 0; (ii
< ArrayLength(accessLevels
)); ii
++)
842 if(level
>= accessLevels
[ii
].level
)
843 highest
= accessLevels
[ii
].title
;
849 parse_level_range(unsigned short *minl
, unsigned short *maxl
, const char *arg
)
852 *minl
= strtoul(arg
, &sep
, 10);
860 *maxl
= strtoul(sep
+1, &sep
, 10);
868 _GetChannelUser(struct chanData
*channel
, struct handle_info
*handle
, int override
, int allow_suspended
)
870 struct userData
*uData
, **head
;
872 if(!channel
|| !handle
)
875 if(override
&& HANDLE_FLAGGED(handle
, HELPING
)
876 && ((handle
->opserv_level
>= chanserv_conf
.nodelete_level
) || !IsProtected(channel
)))
878 for(uData
= helperList
;
879 uData
&& uData
->handle
!= handle
;
880 uData
= uData
->next
);
884 uData
= calloc(1, sizeof(struct userData
));
885 uData
->handle
= handle
;
887 uData
->access
= UL_HELPER
;
893 uData
->next
= helperList
;
895 helperList
->prev
= uData
;
903 for(uData
= channel
->users
; uData
; uData
= uData
->next
)
904 if((uData
->handle
== handle
) && (allow_suspended
|| !IsUserSuspended(uData
)))
907 head
= &(channel
->users
);
910 if(uData
&& (uData
!= *head
))
912 /* Shuffle the user to the head of whatever list he was in. */
914 uData
->next
->prev
= uData
->prev
;
916 uData
->prev
->next
= uData
->next
;
922 (**head
).prev
= uData
;
929 /* Returns non-zero if user has at least the minimum access.
930 * exempt_owner is set when handling !set, so the owner can set things
933 int check_user_level(struct chanNode
*channel
, struct userNode
*user
, enum levelOption opt
, int allow_override
, int exempt_owner
)
935 struct userData
*uData
;
936 struct chanData
*cData
= channel
->channel_info
;
937 unsigned short minimum
= cData
->lvlOpts
[opt
];
940 uData
= _GetChannelUser(cData
, user
->handle_info
, allow_override
, 0);
943 if(minimum
<= uData
->access
)
945 if((minimum
> UL_OWNER
) && (uData
->access
== UL_OWNER
) && exempt_owner
)
950 /* Scan for other users authenticated to the same handle
951 still in the channel. If so, keep them listed as present.
953 user is optional, if not null, it skips checking that userNode
954 (for the handle_part function) */
956 scan_user_presence(struct userData
*uData
, struct userNode
*user
)
960 if(IsSuspended(uData
->channel
)
961 || IsUserSuspended(uData
)
962 || !(mn
= find_handle_in_channel(uData
->channel
->channel
, uData
->handle
, user
)))
974 chanserv_ctcp_check(struct userNode
*user
, struct chanNode
*channel
, char *text
, UNUSED_ARG(struct userNode
*bot
))
976 unsigned int eflags
, argc
;
978 static char *bad_ctcp_reason
= "CTCPs to this channel are forbidden.";
980 /* Bail early if channel is inactive or doesn't restrict CTCPs, or sender is a service */
981 if(!channel
->channel_info
982 || IsSuspended(channel
->channel_info
)
984 || !ircncasecmp(text
, "ACTION ", 7))
986 /* We dont punish people we know -Rubin
987 * * Figure out the minimum level needed to CTCP the channel *
989 * if(check_user_level(channel, user, lvlCTCPUsers, 1, 0))
992 /* If they are a user of the channel, they are exempt */
993 if(_GetChannelUser(channel
->channel_info
, user
->handle_info
, 0, 0))
995 /* We need to enforce against them; do so. */
998 argv
[1] = user
->nick
;
1000 if(GetUserMode(channel
, user
))
1001 eflags
|= ACTION_KICK
;
1002 switch(channel
->channel_info
->chOpts
[chCTCPReaction
]) {
1003 default: case 'n': return;
1005 eflags
|= ACTION_KICK
;
1008 eflags
|= ACTION_BAN
;
1011 eflags
|= ACTION_BAN
| ACTION_ADD_LAMER
| ACTION_ADD_TIMED_LAMER
;
1012 argv
[argc
++] = (char*)chanserv_conf
.ctcp_short_ban_duration
;
1015 eflags
|= ACTION_BAN
| ACTION_ADD_LAMER
| ACTION_ADD_TIMED_LAMER
;
1016 argv
[argc
++] = (char*)chanserv_conf
.ctcp_long_ban_duration
;
1019 argv
[argc
++] = bad_ctcp_reason
;
1020 eject_user(chanserv
, channel
, argc
, argv
, NULL
, eflags
);
1024 chanserv_create_note_type(const char *name
)
1026 struct note_type
*ntype
= calloc(1, sizeof(*ntype
) + strlen(name
));
1027 strcpy(ntype
->name
, name
);
1029 dict_insert(note_types
, ntype
->name
, ntype
);
1034 chanserv_deref_note_type(void *data
)
1036 struct note_type
*ntype
= data
;
1038 if(--ntype
->refs
> 0)
1044 chanserv_flush_note_type(struct note_type
*ntype
)
1046 struct chanData
*cData
;
1047 for(cData
= channelList
; cData
; cData
= cData
->next
)
1048 dict_remove(cData
->notes
, ntype
->name
);
1052 chanserv_truncate_notes(struct note_type
*ntype
)
1054 struct chanData
*cData
;
1056 unsigned int size
= sizeof(*note
) + ntype
->max_length
;
1058 for(cData
= channelList
; cData
; cData
= cData
->next
) {
1059 note
= dict_find(cData
->notes
, ntype
->name
, NULL
);
1062 if(strlen(note
->note
) <= ntype
->max_length
)
1064 dict_remove2(cData
->notes
, ntype
->name
, 1);
1065 note
= realloc(note
, size
);
1066 note
->note
[ntype
->max_length
] = 0;
1067 dict_insert(cData
->notes
, ntype
->name
, note
);
1071 static int note_type_visible_to_user(struct chanData
*channel
, struct note_type
*ntype
, struct userNode
*user
);
1073 static struct note
*
1074 chanserv_add_channel_note(struct chanData
*channel
, struct note_type
*type
, const char *setter
, const char *text
)
1077 unsigned int len
= strlen(text
);
1079 if(len
> type
->max_length
) len
= type
->max_length
;
1080 note
= calloc(1, sizeof(*note
) + len
);
1082 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
1083 memcpy(note
->note
, text
, len
);
1084 note
->note
[len
] = 0;
1085 dict_insert(channel
->notes
, type
->name
, note
);
1091 chanserv_free_note(void *data
)
1093 struct note
*note
= data
;
1095 chanserv_deref_note_type(note
->type
);
1096 assert(note
->type
->refs
> 0); /* must use delnote to remove the type */
1100 static MODCMD_FUNC(cmd_createnote
) {
1101 struct note_type
*ntype
;
1102 unsigned int arg
= 1, existed
= 0, max_length
;
1104 if((ntype
= dict_find(note_types
, argv
[1], NULL
)))
1107 ntype
= chanserv_create_note_type(argv
[arg
]);
1108 if(!irccasecmp(argv
[++arg
], "privileged"))
1111 ntype
->set_access_type
= NOTE_SET_PRIVILEGED
;
1112 ntype
->set_access
.min_opserv
= strtoul(argv
[arg
], NULL
, 0);
1114 else if(!irccasecmp(argv
[arg
], "channel"))
1116 unsigned short ulvl
= user_level_from_name(argv
[++arg
], UL_OWNER
);
1119 reply("CSMSG_INVALID_ACCESS", argv
[arg
]);
1122 ntype
->set_access_type
= NOTE_SET_CHANNEL_ACCESS
;
1123 ntype
->set_access
.min_ulevel
= ulvl
;
1125 else if(!irccasecmp(argv
[arg
], "setter"))
1127 ntype
->set_access_type
= NOTE_SET_CHANNEL_SETTER
;
1131 reply("CSMSG_BAD_NOTE_ACCESS", argv
[arg
]);
1135 if(!irccasecmp(argv
[++arg
], "privileged"))
1136 ntype
->visible_type
= NOTE_VIS_PRIVILEGED
;
1137 else if(!irccasecmp(argv
[arg
], "channel_users"))
1138 ntype
->visible_type
= NOTE_VIS_CHANNEL_USERS
;
1139 else if(!irccasecmp(argv
[arg
], "all"))
1140 ntype
->visible_type
= NOTE_VIS_ALL
;
1142 reply("CSMSG_BAD_NOTE_ACCESS", argv
[arg
]);
1146 if((arg
+1) >= argc
) {
1147 reply("MSG_MISSING_PARAMS", argv
[0]);
1150 max_length
= strtoul(argv
[++arg
], NULL
, 0);
1151 if(max_length
< 20 || max_length
> 450)
1153 reply("CSMSG_BAD_MAX_LENGTH", argv
[arg
]);
1156 if(existed
&& (max_length
< ntype
->max_length
))
1158 ntype
->max_length
= max_length
;
1159 chanserv_truncate_notes(ntype
);
1161 ntype
->max_length
= max_length
;
1164 reply("CSMSG_NOTE_MODIFIED", ntype
->name
);
1166 reply("CSMSG_NOTE_CREATED", ntype
->name
);
1171 dict_remove(note_types
, ntype
->name
);
1175 static MODCMD_FUNC(cmd_removenote
) {
1176 struct note_type
*ntype
;
1179 ntype
= dict_find(note_types
, argv
[1], NULL
);
1180 force
= (argc
> 2) && !irccasecmp(argv
[2], "force");
1183 reply("CSMSG_BAD_NOTE_TYPE", argv
[1]);
1190 reply("CSMSG_NOTE_TYPE_USED", ntype
->name
);
1193 chanserv_flush_note_type(ntype
);
1195 dict_remove(note_types
, argv
[1]);
1196 reply("CSMSG_NOTE_DELETED", argv
[1]);
1201 mode_lock_violated(const struct mod_chanmode
*orig
, const struct mod_chanmode
*change
)
1205 if(orig
->modes_set
& change
->modes_clear
)
1207 if(orig
->modes_clear
& change
->modes_set
)
1209 if((orig
->modes_set
& MODE_KEY
) && (change
->modes_set
& MODE_KEY
)
1210 && strcmp(orig
->new_key
, change
->new_key
))
1212 if((orig
->modes_set
& MODE_LIMIT
) && (change
->modes_set
& MODE_LIMIT
)
1213 && (orig
->new_limit
!= change
->new_limit
))
1218 static char max_length_text
[MAXLEN
+1][16];
1220 static struct helpfile_expansion
1221 chanserv_expand_variable(const char *variable
)
1223 struct helpfile_expansion exp
;
1225 if(!irccasecmp(variable
, "notes"))
1228 exp
.type
= HF_TABLE
;
1229 exp
.value
.table
.length
= 1;
1230 exp
.value
.table
.width
= 3;
1231 exp
.value
.table
.flags
= 0;
1232 exp
.value
.table
.contents
= calloc(dict_size(note_types
)+1, sizeof(char**));
1233 exp
.value
.table
.contents
[0] = calloc(exp
.value
.table
.width
, sizeof(char*));
1234 exp
.value
.table
.contents
[0][0] = "Note Type";
1235 exp
.value
.table
.contents
[0][1] = "Visibility";
1236 exp
.value
.table
.contents
[0][2] = "Max Length";
1237 for(it
=dict_first(note_types
); it
; it
=iter_next(it
))
1239 struct note_type
*ntype
= iter_data(it
);
1242 if(!note_type_visible_to_user(NULL
, ntype
, message_dest
)) continue;
1243 row
= exp
.value
.table
.length
++;
1244 exp
.value
.table
.contents
[row
] = calloc(exp
.value
.table
.width
, sizeof(char*));
1245 exp
.value
.table
.contents
[row
][0] = ntype
->name
;
1246 exp
.value
.table
.contents
[row
][1] = (ntype
->visible_type
== NOTE_VIS_ALL
) ? "all" :
1247 (ntype
->visible_type
== NOTE_VIS_CHANNEL_USERS
) ? "chan users" :
1249 if(!max_length_text
[ntype
->max_length
][0])
1250 snprintf(max_length_text
[ntype
->max_length
], sizeof(max_length_text
[ntype
->max_length
]), "%u", ntype
->max_length
);
1251 exp
.value
.table
.contents
[row
][2] = max_length_text
[ntype
->max_length
];
1256 exp
.type
= HF_STRING
;
1257 exp
.value
.str
= NULL
;
1261 static struct chanData
*
1262 register_channel(struct chanNode
*cNode
, char *registrar
)
1264 struct chanData
*channel
;
1265 enum levelOption lvlOpt
;
1266 enum charOption chOpt
;
1268 channel
= calloc(1, sizeof(struct chanData
));
1270 channel
->notes
= dict_new();
1271 dict_set_free_data(channel
->notes
, chanserv_free_note
);
1273 channel
->registrar
= strdup(registrar
);
1274 channel
->registered
= now
;
1275 channel
->visited
= now
;
1276 channel
->limitAdjusted
= now
;
1277 channel
->ownerTransfer
= now
;
1278 channel
->flags
= CHANNEL_DEFAULT_FLAGS
;
1279 for(lvlOpt
= 0; lvlOpt
< NUM_LEVEL_OPTIONS
; ++lvlOpt
)
1280 channel
->lvlOpts
[lvlOpt
] = levelOptions
[lvlOpt
].default_value
;
1281 for(chOpt
= 0; chOpt
< NUM_CHAR_OPTIONS
; ++chOpt
)
1282 channel
->chOpts
[chOpt
] = charOptions
[chOpt
].default_value
;
1284 channel
->prev
= NULL
;
1285 channel
->next
= channelList
;
1288 channelList
->prev
= channel
;
1289 channelList
= channel
;
1290 registered_channels
++;
1292 channel
->channel
= cNode
;
1294 cNode
->channel_info
= channel
;
1299 static struct userData
*
1300 add_channel_user(struct chanData
*channel
, struct handle_info
*handle
, unsigned short access
, time_t seen
, const char *info
, time_t accessexpiry
)
1302 struct userData
*ud
;
1304 if(access
> UL_OWNER
)
1307 ud
= calloc(1, sizeof(*ud
));
1308 ud
->channel
= channel
;
1309 ud
->handle
= handle
;
1311 ud
->access
= access
;
1312 ud
->info
= info
? strdup(info
) : NULL
;
1313 ud
->accessexpiry
= accessexpiry
? accessexpiry
: 0;
1318 ud
->next
= channel
->users
;
1320 channel
->users
->prev
= ud
;
1321 channel
->users
= ud
;
1323 channel
->userCount
++;
1327 ud
->u_next
= ud
->handle
->channels
;
1329 ud
->u_next
->u_prev
= ud
;
1330 ud
->handle
->channels
= ud
;
1332 ud
->flags
= USER_FLAGS_DEFAULT
;
1336 static void unregister_channel(struct chanData
*channel
, const char *reason
);
1339 chanserv_expire_tempuser(void *data
)
1341 struct userData
*uData
= data
;
1345 handle
= strdup(uData
->handle
->handle
);
1346 if (uData
->accessexpiry
> 0) {
1347 if (uData
->present
) {
1348 struct userNode
*user
, *next_un
= NULL
;
1349 struct handle_info
*hi
;
1351 hi
= get_handle_info(handle
);
1352 for (user
= hi
->users
; user
; user
= next_un
) {
1353 struct mod_chanmode
*change
;
1354 struct modeNode
*mn
;
1355 unsigned int count
= 0;
1357 send_message(user
, chanserv
, "CSMSG_AUTO_DELETED", chanserv
->nick
, uData
->channel
->channel
->name
);
1358 if (!(mn
= GetUserMode(uData
->channel
->channel
, user
)) || !(mn
->modes
& MODE_CHANOP
)) {
1359 next_un
= user
->next_authed
;
1363 change
= mod_chanmode_alloc(2);
1364 change
->args
[count
].mode
= MODE_REMOVE
| MODE_CHANOP
;
1365 change
->args
[count
++].u
.member
= mn
;
1368 change
->argc
= count
;
1369 mod_chanmode_announce(chanserv
, uData
->channel
->channel
, change
);
1371 mod_chanmode_free(change
);
1372 next_un
= user
->next_authed
;
1375 del_channel_user(uData
, 1);
1381 chanserv_expire_tempclvl(void *data
)
1383 struct userData
*uData
= data
;
1387 handle
= strdup(uData
->handle
->handle
);
1388 if (uData
->clvlexpiry
> 0) {
1389 int changemodes
= 0;
1390 unsigned int mode
= 0;
1392 if (((uData
->lastaccess
== UL_PEON
) || (uData
->lastaccess
== UL_HALFOP
)) && (uData
->access
>= UL_OP
)) {
1394 mode
= MODE_REMOVE
| MODE_CHANOP
;
1395 } else if ((uData
->lastaccess
== UL_PEON
) && (uData
->access
== UL_HALFOP
)) {
1397 mode
= MODE_REMOVE
| MODE_HALFOP
;
1401 if (uData
->present
) {
1402 struct userNode
*user
, *next_un
= NULL
;
1403 struct handle_info
*hi
;
1405 hi
= get_handle_info(handle
);
1406 for (user
= hi
->users
; user
; user
= next_un
) {
1407 struct mod_chanmode
*change
;
1408 struct modeNode
*mn
;
1409 unsigned int count
= 0;
1411 send_message(user
, chanserv
, "CSMSG_CLVL_EXPIRED", uData
->channel
->channel
->name
);
1412 if (!(mn
= GetUserMode(uData
->channel
->channel
, user
))) {
1413 next_un
= user
->next_authed
;
1417 if (changemodes
== 0) {
1418 next_un
= user
->next_authed
;
1422 change
= mod_chanmode_alloc(2);
1423 change
->args
[count
].mode
= mode
;
1424 change
->args
[count
++].u
.member
= mn
;
1427 change
->argc
= count
;
1428 mod_chanmode_announce(chanserv
, uData
->channel
->channel
, change
);
1430 mod_chanmode_free(change
);
1431 next_un
= user
->next_authed
;
1435 uData
->access
= uData
->lastaccess
;
1436 uData
->lastaccess
= 0;
1437 uData
->clvlexpiry
= 0;
1443 del_channel_user(struct userData
*user
, int do_gc
)
1445 struct chanData
*channel
= user
->channel
;
1447 channel
->userCount
--;
1450 timeq_del(0, chanserv_expire_tempuser
, user
, TIMEQ_IGNORE_WHEN
);
1451 timeq_del(0, chanserv_expire_tempclvl
, user
, TIMEQ_IGNORE_WHEN
);
1454 user
->prev
->next
= user
->next
;
1456 channel
->users
= user
->next
;
1458 user
->next
->prev
= user
->prev
;
1461 user
->u_prev
->u_next
= user
->u_next
;
1463 user
->handle
->channels
= user
->u_next
;
1465 user
->u_next
->u_prev
= user
->u_prev
;
1469 if(do_gc
&& !channel
->users
&& !IsProtected(channel
)) {
1470 spamserv_cs_unregister(NULL
, channel
->channel
, lost_all_users
, NULL
);
1471 unregister_channel(channel
, "lost all users.");
1475 static struct adduserPending
*
1476 add_adduser_pending(struct chanNode
*channel
, struct userNode
*user
, int level
)
1478 struct adduserPending
*ap
;
1479 ap
= calloc(1,sizeof(struct adduserPending
));
1480 ap
->channel
= channel
;
1483 ap
->created
= time(NULL
);
1485 /* ap->prev defaults to NULL already.. */
1486 ap
->next
= adduser_pendings
;
1487 if(adduser_pendings
)
1488 adduser_pendings
->prev
= ap
;
1489 adduser_pendings
= ap
;
1490 adduser_pendings_count
++;
1495 del_adduser_pending(struct adduserPending
*ap
)
1498 ap
->prev
->next
= ap
->next
;
1500 adduser_pendings
= ap
->next
;
1503 ap
->next
->prev
= ap
->prev
;
1507 static void expire_adduser_pending();
1509 /* find_adduser_pending(channel, user) will find an arbitrary record
1510 * from user, channel, or user and channel.
1511 * if user or channel are NULL, they will match any records.
1513 static struct adduserPending
*
1514 find_adduser_pending(struct chanNode
*channel
, struct userNode
*user
)
1516 struct adduserPending
*ap
;
1518 expire_adduser_pending(); /* why not here.. */
1520 if(!channel
&& !user
) /* 2 nulls matches all */
1521 return(adduser_pendings
);
1522 for(ap
= adduser_pendings
;ap
;ap
= ap
->next
)
1524 if((channel
== ap
->channel
&& (user
== NULL
|| user
== ap
->user
)) || (user
==ap
->user
&& channel
==NULL
))
1531 /* Remove all pendings for a user or channel
1533 * called in nickserv.c DelUser() and proto-* unregister_channel()
1536 wipe_adduser_pending(struct chanNode
*channel
, struct userNode
*user
)
1538 struct adduserPending
*ap
;
1540 /* So this is a bit wastefull, i hate dealing with linked lists.
1541 * if its a problem we'll rewrite it right */
1542 while((ap
= find_adduser_pending(channel
, user
))) {
1543 del_adduser_pending(ap
);
1547 /* Called from nickserv.c cmd_auth after someone auths */
1549 process_adduser_pending(struct userNode
*user
)
1551 struct adduserPending
*ap
;
1552 if(!user
->handle_info
)
1553 return; /* not associated with an account */
1554 while((ap
= find_adduser_pending(NULL
, user
)))
1556 struct userData
*actee
;
1557 if(GetTrueChannelAccess(ap
->channel
->channel_info
, ap
->user
->handle_info
))
1559 /* Already on the userlist. do nothing*/
1563 actee
= add_channel_user(ap
->channel
->channel_info
, ap
->user
->handle_info
, ap
->level
, 0, NULL
, 0);
1564 scan_user_presence(actee
, NULL
);
1566 del_adduser_pending(ap
);
1571 expire_adduser_pending()
1573 struct adduserPending
*ap
, *ap_next
;
1574 ap
= adduser_pendings
;
1577 if((ap
->created
+ ADDUSER_PENDING_EXPIRE
) < time(NULL
))
1579 ap_next
= ap
->next
; /* save next */
1580 del_adduser_pending(ap
); /* free and relink */
1581 ap
= ap_next
; /* advance */
1588 static void expire_ban(void *data
);
1591 add_channel_ban(struct chanData
*channel
, const char *mask
, char *owner
, time_t set
, time_t triggered
, time_t expires
, char *reason
)
1594 unsigned int ii
, l1
, l2
;
1599 bd
= malloc(sizeof(struct banData
));
1601 bd
->channel
= channel
;
1603 bd
->triggered
= triggered
;
1604 bd
->expires
= expires
;
1606 for(ii
= 0; ii
< chanserv_conf
.old_ban_names
->used
; ++ii
)
1608 extern const char *hidden_host_suffix
;
1609 const char *old_name
= chanserv_conf
.old_ban_names
->list
[ii
];
1613 l2
= strlen(old_name
);
1616 if(irccasecmp(mask
+ l1
- l2
, old_name
))
1618 new_mask
= alloca(MAXLEN
);
1619 sprintf(new_mask
, "%.*s%s", (int)(l1
-l2
), mask
, hidden_host_suffix
);
1622 safestrncpy(bd
->mask
, mask
, sizeof(bd
->mask
));
1624 safestrncpy(bd
->owner
, owner
, sizeof(bd
->owner
));
1625 bd
->reason
= strdup(reason
);
1628 timeq_add(expires
, expire_ban
, bd
);
1631 bd
->next
= channel
->bans
; /* lamers */
1633 channel
->bans
->prev
= bd
;
1635 channel
->banCount
++;
1642 del_channel_ban(struct banData
*ban
)
1644 ban
->channel
->banCount
--;
1648 ban
->prev
->next
= ban
->next
;
1650 ban
->channel
->bans
= ban
->next
;
1653 ban
->next
->prev
= ban
->prev
;
1656 timeq_del(0, expire_ban
, ban
, TIMEQ_IGNORE_WHEN
);
1665 expire_ban(void *data
) /* lamer.. */
1667 struct banData
*bd
= data
;
1668 if(!IsSuspended(bd
->channel
))
1670 struct banList bans
;
1671 struct mod_chanmode change
;
1673 bans
= bd
->channel
->channel
->banlist
;
1674 mod_chanmode_init(&change
);
1675 for(ii
=0; ii
<bans
.used
; ii
++)
1677 if(!strcmp(bans
.list
[ii
]->ban
, bd
->mask
))
1680 change
.args
[0].mode
= MODE_REMOVE
|MODE_BAN
;
1681 change
.args
[0].u
.hostmask
= bd
->mask
;
1682 mod_chanmode_announce(chanserv
, bd
->channel
->channel
, &change
);
1688 del_channel_ban(bd
);
1691 static void chanserv_expire_suspension(void *data
);
1694 unregister_channel(struct chanData
*channel
, const char *reason
)
1696 struct mod_chanmode change
;
1697 char msgbuf
[MAXLEN
];
1699 /* After channel unregistration, the following must be cleaned
1701 - Channel information.
1703 - Channel bans. (lamers)
1704 - Channel suspension data.
1705 - adduser_pending data.
1706 - Timeq entries. (Except timed bans, which are handled elsewhere.)
1712 timeq_del(0, NULL
, channel
, TIMEQ_IGNORE_FUNC
| TIMEQ_IGNORE_WHEN
);
1716 mod_chanmode_init(&change
);
1717 change
.modes_clear
|= MODE_REGISTERED
;
1718 mod_chanmode_announce(chanserv
, channel
->channel
, &change
);
1721 wipe_adduser_pending(channel
->channel
, NULL
);
1723 while(channel
->users
)
1724 del_channel_user(channel
->users
, 0);
1726 while(channel
->bans
)
1727 del_channel_ban(channel
->bans
);
1729 free(channel
->topic
);
1730 free(channel
->registrar
);
1731 free(channel
->greeting
);
1732 free(channel
->user_greeting
);
1733 free(channel
->topic_mask
);
1736 channel
->prev
->next
= channel
->next
;
1738 channelList
= channel
->next
;
1741 channel
->next
->prev
= channel
->prev
;
1743 if(channel
->suspended
)
1745 struct chanNode
*cNode
= channel
->channel
;
1746 struct suspended
*suspended
, *next_suspended
;
1748 for(suspended
= channel
->suspended
; suspended
; suspended
= next_suspended
)
1750 next_suspended
= suspended
->previous
;
1751 free(suspended
->suspender
);
1752 free(suspended
->reason
);
1753 if(suspended
->expires
)
1754 timeq_del(suspended
->expires
, chanserv_expire_suspension
, suspended
, 0);
1759 cNode
->channel_info
= NULL
;
1761 channel
->channel
->channel_info
= NULL
;
1763 dict_delete(channel
->notes
);
1764 sprintf(msgbuf
, "%s %s", channel
->channel
->name
, reason
);
1765 if(!IsSuspended(channel
))
1766 DelChannelUser(chanserv
, channel
->channel
, msgbuf
, 0);
1767 global_message(MESSAGE_RECIPIENT_OPERS
| MESSAGE_RECIPIENT_HELPERS
, msgbuf
);
1768 UnlockChannel(channel
->channel
);
1770 registered_channels
--;
1774 expire_channels(UNUSED_ARG(void *data
))
1776 struct chanData
*channel
, *next
;
1777 struct userData
*user
;
1778 char delay
[INTERVALLEN
], reason
[INTERVALLEN
+ 64];
1780 intervalString(delay
, chanserv_conf
.channel_expire_delay
, NULL
);
1781 sprintf(reason
, "Channel registration automatically expired after %s of disuse.", delay
);
1783 for(channel
= channelList
; channel
; channel
= next
)
1785 next
= channel
->next
;
1787 /* See if the channel can be expired. */
1788 if(((now
- channel
->visited
) <= chanserv_conf
.channel_expire_delay
)
1789 || IsProtected(channel
))
1792 /* Make sure there are no high-ranking users still in the channel. */
1793 for(user
=channel
->users
; user
; user
=user
->next
)
1794 if(user
->present
&& (user
->access
>= UL_PRESENT
))
1799 /* Unregister the channel */
1800 log_module(CS_LOG
, LOG_INFO
, "(%s) Channel registration expired.", channel
->channel
->name
);
1801 spamserv_cs_unregister(NULL
, channel
->channel
, expire
, NULL
);
1802 unregister_channel(channel
, "registration expired.");
1805 if(chanserv_conf
.channel_expire_frequency
)
1806 timeq_add(now
+ chanserv_conf
.channel_expire_frequency
, expire_channels
, NULL
);
1810 protect_user(const struct userNode
*victim
, const struct userNode
*aggressor
, struct chanData
*channel
, int protect_invitables
)
1812 char protect
= channel
->chOpts
[chProtect
];
1813 struct userData
*cs_victim
, *cs_aggressor
;
1815 /* If victim access level is greater than set invitelevel, don't let
1816 * us kick them, but don't consider it punishment if someone else does
1820 if(victim
== aggressor
)
1822 /* Don't protect if the victim isn't authenticated (because they
1823 can't be a channel user), unless we are to protect non-users
1826 cs_victim
= GetChannelAccess(channel
, victim
->handle_info
);
1828 /* If they have enough access to invite themselvs through a ban,
1829 * and its us kicking them, don't. -Rubin */
1830 if(protect_invitables
==true && cs_victim
&& (cs_victim
->access
>= channel
->lvlOpts
[lvlInviteMe
]))
1836 if(protect
!= 'a' && !cs_victim
)
1839 /* Protect if the aggressor isn't a user because at this point,
1840 the aggressor can only be less than or equal to the victim. */
1842 /* Not protected from chanserv except above */
1843 /* XXX: need to generic-ize chanserv to "one of x3's services" somehow.. */
1844 if(aggressor
== chanserv
)
1847 cs_aggressor
= GetChannelAccess(channel
, aggressor
->handle_info
);
1851 /* If the aggressor was a user, then the victim can't be helped. */
1858 if(cs_victim
->access
> cs_aggressor
->access
)
1863 if(cs_victim
->access
>= cs_aggressor
->access
)
1872 validate_op(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, struct userNode
*victim
)
1874 struct chanData
*cData
= channel
->channel_info
;
1875 struct userData
*cs_victim
;
1877 if((!(cs_victim
= GetChannelUser(cData
, victim
->handle_info
))
1878 || (cs_victim
->access
< UL_OP
/* cData->lvlOpts[lvlGiveOps]*/))
1879 && !check_user_level(channel
, user
, lvlEnfOps
, 0, 0))
1882 reply("CSMSG_OPBY_LOCKED");
1884 send_message(user
, chanserv
, "CSMSG_OPBY_LOCKED");
1892 validate_halfop(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, struct userNode
*victim
)
1894 struct chanData
*cData
= channel
->channel_info
;
1895 struct userData
*cs_victim
;
1897 if((!(cs_victim
= GetChannelUser(cData
, victim
->handle_info
))
1898 || (cs_victim
->access
< UL_HALFOP
/* cData->lvlOpts[lvlGiveHalfOps] */))
1899 && !check_user_level(channel
, user
, lvlEnfHalfOps
, 0, 0))
1901 reply("CSMSG_HOPBY_LOCKED");
1910 validate_deop(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, struct userNode
*victim
)
1912 if(IsService(victim
))
1914 reply("MSG_SERVICE_IMMUNE", victim
->nick
);
1918 if(protect_user(victim
, user
, channel
->channel_info
, false))
1920 reply("CSMSG_USER_PROTECTED", victim
->nick
);
1928 validate_dehop(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, struct userNode
*victim
)
1930 if(IsService(victim
))
1932 reply("MSG_SERVICE_IMMUNE", victim
->nick
);
1936 if(protect_user(victim
, user
, channel
->channel_info
, false))
1938 reply("CSMSG_USER_PROTECTED", victim
->nick
);
1945 static struct do_not_register
*
1946 chanserv_add_dnr(const char *chan_name
, const char *setter
, const char *reason
)
1948 struct do_not_register
*dnr
= calloc(1, sizeof(*dnr
)+strlen(reason
));
1949 safestrncpy(dnr
->chan_name
, chan_name
, sizeof(dnr
->chan_name
));
1950 safestrncpy(dnr
->setter
, setter
, sizeof(dnr
->setter
));
1951 strcpy(dnr
->reason
, reason
);
1953 if(dnr
->chan_name
[0] == '*')
1954 dict_insert(handle_dnrs
, dnr
->chan_name
+1, dnr
);
1955 else if(strpbrk(dnr
->chan_name
, "*?"))
1956 dict_insert(mask_dnrs
, dnr
->chan_name
, dnr
);
1958 dict_insert(plain_dnrs
, dnr
->chan_name
, dnr
);
1962 static struct dnrList
1963 chanserv_find_dnrs(const char *chan_name
, const char *handle
)
1965 struct dnrList list
;
1967 struct do_not_register
*dnr
;
1969 dnrList_init(&list
);
1970 if(handle
&& (dnr
= dict_find(handle_dnrs
, handle
, NULL
)))
1971 dnrList_append(&list
, dnr
);
1972 if(chan_name
&& (dnr
= dict_find(plain_dnrs
, chan_name
, NULL
)))
1973 dnrList_append(&list
, dnr
);
1975 for(it
= dict_first(mask_dnrs
); it
; it
= iter_next(it
))
1976 if(match_ircglob(chan_name
, iter_key(it
)))
1977 dnrList_append(&list
, iter_data(it
));
1982 chanserv_show_dnrs(struct userNode
*user
, struct svccmd
*cmd
, const char *chan_name
, const char *handle
)
1984 struct dnrList list
;
1985 struct do_not_register
*dnr
;
1987 char buf
[INTERVALLEN
];
1989 list
= chanserv_find_dnrs(chan_name
, handle
);
1990 for(ii
= 0; (ii
< list
.used
) && (ii
< 10); ++ii
)
1992 dnr
= list
.list
[ii
];
1995 strftime(buf
, sizeof(buf
), "%Y %b %d", localtime(&dnr
->set
));
1996 reply("CSMSG_DNR_INFO_SET", dnr
->chan_name
, buf
, dnr
->setter
, dnr
->reason
);
1999 reply("CSMSG_DNR_INFO", dnr
->chan_name
, dnr
->setter
, dnr
->reason
);
2002 reply("CSMSG_MORE_DNRS", list
.used
- ii
);
2007 struct do_not_register
*
2008 chanserv_is_dnr(const char *chan_name
, struct handle_info
*handle
)
2010 struct do_not_register
*dnr
;
2013 if(handle
&& (dnr
= dict_find(handle_dnrs
, handle
->handle
, NULL
)))
2017 if((dnr
= dict_find(plain_dnrs
, chan_name
, NULL
)))
2019 for(it
= dict_first(mask_dnrs
); it
; it
= iter_next(it
))
2020 if(match_ircglob(chan_name
, iter_key(it
)))
2021 return iter_data(it
);
2026 static CHANSERV_FUNC(cmd_noregister
)
2029 struct do_not_register
*dnr
;
2030 char buf
[INTERVALLEN
];
2031 unsigned int matches
;
2037 reply("CSMSG_DNR_SEARCH_RESULTS");
2038 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
2041 for(it
= dict_first(handle_dnrs
); it
; it
= iter_next(it
))
2043 dnr
= iter_data(it
);
2045 reply("CSMSG_DNR_INFO_SET", dnr
->chan_name
, intervalString(buf
, now
- dnr
->set
, user
->handle_info
), dnr
->setter
, dnr
->reason
);
2047 reply("CSMSG_DNR_INFO", dnr
->chan_name
, dnr
->setter
, dnr
->reason
);
2050 for(it
= dict_first(plain_dnrs
); it
; it
= iter_next(it
))
2052 dnr
= iter_data(it
);
2054 reply("CSMSG_DNR_INFO_SET", dnr
->chan_name
, intervalString(buf
, now
- dnr
->set
, user
->handle_info
), dnr
->setter
, dnr
->reason
);
2056 reply("CSMSG_DNR_INFO", dnr
->chan_name
, dnr
->setter
, dnr
->reason
);
2059 for(it
= dict_first(mask_dnrs
); it
; it
= iter_next(it
))
2061 dnr
= iter_data(it
);
2063 reply("CSMSG_DNR_INFO_SET", dnr
->chan_name
, intervalString(buf
, now
- dnr
->set
, user
->handle_info
), dnr
->setter
, dnr
->reason
);
2065 reply("CSMSG_DNR_INFO", dnr
->chan_name
, dnr
->setter
, dnr
->reason
);
2070 reply("MSG_MATCH_COUNT", matches
);
2072 reply("MSG_NO_MATCHES");
2078 if(!IsChannelName(target
) && (*target
!= '*'))
2080 reply("CSMSG_NOT_DNR", target
);
2086 const char *reason
= unsplit_string(argv
+ 2, argc
- 2, NULL
);
2087 if((*target
== '*') && !get_handle_info(target
+ 1))
2089 reply("MSG_HANDLE_UNKNOWN", target
+ 1);
2092 chanserv_add_dnr(target
, user
->handle_info
->handle
, reason
);
2093 reply("CSMSG_NOREGISTER_CHANNEL", target
);
2097 reply("CSMSG_DNR_SEARCH_RESULTS");
2098 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
2101 matches
= chanserv_show_dnrs(user
, cmd
, NULL
, target
+ 1);
2103 matches
= chanserv_show_dnrs(user
, cmd
, target
, NULL
);
2105 reply("MSG_NO_MATCHES");
2109 static CHANSERV_FUNC(cmd_allowregister
)
2111 const char *chan_name
= argv
[1];
2113 if((chan_name
[0] == '*') && dict_find(handle_dnrs
, chan_name
+1, NULL
))
2115 dict_remove(handle_dnrs
, chan_name
+1);
2116 reply("CSMSG_DNR_REMOVED", chan_name
);
2118 else if(dict_find(plain_dnrs
, chan_name
, NULL
))
2120 dict_remove(plain_dnrs
, chan_name
);
2121 reply("CSMSG_DNR_REMOVED", chan_name
);
2123 else if(dict_find(mask_dnrs
, chan_name
, NULL
))
2125 dict_remove(mask_dnrs
, chan_name
);
2126 reply("CSMSG_DNR_REMOVED", chan_name
);
2130 reply("CSMSG_NO_SUCH_DNR", chan_name
);
2137 chanserv_get_owned_count(struct handle_info
*hi
)
2139 struct userData
*cList
;
2142 for(owned
=0, cList
=hi
->channels
; cList
; cList
=cList
->u_next
)
2143 if(cList
->access
== UL_OWNER
)
2148 static CHANSERV_FUNC(cmd_register
)
2150 struct handle_info
*handle
;
2151 struct chanData
*cData
;
2152 struct modeNode
*mn
;
2153 char reason
[MAXLEN
];
2155 unsigned int new_channel
, force
=0;
2156 struct do_not_register
*dnr
;
2159 if (checkDefCon(DEFCON_NO_NEW_CHANNELS
) && !IsOper(user
)) {
2160 reply("CSMSG_DEFCON_NO_NEW_CHANNELS");
2166 if(channel
->channel_info
)
2168 reply("CSMSG_ALREADY_REGGED", channel
->name
);
2172 if(channel
->bad_channel
)
2174 reply("CSMSG_ILLEGAL_CHANNEL", channel
->name
);
2178 if(!IsHelping(user
) && (!(mn
= GetUserMode(channel
, user
)) || !(mn
->modes
& MODE_CHANOP
)))
2180 reply("CSMSG_MUST_BE_OPPED", channel
->name
);
2185 chan_name
= channel
->name
;
2191 reply("MSG_MISSING_PARAMS", cmd
->name
);
2192 svccmd_send_help_brief(user
, chanserv
, cmd
);
2195 if(!IsChannelName(argv
[1]))
2197 reply("MSG_NOT_CHANNEL_NAME");
2201 if(opserv_bad_channel(argv
[1]))
2203 reply("CSMSG_ILLEGAL_CHANNEL", argv
[1]);
2208 chan_name
= argv
[1];
2211 if(argc
>= (new_channel
+2))
2213 if(!IsHelping(user
))
2215 reply("CSMSG_PROXY_FORBIDDEN");
2219 if(!(handle
= modcmd_get_handle_info(user
, argv
[new_channel
+1])))
2221 force
= (argc
> (new_channel
+2)) && !irccasecmp(argv
[new_channel
+2], "force");
2222 dnr
= chanserv_is_dnr(chan_name
, handle
);
2224 /* Check if they are over the limit.. */
2225 if((chanserv_get_owned_count(handle
) >= chanserv_conf
.max_owned
) && !force
)
2227 reply("CSMSG_OWN_TOO_MANY", handle
->handle
, chanserv_conf
.max_owned
);
2234 handle
= user
->handle_info
;
2235 dnr
= chanserv_is_dnr(chan_name
, handle
);
2236 /* Check if they are over the limit.. */
2237 if((chanserv_get_owned_count(handle
) >= chanserv_conf
.max_owned
) && !force
)
2239 reply("CSMSG_YOU_OWN_TOO_MANY", chanserv_conf
.max_owned
);
2242 /* Check if another service is in the channel */
2244 for(n
= 0; n
< channel
->members
.used
; n
++)
2246 mn
= channel
->members
.list
[n
];
2247 if((mn
&& mn
->user
&& (mn
->user
->modes
& FLAGS_SERVICE
)) || IsLocal(mn
->user
))
2249 reply("CSMSG_ANOTHER_SERVICE");
2256 if(!IsHelping(user
))
2257 reply("CSMSG_DNR_CHANNEL", chan_name
);
2259 chanserv_show_dnrs(user
, cmd
, chan_name
, handle
->handle
);
2263 /* now handled above for message specilization *
2264 if((chanserv_get_owned_count(handle) >= chanserv_conf.max_owned) && !force)
2266 reply("CSMSG_OWN_TOO_MANY", handle->handle, chanserv_conf.max_owned);
2272 channel
= AddChannel(argv
[1], now
, NULL
, NULL
, NULL
);
2274 cData
= register_channel(channel
, user
->handle_info
->handle
);
2275 scan_user_presence(add_channel_user(cData
, handle
, UL_OWNER
, 0, NULL
, 0), NULL
);
2276 cData
->modes
= chanserv_conf
.default_modes
;
2278 cData
->modes
.modes_set
|= MODE_REGISTERED
;
2279 if (IsOffChannel(cData
))
2281 mod_chanmode_announce(chanserv
, channel
, &cData
->modes
);
2285 struct mod_chanmode
*change
= mod_chanmode_dup(&cData
->modes
, 1);
2286 change
->args
[change
->argc
].mode
= MODE_CHANOP
;
2287 change
->args
[change
->argc
].u
.member
= AddChannelUser(chanserv
, channel
);
2289 mod_chanmode_announce(chanserv
, channel
, change
);
2290 mod_chanmode_free(change
);
2293 /* Initialize the channel's max user record. */
2294 cData
->max
= channel
->members
.used
;
2295 cData
->maxsetinfo
= chanserv_conf
.max_userinfo_length
;
2297 if(handle
!= user
->handle_info
)
2298 reply("CSMSG_PROXY_SUCCESS", handle
->handle
, channel
->name
);
2301 sprintf(reason
, "%s registered to %s by %s.", channel
->name
, handle
->handle
, user
->handle_info
->handle
);
2302 global_message_args(MESSAGE_RECIPIENT_OPERS
| MESSAGE_RECIPIENT_HELPERS
, "CSMSG_REGISTERED_TO", channel
->name
,
2303 handle
->handle
, user
->handle_info
->handle
);
2308 make_confirmation_string(struct userData
*uData
)
2310 static char strbuf
[16];
2315 for(src
= uData
->handle
->handle
; *src
; )
2316 accum
= accum
* 31 + toupper(*src
++);
2318 for(src
= uData
->channel
->channel
->name
; *src
; )
2319 accum
= accum
* 31 + toupper(*src
++);
2320 sprintf(strbuf
, "%08x", accum
);
2324 static CHANSERV_FUNC(cmd_unregister
)
2327 char reason
[MAXLEN
];
2328 struct chanData
*cData
;
2329 struct userData
*uData
;
2331 cData
= channel
->channel_info
;
2334 reply("CSMSG_NOT_REGISTERED", channel
->name
);
2338 uData
= GetChannelUser(cData
, user
->handle_info
);
2339 if(!uData
|| (uData
->access
< UL_OWNER
))
2341 reply("CSMSG_NO_ACCESS");
2345 if(IsProtected(cData
))
2347 reply("CSMSG_UNREG_NODELETE", channel
->name
);
2351 if(!IsHelping(user
))
2353 const char *confirm_string
;
2354 if(IsSuspended(cData
))
2356 reply("CSMSG_CHAN_SUSPENDED", channel
->name
, cData
->suspended
->reason
);
2359 confirm_string
= make_confirmation_string(uData
);
2360 if((argc
< 2) || strcmp(argv
[1], confirm_string
))
2362 reply("CSMSG_CONFIRM_UNREG", channel
->name
, confirm_string
);
2367 sprintf(reason
, "unregistered by %s.", user
->handle_info
->handle
);
2368 name
= strdup(channel
->name
);
2369 unregister_channel(cData
, reason
);
2370 spamserv_cs_unregister(user
, channel
, manually
, "unregistered");
2371 reply("CSMSG_UNREG_SUCCESS", name
);
2377 ss_cs_join_channel(struct chanNode
*channel
, int spamserv_join
)
2379 extern struct userNode
*spamserv
;
2380 struct mod_chanmode
*change
;
2382 if(spamserv
&& spamserv_join
&& get_chanInfo(channel
->name
))
2384 change
= mod_chanmode_alloc(2);
2386 change
->args
[0].mode
= MODE_CHANOP
;
2387 change
->args
[0].u
.member
= AddChannelUser(chanserv
, channel
);
2388 change
->args
[1].mode
= MODE_CHANOP
;
2389 change
->args
[1].u
.member
= AddChannelUser(spamserv
, channel
);
2393 change
= mod_chanmode_alloc(1);
2395 change
->args
[0].mode
= MODE_CHANOP
;
2396 change
->args
[0].u
.member
= AddChannelUser(chanserv
, channel
);
2399 mod_chanmode_announce(chanserv
, channel
, change
);
2400 mod_chanmode_free(change
);
2403 static CHANSERV_FUNC(cmd_move
)
2405 struct mod_chanmode change
;
2406 struct chanNode
*target
;
2407 struct modeNode
*mn
;
2408 struct userData
*uData
;
2409 struct do_not_register
*dnr
;
2410 int chanserv_join
= 0, spamserv_join
;
2414 if(IsProtected(channel
->channel_info
))
2416 reply("CSMSG_MOVE_NODELETE", channel
->name
);
2420 if(!IsChannelName(argv
[1]))
2422 reply("MSG_NOT_CHANNEL_NAME");
2426 if(opserv_bad_channel(argv
[1]))
2428 reply("CSMSG_ILLEGAL_CHANNEL", argv
[1]);
2432 if(!IsHelping(user
) || (argc
< 3) || irccasecmp(argv
[2], "force"))
2434 for(uData
= channel
->channel_info
->users
; uData
; uData
= uData
->next
)
2436 if((uData
->access
== UL_OWNER
) && (dnr
= chanserv_is_dnr(argv
[1], uData
->handle
)))
2438 if(!IsHelping(user
))
2439 reply("CSMSG_DNR_CHANNEL_MOVE", argv
[1]);
2441 chanserv_show_dnrs(user
, cmd
, argv
[1], uData
->handle
->handle
);
2447 mod_chanmode_init(&change
);
2448 if(!(target
= GetChannel(argv
[1])))
2450 target
= AddChannel(argv
[1], now
, NULL
, NULL
, NULL
);
2451 if(!IsSuspended(channel
->channel_info
))
2454 else if(target
->channel_info
)
2456 reply("CSMSG_ALREADY_REGGED", target
->name
);
2459 else if((!(mn
= GetUserMode(target
, user
)) || !(mn
->modes
&& MODE_CHANOP
))
2460 && !IsHelping(user
))
2462 reply("CSMSG_MUST_BE_OPPED", target
->name
);
2465 else if(!IsSuspended(channel
->channel_info
))
2470 /* Clear MODE_REGISTERED from old channel, add it to new. */
2472 change
.modes_clear
= MODE_REGISTERED
;
2473 mod_chanmode_announce(chanserv
, channel
, &change
);
2474 change
.modes_clear
= 0;
2475 change
.modes_set
= MODE_REGISTERED
;
2476 mod_chanmode_announce(chanserv
, target
, &change
);
2479 /* Move the channel_info to the target channel; it
2480 shouldn't be necessary to clear timeq callbacks
2481 for the old channel. */
2482 target
->channel_info
= channel
->channel_info
;
2483 target
->channel_info
->channel
= target
;
2484 channel
->channel_info
= NULL
;
2486 spamserv_join
= spamserv_cs_move_merge(user
, channel
, target
, 1);
2489 ss_cs_join_channel(target
, spamserv_join
);
2491 if(!IsSuspended(target
->channel_info
))
2493 char reason2
[MAXLEN
];
2494 sprintf(reason2
, "Channel moved to %s by %s.", target
->name
, user
->handle_info
->handle
);
2495 DelChannelUser(chanserv
, channel
, reason2
, 0);
2498 UnlockChannel(channel
);
2499 LockChannel(target
);
2500 global_message_args(MESSAGE_RECIPIENT_OPERS
| MESSAGE_RECIPIENT_HELPERS
, "CSMSG_CHANNEL_MOVED",
2501 channel
->name
, target
->name
, user
->handle_info
->handle
);
2503 reply("CSMSG_MOVE_SUCCESS", target
->name
);
2508 merge_users(struct chanData
*source
, struct chanData
*target
)
2510 struct userData
*suData
, *tuData
, *next
;
2516 /* Insert the source's users into the scratch area. */
2517 for(suData
= source
->users
; suData
; suData
= suData
->next
)
2518 dict_insert(merge
, suData
->handle
->handle
, suData
);
2520 /* Iterate through the target's users, looking for
2521 users common to both channels. The lower access is
2522 removed from either the scratch area or target user
2524 for(tuData
= target
->users
; tuData
; tuData
= next
)
2526 struct userData
*choice
;
2528 next
= tuData
->next
;
2530 /* If a source user exists with the same handle as a target
2531 channel's user, resolve the conflict by removing one. */
2532 suData
= dict_find(merge
, tuData
->handle
->handle
, NULL
);
2536 /* Pick the data we want to keep. */
2537 /* If the access is the same, use the later seen time. */
2538 if(suData
->access
== tuData
->access
)
2539 choice
= (suData
->seen
> tuData
->seen
) ? suData
: tuData
;
2540 else /* Otherwise, keep the higher access level. */
2541 choice
= (suData
->access
> tuData
->access
) ? suData
: tuData
;
2543 /* Remove the user that wasn't picked. */
2544 if(choice
== tuData
)
2546 dict_remove(merge
, suData
->handle
->handle
);
2547 del_channel_user(suData
, 0);
2550 del_channel_user(tuData
, 0);
2553 /* Move the remaining users to the target channel. */
2554 for(it
= dict_first(merge
); it
; it
= iter_next(it
))
2556 suData
= iter_data(it
);
2558 /* Insert the user into the target channel's linked list. */
2559 suData
->prev
= NULL
;
2560 suData
->next
= target
->users
;
2561 suData
->channel
= target
;
2564 target
->users
->prev
= suData
;
2565 target
->users
= suData
;
2567 /* Update the user counts for the target channel; the
2568 source counts are left alone. */
2569 target
->userCount
++;
2572 /* Possible to assert (source->users == NULL) here. */
2573 source
->users
= NULL
;
2578 merge_bans(struct chanData
*source
, struct chanData
*target
)
2580 struct banData
*sbData
, *tbData
, *sNext
, *tNext
, *tFront
;
2582 /* Hold on to the original head of the target ban list
2583 to avoid comparing source bans with source bans. */
2584 tFront
= target
->bans
;
2586 /* Perform a totally expensive O(n*m) merge, ick. */
2587 for(sbData
= source
->bans
; sbData
; sbData
= sNext
)
2589 /* Flag to track whether the ban's been moved
2590 to the destination yet. */
2593 /* Possible to assert (sbData->prev == NULL) here. */
2594 sNext
= sbData
->next
;
2596 for(tbData
= tFront
; tbData
; tbData
= tNext
)
2598 tNext
= tbData
->next
;
2600 /* Perform two comparisons between each source
2601 and target ban, conflicts are resolved by
2602 keeping the broader ban and copying the later
2603 expiration and triggered time. */
2604 if(match_ircglobs(tbData
->mask
, sbData
->mask
))
2606 /* There is a broader ban in the target channel that
2607 overrides one in the source channel; remove the
2608 source ban and break. */
2609 if(sbData
->expires
> tbData
->expires
)
2610 tbData
->expires
= sbData
->expires
;
2611 if(sbData
->triggered
> tbData
->triggered
)
2612 tbData
->triggered
= sbData
->triggered
;
2613 del_channel_ban(sbData
);
2616 else if(match_ircglobs(sbData
->mask
, tbData
->mask
))
2618 /* There is a broader ban in the source channel that
2619 overrides one in the target channel; remove the
2620 target ban, fall through and move the source over. */
2621 if(tbData
->expires
> sbData
->expires
)
2622 sbData
->expires
= tbData
->expires
;
2623 if(tbData
->triggered
> sbData
->triggered
)
2624 sbData
->triggered
= tbData
->triggered
;
2625 if(tbData
== tFront
)
2627 del_channel_ban(tbData
);
2630 /* Source bans can override multiple target bans, so
2631 we allow a source to run through this loop multiple
2632 times, but we can only move it once. */
2637 /* Remove the source ban from the source ban list. */
2639 sbData
->next
->prev
= sbData
->prev
;
2641 /* Modify the source ban's associated channel. */
2642 sbData
->channel
= target
;
2644 /* Insert the ban into the target channel's linked list. */
2645 sbData
->prev
= NULL
;
2646 sbData
->next
= target
->bans
;
2649 target
->bans
->prev
= sbData
;
2650 target
->bans
= sbData
;
2652 /* Update the user counts for the target channel. */
2657 /* Possible to assert (source->bans == NULL) here. */
2658 source
->bans
= NULL
;
2662 merge_data(struct chanData
*source
, struct chanData
*target
)
2664 /* Use more recent visited and owner-transfer time; use older
2665 * registered time. Bitwise or may_opchan. Use higher max.
2666 * Do not touch last_refresh, ban count or user counts.
2668 if(source
->visited
> target
->visited
)
2669 target
->visited
= source
->visited
;
2670 if(source
->registered
< target
->registered
)
2671 target
->registered
= source
->registered
;
2672 if(source
->ownerTransfer
> target
->ownerTransfer
)
2673 target
->ownerTransfer
= source
->ownerTransfer
;
2674 if(source
->may_opchan
)
2675 target
->may_opchan
= 1;
2676 if(source
->max
> target
->max
)
2677 target
->max
= source
->max
;
2681 merge_channel(struct chanData
*source
, struct chanData
*target
)
2683 merge_users(source
, target
);
2684 merge_bans(source
, target
);
2685 merge_data(source
, target
);
2688 static CHANSERV_FUNC(cmd_merge
)
2690 struct userData
*target_user
;
2691 struct chanNode
*target
;
2692 char reason
[MAXLEN
];
2696 /* Make sure the target channel exists and is registered to the user
2697 performing the command. */
2698 if(!(target
= GetChannel(argv
[1])))
2700 reply("MSG_INVALID_CHANNEL");
2704 if(!target
->channel_info
)
2706 reply("CSMSG_NOT_REGISTERED", target
->name
);
2710 if(IsProtected(channel
->channel_info
))
2712 reply("CSMSG_MERGE_NODELETE");
2716 if(IsSuspended(target
->channel_info
))
2718 reply("CSMSG_MERGE_SUSPENDED");
2722 if(channel
== target
)
2724 reply("CSMSG_MERGE_SELF");
2728 target_user
= GetChannelUser(target
->channel_info
, user
->handle_info
);
2729 if(!target_user
|| (target_user
->access
< UL_OWNER
))
2731 reply("CSMSG_MERGE_NOT_OWNER");
2735 /* Merge the channel structures and associated data. */
2736 merge_channel(channel
->channel_info
, target
->channel_info
);
2737 spamserv_cs_move_merge(user
, channel
, target
, 0);
2738 sprintf(reason
, "merged into %s by %s.", target
->name
, user
->handle_info
->handle
);
2739 unregister_channel(channel
->channel_info
, reason
);
2740 reply("CSMSG_MERGE_SUCCESS", target
->name
);
2744 static CHANSERV_FUNC(cmd_opchan
)
2746 struct mod_chanmode change
;
2747 if(!IsHelping(user
) && !channel
->channel_info
->may_opchan
)
2749 reply("CSMSG_ALREADY_OPCHANNED", channel
->name
);
2752 channel
->channel_info
->may_opchan
= 0;
2753 mod_chanmode_init(&change
);
2755 change
.args
[0].mode
= MODE_CHANOP
;
2756 change
.args
[0].u
.member
= GetUserMode(channel
, chanserv
);
2757 mod_chanmode_announce(chanserv
, channel
, &change
);
2758 reply("CSMSG_OPCHAN_DONE", channel
->name
);
2762 static CHANSERV_FUNC(cmd_adduser
)
2764 struct userData
*actee
;
2765 struct userData
*actor
;
2766 struct handle_info
*handle
;
2767 unsigned short access
;
2771 if(channel
->channel_info
->userCount
>= chanserv_conf
.max_chan_users
)
2773 reply("CSMSG_MAXIMUM_USERS", chanserv_conf
.max_chan_users
);
2777 access
= user_level_from_name(argv
[2], UL_OWNER
);
2780 reply("CSMSG_INVALID_ACCESS", argv
[2]);
2784 actor
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
2785 if(actor
->access
<= access
)
2787 reply("CSMSG_NO_BUMP_ACCESS");
2791 if(!(handle
= modcmd_get_handle_info(user
, argv
[1])))
2793 // 'kevin must first authenticate with AuthServ.' is sent to user
2794 struct userNode
*unode
;
2795 unode
= GetUserH(argv
[1]); /* find user struct by nick */
2798 if(find_adduser_pending(channel
, unode
)) {
2799 reply("CSMSG_ADDUSER_PENDING_ALREADY", channel
->name
);
2802 if(IsInChannel(channel
, unode
)) {
2803 reply("CSMSG_ADDUSER_PENDING");
2804 add_adduser_pending(channel
, unode
, access
);
2805 send_message_type(1,unode
, chanserv
, "CSMSG_ADDUSER_PENDING_TARGET", user
->nick
, channel
->name
);
2807 /* this results in user must auth AND not in chan errors. too confusing..
2809 reply("CSMSG_ADDUSER_PENDING_NOTINCHAN", channel->name);
2817 if((actee
= GetTrueChannelAccess(channel
->channel_info
, handle
)))
2819 reply("CSMSG_USER_EXISTS", handle
->handle
, channel
->name
, user_level_name_from_level(actee
->access
));
2823 time_t accessexpiry
= 0;
2824 unsigned int duration
= 0;
2826 if ((duration
= ParseInterval(argv
[3])))
2827 accessexpiry
= now
+ duration
;
2830 actee
= add_channel_user(channel
->channel_info
, handle
, access
, 0, NULL
, accessexpiry
);
2831 scan_user_presence(actee
, NULL
);
2834 timeq_add(accessexpiry
, chanserv_expire_tempuser
, actee
);
2836 reply("CSMSG_ADDED_USER", handle
->handle
, channel
->name
, user_level_name_from_level(access
), access
);
2840 static CHANSERV_FUNC(cmd_clvl
)
2842 struct handle_info
*handle
;
2843 struct userData
*victim
;
2844 struct userData
*actor
;
2845 unsigned short new_access
;
2846 int privileged
= IsHelping(user
) && ((user
->handle_info
->opserv_level
>= chanserv_conf
.nodelete_level
) || !IsProtected(channel
->channel_info
));
2850 actor
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
2852 if(!(handle
= modcmd_get_handle_info(user
, argv
[1])))
2855 if(handle
== user
->handle_info
&& !privileged
)
2857 reply("CSMSG_NO_SELF_CLVL");
2861 if(!(victim
= GetTrueChannelAccess(channel
->channel_info
, handle
)))
2863 reply("CSMSG_NO_CHAN_USER", handle
->handle
, channel
->name
);
2867 if(actor
->access
<= victim
->access
&& !privileged
)
2869 reply("MSG_USER_OUTRANKED", handle
->handle
);
2873 new_access
= user_level_from_name(argv
[2], UL_OWNER
);
2877 reply("CSMSG_INVALID_ACCESS", argv
[2]);
2881 if(new_access
>= actor
->access
&& !privileged
)
2883 reply("CSMSG_NO_BUMP_ACCESS");
2887 time_t clvlexpiry
= 0;
2888 unsigned int duration
= 0;
2890 if ((duration
= ParseInterval(argv
[3])))
2891 clvlexpiry
= now
+ duration
;
2895 if (victim
->accessexpiry
> 0) {
2896 reply("CSMSG_NO_BUMP_EXPIRY");
2900 victim
->clvlexpiry
= clvlexpiry
;
2901 victim
->lastaccess
= victim
->access
;
2902 timeq_add(clvlexpiry
, chanserv_expire_tempclvl
, victim
);
2905 victim
->access
= new_access
;
2906 reply("CSMSG_CHANGED_ACCESS", handle
->handle
, user_level_name_from_level(new_access
), new_access
, channel
->name
);
2910 static CHANSERV_FUNC(cmd_deluser
)
2912 struct handle_info
*handle
;
2913 struct userData
*victim
;
2914 struct userData
*actor
;
2915 unsigned short access
;
2920 actor
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
2922 if(!(handle
= modcmd_get_handle_info(user
, argv
[argc
-1])))
2925 if(!(victim
= GetTrueChannelAccess(channel
->channel_info
, handle
)))
2927 reply("CSMSG_NO_CHAN_USER", handle
->handle
, channel
->name
);
2933 access
= user_level_from_name(argv
[1], UL_OWNER
);
2934 char *useraccess
= user_level_name_from_level(victim
->access
);
2937 reply("CSMSG_INVALID_ACCESS", argv
[1]);
2940 if(strcasecmp(argv
[1], useraccess
))
2942 reply("CSMSG_INCORRECT_ACCESS", handle
->handle
, user_level_name_from_level(victim
->access
), argv
[1]);
2948 access
= victim
->access
;
2951 if((actor
->access
<= victim
->access
) && !IsHelping(user
))
2953 reply("MSG_USER_OUTRANKED", victim
->handle
->handle
);
2957 chan_name
= strdup(channel
->name
);
2958 del_channel_user(victim
, 1);
2959 reply("CSMSG_DELETED_USER", handle
->handle
, access
, chan_name
);
2965 cmd_mdel_user(struct userNode
*user
, struct chanNode
*channel
, unsigned short min_access
, unsigned short max_access
, char *mask
, struct svccmd
*cmd
)
2967 struct userData
*actor
, *uData
, *next
;
2969 actor
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
2971 if(min_access
> max_access
)
2973 reply("CSMSG_BAD_RANGE", min_access
, max_access
);
2977 if((actor
->access
<= max_access
) && !IsHelping(user
))
2979 reply("CSMSG_NO_ACCESS");
2983 for(uData
= channel
->channel_info
->users
; uData
; uData
= next
)
2987 if((uData
->access
>= min_access
)
2988 && (uData
->access
<= max_access
)
2989 && match_ircglob(uData
->handle
->handle
, mask
))
2990 del_channel_user(uData
, 1);
2993 reply("CSMSG_DELETED_USERS", mask
, min_access
, max_access
, channel
->name
);
2997 static CHANSERV_FUNC(cmd_mdelowner
)
2999 return cmd_mdel_user(user
, channel
, UL_OWNER
, UL_OWNER
, argv
[1], cmd
);
3002 static CHANSERV_FUNC(cmd_mdelcoowner
)
3004 return cmd_mdel_user(user
, channel
, UL_COOWNER
, UL_OWNER
-1, argv
[1], cmd
);
3007 static CHANSERV_FUNC(cmd_mdelmanager
)
3009 return cmd_mdel_user(user
, channel
, UL_MANAGER
, UL_COOWNER
-1, argv
[1], cmd
);
3012 static CHANSERV_FUNC(cmd_mdelop
)
3014 return cmd_mdel_user(user
, channel
, UL_OP
, UL_MANAGER
-1, argv
[1], cmd
);
3017 static CHANSERV_FUNC(cmd_mdelhalfop
)
3019 return cmd_mdel_user(user
, channel
, UL_HALFOP
, UL_OP
-1, argv
[1], cmd
);
3022 static CHANSERV_FUNC(cmd_mdelpeon
)
3024 return cmd_mdel_user(user
, channel
, UL_PEON
, UL_HALFOP
-1, argv
[1], cmd
);
3028 static CHANSERV_FUNC(cmd_levels
)
3030 struct helpfile_table tbl
;
3033 tbl
.length
= 6 + 1; // 6 levels
3036 tbl
.contents
= calloc(tbl
.length
,sizeof(tbl
.contents
[0]));
3037 tbl
.contents
[0] = calloc(tbl
.width
,sizeof(tbl
.contents
[0][0]));
3038 tbl
.contents
[0][0] = "Level";
3039 tbl
.contents
[0][1] = "From";
3040 tbl
.contents
[0][2] = "-";
3041 tbl
.contents
[0][3] = "To";
3043 tbl
.contents
[++ii
] = calloc(tbl
.width
, sizeof(tbl
.contents
[0][0]));
3044 tbl
.contents
[ii
][0] = strdup(user_level_name_from_level(UL_OWNER
));
3045 tbl
.contents
[ii
][1] = msnprintf(4, "%d", UL_OWNER
);
3046 tbl
.contents
[ii
][2] = msnprintf(2, " ");
3047 tbl
.contents
[ii
][3] = msnprintf(1, "");
3049 tbl
.contents
[++ii
] = calloc(tbl
.width
, sizeof(tbl
.contents
[0][0]));
3050 tbl
.contents
[ii
][0] = strdup(user_level_name_from_level(UL_COOWNER
));
3051 tbl
.contents
[ii
][1] = msnprintf(4, "%d", UL_COOWNER
);
3052 tbl
.contents
[ii
][2] = msnprintf(2, "-");
3053 tbl
.contents
[ii
][3] = msnprintf(4, "%d", UL_OWNER
-1);
3055 tbl
.contents
[++ii
] = calloc(tbl
.width
, sizeof(tbl
.contents
[0][0]));
3056 tbl
.contents
[ii
][0] = strdup(user_level_name_from_level(UL_MANAGER
));
3057 tbl
.contents
[ii
][1] = msnprintf(4, "%d", UL_MANAGER
);
3058 tbl
.contents
[ii
][2] = msnprintf(2, "-");
3059 tbl
.contents
[ii
][3] = msnprintf(4, "%d", UL_COOWNER
-1);
3061 tbl
.contents
[++ii
] = calloc(tbl
.width
, sizeof(tbl
.contents
[0][0]));
3062 tbl
.contents
[ii
][0] = strdup(user_level_name_from_level(UL_OP
));
3063 tbl
.contents
[ii
][1] = msnprintf(4, "%d", UL_OP
);
3064 tbl
.contents
[ii
][2] = msnprintf(2, "-");
3065 tbl
.contents
[ii
][3] = msnprintf(4, "%d", UL_MANAGER
-1);
3067 tbl
.contents
[++ii
] = calloc(tbl
.width
, sizeof(tbl
.contents
[0][0]));
3068 tbl
.contents
[ii
][0] = strdup(user_level_name_from_level(UL_HALFOP
));
3069 tbl
.contents
[ii
][1] = msnprintf(4, "%d", UL_HALFOP
);
3070 tbl
.contents
[ii
][2] = msnprintf(2, "-");
3071 tbl
.contents
[ii
][3] = msnprintf(4, "%d", UL_OP
-1);
3073 tbl
.contents
[++ii
] = calloc(tbl
.width
, sizeof(tbl
.contents
[0][0]));
3074 tbl
.contents
[ii
][0] = strdup(user_level_name_from_level(UL_PEON
));
3075 tbl
.contents
[ii
][1] = msnprintf(4, "%d", UL_PEON
);
3076 tbl
.contents
[ii
][2] = msnprintf(2, "-");
3077 tbl
.contents
[ii
][3] = msnprintf(4, "%d", UL_HALFOP
-1);
3079 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3083 reply("CSMSG_LEVELS_HEADER");
3084 reply("CSMSG_LEVELS", user_level_name_from_level(UL_OWNER), UL_OWNER, UL_OWNER);
3085 reply("CSMSG_LEVELS", user_level_name_from_level(UL_COOWNER), UL_COOWNER, UL_OWNER-1);
3086 reply("CSMSG_LEVELS", user_level_name_from_level(UL_MANAGER), UL_MANAGER, UL_COOWNER-1);
3087 reply("CSMSG_LEVELS", user_level_name_from_level(UL_OP), UL_OP, UL_MANAGER-1);
3088 reply("CSMSG_LEVELS", user_level_name_from_level(UL_HALFOP), UL_HALFOP, UL_OP-1);
3089 reply("CSMSG_LEVELS", user_level_name_from_level(UL_PEON), UL_PEON, UL_HALFOP-1);
3096 cmd_trim_bans(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, unsigned long duration
)
3098 struct banData
*bData
, *next
;
3099 char interval
[INTERVALLEN
];
3104 limit
= now
- duration
;
3105 for(bData
= channel
->channel_info
->bans
; bData
; bData
= next
)
3109 if((bData
->triggered
&& bData
->triggered
>= limit
) || (bData
->set
&& bData
->set
>= limit
))
3112 del_channel_ban(bData
);
3116 intervalString(interval
, duration
, user
->handle_info
);
3117 reply("CSMSG_TRIMMED_LAMERS", count
, channel
->name
, interval
);
3122 cmd_trim_users(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, unsigned short min_access
, unsigned short max_access
, unsigned long duration
, int vacation
)
3124 struct userData
*actor
, *uData
, *next
;
3125 char interval
[INTERVALLEN
];
3129 actor
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
3130 if(min_access
> max_access
)
3132 reply("CSMSG_BAD_RANGE", min_access
, max_access
);
3136 if((actor
->access
<= max_access
) && !IsHelping(user
))
3138 reply("CSMSG_NO_ACCESS");
3143 limit
= now
- duration
;
3144 for(uData
= channel
->channel_info
->users
; uData
; uData
= next
)
3148 if((uData
->seen
> limit
)
3150 || (HANDLE_FLAGGED(uData
->handle
, FROZEN
) && !vacation
))
3153 if(((uData
->access
>= min_access
) && (uData
->access
<= max_access
))
3154 || (!max_access
&& (uData
->access
< actor
->access
)))
3156 del_channel_user(uData
, 1);
3164 max_access
= (actor
->access
> UL_OWNER
) ? UL_OWNER
: (actor
->access
- 1);
3166 reply("CSMSG_TRIMMED_USERS", count
, min_access
, max_access
, channel
->name
, intervalString(interval
, duration
, user
->handle_info
));
3170 static CHANSERV_FUNC(cmd_trim
)
3172 unsigned long duration
;
3173 unsigned short min_level
, max_level
;
3178 vacation
= argc
> 3 && !strcmp(argv
[3], "vacation");
3179 duration
= ParseInterval(argv
[2]);
3182 reply("CSMSG_CANNOT_TRIM");
3186 if(!irccasecmp(argv
[1], "lamers"))
3188 cmd_trim_bans(cmd
, user
, channel
, duration
); /* trim_lamers.. */
3191 else if(!irccasecmp(argv
[1], "users"))
3193 cmd_trim_users(cmd
, user
, channel
, 0, 0, duration
, vacation
);
3196 else if(parse_level_range(&min_level
, &max_level
, argv
[1]))
3198 cmd_trim_users(cmd
, user
, channel
, min_level
, max_level
, duration
, vacation
);
3201 else if((min_level
= user_level_from_name(argv
[1], UL_OWNER
)))
3203 cmd_trim_users(cmd
, user
, channel
, min_level
, min_level
, duration
, vacation
);
3208 reply("CSMSG_INVALID_TRIM", argv
[1]);
3213 /* If argc is 0 in cmd_up or cmd_down, no notices will be sent
3214 to the user. cmd_all takes advantage of this. */
3215 static CHANSERV_FUNC(cmd_up
)
3217 struct mod_chanmode change
;
3218 struct userData
*uData
;
3221 mod_chanmode_init(&change
);
3223 change
.args
[0].u
.member
= GetUserMode(channel
, user
);
3224 if(!change
.args
[0].u
.member
)
3227 reply("MSG_CHANNEL_ABSENT", channel
->name
);
3231 uData
= GetChannelAccess(channel
->channel_info
, user
->handle_info
);
3235 reply("CSMSG_GODMODE_UP", argv
[0]);
3238 else if(uData
->access
>= UL_OP
)
3240 change
.args
[0].mode
= MODE_CHANOP
;
3241 errmsg
= "CSMSG_ALREADY_OPPED";
3243 else if(uData
->access
>= UL_HALFOP
)
3245 change
.args
[0].mode
= MODE_HALFOP
;
3246 errmsg
= "CSMSG_ALREADY_HALFOPPED";
3248 else if(uData
->access
>= UL_PEON
&& (channel
->channel_info
->chOpts
[chAutomode
] != 'm' ))
3250 change
.args
[0].mode
= MODE_VOICE
;
3251 errmsg
= "CSMSG_ALREADY_VOICED";
3256 reply("CSMSG_NO_ACCESS");
3259 change
.args
[0].mode
&= ~change
.args
[0].u
.member
->modes
;
3260 if(!change
.args
[0].mode
)
3263 reply(errmsg
, channel
->name
);
3266 modcmd_chanmode_announce(&change
);
3270 static CHANSERV_FUNC(cmd_down
)
3272 struct mod_chanmode change
;
3274 mod_chanmode_init(&change
);
3276 change
.args
[0].u
.member
= GetUserMode(channel
, user
);
3277 if(!change
.args
[0].u
.member
)
3280 reply("MSG_CHANNEL_ABSENT", channel
->name
);
3284 if(!change
.args
[0].u
.member
->modes
)
3287 reply("CSMSG_ALREADY_DOWN", channel
->name
);
3291 change
.args
[0].mode
= MODE_REMOVE
| change
.args
[0].u
.member
->modes
;
3292 modcmd_chanmode_announce(&change
);
3296 static int cmd_all(struct userNode
*user
, UNUSED_ARG(struct chanNode
*channel
), UNUSED_ARG(unsigned int argc
), UNUSED_ARG(char *argv
[]), struct svccmd
*cmd
, modcmd_func_t mcmd
)
3298 struct userData
*cList
;
3300 for(cList
= user
->handle_info
->channels
; cList
; cList
= cList
->u_next
)
3302 if(IsSuspended(cList
->channel
)
3303 || IsUserSuspended(cList
)
3304 || !GetUserMode(cList
->channel
->channel
, user
))
3307 mcmd(user
, cList
->channel
->channel
, 0, NULL
, cmd
);
3313 static CHANSERV_FUNC(cmd_upall
)
3315 return cmd_all(CSFUNC_ARGS
, cmd_up
);
3318 static CHANSERV_FUNC(cmd_downall
)
3320 return cmd_all(CSFUNC_ARGS
, cmd_down
);
3323 typedef int validate_func_t(struct svccmd
*cmd
, struct userNode
*user
, struct chanNode
*channel
, struct userNode
*victim
);
3324 typedef void process_func_t(unsigned int num
, struct userNode
**newops
, struct chanNode
*channel
, struct userNode
*who
, int announce
);
3327 modify_users(struct userNode
*user
, struct chanNode
*channel
, unsigned int argc
, char *argv
[], struct svccmd
*cmd
, validate_func_t validate
, chan_mode_t mode
, char *action
)
3329 unsigned int ii
, valid
;
3330 struct userNode
*victim
;
3331 struct mod_chanmode
*change
;
3333 change
= mod_chanmode_alloc(argc
- 1);
3335 for(ii
=valid
=0; ++ii
< argc
; )
3337 if(!(victim
= GetUserH(argv
[ii
])))
3339 change
->args
[valid
].mode
= mode
;
3340 change
->args
[valid
].u
.member
= GetUserMode(channel
, victim
);
3341 if(!change
->args
[valid
].u
.member
)
3343 if(validate
&& !validate(cmd
, user
, channel
, victim
))
3348 change
->argc
= valid
;
3349 if(valid
< (argc
-1))
3350 reply("CSMSG_PROCESS_FAILED");
3353 modcmd_chanmode_announce(change
);
3354 reply(action
, channel
->name
);
3356 mod_chanmode_free(change
);
3360 static CHANSERV_FUNC(cmd_op
)
3362 return modify_users(CSFUNC_ARGS
, validate_op
, MODE_CHANOP
, "CSMSG_OPPED_USERS");
3365 static CHANSERV_FUNC(cmd_hop
)
3367 return modify_users(CSFUNC_ARGS
, validate_halfop
, MODE_HALFOP
, "CSMSG_HALFOPPED_USERS");
3370 static CHANSERV_FUNC(cmd_deop
)
3372 return modify_users(CSFUNC_ARGS
, validate_deop
, MODE_REMOVE
|MODE_CHANOP
, "CSMSG_DEOPPED_USERS");
3375 static CHANSERV_FUNC(cmd_dehop
)
3377 return modify_users(CSFUNC_ARGS
, validate_dehop
, MODE_REMOVE
|MODE_HALFOP
, "CSMSG_DEHALFOPPED_USERS");
3380 static CHANSERV_FUNC(cmd_voice
)
3382 return modify_users(CSFUNC_ARGS
, NULL
, MODE_VOICE
, "CSMSG_VOICED_USERS");
3385 static CHANSERV_FUNC(cmd_devoice
)
3387 return modify_users(CSFUNC_ARGS
, NULL
, MODE_REMOVE
|MODE_VOICE
, "CSMSG_DEVOICED_USERS");
3391 bad_channel_ban(struct chanNode
*channel
, struct userNode
*user
, const char *ban
, unsigned int *victimCount
, struct modeNode
**victims
)
3397 for(ii
=0; ii
<channel
->members
.used
; ii
++)
3399 struct modeNode
*mn
= channel
->members
.list
[ii
];
3401 if(IsService(mn
->user
))
3404 if(!user_matches_glob(mn
->user
, ban
, MATCH_USENICK
| MATCH_VISIBLE
))
3407 if(protect_user(mn
->user
, user
, channel
->channel_info
, false))
3411 victims
[(*victimCount
)++] = mn
;
3417 eject_user(struct userNode
*user
, struct chanNode
*channel
, unsigned int argc
, char *argv
[], struct svccmd
*cmd
, int action
)
3419 struct userNode
*victim
;
3420 struct modeNode
**victims
;
3421 unsigned int offset
, n
, victimCount
, duration
= 0;
3422 char *reason
= "Bye.", *ban
, *name
;
3423 char interval
[INTERVALLEN
];
3425 offset
= (action
& ACTION_ADD_TIMED_LAMER
) ? 3 : 2;
3426 REQUIRE_PARAMS(offset
);
3429 reason
= unsplit_string(argv
+ offset
, argc
- offset
, NULL
);
3430 if(strlen(reason
) > (TOPICLEN
- (NICKLEN
+ 3)))
3432 /* Truncate the reason to a length of TOPICLEN, as
3433 the ircd does; however, leave room for an ellipsis
3434 and the kicker's nick. */
3435 sprintf(reason
+ (TOPICLEN
- (NICKLEN
+ 6)), "...");
3439 if((victim
= GetUserH(argv
[1])))
3441 victims
= alloca(sizeof(victims
[0]));
3442 victims
[0] = GetUserMode(channel
, victim
);
3443 /* XXX: The comparison with ACTION_KICK is just because all
3444 * other actions can work on users outside the channel, and we
3445 * want to allow those (e.g. unbans) in that case. If we add
3446 * some other ejection action for in-channel users, change
3448 victimCount
= victims
[0] ? 1 : 0;
3450 if(IsService(victim
))
3453 reply("MSG_SERVICE_IMMUNE", victim
->nick
);
3457 if((action
== ACTION_KICK
) && !victimCount
)
3460 reply("MSG_CHANNEL_USER_ABSENT", victim
->nick
, channel
->name
);
3464 if(protect_user(victim
, user
, channel
->channel_info
, false))
3466 // This translates to send_message(user, cmd->parent->bot, ...)
3467 // if user is x3 (ctcp action) cmd is null and segfault.
3469 reply("CSMSG_USER_PROTECTED", victim
->nick
);
3473 ban
= generate_hostmask(victim
, GENMASK_STRICT_HOST
|GENMASK_ANY_IDENT
);
3474 name
= victim
->nick
;
3478 if(!is_ircmask(argv
[1]))
3481 reply("MSG_NICK_UNKNOWN", argv
[1]);
3485 victims
= alloca(sizeof(victims
[0]) * channel
->members
.used
);
3487 if(bad_channel_ban(channel
, user
, argv
[1], &victimCount
, victims
))
3490 reply("CSMSG_MASK_PROTECTED", argv
[1]);
3493 /* If i want to ban *.nl and theres 5 of them, what is it to the bot?!?
3494 // if((victimCount > 4) && ((victimCount * 3) > channel->members.used) && !IsOper(user))
3496 We use x2 style over-mask detection instead because it doesnt stop channel owners from doing
3497 reasonable bans, but does stop *@*, *@*a* *@*b* etc type masks. Yes, you can defeat it with
3498 some creativity, but its not x3's job to be the ban censor anyway. */
3499 if(is_overmask(argv
[1]))
3502 reply("CSMSG_LAME_MASK", argv
[1]);
3506 if((action
== ACTION_KICK
) && (victimCount
== 0))
3509 reply("CSMSG_NO_MATCHING_USERS", channel
->name
, argv
[1]);
3513 name
= ban
= strdup(argv
[1]);
3516 /* Truncate the ban in place if necessary; we must ensure
3517 that 'ban' is a valid ban mask before sanitizing it. */
3518 sanitize_ircmask(ban
);
3520 if(action
& ACTION_ADD_LAMER
)
3522 struct banData
*bData
, *next
;
3524 if(channel
->channel_info
->banCount
>= chanserv_conf
.max_chan_bans
) /* ..lamers.. */
3527 reply("CSMSG_MAXIMUM_LAMERS", chanserv_conf
.max_chan_bans
); /* ..lamers.. */
3532 if(action
& ACTION_ADD_TIMED_LAMER
)
3534 duration
= ParseInterval(argv
[2]);
3539 reply("CSMSG_DURATION_TOO_LOW");
3543 else if(duration
> (86400 * 365 * 2))
3546 reply("CSMSG_DURATION_TOO_HIGH");
3553 for(bData
= channel
->channel_info
->bans
; bData
; bData
= next
)
3555 if(match_ircglobs(bData
->mask
, ban
))
3557 int exact
= !irccasecmp(bData
->mask
, ban
);
3559 /* The ban is redundant; there is already a ban
3560 with the same effect in place. */
3564 free(bData
->reason
);
3565 bData
->reason
= strdup(reason
);
3566 safestrncpy(bData
->owner
, (user
->handle_info
? user
->handle_info
->handle
: user
->nick
), sizeof(bData
->owner
));
3568 reply("CSMSG_REASON_CHANGE", ban
);
3572 if(exact
&& bData
->expires
)
3576 /* If the ban matches an existing one exactly,
3577 extend the expiration time if the provided
3578 duration is longer. */
3579 if(duration
&& ((time_t)(now
+ duration
) > bData
->expires
))
3581 bData
->expires
= now
+ duration
;
3592 /* Delete the expiration timeq entry and
3593 requeue if necessary. */
3594 timeq_del(0, expire_ban
, bData
, TIMEQ_IGNORE_WHEN
);
3597 timeq_add(bData
->expires
, expire_ban
, bData
);
3601 /* automated kickban, dont reply */
3604 reply("CSMSG_LAMER_EXTENDED", ban
, intervalString(interval
, duration
, user
->handle_info
));
3606 reply("CSMSG_LAMER_ADDED", name
, channel
->name
);
3612 reply("CSMSG_REDUNDANT_LAMER", name
, channel
->name
);
3619 if(match_ircglobs(ban
, bData
->mask
))
3621 /* The ban we are adding makes previously existing
3622 bans redundant; silently remove them. */
3623 del_channel_ban(bData
);
3627 bData
= add_channel_ban(channel
->channel_info
, ban
, (user
->handle_info
? user
->handle_info
->handle
: user
->nick
), now
, (victimCount
? now
: 0), (duration
? now
+ duration
: 0), reason
);
3629 name
= ban
= strdup(bData
->mask
);
3633 /* WHAT DOES THIS DO?? -Rubin */
3634 for(n
= 0; n
< chanserv_conf
.old_ban_names
->used
; ++n
)
3636 extern const char *hidden_host_suffix
;
3637 const char *old_name
= chanserv_conf
.old_ban_names
->list
[n
];
3639 unsigned int l1
, l2
;
3642 l2
= strlen(old_name
);
3645 if(irccasecmp(ban
+ l1
- l2
, old_name
))
3647 new_mask
= malloc(MAXLEN
);
3648 sprintf(new_mask
, "%.*s%s", (int)(l1
-l2
), ban
, hidden_host_suffix
);
3650 name
= ban
= new_mask
;
3655 if(action
& ACTION_BAN
)
3657 unsigned int exists
;
3658 struct mod_chanmode
*change
;
3660 if(channel
->banlist
.used
>= MAXBANS
)
3663 reply("CSMSG_BANLIST_FULL", channel
->name
);
3668 exists
= ChannelBanExists(channel
, ban
);
3669 change
= mod_chanmode_alloc(victimCount
+ 1);
3670 for(n
= 0; n
< victimCount
; ++n
)
3672 change
->args
[n
].mode
= MODE_REMOVE
|MODE_CHANOP
|MODE_HALFOP
|MODE_VOICE
;
3673 change
->args
[n
].u
.member
= victims
[n
];
3677 change
->args
[n
].mode
= MODE_BAN
;
3678 change
->args
[n
++].u
.hostmask
= ban
;
3682 modcmd_chanmode_announce(change
);
3684 mod_chanmode_announce(chanserv
, channel
, change
);
3685 mod_chanmode_free(change
);
3687 if(exists
&& (action
== ACTION_BAN
))
3690 reply("CSMSG_REDUNDANT_BAN", name
, channel
->name
);
3696 if(action
& ACTION_ADD_LAMER
)
3698 char kick_reason
[MAXLEN
];
3699 sprintf(kick_reason
, "(%s) %s", user
->nick
, reason
);
3701 for(n
= 0; n
< victimCount
; n
++) {
3702 if(!protect_user(victims
[n
]->user
, user
, channel
->channel_info
, true)) {
3703 KickChannelUser(victims
[n
]->user
, channel
, chanserv
, kick_reason
);
3707 else if(action
& ACTION_KICK
)
3709 char kick_reason
[MAXLEN
];
3710 sprintf(kick_reason
, "(%s) %s", user
->nick
, reason
);
3712 for(n
= 0; n
< victimCount
; n
++) {
3713 KickChannelUser(victims
[n
]->user
, channel
, chanserv
, kick_reason
);
3719 /* No response, since it was automated. */
3721 else if(action
& ACTION_ADD_LAMER
)
3724 reply("CSMSG_TIMED_LAMER_ADDED", name
, channel
->name
, intervalString(interval
, duration
, user
->handle_info
));
3726 reply("CSMSG_LAMER_ADDED", name
, channel
->name
);
3728 else if((action
& (ACTION_BAN
| ACTION_KICK
)) == (ACTION_BAN
| ACTION_KICK
))
3729 reply("CSMSG_KICK_BAN_DONE", name
, channel
->name
);
3730 else if(action
& ACTION_BAN
)
3731 reply("CSMSG_BAN_DONE", name
, channel
->name
);
3732 else if(action
& ACTION_KICK
&& victimCount
)
3733 reply("CSMSG_KICK_DONE", name
, channel
->name
);
3739 static CHANSERV_FUNC(cmd_kickban
)
3741 return eject_user(CSFUNC_ARGS
, ACTION_KICK
| ACTION_BAN
);
3744 static CHANSERV_FUNC(cmd_kick
)
3746 return eject_user(CSFUNC_ARGS
, ACTION_KICK
);
3749 static CHANSERV_FUNC(cmd_ban
)
3751 return eject_user(CSFUNC_ARGS
, ACTION_BAN
);
3754 static CHANSERV_FUNC(cmd_addlamer
)
3756 return eject_user(CSFUNC_ARGS
, ACTION_KICK
| ACTION_BAN
| ACTION_ADD_LAMER
);
3759 static CHANSERV_FUNC(cmd_addtimedlamer
)
3761 return eject_user(CSFUNC_ARGS
, ACTION_KICK
| ACTION_BAN
| ACTION_ADD_LAMER
| ACTION_ADD_TIMED_LAMER
);
3764 static struct mod_chanmode
*
3765 find_matching_bans(struct banList
*bans
, struct userNode
*actee
, const char *mask
)
3767 struct mod_chanmode
*change
;
3768 unsigned char *match
;
3769 unsigned int ii
, count
;
3771 match
= alloca(bans
->used
);
3774 for(ii
= count
= 0; ii
< bans
->used
; ++ii
)
3776 match
[ii
] = user_matches_glob(actee
, bans
->list
[ii
]->ban
,
3777 MATCH_USENICK
| MATCH_VISIBLE
);
3784 for(ii
= count
= 0; ii
< bans
->used
; ++ii
)
3786 match
[ii
] = match_ircglobs(mask
, bans
->list
[ii
]->ban
);
3793 change
= mod_chanmode_alloc(count
);
3794 for(ii
= count
= 0; ii
< bans
->used
; ++ii
)
3798 change
->args
[count
].mode
= MODE_REMOVE
| MODE_BAN
;
3799 change
->args
[count
++].u
.hostmask
= strdup(bans
->list
[ii
]->ban
);
3801 assert(count
== change
->argc
);
3805 void expire_bans(UNUSED_ARG(void* data
)) /* Real bans, not lamers */
3807 unsigned int jj
, ii
, count
;
3809 struct chanData
*channel
;
3811 struct mod_chanmode
*change
;
3813 log_module(CS_LOG
, LOG_DEBUG
, "Checking for expired bans");
3814 /* Walk through every channel */
3815 for(channel
= channelList
; channel
; channel
= channel
->next
) {
3816 switch(channel
->chOpts
[chBanTimeout
])
3818 default: case '0': continue; /* Dont remove bans in this chan */
3819 case '1': bantimeout
= now
- (10 * 60); break; /* 10 minutes */
3820 case '2': bantimeout
= now
- (2 * 60 * 60); break; /* 2 hours */
3821 case '3': bantimeout
= now
- (4 * 60 * 60); break; /* 4 hours */
3822 case '4': bantimeout
= now
- (24 * 60 * 60); break; /* 24 hours */
3823 case '5': bantimeout
= now
- (7 * 24 * 60 * 60); break; /* 1 week */
3826 /* First find out how many bans were going to unset */
3827 for (jj
=0; jj
< channel
->channel
->banlist
.used
; ++jj
) {
3828 if(channel
->channel
->banlist
.list
[jj
]->set
< bantimeout
)
3832 /* At least one ban, so setup a removal */
3833 change
= mod_chanmode_alloc(count
);
3835 /* Walk over every ban in this channel.. */
3836 for (jj
=0; jj
< channel
->channel
->banlist
.used
; ++jj
) {
3837 bn
= channel
->channel
->banlist
.list
[jj
];
3838 if (bn
->set
< bantimeout
) {
3839 log_module(CS_LOG
, LOG_DEBUG
, "Removing ban %s from %s", bn
->ban
, channel
->channel
->name
);
3841 /* Add this ban to the mode change */
3842 change
->args
[ii
].mode
= MODE_REMOVE
| MODE_BAN
;
3843 change
->args
[ii
].u
.hostmask
= strdup(bn
->ban
);
3845 /* Pull this ban out of the list */
3846 banList_remove(&(channel
->channel
->banlist
), bn
);
3851 /* Send the modes to IRC */
3852 mod_chanmode_announce(chanserv
, channel
->channel
, change
);
3854 /* free memory from strdup above */
3855 for(ii
= 0; ii
< count
; ++ii
)
3856 free((char*)change
->args
[ii
].u
.hostmask
);
3858 mod_chanmode_free(change
);
3861 /* Set this function to run again */
3862 if(chanserv_conf
.ban_timeout_frequency
)
3863 timeq_add(now
+ chanserv_conf
.ban_timeout_frequency
, expire_bans
, NULL
);
3868 unban_user(struct userNode
*user
, struct chanNode
*channel
, unsigned int argc
, char *argv
[], struct svccmd
*cmd
, int action
)
3870 struct userNode
*actee
;
3876 /* may want to allow a comma delimited list of users... */
3877 if(!(actee
= GetUserH(argv
[1])))
3879 if(!is_ircmask(argv
[1]))
3881 reply("MSG_NICK_UNKNOWN", argv
[1]);
3885 mask
= strdup(argv
[1]);
3888 /* We don't sanitize the mask here because ircu
3890 if(action
& ACTION_UNBAN
)
3892 struct mod_chanmode
*change
;
3893 change
= find_matching_bans(&channel
->banlist
, actee
, mask
);
3898 modcmd_chanmode_announce(change
);
3899 for(ii
= 0; ii
< change
->argc
; ++ii
)
3900 free((char*)change
->args
[ii
].u
.hostmask
);
3901 mod_chanmode_free(change
);
3906 if(action
& ACTION_DEL_LAMER
)
3908 struct banData
*ban
, *next
;
3910 ban
= channel
->channel_info
->bans
; /* lamers */
3914 for( ; ban
&& !user_matches_glob(actee
, ban
->mask
, MATCH_USENICK
| MATCH_VISIBLE
);
3917 for( ; ban
&& !match_ircglobs(mask
, ban
->mask
);
3922 del_channel_ban(ban
);
3929 reply("CSMSG_BAN_NOT_FOUND", actee
? actee
->nick
: mask
);
3931 reply("CSMSG_BAN_REMOVED", actee
? actee
->nick
: mask
);
3937 static CHANSERV_FUNC(cmd_unban
)
3939 return unban_user(CSFUNC_ARGS
, ACTION_UNBAN
);
3942 static CHANSERV_FUNC(cmd_dellamer
)
3944 /* it doesn't necessarily have to remove the channel ban - may want
3945 to make that an option. */
3946 return unban_user(CSFUNC_ARGS
, ACTION_UNBAN
| ACTION_DEL_LAMER
);
3949 static CHANSERV_FUNC(cmd_unbanme
)
3951 struct userData
*uData
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
3952 long flags
= ACTION_UNBAN
;
3954 /* remove permanent bans if the user has the proper access. */
3955 if(uData
->access
>= UL_MANAGER
)
3956 flags
|= ACTION_DEL_LAMER
;
3958 argv
[1] = user
->nick
;
3959 return unban_user(user
, channel
, 2, argv
, cmd
, flags
);
3962 static CHANSERV_FUNC(cmd_unbanall
)
3964 struct mod_chanmode
*change
;
3967 if(!channel
->banlist
.used
)
3969 reply("CSMSG_NO_BANS", channel
->name
);
3973 change
= mod_chanmode_alloc(channel
->banlist
.used
);
3974 for(ii
=0; ii
<channel
->banlist
.used
; ii
++)
3976 change
->args
[ii
].mode
= MODE_REMOVE
| MODE_BAN
;
3977 change
->args
[ii
].u
.hostmask
= strdup(channel
->banlist
.list
[ii
]->ban
);
3979 modcmd_chanmode_announce(change
);
3980 for(ii
= 0; ii
< change
->argc
; ++ii
)
3981 free((char*)change
->args
[ii
].u
.hostmask
);
3982 mod_chanmode_free(change
);
3983 reply("CSMSG_BANS_REMOVED", channel
->name
);
3987 static CHANSERV_FUNC(cmd_open
)
3989 struct mod_chanmode
*change
;
3992 change
= find_matching_bans(&channel
->banlist
, user
, NULL
);
3994 change
= mod_chanmode_alloc(0);
3995 change
->modes_clear
|= MODE_INVITEONLY
| MODE_LIMIT
| MODE_KEY
;
3996 if(!check_user_level(channel
, user
, lvlEnfModes
, 1, 0)
3997 && channel
->channel_info
->modes
.modes_set
)
3998 change
->modes_clear
&= ~channel
->channel_info
->modes
.modes_set
;
3999 modcmd_chanmode_announce(change
);
4000 reply("CSMSG_CHANNEL_OPENED", channel
->name
);
4001 for(ii
= 0; ii
< change
->argc
; ++ii
)
4002 free((char*)change
->args
[ii
].u
.hostmask
);
4003 mod_chanmode_free(change
);
4007 static CHANSERV_FUNC(cmd_myaccess
)
4009 static struct string_buffer sbuf
;
4010 struct handle_info
*target_handle
;
4011 struct userData
*uData
;
4014 target_handle
= user
->handle_info
;
4015 else if(!(target_handle
= modcmd_get_handle_info(user
, argv
[1])))
4017 else if(!IsHelping(user
) && target_handle
!= user
->handle_info
)
4019 reply("CSMSG_MYACCESS_SELF_ONLY", argv
[0]);
4022 if(!target_handle
->channels
)
4024 reply("CSMSG_SQUAT_ACCESS", target_handle
->handle
);
4028 reply("CSMSG_INFOLINE_LIST", target_handle
->handle
);
4029 for(uData
= target_handle
->channels
; uData
; uData
= uData
->u_next
)
4031 struct chanData
*cData
= uData
->channel
;
4033 if(uData
->access
> UL_OWNER
)
4035 if(IsProtected(cData
)
4036 && (target_handle
!= user
->handle_info
)
4037 && !GetTrueChannelAccess(cData
, user
->handle_info
))
4040 string_buffer_append_printf(&sbuf
, "[%s (%d", cData
->channel
->name
, uData
->access
);
4041 if(uData
->flags
== USER_AUTO_OP
)
4042 string_buffer_append(&sbuf
, ',');
4043 if(IsUserSuspended(uData
))
4044 string_buffer_append(&sbuf
, 's');
4045 if(IsUserAutoOp(uData
))
4047 if(uData
->access
>= UL_OP
)
4048 string_buffer_append(&sbuf
, 'o');
4049 else if(uData
->access
>= UL_HALFOP
)
4050 string_buffer_append(&sbuf
, 'h');
4051 else if(uData
->access
>= UL_PEON
)
4052 string_buffer_append(&sbuf
, 'v');
4054 if(IsUserAutoInvite(uData
) && (uData
->access
>= cData
->lvlOpts
[lvlInviteMe
]))
4055 string_buffer_append(&sbuf
, 'i');
4056 if(IsUserAutoJoin(uData
) && (uData
->access
>= cData
->lvlOpts
[lvlInviteMe
]))
4057 string_buffer_append(&sbuf
, 'j');
4059 string_buffer_append_printf(&sbuf
, ")] %s", uData
->info
);
4061 string_buffer_append_string(&sbuf
, ")]");
4062 string_buffer_append(&sbuf
, '\0');
4063 send_message_type(4, user
, cmd
->parent
->bot
, "%s", sbuf
.list
);
4069 static CHANSERV_FUNC(cmd_access
)
4071 struct userNode
*target
;
4072 struct handle_info
*target_handle
;
4073 struct userData
*uData
;
4075 char prefix
[MAXLEN
];
4080 target_handle
= target
->handle_info
;
4082 else if((target
= GetUserH(argv
[1])))
4084 target_handle
= target
->handle_info
;
4086 else if(argv
[1][0] == '*')
4088 if(!(target_handle
= get_handle_info(argv
[1]+1)))
4090 reply("MSG_HANDLE_UNKNOWN", argv
[1]+1);
4096 reply("MSG_NICK_UNKNOWN", argv
[1]);
4100 assert(target
|| target_handle
);
4102 if(target
== chanserv
)
4104 reply("CSMSG_IS_CHANSERV");
4112 reply("CSMSG_LAZY_SMURF_TARGET", target
->nick
, chanserv_conf
.irc_operator_epithet
);
4117 reply("MSG_USER_AUTHENTICATE", target
->nick
);
4120 reply("MSG_AUTHENTICATE");
4126 const char *epithet
= NULL
, *type
= NULL
;
4129 epithet
= chanserv_conf
.irc_operator_epithet
;
4132 else if(IsNetworkHelper(target
))
4134 epithet
= chanserv_conf
.network_helper_epithet
;
4135 type
= "network helper";
4137 else if(IsSupportHelper(target
))
4139 epithet
= chanserv_conf
.support_helper_epithet
;
4140 type
= "support helper";
4144 if(target_handle
->epithet
)
4145 reply("CSMSG_SMURF_TARGET", target
->nick
, target_handle
->epithet
, type
);
4147 reply("CSMSG_SMURF_TARGET", target
->nick
, epithet
, type
);
4149 sprintf(prefix
, "%s (%s)", target
->nick
, target_handle
->handle
);
4153 sprintf(prefix
, "%s", target_handle
->handle
);
4156 if(!channel
->channel_info
)
4158 reply("CSMSG_NOT_REGISTERED", channel
->name
);
4162 helping
= HANDLE_FLAGGED(target_handle
, HELPING
)
4163 && ((target_handle
->opserv_level
>= chanserv_conf
.nodelete_level
) || !IsProtected(channel
->channel_info
));
4164 if((uData
= GetTrueChannelAccess(channel
->channel_info
, target_handle
)))
4166 reply((helping
? "CSMSG_HELPER_HAS_ACCESS" : "CSMSG_USER_HAS_ACCESS"), prefix
, user_level_name_from_level(uData
->access
), uData
->access
, channel
->name
);
4167 /* To prevent possible information leaks, only show infolines
4168 * if the requestor is in the channel or it's their own
4170 if(uData
->info
&& (GetUserMode(channel
, user
) || (target_handle
== user
->handle_info
)))
4172 send_message_type(4, user
, cmd
->parent
->bot
, "[%s] %s", (target
? target
->nick
: target_handle
->handle
), uData
->info
);
4174 /* Likewise, only say it's suspended if the user has active
4175 * access in that channel or it's their own entry. */
4176 if(IsUserSuspended(uData
)
4177 && (GetChannelUser(channel
->channel_info
, user
->handle_info
)
4178 || (user
->handle_info
== uData
->handle
)))
4180 reply("CSMSG_USER_SUSPENDED", (target
? target
->nick
: target_handle
->handle
), channel
->name
);
4185 reply((helping
? "CSMSG_HELPER_NO_ACCESS" : "CSMSG_USER_NO_ACCESS"), prefix
, channel
->name
);
4191 /* This is never used...
4193 zoot_list(struct listData *list)
4195 struct userData *uData;
4196 unsigned int start, curr, highest, lowest;
4197 struct helpfile_table tmp_table;
4198 const char **temp, *msg;
4200 if(list->table.length == 1)
4203 send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER", list->channel->name, user_level_name_from_level(list->lowest), user_level_name_from_level(list->highest), list->search);
4205 send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER", list->channel->name, user_level_name_from_level(list->lowest), user_level_name_from_level(list->highest));
4206 msg = user_find_message(list->user, "MSG_NONE");
4207 send_message_type(4, list->user, list->bot, " %s", msg);
4209 tmp_table.width = list->table.width;
4210 tmp_table.flags = list->table.flags;
4211 list->table.contents[0][0] = " ";
4212 highest = list->highest;
4213 if(list->lowest != 0)
4214 lowest = list->lowest;
4215 else if(highest < 100)
4218 lowest = highest - 100;
4219 for(start = curr = 1; curr < list->table.length; )
4221 uData = list->users[curr-1];
4222 list->table.contents[curr++][0] = " ";
4223 if((curr == list->table.length) || (list->users[curr-1]->access < lowest))
4226 send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER", list->channel->name, user_level_name_from_level(lowest), user_level_name_from_level(highest), list->search);
4228 send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER", list->channel->name, user_level_name_from_level(lowest), user_level_name_from_level(highest));
4229 temp = list->table.contents[--start];
4230 list->table.contents[start] = list->table.contents[0];
4231 tmp_table.contents = list->table.contents + start;
4232 tmp_table.length = curr - start;
4233 table_send(list->bot, list->user->nick, 0, NULL, tmp_table);
4234 list->table.contents[start] = temp;
4236 highest = lowest - 1;
4237 lowest = (highest < 100) ? 0 : (highest - 99);
4244 normal_list(struct listData
*list
)
4248 send_message(list
->user
, list
->bot
, "CSMSG_ACCESS_SEARCH_HEADER_NORMAL", list
->channel
->name
, user_level_name_from_level(list
->lowest
), user_level_name_from_level(list
->highest
), list
->search
);
4250 send_message(list
->user
, list
->bot
, "CSMSG_ACCESS_ALL_HEADER_NORMAL", list
->channel
->name
, user_level_name_from_level(list
->lowest
), user_level_name_from_level(list
->highest
));
4251 if(list
->table
.length
== 1)
4253 msg
= user_find_message(list
->user
, "MSG_NONE");
4254 send_message_type(4, list
->user
, list
->bot
, " %s", msg
);
4257 table_send(list
->bot
, list
->user
->nick
, 0, NULL
, list
->table
);
4260 /* if these need changed, uncomment and customize
4262 clean_list(struct listData *list)
4266 send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER_CLEAN", list->channel->name, user_level_name_from_level(list->lowest), user_level_name_from_level(list->highest), list->search);
4268 send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER_CLEAN", list->channel->name, user_level_name_from_level(list->lowest), user_level_name_from_level(list->highest));
4269 if(list->table.length == 1)
4271 msg = user_find_message(list->user, "MSG_NONE");
4272 send_message_type(4, list->user, list->bot, " %s", msg);
4275 table_send(list->bot, list->user->nick, 0, NULL, list->table);
4279 advanced_list(struct listData *list)
4283 send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER_ADVANCED", list->channel->name, user_level_name_from_level(list->lowest), user_level_name_from_level(list->highest), list->search);
4285 send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER_ADVANCED", list->channel->name, user_level_name_from_level(list->lowest), user_level_name_from_level(list->highest));
4286 if(list->table.length == 1)
4288 msg = user_find_message(list->user, "MSG_NONE");
4289 send_message_type(4, list->user, list->bot, " %s", msg);
4292 table_send(list->bot, list->user->nick, 0, NULL, list->table);
4296 classic_list(struct listData *list)
4300 send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER_CLASSIC", list->channel->name, list->lowest, list->highest, list->search);
4302 send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER_CLASSIC", list->channel->name, list->lowest, list->highest);
4303 if(list->table.length == 1)
4305 msg = user_find_message(list->user, "MSG_NONE");
4306 send_message_type(4, list->user, list->bot, " %s", msg);
4309 table_send(list->bot, list->user->nick, 0, NULL, list->table);
4314 userData_access_comp(const void *arg_a
, const void *arg_b
)
4316 const struct userData
*a
= *(struct userData
**)arg_a
;
4317 const struct userData
*b
= *(struct userData
**)arg_b
;
4319 if(a
->access
!= b
->access
)
4320 res
= b
->access
- a
->access
;
4322 res
= irccasecmp(a
->handle
->handle
, b
->handle
->handle
);
4327 cmd_list_users(struct userNode
*user
, struct chanNode
*channel
, unsigned int argc
, char *argv
[], struct svccmd
*cmd
, unsigned short lowest
, unsigned short highest
)
4329 void (*send_list
)(struct listData
*);
4330 struct userData
*uData
;
4331 struct listData lData
;
4332 unsigned int matches
;
4338 lData
.bot
= cmd
->parent
->bot
;
4339 lData
.channel
= channel
;
4340 lData
.lowest
= lowest
;
4341 lData
.highest
= highest
;
4342 lData
.search
= (argc
> 1) ? argv
[1] : NULL
;
4343 send_list
= normal_list
;
4344 /* What does the following line do exactly?? */
4345 /*(void)zoot_list; ** since it doesn't show user levels */
4348 if(user->handle_info)
4350 switch(user->handle_info->userlist_style)
4352 case HI_STYLE_CLEAN:
4353 send_list = clean_list;
4355 case HI_STYLE_ADVANCED:
4356 send_list = advanced_list;
4358 case HI_STYLE_CLASSIC:
4359 send_list = classic_list;
4361 case HI_STYLE_NORMAL:
4363 send_list = normal_list;
4368 send_list
= normal_list
;
4370 lData
.users
= alloca(channel
->channel_info
->userCount
* sizeof(struct userData
*));
4372 for(uData
= channel
->channel_info
->users
; uData
; uData
= uData
->next
)
4374 if((uData
->access
< lowest
)
4375 || (uData
->access
> highest
)
4376 || (lData
.search
&& !match_ircglob(uData
->handle
->handle
, lData
.search
)))
4378 lData
.users
[matches
++] = uData
;
4380 qsort(lData
.users
, matches
, sizeof(lData
.users
[0]), userData_access_comp
);
4382 lData
.table
.length
= matches
+1;
4383 lData
.table
.flags
= TABLE_NO_FREE
;
4384 lData
.table
.contents
= malloc(lData
.table
.length
*sizeof(*lData
.table
.contents
));
4386 if(user
->handle_info
&& user
->handle_info
->userlist_style
== HI_STYLE_ADVANCED
)
4387 lData
.table
.width
= 6; /* with level = 6 */
4389 lData
.table
.width
= 5; /* without = 5 */
4390 ary
= malloc(lData
.table
.width
*sizeof(**lData
.table
.contents
));
4391 lData
.table
.contents
[0] = ary
;
4392 if(user
->handle_info
) {
4393 switch(user
->handle_info
->userlist_style
) {
4394 case HI_STYLE_CLASSIC
:
4397 case HI_STYLE_ADVANCED
:
4398 ary
[i
++] = "Access";
4401 case HI_STYLE_CLEAN
:
4402 ary
[i
++] = "Access";
4404 case HI_STYLE_NORMAL
:
4406 ary
[i
++] = "Access";
4411 ary
[i
++] = "Access";
4413 ary
[i
++] = "Account";
4414 ary
[i
] = "Last Seen";
4416 ary
[i
++] = "Status";
4417 ary
[i
++] = "Expiry";
4418 for(matches
= 1; matches
< lData
.table
.length
; ++matches
)
4420 struct userData
*uData
= lData
.users
[matches
-1];
4421 char seen
[INTERVALLEN
];
4424 ary
= malloc(lData
.table
.width
*sizeof(**lData
.table
.contents
));
4425 lData
.table
.contents
[matches
] = ary
;
4426 if(user
->handle_info
) {
4427 switch(user
->handle_info
->userlist_style
) {
4428 case HI_STYLE_CLASSIC
:
4429 ary
[i
++] = strtab(uData
->access
);
4431 case HI_STYLE_ADVANCED
:
4432 ary
[i
++] = user_level_name_from_level(uData
->access
);
4433 ary
[i
++] = strtab(uData
->access
);
4435 case HI_STYLE_CLEAN
:
4436 ary
[i
++] = user_level_name_from_level(uData
->access
);
4438 case HI_STYLE_NORMAL
:
4440 ary
[i
++] = user_level_name_from_level(uData
->access
);
4445 ary
[i
++] = user_level_name_from_level(uData
->access
);
4447 ary
[i
++] = uData
->handle
->handle
;
4450 else if(!uData
->seen
)
4453 ary
[i
] = intervalString(seen
, now
- uData
->seen
, user
->handle_info
);
4454 ary
[i
] = strdup(ary
[i
]);
4456 if(IsUserSuspended(uData
))
4457 ary
[i
++] = "Suspended";
4458 else if(HANDLE_FLAGGED(uData
->handle
, FROZEN
))
4459 ary
[i
++] = "Vacation";
4461 ary
[i
++] = "Normal";
4463 if ((uData
->accessexpiry
> 0) || (uData
->clvlexpiry
> 0)) {
4464 char delay
[INTERVALLEN
];
4467 if (uData
->accessexpiry
> 0) {
4468 diff
= uData
->accessexpiry
- now
;
4469 intervalString(delay
, diff
, user
->handle_info
);
4471 diff
= uData
->clvlexpiry
- now
;
4472 intervalString(delay
, diff
, user
->handle_info
);
4480 for(matches
= 1; matches
< lData
.table
.length
; ++matches
)
4482 /* Free strdup above */
4483 free((char*)lData
.table
.contents
[matches
][seen_index
]);
4484 free(lData
.table
.contents
[matches
]);
4486 free(lData
.table
.contents
[0]);
4487 free(lData
.table
.contents
);
4491 /* Remove this now that debugging is over? or improve it for
4492 * users? Would it be better tied into USERS somehow? -Rubin */
4493 static CHANSERV_FUNC(cmd_pending
)
4495 struct adduserPending
*ap
;
4496 reply("CSMSG_ADDUSER_PENDING_HEADER");
4497 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
4499 for(ap
= adduser_pendings
;ap
;ap
= ap
->next
)
4500 reply("CSMSG_ADDUSER_PENDING_LIST", ap
->channel
->name
, ap
->user
->nick
);
4501 reply("CSMSG_ADDUSER_PENDING_FOOTER");
4505 static CHANSERV_FUNC(cmd_users
)
4507 return cmd_list_users(CSFUNC_ARGS
, 1, UL_OWNER
);
4510 static CHANSERV_FUNC(cmd_wlist
)
4512 return cmd_list_users(CSFUNC_ARGS
, UL_OWNER
, UL_OWNER
);
4515 static CHANSERV_FUNC(cmd_clist
)
4517 return cmd_list_users(CSFUNC_ARGS
, UL_COOWNER
, UL_OWNER
-1);
4520 static CHANSERV_FUNC(cmd_mlist
)
4522 return cmd_list_users(CSFUNC_ARGS
, UL_MANAGER
, UL_COOWNER
-1);
4525 static CHANSERV_FUNC(cmd_olist
)
4527 return cmd_list_users(CSFUNC_ARGS
, UL_OP
, UL_MANAGER
-1);
4530 static CHANSERV_FUNC(cmd_hlist
)
4532 return cmd_list_users(CSFUNC_ARGS
, UL_HALFOP
, UL_OP
-1);
4535 static CHANSERV_FUNC(cmd_plist
)
4537 return cmd_list_users(CSFUNC_ARGS
, 1, UL_HALFOP
-1);
4540 static CHANSERV_FUNC(cmd_lamers
)
4542 struct helpfile_table tbl
;
4543 unsigned int matches
= 0, timed
= 0, ii
;
4544 char t_buffer
[INTERVALLEN
], e_buffer
[INTERVALLEN
], *search
;
4545 const char *msg_never
, *triggered
, *expires
;
4546 struct banData
*ban
, **bans
; /* lamers */
4553 reply("CSMSG_LAMERS_HEADER", channel
->name
);
4554 bans
= alloca(channel
->channel_info
->banCount
* sizeof(struct banData
*)); /* lamers */
4557 for(ban
= channel
->channel_info
->bans
; ban
; ban
= ban
->next
)
4559 if(search
&& !match_ircglobs(search
, ban
->mask
))
4561 bans
[matches
++] = ban
;
4566 tbl
.length
= matches
+ 1;
4567 tbl
.width
= 4 + timed
;
4569 tbl
.flags
= TABLE_NO_FREE
;
4570 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4571 tbl
.contents
[0] = malloc(tbl
.width
* sizeof(tbl
.contents
[0][0]));
4572 tbl
.contents
[0][0] = "Mask";
4573 tbl
.contents
[0][1] = "Set By";
4574 tbl
.contents
[0][2] = "Triggered";
4577 tbl
.contents
[0][3] = "Expires";
4578 tbl
.contents
[0][4] = "Reason";
4581 tbl
.contents
[0][3] = "Reason";
4584 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4585 /* reply("MSG_NONE"); */
4586 free(tbl
.contents
[0]);
4591 msg_never
= user_find_message(user
, "MSG_NEVER");
4592 for(ii
= 0; ii
< matches
; )
4598 else if(ban
->expires
)
4599 expires
= intervalString(e_buffer
, ban
->expires
- now
, user
->handle_info
);
4601 expires
= msg_never
;
4604 triggered
= intervalString(t_buffer
, now
- ban
->triggered
, user
->handle_info
);
4606 triggered
= msg_never
;
4608 tbl
.contents
[++ii
] = malloc(tbl
.width
* sizeof(tbl
.contents
[0][0]));
4609 tbl
.contents
[ii
][0] = ban
->mask
;
4610 tbl
.contents
[ii
][1] = ban
->owner
;
4611 tbl
.contents
[ii
][2] = strdup(triggered
);
4614 tbl
.contents
[ii
][3] = strdup(expires
);
4615 tbl
.contents
[ii
][4] = ban
->reason
;
4618 tbl
.contents
[ii
][3] = ban
->reason
;
4620 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4621 /* reply("MSG_MATCH_COUNT", matches); */
4622 for(ii
= 1; ii
< tbl
.length
; ++ii
)
4624 free((char*)tbl
.contents
[ii
][2]);
4626 free((char*)tbl
.contents
[ii
][3]);
4627 free(tbl
.contents
[ii
]);
4629 free(tbl
.contents
[0]);
4636 * return + if the user does NOT have the right to set the topic, and
4637 * the topic is changed.
4640 bad_topic(struct chanNode
*channel
, struct userNode
*user
, const char *new_topic
)
4642 struct chanData
*cData
= channel
->channel_info
;
4643 if(check_user_level(channel
, user
, lvlEnfTopic
, 1, 0))
4645 else if(cData
->topic
)
4646 return irccasecmp(new_topic
, cData
->topic
);
4653 * Makes a givin topic fit into a givin topic mask and returns
4656 * topic_mask - the mask to conform to
4657 * topic - the topic to make conform
4658 * new_topic - the pre-allocated char* to put the new topic into
4660 * modifies: new_topic
4663 conform_topic(char* topic_mask
, char* topic
, char *new_topic
)
4665 //char *topic_mask = cData->topic_mask;
4667 int pos
=0, starpos
=-1, dpos
=0, len
;
4669 while((tchar
= topic_mask
[pos
++]) && (dpos
<= TOPICLEN
))
4676 strcpy(new_topic
, "");
4679 len
= strlen(topic
);
4680 if((dpos
+ len
) > TOPICLEN
)
4681 len
= TOPICLEN
+ 1 - dpos
;
4682 memcpy(new_topic
+dpos
, topic
, len
);
4686 case '\\': tchar
= topic_mask
[pos
++]; /* and fall through */
4687 default: new_topic
[dpos
++] = tchar
; break;
4690 if((dpos
> TOPICLEN
) || tchar
)
4692 strcpy(new_topic
, "");
4695 new_topic
[dpos
] = 0;
4699 static CHANSERV_FUNC(cmd_topic
)
4701 struct chanData
*cData
;
4705 #ifdef WITH_PROTOCOL_P10
4709 cData
= channel
->channel_info
;
4714 /*XXX Why would we ever want to send chanserv as the setter? I dont understand -Rubin */
4715 SetChannelTopic(channel
, chanserv
, p10
? user
: chanserv
, cData
->topic
, 1);
4716 reply("CSMSG_TOPIC_SET", cData
->topic
);
4720 reply("CSMSG_NO_TOPIC", channel
->name
);
4724 topic
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
4725 /* If they say "!topic *", use an empty topic. */
4726 if((topic
[0] == '*') && (topic
[1] == 0))
4729 if(bad_topic(channel
, user
, topic
))
4731 reply("CSMSG_TOPIC_LOCKED", channel
->name
);
4736 /* If there is a topicmask set, and the new topic doesnt match, make it */
4737 if(cData
->topic_mask
&& !match_ircglob(topic
, cData
->topic_mask
))
4739 char *topic_mask
= cData
->topic_mask
;
4740 char new_topic
[TOPICLEN
+1];
4742 /* make a new topic fitting mask */
4743 conform_topic(topic_mask
, topic
, new_topic
);
4746 /* Topic couldnt fit into mask, was too long */
4747 reply("CSMSG_TOPICMASK_CONFLICT1", channel
->name
, topic_mask
);
4748 reply("CSMSG_TOPICMASK_CONFLICT2", TOPICLEN
);
4751 SetChannelTopic(channel
, chanserv
, p10
? user
: chanserv
, new_topic
, 1);
4753 else /* No mask set, just set the topic */
4754 SetChannelTopic(channel
, chanserv
, p10
? user
: chanserv
, topic
, 1);
4757 if(check_user_level(channel
, user
, lvlTopicSnarf
, 1, 0))
4759 /* Grab the topic and save it as the default topic. */
4761 cData
->topic
= strdup(channel
->topic
);
4767 static CHANSERV_FUNC(cmd_mode
)
4769 struct userData
*uData
;
4770 struct mod_chanmode
*change
;
4775 if (checkDefCon(DEFCON_NO_MODE_CHANGE
) && !IsOper(user
)) {
4776 reply("CSMSG_DEFCON_NO_MODE_CHANGE");
4780 change
= &channel
->channel_info
->modes
;
4781 if(change
->modes_set
|| change
->modes_clear
) {
4782 modcmd_chanmode_announce(change
);
4783 reply("CSMSG_DEFAULTED_MODES", channel
->name
);
4785 reply("CSMSG_NO_MODES", channel
->name
);
4789 uData
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
4791 base_oplevel
= MAXOPLEVEL
;
4792 else if (uData
->access
>= UL_OWNER
)
4795 base_oplevel
= 1 + UL_OWNER
- uData
->access
;
4796 change
= mod_chanmode_parse(channel
, argv
+1, argc
-1, MCP_KEY_FREE
|MCP_REGISTERED
, base_oplevel
);
4800 reply("MSG_INVALID_MODES", unsplit_string(argv
+1, argc
-1, NULL
));
4804 if(!check_user_level(channel
, user
, lvlEnfModes
, 1, 0)
4805 && mode_lock_violated(&channel
->channel_info
->modes
, change
))
4808 mod_chanmode_format(&channel
->channel_info
->modes
, modes
);
4809 reply("CSMSG_MODE_LOCKED", modes
, channel
->name
);
4813 modcmd_chanmode_announce(change
);
4814 mod_chanmode_free(change
);
4815 reply("CSMSG_MODES_SET", unsplit_string(argv
+1, argc
-1, NULL
));
4819 static CHANSERV_FUNC(cmd_invite
)
4821 struct userData
*uData
;
4822 struct userNode
*invite
;
4824 uData
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
4828 if(!(invite
= GetUserH(argv
[1])))
4830 reply("MSG_NICK_UNKNOWN", argv
[1]);
4837 if(GetUserMode(channel
, invite
))
4839 reply("CSMSG_ALREADY_PRESENT", invite
->nick
, channel
->name
);
4847 char *reason
= unsplit_string(argv
+ 2, argc
- 2, NULL
);
4848 send_message(invite
, chanserv
, "CSMSG_INVITING_YOU_REASON", user
->nick
, channel
->name
, reason
);
4851 send_message(invite
, chanserv
, "CSMSG_INVITING_YOU", user
->nick
, channel
->name
);
4854 if (invite
->handle_info
&& invite
->handle_info
->ignores
->used
&& (argc
> 1)) {
4856 for (i
=0; i
< invite
->handle_info
->ignores
->used
; i
++) {
4857 if (user_matches_glob(user
, invite
->handle_info
->ignores
->list
[i
], MATCH_USENICK
)) {
4858 reply("CSMSG_CANNOT_INVITE", argv
[1], channel
->name
);
4864 irc_invite(chanserv
, invite
, channel
);
4866 reply("CSMSG_INVITED_USER", argv
[1], channel
->name
);
4871 static CHANSERV_FUNC(cmd_inviteme
)
4873 if(GetUserMode(channel
, user
))
4875 reply("CSMSG_YOU_ALREADY_PRESENT", channel
->name
);
4878 if(channel
->channel_info
4879 && !check_user_level(channel
, user
, lvlInviteMe
, 1, 0))
4881 reply("CSMSG_LOW_CHANNEL_ACCESS", channel
->name
);
4884 irc_invite(cmd
->parent
->bot
, user
, channel
);
4889 show_suspension_info(struct svccmd
*cmd
, struct userNode
*user
, struct suspended
*suspended
)
4892 char buf1
[INTERVALLEN
], buf2
[INTERVALLEN
];
4894 /* We display things based on two dimensions:
4895 * - Issue time: present or absent
4896 * - Expiration: revoked, expired, expires in future, or indefinite expiration
4897 * (in order of precedence, so something both expired and revoked
4898 * only counts as revoked)
4900 combo
= (suspended
->issued
? 4 : 0)
4901 + (suspended
->revoked
? 3 : suspended
->expires
? ((suspended
->expires
< now
) ? 2 : 1) : 0);
4903 case 0: /* no issue time, indefinite expiration */
4904 reply("CSMSG_CHANNEL_SUSPENDED_0", suspended
->suspender
, suspended
->reason
);
4906 case 1: /* no issue time, expires in future */
4907 intervalString(buf1
, suspended
->expires
-now
, user
->handle_info
);
4908 reply("CSMSG_CHANNEL_SUSPENDED_1", suspended
->suspender
, buf1
, suspended
->reason
);
4910 case 2: /* no issue time, expired */
4911 intervalString(buf1
, now
-suspended
->expires
, user
->handle_info
);
4912 reply("CSMSG_CHANNEL_SUSPENDED_2", suspended
->suspender
, buf1
, suspended
->reason
);
4914 case 3: /* no issue time, revoked */
4915 intervalString(buf1
, now
-suspended
->revoked
, user
->handle_info
);
4916 reply("CSMSG_CHANNEL_SUSPENDED_3", suspended
->suspender
, buf1
, suspended
->reason
);
4918 case 4: /* issue time set, indefinite expiration */
4919 intervalString(buf1
, now
-suspended
->issued
, user
->handle_info
);
4920 reply("CSMSG_CHANNEL_SUSPENDED_4", buf1
, suspended
->suspender
, suspended
->reason
);
4922 case 5: /* issue time set, expires in future */
4923 intervalString(buf1
, now
-suspended
->issued
, user
->handle_info
);
4924 intervalString(buf2
, suspended
->expires
-now
, user
->handle_info
);
4925 reply("CSMSG_CHANNEL_SUSPENDED_5", buf1
, suspended
->suspender
, buf2
, suspended
->reason
);
4927 case 6: /* issue time set, expired */
4928 intervalString(buf1
, now
-suspended
->issued
, user
->handle_info
);
4929 intervalString(buf2
, now
-suspended
->expires
, user
->handle_info
);
4930 reply("CSMSG_CHANNEL_SUSPENDED_6", buf1
, suspended
->suspender
, buf2
, suspended
->reason
);
4932 case 7: /* issue time set, revoked */
4933 intervalString(buf1
, now
-suspended
->issued
, user
->handle_info
);
4934 intervalString(buf2
, now
-suspended
->revoked
, user
->handle_info
);
4935 reply("CSMSG_CHANNEL_SUSPENDED_7", buf1
, suspended
->suspender
, buf2
, suspended
->reason
);
4938 log_module(CS_LOG
, LOG_ERROR
, "Invalid combo value %d in show_suspension_info()", combo
);
4944 show_giveownership_info(struct svccmd
*cmd
, struct userNode
*user
, struct giveownership
*giveownership
)
4947 const char *fmt
= "%a %b %d %H:%M %Y";
4948 strftime(buf
, sizeof(buf
), fmt
, localtime(&giveownership
->issued
));
4950 if(giveownership
->staff_issuer
)
4952 if(giveownership
->reason
)
4953 reply("CSMSG_CHANNEL_OWNERSHIP_STAFF_REASON", giveownership
->old_owner
,
4954 giveownership
->target
, giveownership
->target_access
,
4955 giveownership
->staff_issuer
, buf
, giveownership
->reason
);
4957 reply("CSMSG_CHANNEL_OWNERSHIP_STAFF", giveownership
->old_owner
,
4958 giveownership
->target
, giveownership
->target_access
,
4959 giveownership
->staff_issuer
, buf
);
4963 reply("CSMSG_CHANNEL_OWNERSHIP_NORMAL", giveownership
->old_owner
, giveownership
->target
, giveownership
->target_access
, buf
);
4968 static CHANSERV_FUNC(cmd_info
)
4970 char modes
[MAXLEN
], buffer
[INTERVALLEN
];
4971 struct userData
*uData
, *owner
;
4972 struct chanData
*cData
;
4973 struct do_not_register
*dnr
;
4978 cData
= channel
->channel_info
;
4979 reply("CSMSG_CHANNEL_INFO", channel
->name
);
4980 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
4983 uData
= GetChannelUser(cData
, user
->handle_info
);
4984 if(uData
&& (uData
->access
>= UL_OP
/*cData->lvlOpts[lvlGiveOps]*/))
4986 mod_chanmode_format(&cData
->modes
, modes
);
4987 reply("CSMSG_CHANNEL_TOPIC", cData
->topic
);
4988 reply("CSMSG_CHANNEL_MODES", modes
[0] ? modes
: user_find_message(user
, "MSG_NONE"));
4991 for(it
= dict_first(cData
->notes
); it
; it
= iter_next(it
))
4995 note
= iter_data(it
);
4996 if(!note_type_visible_to_user(cData
, note
->type
, user
))
4999 padding
= PADLEN
- 1 - strlen(iter_key(it
));
5000 reply("CSMSG_CHANNEL_NOTE", iter_key(it
), padding
> 0 ? padding
: 1, "", note
->note
);
5003 reply("CSMSG_CHANNEL_MAX", cData
->max
);
5004 for(owner
= cData
->users
; owner
; owner
= owner
->next
)
5005 if(owner
->access
== UL_OWNER
)
5006 reply("CSMSG_CHANNEL_OWNER", owner
->handle
->handle
);
5007 reply("CSMSG_CHANNEL_USERS", cData
->userCount
);
5008 reply("CSMSG_CHANNEL_LAMERS", cData
->banCount
);
5009 reply("CSMSG_CHANNEL_VISITED", intervalString(buffer
, now
- cData
->visited
, user
->handle_info
));
5011 privileged
= IsStaff(user
);
5012 /* if(privileged) */
5013 reply("CSMSG_CHANNEL_REGISTERED", intervalString(buffer
, now
- cData
->registered
, user
->handle_info
));
5014 if(/*((uData && uData->access >= UL_COOWNER) || privileged) && */cData
->registrar
)
5015 reply("CSMSG_CHANNEL_REGISTRAR", cData
->registrar
);
5017 if(privileged
&& (dnr
= chanserv_is_dnr(channel
->name
, NULL
)))
5018 chanserv_show_dnrs(user
, cmd
, channel
->name
, NULL
);
5020 if(cData
->suspended
&& ((uData
&& (uData
->access
>= UL_COOWNER
)) || IsHelping(user
)))
5022 struct suspended
*suspended
;
5023 reply((IsSuspended(cData
) ? "CSMSG_CHANNEL_SUSPENDED" : "CSMSG_CHANNEL_HISTORY"), channel
->name
);
5024 for(suspended
= cData
->suspended
; suspended
; suspended
= suspended
->previous
)
5025 show_suspension_info(cmd
, user
, suspended
);
5027 else if(IsSuspended(cData
))
5029 reply("CSMSG_CHANNEL_SUSPENDED", channel
->name
);
5030 show_suspension_info(cmd
, user
, cData
->suspended
);
5032 if(cData
->giveownership
&& ((uData
&& (uData
->access
>= UL_COOWNER
)) || IsStaff(user
)))
5034 struct giveownership
*giveownership
;
5035 reply("CSMSG_CHANNEL_OWNERSHIP_HISTORY", channel
->name
);
5036 for(giveownership
= cData
->giveownership
; giveownership
; giveownership
= giveownership
->previous
)
5037 show_giveownership_info(cmd
, user
, giveownership
);
5039 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
5040 reply("CSMSG_CHANNEL_END");
5042 reply("CSMSG_CHANNEL_END_CLEAN");
5046 static CHANSERV_FUNC(cmd_netinfo
)
5048 extern time_t boot_time
;
5049 extern unsigned long burst_length
;
5050 char interval
[INTERVALLEN
];
5052 reply("CSMSG_NETWORK_INFO");
5053 reply("CSMSG_NETWORK_SERVERS", dict_size(servers
));
5054 reply("CSMSG_NETWORK_USERS", dict_size(clients
));
5055 reply("CSMSG_NETWORK_OPERS", curr_opers
.used
);
5056 reply("CSMSG_NETWORK_CHANNELS", registered_channels
);
5057 reply("CSMSG_NETWORK_LAMERS", banCount
);
5058 reply("CSMSG_NETWORK_CHANUSERS", userCount
);
5059 reply("CSMSG_SERVICES_UPTIME", intervalString(interval
, time(NULL
) - boot_time
, user
->handle_info
));
5060 reply("CSMSG_BURST_LENGTH", intervalString(interval
, burst_length
, user
->handle_info
));
5065 send_staff_list(struct userNode
*to
, struct userList
*list
, int skip_flags
)
5067 struct helpfile_table table
;
5069 struct userNode
*user
;
5074 table
.flags
= TABLE_REPEAT_ROWS
| TABLE_NO_FREE
| TABLE_NO_HEADERS
;
5075 table
.contents
= alloca(list
->used
*sizeof(*table
.contents
));
5076 for(nn
=0; nn
<list
->used
; nn
++)
5078 user
= list
->list
[nn
];
5079 if(user
->modes
& skip_flags
)
5083 table
.contents
[table
.length
] = alloca(table
.width
*sizeof(**table
.contents
));
5086 nick
= alloca(strlen(user
->nick
)+3);
5087 sprintf(nick
, "(%s)", user
->nick
);
5091 table
.contents
[table
.length
][0] = nick
;
5094 table_send(chanserv
, to
->nick
, 0, NULL
, table
);
5097 static CHANSERV_FUNC(cmd_ircops
)
5099 reply("CSMSG_STAFF_OPERS");
5100 send_staff_list(user
, &curr_opers
, FLAGS_SERVICE
);
5104 static CHANSERV_FUNC(cmd_helpers
)
5106 reply("CSMSG_STAFF_HELPERS");
5107 send_staff_list(user
, &curr_helpers
, FLAGS_OPER
);
5111 static CHANSERV_FUNC(cmd_staff
)
5113 reply("CSMSG_NETWORK_STAFF");
5114 cmd_ircops(CSFUNC_ARGS
);
5115 cmd_helpers(CSFUNC_ARGS
);
5119 static CHANSERV_FUNC(cmd_peek
)
5121 struct modeNode
*mn
;
5122 char modes
[MODELEN
];
5124 struct helpfile_table table
;
5126 irc_make_chanmode(channel
, modes
);
5128 reply("CSMSG_PEEK_INFO", channel
->name
);
5129 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
5131 reply("CSMSG_PEEK_TOPIC", channel
->topic
);
5132 reply("CSMSG_PEEK_MODES", modes
);
5133 reply("CSMSG_PEEK_USERS", channel
->members
.used
);
5137 table
.flags
= TABLE_REPEAT_ROWS
| TABLE_NO_FREE
| TABLE_NO_HEADERS
;
5138 table
.contents
= alloca(channel
->members
.used
*sizeof(*table
.contents
));
5139 for(n
= 0; n
< channel
->members
.used
; n
++)
5141 mn
= channel
->members
.list
[n
];
5142 if(!(mn
->modes
& MODE_CHANOP
) || IsLocal(mn
->user
))
5144 table
.contents
[table
.length
] = alloca(sizeof(**table
.contents
));
5145 table
.contents
[table
.length
][0] = mn
->user
->nick
;
5150 reply("CSMSG_PEEK_OPS");
5151 table_send(chanserv
, user
->nick
, 0, NULL
, table
);
5154 reply("CSMSG_PEEK_NO_OPS");
5155 reply("CSMSG_PEEK_END");
5159 static MODCMD_FUNC(cmd_wipeinfo
)
5161 struct handle_info
*victim
;
5162 struct userData
*ud
, *actor
;
5165 actor
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
5166 if(!(victim
= modcmd_get_handle_info(user
, argv
[1])))
5168 if(!(ud
= GetTrueChannelAccess(channel
->channel_info
, victim
)))
5170 reply("CSMSG_NO_CHAN_USER", argv
[1], channel
->name
);
5173 if((ud
->access
>= actor
->access
) && (ud
!= actor
))
5175 reply("MSG_USER_OUTRANKED", victim
->handle
);
5181 reply("CSMSG_WIPED_INFO_LINE", argv
[1], channel
->name
);
5186 resync_channel(struct chanNode
*channel
)
5188 struct mod_chanmode
*changes
;
5189 struct chanData
*cData
= channel
->channel_info
;
5190 unsigned int ii
, used
;
5192 /* 6 = worst case -ovh+ovh on everyone */
5193 changes
= mod_chanmode_alloc(channel
->members
.used
* 6);
5194 for(ii
= used
= 0; ii
< channel
->members
.used
; ++ii
)
5196 struct modeNode
*mn
= channel
->members
.list
[ii
];
5197 struct userData
*uData
;
5199 if(IsService(mn
->user
))
5203 uData
= GetChannelAccess(cData
, mn
->user
->handle_info
);
5205 /* If the channel is in no-mode mode, de-mode EVERYONE */
5206 if(cData
->chOpts
[chAutomode
] == 'n')
5210 changes
->args
[used
].mode
= MODE_REMOVE
| mn
->modes
;
5211 changes
->args
[used
++].u
.member
= mn
;
5214 else /* Give various userlevels their modes.. */
5216 if(uData
&& uData
->access
>= UL_OP
)
5218 if(!(mn
->modes
& MODE_CHANOP
))
5220 changes
->args
[used
].mode
= MODE_CHANOP
;
5221 changes
->args
[used
++].u
.member
= mn
;
5224 else if(uData
&& uData
->access
>= UL_HALFOP
)
5226 if(mn
->modes
& MODE_CHANOP
)
5228 changes
->args
[used
].mode
= MODE_REMOVE
| MODE_CHANOP
;
5229 changes
->args
[used
++].u
.member
= mn
;
5231 if(!(mn
->modes
& MODE_HALFOP
))
5233 changes
->args
[used
].mode
= MODE_HALFOP
;
5234 changes
->args
[used
++].u
.member
= mn
;
5237 else if(uData
&& uData
->access
>= UL_PEON
)
5239 if(mn
->modes
& MODE_CHANOP
)
5241 changes
->args
[used
].mode
= MODE_REMOVE
| MODE_CHANOP
;
5242 changes
->args
[used
++].u
.member
= mn
;
5244 if(mn
->modes
& MODE_HALFOP
)
5246 changes
->args
[used
].mode
= MODE_REMOVE
| MODE_HALFOP
;
5247 changes
->args
[used
++].u
.member
= mn
;
5249 /* Don't voice peons if were in mode m */
5250 if( cData
->chOpts
[chAutomode
] == 'm')
5252 if(mn
->modes
& MODE_VOICE
)
5254 changes
->args
[used
].mode
= MODE_REMOVE
| MODE_VOICE
;
5255 changes
->args
[used
++].u
.member
= mn
;
5258 /* otherwise, make user they do have voice */
5259 else if(!(mn
->modes
& MODE_VOICE
))
5261 changes
->args
[used
].mode
= MODE_VOICE
;
5262 changes
->args
[used
++].u
.member
= mn
;
5265 else /* They arnt on the userlist.. */
5267 /* If we voice everyone, but they dont.. */
5268 if(cData
->chOpts
[chAutomode
] == 'v')
5270 /* Remove anything except v */
5271 if(mn
->modes
& ~MODE_VOICE
)
5273 changes
->args
[used
].mode
= MODE_REMOVE
| (mn
->modes
& ~MODE_VOICE
);
5274 changes
->args
[used
++].u
.member
= mn
;
5277 if(!(mn
->modes
& MODE_VOICE
))
5279 changes
->args
[used
].mode
= MODE_VOICE
;
5280 changes
->args
[used
++].u
.member
= mn
;
5283 /* If we hop everyone, but they dont.. */
5284 else if(cData
->chOpts
[chAutomode
] == 'h')
5286 /* Remove anything except h */
5287 if(mn
->modes
& ~MODE_HALFOP
)
5289 changes
->args
[used
].mode
= MODE_REMOVE
| (mn
->modes
& ~MODE_HALFOP
);
5290 changes
->args
[used
++].u
.member
= mn
;
5293 if(!(mn
->modes
& MODE_HALFOP
))
5295 changes
->args
[used
].mode
= MODE_HALFOP
;
5296 changes
->args
[used
++].u
.member
= mn
;
5299 /* If we op everyone, but they dont.. */
5300 else if(cData
->chOpts
[chAutomode
] == 'o')
5302 /* Remove anything except h */
5303 if(mn
->modes
& ~MODE_CHANOP
)
5305 changes
->args
[used
].mode
= MODE_REMOVE
| (mn
->modes
& ~MODE_CHANOP
);
5306 changes
->args
[used
++].u
.member
= mn
;
5309 if(!(mn
->modes
& MODE_CHANOP
))
5311 changes
->args
[used
].mode
= MODE_CHANOP
;
5312 changes
->args
[used
++].u
.member
= mn
;
5315 /* they have no excuse for having modes, de-everything them */
5320 changes
->args
[used
].mode
= MODE_REMOVE
| mn
->modes
;
5321 changes
->args
[used
++].u
.member
= mn
;
5327 changes
->argc
= used
;
5328 mod_chanmode_announce(chanserv
, channel
, changes
);
5329 mod_chanmode_free(changes
);
5332 static CHANSERV_FUNC(cmd_resync
)
5334 resync_channel(channel
);
5335 reply("CSMSG_RESYNCED_USERS", channel
->name
);
5339 static CHANSERV_FUNC(cmd_seen
)
5341 struct userData
*uData
;
5342 struct handle_info
*handle
;
5343 char seen
[INTERVALLEN
];
5347 if(!irccasecmp(argv
[1], chanserv
->nick
))
5349 reply("CSMSG_IS_CHANSERV");
5353 if(!(handle
= get_handle_info(argv
[1])))
5355 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
5359 if(!(uData
= GetTrueChannelAccess(channel
->channel_info
, handle
)))
5361 reply("CSMSG_NO_CHAN_USER", handle
->handle
, channel
->name
);
5366 reply("CSMSG_USER_PRESENT", handle
->handle
);
5367 else if(uData
->seen
)
5368 reply("CSMSG_USER_SEEN", handle
->handle
, channel
->name
, intervalString(seen
, now
- uData
->seen
, user
->handle_info
));
5370 reply("CSMSG_NEVER_SEEN", handle
->handle
, channel
->name
);
5372 if(!uData
->present
&& HANDLE_FLAGGED(handle
, FROZEN
))
5373 reply("CSMSG_USER_VACATION", handle
->handle
);
5378 static MODCMD_FUNC(cmd_names
)
5380 struct userNode
*targ
;
5381 struct userData
*targData
;
5382 unsigned int ii
, pos
;
5385 for(ii
=pos
=0; ii
<channel
->members
.used
; ++ii
)
5387 targ
= channel
->members
.list
[ii
]->user
;
5388 targData
= GetTrueChannelAccess(channel
->channel_info
, targ
->handle_info
);
5391 if(pos
+ strlen(targ
->nick
) + strlen(targ
->handle_info
->handle
) + 8 > sizeof(buf
))
5394 reply("CSMSG_CHANNEL_NAMES", channel
->name
, buf
);
5398 if(IsUserSuspended(targData
))
5400 pos
+= sprintf(buf
+pos
, "%d:%s(%s)", targData
->access
, targ
->nick
, targ
->handle_info
->handle
);
5403 reply("CSMSG_CHANNEL_NAMES", channel
->name
, buf
);
5404 reply("CSMSG_END_NAMES", channel
->name
);
5409 note_type_visible_to_user(struct chanData
*channel
, struct note_type
*ntype
, struct userNode
*user
)
5411 switch(ntype
->visible_type
)
5413 case NOTE_VIS_ALL
: return 1;
5414 case NOTE_VIS_CHANNEL_USERS
: return !channel
|| !user
|| (user
->handle_info
&& GetChannelUser(channel
, user
->handle_info
));
5415 case NOTE_VIS_PRIVILEGED
: default: return user
&& (IsOper(user
) || IsSupportHelper(user
) || IsNetworkHelper(user
));
5420 note_type_settable_by_user(struct chanNode
*channel
, struct note_type
*ntype
, struct userNode
*user
)
5422 struct userData
*uData
;
5424 switch(ntype
->set_access_type
)
5426 case NOTE_SET_CHANNEL_ACCESS
:
5427 if(!user
->handle_info
)
5429 if(!(uData
= GetChannelUser(channel
->channel_info
, user
->handle_info
)))
5431 return uData
->access
>= ntype
->set_access
.min_ulevel
;
5432 case NOTE_SET_CHANNEL_SETTER
:
5433 return check_user_level(channel
, user
, lvlSetters
, 1, 0);
5434 case NOTE_SET_PRIVILEGED
: default:
5435 return IsHelping(user
) && (user
->handle_info
->opserv_level
>= ntype
->set_access
.min_opserv
);
5439 static CHANSERV_FUNC(cmd_note
)
5441 struct chanData
*cData
;
5443 struct note_type
*ntype
;
5445 cData
= channel
->channel_info
;
5448 reply("CSMSG_NOT_REGISTERED", channel
->name
);
5452 /* If no arguments, show all visible notes for the channel. */
5458 for(count
=0, it
=dict_first(cData
->notes
); it
; it
=iter_next(it
))
5460 note
= iter_data(it
);
5461 if(!note_type_visible_to_user(cData
, note
->type
, user
))
5464 reply("CSMSG_NOTELIST_HEADER", channel
->name
);
5465 reply("CSMSG_NOTE_FORMAT", iter_key(it
), note
->setter
, note
->note
);
5468 reply("CSMSG_NOTELIST_END", channel
->name
);
5470 reply("CSMSG_NOTELIST_EMPTY", channel
->name
);
5472 /* If one argument, show the named note. */
5475 if((note
= dict_find(cData
->notes
, argv
[1], NULL
))
5476 && note_type_visible_to_user(cData
, note
->type
, user
))
5478 reply("CSMSG_NOTE_FORMAT", note
->type
->name
, note
->setter
, note
->note
);
5480 else if((ntype
= dict_find(note_types
, argv
[1], NULL
))
5481 && note_type_visible_to_user(NULL
, ntype
, user
))
5483 reply("CSMSG_NO_SUCH_NOTE", channel
->name
, ntype
->name
);
5488 reply("CSMSG_BAD_NOTE_TYPE", argv
[1]);
5492 /* Assume they're trying to set a note. */
5496 ntype
= dict_find(note_types
, argv
[1], NULL
);
5499 reply("CSMSG_BAD_NOTE_TYPE", argv
[1]);
5502 else if(note_type_settable_by_user(channel
, ntype
, user
))
5504 note_text
= unsplit_string(argv
+2, argc
-2, NULL
);
5505 if((note
= dict_find(cData
->notes
, argv
[1], NULL
)))
5506 reply("CSMSG_REPLACED_NOTE", ntype
->name
, channel
->name
, note
->setter
, note
->note
);
5507 chanserv_add_channel_note(cData
, ntype
, user
->handle_info
->handle
, note_text
);
5508 reply("CSMSG_NOTE_SET", ntype
->name
, channel
->name
);
5510 if(ntype
->visible_type
== NOTE_VIS_PRIVILEGED
)
5512 /* The note is viewable to staff only, so return 0
5513 to keep the invocation from getting logged (or
5514 regular users can see it in !events). */
5520 reply("CSMSG_NO_ACCESS");
5527 static CHANSERV_FUNC(cmd_delnote
)
5532 if(!(note
= dict_find(channel
->channel_info
->notes
, argv
[1], NULL
))
5533 || !note_type_settable_by_user(channel
, note
->type
, user
))
5535 reply("CSMSG_NO_SUCH_NOTE", channel
->name
, argv
[1]);
5538 dict_remove(channel
->channel_info
->notes
, note
->type
->name
);
5539 reply("CSMSG_NOTE_REMOVED", argv
[1], channel
->name
);
5543 static CHANSERV_FUNC(cmd_last
)
5549 numoflines
= (argc
> 1) ? atoi(argv
[1]) : 10;
5551 if(numoflines
< 1 || numoflines
> 200)
5553 reply("CSMSG_LAST_INVALID");
5556 ShowLog(user
, channel
, "*", "*", "*", "*", numoflines
);
5560 static CHANSERV_FUNC(cmd_events
)
5562 struct logSearch discrim
;
5563 struct logReport report
;
5564 unsigned int matches
, limit
;
5566 limit
= (argc
> 1) ? atoi(argv
[1]) : 10;
5567 if(limit
< 1 || limit
> 200)
5570 memset(&discrim
, 0, sizeof(discrim
));
5571 discrim
.masks
.bot
= chanserv
;
5572 discrim
.masks
.channel_name
= channel
->name
;
5574 discrim
.masks
.command
= argv
[2];
5575 discrim
.limit
= limit
;
5576 discrim
.max_time
= INT_MAX
;
5577 discrim
.severities
= 1 << LOG_COMMAND
;
5578 report
.reporter
= chanserv
;
5580 reply("CSMSG_EVENT_SEARCH_RESULTS", channel
->name
);
5581 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
5583 matches
= log_entry_search(&discrim
, log_report_entry
, &report
);
5585 reply("MSG_MATCH_COUNT", matches
);
5587 reply("MSG_NO_MATCHES");
5591 static CHANSERV_FUNC(cmd_say
)
5597 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
5598 send_channel_message(channel
, cmd
->parent
->bot
, "%s", msg
);
5600 else if(GetUserH(argv
[1]))
5603 msg
= unsplit_string(argv
+ 2, argc
- 2, NULL
);
5604 send_target_message(5, argv
[1], cmd
->parent
->bot
, "%s", msg
);
5608 reply("MSG_NOT_TARGET_NAME");
5614 static CHANSERV_FUNC(cmd_emote
)
5620 /* CTCP is so annoying. */
5621 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
5622 send_channel_message(channel
, cmd
->parent
->bot
, "\001ACTION %s\001", msg
);
5624 else if(GetUserH(argv
[1]))
5626 msg
= unsplit_string(argv
+ 2, argc
- 2, NULL
);
5627 send_target_message(5, argv
[1], cmd
->parent
->bot
, "\001ACTION %s\001", msg
);
5631 reply("MSG_NOT_TARGET_NAME");
5637 struct channelList
*
5638 chanserv_support_channels(void)
5640 return &chanserv_conf
.support_channels
;
5643 static CHANSERV_FUNC(cmd_expire
)
5645 int channel_count
= registered_channels
;
5646 expire_channels(NULL
);
5647 reply("CSMSG_CHANNELS_EXPIRED", channel_count
- registered_channels
);
5652 chanserv_expire_suspension(void *data
)
5654 struct suspended
*suspended
= data
;
5655 struct chanNode
*channel
;
5657 if(!suspended
->expires
|| (now
< suspended
->expires
))
5658 suspended
->revoked
= now
;
5659 channel
= suspended
->cData
->channel
;
5660 suspended
->cData
->channel
= channel
;
5661 suspended
->cData
->flags
&= ~CHANNEL_SUSPENDED
;
5662 if(!IsOffChannel(suspended
->cData
))
5664 spamserv_cs_suspend(channel
, 0, 0, NULL
);
5665 ss_cs_join_channel(channel
, 1);
5669 static CHANSERV_FUNC(cmd_csuspend
)
5671 struct suspended
*suspended
;
5672 char reason
[MAXLEN
];
5673 time_t expiry
, duration
;
5674 struct userData
*uData
;
5678 if(IsProtected(channel
->channel_info
))
5680 reply("CSMSG_SUSPEND_NODELETE", channel
->name
);
5684 if(argv
[1][0] == '!')
5686 else if(IsSuspended(channel
->channel_info
))
5688 reply("CSMSG_ALREADY_SUSPENDED", channel
->name
);
5689 show_suspension_info(cmd
, user
, channel
->channel_info
->suspended
);
5693 if(!strcmp(argv
[1], "0"))
5695 else if((duration
= ParseInterval(argv
[1])))
5696 expiry
= now
+ duration
;
5699 reply("MSG_INVALID_DURATION", argv
[1]);
5703 unsplit_string(argv
+ 2, argc
- 2, reason
);
5705 suspended
= calloc(1, sizeof(*suspended
));
5706 suspended
->revoked
= 0;
5707 suspended
->issued
= now
;
5708 suspended
->suspender
= strdup(user
->handle_info
->handle
);
5709 suspended
->expires
= expiry
;
5710 suspended
->reason
= strdup(reason
);
5711 suspended
->cData
= channel
->channel_info
;
5712 suspended
->previous
= suspended
->cData
->suspended
;
5713 suspended
->cData
->suspended
= suspended
;
5715 if(suspended
->expires
)
5716 timeq_add(suspended
->expires
, chanserv_expire_suspension
, suspended
);
5718 if(IsSuspended(channel
->channel_info
))
5720 suspended
->previous
->revoked
= now
;
5721 if(suspended
->previous
->expires
)
5722 timeq_del(suspended
->previous
->expires
, chanserv_expire_suspension
, suspended
->previous
, 0);
5724 global_message_args(MESSAGE_RECIPIENT_OPERS
| MESSAGE_RECIPIENT_HELPERS
, "CSMSG_SUSPENSION_MODIFIED",
5725 channel
->name
, suspended
->suspender
);
5729 /* Mark all users in channel as absent. */
5730 for(uData
= channel
->channel_info
->users
; uData
; uData
= uData
->next
)
5739 /* Mark the channel as suspended, then part. */
5740 channel
->channel_info
->flags
|= CHANNEL_SUSPENDED
;
5741 spamserv_cs_suspend(channel
, expiry
, 1, suspended
->reason
);
5742 DelChannelUser(chanserv
, channel
, suspended
->reason
, 0);
5743 reply("CSMSG_SUSPENDED", channel
->name
);
5744 global_message_args(MESSAGE_RECIPIENT_OPERS
| MESSAGE_RECIPIENT_HELPERS
, "CSMSG_SUSPENDED_BY",
5745 channel
->name
, suspended
->suspender
);
5750 static CHANSERV_FUNC(cmd_cunsuspend
)
5752 struct suspended
*suspended
;
5754 if(!IsSuspended(channel
->channel_info
))
5756 reply("CSMSG_NOT_SUSPENDED", channel
->name
);
5760 suspended
= channel
->channel_info
->suspended
;
5762 /* Expire the suspension and join ChanServ to the channel. */
5763 timeq_del(suspended
->expires
, chanserv_expire_suspension
, suspended
, 0);
5764 chanserv_expire_suspension(suspended
);
5765 reply("CSMSG_UNSUSPENDED", channel
->name
);
5766 global_message_args(MESSAGE_RECIPIENT_OPERS
|MESSAGE_RECIPIENT_HELPERS
, "CSMSG_UNSUSPENDED_BY",
5767 channel
->name
, user
->handle_info
->handle
);
5771 typedef struct chanservSearch
5779 unsigned long flags
;
5783 typedef void (*channel_search_func
)(struct chanData
*channel
, void *data
);
5786 chanserv_search_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
5791 search
= malloc(sizeof(struct chanservSearch
));
5792 memset(search
, 0, sizeof(*search
));
5795 for(i
= 0; i
< argc
; i
++)
5797 /* Assume all criteria require arguments. */
5800 reply("MSG_MISSING_PARAMS", argv
[i
]);
5804 if(!irccasecmp(argv
[i
], "name"))
5805 search
->name
= argv
[++i
];
5806 else if(!irccasecmp(argv
[i
], "registrar"))
5807 search
->registrar
= argv
[++i
];
5808 else if(!irccasecmp(argv
[i
], "unvisited"))
5809 search
->unvisited
= ParseInterval(argv
[++i
]);
5810 else if(!irccasecmp(argv
[i
], "registered"))
5811 search
->registered
= ParseInterval(argv
[++i
]);
5812 else if(!irccasecmp(argv
[i
], "flags"))
5815 if(!irccasecmp(argv
[i
], "nodelete"))
5816 search
->flags
|= CHANNEL_NODELETE
;
5817 else if(!irccasecmp(argv
[i
], "suspended"))
5818 search
->flags
|= CHANNEL_SUSPENDED
;
5821 reply("CSMSG_INVALID_CFLAG", argv
[i
]);
5825 else if(!irccasecmp(argv
[i
], "limit"))
5826 search
->limit
= strtoul(argv
[++i
], NULL
, 10);
5829 reply("MSG_INVALID_CRITERIA", argv
[i
]);
5834 if(search
->name
&& !strcmp(search
->name
, "*"))
5836 if(search
->registrar
&& !strcmp(search
->registrar
, "*"))
5837 search
->registrar
= 0;
5846 chanserv_channel_match(struct chanData
*channel
, search_t search
)
5848 const char *name
= channel
->channel
->name
;
5849 if((search
->name
&& !match_ircglob(name
, search
->name
)) ||
5850 (search
->registrar
&& !channel
->registrar
) ||
5851 (search
->registrar
&& !match_ircglob(channel
->registrar
, search
->registrar
)) ||
5852 (search
->unvisited
&& (now
- channel
->visited
) < search
->unvisited
) ||
5853 (search
->registered
&& (now
- channel
->registered
) > search
->registered
) ||
5854 (search
->flags
&& ((search
->flags
& channel
->flags
) != search
->flags
)))
5861 chanserv_channel_search(search_t search
, channel_search_func smf
, void *data
)
5863 struct chanData
*channel
;
5864 unsigned int matches
= 0;
5866 for(channel
= channelList
; channel
&& matches
< search
->limit
; channel
= channel
->next
)
5868 if(!chanserv_channel_match(channel
, search
))
5878 search_count(UNUSED_ARG(struct chanData
*channel
), UNUSED_ARG(void *data
))
5883 search_print(struct chanData
*channel
, void *data
)
5885 send_message_type(4, data
, chanserv
, "%s", channel
->channel
->name
);
5888 static CHANSERV_FUNC(cmd_search
)
5891 unsigned int matches
;
5892 channel_search_func action
;
5896 if(!irccasecmp(argv
[1], "count"))
5897 action
= search_count
;
5898 else if(!irccasecmp(argv
[1], "print"))
5899 action
= search_print
;
5902 reply("CSMSG_ACTION_INVALID", argv
[1]);
5906 search
= chanserv_search_create(cmd
, user
, argc
- 2, argv
+ 2);
5910 if(action
== search_count
)
5911 search
->limit
= INT_MAX
;
5913 if(action
== search_print
)
5915 reply("CSMSG_CHANNEL_SEARCH_RESULTS");
5916 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
5920 matches
= chanserv_channel_search(search
, action
, user
);
5923 reply("MSG_MATCH_COUNT", matches
);
5925 reply("MSG_NO_MATCHES");
5931 static CHANSERV_FUNC(cmd_unvisited
)
5933 struct chanData
*cData
;
5934 time_t interval
= chanserv_conf
.channel_expire_delay
;
5935 char buffer
[INTERVALLEN
];
5936 unsigned int limit
= 25, matches
= 0;
5940 interval
= ParseInterval(argv
[1]);
5942 limit
= atoi(argv
[2]);
5945 intervalString(buffer
, interval
, user
->handle_info
);
5946 reply("CSMSG_UNVISITED_HEADER", limit
, buffer
);
5948 for(cData
= channelList
; cData
&& matches
< limit
; cData
= cData
->next
)
5950 if((now
- cData
->visited
) < interval
)
5953 intervalString(buffer
, now
- cData
->visited
, user
->handle_info
);
5954 reply("CSMSG_UNVISITED_DATA", cData
->channel
->name
, buffer
);
5961 static MODCMD_FUNC(chan_opt_defaulttopic
)
5967 if(!check_user_level(channel
, user
, lvlEnfTopic
, 1, 0))
5969 reply("CSMSG_TOPIC_LOCKED", channel
->name
);
5973 topic
= unsplit_string(argv
+1, argc
-1, NULL
);
5975 free(channel
->channel_info
->topic
);
5976 if(topic
[0] == '*' && topic
[1] == 0)
5978 topic
= channel
->channel_info
->topic
= NULL
;
5982 topic
= channel
->channel_info
->topic
= strdup(topic
);
5983 if(channel
->channel_info
->topic_mask
5984 && !match_ircglob(channel
->channel_info
->topic
, channel
->channel_info
->topic_mask
))
5985 reply("CSMSG_TOPIC_MISMATCH", channel
->name
);
5987 SetChannelTopic(channel
, chanserv
, user
, topic
? topic
: "", 1);
5990 if(channel
->channel_info
->topic
)
5991 reply("CSMSG_SET_DEFAULT_TOPIC", channel
->channel_info
->topic
);
5993 reply("CSMSG_SET_DEFAULT_TOPIC", user_find_message(user
, "MSG_NONE"));
5997 static MODCMD_FUNC(chan_opt_topicmask
)
6001 struct chanData
*cData
= channel
->channel_info
;
6004 if(!check_user_level(channel
, user
, lvlEnfTopic
, 1, 0))
6006 reply("CSMSG_TOPIC_LOCKED", channel
->name
);
6010 mask
= unsplit_string(argv
+1, argc
-1, NULL
);
6012 if(cData
->topic_mask
)
6013 free(cData
->topic_mask
);
6014 if(mask
[0] == '*' && mask
[1] == 0)
6016 cData
->topic_mask
= 0;
6020 cData
->topic_mask
= strdup(mask
);
6022 reply("CSMSG_MASK_BUT_NO_TOPIC", channel
->name
);
6023 else if(!match_ircglob(cData
->topic
, cData
->topic_mask
))
6024 reply("CSMSG_TOPIC_MISMATCH", channel
->name
);
6028 if(channel
->channel_info
->topic_mask
)
6029 reply("CSMSG_SET_TOPICMASK", channel
->channel_info
->topic_mask
);
6031 reply("CSMSG_SET_TOPICMASK", user_find_message(user
, "MSG_NONE"));
6035 int opt_greeting_common(struct userNode
*user
, struct svccmd
*cmd
, int argc
, char *argv
[], char *name
, char **data
)
6039 char *greeting
= unsplit_string(argv
+1, argc
-1, NULL
);
6043 if(greeting
[0] == '*' && greeting
[1] == 0)
6047 unsigned int length
= strlen(greeting
);
6048 if(length
> chanserv_conf
.greeting_length
)
6050 reply("CSMSG_GREETING_TOO_LONG", length
, chanserv_conf
.greeting_length
);
6053 *data
= strdup(greeting
);
6062 reply(name
, user_find_message(user
, "MSG_NONE"));
6066 static MODCMD_FUNC(chan_opt_greeting
)
6068 return opt_greeting_common(user
, cmd
, argc
, argv
, "CSMSG_SET_GREETING", &channel
->channel_info
->greeting
);
6071 static MODCMD_FUNC(chan_opt_usergreeting
)
6073 return opt_greeting_common(user
, cmd
, argc
, argv
, "CSMSG_SET_USERGREETING", &channel
->channel_info
->user_greeting
);
6076 static MODCMD_FUNC(chan_opt_maxsetinfo
)
6078 unsigned int charmax
;
6081 charmax
= atoi(argv
[1]);
6082 if ((charmax
> 0) && (charmax
< chanserv_conf
.max_userinfo_length
))
6083 channel
->channel_info
->maxsetinfo
= charmax
;
6086 reply("CSMSG_SET_MAXSETINFO", channel
->channel_info
->maxsetinfo
);
6090 static MODCMD_FUNC(chan_opt_modes
)
6092 struct mod_chanmode
*new_modes
;
6093 char modes
[MODELEN
];
6097 if (checkDefCon(DEFCON_NO_MODE_CHANGE
) && !IsOper(user
)) {
6098 reply("CSMSG_DEFCON_NO_MODE_CHANGE");
6102 if(!check_user_level(channel
, user
, lvlEnfModes
, 1, 0))
6104 reply("CSMSG_NO_ACCESS");
6107 if(argv
[1][0] == '*' && argv
[1][1] == 0)
6109 memset(&channel
->channel_info
->modes
, 0, sizeof(channel
->channel_info
->modes
));
6111 else if(!(new_modes
= mod_chanmode_parse(channel
, argv
+1, argc
-1,MCP_KEY_FREE
|MCP_REGISTERED
, 0)))
6113 reply("CSMSG_INVALID_MODE_LOCK", unsplit_string(argv
+1, argc
-1, NULL
));
6116 else if(new_modes
->argc
> 1)
6118 reply("CSMSG_INVALID_MODE_LOCK", unsplit_string(argv
+1, argc
-1, NULL
));
6119 mod_chanmode_free(new_modes
);
6124 channel
->channel_info
->modes
= *new_modes
;
6125 modcmd_chanmode_announce(new_modes
);
6126 mod_chanmode_free(new_modes
);
6130 mod_chanmode_format(&channel
->channel_info
->modes
, modes
);
6132 reply("CSMSG_SET_MODES", modes
);
6134 reply("CSMSG_SET_MODES", user_find_message(user
, "MSG_NONE"));
6138 #define CHANNEL_BINARY_OPTION(MSG, FLAG) return channel_binary_option(MSG, FLAG, CSFUNC_ARGS);
6140 channel_binary_option(char *name
, unsigned long mask
, struct userNode
*user
, struct chanNode
*channel
, int argc
, char *argv
[], struct svccmd
*cmd
)
6142 struct chanData
*cData
= channel
->channel_info
;
6147 /* Set flag according to value. */
6148 if(enabled_string(argv
[1]))
6150 cData
->flags
|= mask
;
6153 else if(disabled_string(argv
[1]))
6155 cData
->flags
&= ~mask
;
6160 reply("MSG_INVALID_BINARY", argv
[1]);
6166 /* Find current option value. */
6167 value
= (cData
->flags
& mask
) ? 1 : 0;
6171 reply(name
, user_find_message(user
, "MSG_ON"));
6173 reply(name
, user_find_message(user
, "MSG_OFF"));
6177 static MODCMD_FUNC(chan_opt_nodelete
)
6179 if((argc
> 1) && (!IsOper(user
) || !user
->handle_info
|| (user
->handle_info
->opserv_level
< chanserv_conf
.nodelete_level
)))
6181 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
6185 CHANNEL_BINARY_OPTION("CSMSG_SET_NODELETE", CHANNEL_NODELETE
);
6188 static MODCMD_FUNC(chan_opt_dynlimit
)
6190 CHANNEL_BINARY_OPTION("CSMSG_SET_DYNLIMIT", CHANNEL_DYNAMIC_LIMIT
);
6193 static MODCMD_FUNC(chan_opt_offchannel
)
6195 struct chanData
*cData
= channel
->channel_info
;
6200 /* Set flag according to value. */
6201 if(enabled_string(argv
[1]))
6203 if(!IsOffChannel(cData
))
6204 DelChannelUser(chanserv
, channel
, "Going off-channel.", 0);
6205 cData
->flags
|= CHANNEL_OFFCHANNEL
;
6208 else if(disabled_string(argv
[1]))
6210 if(IsOffChannel(cData
))
6212 struct mod_chanmode change
;
6213 mod_chanmode_init(&change
);
6215 change
.args
[0].mode
= MODE_CHANOP
;
6216 change
.args
[0].u
.member
= AddChannelUser(chanserv
, channel
);
6217 mod_chanmode_announce(chanserv
, channel
, &change
);
6219 cData
->flags
&= ~CHANNEL_OFFCHANNEL
;
6224 reply("MSG_INVALID_BINARY", argv
[1]);
6230 /* Find current option value. */
6231 value
= (cData
->flags
& CHANNEL_OFFCHANNEL
) ? 1 : 0;
6235 reply("CSMSG_SET_OFFCHANNEL", user_find_message(user
, "MSG_ON"));
6237 reply("CSMSG_SET_OFFCHANNEL", user_find_message(user
, "MSG_OFF"));
6241 static MODCMD_FUNC(chan_opt_defaults
)
6243 struct userData
*uData
;
6244 struct chanData
*cData
;
6245 const char *confirm
;
6246 enum levelOption lvlOpt
;
6247 enum charOption chOpt
;
6249 cData
= channel
->channel_info
;
6250 uData
= GetChannelUser(cData
, user
->handle_info
);
6251 if(!uData
|| (uData
->access
< UL_OWNER
))
6253 reply("CSMSG_OWNER_DEFAULTS", channel
->name
);
6256 confirm
= make_confirmation_string(uData
);
6257 if((argc
< 2) || strcmp(argv
[1], confirm
))
6259 reply("CSMSG_CONFIRM_DEFAULTS", channel
->name
, confirm
);
6262 cData
->flags
= CHANNEL_DEFAULT_FLAGS
;
6263 cData
->modes
= chanserv_conf
.default_modes
;
6264 for(lvlOpt
= 0; lvlOpt
< NUM_LEVEL_OPTIONS
; ++lvlOpt
)
6265 cData
->lvlOpts
[lvlOpt
] = levelOptions
[lvlOpt
].default_value
;
6266 for(chOpt
= 0; chOpt
< NUM_CHAR_OPTIONS
; ++chOpt
)
6267 cData
->chOpts
[chOpt
] = charOptions
[chOpt
].default_value
;
6268 reply("CSMSG_SETTINGS_DEFAULTED", channel
->name
);
6273 channel_level_option(enum levelOption option
, struct userNode
*user
, struct chanNode
*channel
, int argc
, char *argv
[], struct svccmd
*cmd
)
6275 struct chanData
*cData
= channel
->channel_info
;
6276 struct userData
*uData
;
6277 unsigned short value
;
6281 if(!check_user_level(channel
, user
, option
, 1, 1))
6283 reply("CSMSG_CANNOT_SET");
6286 value
= user_level_from_name(argv
[1], UL_OWNER
+1);
6287 if(!value
&& strcmp(argv
[1], "0"))
6289 reply("CSMSG_INVALID_ACCESS", argv
[1]);
6292 uData
= GetChannelUser(cData
, user
->handle_info
);
6293 if(!uData
|| ((uData
->access
< UL_OWNER
) && (value
> uData
->access
)))
6295 reply("CSMSG_BAD_SETLEVEL");
6301 /* This test only applies to owners, since non-owners
6302 * trying to set an option to above their level get caught
6303 * by the CSMSG_BAD_SETLEVEL test above.
6305 if(value
> uData
->access
)
6307 reply("CSMSG_BAD_SETTERS");
6314 cData
->lvlOpts
[option
] = value
;
6316 reply(levelOptions
[option
].format_name
, cData
->lvlOpts
[option
]);
6320 static MODCMD_FUNC(chan_opt_enfops
)
6322 return channel_level_option(lvlEnfOps
, CSFUNC_ARGS
);
6325 static MODCMD_FUNC(chan_opt_enfhalfops
)
6327 return channel_level_option(lvlEnfHalfOps
, CSFUNC_ARGS
);
6329 static MODCMD_FUNC(chan_opt_enfmodes
)
6331 return channel_level_option(lvlEnfModes
, CSFUNC_ARGS
);
6334 static MODCMD_FUNC(chan_opt_enftopic
)
6336 return channel_level_option(lvlEnfTopic
, CSFUNC_ARGS
);
6339 static MODCMD_FUNC(chan_opt_pubcmd
)
6341 return channel_level_option(lvlPubCmd
, CSFUNC_ARGS
);
6344 static MODCMD_FUNC(chan_opt_setters
)
6346 return channel_level_option(lvlSetters
, CSFUNC_ARGS
);
6349 static MODCMD_FUNC(chan_opt_userinfo
)
6351 return channel_level_option(lvlUserInfo
, CSFUNC_ARGS
);
6354 static MODCMD_FUNC(chan_opt_topicsnarf
)
6356 return channel_level_option(lvlTopicSnarf
, CSFUNC_ARGS
);
6359 static MODCMD_FUNC(chan_opt_inviteme
)
6361 return channel_level_option(lvlInviteMe
, CSFUNC_ARGS
);
6364 /* TODO: Make look like this when no args are
6366 * -X3- -------------------------------
6367 * -X3- BanTimeout: Bans are removed:
6368 * -X3- ----- * indicates current -----
6369 * -X3- 0: [*] Never.
6370 * -X3- 1: [ ] After 10 minutes.
6371 * -X3- 2: [ ] After 2 hours.
6372 * -X3- 3: [ ] After 4 hours.
6373 * -X3- 4: [ ] After 24 hours.
6374 * -X3- 5: [ ] After one week.
6375 * -X3- ------------- End -------------
6378 channel_multiple_option(enum charOption option
, struct userNode
*user
, struct chanNode
*channel
, int argc
, char *argv
[], struct svccmd
*cmd
)
6380 struct chanData
*cData
= channel
->channel_info
;
6381 int count
= charOptions
[option
].count
, index
;
6385 index
= atoi(argv
[1]);
6387 if(!isdigit(argv
[1][0]) || (index
< 0) || (index
>= count
))
6389 reply("CSMSG_INVALID_NUMERIC", index
);
6390 /* Show possible values. */
6391 for(index
= 0; index
< count
; index
++)
6392 reply(charOptions
[option
].format_name
, index
, user_find_message(user
, charOptions
[option
].values
[index
].format_name
));
6396 cData
->chOpts
[option
] = charOptions
[option
].values
[index
].value
;
6400 /* Find current option value. */
6403 (index
< count
) && (cData
->chOpts
[option
] != charOptions
[option
].values
[index
].value
);
6407 /* Somehow, the option value is corrupt; reset it to the default. */
6408 cData
->chOpts
[option
] = charOptions
[option
].default_value
;
6413 reply(charOptions
[option
].format_name
, index
, user_find_message(user
, charOptions
[option
].values
[index
].format_name
));
6417 static MODCMD_FUNC(chan_opt_automode
)
6419 return channel_multiple_option(chAutomode
, CSFUNC_ARGS
);
6422 static MODCMD_FUNC(chan_opt_protect
)
6424 return channel_multiple_option(chProtect
, CSFUNC_ARGS
);
6427 static MODCMD_FUNC(chan_opt_toys
)
6429 return channel_multiple_option(chToys
, CSFUNC_ARGS
);
6432 static MODCMD_FUNC(chan_opt_ctcpreaction
)
6434 return channel_multiple_option(chCTCPReaction
, CSFUNC_ARGS
);
6437 static MODCMD_FUNC(chan_opt_bantimeout
)
6439 return channel_multiple_option(chBanTimeout
, CSFUNC_ARGS
);
6442 static MODCMD_FUNC(chan_opt_topicrefresh
)
6444 return channel_multiple_option(chTopicRefresh
, CSFUNC_ARGS
);
6447 static MODCMD_FUNC(chan_opt_resync
)
6449 return channel_multiple_option(chResync
, CSFUNC_ARGS
);
6452 static struct svccmd_list set_shows_list
;
6455 handle_svccmd_unbind(struct svccmd
*target
) {
6457 for(ii
=0; ii
<set_shows_list
.used
; ++ii
)
6458 if(target
== set_shows_list
.list
[ii
])
6459 set_shows_list
.used
= 0;
6462 static CHANSERV_FUNC(cmd_set
)
6464 struct svccmd
*subcmd
;
6468 /* Check if we need to (re-)initialize set_shows_list. */
6469 if(!set_shows_list
.used
)
6471 if(!set_shows_list
.size
)
6473 set_shows_list
.size
= chanserv_conf
.set_shows
->used
;
6474 set_shows_list
.list
= calloc(set_shows_list
.size
, sizeof(set_shows_list
.list
[0]));
6476 for(ii
= 0; ii
< chanserv_conf
.set_shows
->used
; ii
++)
6478 const char *name
= chanserv_conf
.set_shows
->list
[ii
];
6479 sprintf(buf
, "%s %s", argv
[0], name
);
6480 subcmd
= dict_find(cmd
->parent
->commands
, buf
, NULL
);
6483 log_module(CS_LOG
, LOG_ERROR
, "Unable to find set option \"%s\".", name
);
6486 svccmd_list_append(&set_shows_list
, subcmd
);
6492 reply("CSMSG_CHANNEL_OPTIONS", channel
->name
);
6493 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
6495 for(ii
= 0; ii
< set_shows_list
.used
; ii
++)
6497 subcmd
= set_shows_list
.list
[ii
];
6498 subcmd
->command
->func(user
, channel
, 1, argv
+1, subcmd
);
6500 reply("CSMSG_CHANNEL_OPTIONS_END");
6504 sprintf(buf
, "%s %s", argv
[0], argv
[1]);
6505 subcmd
= dict_find(cmd
->parent
->commands
, buf
, NULL
);
6508 reply("CSMSG_INVALID_OPTION", argv
[1], argv
[0]);
6511 if((argc
> 2) && !check_user_level(channel
, user
, lvlSetters
, 1, 0))
6513 reply("CSMSG_NO_ACCESS");
6517 return subcmd
->command
->func(user
, channel
, argc
- 1, argv
+ 1, subcmd
);
6521 user_binary_option(char *name
, unsigned long mask
, struct userNode
*user
, struct chanNode
*channel
, int argc
, char *argv
[], struct svccmd
*cmd
)
6523 struct userData
*uData
;
6525 uData
= GetChannelAccess(channel
->channel_info
, user
->handle_info
);
6528 reply("CSMSG_NOT_USER", channel
->name
);
6534 /* Just show current option value. */
6536 else if(enabled_string(argv
[1]))
6538 uData
->flags
|= mask
;
6540 else if(disabled_string(argv
[1]))
6542 uData
->flags
&= ~mask
;
6546 reply("MSG_INVALID_BINARY", argv
[1]);
6550 reply(name
, user_find_message(user
, (uData
->flags
& mask
) ? "MSG_ON" : "MSG_OFF"));
6554 static MODCMD_FUNC(user_opt_autoop
)
6556 struct userData
*uData
;
6558 uData
= GetChannelAccess(channel
->channel_info
, user
->handle_info
);
6561 reply("CSMSG_NOT_USER", channel
->name
);
6564 if(uData
->access
< UL_HALFOP
/*channel->channel_info->lvlOpts[lvlGiveOps]*/)
6565 return user_binary_option("CSMSG_USET_AUTOVOICE", USER_AUTO_OP
, CSFUNC_ARGS
);
6567 return user_binary_option("CSMSG_USET_AUTOOP", USER_AUTO_OP
, CSFUNC_ARGS
);
6570 static MODCMD_FUNC(user_opt_autoinvite
)
6572 return user_binary_option("CSMSG_USET_AUTOINVITE", USER_AUTO_INVITE
, CSFUNC_ARGS
);
6575 static MODCMD_FUNC(user_opt_autojoin
)
6577 return user_binary_option("CSMSG_USET_AUTOJOIN", USER_AUTO_JOIN
, CSFUNC_ARGS
);
6580 static MODCMD_FUNC(user_opt_info
)
6582 struct userData
*uData
;
6585 uData
= GetChannelAccess(channel
->channel_info
, user
->handle_info
);
6589 /* If they got past the command restrictions (which require access)
6590 * but fail this test, we have some fool with security override on.
6592 reply("CSMSG_NOT_USER", channel
->name
);
6599 infoline
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
6600 if(strlen(infoline
) > channel
->channel_info
->maxsetinfo
)
6602 reply("CSMSG_INFOLINE_TOO_LONG", channel
->channel_info
->maxsetinfo
);
6605 bp
= strcspn(infoline
, "\001");
6608 reply("CSMSG_BAD_INFOLINE", infoline
[bp
]);
6613 if(infoline
[0] == '*' && infoline
[1] == 0)
6616 uData
->info
= strdup(infoline
);
6619 reply("CSMSG_USET_INFO", uData
->info
);
6621 reply("CSMSG_USET_INFO", user_find_message(user
, "MSG_NONE"));
6625 struct svccmd_list uset_shows_list
;
6627 static CHANSERV_FUNC(cmd_uset
)
6629 struct svccmd
*subcmd
;
6633 /* Check if we need to (re-)initialize uset_shows_list. */
6634 if(!uset_shows_list
.used
)
6638 "AutoOp", "AutoInvite", "AutoJoin", "Info"
6641 if(!uset_shows_list
.size
)
6643 uset_shows_list
.size
= ArrayLength(options
);
6644 uset_shows_list
.list
= calloc(uset_shows_list
.size
, sizeof(uset_shows_list
.list
[0]));
6646 for(ii
= 0; ii
< ArrayLength(options
); ii
++)
6648 const char *name
= options
[ii
];
6649 sprintf(buf
, "%s %s", argv
[0], name
);
6650 subcmd
= dict_find(cmd
->parent
->commands
, buf
, NULL
);
6653 log_module(CS_LOG
, LOG_ERROR
, "Unable to find uset option %s.", name
);
6656 svccmd_list_append(&uset_shows_list
, subcmd
);
6662 /* Do this so options are presented in a consistent order. */
6663 reply("CSMSG_USER_OPTIONS");
6664 for(ii
= 0; ii
< uset_shows_list
.used
; ii
++)
6665 uset_shows_list
.list
[ii
]->command
->func(user
, channel
, 1, argv
+1, uset_shows_list
.list
[ii
]);
6669 sprintf(buf
, "%s %s", argv
[0], argv
[1]);
6670 subcmd
= dict_find(cmd
->parent
->commands
, buf
, NULL
);
6673 reply("CSMSG_INVALID_OPTION", argv
[1], argv
[0]);
6677 return subcmd
->command
->func(user
, channel
, argc
- 1, argv
+ 1, subcmd
);
6680 static CHANSERV_FUNC(cmd_giveownership
)
6682 struct handle_info
*new_owner_hi
;
6683 struct userData
*new_owner
, *curr_user
;
6684 struct chanData
*cData
= channel
->channel_info
;
6685 struct do_not_register
*dnr
;
6686 struct giveownership
*giveownership
;
6687 unsigned int force
, override
;
6688 unsigned short co_access
, new_owner_old_access
;
6689 char transfer_reason
[MAXLEN
];
6692 curr_user
= GetChannelAccess(cData
, user
->handle_info
);
6693 force
= IsHelping(user
) && (argc
> 2) && !irccasecmp(argv
[2], "force");
6695 struct userData
*uData
= _GetChannelUser(channel
->channel_info
, user
->handle_info
, 1, 0);
6696 override
= ((cmd
->effective_flags
& MODCMD_REQUIRE_CHANUSER
)
6697 && (uData
->access
> 500)
6698 && (!(uData
= _GetChannelUser(channel
->channel_info
, user
->handle_info
, 0, 0))
6699 || uData
->access
< 500));
6702 if(!curr_user
|| (curr_user
->access
!= UL_OWNER
))
6704 struct userData
*owner
= NULL
;
6705 for(curr_user
= channel
->channel_info
->users
;
6707 curr_user
= curr_user
->next
)
6709 if(curr_user
->access
!= UL_OWNER
)
6713 reply("CSMSG_MULTIPLE_OWNERS", channel
->name
);
6720 else if (!force
&& (now
< (time_t)(cData
->ownerTransfer
+ chanserv_conf
.giveownership_period
)))
6722 char delay
[INTERVALLEN
];
6723 intervalString(delay
, cData
->ownerTransfer
+ chanserv_conf
.giveownership_period
- now
, user
->handle_info
);
6724 reply("CSMSG_TRANSFER_WAIT", delay
, channel
->name
);
6728 reply("CSMSG_NO_OWNER", channel
->name
);
6731 if(!(new_owner_hi
= modcmd_get_handle_info(user
, argv
[1])))
6733 if(new_owner_hi
== user
->handle_info
)
6735 reply("CSMSG_NO_TRANSFER_SELF");
6738 new_owner
= GetChannelAccess(cData
, new_owner_hi
);
6743 new_owner
= add_channel_user(cData
, new_owner_hi
, UL_COOWNER
, 0, NULL
, 0);
6747 reply("CSMSG_NO_CHAN_USER", new_owner_hi
->handle
, channel
->name
);
6751 if((chanserv_get_owned_count(new_owner_hi
) >= chanserv_conf
.max_owned
) && !force
)
6753 reply("CSMSG_OWN_TOO_MANY", new_owner_hi
->handle
, chanserv_conf
.max_owned
);
6756 if((dnr
= chanserv_is_dnr(NULL
, new_owner_hi
)) && !force
) {
6757 if(!IsHelping(user
))
6758 reply("CSMSG_DNR_ACCOUNT", new_owner_hi
->handle
);
6760 chanserv_show_dnrs(user
, cmd
, NULL
, new_owner_hi
->handle
);
6764 new_owner_old_access
= new_owner
->access
;
6765 if(new_owner
->access
>= UL_COOWNER
)
6766 co_access
= new_owner
->access
;
6768 co_access
= UL_COOWNER
;
6769 new_owner
->access
= UL_OWNER
;
6771 curr_user
->access
= co_access
;
6772 cData
->ownerTransfer
= now
;
6774 giveownership
= calloc(1, sizeof(*giveownership
));
6775 giveownership
->issued
= now
;
6776 giveownership
->old_owner
= strdup(curr_user
->handle
->handle
);
6777 giveownership
->target
= strdup(new_owner_hi
->handle
);
6778 giveownership
->target_access
= new_owner_old_access
;
6781 if(argc
> (2 + force
))
6783 unsplit_string(argv
+ 2 + force
, argc
- 2 - force
, transfer_reason
);
6784 giveownership
->reason
= strdup(transfer_reason
);
6786 giveownership
->staff_issuer
= strdup(user
->handle_info
->handle
);
6789 giveownership
->previous
= channel
->channel_info
->giveownership
;
6790 channel
->channel_info
->giveownership
= giveownership
;
6792 reply("CSMSG_OWNERSHIP_GIVEN", channel
->name
, new_owner_hi
->handle
);
6793 global_message_args(MESSAGE_RECIPIENT_OPERS
| MESSAGE_RECIPIENT_HELPERS
, "CSMSG_OWNERSHIP_TRANSFERRED",
6794 channel
->name
, new_owner_hi
->handle
, user
->handle_info
->handle
);
6799 chanserv_expire_user_suspension(void *data
)
6801 struct userData
*target
= data
;
6803 target
->expires
= 0;
6804 target
->flags
&= ~USER_SUSPENDED
;
6807 static CHANSERV_FUNC(cmd_suspend
)
6809 struct handle_info
*hi
;
6810 struct userData
*self
, *target
;
6814 if(!(hi
= modcmd_get_handle_info(user
, argv
[1]))) return 0;
6815 self
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
6816 if(!(target
= GetTrueChannelAccess(channel
->channel_info
, hi
)))
6818 reply("CSMSG_NO_CHAN_USER", hi
->handle
, channel
->name
);
6821 if(target
->access
>= self
->access
)
6823 reply("MSG_USER_OUTRANKED", hi
->handle
);
6826 if(target
->flags
& USER_SUSPENDED
)
6828 reply("CSMSG_ALREADY_SUSPENDED", hi
->handle
);
6833 target
->present
= 0;
6836 if(!strcmp(argv
[2], "0"))
6840 unsigned int duration
;
6841 if(!(duration
= ParseInterval(argv
[2])))
6843 reply("MSG_INVALID_DURATION", argv
[2]);
6846 expiry
= now
+ duration
;
6849 target
->expires
= expiry
;
6852 timeq_add(target
->expires
, chanserv_expire_user_suspension
, target
);
6854 target
->flags
|= USER_SUSPENDED
;
6855 reply("CSMSG_USER_SUSPENDED", hi
->handle
, channel
->name
);
6859 static CHANSERV_FUNC(cmd_unsuspend
)
6861 struct handle_info
*hi
;
6862 struct userData
*self
, *target
;
6865 if(!(hi
= modcmd_get_handle_info(user
, argv
[1]))) return 0;
6866 self
= GetChannelUser(channel
->channel_info
, user
->handle_info
);
6867 if(!(target
= GetTrueChannelAccess(channel
->channel_info
, hi
)))
6869 reply("CSMSG_NO_CHAN_USER", hi
->handle
, channel
->name
);
6872 if(target
->access
>= self
->access
)
6874 reply("MSG_USER_OUTRANKED", hi
->handle
);
6877 if(!(target
->flags
& USER_SUSPENDED
))
6879 reply("CSMSG_NOT_SUSPENDED", hi
->handle
);
6882 target
->flags
&= ~USER_SUSPENDED
;
6883 scan_user_presence(target
, NULL
);
6884 timeq_del(target
->expires
, chanserv_expire_user_suspension
, target
, 0);
6885 reply("CSMSG_USER_UNSUSPENDED", hi
->handle
, channel
->name
);
6889 static MODCMD_FUNC(cmd_deleteme
)
6891 struct handle_info
*hi
;
6892 struct userData
*target
;
6893 const char *confirm_string
;
6894 unsigned short access
;
6897 hi
= user
->handle_info
;
6898 if(!(target
= GetTrueChannelAccess(channel
->channel_info
, hi
)))
6900 reply("CSMSG_NO_CHAN_USER", hi
->handle
, channel
->name
);
6903 if(target
->access
== UL_OWNER
)
6905 reply("CSMSG_NO_OWNER_DELETEME", channel
->name
);
6908 confirm_string
= make_confirmation_string(target
);
6909 if((argc
< 2) || strcmp(argv
[1], confirm_string
))
6911 reply("CSMSG_CONFIRM_DELETEME", confirm_string
);
6914 access
= target
->access
;
6915 channel_name
= strdup(channel
->name
);
6916 del_channel_user(target
, 1);
6917 reply("CSMSG_DELETED_YOU", access
, channel_name
);
6923 chanserv_refresh_topics(UNUSED_ARG(void *data
))
6925 unsigned int refresh_num
= (now
- self
->link
) / chanserv_conf
.refresh_period
;
6926 struct chanData
*cData
;
6929 for(cData
= channelList
; cData
; cData
= cData
->next
)
6931 if(IsSuspended(cData
))
6933 opt
= cData
->chOpts
[chTopicRefresh
];
6936 if((refresh_num
- cData
->last_refresh
) < (unsigned int)(1 << (opt
- '1')))
6939 SetChannelTopic(cData
->channel
, chanserv
, chanserv
, cData
->topic
, 1);
6940 cData
->last_refresh
= refresh_num
;
6942 timeq_add(now
+ chanserv_conf
.refresh_period
, chanserv_refresh_topics
, NULL
);
6946 chanserv_auto_resync(UNUSED_ARG(void *data
))
6948 unsigned int refresh_num
= (now
- self
->link
) / chanserv_conf
.refresh_period
;
6949 struct chanData
*cData
;
6952 for(cData
= channelList
; cData
; cData
= cData
->next
)
6954 if(IsSuspended(cData
)) continue;
6955 opt
= cData
->chOpts
[chResync
];
6956 if(opt
== 'n') continue;
6957 if((refresh_num
- cData
->last_resync
) < (unsigned int)(1 << (opt
- '1'))) continue;
6958 resync_channel(cData
->channel
);
6959 cData
->last_resync
= refresh_num
;
6961 timeq_add(now
+ chanserv_conf
.refresh_period
, chanserv_auto_resync
, NULL
);
6964 static CHANSERV_FUNC(cmd_unf
)
6968 char response
[MAXLEN
];
6969 const char *fmt
= user_find_message(user
, "CSMSG_UNF_RESPONSE");
6970 sprintf(response
, "\ 2%s\ 2: %s", user
->nick
, fmt
);
6971 irc_privmsg(cmd
->parent
->bot
, channel
->name
, response
);
6974 reply("CSMSG_UNF_RESPONSE");
6978 static CHANSERV_FUNC(cmd_ping
)
6982 char response
[MAXLEN
];
6983 const char *fmt
= user_find_message(user
, "CSMSG_PING_RESPONSE");
6984 sprintf(response
, "\ 2%s\ 2: %s", user
->nick
, fmt
);
6985 irc_privmsg(cmd
->parent
->bot
, channel
->name
, response
);
6988 reply("CSMSG_PING_RESPONSE");
6992 static CHANSERV_FUNC(cmd_wut
)
6996 char response
[MAXLEN
];
6997 const char *fmt
= user_find_message(user
, "CSMSG_WUT_RESPONSE");
6998 sprintf(response
, "\ 2%s\ 2: %s", user
->nick
, fmt
);
6999 irc_privmsg(cmd
->parent
->bot
, channel
->name
, response
);
7002 reply("CSMSG_WUT_RESPONSE");
7006 static CHANSERV_FUNC(cmd_roulette
)
7009 struct chanData
*cData
= channel
->channel_info
;
7012 if (cData
->roulette_chamber
) {
7013 DelUser(user
, chanserv
, 1, "BANG - Don't stuff bullets into a loaded gun");
7017 send_target_message(1, channel
->name
, cmd
->parent
->bot
, "CSMSG_ROULETTE_LOADS");
7018 cData
->roulette_chamber
= 1 + rand() % 6;
7024 static CHANSERV_FUNC(cmd_shoot
)
7027 struct chanData
*cData
= channel
->channel_info
;
7029 if (cData
->roulette_chamber
<= 0) {
7030 reply("CSMSG_ROULETTE_NEW");
7034 cData
->roulette_chamber
--;
7036 if (cData
->roulette_chamber
== 0) {
7037 reply("CSMSG_ROULETTE_BANG");
7038 reply("CSMSG_ROULETTE_BETTER_LUCK", user
->nick
);
7039 DelUser(user
, chanserv
, 1, "BANG!!!!");
7041 reply("CSMSG_ROULETTE_CLICK");
7048 chanserv_remove_abuse(void *data
)
7050 char *remnick
= data
;
7051 struct userNode
*user
;
7052 /* sometimes the clone was killed and maybe even the user took their nick back
7053 * (ie, an oper) so dont kill them here after all unless they are local. */
7054 if( (user
= GetUserH(remnick
)) )
7056 DelUser(user
, NULL
, 1, "");
7059 int lamepart(struct userNode
*nick
) {
7060 struct modeNode
*mn
;
7061 unsigned int count
, n
;
7063 for (n
=count
=0; n
<nick
->channels
.used
; n
++) {
7064 mn
= nick
->channels
.list
[n
];
7065 irc_svspart(chanserv
, nick
, mn
->channel
);
7071 static CHANSERV_FUNC(cmd_spin
)
7076 int type
, lamep
= 1;
7079 tstr
= conf_get_data("server/type", RECDB_QSTRING
);
7086 int wheel
= 1 + rand() % 12;
7088 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_WHEEL1", user
->nick
);
7089 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_WHEEL2");
7090 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_WHEEL3");
7093 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_1");
7095 irc_kill(chanserv
, user
, "Connection reset by peer");
7097 sputsock("%s SQ %s :Connection reset by peer", self
->numeric
, user
->numeric
);
7100 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_2");
7104 sputsock("%s SJ %s 0 "FMT_TIME_T
, self
->numeric
, user
->numeric
, now
);
7107 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_3");
7111 sputsock("%s SJ %s 0 "FMT_TIME_T
, self
->numeric
, user
->numeric
, now
);
7114 char target
[IRC_NTOP_MAX_SIZE
+ 3] = { '*', '@', '\0' };
7115 int wtime
= 120 + rand() % 600;
7117 strcpy(target
+ 2, user
->hostname
);
7118 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_4");
7120 gline_add(chanserv
->nick
, target
, wtime
, "Reward for spinning the wheel of misfortune!", now
, 1, 0);
7121 irc_kill(chanserv
, user
, "Reward for spinning the wheel of misfortune!");
7124 char target
[IRC_NTOP_MAX_SIZE
+ 3] = { '*', '@', '\0' };
7125 int wtime
= 120 + rand() % 600;
7127 strcpy(target
+ 2, user
->hostname
);
7128 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_5");
7130 shun_add(chanserv
->nick
, target
, wtime
, "Reward for spinning the wheel of misfortune!", now
, 1);
7133 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_6");
7141 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_7");
7142 while(complete
!= 1) {
7143 if (rndchans
!= 15) {
7144 chango
= 120 + rand() % 600;
7145 sputsock("%s SJ %s #%d %ld", self
->numeric
, user
->numeric
, chango
, now
);
7148 if (roundz0r
!= 1) {
7152 sputsock("%s SJ %s 0 "FMT_TIME_T
, self
->numeric
, user
->numeric
, now
);
7159 sputsock("%s SJ %s 0 "FMT_TIME_T
, self
->numeric
, user
->numeric
, now
);
7166 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_8");
7167 irc_swhois(chanserv
, user
, "is being defecated on by services");
7170 unsigned int count
, n
;
7171 struct modeNode
*mn
;
7173 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_9");
7175 for (n
=count
=0; n
<user
->channels
.used
; n
++) {
7176 mn
= user
->channels
.list
[n
];
7177 irc_kick(chanserv
, user
, mn
->channel
, "Reward for spinning the wheel of misfortune!");
7181 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_10");
7183 char *oldnick
= NULL
;
7184 char *oldident
= NULL
;
7185 char *oldhost
= NULL
;
7186 char abusednick
[NICKLEN
] = "";
7187 int abusednum
= time(NULL
);
7188 struct userNode
*clone
;
7190 oldnick
= strdup(user
->nick
);
7191 oldident
= strdup(user
->ident
);
7192 oldhost
= strdup(user
->hostname
);
7194 snprintf(abusednick
, NICKLEN
, "Abused%d", abusednum
+(1 + rand() % 120));
7196 log_module(MAIN_LOG
, LOG_DEBUG
, "Abused Nick: %s, Client Nick: %s", abusednick
, user
->nick
);
7197 snprintf(abusednick
, NICKLEN
, "Abused%d", abusednum
+(1 + rand() % 120));
7198 if (user
->nick
!= abusednick
)
7202 SVSNickChange(user
, abusednick
);
7203 irc_svsnick(chanserv
, user
, abusednick
);
7205 clone
= AddClone(oldnick
, oldident
, oldhost
, "I got abused by the wheel of misfortune :D");
7206 timeq_add(now
+ 300, chanserv_remove_abuse
, clone
->nick
);
7209 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_11");
7211 irc_kill(chanserv
, user
, "Reward for spinning the wheel of misfortune!");
7214 int gagged
, ignoretime
= 0;
7215 char target
[IRC_NTOP_MAX_SIZE
+ 13] = { '+', 'b', ' ', '*', '!', '*', '@', '\0' };
7217 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_12");
7219 strcpy(target
+ 4, user
->hostname
);
7221 ignoretime
= now
+ (1 + rand() % 120);
7223 gagged
= gag_create(target
, "wheelofabuse", "Reward for spinning the wheel of misfortune!", ignoretime
);
7226 unsigned int count
, n
;
7227 struct modeNode
*mn
;
7228 char target
[IRC_NTOP_MAX_SIZE
+ 1];
7230 send_target_message(1, channel
->name
, chanserv
, "CSMSG_SPIN_13");
7232 snprintf(target
, sizeof(target
), "+b *!*@%s", user
->hostname
);
7233 for (n
=count
=0; n
<user
->channels
.used
; n
++) {
7234 mn
= user
->channels
.list
[n
];
7235 irc_mode(chanserv
, mn
->channel
, target
);
7236 irc_kick(chanserv
, user
, mn
->channel
, "Reward for spinning the wheel of misfortune!");
7244 static CHANSERV_FUNC(cmd_8ball
)
7246 unsigned int i
, j
, accum
;
7251 for(i
=1; i
<argc
; i
++)
7252 for(j
=0; argv
[i
][j
]; j
++)
7253 accum
= (accum
<< 5) - accum
+ toupper(argv
[i
][j
]);
7254 resp
= chanserv_conf
.eightball
->list
[accum
% chanserv_conf
.eightball
->used
];
7257 char response
[MAXLEN
];
7258 sprintf(response
, "\ 2%s\ 2: %s", user
->nick
, resp
);
7259 irc_privmsg(cmd
->parent
->bot
, channel
->name
, response
);
7262 send_message_type(4, user
, cmd
->parent
->bot
, "%s", resp
);
7266 #else /* Use cool 8ball instead */
7268 void eightball(char *outcome
, int method
, unsigned int seed
)
7272 #define NUMOFCOLORS 18
7273 char ballcolors
[50][50] = {"blue", "red", "green", "yellow",
7274 "white", "black", "grey", "brown",
7275 "yellow", "pink", "purple", "orange", "teal", "burgandy",
7276 "fuchsia","turquoise","magenta", "cyan"};
7277 #define NUMOFLOCATIONS 50
7278 char balllocations
[50][55] = {
7279 "Locke's house", "Oregon", "California", "Indiana", "Canada",
7280 "Russia", "Japan", "Florida", "the Bahamas", "Hiroshima",
7281 "the Caribbean", "the Everglades", "your head", "your pants", "your school",
7282 "the Statue of Liberty", "Mt. Fugi", "your mother's house", "IRC", "OSU",
7283 "Locke's cat", "the closet", "the washroom", "the lake", "Spain",
7284 "the bathtub", "the toilet", "the sewer", "a horse", "Jupiter",
7285 "Uranus", "Pluto", "a dark place", "your undies", "your shirt",
7286 "your bra", "your hair", "your bed", "the couch", "the wall",
7287 "Reed", "here --> [X]", "your brain", "Italy", "the Netherlands",
7288 "Mars", "my hardware", "the bar", "Neverland Ranch", "Germany" };
7289 #define NUMOFPREPS 15
7290 char ballpreps
[50][50] = {
7291 "Near", "Somewhere near", "In", "In", "In",
7292 "In", "Hiding in", "Under", "Next to", "Over",
7293 "Crying in", "Right beside", "Nowhere near", "North of", "Trying to find"};
7294 #define NUMOFNUMS 34
7295 char ballnums
[50][50] = {
7296 "A hundred", "A thousand", "A few", "42",
7297 "About 1", "About 2", "About 3", "About 4", "About 5", "About 6", "About 7", "About 8", "About 9", "About 10",
7298 "1", "2", "3", "4", "5", "6", "7", "8", "9", "Ten",
7299 "1", "2", "3", "4", "5", "6", "7", "8", "9", "Ten",
7301 #define NUMOFMULTS 8
7302 char ballmults
[50][50] = { " million", " or so", " thousand", "", " or less", " or more", "", ""};
7305 * 0: normal (Not used in x3)
7312 if (method
== 1) /* A Color */
7316 answer
= (rand() % 12); /* Make sure this is the # of entries */
7319 case 0: strcpy(tmp
, "Very bright %s, I'd say.");
7321 case 1: strcpy(tmp
, "Sort of a light %s color.");
7323 case 2: strcpy(tmp
, "Dark and dreary %s.");
7325 case 3: strcpy(tmp
, "Quite a pale shade of %s.");
7327 case 4: strcpy(tmp
, "A gross kind of mucky %s.");
7329 case 5: strcpy(tmp
, "Brilliant whiteish %s.");
7331 case 6: case 7: case 8: case 9: strcpy(tmp
, "%s.");
7333 case 10: strcpy(tmp
, "Solid %s.");
7335 case 11: strcpy(tmp
, "Transparent %s.");
7337 default: strcpy(outcome
, "An invalid random number was generated.");
7340 sprintf(outcome
, tmp
, ballcolors
[rand() % NUMOFCOLORS
]);
7343 else if (method
== 2) /* Location */
7345 sprintf(outcome
, "%s %s.", ballpreps
[rand() % NUMOFPREPS
], balllocations
[rand() % NUMOFLOCATIONS
]);
7347 else if (method
== 3) /* Number of ___ */
7349 sprintf(outcome
, "%s%s.", ballnums
[rand() % NUMOFNUMS
], ballmults
[rand() % NUMOFMULTS
]);
7353 //Debug(DBGWARNING, "Error in 8ball.");
7358 static CHANSERV_FUNC(cmd_8ball
)
7360 char *word1
, *word2
, *word3
;
7361 static char eb
[MAXLEN
];
7362 unsigned int accum
, i
, j
;
7366 for(i
=1; i
<argc
; i
++)
7367 for(j
=0; argv
[i
][j
]; j
++)
7368 accum
= (accum
<< 5) - accum
+ toupper(argv
[i
][j
]);
7370 accum
+= time(NULL
)/3600;
7372 word2
= argc
>2?argv
[2]:"";
7373 word3
= argc
>3?argv
[3]:"";
7376 if((word2
) && strcasecmp(word1
, "what") == 0 && strcasecmp(word2
, "color") == 0)
7377 eightball(eb
, 1, accum
);
7378 else if((word3
) && strcasecmp(word1
, "what's") == 0 && strcasecmp(word2
, "the") == 0 && strcasecmp(word3
, "color") == 0)
7379 eightball(eb
, 1, accum
);
7380 else if((word3
) && strcasecmp(word1
, "whats") == 0 && strcasecmp(word2
, "the") == 0 && strcasecmp(word3
, "color") == 0)
7381 eightball(eb
, 1, accum
);
7382 /*** LOCATION *****/
7387 (strcasecmp(word1
, "where") == 0) &&
7388 (strcasecmp(word2
, "is") == 0)
7392 strcasecmp(word1
, "where's") == 0
7395 eightball(eb
, 2, accum
);
7397 else if((word2
) && strcasecmp(word1
, "how") == 0 && strcasecmp(word2
, "many") == 0)
7398 eightball(eb
, 3, accum
);
7402 /* Generic 8ball question.. so pull from x3.conf srvx style */
7405 resp
= chanserv_conf
.eightball
->list
[accum
% chanserv_conf
.eightball
->used
];
7408 char response
[MAXLEN
];
7409 sprintf(response
, "\002%s\002: %s", user
->nick
, resp
);
7410 irc_privmsg(cmd
->parent
->bot
, channel
->name
, response
);
7413 send_message_type(4, user
, cmd
->parent
->bot
, "%s", resp
);
7419 char response
[MAXLEN
];
7420 sprintf(response
, "\002%s\002: %s", user
->nick
, eb
);
7421 irc_privmsg(cmd
->parent
->bot
, channel
->name
, response
);
7424 send_message_type(4, user
, cmd
->parent
->bot
, "%s", eb
);
7429 static CHANSERV_FUNC(cmd_d
)
7431 unsigned long sides
, count
, modifier
, ii
, total
;
7432 char response
[MAXLEN
], *sep
;
7436 if((count
= strtoul(argv
[1], &sep
, 10)) < 1)
7446 else if(((sep
[0] == 'd') || (sep
[0] == 'D')) && isdigit(sep
[1])
7447 && (sides
= strtoul(sep
+1, &sep
, 10)) > 1)
7451 else if((sep
[0] == '-') && isdigit(sep
[1]))
7452 modifier
= strtoul(sep
, NULL
, 10);
7453 else if((sep
[0] == '+') && isdigit(sep
[1]))
7454 modifier
= strtoul(sep
+1, NULL
, 10);
7461 reply("CSMSG_BAD_DIE_FORMAT", argv
[1]);
7466 reply("CSMSG_BAD_DICE_COUNT", count
, 10);
7469 for(total
= ii
= 0; ii
< count
; ++ii
)
7470 total
+= (rand() % sides
) + 1;
7473 if((count
> 1) || modifier
)
7475 fmt
= user_find_message(user
, "CSMSG_DICE_ROLL");
7476 sprintf(response
, fmt
, total
, count
, sides
, modifier
);
7480 fmt
= user_find_message(user
, "CSMSG_DIE_ROLL");
7481 sprintf(response
, fmt
, total
, sides
);
7484 send_channel_message(channel
, cmd
->parent
->bot
, "$b%s$b: %s", user
->nick
, response
);
7486 send_message_type(4, user
, cmd
->parent
->bot
, "%s", response
);
7490 static CHANSERV_FUNC(cmd_huggle
)
7492 /* CTCP must be via PRIVMSG, never notice */
7494 send_target_message(1, channel
->name
, cmd
->parent
->bot
, "CSMSG_HUGGLES_HIM", user
->nick
);
7496 send_target_message(1, user
->nick
, cmd
->parent
->bot
, "CSMSG_HUGGLES_YOU");
7500 static CHANSERV_FUNC(cmd_calc
)
7502 char response
[MAXLEN
];
7505 do_math(response
, unsplit_string(argv
+ 1, argc
- 1, NULL
));
7508 send_channel_message(channel
, cmd
->parent
->bot
, "$b%s$b: %s", user
->nick
, response
);
7510 send_message_type(4, user
, cmd
->parent
->bot
, "%s", response
);
7514 static CHANSERV_FUNC(cmd_reply
)
7518 unsplit_string(argv
+ 1, argc
- 1, NULL
);
7521 send_channel_message(channel
, cmd
->parent
->bot
, "$b%s$b: %s", user
->nick
, unsplit_string(argv
+ 1, argc
- 1, NULL
));
7523 send_message_type(4, user
, cmd
->parent
->bot
, "%s", unsplit_string(argv
+ 1, argc
- 1, NULL
));
7528 chanserv_adjust_limit(void *data
)
7530 struct mod_chanmode change
;
7531 struct chanData
*cData
= data
;
7532 struct chanNode
*channel
= cData
->channel
;
7535 if(IsSuspended(cData
))
7538 cData
->limitAdjusted
= now
;
7539 limit
= channel
->members
.used
+ chanserv_conf
.adjust_threshold
+ 5;
7540 if(cData
->modes
.modes_set
& MODE_LIMIT
)
7542 if(limit
> cData
->modes
.new_limit
)
7543 limit
= cData
->modes
.new_limit
;
7544 else if(limit
== cData
->modes
.new_limit
)
7548 mod_chanmode_init(&change
);
7549 change
.modes_set
= MODE_LIMIT
;
7550 change
.new_limit
= limit
;
7551 mod_chanmode_announce(chanserv
, channel
, &change
);
7555 handle_new_channel(struct chanNode
*channel
)
7557 struct chanData
*cData
;
7559 if(!(cData
= channel
->channel_info
))
7562 if(cData
->modes
.modes_set
|| cData
->modes
.modes_clear
)
7563 mod_chanmode_announce(chanserv
, cData
->channel
, &cData
->modes
);
7565 if(self
->uplink
&& !self
->uplink
->burst
&& channel
->channel_info
->topic
)
7566 SetChannelTopic(channel
, chanserv
, chanserv
, channel
->channel_info
->topic
, 1);
7570 trace_check_bans(struct userNode
*user
, struct chanNode
*chan
)
7572 struct banData
*bData
;
7573 struct mod_chanmode
*change
;
7575 change
= find_matching_bans(&chan
->banlist
, user
, NULL
);
7580 if (chan
->channel_info
) {
7581 for(bData
= chan
->channel_info
->bans
; bData
; bData
= bData
->next
) {
7583 if(!user_matches_glob(user
, bData
->mask
, MATCH_USENICK
))
7595 check_bans(struct userNode
*user
, const char *channel
)
7597 struct chanNode
*chan
;
7598 struct mod_chanmode change
;
7599 struct chanData
*cData
;
7600 struct banData
*bData
;
7602 if (!(chan
= GetChannel(channel
)))
7605 if(!(cData
= chan
->channel_info
))
7608 mod_chanmode_init(&change
);
7611 if(chan
->banlist
.used
< MAXBANS
)
7613 /* Not joining through a ban. */
7614 for(bData
= cData
->bans
;
7615 bData
&& !user_matches_glob(user
, bData
->mask
, MATCH_USENICK
);
7616 bData
= bData
->next
);
7620 char kick_reason
[MAXLEN
];
7621 sprintf(kick_reason
, "(%s) %s", bData
->owner
, bData
->reason
);
7623 bData
->triggered
= now
;
7624 if(bData
!= cData
->bans
)
7626 /* Shuffle the ban to the head of the list. */
7628 bData
->next
->prev
= bData
->prev
;
7630 bData
->prev
->next
= bData
->next
;
7633 bData
->next
= cData
->bans
;
7636 cData
->bans
->prev
= bData
;
7638 cData
->bans
= bData
;
7641 change
.args
[0].mode
= MODE_BAN
;
7642 change
.args
[0].u
.hostmask
= bData
->mask
;
7643 mod_chanmode_announce(chanserv
, chan
, &change
);
7644 KickChannelUser(user
, chan
, chanserv
, kick_reason
);
7652 channel_user_is_exempt(struct userNode
*user
, struct chanNode
*channel
)
7655 for(ii
= 0; ii
< channel
->exemptlist
.used
; ii
++)
7657 if(user_matches_glob(user
, channel
->exemptlist
.list
[ii
]->exempt
, MATCH_USENICK
))
7664 /* Welcome to my worst nightmare. Warning: Read (or modify)
7665 the code below at your own risk. */
7667 handle_join(struct modeNode
*mNode
)
7669 struct mod_chanmode change
;
7670 struct userNode
*user
= mNode
->user
;
7671 struct chanNode
*channel
= mNode
->channel
;
7672 struct chanData
*cData
;
7673 struct userData
*uData
= NULL
;
7674 struct banData
*bData
;
7675 struct handle_info
*handle
;
7676 unsigned int modes
= 0, info
= 0;
7679 if(IsLocal(user
) || !channel
|| !channel
->channel_info
|| IsSuspended(channel
->channel_info
))
7682 cData
= channel
->channel_info
;
7683 if(channel
->members
.used
> cData
->max
)
7684 cData
->max
= channel
->members
.used
;
7687 /* Check for bans. If they're joining through a ban, one of two
7689 * 1: Join during a netburst, by riding the break. Kick them
7690 * unless they have ops or voice in the channel.
7691 * 2: They're allowed to join through the ban (an invite in
7692 * ircu2.10, or a +e on Hybrid, or something).
7693 * If they're not joining through a ban, and the banlist is not
7694 * full, see if they're on the banlist for the channel. If so,
7697 if(user
->uplink
->burst
&& !mNode
->modes
)
7700 for(ii
= 0; ii
< channel
->banlist
.used
; ii
++)
7702 if(user_matches_glob(user
, channel
->banlist
.list
[ii
]->ban
, MATCH_USENICK
))
7704 /* Riding a netburst. Naughty. */
7705 KickChannelUser(user
, channel
, chanserv
, "User from far side of netsplit should have been banned - bye.");
7712 if(user
->handle_info
)
7714 handle
= user
->handle_info
;
7717 uData
= GetTrueChannelAccess(cData
, handle
);
7722 mod_chanmode_init(&change
);
7725 /* TODO: maybe only people above inviteme level? -Rubin */
7726 /* We don't kick people with access */
7727 if(!uData
&& !channel_user_is_exempt(user
, channel
))
7729 if(channel
->banlist
.used
< MAXBANS
)
7731 /* Not joining through a ban. */
7732 for(bData
= cData
->bans
;
7733 bData
&& !user_matches_glob(user
, bData
->mask
, MATCH_USENICK
);
7734 bData
= bData
->next
);
7738 char kick_reason
[MAXLEN
];
7739 sprintf(kick_reason
, "(%s) %s", bData
->owner
, bData
->reason
);
7741 bData
->triggered
= now
;
7742 if(bData
!= cData
->bans
)
7744 /* Shuffle the ban to the head of the list. */
7746 bData
->next
->prev
= bData
->prev
;
7748 bData
->prev
->next
= bData
->next
;
7751 bData
->next
= cData
->bans
;
7754 cData
->bans
->prev
= bData
;
7755 cData
->bans
= bData
;
7758 change
.args
[0].mode
= MODE_BAN
;
7759 change
.args
[0].u
.hostmask
= bData
->mask
;
7760 mod_chanmode_announce(chanserv
, channel
, &change
);
7761 KickChannelUser(user
, channel
, chanserv
, kick_reason
);
7767 /* ChanServ will not modify the limits in join-flooded channels.
7768 It will also skip DynLimit processing when the user (or srvx)
7769 is bursting in, because there are likely more incoming. */
7770 if((cData
->flags
& CHANNEL_DYNAMIC_LIMIT
)
7771 && !user
->uplink
->burst
7772 && !channel
->join_flooded
7773 && (channel
->limit
- channel
->members
.used
) < chanserv_conf
.adjust_threshold
)
7775 /* The user count has begun "bumping" into the channel limit,
7776 so set a timer to raise the limit a bit. Any previous
7777 timers are removed so three incoming users within the delay
7778 results in one limit change, not three. */
7780 timeq_del(0, chanserv_adjust_limit
, cData
, TIMEQ_IGNORE_WHEN
);
7781 timeq_add(now
+ chanserv_conf
.adjust_delay
, chanserv_adjust_limit
, cData
);
7784 /* Give automodes exept during join-floods */
7785 if(!channel
->join_flooded
)
7787 if(cData
->chOpts
[chAutomode
] == 'v')
7788 modes
|= MODE_VOICE
;
7789 else if(cData
->chOpts
[chAutomode
] == 'h')
7790 modes
|= MODE_HALFOP
;
7791 else if(cData
->chOpts
[chAutomode
] == 'o')
7792 modes
|= MODE_CHANOP
;
7795 greeting
= cData
->greeting
;
7796 if(user
->handle_info
)
7798 /* handle = user->handle_info; */
7800 if(IsHelper(user
) && !IsHelping(user
))
7803 for(ii
= 0; ii
< chanserv_conf
.support_channels
.used
; ++ii
)
7805 if(channel
== chanserv_conf
.support_channels
.list
[ii
])
7807 HANDLE_SET_FLAG(user
->handle_info
, HELPING
);
7813 /* uData = GetTrueChannelAccess(cData, handle); */
7814 if(uData
&& !IsUserSuspended(uData
))
7816 /* non users getting automodes are handled above. */
7817 if(IsUserAutoOp(uData
) && cData
->chOpts
[chAutomode
] != 'n')
7819 /* just op everyone with access */
7820 if(uData
->access
>= UL_PEON
&& cData
->chOpts
[chAutomode
] == 'l')
7821 modes
|= MODE_VOICE
;
7822 /* or do their access level */
7823 else if(uData
->access
>= UL_OP
)
7824 modes
|= MODE_CHANOP
;
7825 else if(uData
->access
>= UL_HALFOP
)
7826 modes
|= MODE_HALFOP
;
7827 else if(uData
->access
>= UL_PEON
&& cData
->chOpts
[chAutomode
] != 'm')
7828 modes
|= MODE_VOICE
;
7830 if(uData
->access
>= UL_PRESENT
)
7831 cData
->visited
= now
;
7832 if(cData
->user_greeting
)
7833 greeting
= cData
->user_greeting
;
7835 && (uData
->access
>= cData
->lvlOpts
[lvlUserInfo
])
7836 && ((now
- uData
->seen
) >= chanserv_conf
.info_delay
)
7844 /* If user joining normally (not during burst), apply op or voice,
7845 * and send greeting/userinfo as appropriate.
7847 if(!user
->uplink
->burst
)
7851 /* -- I'd rather have ops get voice too, if automode is v. -Rubin
7852 if(modes & MODE_CHANOP) {
7853 modes &= ~MODE_HALFOP;
7854 modes &= ~MODE_VOICE;
7857 change
.args
[0].mode
= modes
;
7858 change
.args
[0].u
.member
= mNode
;
7859 mod_chanmode_announce(chanserv
, channel
, &change
);
7862 send_message_type(4, user
, chanserv
, "(%s) %s", channel
->name
, greeting
);
7864 send_target_message(5, channel
->name
, chanserv
, "[%s] %s", user
->nick
, uData
->info
);
7870 chanserv_autojoin_channels(struct userNode
*user
)
7872 struct userData
*channel
;
7874 for(channel
= user
->handle_info
->channels
; channel
; channel
= channel
->u_next
)
7876 struct chanNode
*cn
;
7877 struct modeNode
*mn
;
7879 if(IsUserSuspended(channel
)
7880 || IsSuspended(channel
->channel
)
7881 || !(cn
= channel
->channel
->channel
))
7884 mn
= GetUserMode(cn
, user
);
7887 if(!IsUserSuspended(channel
)
7888 && IsUserAutoJoin(channel
)
7889 && (channel
->access
>= channel
->channel
->lvlOpts
[lvlInviteMe
])
7891 && !user
->uplink
->burst
)
7892 irc_svsjoin(chanserv
, user
, cn
);
7898 handle_auth(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
))
7900 struct mod_chanmode change
;
7901 struct userData
*channel
;
7902 unsigned int ii
, jj
, i
;
7904 if(!user
->handle_info
)
7907 mod_chanmode_init(&change
);
7909 for(channel
= user
->handle_info
->channels
; channel
; channel
= channel
->u_next
)
7911 struct chanNode
*cn
;
7912 struct chanData
*cData
;
7913 struct modeNode
*mn
;
7914 if(IsUserSuspended(channel
)
7915 || IsSuspended(channel
->channel
)
7916 || !(cn
= channel
->channel
->channel
))
7919 cData
= cn
->channel_info
;
7920 mn
= GetUserMode(cn
, user
);
7923 if(!IsUserSuspended(channel
)
7924 && IsUserAutoInvite(channel
)
7925 && (channel
->access
>= channel
->channel
->lvlOpts
[lvlInviteMe
])
7927 && !user
->uplink
->burst
)
7928 irc_invite(chanserv
, user
, cn
);
7932 if(channel
->access
>= UL_PRESENT
)
7933 channel
->channel
->visited
= now
;
7935 if(IsUserAutoOp(channel
) && cData
->chOpts
[chAutomode
] != 'n')
7937 if(channel
->access
>= UL_OP
)
7938 change
.args
[0].mode
= MODE_CHANOP
;
7939 else if(channel
->access
>= UL_HALFOP
)
7940 change
.args
[0].mode
= MODE_HALFOP
;
7941 else if(channel
->access
>= UL_PEON
)
7942 change
.args
[0].mode
= MODE_VOICE
;
7944 change
.args
[0].mode
= 0;
7945 change
.args
[0].u
.member
= mn
;
7946 if(change
.args
[0].mode
)
7947 mod_chanmode_announce(chanserv
, cn
, &change
);
7950 channel
->seen
= now
;
7951 channel
->present
= 1;
7954 for(ii
= 0; ii
< user
->channels
.used
; ++ii
)
7956 struct chanNode
*channel
= user
->channels
.list
[ii
]->channel
;
7957 struct banData
*ban
;
7959 if((user
->channels
.list
[ii
]->modes
& (MODE_CHANOP
|MODE_HALFOP
|MODE_VOICE
))
7960 || !channel
->channel_info
7961 || IsSuspended(channel
->channel_info
))
7963 if(protect_user(user
, chanserv
, channel
->channel_info
, true))
7965 for(jj
= 0; jj
< channel
->banlist
.used
; ++jj
)
7966 if(user_matches_glob(user
, channel
->banlist
.list
[jj
]->ban
, MATCH_USENICK
))
7968 if(jj
< channel
->banlist
.used
)
7970 for(ban
= channel
->channel_info
->bans
; ban
; ban
= ban
->next
)
7972 char kick_reason
[MAXLEN
];
7973 if(!user_matches_glob(user
, ban
->mask
,MATCH_USENICK
| MATCH_VISIBLE
))
7975 change
.args
[0].mode
= MODE_BAN
;
7976 change
.args
[0].u
.hostmask
= ban
->mask
;
7977 mod_chanmode_announce(chanserv
, channel
, &change
);
7978 sprintf(kick_reason
, "(%s) %s", ban
->owner
, ban
->reason
);
7979 KickChannelUser(user
, channel
, chanserv
, kick_reason
);
7980 ban
->triggered
= now
;
7985 if(IsSupportHelper(user
))
7987 for(ii
= 0; ii
< chanserv_conf
.support_channels
.used
; ++ii
)
7989 if(GetUserMode(chanserv_conf
.support_channels
.list
[ii
], user
))
7991 HANDLE_SET_FLAG(user
->handle_info
, HELPING
);
7997 if (user
->handle_info
->ignores
->used
) {
7998 for (i
=0; i
< user
->handle_info
->ignores
->used
; i
++) {
7999 irc_silence(user
, user
->handle_info
->ignores
->list
[i
], 1);
8003 if (user
->handle_info
->epithet
)
8004 irc_swhois(chanserv
, user
, user
->handle_info
->epithet
);
8006 /* process autojoin channels 5 seconds later as this sometimes
8007 happens before autohide */
8008 // timeq_add(now + 5, chanserv_autojoin_channels, user);
8009 chanserv_autojoin_channels(user
);
8013 handle_part(struct modeNode
*mn
, UNUSED_ARG(const char *reason
))
8015 struct chanData
*cData
;
8016 struct userData
*uData
;
8018 cData
= mn
->channel
->channel_info
;
8019 if(!cData
|| IsSuspended(cData
) || IsLocal(mn
->user
))
8022 if((cData
->flags
& CHANNEL_DYNAMIC_LIMIT
) && !mn
->channel
->join_flooded
)
8024 /* Allow for a bit of padding so that the limit doesn't
8025 track the user count exactly, which could get annoying. */
8026 if((mn
->channel
->limit
- mn
->channel
->members
.used
) > chanserv_conf
.adjust_threshold
+ 5)
8028 timeq_del(0, chanserv_adjust_limit
, cData
, TIMEQ_IGNORE_WHEN
);
8029 timeq_add(now
+ chanserv_conf
.adjust_delay
, chanserv_adjust_limit
, cData
);
8033 if((uData
= GetTrueChannelAccess(cData
, mn
->user
->handle_info
)))
8035 scan_user_presence(uData
, mn
->user
);
8039 if(IsHelping(mn
->user
) && IsSupportHelper(mn
->user
))
8041 unsigned int ii
, jj
;
8042 for(ii
= 0; ii
< chanserv_conf
.support_channels
.used
; ++ii
)
8044 for(jj
= 0; jj
< mn
->user
->channels
.used
; ++jj
)
8045 if(mn
->user
->channels
.list
[jj
]->channel
== chanserv_conf
.support_channels
.list
[ii
])
8047 if(jj
< mn
->user
->channels
.used
)
8050 if(ii
== chanserv_conf
.support_channels
.used
)
8051 HANDLE_CLEAR_FLAG(mn
->user
->handle_info
, HELPING
);
8056 handle_kick(struct userNode
*kicker
, struct userNode
*victim
, struct chanNode
*channel
)
8058 struct userData
*uData
;
8060 if(!channel
->channel_info
|| !kicker
|| IsService(kicker
)
8061 || (kicker
== victim
) || IsSuspended(channel
->channel_info
)
8062 || (kicker
->handle_info
&& kicker
->handle_info
== victim
->handle_info
))
8065 if(protect_user(victim
, kicker
, channel
->channel_info
, false))
8067 const char *reason
= user_find_message(kicker
, "CSMSG_USER_PROTECTED_KICK");
8068 KickChannelUser(kicker
, channel
, chanserv
, reason
);
8071 if((uData
= GetTrueChannelAccess(channel
->channel_info
, victim
->handle_info
)))
8076 handle_topic(struct userNode
*user
, struct chanNode
*channel
, const char *old_topic
)
8078 struct chanData
*cData
;
8080 if(!channel
->channel_info
|| !user
|| IsSuspended(channel
->channel_info
) || IsService(user
))
8083 cData
= channel
->channel_info
;
8084 if(bad_topic(channel
, user
, channel
->topic
))
8085 { /* User doesnt have privs to set topics. Undo it */
8086 send_message(user
, chanserv
, "CSMSG_TOPIC_LOCKED", channel
->name
);
8087 SetChannelTopic(channel
, chanserv
, chanserv
, old_topic
, 1);
8090 /* If there is a topic mask set, and the new topic doesnt match,
8091 * set the topic to mask + new_topic */
8092 if(cData
->topic_mask
&& !match_ircglob(channel
->topic
, cData
->topic_mask
))
8094 char new_topic
[TOPICLEN
+1];
8095 conform_topic(cData
->topic_mask
, channel
->topic
, new_topic
);
8098 SetChannelTopic(channel
, chanserv
, user
, new_topic
, 1);
8099 /* and fall through to topicsnarf code below.. */
8101 else /* Topic couldnt fit into mask, was too long */
8103 SetChannelTopic(channel
, chanserv
, user
, old_topic
, 1);
8104 send_message(user
, chanserv
, "CSMSG_TOPICMASK_CONFLICT1", channel
->name
, cData
->topic_mask
);
8105 send_message(user
, chanserv
, "CSMSG_TOPICMASK_CONFLICT2", TOPICLEN
);
8109 /* With topicsnarf, grab the topic and save it as the default topic. */
8110 if(check_user_level(channel
, user
, lvlTopicSnarf
, 0, 0))
8113 cData
->topic
= strdup(channel
->topic
);
8119 handle_mode(struct chanNode
*channel
, struct userNode
*user
, const struct mod_chanmode
*change
)
8121 struct mod_chanmode
*bounce
= NULL
;
8122 unsigned int bnc
, ii
;
8125 if(!channel
->channel_info
|| IsLocal(user
) || IsSuspended(channel
->channel_info
) || IsService(user
))
8128 if(!check_user_level(channel
, user
, lvlEnfModes
, 1, 0)
8129 && mode_lock_violated(&channel
->channel_info
->modes
, change
))
8131 char correct
[MAXLEN
];
8132 bounce
= mod_chanmode_dup(&channel
->channel_info
->modes
, change
->argc
+ 1);
8133 mod_chanmode_format(&channel
->channel_info
->modes
, correct
);
8134 send_message(user
, chanserv
, "CSMSG_MODE_LOCKED", correct
, channel
->name
);
8136 for(ii
= bnc
= 0; ii
< change
->argc
; ++ii
)
8138 if((change
->args
[ii
].mode
& (MODE_REMOVE
|MODE_CHANOP
)) == (MODE_REMOVE
|MODE_CHANOP
))
8140 const struct userNode
*victim
= change
->args
[ii
].u
.member
->user
;
8141 if(!protect_user(victim
, user
, channel
->channel_info
, false))
8144 bounce
= mod_chanmode_alloc(change
->argc
+ 1 - ii
);
8147 bounce
->args
[bnc
].mode
= MODE_REMOVE
| MODE_CHANOP
;
8148 bounce
->args
[bnc
].u
.member
= GetUserMode(channel
, user
);
8149 if(bounce
->args
[bnc
].u
.member
)
8153 bounce
->args
[bnc
].mode
= MODE_CHANOP
;
8154 bounce
->args
[bnc
].u
.member
= change
->args
[ii
].u
.member
;
8156 send_message(user
, chanserv
, "CSMSG_USER_PROTECTED", victim
->nick
);
8158 else if(change
->args
[ii
].mode
& MODE_CHANOP
)
8160 const struct userNode
*victim
= change
->args
[ii
].u
.member
->user
;
8161 if(IsService(victim
) || validate_op(NULL
, user
, channel
, (struct userNode
*)victim
))
8164 bounce
= mod_chanmode_alloc(change
->argc
+ 1 - ii
);
8165 bounce
->args
[bnc
].mode
= MODE_REMOVE
| MODE_CHANOP
;
8166 bounce
->args
[bnc
].u
.member
= change
->args
[ii
].u
.member
;
8169 else if((change
->args
[ii
].mode
& (MODE_REMOVE
| MODE_BAN
)) == MODE_BAN
)
8171 const char *ban
= change
->args
[ii
].u
.hostmask
;
8172 if(!bad_channel_ban(channel
, user
, ban
, NULL
, NULL
))
8175 bounce
= mod_chanmode_alloc(change
->argc
+ 1 - ii
);
8176 bounce
->args
[bnc
].mode
= MODE_REMOVE
| MODE_BAN
;
8177 bounce
->args
[bnc
].u
.hostmask
= strdup(ban
);
8179 send_message(user
, chanserv
, "CSMSG_MASK_PROTECTED", ban
);
8184 if((bounce
->argc
= bnc
) || bounce
->modes_set
|| bounce
->modes_clear
)
8185 mod_chanmode_announce(chanserv
, channel
, bounce
);
8186 for(ii
= 0; ii
< change
->argc
; ++ii
)
8187 if(bounce
->args
[ii
].mode
== (MODE_REMOVE
| MODE_BAN
))
8188 free((char*)bounce
->args
[ii
].u
.hostmask
);
8189 mod_chanmode_free(bounce
);
8194 handle_nick_change(struct userNode
*user
, UNUSED_ARG(const char *old_nick
))
8196 struct chanNode
*channel
;
8197 struct banData
*bData
;
8198 struct mod_chanmode change
;
8199 unsigned int ii
, jj
;
8200 char kick_reason
[MAXLEN
];
8202 mod_chanmode_init(&change
);
8204 change
.args
[0].mode
= MODE_BAN
;
8205 for(ii
= 0; ii
< user
->channels
.used
; ++ii
)
8207 channel
= user
->channels
.list
[ii
]->channel
;
8208 /* Need not check for bans if they're opped or voiced. */
8209 /* TODO: does this make sense in automode v, h, and o? *
8210 * lets still enforce on voice people anyway, and see how that goes -Rubin */
8211 if(user
->channels
.list
[ii
]->modes
& (MODE_CHANOP
|MODE_HALFOP
|MODE_VOICE
))
8213 /* Need not check for bans unless channel registration is active. */
8214 if(!channel
->channel_info
|| IsSuspended(channel
->channel_info
))
8216 /* Look for a matching ban already on the channel. */
8217 for(jj
= 0; jj
< channel
->banlist
.used
; ++jj
)
8218 if(user_matches_glob(user
, channel
->banlist
.list
[jj
]->ban
, MATCH_USENICK
))
8220 /* Need not act if we found one. */
8221 if(jj
< channel
->banlist
.used
)
8223 /* don't kick someone on the userlist */
8224 if(protect_user(user
, chanserv
, channel
->channel_info
, true))
8226 /* Look for a matching ban in this channel. */
8227 for(bData
= channel
->channel_info
->bans
; bData
; bData
= bData
->next
)
8229 if(!user_matches_glob(user
, bData
->mask
, MATCH_USENICK
| MATCH_VISIBLE
))
8231 change
.args
[0].u
.hostmask
= bData
->mask
;
8232 mod_chanmode_announce(chanserv
, channel
, &change
);
8233 sprintf(kick_reason
, "(%s) %s", bData
->owner
, bData
->reason
);
8234 KickChannelUser(user
, channel
, chanserv
, kick_reason
);
8235 bData
->triggered
= now
;
8236 break; /* we don't need to check any more bans in the channel */
8241 static void handle_rename(struct handle_info
*handle
, const char *old_handle
)
8243 struct do_not_register
*dnr
= dict_find(handle_dnrs
, old_handle
, NULL
);
8247 dict_remove2(handle_dnrs
, old_handle
, 1);
8248 safestrncpy(dnr
->chan_name
+ 1, handle
->handle
, sizeof(dnr
->chan_name
) - 1);
8249 dict_insert(handle_dnrs
, dnr
->chan_name
+ 1, dnr
);
8254 handle_unreg(UNUSED_ARG(struct userNode
*user
), struct handle_info
*handle
)
8256 struct userNode
*h_user
;
8258 if(handle
->channels
)
8260 for(h_user
= handle
->users
; h_user
; h_user
= h_user
->next_authed
)
8261 send_message(h_user
, chanserv
, "CSMSG_HANDLE_UNREGISTERED");
8263 while(handle
->channels
)
8264 del_channel_user(handle
->channels
, 1);
8269 handle_server_link(UNUSED_ARG(struct server
*server
))
8271 struct chanData
*cData
;
8273 for(cData
= channelList
; cData
; cData
= cData
->next
)
8275 if(!IsSuspended(cData
))
8276 cData
->may_opchan
= 1;
8277 if((cData
->flags
& CHANNEL_DYNAMIC_LIMIT
)
8278 && !cData
->channel
->join_flooded
8279 && ((cData
->channel
->limit
- cData
->channel
->members
.used
)
8280 < chanserv_conf
.adjust_threshold
))
8282 timeq_del(0, chanserv_adjust_limit
, cData
, TIMEQ_IGNORE_WHEN
);
8283 timeq_add(now
+ chanserv_conf
.adjust_delay
, chanserv_adjust_limit
, cData
);
8289 chanserv_conf_read(void)
8293 char mode_line
[MAXLEN
], *modes
[MAXNUMPARAMS
];
8294 struct mod_chanmode
*change
;
8295 struct string_list
*strlist
;
8296 struct chanNode
*chan
;
8299 if(!(conf_node
= conf_get_data(CHANSERV_CONF_NAME
, RECDB_OBJECT
)))
8301 log_module(CS_LOG
, LOG_ERROR
, "Invalid config node `%s'.", CHANSERV_CONF_NAME
);
8304 for(ii
= 0; ii
< chanserv_conf
.support_channels
.used
; ++ii
)
8305 UnlockChannel(chanserv_conf
.support_channels
.list
[ii
]);
8306 chanserv_conf
.support_channels
.used
= 0;
8307 if((strlist
= database_get_data(conf_node
, KEY_SUPPORT_CHANNEL
, RECDB_STRING_LIST
)))
8309 for(ii
= 0; ii
< strlist
->used
; ++ii
)
8311 const char *str2
= database_get_data(conf_node
, KEY_SUPPORT_CHANNEL_MODES
, RECDB_QSTRING
);
8314 chan
= AddChannel(strlist
->list
[ii
], now
, str2
, NULL
, NULL
);
8316 channelList_append(&chanserv_conf
.support_channels
, chan
);
8319 else if((str
= database_get_data(conf_node
, KEY_SUPPORT_CHANNEL
, RECDB_QSTRING
)))
8322 str2
= database_get_data(conf_node
, KEY_SUPPORT_CHANNEL_MODES
, RECDB_QSTRING
);
8325 chan
= AddChannel(str
, now
, str2
, NULL
, NULL
);
8327 channelList_append(&chanserv_conf
.support_channels
, chan
);
8329 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
8330 chanserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
8331 str
= database_get_data(conf_node
, KEY_INFO_DELAY
, RECDB_QSTRING
);
8332 chanserv_conf
.info_delay
= str
? ParseInterval(str
) : 180;
8333 str
= database_get_data(conf_node
, KEY_MAX_GREETLEN
, RECDB_QSTRING
);
8334 chanserv_conf
.greeting_length
= str
? atoi(str
) : 200;
8335 str
= database_get_data(conf_node
, KEY_ADJUST_THRESHOLD
, RECDB_QSTRING
);
8336 chanserv_conf
.adjust_threshold
= str
? atoi(str
) : 15;
8337 str
= database_get_data(conf_node
, KEY_ADJUST_DELAY
, RECDB_QSTRING
);
8338 chanserv_conf
.adjust_delay
= str
? ParseInterval(str
) : 30;
8339 str
= database_get_data(conf_node
, KEY_CHAN_EXPIRE_FREQ
, RECDB_QSTRING
);
8340 chanserv_conf
.channel_expire_frequency
= str
? ParseInterval(str
) : 86400;
8341 str
= database_get_data(conf_node
, KEY_BAN_TIMEOUT_FREQ
, RECDB_QSTRING
);
8342 chanserv_conf
.ban_timeout_frequency
= str
? ParseInterval(str
) : 600;
8343 str
= database_get_data(conf_node
, KEY_CHAN_EXPIRE_DELAY
, RECDB_QSTRING
);
8344 chanserv_conf
.channel_expire_delay
= str
? ParseInterval(str
) : 86400*30;
8345 str
= database_get_data(conf_node
, KEY_NODELETE_LEVEL
, RECDB_QSTRING
);
8346 chanserv_conf
.nodelete_level
= str
? atoi(str
) : 1;
8347 str
= database_get_data(conf_node
, KEY_MAX_CHAN_USERS
, RECDB_QSTRING
);
8348 chanserv_conf
.max_chan_users
= str
? atoi(str
) : 512;
8349 str
= database_get_data(conf_node
, KEY_MAX_CHAN_BANS
, RECDB_QSTRING
);
8350 chanserv_conf
.max_chan_bans
= str
? atoi(str
) : 512;
8351 str
= database_get_data(conf_node
, KEY_MAX_USERINFO_LENGTH
, RECDB_QSTRING
);
8352 chanserv_conf
.max_userinfo_length
= str
? atoi(str
) : 400;
8353 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
8355 NickChange(chanserv
, str
, 0);
8356 str
= database_get_data(conf_node
, KEY_REFRESH_PERIOD
, RECDB_QSTRING
);
8357 chanserv_conf
.refresh_period
= str
? ParseInterval(str
) : 3*60*60;
8358 str
= database_get_data(conf_node
, KEY_GIVEOWNERSHIP_PERIOD
, RECDB_QSTRING
);
8359 chanserv_conf
.giveownership_period
= str
? ParseInterval(str
) : 0;
8360 str
= database_get_data(conf_node
, KEY_CTCP_SHORT_BAN_DURATION
, RECDB_QSTRING
);
8361 chanserv_conf
.ctcp_short_ban_duration
= str
? str
: "3m";
8362 str
= database_get_data(conf_node
, KEY_CTCP_LONG_BAN_DURATION
, RECDB_QSTRING
);
8363 chanserv_conf
.ctcp_long_ban_duration
= str
? str
: "1h";
8364 str
= database_get_data(conf_node
, KEY_MAX_OWNED
, RECDB_QSTRING
);
8365 chanserv_conf
.max_owned
= str
? atoi(str
) : 5;
8366 str
= database_get_data(conf_node
, KEY_IRC_OPERATOR_EPITHET
, RECDB_QSTRING
);
8367 chanserv_conf
.irc_operator_epithet
= str
? str
: "a megalomaniacal power hungry tyrant";
8368 str
= database_get_data(conf_node
, KEY_NETWORK_HELPER_EPITHET
, RECDB_QSTRING
);
8369 chanserv_conf
.network_helper_epithet
= str
? str
: "a wannabe tyrant";
8370 str
= database_get_data(conf_node
, KEY_SUPPORT_HELPER_EPITHET
, RECDB_QSTRING
);
8371 chanserv_conf
.support_helper_epithet
= str
? str
: "a wannabe tyrant";
8372 str
= database_get_data(conf_node
, KEY_GOD_TIMEOUT
, RECDB_QSTRING
);
8373 god_timeout
= str
? ParseInterval(str
) : 60*15;
8374 str
= database_get_data(conf_node
, "default_modes", RECDB_QSTRING
);
8377 safestrncpy(mode_line
, str
, sizeof(mode_line
));
8378 ii
= split_line(mode_line
, 0, ArrayLength(modes
), modes
);
8379 if((change
= mod_chanmode_parse(NULL
, modes
, ii
, MCP_KEY_FREE
, 0))
8380 && (change
->argc
< 2))
8382 chanserv_conf
.default_modes
= *change
;
8383 mod_chanmode_free(change
);
8385 free_string_list(chanserv_conf
.set_shows
);
8386 strlist
= database_get_data(conf_node
, "set_shows", RECDB_STRING_LIST
);
8388 strlist
= string_list_copy(strlist
);
8391 static const char *list
[] = {
8392 /* free form text */
8393 "DefaultTopic", "TopicMask", "Greeting", "UserGreeting", "Modes",
8394 /* options based on user level */
8395 "PubCmd", "InviteMe", "UserInfo","EnfOps",
8396 "EnfHalfOps", "EnfModes", "EnfTopic", "TopicSnarf", "Setters",
8397 /* multiple choice options */
8398 "AutoMode", "CtcpReaction", "Protect", "Toys", "TopicRefresh", "Resync",
8399 /* binary options */
8400 "DynLimit", "NoDelete", "BanTimeout",
8405 strlist
= alloc_string_list(ArrayLength(list
)-1);
8406 for(ii
=0; list
[ii
]; ii
++)
8407 string_list_append(strlist
, strdup(list
[ii
]));
8409 chanserv_conf
.set_shows
= strlist
;
8410 /* We don't look things up now, in case the list refers to options
8411 * defined by modules initialized after this point. Just mark the
8412 * function list as invalid, so it will be initialized.
8414 set_shows_list
.used
= 0;
8415 free_string_list(chanserv_conf
.eightball
);
8416 strlist
= database_get_data(conf_node
, KEY_8BALL_RESPONSES
, RECDB_STRING_LIST
);
8419 strlist
= string_list_copy(strlist
);
8423 strlist
= alloc_string_list(4);
8424 string_list_append(strlist
, strdup("Yes."));
8425 string_list_append(strlist
, strdup("No."));
8426 string_list_append(strlist
, strdup("Maybe so."));
8428 chanserv_conf
.eightball
= strlist
;
8429 free_string_list(chanserv_conf
.old_ban_names
);
8430 strlist
= database_get_data(conf_node
, KEY_OLD_BAN_NAMES
, RECDB_STRING_LIST
);
8432 strlist
= string_list_copy(strlist
);
8434 strlist
= alloc_string_list(2);
8435 chanserv_conf
.old_ban_names
= strlist
;
8436 str
= database_get_data(conf_node
, "off_channel", RECDB_QSTRING
);
8437 off_channel
= str
? atoi(str
) : 0;
8441 chanserv_note_type_read(const char *key
, struct record_data
*rd
)
8444 struct note_type
*ntype
;
8447 if(!(obj
= GET_RECORD_OBJECT(rd
)))
8449 log_module(CS_LOG
, LOG_ERROR
, "Invalid note type %s.", key
);
8452 if(!(ntype
= chanserv_create_note_type(key
)))
8454 log_module(CS_LOG
, LOG_ERROR
, "Memory allocation failed for note %s.", key
);
8458 /* Figure out set access */
8459 if((str
= database_get_data(obj
, KEY_NOTE_OPSERV_ACCESS
, RECDB_QSTRING
)))
8461 ntype
->set_access_type
= NOTE_SET_PRIVILEGED
;
8462 ntype
->set_access
.min_opserv
= strtoul(str
, NULL
, 0);
8464 else if((str
= database_get_data(obj
, KEY_NOTE_CHANNEL_ACCESS
, RECDB_QSTRING
)))
8466 ntype
->set_access_type
= NOTE_SET_CHANNEL_ACCESS
;
8467 ntype
->set_access
.min_ulevel
= strtoul(str
, NULL
, 0);
8469 else if((str
= database_get_data(obj
, KEY_NOTE_SETTER_ACCESS
, RECDB_QSTRING
)))
8471 ntype
->set_access_type
= NOTE_SET_CHANNEL_SETTER
;
8475 log_module(CS_LOG
, LOG_ERROR
, "Could not find access type for note %s; defaulting to OpServ access level 0.", key
);
8476 ntype
->set_access_type
= NOTE_SET_PRIVILEGED
;
8477 ntype
->set_access
.min_opserv
= 0;
8480 /* Figure out visibility */
8481 if(!(str
= database_get_data(obj
, KEY_NOTE_VISIBILITY
, RECDB_QSTRING
)))
8482 ntype
->visible_type
= NOTE_VIS_PRIVILEGED
;
8483 else if(!irccasecmp(str
, KEY_NOTE_VIS_PRIVILEGED
))
8484 ntype
->visible_type
= NOTE_VIS_PRIVILEGED
;
8485 else if(!irccasecmp(str
, KEY_NOTE_VIS_CHANNEL_USERS
))
8486 ntype
->visible_type
= NOTE_VIS_CHANNEL_USERS
;
8487 else if(!irccasecmp(str
, KEY_NOTE_VIS_ALL
))
8488 ntype
->visible_type
= NOTE_VIS_ALL
;
8490 ntype
->visible_type
= NOTE_VIS_PRIVILEGED
;
8492 str
= database_get_data(obj
, KEY_NOTE_MAX_LENGTH
, RECDB_QSTRING
);
8493 ntype
->max_length
= str
? strtoul(str
, NULL
, 0) : 400;
8497 user_read_helper(const char *key
, struct record_data
*rd
, struct chanData
*chan
)
8499 struct handle_info
*handle
;
8500 struct userData
*uData
;
8501 char *seen
, *inf
, *flags
, *expires
, *accessexpiry
, *clvlexpiry
, *lstacc
;
8503 unsigned short access
, lastaccess
= 0;
8505 if(rd
->type
!= RECDB_OBJECT
|| !dict_size(rd
->d
.object
))
8507 log_module(CS_LOG
, LOG_ERROR
, "Invalid user in %s.", chan
->channel
->name
);
8511 access
= atoi(database_get_data(rd
->d
.object
, KEY_LEVEL
, RECDB_QSTRING
));
8512 if(access
> UL_OWNER
)
8514 log_module(CS_LOG
, LOG_ERROR
, "Invalid access level for %s in %s.", key
, chan
->channel
->name
);
8518 inf
= database_get_data(rd
->d
.object
, KEY_INFO
, RECDB_QSTRING
);
8519 seen
= database_get_data(rd
->d
.object
, KEY_SEEN
, RECDB_QSTRING
);
8520 last_seen
= seen
? (signed)strtoul(seen
, NULL
, 0) : now
;
8521 flags
= database_get_data(rd
->d
.object
, KEY_FLAGS
, RECDB_QSTRING
);
8522 expires
= database_get_data(rd
->d
.object
, KEY_EXPIRES
, RECDB_QSTRING
);
8523 accessexpiry
= database_get_data(rd
->d
.object
, KEY_ACCESSEXPIRY
, RECDB_QSTRING
);
8524 clvlexpiry
= database_get_data(rd
->d
.object
, KEY_CLVLEXPIRY
, RECDB_QSTRING
);
8525 lstacc
= database_get_data(rd
->d
.object
, KEY_LASTLEVEL
, RECDB_QSTRING
);
8526 lastaccess
= lstacc
? atoi(lstacc
) : 0;
8528 handle
= get_handle_info(key
);
8531 log_module(CS_LOG
, LOG_ERROR
, "Nonexistent account %s in %s.", key
, chan
->channel
->name
);
8535 uData
= add_channel_user(chan
, handle
, access
, last_seen
, inf
, 0);
8536 uData
->flags
= flags
? strtoul(flags
, NULL
, 0) : 0;
8537 uData
->expires
= expires
? strtoul(expires
, NULL
, 0) : 0;
8539 uData
->accessexpiry
= accessexpiry
? strtoul(accessexpiry
, NULL
, 0) : 0;
8540 if (uData
->accessexpiry
> 0)
8541 timeq_add(uData
->accessexpiry
, chanserv_expire_tempuser
, uData
);
8543 uData
->clvlexpiry
= clvlexpiry
? strtoul(clvlexpiry
, NULL
, 0) : 0;
8544 if (uData
->clvlexpiry
> 0)
8545 timeq_add(uData
->clvlexpiry
, chanserv_expire_tempclvl
, uData
);
8547 uData
->lastaccess
= lastaccess
;
8549 if((uData
->flags
& USER_SUSPENDED
) && uData
->expires
)
8551 if(uData
->expires
> now
)
8552 timeq_add(uData
->expires
, chanserv_expire_user_suspension
, uData
);
8554 uData
->flags
&= ~USER_SUSPENDED
;
8557 /* Upgrade: set autoop to the inverse of noautoop */
8558 if(chanserv_read_version
< 2)
8560 /* if noautoop is true, set autoop false, and vice versa */
8561 if(uData
->flags
& USER_NOAUTO_OP
)
8562 uData
->flags
= uData
->flags
& ~USER_AUTO_OP
;
8564 uData
->flags
= uData
->flags
| USER_AUTO_OP
;
8565 log_module(CS_LOG
, LOG_INFO
, "UPGRADE: to db version 2 from %u. Changing flag to %d for %s in %s.", chanserv_read_version
, uData
->flags
, key
, chan
->channel
->name
);
8571 ban_read_helper(const char *key
, struct record_data
*rd
, struct chanData
*chan
)
8573 struct banData
*bData
;
8574 char *set
, *triggered
, *s_duration
, *s_expires
, *reason
, *owner
;
8575 time_t set_time
, triggered_time
, expires_time
;
8577 if(rd
->type
!= RECDB_OBJECT
|| !dict_size(rd
->d
.object
))
8579 log_module(CS_LOG
, LOG_ERROR
, "Invalid ban in %s.", chan
->channel
->name
);
8583 set
= database_get_data(rd
->d
.object
, KEY_SET
, RECDB_QSTRING
);
8584 triggered
= database_get_data(rd
->d
.object
, KEY_TRIGGERED
, RECDB_QSTRING
);
8585 s_duration
= database_get_data(rd
->d
.object
, KEY_DURATION
, RECDB_QSTRING
);
8586 s_expires
= database_get_data(rd
->d
.object
, KEY_EXPIRES
, RECDB_QSTRING
);
8587 owner
= database_get_data(rd
->d
.object
, KEY_OWNER
, RECDB_QSTRING
);
8588 reason
= database_get_data(rd
->d
.object
, KEY_REASON
, RECDB_QSTRING
);
8589 if (!reason
|| !owner
)
8592 set_time
= set
? (time_t)strtoul(set
, NULL
, 0) : now
;
8593 triggered_time
= triggered
? (time_t)strtoul(triggered
, NULL
, 0) : 0;
8595 expires_time
= (time_t)strtoul(s_expires
, NULL
, 0);
8597 expires_time
= set_time
+ atoi(s_duration
);
8601 if(!reason
|| (expires_time
&& (expires_time
< now
)))
8604 bData
= add_channel_ban(chan
, key
, owner
, set_time
, triggered_time
, expires_time
, reason
);
8607 static struct suspended
*
8608 chanserv_read_suspended(dict_t obj
)
8610 struct suspended
*suspended
= calloc(1, sizeof(*suspended
));
8614 str
= database_get_data(obj
, KEY_EXPIRES
, RECDB_QSTRING
);
8615 suspended
->expires
= str
? (time_t)strtoul(str
, NULL
, 0) : 0;
8616 str
= database_get_data(obj
, KEY_REVOKED
, RECDB_QSTRING
);
8617 suspended
->revoked
= str
? (time_t)strtoul(str
, NULL
, 0) : 0;
8618 str
= database_get_data(obj
, KEY_ISSUED
, RECDB_QSTRING
);
8619 suspended
->issued
= str
? (time_t)strtoul(str
, NULL
, 0) : 0;
8620 suspended
->suspender
= strdup(database_get_data(obj
, KEY_SUSPENDER
, RECDB_QSTRING
));
8621 suspended
->reason
= strdup(database_get_data(obj
, KEY_REASON
, RECDB_QSTRING
));
8622 previous
= database_get_data(obj
, KEY_PREVIOUS
, RECDB_OBJECT
);
8623 suspended
->previous
= previous
? chanserv_read_suspended(previous
) : NULL
;
8627 static struct giveownership
*
8628 chanserv_read_giveownership(dict_t obj
)
8630 struct giveownership
*giveownership
= calloc(1, sizeof(*giveownership
));
8634 str
= database_get_data(obj
, KEY_STAFF_ISSUER
, RECDB_QSTRING
);
8635 giveownership
->staff_issuer
= str
? strdup(str
) : NULL
;
8637 giveownership
->old_owner
= strdup(database_get_data(obj
, KEY_OLD_OWNER
, RECDB_QSTRING
));
8639 giveownership
->target
= strdup(database_get_data(obj
, KEY_TARGET
, RECDB_QSTRING
));
8640 giveownership
->target_access
= atoi(database_get_data(obj
, KEY_TARGET_ACCESS
, RECDB_QSTRING
));
8642 str
= database_get_data(obj
, KEY_REASON
, RECDB_QSTRING
);
8643 giveownership
->reason
= str
? strdup(str
) : NULL
;
8644 str
= database_get_data(obj
, KEY_ISSUED
, RECDB_QSTRING
);
8645 giveownership
->issued
= str
? (time_t)strtoul(str
, NULL
, 0) : 0;
8647 previous
= database_get_data(obj
, KEY_PREVIOUS
, RECDB_OBJECT
);
8648 giveownership
->previous
= previous
? chanserv_read_giveownership(previous
) : NULL
;
8649 return giveownership
;
8653 chanserv_channel_read(const char *key
, struct record_data
*hir
)
8655 struct suspended
*suspended
;
8656 struct giveownership
*giveownership
;
8657 struct mod_chanmode
*modes
;
8658 struct chanNode
*cNode
;
8659 struct chanData
*cData
;
8660 struct dict
*channel
, *obj
;
8661 char *str
, *argv
[10];
8665 channel
= hir
->d
.object
;
8667 str
= database_get_data(channel
, KEY_REGISTRAR
, RECDB_QSTRING
);
8670 cNode
= AddChannel(key
, now
, NULL
, NULL
, NULL
);
8673 log_module(CS_LOG
, LOG_ERROR
, "Unable to create registered channel %s.", key
);
8676 cData
= register_channel(cNode
, str
);
8679 log_module(CS_LOG
, LOG_ERROR
, "Unable to register channel %s from database.", key
);
8683 if((obj
= database_get_data(channel
, KEY_OPTIONS
, RECDB_OBJECT
)))
8685 enum levelOption lvlOpt
;
8686 enum charOption chOpt
;
8688 if((str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
)))
8689 cData
->flags
= atoi(str
);
8691 for(lvlOpt
= 0; lvlOpt
< NUM_LEVEL_OPTIONS
; ++lvlOpt
)
8693 str
= database_get_data(obj
, levelOptions
[lvlOpt
].db_name
, RECDB_QSTRING
);
8695 cData
->lvlOpts
[lvlOpt
] = user_level_from_name(str
, UL_OWNER
+1);
8696 else if(levelOptions
[lvlOpt
].old_flag
)
8698 if(cData
->flags
& levelOptions
[lvlOpt
].old_flag
)
8699 cData
->lvlOpts
[lvlOpt
] = levelOptions
[lvlOpt
].flag_value
;
8701 cData
->lvlOpts
[lvlOpt
] = levelOptions
[lvlOpt
].default_value
;
8705 for(chOpt
= 0; chOpt
< NUM_CHAR_OPTIONS
; ++chOpt
)
8707 if(!(str
= database_get_data(obj
, charOptions
[chOpt
].db_name
, RECDB_QSTRING
)))
8709 cData
->chOpts
[chOpt
] = str
[0];
8712 else if((str
= database_get_data(channel
, KEY_FLAGS
, RECDB_QSTRING
)))
8714 enum levelOption lvlOpt
;
8715 enum charOption chOpt
;
8718 cData
->flags
= base64toint(str
, 5);
8719 count
= strlen(str
+= 5);
8720 for(lvlOpt
= 0; lvlOpt
< NUM_LEVEL_OPTIONS
; ++lvlOpt
)
8723 if(levelOptions
[lvlOpt
].old_flag
)
8725 if(cData
->flags
& levelOptions
[lvlOpt
].old_flag
)
8726 lvl
= levelOptions
[lvlOpt
].flag_value
;
8728 lvl
= levelOptions
[lvlOpt
].default_value
;
8730 else switch(((count
<= levelOptions
[lvlOpt
].old_idx
) ? str
: CHANNEL_DEFAULT_OPTIONS
)[levelOptions
[lvlOpt
].old_idx
])
8732 case 'c': lvl
= UL_COOWNER
; break;
8733 case 'm': lvl
= UL_MANAGER
; break;
8734 case 'n': lvl
= UL_OWNER
+1; break;
8735 case 'o': lvl
= UL_OP
; break;
8736 case 'p': lvl
= UL_PEON
; break;
8737 case 'h': lvl
= UL_HALFOP
; break;
8738 case 'w': lvl
= UL_OWNER
; break;
8739 default: lvl
= 0; break;
8741 cData
->lvlOpts
[lvlOpt
] = lvl
;
8743 for(chOpt
= 0; chOpt
< NUM_CHAR_OPTIONS
; ++chOpt
)
8744 cData
->chOpts
[chOpt
] = ((count
<= charOptions
[chOpt
].old_idx
) ? str
: CHANNEL_DEFAULT_OPTIONS
)[charOptions
[chOpt
].old_idx
];
8747 if((obj
= database_get_data(hir
->d
.object
, KEY_SUSPENDED
, RECDB_OBJECT
)))
8749 suspended
= chanserv_read_suspended(obj
);
8750 cData
->suspended
= suspended
;
8751 suspended
->cData
= cData
;
8752 /* We could use suspended->expires and suspended->revoked to
8753 * set the CHANNEL_SUSPENDED flag, but we don't. */
8755 else if(IsSuspended(cData
) && (str
= database_get_data(hir
->d
.object
, KEY_SUSPENDER
, RECDB_QSTRING
)))
8757 suspended
= calloc(1, sizeof(*suspended
));
8758 suspended
->issued
= 0;
8759 suspended
->revoked
= 0;
8760 suspended
->suspender
= strdup(str
);
8761 str
= database_get_data(hir
->d
.object
, KEY_SUSPEND_EXPIRES
, RECDB_QSTRING
);
8762 suspended
->expires
= str
? atoi(str
) : 0;
8763 str
= database_get_data(hir
->d
.object
, KEY_SUSPEND_REASON
, RECDB_QSTRING
);
8764 suspended
->reason
= strdup(str
? str
: "No reason");
8765 suspended
->previous
= NULL
;
8766 cData
->suspended
= suspended
;
8767 suspended
->cData
= cData
;
8771 cData
->flags
&= ~CHANNEL_SUSPENDED
;
8772 suspended
= NULL
; /* to squelch a warning */
8775 if(IsSuspended(cData
)) {
8776 if(suspended
->expires
> now
)
8777 timeq_add(suspended
->expires
, chanserv_expire_suspension
, suspended
);
8778 else if(suspended
->expires
)
8779 cData
->flags
&= ~CHANNEL_SUSPENDED
;
8782 if((obj
= database_get_data(hir
->d
.object
, KEY_GIVEOWNERSHIP
, RECDB_OBJECT
)))
8784 giveownership
= chanserv_read_giveownership(obj
);
8785 cData
->giveownership
= giveownership
;
8788 if((!off_channel
|| !IsOffChannel(cData
)) && !IsSuspended(cData
)) {
8789 struct mod_chanmode change
;
8790 mod_chanmode_init(&change
);
8792 change
.args
[0].mode
= MODE_CHANOP
;
8793 change
.args
[0].u
.member
= AddChannelUser(chanserv
, cNode
);
8794 mod_chanmode_announce(chanserv
, cNode
, &change
);
8797 str
= database_get_data(channel
, KEY_REGISTERED
, RECDB_QSTRING
);
8798 cData
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
8799 str
= database_get_data(channel
, KEY_VISITED
, RECDB_QSTRING
);
8800 cData
->visited
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
8801 str
= database_get_data(channel
, KEY_OWNER_TRANSFER
, RECDB_QSTRING
);
8802 cData
->ownerTransfer
= str
? (time_t)strtoul(str
, NULL
, 0) : 0;
8803 str
= database_get_data(channel
, KEY_MAX
, RECDB_QSTRING
);
8804 cData
->max
= str
? atoi(str
) : 0;
8805 str
= database_get_data(channel
, KEY_GREETING
, RECDB_QSTRING
);
8806 cData
->greeting
= str
? strdup(str
) : NULL
;
8807 str
= database_get_data(channel
, KEY_USER_GREETING
, RECDB_QSTRING
);
8808 cData
->user_greeting
= str
? strdup(str
) : NULL
;
8809 str
= database_get_data(channel
, KEY_TOPIC_MASK
, RECDB_QSTRING
);
8810 cData
->topic_mask
= str
? strdup(str
) : NULL
;
8811 str
= database_get_data(channel
, KEY_TOPIC
, RECDB_QSTRING
);
8812 cData
->topic
= str
? strdup(str
) : NULL
;
8814 str
= database_get_data(channel
, KEY_MAXSETINFO
, RECDB_QSTRING
);
8815 cData
->maxsetinfo
= str
? strtoul(str
, NULL
, 0) : chanserv_conf
.max_userinfo_length
;
8817 if(!IsSuspended(cData
)
8818 && (str
= database_get_data(channel
, KEY_MODES
, RECDB_QSTRING
))
8819 && (argc
= split_line(str
, 0, ArrayLength(argv
), argv
))
8820 && (modes
= mod_chanmode_parse(cNode
, argv
, argc
, MCP_KEY_FREE
, 0))) {
8821 cData
->modes
= *modes
;
8823 cData
->modes
.modes_set
|= MODE_REGISTERED
;
8824 if(cData
->modes
.argc
> 1)
8825 cData
->modes
.argc
= 1;
8826 mod_chanmode_announce(chanserv
, cNode
, &cData
->modes
);
8827 mod_chanmode_free(modes
);
8830 obj
= database_get_data(channel
, KEY_USERS
, RECDB_OBJECT
);
8831 for(it
= dict_first(obj
); it
; it
= iter_next(it
))
8832 user_read_helper(iter_key(it
), iter_data(it
), cData
);
8834 if(!cData
->users
&& !IsProtected(cData
))
8836 log_module(CS_LOG
, LOG_ERROR
, "Channel %s had no users in database, unregistering it.", key
);
8837 unregister_channel(cData
, "has empty user list.");
8841 obj
= database_get_data(channel
, KEY_BANS
, RECDB_OBJECT
);
8842 for(it
= dict_first(obj
); it
; it
= iter_next(it
))
8843 ban_read_helper(iter_key(it
), iter_data(it
), cData
);
8845 obj
= database_get_data(channel
, KEY_NOTES
, RECDB_OBJECT
);
8846 for(it
= dict_first(obj
); it
; it
= iter_next(it
))
8848 struct note_type
*ntype
= dict_find(note_types
, iter_key(it
), NULL
);
8849 struct record_data
*rd
= iter_data(it
);
8850 const char *note
, *setter
;
8852 if(rd
->type
!= RECDB_OBJECT
)
8854 log_module(CS_LOG
, LOG_ERROR
, "Bad record type for note %s in channel %s.", iter_key(it
), key
);
8858 log_module(CS_LOG
, LOG_ERROR
, "Bad note type name %s in channel %s.", iter_key(it
), key
);
8860 else if(!(note
= database_get_data(rd
->d
.object
, KEY_NOTE_NOTE
, RECDB_QSTRING
)))
8862 log_module(CS_LOG
, LOG_ERROR
, "Missing note text for note %s in channel %s.", iter_key(it
), key
);
8866 setter
= database_get_data(rd
->d
.object
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
8867 if(!setter
) setter
= "<unknown>";
8868 chanserv_add_channel_note(cData
, ntype
, setter
, note
);
8876 chanserv_dnr_read(const char *key
, struct record_data
*hir
)
8878 const char *setter
, *reason
, *str
;
8879 struct do_not_register
*dnr
;
8881 setter
= database_get_data(hir
->d
.object
, KEY_DNR_SETTER
, RECDB_QSTRING
);
8884 log_module(CS_LOG
, LOG_ERROR
, "Missing setter for DNR %s.", key
);
8887 reason
= database_get_data(hir
->d
.object
, KEY_DNR_REASON
, RECDB_QSTRING
);
8890 log_module(CS_LOG
, LOG_ERROR
, "Missing reason for DNR %s.", key
);
8893 dnr
= chanserv_add_dnr(key
, setter
, reason
);
8896 str
= database_get_data(hir
->d
.object
, KEY_DNR_SET
, RECDB_QSTRING
);
8898 dnr
->set
= atoi(str
);
8904 chanserv_version_read(struct dict
*section
)
8908 str
= database_get_data(section
, KEY_VERSION_NUMBER
, RECDB_QSTRING
);
8910 chanserv_read_version
= atoi(str
);
8911 log_module(CS_LOG
, LOG_DEBUG
, "Chanserv db version is %d.", chanserv_read_version
);
8915 chanserv_saxdb_read(struct dict
*database
)
8917 struct dict
*section
;
8920 if((section
= database_get_data(database
, KEY_VERSION_CONTROL
, RECDB_OBJECT
)))
8921 chanserv_version_read(section
);
8923 if((section
= database_get_data(database
, KEY_NOTE_TYPES
, RECDB_OBJECT
)))
8924 for(it
= dict_first(section
); it
; it
= iter_next(it
))
8925 chanserv_note_type_read(iter_key(it
), iter_data(it
));
8927 if((section
= database_get_data(database
, KEY_CHANNELS
, RECDB_OBJECT
)))
8928 for(it
= dict_first(section
); it
; it
= iter_next(it
))
8929 chanserv_channel_read(iter_key(it
), iter_data(it
));
8931 if((section
= database_get_data(database
, KEY_DNR
, RECDB_OBJECT
)))
8932 for(it
= dict_first(section
); it
; it
= iter_next(it
))
8933 chanserv_dnr_read(iter_key(it
), iter_data(it
));
8939 chanserv_write_users(struct saxdb_context
*ctx
, struct userData
*uData
)
8941 int high_present
= 0;
8942 saxdb_start_record(ctx
, KEY_USERS
, 1);
8943 for(; uData
; uData
= uData
->next
)
8945 if((uData
->access
>= UL_PRESENT
) && uData
->present
)
8947 saxdb_start_record(ctx
, uData
->handle
->handle
, 0);
8948 saxdb_write_int(ctx
, KEY_LEVEL
, uData
->access
);
8949 saxdb_write_int(ctx
, KEY_SEEN
, uData
->seen
);
8950 saxdb_write_int(ctx
, KEY_ACCESSEXPIRY
, uData
->accessexpiry
);
8951 saxdb_write_int(ctx
, KEY_CLVLEXPIRY
, uData
->clvlexpiry
);
8952 saxdb_write_int(ctx
, KEY_LASTLEVEL
, uData
->lastaccess
);
8954 saxdb_write_int(ctx
, KEY_FLAGS
, uData
->flags
);
8956 saxdb_write_int(ctx
, KEY_EXPIRES
, uData
->expires
);
8958 saxdb_write_string(ctx
, KEY_INFO
, uData
->info
);
8959 saxdb_end_record(ctx
);
8961 saxdb_end_record(ctx
);
8962 return high_present
;
8966 chanserv_write_bans(struct saxdb_context
*ctx
, struct banData
*bData
)
8970 saxdb_start_record(ctx
, KEY_BANS
, 1);
8971 for(; bData
; bData
= bData
->next
)
8973 saxdb_start_record(ctx
, bData
->mask
, 0);
8974 saxdb_write_int(ctx
, KEY_SET
, bData
->set
);
8975 if(bData
->triggered
)
8976 saxdb_write_int(ctx
, KEY_TRIGGERED
, bData
->triggered
);
8978 saxdb_write_int(ctx
, KEY_EXPIRES
, bData
->expires
);
8980 saxdb_write_string(ctx
, KEY_OWNER
, bData
->owner
);
8982 saxdb_write_string(ctx
, KEY_REASON
, bData
->reason
);
8983 saxdb_end_record(ctx
);
8985 saxdb_end_record(ctx
);
8989 chanserv_write_suspended(struct saxdb_context
*ctx
, const char *name
, struct suspended
*susp
)
8991 saxdb_start_record(ctx
, name
, 0);
8992 saxdb_write_string(ctx
, KEY_SUSPENDER
, susp
->suspender
);
8993 saxdb_write_string(ctx
, KEY_REASON
, susp
->reason
);
8995 saxdb_write_int(ctx
, KEY_ISSUED
, susp
->issued
);
8997 saxdb_write_int(ctx
, KEY_EXPIRES
, susp
->expires
);
8999 saxdb_write_int(ctx
, KEY_REVOKED
, susp
->revoked
);
9001 chanserv_write_suspended(ctx
, KEY_PREVIOUS
, susp
->previous
);
9002 saxdb_end_record(ctx
);
9006 chanserv_write_giveownership(struct saxdb_context
*ctx
, const char *name
, struct giveownership
*giveownership
)
9008 saxdb_start_record(ctx
, name
, 0);
9009 if(giveownership
->staff_issuer
)
9010 saxdb_write_string(ctx
, KEY_STAFF_ISSUER
, giveownership
->staff_issuer
);
9011 if(giveownership
->old_owner
)
9012 saxdb_write_string(ctx
, KEY_OLD_OWNER
, giveownership
->old_owner
);
9013 if(giveownership
->target
)
9014 saxdb_write_string(ctx
, KEY_TARGET
, giveownership
->target
);
9015 if(giveownership
->target_access
)
9016 saxdb_write_int(ctx
, KEY_TARGET_ACCESS
, giveownership
->target_access
);
9017 if(giveownership
->reason
)
9018 saxdb_write_string(ctx
, KEY_REASON
, giveownership
->reason
);
9019 if(giveownership
->issued
)
9020 saxdb_write_int(ctx
, KEY_ISSUED
, giveownership
->issued
);
9021 if(giveownership
->previous
)
9022 chanserv_write_giveownership(ctx
, KEY_PREVIOUS
, giveownership
->previous
);
9023 saxdb_end_record(ctx
);
9027 chanserv_write_channel(struct saxdb_context
*ctx
, struct chanData
*channel
)
9031 enum levelOption lvlOpt
;
9032 enum charOption chOpt
;
9034 saxdb_start_record(ctx
, channel
->channel
->name
, 1);
9036 saxdb_write_int(ctx
, KEY_REGISTERED
, channel
->registered
);
9037 saxdb_write_int(ctx
, KEY_MAX
, channel
->max
);
9039 saxdb_write_string(ctx
, KEY_TOPIC
, channel
->topic
);
9040 if(channel
->registrar
)
9041 saxdb_write_string(ctx
, KEY_REGISTRAR
, channel
->registrar
);
9042 if(channel
->greeting
)
9043 saxdb_write_string(ctx
, KEY_GREETING
, channel
->greeting
);
9044 if(channel
->user_greeting
)
9045 saxdb_write_string(ctx
, KEY_USER_GREETING
, channel
->user_greeting
);
9046 if(channel
->topic_mask
)
9047 saxdb_write_string(ctx
, KEY_TOPIC_MASK
, channel
->topic_mask
);
9048 if(channel
->suspended
)
9049 chanserv_write_suspended(ctx
, "suspended", channel
->suspended
);
9050 if(channel
->giveownership
)
9051 chanserv_write_giveownership(ctx
, "giveownership", channel
->giveownership
);
9053 saxdb_start_record(ctx
, KEY_OPTIONS
, 0);
9054 saxdb_write_int(ctx
, KEY_FLAGS
, channel
->flags
);
9055 for(lvlOpt
= 0; lvlOpt
< NUM_LEVEL_OPTIONS
; ++lvlOpt
)
9056 saxdb_write_int(ctx
, levelOptions
[lvlOpt
].db_name
, channel
->lvlOpts
[lvlOpt
]);
9057 for(chOpt
= 0; chOpt
< NUM_CHAR_OPTIONS
; ++chOpt
)
9059 buf
[0] = channel
->chOpts
[chOpt
];
9061 saxdb_write_string(ctx
, charOptions
[chOpt
].db_name
, buf
);
9063 saxdb_end_record(ctx
);
9065 if (channel
->maxsetinfo
)
9066 saxdb_write_int(ctx
, KEY_MAXSETINFO
, channel
->maxsetinfo
);
9068 if(channel
->modes
.modes_set
|| channel
->modes
.modes_clear
)
9070 mod_chanmode_format(&channel
->modes
, buf
);
9071 saxdb_write_string(ctx
, KEY_MODES
, buf
);
9074 high_present
= chanserv_write_users(ctx
, channel
->users
);
9075 chanserv_write_bans(ctx
, channel
->bans
);
9077 if(dict_size(channel
->notes
))
9081 saxdb_start_record(ctx
, KEY_NOTES
, 1);
9082 for(it
= dict_first(channel
->notes
); it
; it
= iter_next(it
))
9084 struct note
*note
= iter_data(it
);
9085 saxdb_start_record(ctx
, iter_key(it
), 0);
9086 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, note
->setter
);
9087 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, note
->note
);
9088 saxdb_end_record(ctx
);
9090 saxdb_end_record(ctx
);
9093 if(channel
->ownerTransfer
)
9094 saxdb_write_int(ctx
, KEY_OWNER_TRANSFER
, channel
->ownerTransfer
);
9095 saxdb_write_int(ctx
, KEY_VISITED
, high_present
? now
: channel
->visited
);
9096 saxdb_end_record(ctx
);
9100 chanserv_write_note_type(struct saxdb_context
*ctx
, struct note_type
*ntype
)
9104 saxdb_start_record(ctx
, ntype
->name
, 0);
9105 switch(ntype
->set_access_type
)
9107 case NOTE_SET_CHANNEL_ACCESS
:
9108 saxdb_write_int(ctx
, KEY_NOTE_CHANNEL_ACCESS
, ntype
->set_access
.min_ulevel
);
9110 case NOTE_SET_CHANNEL_SETTER
:
9111 saxdb_write_int(ctx
, KEY_NOTE_SETTER_ACCESS
, 1);
9113 case NOTE_SET_PRIVILEGED
: default:
9114 saxdb_write_int(ctx
, KEY_NOTE_OPSERV_ACCESS
, ntype
->set_access
.min_opserv
);
9117 switch(ntype
->visible_type
)
9119 case NOTE_VIS_ALL
: str
= KEY_NOTE_VIS_ALL
; break;
9120 case NOTE_VIS_CHANNEL_USERS
: str
= KEY_NOTE_VIS_CHANNEL_USERS
; break;
9121 case NOTE_VIS_PRIVILEGED
:
9122 default: str
= KEY_NOTE_VIS_PRIVILEGED
; break;
9124 saxdb_write_string(ctx
, KEY_NOTE_VISIBILITY
, str
);
9125 saxdb_write_int(ctx
, KEY_NOTE_MAX_LENGTH
, ntype
->max_length
);
9126 saxdb_end_record(ctx
);
9130 write_dnrs_helper(struct saxdb_context
*ctx
, struct dict
*dnrs
)
9132 struct do_not_register
*dnr
;
9135 for(it
= dict_first(dnrs
); it
; it
= iter_next(it
))
9137 dnr
= iter_data(it
);
9138 saxdb_start_record(ctx
, dnr
->chan_name
, 0);
9140 saxdb_write_int(ctx
, KEY_DNR_SET
, dnr
->set
);
9141 saxdb_write_string(ctx
, KEY_DNR_SETTER
, dnr
->setter
);
9142 saxdb_write_string(ctx
, KEY_DNR_REASON
, dnr
->reason
);
9143 saxdb_end_record(ctx
);
9148 chanserv_saxdb_write(struct saxdb_context
*ctx
)
9151 struct chanData
*channel
;
9153 /* Version Control*/
9154 saxdb_start_record(ctx
, KEY_VERSION_CONTROL
, 1);
9155 saxdb_write_int(ctx
, KEY_VERSION_NUMBER
, CHANSERV_DB_VERSION
);
9156 saxdb_end_record(ctx
);
9159 saxdb_start_record(ctx
, KEY_NOTE_TYPES
, 1);
9160 for(it
= dict_first(note_types
); it
; it
= iter_next(it
))
9161 chanserv_write_note_type(ctx
, iter_data(it
));
9162 saxdb_end_record(ctx
);
9165 saxdb_start_record(ctx
, KEY_DNR
, 1);
9166 write_dnrs_helper(ctx
, handle_dnrs
);
9167 write_dnrs_helper(ctx
, plain_dnrs
);
9168 write_dnrs_helper(ctx
, mask_dnrs
);
9169 saxdb_end_record(ctx
);
9172 saxdb_start_record(ctx
, KEY_CHANNELS
, 1);
9173 for(channel
= channelList
; channel
; channel
= channel
->next
)
9174 chanserv_write_channel(ctx
, channel
);
9175 saxdb_end_record(ctx
);
9181 chanserv_db_cleanup(void) {
9183 unreg_part_func(handle_part
);
9185 unregister_channel(channelList
, "terminating.");
9186 for(ii
= 0; ii
< chanserv_conf
.support_channels
.used
; ++ii
)
9187 UnlockChannel(chanserv_conf
.support_channels
.list
[ii
]);
9188 free(chanserv_conf
.support_channels
.list
);
9189 dict_delete(handle_dnrs
);
9190 dict_delete(plain_dnrs
);
9191 dict_delete(mask_dnrs
);
9192 dict_delete(note_types
);
9193 free_string_list(chanserv_conf
.eightball
);
9194 free_string_list(chanserv_conf
.old_ban_names
);
9195 free_string_list(chanserv_conf
.set_shows
);
9196 free(set_shows_list
.list
);
9197 free(uset_shows_list
.list
);
9200 struct userData
*helper
= helperList
;
9201 helperList
= helperList
->next
;
9206 #define DEFINE_COMMAND(NAME, MIN_ARGC, FLAGS, OPTIONS...) modcmd_register(chanserv_module, #NAME, cmd_##NAME, MIN_ARGC, FLAGS, ## OPTIONS)
9207 #define DEFINE_CHANNEL_OPTION(NAME) modcmd_register(chanserv_module, "set "#NAME, chan_opt_##NAME, 1, 0, NULL)
9208 #define DEFINE_USER_OPTION(NAME) modcmd_register(chanserv_module, "uset "#NAME, user_opt_##NAME, 1, MODCMD_REQUIRE_REGCHAN, NULL)
9211 init_chanserv(const char *nick
)
9213 struct chanNode
*chan
;
9216 CS_LOG
= log_register_type("ChanServ", "file:chanserv.log");
9217 conf_register_reload(chanserv_conf_read
);
9219 reg_server_link_func(handle_server_link
);
9221 reg_new_channel_func(handle_new_channel
);
9222 reg_join_func(handle_join
);
9223 reg_part_func(handle_part
);
9224 reg_kick_func(handle_kick
);
9225 reg_topic_func(handle_topic
);
9226 reg_mode_change_func(handle_mode
);
9227 reg_nick_change_func(handle_nick_change
);
9229 reg_auth_func(handle_auth
);
9230 reg_handle_rename_func(handle_rename
);
9231 reg_unreg_func(handle_unreg
);
9233 handle_dnrs
= dict_new();
9234 dict_set_free_data(handle_dnrs
, free
);
9235 plain_dnrs
= dict_new();
9236 dict_set_free_data(plain_dnrs
, free
);
9237 mask_dnrs
= dict_new();
9238 dict_set_free_data(mask_dnrs
, free
);
9240 reg_svccmd_unbind_func(handle_svccmd_unbind
);
9241 chanserv_module
= module_register("ChanServ", CS_LOG
, "chanserv.help", chanserv_expand_variable
);
9242 DEFINE_COMMAND(register, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+acceptchan,+helping", NULL
);
9243 DEFINE_COMMAND(noregister
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+helping", NULL
);
9244 DEFINE_COMMAND(allowregister
, 2, 0, "template", "noregister", NULL
);
9245 DEFINE_COMMAND(move
, 1, MODCMD_REQUIRE_AUTHED
|MODCMD_REQUIRE_REGCHAN
, "template", "register", NULL
);
9246 DEFINE_COMMAND(csuspend
, 2, MODCMD_REQUIRE_AUTHED
|MODCMD_REQUIRE_REGCHAN
, "flags", "+helping", NULL
);
9247 DEFINE_COMMAND(cunsuspend
, 1, MODCMD_REQUIRE_AUTHED
|MODCMD_REQUIRE_REGCHAN
, "flags", "+helping", NULL
);
9248 DEFINE_COMMAND(createnote
, 5, 0, "level", "800", NULL
);
9249 DEFINE_COMMAND(removenote
, 2, 0, "level", "800", NULL
);
9251 DEFINE_COMMAND(pending
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+helping", NULL
);
9253 DEFINE_COMMAND(unregister
, 1, MODCMD_REQUIRE_AUTHED
|MODCMD_REQUIRE_REGCHAN
, "flags", "+loghostmask", NULL
);
9254 DEFINE_COMMAND(merge
, 2, MODCMD_REQUIRE_AUTHED
|MODCMD_REQUIRE_REGCHAN
, "access", "owner", NULL
);
9256 DEFINE_COMMAND(adduser
, 3, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9257 DEFINE_COMMAND(deluser
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9258 DEFINE_COMMAND(suspend
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9259 DEFINE_COMMAND(unsuspend
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9260 DEFINE_COMMAND(deleteme
, 1, MODCMD_REQUIRE_CHANUSER
, NULL
);
9262 DEFINE_COMMAND(mdelowner
, 2, MODCMD_REQUIRE_CHANUSER
, "flags", "+helping", NULL
);
9263 DEFINE_COMMAND(mdelcoowner
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "owner", NULL
);
9264 DEFINE_COMMAND(mdelmanager
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "coowner", NULL
);
9265 DEFINE_COMMAND(mdelop
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9266 DEFINE_COMMAND(mdelpeon
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9267 DEFINE_COMMAND(mdelhalfop
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9269 DEFINE_COMMAND(levels
, 1, 0, NULL
);
9271 DEFINE_COMMAND(trim
, 3, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9272 DEFINE_COMMAND(opchan
, 1, MODCMD_REQUIRE_REGCHAN
|MODCMD_NEVER_CSUSPEND
, "access", "1", NULL
);
9273 DEFINE_COMMAND(clvl
, 3, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9274 DEFINE_COMMAND(giveownership
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "owner", "flags", "+loghostmask", NULL
);
9276 DEFINE_COMMAND(up
, 1, MODCMD_REQUIRE_CHANUSER
, NULL
);
9277 DEFINE_COMMAND(down
, 1, MODCMD_REQUIRE_REGCHAN
, NULL
);
9278 DEFINE_COMMAND(upall
, 1, MODCMD_REQUIRE_AUTHED
, NULL
);
9279 DEFINE_COMMAND(downall
, 1, MODCMD_REQUIRE_AUTHED
, NULL
);
9280 DEFINE_COMMAND(hop
, 2, MODCMD_REQUIRE_CHANNEL
, "access", "op", NULL
);
9281 DEFINE_COMMAND(op
, 2, MODCMD_REQUIRE_CHANNEL
, "access", "op", NULL
);
9282 DEFINE_COMMAND(deop
, 2, MODCMD_REQUIRE_CHANNEL
, "template", "op", NULL
);
9283 DEFINE_COMMAND(dehop
, 2, MODCMD_REQUIRE_CHANNEL
, "template", "op", NULL
);
9284 DEFINE_COMMAND(voice
, 2, MODCMD_REQUIRE_CHANNEL
, "template", "op", NULL
);
9285 DEFINE_COMMAND(devoice
, 2, MODCMD_REQUIRE_CHANNEL
, "template", "op", NULL
);
9287 DEFINE_COMMAND(kickban
, 2, MODCMD_REQUIRE_REGCHAN
, "template", "hop", NULL
);
9288 DEFINE_COMMAND(kick
, 2, MODCMD_REQUIRE_REGCHAN
, "template", "hop", NULL
);
9289 DEFINE_COMMAND(ban
, 2, MODCMD_REQUIRE_REGCHAN
, "template", "hop", NULL
);
9290 DEFINE_COMMAND(unban
, 2, 0, "template", "hop", NULL
);
9291 DEFINE_COMMAND(unbanall
, 1, 0, "template", "hop", NULL
);
9292 DEFINE_COMMAND(unbanme
, 1, MODCMD_REQUIRE_CHANUSER
, "template", "hop", NULL
);
9293 DEFINE_COMMAND(open
, 1, MODCMD_REQUIRE_CHANUSER
, "template", "op", NULL
);
9294 DEFINE_COMMAND(topic
, 1, MODCMD_REQUIRE_REGCHAN
, "template", "hop", "flags", "+never_csuspend", NULL
);
9295 DEFINE_COMMAND(mode
, 1, MODCMD_REQUIRE_REGCHAN
, "template", "op", NULL
);
9296 DEFINE_COMMAND(inviteme
, 1, MODCMD_REQUIRE_CHANNEL
, "access", "1", NULL
);
9297 DEFINE_COMMAND(invite
, 1, MODCMD_REQUIRE_CHANNEL
, "access", "manager", NULL
);
9298 DEFINE_COMMAND(set
, 1, MODCMD_REQUIRE_CHANUSER
, "access", "op", NULL
);
9299 DEFINE_COMMAND(wipeinfo
, 2, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9300 DEFINE_COMMAND(resync
, 1, MODCMD_REQUIRE_CHANUSER
, "access", "manager", NULL
);
9302 DEFINE_COMMAND(events
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog", "access", "manager", NULL
);
9303 DEFINE_COMMAND(last
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog", "access", "manager", NULL
);
9304 DEFINE_COMMAND(addlamer
, 2, MODCMD_REQUIRE_REGCHAN
, "access", "manager", NULL
);
9305 DEFINE_COMMAND(addtimedlamer
, 3, MODCMD_REQUIRE_REGCHAN
, "access", "manager", NULL
);
9307 /* if you change dellamer access, see also places
9308 * like unbanme which have manager hardcoded. */
9309 DEFINE_COMMAND(dellamer
, 2, MODCMD_REQUIRE_REGCHAN
, "access", "manager", NULL
);
9310 DEFINE_COMMAND(uset
, 1, MODCMD_REQUIRE_CHANUSER
, "access", "1", NULL
);
9312 DEFINE_COMMAND(lamers
, 1, MODCMD_REQUIRE_REGCHAN
, "access", "1", "flags", "+nolog", NULL
);
9314 DEFINE_COMMAND(peek
, 1, MODCMD_REQUIRE_REGCHAN
, "access", "op", "flags", "+nolog", NULL
);
9316 DEFINE_COMMAND(myaccess
, 1, MODCMD_REQUIRE_AUTHED
, NULL
);
9317 DEFINE_COMMAND(access
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9318 DEFINE_COMMAND(users
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9319 DEFINE_COMMAND(wlist
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9320 DEFINE_COMMAND(clist
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9321 DEFINE_COMMAND(mlist
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9322 DEFINE_COMMAND(olist
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9323 DEFINE_COMMAND(hlist
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9324 DEFINE_COMMAND(plist
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9325 DEFINE_COMMAND(info
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9326 DEFINE_COMMAND(seen
, 2, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9327 DEFINE_COMMAND(names
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+nolog,+joinable", NULL
);
9329 DEFINE_COMMAND(note
, 1, MODCMD_REQUIRE_REGCHAN
, "flags", "+joinable,+acceptchan", NULL
);
9330 DEFINE_COMMAND(delnote
, 2, MODCMD_REQUIRE_CHANUSER
, NULL
);
9332 DEFINE_COMMAND(netinfo
, 1, 0, "flags", "+nolog", NULL
);
9333 DEFINE_COMMAND(ircops
, 1, 0, "flags", "+nolog", NULL
);
9334 DEFINE_COMMAND(helpers
, 1, 0, "flags", "+nolog", NULL
);
9335 DEFINE_COMMAND(staff
, 1, 0, "flags", "+nolog", NULL
);
9337 DEFINE_COMMAND(say
, 2, 0, "flags", "+oper,+acceptchan", NULL
);
9338 DEFINE_COMMAND(emote
, 2, 0, "flags", "+oper,+acceptchan", NULL
);
9339 DEFINE_COMMAND(expire
, 1, 0, "flags", "+oper", NULL
);
9340 DEFINE_COMMAND(search
, 3, 0, "flags", "+nolog,+helping", NULL
);
9341 DEFINE_COMMAND(unvisited
, 1, 0, "flags", "+nolog,+helping", NULL
);
9343 DEFINE_COMMAND(unf
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9344 DEFINE_COMMAND(ping
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9345 DEFINE_COMMAND(wut
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9346 DEFINE_COMMAND(8ball
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9347 DEFINE_COMMAND(d
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9348 DEFINE_COMMAND(huggle
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9349 DEFINE_COMMAND(calc
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9350 DEFINE_COMMAND(reply
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9351 DEFINE_COMMAND(roulette
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9352 DEFINE_COMMAND(shoot
, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL
);
9353 DEFINE_COMMAND(spin
, 1, MODCMD_REQUIRE_AUTHED
, "spin", "+nolog,+toy,+acceptchan", NULL
);
9355 /* Channel options */
9356 DEFINE_CHANNEL_OPTION(defaulttopic
);
9357 DEFINE_CHANNEL_OPTION(topicmask
);
9358 DEFINE_CHANNEL_OPTION(greeting
);
9359 DEFINE_CHANNEL_OPTION(usergreeting
);
9360 DEFINE_CHANNEL_OPTION(modes
);
9361 DEFINE_CHANNEL_OPTION(enfops
);
9362 DEFINE_CHANNEL_OPTION(enfhalfops
);
9363 DEFINE_CHANNEL_OPTION(automode
);
9364 DEFINE_CHANNEL_OPTION(protect
);
9365 DEFINE_CHANNEL_OPTION(enfmodes
);
9366 DEFINE_CHANNEL_OPTION(enftopic
);
9367 DEFINE_CHANNEL_OPTION(pubcmd
);
9368 DEFINE_CHANNEL_OPTION(userinfo
);
9369 DEFINE_CHANNEL_OPTION(dynlimit
);
9370 DEFINE_CHANNEL_OPTION(topicsnarf
);
9371 DEFINE_CHANNEL_OPTION(nodelete
);
9372 DEFINE_CHANNEL_OPTION(toys
);
9373 DEFINE_CHANNEL_OPTION(setters
);
9374 DEFINE_CHANNEL_OPTION(topicrefresh
);
9375 DEFINE_CHANNEL_OPTION(resync
);
9376 DEFINE_CHANNEL_OPTION(ctcpreaction
);
9377 DEFINE_CHANNEL_OPTION(bantimeout
);
9378 DEFINE_CHANNEL_OPTION(inviteme
);
9379 DEFINE_CHANNEL_OPTION(maxsetinfo
);
9381 DEFINE_CHANNEL_OPTION(offchannel
);
9382 modcmd_register(chanserv_module
, "set defaults", chan_opt_defaults
, 1, 0, "access", "owner", NULL
);
9384 /* Alias set topic to set defaulttopic for compatibility. */
9385 modcmd_register(chanserv_module
, "set topic", chan_opt_defaulttopic
, 1, 0, NULL
);
9388 DEFINE_USER_OPTION(autoinvite
);
9389 DEFINE_USER_OPTION(autojoin
);
9390 DEFINE_USER_OPTION(info
);
9391 DEFINE_USER_OPTION(autoop
);
9393 /* Alias uset autovoice to uset autoop. */
9394 modcmd_register(chanserv_module
, "uset autovoice", user_opt_autoop
, 1, 0, NULL
);
9396 note_types
= dict_new();
9397 dict_set_free_data(note_types
, chanserv_deref_note_type
);
9400 const char *modes
= conf_get_data("services/chanserv/modes", RECDB_QSTRING
);
9401 chanserv
= AddService(nick
, modes
? modes
: NULL
, "Channel Services", NULL
);
9402 service_register(chanserv
)->trigger
= '!';
9403 reg_chanmsg_func('\001', chanserv
, chanserv_ctcp_check
);
9406 saxdb_register("ChanServ", chanserv_saxdb_read
, chanserv_saxdb_write
);
9408 if(chanserv_conf
.channel_expire_frequency
)
9409 timeq_add(now
+ chanserv_conf
.channel_expire_frequency
, expire_channels
, NULL
);
9411 if(chanserv_conf
.ban_timeout_frequency
)
9412 timeq_add(now
+ chanserv_conf
.ban_timeout_frequency
, expire_bans
, NULL
);
9414 if(chanserv_conf
.refresh_period
)
9416 time_t next_refresh
;
9417 next_refresh
= (now
+ chanserv_conf
.refresh_period
- 1) / chanserv_conf
.refresh_period
* chanserv_conf
.refresh_period
;
9418 timeq_add(next_refresh
, chanserv_refresh_topics
, NULL
);
9419 timeq_add(next_refresh
, chanserv_auto_resync
, NULL
);
9422 if (autojoin_channels
&& chanserv
) {
9423 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
9424 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
9425 AddChannelUser(chanserv
, chan
)->modes
|= MODE_CHANOP
;
9429 reg_exit_func(chanserv_db_cleanup
);
9430 message_register_table(msgtab
);