1 #ifdef RCS
2 static char rcsid[]="$Id: setup.c,v 1.2 2001/03/13 05:04:47 holsta Exp $";
3 #endif
4 /******************************************************************************
5 * Internetting Cooperating Programmers
6 * ----------------------------------------------------------------------------
7 *
8 * ____ PROJECT
9 * | _ \ __ _ _ __ ___ ___ _ __
10 * | | | |/ _` | '_ \ / __/ _ \ '__|
11 * | |_| | (_| | | | | (_| __/ |
12 * |____/ \__,_|_| |_|\___\___|_| the IRC bot
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 *
16 * $Source: /cvsroot/dancer/dancer/src/setup.c,v $
17 * $Revision: 1.2 $
18 * $Date: 2001/03/13 05:04:47 $
19 * $Author: holsta $
20 * $State: Exp $
21 * $Locker: $
22 *
23 * ---------------------------------------------------------------------------
24 *****************************************************************************/
25
26 #include <stdlib.h>
27 #include <stddef.h> /* does this work in all unixes? the offsetof() */
28
29 #include "dancer.h"
30 #include "trio.h"
31 #include "strio.h"
32 #include "list.h"
33 #include "function.h"
34 #include "setup.h"
35 #include "user.h"
36 #include "command.h"
37 #include "files.h"
38
39 extern int floodrate, floodtime, floodrepeatrate, floodrepeattime;
40 extern int floodbeeps, floodjoins;
41 extern int logdays;
42 extern ulong activelog;
43 extern char *errfrom; /* this is like stderr, only for nicks */
44 extern itemident *current;
45
46 int numretry;
47 int opactionlen;
48 int pubbantime;
49 int oplevel;
50 int netburp; /* Period after netsplit where FLOOD is off */
51 int defbantime; /* Default value if time is omitted in BAN */
52 int seenmonths; /* Max number of months to keep entries in seen file */
53 int tellmonths; /* Max number of months to keep entries in tell file */
54 int warnmonths; /* Max number of months to keep entries in tell file */
55 long climit; /* the +l limit, 0 disables */
56 long newsexpire;
57 ulong linkvalue; /* "Public" key for linkbot */
58 bool lockmode; /* lock channel mode */
59 bool lockkey; /* lock channel key */
60 bool locklimit; /* lock channel limit */
61 bool avalance; /* kick ctcp bombers */
62 bool floodmode; /* prevent user floods */
63 bool welcome; /* welcome new users */
64 bool netsplitmode; /* deop and unban server ops/bans */
65 bool deopprotect; /* bankick massive deoppers */
66 bool uppercheck; /* check users for uppercase violations! */
67 bool nickflood; /* kick on nick floods */
68 bool talkative; /* start in talkative mode */
69 bool xdccmode; /* kick xdcc senders */
70 bool saymode; /* allow say/me commands */
71 bool warnmode; /* check people with the warnlist */
72 bool repeatmode; /* kick repeaters */
73 bool multimode; /* kick multiple users */
74 bool ctcpmode; /* CTCP flood checks */
75 bool reportban; /* report SET and BANs in public */
76 bool invitable; /* Respond to /invite or not */
77 bool autojoin; /* Rejoin on kick */
78 bool autoop; /* Auto-Op feature */
79 bool dispcomment; /* Display Comments */
80 bool masterflood;
81 bool kickbans; /* kick banned users if they still join */
82 bool beepcheck; /* kick/warn beepers */
83 bool colourcheck; /* kick/warn colourcode violators */
84 bool helpsyntax; /* automatically show syntax info after help */
85 bool execprotect; /* Enable/disable execution of shell scripts */
86 bool identprotect; /* Enable/disable the IDENT command */
87 bool autounban; /* automatically unban the weakest ban when 18 bans are
88 set in the channel */
89 bool strictopmode; /* Deop unrecognized users if they get opped by someone
90 less than LEVEL_BOT.
91 [FASCISM ALERT] Use with care! */
92 bool banuserkicks; /* Enable/disable non-bot users' kicks from causing the
93 bot to ban for multiple kicks. If DISABLED, the bot
94 will only ban if its own kicks are too frequent to
95 be acceptable. If ENABLED, all users' kicks are counted
96 and taken into consideration! */
97 bool fakenamemode; /* Kick people joining with a faked host/domain name. The
98 bot won't ban them since it may not be able to select a
99 ban pattern on user with '* in their patterns. */
100 bool banprotect; /* Enable/disable banprotection (main switch) */
101 bool mute; /* Disable most other noise not controlled by say,
102 talkative, welcome and reportban settings */
103 bool opprotect; /* Op chanop-users if they get deoped by someone
104 less than LEVEL_CHANOP. Will first deop the deoper.
105 [FASCISM ALERT] Use with care! */
106 bool loopservers; /* Loop the serverlist forever */
107
108 char nameserver[256] = "";
109 char userfile[256] = "";
110 char logfile[256] = "";
111 char setfile[256] = "";
112 char expfile[256] = "";
113 char seenfile[256] = "";
114 char tellfile[256] = "";
115 char banfile[256] = "";
116 char warnfile[256] = "";
117 char funcfile[256] = "";
118 char servfile[256] = "";
119 char fplconf[256] = "";
120 char newsfile[256] = "";
121 char language[128] = "";
122
123 /* Use StrDuplicateMax() instead of static (fixed) arrays ? */
124 char channel[200] = "";
125 char realname[256] = "";
126 char nickstring[128] = "";
127 char nickname[NICKLEN+1] = "";
128 char staticnick[NICKLEN+1] = "";
129 char cmodes[16] = "";
130 char chanmodes[16] = "";
131 char ckey[32] = "";
132 char chankey[32] = "";
133
134 char ctcpversion[256] = "";
135 char ctcpuserinfo[256] = "";
136 char rulesmsg[512] = "";
137 char findfilename[256] = "";
138 char cmdvrfy[256] = "";
139 char cmdhost[256] = "";
140 char cmdfinger[256] = "";
141 char cmdspell[256] = "";
142 char askforops[256] = "";
143 char opaction[256] = "";
144 char exchangecmd[256] = "";
145 char defaultpasswd[256] = "";
146 #ifdef NICKSERV
147 char nickpasswd[256] = "";
148 #endif
149 #ifdef UNDERNET
150 char unetpasswd[256] = "";
151 char unetnick[256] = "";
152 char unetserv[256] = "";
153 #endif
154 char dancer_myhost[256] = "";
155
156 /* New LEVEL stuff - Easy-to-change array */
157 long levels[] = {0, 10, 20, 50, 100, 200, 242, 999999};
158
159 itemlist *serverHead = NULL; /* List of servers for the bot */
160 itemlist *hostispHead = NULL; /* A list of ISP-patterns that should use the
161 host-style bans */
162 itemlist *nonhostispHead = NULL; /* A list of ISP-patterns that DOES not use
163 the host-style bans (even if it matched
164 a hostisp entry in the first run) */
165 itemlist *dontsitebanHead = NULL; /* A list of ISP-patterns that shouldn't
166 get sitebanned by the bot */
167
168 /* --- Config structure ------------------------------------------- */
169
170 struct Config cfg[] =
171 {
172 {"server", &serverHead, "bot.server.org", CFG_LIST, FALSE,
173 "# A comma seperated list of servers, of the format\n"
174 "# server[:port[:password]]\n"},
175
176 {"channel", channel, "#bot", CFG_STRING, FALSE,
177 "# Which channel to join at startup.\n"},
178
179 {"nick", nickstring, "bot", CFG_STRING, FALSE,
180 "# Nickmask, see dancerdoc.html for further info.\n"},
181
182 #ifdef NICKSERV
183 {"nickpass", nickpasswd, "", CFG_STRING, FALSE,
184 "# Password for identifying with NickServ (ie. DALnet services).\n"},
185 #endif
186
187 #ifdef UNDERNET
188 {"unetpass", unetpasswd, "", CFG_STRING, FALSE,
189 "# Password for authenticating with Undernet's X.\n"},
190
191 {"unetnick", unetnick, "", CFG_STRING, FALSE,
192 "# Nick the bot is registered with, for authenticating with Undernet's\n# channel service.\n"},
193
194 {"unetserv", unetserv, "x@channels.undernet.org", CFG_STRING, FALSE,
195 "# Name of Undernet's channel service.\n"},
196 #endif
197 {"staticnick", staticnick, "danc", CFG_STRING, FALSE,
198 "# A static 4-letter-nick that the bot will always recognize as\n"
199 "# itself regardless of its current nickname.\n"},
200
201 {"name", realname, "An IRC bot", CFG_STRING, FALSE,
202 "# Realname. Shows up on i.e /whois output.\n"},
203
204 {"ctcpversion", ctcpversion, CTCPVERSION, CFG_STRING, FALSE,
205 "# Ctcpversion enables you to choose a different reply to ctcp\n"
206 "# version requests. Per default it will reply with the name and\n"
207 "# version of the bot.\n"},
208
209 {"ctcpuserinfo", ctcpuserinfo, "No info", CFG_STRING, FALSE,
210 "# Ctcpuserinfo determines the reply of the ctcp userinfo request.\n"},
211
212 {"rulesmsg", rulesmsg, "No rules", CFG_STRING, FALSE,
213 "# Rulesmsg is the text that the RULES command prints.\n"},
214
215 {"defaultpasswd", defaultpasswd, DEFPASSWDTXT, CFG_STRING, FALSE,
216 "# Default password set to all new users.\n"},
217
218 {"dontsiteban", &dontsitebanHead, "", CFG_LIST, FALSE,
219 "# Specify a comma separated list of ISP patterns that should never\n"
220 "# ever get sitebanned by the bot.\n"
221 "# (see also 'hostisp' / 'nonhostisp')\n"},
222
223 {"hostisp", &hostispHead, "*.demon.co.uk", CFG_LIST, FALSE,
224 "# Specify a comma separated list of ISP patterns that should only\n"
225 "# use host-patterns and never allow sitebans.\n"
226 "# (see also 'nonhostisp')\n"},
227
228 {"nonhostisp", &nonhostispHead, "*dismayl.demon.co.uk", CFG_LIST, FALSE,
229 "# A comma separated list of patterns that should *not* be treated\n"
230 "# as a 'hostisp' even if it matched one of them.\n"},
231
232 {"exchangecmd", exchangecmd, "", CFG_STRING, FALSE,
233 "# Specify the full path to the program that should be used for\n"
234 "# currency translations plus arguments.\n"
235 "# If you're using the supplied 'curr.sh' script for currency\n"
236 "# translation, the setup below should be used. If you write your\n"
237 "# own or use a third party script, set it up accordingly.\n"
238 "#exchangecmd = /my/program/for/currency /full/path/to/rates/file\n"},
239
240 {"spellcmd", cmdspell, "./script/speller.sh", CFG_STRING, FALSE,
241 "# Full path to the spell command/script.\n"},
242
243 {"cmdvrfy", cmdvrfy, "", CFG_STRING, FALSE,
244 "# Cmdvrfy is the name (preferably including the full path) of the\n"
245 "# 'vrfy' command.\n"},
246
247 {"cmdfinger", cmdfinger, "/usr/bin/finger", CFG_STRING, FALSE,
248 "# Cmdfinger is the name (preferably including the full path) of the\n"
249 "# 'finger' command.\n"},
250
251 {"cmdhost", cmdhost, "/usr/bin/host", CFG_STRING, FALSE,
252 "# Cmdhost is the name (preferably including the full path) of the\n"
253 "# 'host' command.\n"},
254
255 {"nameserver", nameserver, "", CFG_STRING, FALSE,
256 "# Nameserver is the name of your local nameserver. This is\n"
257 "# needed for the HOST command. If none is supplied, it will\n"
258 "# try to get the yp master, and if that fails it will try\n"
259 "# to do without.\n"},
260
261 {"findfilename", findfilename, "", CFG_STRING, FALSE,
262 "# Findfilename is the name of the index file which is used by\n"
263 "# the FIND command.\n"},
264
265 {"numretry", &numretry, (void *)8, CFG_INTEGER, FALSE,
266 "# Number of retries to connect to the same server before giving up.\n"},
267
268 {"storedays", &logdays, (void *)7, CFG_INTEGER, FALSE,
269 "# The number of logfiles to keep, and therefore which\n"
270 "# logfiles to remove automatically!\n"},
271
272 {"seenmonths", &seenmonths, (void *)6, CFG_INTEGER, FALSE,
273 "# Maximum number of months to keep old entries in the seenfile.\n"},
274
275 {"tellmonths", &tellmonths, (void *)2, CFG_INTEGER, FALSE,
276 "# Maximum number of months to keep old entries in tellfile.\n"},
277
278 {"warnmonths", &warnmonths, (void *)3, CFG_INTEGER, FALSE,
279 "# Maximum number of months to keep old entries in warnlist.\n"},
280
281 {"newsexpire", &newsexpire, (void *)90, CFG_INTEGER, FALSE,
282 "# Default number of days of a news item to live.\n"},
283
284 {"netburp", &netburp, (void *)NETBURPTIME, CFG_INTEGER, FALSE,
285 "# Netburp is the period (in seconds) after a netjoin where FLOOD\n"
286 "# is off, to prevent kicking people because of an sudden exchange\n"
287 "# of data between the servers (which usually is called a netburp).\n"},
288
289 {"myhost", dancer_myhost, "", CFG_STRING, FALSE,
290 "# The IP number of the host that runs this bot. It should be a valid\n"
291 "# IP from one of your machine's network interfaces or this is likely\n"
292 "# to severly confuse this program. DON'T set this if you don't know\n"
293 "# exactly what you are doing and why.\n"},
294
295 {"askforops", askforops, "", CFG_STRING, FALSE,
296 "# Askforops is an action that the bot does when entering the\n"
297 "# channel, to make people aware that it would like to get opped.\n"},
298
299 {"opaction", opaction, "", CFG_STRING, FALSE,
300 "# Opaction is a kind of passive auto-op. It ops a user/bot if\n"
301 "# the level is exactly LEVELBOT and it makes an action starting\n"
302 "# with the content of opaction. If no opaction is supplied this\n"
303 "# passive auto-op is disabled.\n"},
304
305 {NULL, NULL, NULL, CFG_COMMENT, FALSE,
306 "#################################################################\n"
307 "# Normally you aren't required to touch anything below.\n"
308 "# Use LOG, CHGCMDLEV and SET commands to configure the\n"
309 "# appropriate items online.\n"},
310
311 /* --- Filenames --- */
312 {"banfile", banfile, BANFILE, CFG_STRING, FALSE,
313 "# File name to store ban information in.\n"},
314
315 {"explainfile", expfile, EXPFILE, CFG_STRING, FALSE,
316 "# Explainfile contains all standard explainations. Explainations that\n"
317 "# are added force this file to get re-written.\n"},
318
319 {"fplfile", fplconf, FPLFILE, CFG_STRING, FALSE,
320 "# fplfile is the name of the fpl-config file.\n"},
321
322 {"funcfile", funcfile, FUNCFILE, CFG_STRING, FALSE,
323 "# Funcfile is the name of the file which is read for the 'funcs'/\n"
324 "# aliases Dancer supports.\n"},
325
326 {"logfile", logfile, LOGFILE, CFG_STRING, FALSE,
327 "# This is the prefix to use for the log files.\n"},
328
329 {"newsfile", newsfile, NEWSFILE, CFG_STRING, FALSE,
330 "# File name to store news items in (for the NEWS* commands).\n"},
331
332 {"seenfile", seenfile, SEENFILE, CFG_STRING, FALSE,
333 "# Seenfile contains all the info on who has visited the channel.\n"},
334
335 {"servfile", servfile, SERVFILE, CFG_STRING, FALSE,
336 "# Servfile is the name of the file used for the server list.\n"},
337
338 {"setfile", setfile, SETFILE, CFG_STRING, FALSE,
339 "# Setfile contains all saved settings. It overrides the config stored\n"
340 "# in the .config file.\n"},
341
342 {"tellfile", tellfile, TELLFILE, CFG_STRING, FALSE,
343 "# Tellfile is the file where all TELL messages are stored.\n"},
344
345 {"userfile", userfile, USERFILE, CFG_STRING, FALSE,
346 "# This file contains all registered users.\n"},
347
348 {"warnfile", warnfile, WARNFILE, CFG_STRING, FALSE,
349 "# File name to store warning information in.\n"},
350
351 /* --- User / command levels --- */
352 {"level.anybody", &levels[0], (void *) 0, CFG_INTEGER, FALSE,
353 "# Which numerical value to use for ANYBODY.\n"},
354
355 {"level.recognized", &levels[1], (void *) 10, CFG_INTEGER, FALSE,
356 "# Which numerical value to use for RECOGNIZED.\n"},
357
358 {"level.chanop", &levels[2], (void *) 20, CFG_INTEGER, FALSE,
359 "# Which numerical value to use for CHANOP.\n"},
360
361 {"level.trusted", &levels[3], (void *) 50, CFG_INTEGER, FALSE,
362 "# Which numerical value to use for TRUSTED.\n"},
363
364 {"level.expert", &levels[4], (void *)100, CFG_INTEGER, FALSE,
365 "# Which numerical value to use for EXPERT.\n"},
366
367 {"level.maintainer", &levels[5], (void *)200, CFG_INTEGER, FALSE,
368 "# Which numerical value to use for MAINTAINER.\n"},
369
370 {"level.owner", &levels[6], (void *)242, CFG_INTEGER, FALSE,
371 "# Which numerical value to use for OWNER.\n"},
372
373 {"linkvalue", &linkvalue, (void *)0, CFG_INTEGER, FALSE, NULL},
374
375 {NULL, NULL, NULL, CFG_COMMENT, FALSE,
376 "#################################################################\n"
377 "# Everything below this line can be configured online using\n"
378 "# LOG, CHGCMDLEV and SET commands.\n"},
379
380 {"activelog", &activelog, (void *)-1, CFG_INTEGER, TRUE,
381 "# Numerical representation of what information that should be\n"
382 "# included in the logfile.\n"},
383
384 /* This *is* saved but differently (thus the FALSE): */
385 {"chgcmdlev", ChgCmdLev, NULL, CFG_FUNCTION, FALSE,
386 "# Change the level requirement for single command by entering\n"
387 "# them here. Use the format <command> <level>. One entry per\n"
388 "# line and chgcmdlev:-label.\n"},
389
390 /* --- Ban settings --- */
391 {"ban.autounban", &autounban, BFALSE, CFG_SWITCH, TRUE,
392 "# Automatically unbans the least important ban when the channel\n"
393 "# reaches 18 bans in the list.\n"},
394
395 {"ban.banprotect", &banprotect, BTRUE, CFG_SWITCH, TRUE,
396 "# Enable banprotection.\n"},
397
398 {"ban.banuserkicks", &banuserkicks, BTRUE, CFG_SWITCH, TRUE,
399 "# Count user kicks when deciding whether to ban because of too\n"
400 "# many kicks within a certain time.\n"},
401
402 {"ban.bantime", &pubbantime, (void *)0, CFG_INTEGER, TRUE,
403 "# Default ban time (in seconds) for public bans in the channel.\n"},
404
405 {"ban.botbantime", &defbantime, (void *)0, CFG_INTEGER, TRUE,
406 "# Default time (in seconds) of a bot ban without time specified.\n"},
407
408 {"ban.kickban", &kickbans, BTRUE, CFG_SWITCH, TRUE,
409 "# Kick banned users if they join (split or lagged servers).\n"},
410
411 {"ban.reportban", &reportban, BFALSE, CFG_SWITCH, TRUE,
412 "# Report about bans in public.\n"},
413
414 /* --- Flood settings --- */
415 {"flood.beep", &beepcheck, BTRUE, CFG_SWITCH, TRUE,
416 "# Kick beepers.\n"},
417
418 {"flood.bomb", &avalance, BTRUE, CFG_SWITCH, TRUE,
419 "# Kick CTCP bombers.\n"},
420
421 {"flood.colour", &colourcheck, BTRUE, CFG_SWITCH, TRUE,
422 "# Kick colourcode (ab)users.\n"},
423
424 {"flood.ctcp", &ctcpmode, BTRUE, CFG_SWITCH, TRUE,
425 "# Prevent CTCP floods.\n"},
426
427 {"flood.fakename", &fakenamemode, BTRUE, CFG_SWITCH, TRUE,
428 "# Kick guests joining with faked host/domain names.\n"},
429
430 {"flood.flood", &floodmode, BTRUE, CFG_SWITCH, TRUE,
431 "# Prevent public floods.\n"},
432
433 {"flood.multi", &multimode, BTRUE, CFG_SWITCH, TRUE,
434 "# Prevent user to join from the same account multiple times.\n"},
435
436 {"flood.nick", &nickflood, BTRUE, CFG_SWITCH, TRUE,
437 "# Kick nick flooders.\n"},
438
439 {"flood.repeat", &repeatmode, BTRUE, CFG_SWITCH, TRUE,
440 "# Prevent repeaters.\n"},
441
442 {"flood.upper", &uppercheck, BFALSE, CFG_SWITCH, TRUE,
443 "# Check for uppercase violations.\n"},
444
445 {"flood.xdcc", &xdccmode, BFALSE, CFG_SWITCH, TRUE,
446 "# Kick xdcc announcers.\n"},
447
448 /* --- Misc settings --- */
449 {"misc.autojoin", &autojoin, BTRUE, CFG_SWITCH, TRUE,
450 "# Join channel automatically if being kicked.\n"},
451
452 {"misc.autoop", &autoop, BFALSE, CFG_SWITCH, TRUE,
453 "# Enable auto-ops.\n"},
454
455 {"misc.ckey", ckey, "", CFG_STRING, TRUE,
456 "# Ckey is the channel key.\n"},
457
458 {"misc.cmode", cmodes, "", CFG_STRING, TRUE,
459 "# Cmode determines which channel modes the bot should try\n"
460 "# to keep if lockmode is on.\n"},
461
462 {"misc.climit", &climit, (void *)0, CFG_INTEGER, TRUE,
463 "# Climit is the channel +l limit, 0 disables.\n"},
464
465 {"misc.deop", &deopprotect, BTRUE, CFG_SWITCH, TRUE,
466 "# Check for massive deoppers.\n"},
467
468 {"misc.helpsyntax", &helpsyntax, BTRUE, CFG_SWITCH, TRUE,
469 "# Make the syntax information get displayed when HELP is used.\n"},
470
471 {"misc.invitable", &invitable, BTRUE, CFG_SWITCH, TRUE,
472 "# Join a channel if being /invite'd (by a high-level user).\n"},
473
474 {"misc.key", &lockkey, BTRUE, CFG_SWITCH, TRUE,
475 "# Lock the channel key.\n"},
476
477 {"misc.limit", &locklimit, BTRUE, CFG_SWITCH, TRUE,
478 "# Lock the channel limit.\n"},
479
480 {"misc.mode", &lockmode, BTRUE, CFG_SWITCH, TRUE,
481 "# Lock the channel mode.\n"},
482
483 {"misc.netsplit", &netsplitmode, BTRUE, CFG_SWITCH, TRUE,
484 "# Deop and unban server ops/bans.\n"},
485
486 {"misc.opprotect", &opprotect, BFALSE, CFG_SWITCH, TRUE,
487 "# Protect channel operators. With this enabled, non-chanop users will\n"
488 "# not be allowed to deop or kick chan-op users. The bot will deop the\n"
489 "# deoper and op the chan-op users (if they were deoped).\n"},
490
491 {"misc.strictop", &strictopmode, BFALSE, CFG_SWITCH, TRUE,
492 "# With this enabled, non-recognized users will not be allowed to get\n"
493 "# chanop status by people without very high status. LEVELOP can\n"
494 "# be used to define the level of the allowed ops.\n"},
495
496 /* --- Threshold settings --- */
497 {"thres.floodbeeps", &floodbeeps, (void *)2, CFG_INTEGER, TRUE,
498 "# Maximum number of public beeps allowed.\n"},
499
500 {"thres.floodjoins", &floodjoins, (void *)3, CFG_INTEGER, TRUE,
501 "# Number of joins accepted from the same hostpattern.\n"},
502
503 {"thres.floodrate", &floodrate, (void *)3, CFG_INTEGER, TRUE,
504 "# Prevent more than FLOODRATE messages in FLOODTIME seconds.\n"},
505
506 {"thres.repeatrate", &floodrepeatrate, (void *)3, CFG_INTEGER, TRUE,
507 "# Prevent more than FLOODRATE messages in FLOODTIME seconds.\n"},
508
509 {"thres.repeattime", &floodrepeattime, (void *)20, CFG_INTEGER, TRUE,
510 "# See FLOODREPEATRATE.\n"},
511
512 {"thres.floodtime", &floodtime, (void *)1, CFG_INTEGER, TRUE,
513 "# See FLOODRATE.\n"},
514
515 /* --- Verbose settings --- */
516 {"verbose.comment", &dispcomment, BFALSE, CFG_SWITCH, TRUE,
517 "# Enable user-comments on join.\n"},
518
519 {"verbose.mute", &mute, BFALSE, CFG_SWITCH, TRUE,
520 "# Enable/disable mute mode.\n"},
521
522 {"verbose.say", &saymode, BTRUE, CFG_SWITCH, TRUE,
523 "# Enable/disable the SAY and ME commands.\n"},
524
525 {"verbose.talk", &talkative, BFALSE, CFG_SWITCH, TRUE,
526 "# Talkative mode.\n"},
527
528 {"verbose.warn", &warnmode, BTRUE, CFG_SWITCH, TRUE,
529 "# Report about people on the warnlist.\n"},
530
531 {"verbose.welcome", &welcome, BFALSE, CFG_SWITCH, TRUE,
532 "# Welcome new users.\n"},
533
534 /* --- Owner settings --- */
535 {"owner.execprotect", &execprotect, BTRUE, CFG_SWITCH, TRUE,
536 "# Prevents shell executions by the bot.\n"},
537
538 {"owner.identprotect", &identprotect, BTRUE, CFG_SWITCH, TRUE,
539 "# Prevent users from being able to use the IDENT command.\n"},
540
541 {"owner.language", language, "English", CFG_STRING, TRUE,
542 "# Set primary language for the bot to use.\n"
543 "# ('dansk', 'deutsch', 'english', 'espa�ol', 'fran�ais', 'nederlands',\n"
544 "# 'norsk', 'svenska' and 'suomi' are supported languages).\n"},
545
546 {"owner.loopservers", &loopservers, BFALSE, CFG_SWITCH, TRUE,
547 "# Makes the bot loop the serverlist forever.\n"},
548
549 {"owner.oplevel", &oplevel, (void *)0, CFG_INTEGER, TRUE,
550 "# Users with level lower than OPLEVEL are not allowed to get OPs in\n"
551 "# the channel. Setting oplevel to 0 sets it off. See also opprotect\n"
552 "# and strictop.\n"},
553 };
554
555
556 /* --- MakeConfig ------------------------------------------------- */
557
MakeConfig(void)558 void MakeConfig(void)
559 {
560 int i;
561 itemlist *l;
562
563 snapshot;
564 fprintf(stdout,
565 "#################################################################\n"
566 "# This is an autogenerated config file done by " VERSIONMSG "\n"
567 "#\n"
568 "# You _must_ set the three entries server, channel, and nick.\n"
569 "# (remove preceeding '#' letters to make the labels \"take effect\")\n"
570 );
571 for (i=0; i < sizeof(cfg)/sizeof(cfg[0]); i++) {
572 if (cfg[i].verbose) {
573 /* Print the help string */
574 fprintf(stdout, "\n%s", cfg[i].verbose);
575
576 /* Print out the item and its value (commented out and with default
577 * value if unchanged) */
578 switch (cfg[i].flags) {
579
580 case CFG_SWITCH:
581 if (cfg[i].changed)
582 fprintf(stdout, "%s = %s\n", cfg[i].label, *(bool *)cfg[i].value ? "On" : "Off");
583 else
584 fprintf(stdout, "#%s = %s\n", cfg[i].label, cfg[i].def ? "On" : "Off");
585 break;
586
587 case CFG_INTEGER:
588 if (cfg[i].changed)
589 fprintf(stdout, "%s = %d\n", cfg[i].label, *(int *)cfg[i].value);
590 else
591 fprintf(stdout, "#%s = %d\n", cfg[i].label, (int)cfg[i].def);
592 break;
593
594 case CFG_STRING:
595 if (cfg[i].changed)
596 fprintf(stdout, "%s = %s\n", cfg[i].label, (char *)cfg[i].value);
597 else
598 fprintf(stdout, "#%s = %s\n", cfg[i].label, (char *)cfg[i].def);
599 break;
600
601 case CFG_LIST:
602 if (cfg[i].changed) {
603 int n=0;
604
605 fprintf(stdout, "%s = ", cfg[i].label);
606 for (l = First(*(itemlist **)cfg[i].value); l; l = Next(l)) {
607 fprintf(stdout, "%s%s", n ? "," : "", l->pointer);
608 n++;
609 }
610 fprintf(stdout, "\n");
611 }
612 else
613 fprintf(stdout, "#%s = %s\n", cfg[i].label, (char *)cfg[i].def);
614 break;
615
616 default:
617 break;
618
619 }
620 }
621 }
622 }
623
624 /* --- BuildList -------------------------------------------------- */
625
BuildList(itemlist ** appendHead,char * string)626 itemlist *BuildList(itemlist **appendHead, char *string)
627 {
628 char buffer[BIGBUFFER];
629 int i=0;
630 itemlist *head, *l;
631
632 snapshot;
633 if ((NULL == appendHead) || (NULL == *appendHead)) {
634 head = NewList(itemlist);
635 if (appendHead)
636 *appendHead = head;
637 }
638 else
639 head = *appendHead;
640
641 if (head) {
642 #ifdef HAVE_N_IN_SCANF
643 int index;
644
645 /*
646 * Execution of a %n directive does not increment the
647 * assignment count returned at the completion of
648 * execution of the function.
649 */
650 while (1 == StrScan(&string[i], "%"BIGBUFFERTXT"[^,\n] %n", buffer, &index)) {
651 i += index;
652 #else
653 while (1 == StrScan(&string[i], "%"BIGBUFFERTXT"[^,\n]", buffer)) {
654 i += StrLength(buffer);
655 #endif
656 if (',' == string[i])
657 i++;
658
659 l = NewEntry(itemlist);
660 if (l) {
661 InsertLast(head, l);
662 l->pointer = (void *)StrDuplicate(buffer);
663 }
664 else {
665 break;
666 }
667 }
668 }
669 return head;
670 }
671
672 /* --- PreConfig -------------------------------------------------- */
673
674 static bool inited = FALSE;
675
676 void PreConfig(void)
677 {
678 int i;
679
680 snapshot;
681 for (i=0; i < sizeof(cfg)/sizeof(cfg[0]); i++) {
682 switch (cfg[i].flags) {
683
684 case CFG_SWITCH:
685 *(bool *)cfg[i].value = (bool)((int)cfg[i].def);
686 break;
687
688 case CFG_INTEGER:
689 *(int *)cfg[i].value = (int)cfg[i].def;
690 break;
691
692 case CFG_STRING:
693 /* Need limit check!!! */
694 StrCopy((char *)cfg[i].value, (char *)cfg[i].def);
695 break;
696
697 default:
698 break;
699
700 }
701 cfg[i].changed = FALSE;
702 }
703
704 inited = TRUE;
705 }
706
707 /* --- PostConfig ------------------------------------------------- */
708
709 void PostConfig(void)
710 {
711 int i;
712
713 snapshot;
714 for (i=0; i < sizeof(cfg)/sizeof(cfg[0]); i++) {
715 if (CFG_LIST == cfg[i].flags) {
716 if (NULL == First(*(itemlist **)cfg[i].value))
717 BuildList((itemlist **)cfg[i].value, cfg[i].def);
718 }
719 }
720 defaultlang = LanguageNum(language);
721 }
722
723 /* --- ConfigAddItem ---------------------------------------------- */
724
725 void ConfigAddItem(char *line)
726 {
727 char keyword[MINIBUFFER];
728 char valuebuffer[BIGBUFFER];
729 int i;
730
731 snapshot;
732 if (2 <= StrScan(line, "%"MINIBUFFERTXT"[a-zA-Z0-9.] %*[=: ] %"BIGBUFFERTXT"[^\n]",
733 keyword, valuebuffer)) {
734 for (i=0; i < sizeof(cfg)/sizeof(cfg[0]); i++) {
735 if (StrEqual(keyword, cfg[i].label)) { /* Match */
736 switch (cfg[i].flags) {
737
738 case CFG_SWITCH:
739 if (StrEqual(valuebuffer, "ON") ||
740 StrEqual(valuebuffer, "YES") ||
741 atoi(valuebuffer))
742 *(bool *)cfg[i].value = TRUE;
743 else
744 *(bool *)cfg[i].value = FALSE;
745 break;
746
747 case CFG_INTEGER:
748 *(int *)cfg[i].value = atoi(valuebuffer);
749 break;
750
751 case CFG_STRING:
752 /* Need limit check!!! */
753 StrCopy((char *)cfg[i].value, valuebuffer);
754 break;
755
756 case CFG_LIST:
757 BuildList((itemlist **)cfg[i].value, valuebuffer);
758 break;
759
760 case CFG_FUNCTION:
761 (*(void (*)(char *, char *))cfg[i].value)(cfg[i].def, valuebuffer);
762 break;
763
764 default:
765 break;
766
767 }
768 cfg[i].changed = TRUE;
769 break;
770 }
771 }
772 }
773 }
774
775 /* --- ConfigInit ------------------------------------------------- */
776
777 bool ConfigInit(void)
778 {
779 char line[MAXLINE];
780 FILE *f;
781
782 snapshot;
783 PreConfig();
784
785 f = fopen(CONFIGFILE, "r");
786 if (f) {
787 while (fgets(line, sizeof(line), f)) {
788 switch (line[0]) {
789
790 case '#':
791 case '\n':
792 break;
793
794 default:
795 ConfigAddItem(line);
796 break;
797
798 }
799 }
800 fclose(f);
801
802 f = fopen(setfile, "r");
803 if (f) {
804 while (fgets(line, sizeof(line), f)) {
805 switch (line[0]) {
806
807 case '#':
808 case '\n':
809 break;
810
811 default:
812 ConfigAddItem(line);
813 break;
814
815 }
816 }
817 fclose(f);
818 }
819
820 PostConfig();
821
822 StrCopy(chanmodes, cmodes);
823 StrCopy(chankey, ckey);
824 opactionlen = StrLength(opaction);
825
826 InitSets();
827
828 return TRUE;
829 }
830 return FALSE;
831 }
832
833 /* --- SaveSettings ----------------------------------------------- */
834
835 void SaveSettings(void)
836 {
837 extern struct Command cmds[];
838 char tempfile[MIDBUFFER];
839 bool ok = TRUE;
840 int numchanged = 0;
841 int i;
842 FILE *f;
843
844 snapshot;
845 if (NIL == setfile[0])
846 return;
847
848 StrFormatMax(tempfile, sizeof(tempfile), "%s~", setfile);
849
850 f = fopen(tempfile, "w");
851 if (f) {
852 for (i=0; ok && (i < sizeof(cfg)/sizeof(cfg[0])); i++) {
853 if (cfg[i].setting) {
854 if (cfg[i].verbose) {
855 /* Write comment */
856 if (0 > fprintf(f, "\n%s", cfg[i].verbose)) {
857 ok = FALSE;
858 break;
859 }
860 }
861 switch (cfg[i].flags) {
862
863 case CFG_SWITCH:
864 if (0 > fprintf(f, "%s = %s\n", cfg[i].label, OnOff(*(bool *)cfg[i].value)))
865 ok = FALSE;
866 break;
867
868 case CFG_INTEGER:
869 if (0 > fprintf(f, "%s = %d\n", cfg[i].label, *(int *)cfg[i].value))
870 ok = FALSE;
871 break;
872
873 case CFG_STRING:
874 if (0 > fprintf(f, "%s = %s\n", cfg[i].label, (char *)cfg[i].value))
875 ok = FALSE;
876 break;
877
878 default:
879 break;
880
881 }
882 }
883 }
884
885 /* Save new command levels */
886 for (i=0; ok && cmds[i].name; i++) {
887 if (cmds[i].flags & CMD_CHANGED) {
888 if (1 == ++numchanged) {
889 if (0 > fprintf(f, "\n# Here follows a list of commands with their new levels:\n")) {
890 ok = FALSE;
891 break;
892 }
893 }
894 /* Save the new level */
895 if (0 > fprintf(f, "chgcmdlev: %s %d\n", cmds[i].name, cmds[i].level)) {
896 ok = FALSE;
897 break;
898 }
899 }
900 }
901 fclose(f);
902
903 if (ok)
904 rename(tempfile, setfile);
905 }
906 }
907
908 /* --- ConfigCleanup ---------------------------------------------- */
909
910 void ConfigCleanup(void)
911 {
912 snapshot;
913 if (!inited)
914 return;
915
916 SaveSettings();
917
918 /* Flush server list */
919 DeleteList(serverHead, FreeList);
920 }
921
922
923 /*********************************************************************
924 * The following piece of source is the new SET functions.
925 ********************************************************************/
926
927 #define SPECIAL_CMODE 1
928 #define SPECIAL_CKEY 2
929 #define SPECIAL_LANGUAGE 3
930
931 static struct SetItem ban[] = {
932 {"AUTOUNBAN", LEVEL_ANYBODY, SET_ONOFF, &autounban, 0, msg_helpset_autounban},
933 {"BANPROTECT", LEVEL_ANYBODY, SET_ONOFF, &banprotect, 0, msg_helpset_banprotect},
934 {"BANUSERKICKS", LEVEL_ANYBODY, SET_ONOFF, &banuserkicks, 0, msg_helpset_banuserkicks},
935 {"BANTIME", LEVEL_BOT, SET_TIME, &pubbantime, 0, msg_helpset_bantime},
936 {"BOTBANTIME", LEVEL_BOT, SET_TIME, &defbantime, 0, msg_helpset_botbantime},
937 {"KICKBAN", LEVEL_ANYBODY, SET_ONOFF, &kickbans, 0, msg_helpset_kickban},
938 {"REPORTBAN", LEVEL_ANYBODY, SET_ONOFF, &reportban, 0, msg_helpset_reportban},
939 {NULL, 0, 0, NULL, 0, NULL} /* End series with a NULL-entry */
940 };
941
942 static struct SetItem flood[] = {
943 {"BEEP", LEVEL_ANYBODY, SET_ONOFF, &beepcheck, 0, msg_helpset_beep},
944 {"BOMB", LEVEL_ANYBODY, SET_ONOFF, &avalance, 0, msg_helpset_bomb},
945 {"COLOUR", LEVEL_ANYBODY, SET_ONOFF, &colourcheck, 0, msg_helpset_colour},
946 {"CTCP", LEVEL_ANYBODY, SET_ONOFF, &ctcpmode, 0, msg_helpset_ctcp},
947 {"FAKENAME", LEVEL_ANYBODY, SET_ONOFF, &fakenamemode, 0, msg_helpset_fakename},
948 {"FLOOD", LEVEL_ANYBODY, SET_ONOFF, &floodmode, 0, msg_helpset_flood},
949 {"MULTI", LEVEL_ANYBODY, SET_ONOFF, &multimode, 0, msg_helpset_multi},
950 {"NICK", LEVEL_ANYBODY, SET_ONOFF, &nickflood, 0, msg_helpset_nick},
951 {"REPEAT", LEVEL_ANYBODY, SET_ONOFF, &repeatmode, 0, msg_helpset_repeat},
952 {"UPPER", LEVEL_ANYBODY, SET_ONOFF, &uppercheck, 0, msg_helpset_upper},
953 {"XDCC", LEVEL_ANYBODY, SET_ONOFF, &xdccmode, 0, msg_helpset_xdcc},
954 {NULL, 0, 0, NULL, 0, NULL} /* End series with a NULL-entry */
955 };
956
957 static struct SetItem misc[] = {
958 {"AUTOJOIN", LEVEL_ANYBODY, SET_ONOFF, &autojoin, 0, msg_helpset_autojoin},
959 {"AUTOOP", LEVEL_ANYBODY, SET_ONOFF, &autoop, 0, msg_helpset_autoop},
960 {"CKEY", LEVEL_ANYBODY, SET_SPEC, NULL, SPECIAL_CKEY, msg_helpset_ckey},
961 {"CMODE", LEVEL_ANYBODY, SET_SPEC, NULL, SPECIAL_CMODE, msg_helpset_cmode},
962 {"CLIMIT", LEVEL_ANYBODY, SET_NUM, &climit, 0, msg_helpset_climit},
963 {"DEOP", LEVEL_ANYBODY, SET_ONOFF, &deopprotect, 0, msg_helpset_deop},
964 {"HELPSYNTAX",LEVEL_ANYBODY, SET_ONOFF, &helpsyntax, 0, msg_helpset_helpsyntax},
965 {"INVITE", LEVEL_ANYBODY, SET_ONOFF, &invitable, 0, msg_helpset_invite},
966 {"KEY", LEVEL_ANYBODY, SET_ONOFF, &lockkey, 0, msg_helpset_key},
967 {"LIMIT", LEVEL_ANYBODY, SET_ONOFF, &locklimit, 0, msg_helpset_limit},
968 {"MODE", LEVEL_ANYBODY, SET_ONOFF, &lockmode, 0, msg_helpset_mode},
969 {"NETSPLIT", LEVEL_ANYBODY, SET_ONOFF, &netsplitmode, 0, msg_helpset_netsplit},
970 {"OPPROTECT", LEVEL_BOT, SET_ONOFF, &opprotect, 0, msg_helpset_opprotect},
971 {"STRICTOP", LEVEL_BOT, SET_ONOFF, &strictopmode, 0, msg_helpset_strictop},
972 {NULL, 0, 0, NULL, 0, NULL} /* End series with a NULL-entry */
973 };
974
975 static struct SetItem thres[] = {
976 {"FLOODBEEPS", LEVEL_ANYBODY, SET_NUM, &floodbeeps, 0, msg_helpset_floodbeeps},
977 {"FLOODJOINS", LEVEL_ANYBODY, SET_NUM, &floodjoins, 0, msg_helpset_floodjoins},
978 {"FLOODRATE", LEVEL_ANYBODY, SET_NUM, &floodrate, 0, msg_helpset_floodrate},
979 {"FLOODREPEATRATE", LEVEL_ANYBODY, SET_NUM, &floodrepeatrate, 0, msg_helpset_floodrepeatrate},
980 {"FLOODREPEATTIME", LEVEL_ANYBODY, SET_NUM, &floodrepeattime, 0, msg_helpset_floodrepeattime},
981 {"FLOODTIME", LEVEL_ANYBODY, SET_NUM, &floodtime, 0, msg_helpset_floodtime},
982 {NULL, 0, 0, NULL, 0, NULL} /* End series with a NULL-entry */
983 };
984
985 static struct SetItem verbose[] = {
986 {"COMMENT", LEVEL_ANYBODY, SET_ONOFF, &dispcomment, 0, msg_helpset_comment},
987 {"MUTE", LEVEL_ANYBODY, SET_ONOFF, &mute, 0, msg_helpset_mute},
988 {"SAY", LEVEL_ANYBODY, SET_ONOFF, &saymode, 0, msg_helpset_say},
989 {"TALK", LEVEL_ANYBODY, SET_ONOFF, &talkative, 0, msg_helpset_talk},
990 {"WARN", LEVEL_ANYBODY, SET_ONOFF, &warnmode, 0, msg_helpset_warn},
991 {"WELCOME", LEVEL_ANYBODY, SET_ONOFF, &welcome, 0, msg_helpset_welcome},
992 {NULL, 0, 0, NULL, 0, NULL} /* End series with a NULL-entry */
993 };
994
995 static struct SetItem owner[] = {
996 {"EXECPROTECT", LEVEL_ANYBODY, SET_ONOFF, &execprotect, 0, msg_helpset_execprotect},
997 {"IDENTPROTECT", LEVEL_ANYBODY, SET_ONOFF, &identprotect, 0, msg_helpset_identprotect},
998 {"LANGUAGE", LEVEL_ANYBODY, SET_SPEC, NULL, SPECIAL_LANGUAGE, msg_helpset_language},
999 {"LOOPSERVERS", LEVEL_ANYBODY, SET_ONOFF, &loopservers, 0, msg_helpset_loopservers},
1000 {"OPLEVEL", LEVEL_ANYBODY, SET_NUM, &oplevel, 0, msg_helpset_oplevel},
1001 {NULL, 0, 0, NULL, 0, NULL} /* End series with a NULL-entry */
1002 };
1003
1004 static struct SetGroup sets[] = {
1005 {"BAN", LEVEL_ANYBODY, ban, msg_setgroup_ban},
1006 {"FLOOD", LEVEL_ANYBODY, flood, msg_setgroup_flood},
1007 {"MISC", LEVEL_ANYBODY, misc, msg_setgroup_misc},
1008 {"THRESHOLDS", LEVEL_ANYBODY, thres, msg_setgroup_thres},
1009 {"VERBOSE", LEVEL_ANYBODY, verbose, msg_setgroup_verbose},
1010 {"OWNER", LEVEL_OWNER, owner, msg_setgroup_owner},
1011 };
1012
1013
1014 /* --- ShowSetItem ------------------------------------------------ */
1015
1016 /*
1017 * Fills in a buffer, showing the contents of the specified item.
1018 * Returns buffer.
1019 */
1020
1021 static char *ShowSetItem(char *buffer, int buffer_size, struct SetItem *item)
1022 {
1023 char level[32] = "";
1024
1025 snapshot;
1026 if (item->level) {
1027 StrFormatMax(level, sizeof(level), " [%d]", item->level);
1028 }
1029
1030 StrFormatMax(buffer, buffer_size, "%s%s = ", item->name, level);
1031
1032 switch (item->flags) {
1033
1034 case SET_ONOFF:
1035 StrAppendMax(buffer, buffer_size, OnOff(*(bool *)item->value));
1036 break;
1037
1038 case SET_NUM:
1039 StrFormatAppendMax(buffer, buffer_size, "%d", *(int *)item->value);
1040 break;
1041
1042 case SET_TIME:
1043 StrAppendMax(buffer, buffer_size, SecsToString(*(int *)item->value));
1044 break;
1045
1046 case SET_SPEC:
1047 switch (item->ID) {
1048
1049 case SPECIAL_CMODE:
1050 StrAppendMax(buffer, buffer_size, cmodes);
1051 break;
1052
1053 case SPECIAL_CKEY:
1054 StrAppendMax(buffer, buffer_size, ckey);
1055 break;
1056
1057 case SPECIAL_LANGUAGE:
1058 StrAppendMax(buffer, buffer_size, language);
1059 break;
1060
1061 }
1062 break;
1063
1064 }
1065
1066 return buffer;
1067 }
1068
1069 /* --- ShowSetGroup ----------------------------------------------- */
1070
1071 /* Shows the SETs of the specified group. All items in the group
1072 * will get displayed (even if some might have higher access levels)
1073 * if the person has the access.
1074 *
1075 * Output format:
1076 * "Group OWNER [242]: EXECPROTECT = on, OTHERFLAG = off"
1077 */
1078
1079 static void ShowSetGroup(char *from, struct SetGroup *grp)
1080 {
1081 char buffer[MIDBUFFER];
1082 char set[MINIBUFFER];
1083 char level[32] = "";
1084 int count = 0;
1085 int i;
1086 struct SetItem *item = grp->group;
1087
1088 snapshot;
1089 if (grp->level > current->level) {
1090 return;
1091 }
1092
1093 if (grp->level) {
1094 StrFormatMax(level, sizeof(level), " [%d]", grp->level);
1095 }
1096
1097 StrFormatMax(buffer, sizeof(buffer), "<%s%s>: ", grp->name, level);
1098
1099 for (i=0; item[i].name; i++) {
1100
1101 /* Don't show non-accessible items */
1102 if (item[i].level > current->level)
1103 continue;
1104
1105 ShowSetItem(set, sizeof(set), &item[i]);
1106
1107 if ((StrLength(buffer) + StrLength(set) + 1) >= sizeof(buffer)) {
1108 Send(from, buffer);
1109 buffer[0] = (char)0;
1110 count = 0;
1111 }
1112
1113 StrFormatAppendMax(buffer, sizeof(buffer), "%s%s", count ? ", " : "", set);
1114 count++;
1115 }
1116
1117 Send(from, buffer);
1118 }
1119
1120 /* --- FindItemInGroup -------------------------------------------- */
1121
1122 int static FindItemInGroup(struct SetGroup *grp, char *label,
1123 struct SetItem **item)
1124 {
1125 int i;
1126 int amount = 0;
1127 struct SetItem *group = grp->group;
1128 struct SetItem *hit = NULL;
1129
1130 snapshot;
1131 for (i=0; group[i].name; i++) {
1132 #if 0
1133 if (group[i].level > current->level)
1134 /*
1135 * Don't even bother to try labels we aren't allowed
1136 * to access.
1137 */
1138 continue;
1139 #endif
1140
1141 if (StrEqualMax(group[i].name, StrLength(label), label)) {
1142 *item = &group[i];
1143 amount++;
1144 }
1145 }
1146 return amount;
1147 }
1148
1149 /* --- GimmeGroup ------------------------------------------------- */
1150
1151 /* Returns the group number which matches the 'group' parameter.
1152 * Set 'error' to TRUE to get error reports, FALSE will make it
1153 * return -1 silently.
1154 */
1155
1156 static struct SetGroup *GimmeGroup(char *from, char *group, bool error)
1157 {
1158 int grpnum = -1;
1159 int amount = 0;
1160 int i;
1161
1162 snapshot;
1163 for (i=0; i < sizeof(sets)/sizeof(sets[0]); i++) {
1164 #if 0
1165 if (sets[i].level > current->level)
1166 /*
1167 * Don't even bother to search for a group that we aren't allowed
1168 * to access.
1169 */
1170 continue;
1171 #endif
1172 if (StrEqualMax(sets[i].name, StrLength(group), group)) {
1173 amount++;
1174 grpnum = i;
1175 }
1176 }
1177
1178 if (0 == amount) {
1179 if (error)
1180 Sendf(errfrom, GetText(msg_group_doesnt_exist), group);
1181 return NULL;
1182 }
1183 else if (2 <= amount) {
1184 if (error)
1185 Sendf(errfrom, GetText(msg_matches_several_groups), group);
1186 return NULL;
1187 }
1188 return &sets[grpnum];
1189 }
1190
1191 /* --- GimmeItem -------------------------------------------------- */
1192
1193 /* Returns the label which matches the 'label' parameter.
1194 * Set 'error' to TRUE to get error reports, FALSE will make it
1195 * return -1 silently.
1196 * The 'retgrp' will get a pointer to the group in which the label
1197 * was found.
1198 */
1199
1200 struct SetItem *GimmeItem(char *from, char *group, char *label, bool error,
1201 struct SetGroup **retgrp)
1202
1203 {
1204 struct SetItem *hit;
1205 struct SetGroup *grp;
1206 int amount = 0;
1207 int i;
1208
1209 snapshot;
1210 if (group[0]) {
1211 grp = GimmeGroup(from, group, TRUE);
1212 if (NULL == grp)
1213 return NULL;
1214 amount = FindItemInGroup(grp, label, &hit);
1215 }
1216 else {
1217 int num;
1218
1219 for (i=0; i<sizeof(sets)/sizeof(sets[0]);i++) {
1220 num = FindItemInGroup(&sets[i], label, &hit);
1221 amount += num;
1222 if (num)
1223 grp = &sets[i];
1224 }
1225 }
1226 if (0 == amount) {
1227 if (error)
1228 Sendf(errfrom, GetText(msg_item_doesnt_exist),
1229 label, group[0] ? GetText(msg_in_that_group) : "");
1230 return NULL;
1231 }
1232 else if (2 <= amount) {
1233 if (error)
1234 Sendf(errfrom, GetText(msg_matches_several_items), label);
1235 return NULL;
1236 }
1237
1238 *retgrp = grp;
1239 return hit;
1240 }
1241
1242 /* --- HelpSet ---------------------------------------------------- */
1243
1244 /* Display help text and information about the specified token.
1245 * (group or item)
1246 */
1247
1248 int HelpSet(char *from, char *token)
1249 {
1250 char set[MINIBUFFER];
1251 struct SetItem *hit;
1252 struct SetGroup *grp;
1253
1254 snapshot;
1255 /* First, try an item with this name */
1256 hit = GimmeItem(from, "", token, FALSE, &grp);
1257 if (hit) {
1258 SendMulti(from, "%s %s: %s (%s)", GetText(msg_set),
1259 hit->name, GetText(hit->help),
1260 (hit->level > current->level) ? GetText(msg_no_access) :
1261 ShowSetItem(set, sizeof(set), hit));
1262 }
1263 else {
1264 /* now, try a group names like this */
1265 grp = GimmeGroup(from, token, FALSE);
1266 if (grp) {
1267 SendMulti(from, "%s %s: %s.", GetText(msg_group), grp->name, GetText(grp->help));
1268 }
1269 else {
1270 Send(from, GetText(msg_cant_find_set_keyword));
1271 return TRUE;
1272 }
1273 }
1274 return FALSE;
1275 }
1276
1277 /* --- ShowSetAll ------------------------------------------------- */
1278
1279 /* Show all items in all groups */
1280
1281 void ShowSetAll(char *from)
1282 {
1283 int i;
1284
1285 snapshot;
1286 for (i=0; i < sizeof(sets)/sizeof(sets[0]); i++) {
1287 ShowSetGroup(from, &sets[i]);
1288 }
1289 }
1290
1291 /* --- SetSet ----------------------------------------------------- */
1292
1293 /* Called straight from command.c and the CmdSet(). Parse the input
1294 * and perform every action in here.
1295 */
1296
1297 int SetSet(char *from, char *line)
1298 {
1299 char group[32], dot[32], label[32], value[32];
1300 int amount = 0;
1301 int i;
1302 struct SetItem *hit;
1303 struct SetGroup *grp;
1304
1305 snapshot;
1306 i = StrScan(line, "%31[^ .\n]%31[. ]%31s %31s", group, dot, label, value);
1307
1308 switch (i) {
1309
1310 case -1:
1311 /*
1312 * This is what they call EOF, returned "If the input ends before
1313 * the first matching failure or conversion"
1314 */
1315 case 0:
1316 ShowSetAll(from);
1317 return FALSE;
1318
1319 case 1:
1320 /* One parameter, show the SETs for the specified group */
1321 grp = GimmeGroup(from, group, FALSE);
1322 if (NULL == grp) {
1323 /* We'll try to show the group that item belongs to then */
1324 hit = GimmeItem(from, "", group, FALSE, &grp);
1325 if (NULL == hit) {
1326 Send(errfrom, GetText(msg_i_dont_understand));
1327 return TRUE;
1328 }
1329 }
1330 ShowSetGroup(from, grp);
1331 return FALSE;
1332
1333 case 2:
1334 case 3:
1335 if ((2 == i) || StrIndex(dot, '.')) {
1336 /*
1337 * This just be an attempt to specify a group name, but we don't
1338 * have a value.
1339 */
1340 grp = GimmeGroup(from, group, TRUE);
1341 if (grp)
1342 ShowSetGroup(from, grp);
1343 else
1344 return TRUE;
1345 return FALSE;
1346 }
1347 /* Need limit check!!! */
1348 StrCopy(value, label);
1349 StrCopy(label, group);
1350 group[0] = (char)0; /* No group specified */
1351 break;
1352
1353 }
1354
1355 hit = GimmeItem(from, group, label, TRUE, &grp);
1356 if (NULL == hit)
1357 return TRUE;
1358
1359 /*
1360 * Access control could be done at lower layers. Using it this way,
1361 * everything but actually changing the SET will be available to
1362 * anyone (i.e help and display current status).
1363 */
1364 if (grp->level > current->level ||
1365 hit->level > current->level) {
1366 Send(errfrom, GetText(msg_dont_touch_this));
1367 return TRUE;
1368 }
1369
1370 switch (hit->flags) {
1371
1372 case SET_ONOFF:
1373 *(bool *)hit->value = IsOn(value);
1374 break;
1375
1376 case SET_NUM:
1377 *(int *)hit->value = atoi(value);
1378 if (StrEqualCase(hit->name, "OPLEVEL")) {
1379 if (oplevel > current->level)
1380 oplevel = current->level;
1381 }
1382 break;
1383
1384 case SET_TIME:
1385 *(int *)hit->value = ToSeconds(value);
1386 break;
1387
1388 case SET_SPEC:
1389 switch (hit->ID) {
1390
1391 case SPECIAL_CMODE:
1392 CmdCmode(from, value);
1393 break;
1394
1395 case SPECIAL_CKEY:
1396 CmdCkey(from, value);
1397 break;
1398
1399 case SPECIAL_LANGUAGE:
1400 defaultlang = LanguageNum(value);
1401 StrCopy(language, LanguageLocal(defaultlang));
1402 break;
1403
1404 }
1405 break;
1406
1407 }
1408
1409 SaveSettings();
1410 ShowSetGroup(from, grp);
1411 return FALSE;
1412 }
1413
1414 /* --- InitSets --------------------------------------------------- */
1415
1416 void InitSets(void)
1417 {
1418 int i;
1419 struct SetItem *item;
1420
1421 snapshot;
1422 for (i=0; i < sizeof(sets)/sizeof(sets[0]); i++) {
1423 sets[i].level = levels[ sets[i].level ];
1424 for (item = sets[i].group; item->name; item++)
1425 item->level = levels[ item->level ];
1426 }
1427 }
1428
1429 /* --- ChgCmdLev -------------------------------------------------- */
1430
1431 void ChgCmdLev(char *def, char *value)
1432 {
1433 char cmd[MINIBUFFER];
1434 int level;
1435 struct Command *command;
1436
1437 if (2 == StrScan(value, "%"MINIBUFFERTXT"s %d", cmd, &level)) {
1438 if ((level >= LEVELANYBODY) && (level <= LEVELOWNER)) {
1439 command = FindCommand(cmd);
1440 if (command) {
1441 command->level = level;
1442 command->flags |= CMD_CHANGED;
1443 }
1444 }
1445 }
1446 }
1447
1448 #if 0
1449 /******************************************************************************
1450 New stuff 970618 to better deal with the users' own info, flags and status.
1451
1452 This is 4.7+ stuff
1453
1454 __ __ _ __
1455 | \/ |_ _(_)_ __ / _| ___
1456 | |\/| | | | | | '_ \| |_ / _ \
1457 | | | | |_| | | | | | _| (_) |
1458 |_| |_|\__, |_|_| |_|_| \___/
1459 |___/
1460 *****************************************************************************/
1461
1462
1463 #define MYINFO_USER 0x80
1464 #define MYINFO_GUEST 0x40
1465
1466 typedef enum {
1467 MYINFO_LANGUAGE=1,
1468 MYINFO_REPORT,
1469 MYINFO_SPY,
1470 MYINFO_DEBUG,
1471 } myspecial;
1472
1473 /* debug-defines to make it compile */
1474 #define msg_myinfo_comment NULL
1475 #define msg_myinfo_email NULL
1476 #define msg_myinfo_language NULL
1477 #define msg_myinfo_report NULL
1478 #define msg_myinfo_spy NULL
1479 #define msg_myinfo_debug NULL
1480 #define msg_myinfo_info NULL
1481 #define msg_myinfo_flags NULL
1482
1483 static struct SetItem myinfoinfo[]={
1484 {"EMAIL",
1485 0,
1486 SET_STRING,
1487 (void *)offsetof(itemuser, realname),
1488 MYINFO_USER,
1489 msg_myinfo_email},
1490 /* replaces SETEMAIL */
1491
1492 {"COMMENT", 0, SET_STRING, (void *)offsetof(itemuser, comment), MYINFO_USER,
1493 msg_myinfo_comment},
1494 /* replaces COMMENT */
1495
1496 {"LANGUAGE", 0, SET_STRING,(void *)offsetof(itemuser, language) ,
1497 MYINFO_USER | MYINFO_LANGUAGE, msg_myinfo_language},
1498 /* replaces LANGUAGE */
1499 };
1500 static struct SetItem myinfoflags[]={
1501 {"REPORT", LEVEL_CHANOP, SET_ONOFF, NULL, MYINFO_REPORT, msg_myinfo_report},
1502 /* replaces REPORTADD and REPORTDEL */
1503
1504 {"SPY", LEVEL_BOT, SET_ONOFF, NULL, MYINFO_SPY, msg_myinfo_spy},
1505 /* replaces SPYADD and SPYDEL */
1506
1507 {"DEBUG", LEVEL_BOT, SET_ONOFF, NULL, MYINFO_DEBUG, msg_myinfo_debug},
1508 /* replaces DEBUGADD and DEBUGDEL */
1509 };
1510
1511 static struct SetGroup myinfo[]={
1512 {"INFO", LEVEL_RECOG, myinfoinfo, msg_myinfo_info},
1513 {"FLAGS", 0, myinfoflags, msg_myinfo_flags},
1514 };
1515
1516 #endif
1517