1 /*
2  * flags.c -- handles:
3  *   all the flag matching/conversion functions in one neat package :)
4  *
5  * $Id: flags.c,v 1.27 (0.9) 2004/01/11 16:00:40 [Xp-AvR] Exp $
6  */
7 
8 #include "main.h"
9 
10 extern char userfileCryptKey[];
11 extern int raw_log, require_p, noshare, allow_dk_cmds;
12 extern struct dcc_t *dcc;
13 
logmodes(char * s)14 int logmodes(char *s)
15 {
16   int i;
17   int res = 0;
18 
19   for (i = 0; i < strlen(s); i++)
20     switch (s[i]) {
21     case 'm':
22     case 'M':
23       res |= LOG_MSGS;
24       break;
25     case 'p':
26     case 'P':
27       res |= LOG_PUBLIC;
28       break;
29     case 'j':
30     case 'J':
31       res |= LOG_JOIN;
32       break;
33     case 'k':
34     case 'K':
35       res |= LOG_MODES;
36       break;
37     case 'c':
38     case 'C':
39       res |= LOG_CMDS;
40       break;
41     case 'E':
42       res |= LOG_EVANGELINE;
43       break;
44     case 'o':
45     case 'O':
46       res |= LOG_MISC;
47       break;
48     case 'b':
49     case 'B':
50       res |= LOG_BOTS;
51       break;
52     case 'r':
53     case 'R':
54       res |= raw_log ? LOG_RAW : 0;
55       break;
56     case 'w':
57     case 'W':
58       res |= LOG_WALL;
59       break;
60     case 'x':
61     case 'X':
62       res |= LOG_FILES;
63       break;
64     case 's':
65     case 'S':
66       res |= LOG_SERV;
67       break;
68     case 'd':
69       res |= LOG_DEBUG;
70       break;
71     case 'D':
72       res |= LOG_EDEBUG;
73       break;
74     case 'v':
75     case 'V':
76       res |= raw_log ? LOG_SRVOUT : 0;
77       break;
78     case 't':
79     case 'T':
80       res |= raw_log ? LOG_BOTNET : 0;
81       break;
82     case 'h':
83     case 'H':
84       res |= raw_log ? LOG_BOTSHARE : 0;
85       break;
86     case '1':
87       res |= LOG_LEV1;
88       break;
89     case '2':
90       res |= LOG_LEV2;
91       break;
92     case '3':
93       res |= LOG_LEV3;
94       break;
95     case '4':
96       res |= LOG_LEV4;
97       break;
98     case '5':
99       res |= LOG_LEV5;
100       break;
101     case '6':
102       res |= LOG_LEV6;
103       break;
104     case '7':
105       res |= LOG_LEV7;
106       break;
107     case '*':
108       res |= LOG_ALL;
109       break;
110     }
111   return res;
112 }
113 
masktype(int x)114 char *masktype(int x)
115 {
116   static char s[24];
117   char *p = s;
118 
119   if (x & LOG_MSGS)
120     *p++ = 'm';
121   if (x & LOG_PUBLIC)
122     *p++ = 'p';
123   if (x & LOG_JOIN)
124     *p++ = 'j';
125   if (x & LOG_MODES)
126     *p++ = 'k';
127   if (x & LOG_CMDS)
128     *p++ = 'c';
129   if (x & LOG_MISC)
130     *p++ = 'o';
131   if (x & LOG_BOTS)
132     *p++ = 'b';
133   if ((x & LOG_RAW) && raw_log)
134     *p++ = 'r';
135   if (x & LOG_FILES)
136     *p++ = 'x';
137   if (x & LOG_SERV)
138     *p++ = 's';
139   if (x & LOG_DEBUG)
140     *p++ = 'd';
141   if (x & LOG_EDEBUG)
142     *p++ = 'D';
143   if (x & LOG_EVANGELINE)
144     *p++ = 'e';
145   if (x & LOG_WALL)
146     *p++ = 'w';
147   if ((x & LOG_SRVOUT) && raw_log)
148     *p++ = 'v';
149   if ((x & LOG_BOTNET) && raw_log)
150     *p++ = 't';
151   if ((x & LOG_BOTSHARE) && raw_log)
152     *p++ = 'h';
153   if (x & LOG_LEV1)
154     *p++ = '1';
155   if (x & LOG_LEV2)
156     *p++ = '2';
157   if (x & LOG_LEV3)
158     *p++ = '3';
159   if (x & LOG_LEV4)
160     *p++ = '4';
161   if (x & LOG_LEV5)
162     *p++ = '5';
163   if (x & LOG_LEV6)
164     *p++ = '6';
165   if (x & LOG_LEV7)
166     *p++ = '7';
167   if (p == s)
168     *p++ = '-';
169   *p = 0;
170   return s;
171 }
172 
maskname(int x)173 char *maskname(int x)
174 {
175   static char s[207];
176   int i = 0;
177 
178   s[0] = 0;
179   if (x & LOG_MSGS)
180     i += my_strcpy(s, "msgs, ");
181   if (x & LOG_PUBLIC)
182     i += my_strcpy(s + i, "public, ");
183   if (x & LOG_JOIN)
184     i += my_strcpy(s + i, "joins, ");
185   if (x & LOG_MODES)
186     i += my_strcpy(s + i, "kicks/modes, ");
187   if (x & LOG_CMDS)
188     i += my_strcpy(s + i, "cmds, ");
189   if (x & LOG_MISC)
190     i += my_strcpy(s + i, "misc, ");
191   if (x & LOG_BOTS)
192     i += my_strcpy(s + i, "bots, ");
193   if ((x & LOG_RAW) && raw_log)
194     i += my_strcpy(s + i, "raw, ");
195   if (x & LOG_FILES)
196     i += my_strcpy(s + i, "files, ");
197   if (x & LOG_SERV)
198     i += my_strcpy(s + i, "server, ");
199   if (x & LOG_DEBUG)
200     i += my_strcpy(s + i, "debug, ");
201   if (x & LOG_EDEBUG)
202     i += my_strcpy(s + i, "edebug, ");
203   if (x & LOG_EVANGELINE)
204     i += my_strcpy(s + i, "ecore, ");
205   if (x & LOG_WALL)
206     i += my_strcpy(s + i, "wallops, ");
207   if ((x & LOG_SRVOUT) && raw_log)
208     i += my_strcpy(s + i, "server output, ");
209   if ((x & LOG_BOTNET) && raw_log)
210     i += my_strcpy(s + i, "botnet traffic, ");
211   if ((x & LOG_BOTSHARE) && raw_log)
212     i += my_strcpy(s + i, "share traffic, ");
213   if (x & LOG_LEV1)
214     i += my_strcpy(s + i, "level 1, ");
215   if (x & LOG_LEV2)
216     i += my_strcpy(s + i, "level 2, ");
217   if (x & LOG_LEV3)
218     i += my_strcpy(s + i, "level 3, ");
219   if (x & LOG_LEV4)
220     i += my_strcpy(s + i, "level 4, ");
221   if (x & LOG_LEV5)
222     i += my_strcpy(s + i, "level 5, ");
223   if (x & LOG_LEV6)
224     i += my_strcpy(s + i, "level 6, ");
225   if (x & LOG_LEV7)
226     i += my_strcpy(s + i, "level 7, ");
227   if (i)
228     s[i - 2] = 0;
229   else
230     strcpy(s, "none");
231   return s;
232 }
233 
234 /* Some flags are mutually exclusive -- this roots them out */
sanity_check(int atr)235 int sanity_check(int atr)
236 {
237   if ((atr & USER_BOT) &&
238       (atr & (USER_PARTY | USER_MASTER | USER_COMMON | USER_OWNER)))
239     atr &= ~(USER_PARTY | USER_MASTER | USER_COMMON | USER_OWNER);
240   if ((atr & USER_OP) && (atr & USER_DEOP))
241     atr &= ~(USER_OP | USER_DEOP);
242   if ((atr & USER_AUTOOP) && (atr & USER_DEOP))
243     atr &= ~(USER_AUTOOP | USER_DEOP);
244   if ((atr & USER_VOICE) && (atr & USER_QUIET))
245     atr &= ~(USER_VOICE | USER_QUIET);
246   if ((atr & USER_GVOICE) && (atr & USER_QUIET))
247     atr &= ~(USER_GVOICE | USER_QUIET);
248   if (atr & USER_OWNER)
249     atr |= USER_MASTER;
250   if (atr & USER_MASTER)
251     atr |= USER_BOTMAST | USER_OP | USER_JANITOR;
252 //  if (atr & USER_BOTMAST)
253 //    atr |= USER_PARTY;
254   if (atr & USER_JANITOR)
255     atr |= USER_XFER;
256   return atr;
257 }
258 
259 /* Sanity check on channel attributes */
chan_sanity_check(int chatr,int atr)260 int chan_sanity_check(int chatr, int atr)
261 {
262   if ((chatr & USER_OP) && (chatr & USER_DEOP))
263     chatr &= ~(USER_OP | USER_DEOP);
264   if ((chatr & USER_AUTOOP) && (chatr & USER_DEOP))
265     chatr &= ~(USER_AUTOOP | USER_DEOP);
266   if ((chatr & USER_VOICE) && (chatr & USER_QUIET))
267     chatr &= ~(USER_VOICE | USER_QUIET);
268   if ((chatr & USER_GVOICE) && (chatr & USER_QUIET))
269     chatr &= ~(USER_GVOICE | USER_QUIET);
270   if (chatr & USER_OWNER)
271     chatr |= USER_MASTER;
272   if (chatr & USER_MASTER)
273     chatr |= USER_OP;
274   if (!(atr & USER_BOT))
275     chatr &= ~BOT_SHARE;
276   return chatr;
277 }
278 
279 /* Get icon symbol for a user (depending on access level)
280  *
281  * (*) owner on any channel
282  * (+) master on any channel
283  * (%) botnet master
284  * (@) op on any channel
285  * (-) other
286  */
geticon(int idx)287 char geticon(int idx)
288 {
289   struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
290 
291   if (!dcc[idx].user)
292     return '-';
293   get_user_flagrec(dcc[idx].user, &fr, 0);
294   if (glob_owner(fr) || chan_owner(fr))
295     return '*';
296   if (glob_master(fr) || chan_master(fr))
297     return '+';
298   if (glob_botmast(fr))
299     return '%';
300   if (glob_op(fr) || chan_op(fr))
301     return '@';
302   return '-';
303 }
304 
break_down_flags(const char * string,struct flag_record * plus,struct flag_record * minus)305 void break_down_flags(const char *string, struct flag_record *plus,
306                       struct flag_record *minus)
307 {
308   struct flag_record *which = plus;
309   int mode = 0;
310   int flags = plus->match;
311 
312   if (!(flags & FR_GLOBAL)) {
313     if (flags & FR_BOT)
314       mode = 2;
315     else if (flags & FR_CHAN)
316       mode = 1;
317     else
318       return;
319   }
320   EvangelineBzero(plus, sizeof(struct flag_record));
321 
322   if (minus)
323     EvangelineBzero(minus, sizeof(struct flag_record));
324 
325   plus->match = FR_OR;
326   while (*string) {
327     switch (*string) {
328     case '+':
329       which = plus;
330       break;
331     case '-':
332       which = minus ? minus : plus;
333       break;
334     case '|':
335     case '&':
336       if (!mode) {
337         if (*string == '|')
338           plus->match = FR_OR;
339         else
340           plus->match = FR_AND;
341       }
342       which = plus;
343       mode++;
344       if ((mode == 2) && !(flags & (FR_CHAN | FR_BOT)))
345         string = "";
346       else if (mode == 3)
347         mode = 1;
348       break;
349     default:
350       if ((*string >= 'a') && (*string <= 'z')) {
351         switch (mode) {
352         case 0:
353           which->global |=1 << (*string - 'a');
354 
355           break;
356         case 1:
357           which->chan |= 1 << (*string - 'a');
358           break;
359         case 2:
360           which->bot |= 1 << (*string - 'a');
361         }
362       } else if ((*string >= 'A') && (*string <= 'Z')) {
363         switch (mode) {
364         case 0:
365           which->udef_global |= 1 << (*string - 'A');
366           break;
367         case 1:
368           which->udef_chan |= 1 << (*string - 'A');
369           break;
370         }
371       } else if ((*string >= '0') && (*string <= '9')) {
372         switch (mode) {
373         case 0:
374           which->udef_global |= 1 << (*string - '0');
375           break;
376         case 1:
377           which->udef_chan |= 1 << (*string - '0');
378           break;
379         case 2:
380           which->bot |= BOT_FLAG0 << (*string - '0');
381           break;
382         }
383       }
384     }
385     string++;
386   }
387   for (which = plus; which; which = (which == plus ? minus : 0)) {
388     which->global &=USER_VALID;
389 
390     which->udef_global &= 0x03ffffff;
391     which->chan &= CHAN_VALID;
392     which->udef_chan &= 0x03ffffff;
393     which->bot &= BOT_VALID;
394   }
395   plus->match |= flags;
396   if (minus) {
397     minus->match |= flags;
398     if (!(plus->match & (FR_AND | FR_OR)))
399       plus->match |= FR_OR;
400   }
401 }
402 
flag2str(char * string,int bot,int udef)403 static int flag2str(char *string, int bot, int udef)
404 {
405   char x = 'a', *old = string;
406 
407   while (bot && (x <= 'z')) {
408     if (bot & 1)
409       *string++ = x;
410     x++;
411     bot = bot >> 1;
412   }
413   x = 'A';
414   while (udef && (x <= 'Z')) {
415     if (udef & 1)
416       *string++ = x;
417     udef = udef >> 1;
418     x++;
419   }
420   if (string == old)
421     *string++ = '-';
422   return string - old;
423 }
424 
bot2str(char * string,int bot)425 static int bot2str(char *string, int bot)
426 {
427   char x = 'a', *old = string;
428 
429   while (x < 'v') {
430     if (bot & 1)
431       *string++ = x;
432     x++;
433     bot >>= 1;
434   }
435   x = '0';
436   while (x <= '9') {
437     if (bot & 1)
438       *string++ = x;
439     x++;
440     bot >>= 1;
441   }
442   return string - old;
443 }
444 
build_flags(char * string,struct flag_record * plus,struct flag_record * minus)445 int build_flags(char *string, struct flag_record *plus,
446                 struct flag_record *minus)
447 {
448   char *old = string;
449 
450   if (plus->match & FR_GLOBAL) {
451     if (minus && (plus->global ||plus->udef_global))
452       *string++ = '+';
453     string += flag2str(string, plus->global, plus->udef_global);
454 
455     if (minus && (minus->global ||minus->udef_global)) {
456       *string++ = '-';
457       string += flag2str(string, minus->global, minus->udef_global);
458     }
459   } else if (plus->match & FR_BOT) {
460     if (minus && plus->bot)
461       *string++ = '+';
462     string += bot2str(string, plus->bot);
463     if (minus && minus->bot) {
464       *string++ = '-';
465       string += bot2str(string, minus->bot);
466     }
467   }
468   if (plus->match & FR_CHAN) {
469     if (plus->match & (FR_GLOBAL | FR_BOT))
470       *string++ = (plus->match & FR_AND) ? '&' : '|';
471     if (minus && (plus->chan || plus->udef_chan))
472       *string++ = '+';
473     string += flag2str(string, plus->chan, plus->udef_chan);
474     if (minus && (minus->chan || minus->udef_chan)) {
475       *string++ = '-';
476       string += flag2str(string, minus->global, minus->udef_chan);
477     }
478   }
479   if ((plus->match & (FR_BOT | FR_CHAN)) == (FR_BOT | FR_CHAN)) {
480     *string++ = (plus->match & FR_AND) ? '&' : '|';
481     if (minus && plus->bot)
482       *string++ = '+';
483     string += bot2str(string, plus->bot);
484     if (minus && minus->bot) {
485       *string++ = '-';
486       string += bot2str(string, minus->bot);
487     }
488   }
489   if (string == old) {
490     *string++ = '-';
491     *string = 0;
492     return 0;
493   }
494   *string = 0;
495   return string - old;
496 }
497 
flagrec_ok(struct flag_record * req,struct flag_record * have)498 int flagrec_ok(struct flag_record *req, struct flag_record *have)
499 {
500   if (req->match & FR_AND)
501     return flagrec_eq(req, have);
502   else if (req->match & FR_OR) {
503     int hav = have->global;
504 
505     if (!req->chan && !req->global &&!req->udef_global && !req->udef_chan) {
506       if (!allow_dk_cmds) {
507         if (glob_party(*have))
508           return 1;
509         if (glob_kick(*have) || chan_kick(*have))
510           return 0;
511         if (glob_deop(*have) || chan_deop(*have))
512           return 0;
513       }
514       return 1;
515     }
516     if (!require_p && ((hav & USER_OP) || (have->chan & USER_OWNER)))
517       hav |= USER_PARTY;
518     if (hav & req->global)
519       return 1;
520     if (have->chan & req->chan)
521       return 1;
522     if (have->udef_global & req->udef_global)
523       return 1;
524     if (have->udef_chan & req->udef_chan)
525       return 1;
526     return 0;
527   }
528   return 0;
529 }
530 
flagrec_eq(struct flag_record * req,struct flag_record * have)531 int flagrec_eq(struct flag_record *req, struct flag_record *have)
532 {
533   if (req->match & FR_AND) {
534     if (req->match & FR_GLOBAL) {
535       if ((req->global &have->global) !=req->global)
536         return 0;
537       if ((req->udef_global & have->udef_global) != req->udef_global)
538         return 0;
539     }
540     if (req->match & FR_BOT)
541       if ((req->bot & have->bot) != req->bot)
542         return 0;
543     if (req->match & FR_CHAN) {
544       if ((req->chan & have->chan) != req->chan)
545         return 0;
546       if ((req->udef_chan & have->udef_chan) != req->udef_chan)
547         return 0;
548     }
549     return 1;
550   } else if (req->match & FR_OR) {
551     if (!req->chan && !req->global &&!req->udef_chan &&
552         !req->udef_global && !req->bot)
553       return 1;
554     if (req->match & FR_GLOBAL) {
555       if (have->global &req->global)
556         return 1;
557       if (have->udef_global & req->udef_global)
558         return 1;
559     }
560     if (req->match & FR_BOT)
561       if (have->bot & req->bot)
562         return 1;
563     if (req->match & FR_CHAN) {
564       if (have->chan & req->chan)
565         return 1;
566       if (have->udef_chan & req->udef_chan)
567         return 1;
568     }
569     return 0;
570   }
571   return 0;
572 }
573 
set_user_flagrec(struct userrec * u,struct flag_record * fr,const char * chname)574 void set_user_flagrec(struct userrec *u, struct flag_record *fr,
575                       const char *chname)
576 {
577   struct chanuserrec *cr = NULL;
578   int oldflags = fr->match;
579   char buffer[100];
580   struct chanset_t *ch;
581 
582   if (!u)
583     return;
584   if (oldflags & FR_GLOBAL) {
585     u->flags = fr->global;
586 
587     u->flags_udef = fr->udef_global;
588     if (!noshare && !(u->flags & USER_UNSHARED)) {
589       fr->match = FR_GLOBAL;
590       build_flags(buffer, fr, NULL);
591       shareout(NULL, "a %s %s\n", u->handle, buffer);
592     }
593   }
594   if ((oldflags & FR_BOT) && (u->flags & USER_BOT))
595     set_user(&USERENTRY_BOTFL, u, (void *) fr->bot);
596   if ((oldflags & FR_CHAN) && chname) {
597     for (cr = u->chanrec; cr; cr = cr->next)
598       if (!rfc_casecmp(chname, cr->channel))
599         break;
600     ch = findchan_by_dname(chname);
601     if (!cr && ch) {
602       cr = user_malloc(sizeof(struct chanuserrec));
603       EvangelineBzero(cr, sizeof(struct chanuserrec));
604 
605       cr->next = u->chanrec;
606       u->chanrec = cr;
607       strncpyz(cr->channel, chname, sizeof cr->channel);
608     }
609     if (cr && ch) {
610       cr->flags = fr->chan;
611       cr->flags_udef = fr->udef_chan;
612       if (!noshare && !(u->flags & USER_UNSHARED) && channel_shared(ch)) {
613         fr->match = FR_CHAN;
614         build_flags(buffer, fr, NULL);
615         shareout(ch, "a %s %s %s\n", u->handle, buffer, chname);
616       }
617     }
618   }
619   fr->match = oldflags;
620 }
621 
622 /* Always pass the dname (display name) to this function for chname */
get_user_flagrec(struct userrec * u,struct flag_record * fr,const char * chname)623 void get_user_flagrec(struct userrec *u, struct flag_record *fr,
624                       const char *chname)
625 {
626   struct chanuserrec *cr = NULL;
627 
628   if (!u) {
629     fr->global = fr->udef_global = fr->chan = fr->udef_chan = fr->bot = 0;
630 
631     return;
632   }
633   if (fr->match & FR_GLOBAL) {
634     fr->global = u->flags;
635 
636     fr->udef_global = u->flags_udef;
637   } else {
638     fr->global = 0;
639 
640     fr->udef_global = 0;
641   }
642   if (fr->match & FR_BOT) {
643     fr->bot = (long) get_user(&USERENTRY_BOTFL, u);
644   } else
645     fr->bot = 0;
646   if (fr->match & FR_CHAN) {
647     if (fr->match & FR_ANYWH) {
648       fr->chan = u->flags;
649       fr->udef_chan = u->flags_udef;
650       for (cr = u->chanrec; cr; cr = cr->next)
651         if (findchan_by_dname(cr->channel)) {
652           fr->chan |= cr->flags;
653           fr->udef_chan |= cr->flags_udef;
654         }
655     } else {
656       if (chname)
657         for (cr = u->chanrec; cr; cr = cr->next)
658           if (!rfc_casecmp(chname, cr->channel))
659             break;
660       if (cr) {
661         fr->chan = cr->flags;
662         fr->udef_chan = cr->flags_udef;
663       } else {
664         fr->chan = 0;
665         fr->udef_chan = 0;
666       }
667     }
668   }
669 }
670 
botfl_unpack(struct userrec * u,struct user_entry * e)671 static int botfl_unpack(struct userrec *u, struct user_entry *e)
672 {
673   struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };
674 
675   break_down_flags(e->u.list->extra, &fr, NULL);
676   list_type_kill(e->u.list);
677   e->u.ulong = fr.bot;
678   return 1;
679 }
680 
botfl_pack(struct userrec * u,struct user_entry * e)681 static int botfl_pack(struct userrec *u, struct user_entry *e)
682 {
683   char x[100];
684   struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };
685 
686   fr.bot = e->u.ulong;
687   e->u.list = user_malloc(sizeof(struct list_type));
688   e->u.list->next = NULL;
689   e->u.list->extra = user_malloc(build_flags(x, &fr, NULL) + 1);
690   strcpy(e->u.list->extra, x);
691   return 1;
692 }
693 
botfl_kill(struct user_entry * e)694 static int botfl_kill(struct user_entry *e)
695 {
696   nfree(e);
697   return 1;
698 }
699 
botfl_write_userfile(FILE * f,struct userrec * u,struct user_entry * e,char * key)700 static int botfl_write_userfile(FILE *f, struct userrec *u,
701                                 struct user_entry *e, char *key)
702 {
703   char x[100];
704   struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };
705 
706   fr.bot = e->u.ulong;
707   build_flags(x, &fr, NULL);
708   if (efprintf(f, key, "--%s %s\n", e->type->name, x) == EOF)
709     return 0;
710   return 1;
711 }
712 
botfl_set(struct userrec * u,struct user_entry * e,void * buf)713 static int botfl_set(struct userrec *u, struct user_entry *e, void *buf)
714 {
715   register long atr = ((long) buf & BOT_VALID);
716 
717   if (!(u->flags & USER_BOT))
718     return 1;
719 
720   if ((atr & BOT_HUB) && (atr & BOT_ALT))
721     atr &= ~BOT_ALT;
722   if (atr & BOT_REJECT) {
723     if (atr & BOT_SHARE)
724       atr &= ~(BOT_SHARE | BOT_REJECT);
725     if (atr & BOT_HUB)
726       atr &= ~(BOT_HUB | BOT_REJECT);
727     if (atr & BOT_ALT)
728       atr &= ~(BOT_ALT | BOT_REJECT);
729   }
730   if (!(atr & BOT_SHARE))
731     atr &= ~BOT_GLOBAL;
732   e->u.ulong = atr;
733   return 1;
734 }
735 
botfl_tcl_get(Tcl_Interp * interp,struct userrec * u,struct user_entry * e,int argc,char ** argv)736 static int botfl_tcl_get(Tcl_Interp *interp, struct userrec *u,
737                          struct user_entry *e, int argc, char **argv)
738 {
739   char x[100];
740   struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };
741 
742   fr.bot = e->u.ulong;
743   build_flags(x, &fr, NULL);
744   Tcl_AppendResult(interp, x, NULL);
745   return TCL_OK;
746 }
747 
botfl_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)748 static int botfl_tcl_set(Tcl_Interp *irp, struct userrec *u,
749                          struct user_entry *e, int argc, char **argv)
750 {
751   struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };
752 
753   BADARGS(4, 4, " handle BOTFL flags");
754 
755   if (u->flags & USER_BOT) {
756     break_down_flags(argv[3], &fr, NULL);
757     botfl_set(u, e, (void *) fr.bot);
758   }
759   return TCL_OK;
760 }
761 
botfl_expmem(struct user_entry * e)762 static int botfl_expmem(struct user_entry *e)
763 {
764   return 0;
765 }
766 
botfl_display(int idx,struct user_entry * e)767 static void botfl_display(int idx, struct user_entry *e)
768 {
769   struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };
770   char x[100];
771 
772   fr.bot = e->u.ulong;
773   build_flags(x, &fr, NULL);
774   dprintf(idx, "  BOT FLAGS: %s\n", x);
775 }
776 
777 struct user_entry_type USERENTRY_BOTFL = {
778   0,                            /* always 0 ;) */
779   0,
780   def_dupuser,
781   botfl_unpack,
782   botfl_pack,
783   botfl_write_userfile,
784   botfl_kill,
785   def_get,
786   botfl_set,
787   botfl_tcl_get,
788   botfl_tcl_set,
789   botfl_expmem,
790   botfl_display,
791   "BOTFL"
792 };
793