/[cvs]/eggdrop1.4/src/misc.c
ViewVC logotype

Contents of /eggdrop1.4/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.26 - (show annotations) (download) (as text)
Mon Jan 17 16:14:45 2000 UTC (19 years, 8 months ago) by per
Branch: MAIN
CVS Tags: eggdrop10402RC1, eggdrop10402
Changes since 1.25: +5 -18 lines
File MIME type: text/x-chdr
relayfix, extern_cleanup

1 /*
2 * misc.c -- handles:
3 * split() maskhost() copyfile() movefile()
4 * dumplots() daysago() days() daysdur()
5 * logging things
6 * queueing output for the bot (msg and help)
7 * resync buffers for sharebots
8 * help system
9 * motd display and %var substitution
10 *
11 * dprintf'ized, 12dec1995
12 *
13 * $Id: misc.c,v 1.25 2000/01/12 20:14:52 per Exp $
14 */
15 /*
16 * Copyright (C) 1997 Robey Pointer
17 * Copyright (C) 1999, 2000 Eggheads
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version 2
22 * of the License, or (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 */
33
34 #include "main.h"
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include "chan.h"
39 #ifdef HAVE_UNAME
40 #include <sys/utsname.h>
41 #endif
42
43 extern struct dcc_t *dcc;
44 extern struct chanset_t *chanset;
45 extern char helpdir[], version[], origbotname[], botname[], admin[];
46 extern char motdfile[], ver[], botnetnick[], bannerfile[];
47 extern int backgrd, con_chan, term_z, use_stderr, dcc_total;
48 extern int keep_all_logs, quick_logs, strict_host;
49 extern time_t now;
50
51 int shtime = 1; /* whether or not to display the time
52 * with console output */
53 log_t *logs = 0; /* logfiles */
54 int max_logs = 5; /* current maximum log files */
55 int max_logsize = 0; /* maximum logfile size, 0 for no limit */
56 int conmask = LOG_MODES | LOG_CMDS | LOG_MISC; /* console mask */
57 int debug_output = 0; /* disply output to server to LOG_SERVEROUT */
58
59 struct help_list_t {
60 struct help_list_t *next;
61 char *name;
62 int type;
63 };
64
65 static struct help_ref {
66 char *name;
67 struct help_list_t *first;
68 struct help_ref *next;
69 } *help_list = NULL;
70
71 /* expected memory usage */
72 int expmem_misc()
73 {
74 struct help_ref *current;
75 struct help_list_t *item;
76 int tot = 0;
77
78 for (current = help_list; current; current = current->next) {
79 tot += sizeof(struct help_ref) + strlen(current->name) + 1;
80
81 for (item = current->first; item; item = item->next)
82 tot += sizeof(struct help_list_t) + strlen(item->name) + 1;
83 }
84 return tot + (max_logs * sizeof(log_t));
85 }
86
87 void init_misc()
88 {
89 static int last = 0;
90
91 if (max_logs < 1)
92 max_logs = 1;
93 if (logs)
94 logs = nrealloc(logs, max_logs * sizeof(log_t));
95 else
96 logs = nmalloc(max_logs * sizeof(log_t));
97 for (; last < max_logs; last++) {
98 logs[last].filename = logs[last].chname = NULL;
99 logs[last].mask = 0;
100 logs[last].f = NULL;
101 /* Added by cybah */
102 logs[last].szLast[0] = 0;
103 logs[last].Repeats = 0;
104 /* Added by rtc */
105 logs[last].flags = 0;
106 }
107 }
108
109 /***** MISC FUNCTIONS *****/
110
111 /* low-level stuff for other modules */
112 static int is_file(char *s)
113 {
114 struct stat ss;
115 int i = stat(s, &ss);
116
117 if (i < 0)
118 return 0;
119 if ((ss.st_mode & S_IFREG) || (ss.st_mode & S_IFLNK))
120 return 1;
121 return 0;
122 }
123
124 /* unixware has no strcasecmp() without linking in a hefty library */
125 #if !HAVE_STRCASECMP
126 #define upcase(c) (((c)>='a' && (c)<='z') ? (c)-'a'+'A' : (c))
127
128 int strcasecmp(char *s1, char *s2)
129 {
130 while ((*s1) && (*s2) && (upcase(*s1) == upcase(*s2))) {
131 s1++;
132 s2++;
133 }
134 return upcase(*s1) - upcase(*s2);
135 }
136 #endif
137
138 int my_strcpy(char *a, char *b)
139 {
140 char *c = b;
141
142 while (*b)
143 *a++ = *b++;
144 *a = *b;
145 return b - c;
146 }
147
148 /* split first word off of rest and put it in first */
149 void splitc(char *first, char *rest, char divider)
150 {
151 char *p;
152
153 p = strchr(rest, divider);
154 if (p == NULL) {
155 if ((first != rest) && (first != NULL))
156 first[0] = 0;
157 return;
158 }
159 *p = 0;
160 if (first != NULL)
161 strcpy(first, rest);
162 if (first != rest)
163 strcpy(rest, p + 1);
164 }
165
166 char *splitnick(char **blah)
167 {
168 char *p = strchr(*blah, '!'), *q = *blah;
169
170 if (p) {
171 *p = 0;
172 *blah = p + 1;
173 return q;
174 }
175 return "";
176 }
177
178 char *newsplit(char **rest)
179 {
180 register char *o, *r;
181
182 if (!rest)
183 return *rest = "";
184 o = *rest;
185 while (*o == ' ')
186 o++;
187 r = o;
188 while (*o && (*o != ' '))
189 o++;
190 if (*o)
191 *o++ = 0;
192 *rest = o;
193 return r;
194 }
195
196 /* convert "abc!user@a.b.host" into "*!user@*.b.host"
197 * or "abc!user@1.2.3.4" into "*!user@1.2.3.*" */
198 void maskhost(char *s, char *nw)
199 {
200 char *p, *q, *e, *f;
201 int i;
202
203 *nw++ = '*';
204 *nw++ = '!';
205 p = (q = strchr(s, '!')) ? q + 1 : s;
206 /* strip of any nick, if a username is found, use last 8 chars */
207 if ((q = strchr(p, '@'))) {
208 if ((q - p) > 9) {
209 nw[0] = '*';
210 p = q - 7;
211 i = 1;
212 } else
213 i = 0;
214 while (*p != '@') {
215 if (strchr("~+-^=", *p))
216 if (strict_host)
217 nw[i] = '?';
218 else
219 i--;
220 else
221 nw[i] = *p;
222 p++;
223 i++;
224 }
225 nw[i++] = '@';
226 q++;
227 } else {
228 nw[0] = '*';
229 nw[1] = '@';
230 i = 2;
231 q = s;
232 }
233 nw += i;
234 /* now q points to the hostname, i point to where to put the mask */
235 if (!(p = strchr(q, '.')) || !(e = strchr(p + 1, '.')))
236 /* TLD or 2 part host */
237 strcpy(nw, q);
238 else {
239 for (f = e; *f; f++);
240 f--;
241 if ((*f >= '0') && (*f <= '9')) { /* numeric IP address */
242 while (*f != '.')
243 f--;
244 strncpy(nw, q, f - q);
245 /* No need to nw[f-q]=0 here. */
246 nw += (f - q);
247 strcpy(nw, ".*");
248 } else { /* normal host >= 3 parts */
249 /* ok, people whined at me...how about this? ..
250 * a.b.c -> *.b.c
251 * a.b.c.d -> *.b.c.d if tld is a country (2 chars)
252 * OR *.c.d if tld is com/edu/etc (3 chars)
253 * a.b.c.d.e -> *.c.d.e etc
254 */
255 char *x = strchr(e + 1, '.');
256
257 if (!x)
258 x = p;
259 else if (strchr(x + 1, '.'))
260 x = e;
261 else if (strlen(x) == 3)
262 x = p;
263 else
264 x = e;
265 sprintf(nw, "*%s", x);
266 }
267 }
268 }
269
270 /* copy a file from one place to another (possibly erasing old copy) */
271 /* returns 0 if OK, 1 if can't open original file, 2 if can't open new */
272 /* file, 3 if original file isn't normal, 4 if ran out of disk space */
273 int copyfile(char *oldpath, char *newpath)
274 {
275 int fi, fo, x;
276 char buf[512];
277 struct stat st;
278
279 fi = open(oldpath, O_RDONLY, 0);
280 if (fi < 0)
281 return 1;
282 fstat(fi, &st);
283 if (!(st.st_mode & S_IFREG))
284 return 3;
285 fo = creat(newpath, (int) (st.st_mode & 0777));
286 if (fo < 0) {
287 close(fi);
288 return 2;
289 }
290 for (x = 1; x > 0;) {
291 x = read(fi, buf, 512);
292 if (x > 0) {
293 if (write(fo, buf, x) < x) { /* couldn't write */
294 close(fo);
295 close(fi);
296 unlink(newpath);
297 return 4;
298 }
299 }
300 }
301 close(fo);
302 close(fi);
303 return 0;
304 }
305
306 int movefile(char *oldpath, char *newpath)
307 {
308 int ret;
309
310 #ifdef HAVE_RENAME
311 /* try to use rename first */
312 if (rename(oldpath, newpath) == 0)
313 return 0;
314 #endif /* HAVE_RENAME */
315
316 /* if that fails, fall back to copying the file */
317 ret = copyfile(oldpath, newpath);
318 if (ret == 0)
319 unlink(oldpath);
320 return ret;
321 }
322
323 /* dump a potentially super-long string of text */
324 /* assume prefix 20 chars or less */
325 void dumplots(int idx, char *prefix, char *data)
326 {
327 char *p = data, *q, *n, c;
328
329 if (!(*data)) {
330 dprintf(idx, "%s\n", prefix);
331 return;
332 }
333 while (strlen(p) > 480) {
334 q = p + 480;
335 /* search for embedded linefeed first */
336 n = strchr(p, '\n');
337 if ((n != NULL) && (n < q)) {
338 /* great! dump that first line then start over */
339 *n = 0;
340 dprintf(idx, "%s%s\n", prefix, p);
341 *n = '\n';
342 p = n + 1;
343 } else {
344 /* search backwards for the last space */
345 while ((*q != ' ') && (q != p))
346 q--;
347 if (q == p)
348 q = p + 480;
349 /* ^ 1 char will get squashed cos there was no space -- too bad */
350 c = *q;
351 *q = 0;
352 dprintf(idx, "%s%s\n", prefix, p);
353 *q = c;
354 p = q + 1;
355 }
356 }
357 /* last trailing bit: split by linefeeds if possible */
358 n = strchr(p, '\n');
359 while (n != NULL) {
360 *n = 0;
361 dprintf(idx, "%s%s\n", prefix, p);
362 *n = '\n';
363 p = n + 1;
364 n = strchr(p, '\n');
365 }
366 if (*p)
367 dprintf(idx, "%s%s\n", prefix, p); /* last trailing bit */
368 }
369
370 /* convert an interval (in seconds) to one of:
371 * "19 days ago", "1 day ago", "18:12" */
372 void daysago(time_t now, time_t then, char *out)
373 {
374 char s[81];
375
376 if (now - then > 86400) {
377 int days = (now - then) / 86400;
378
379 sprintf(out, "%d day%s ago", days, (days == 1) ? "" : "s");
380 return;
381 }
382 strcpy(s, ctime(&then));
383 s[16] = 0;
384 strcpy(out, &s[11]);
385 }
386
387 /* convert an interval (in seconds) to one of:
388 * "in 19 days", "in 1 day", "at 18:12" */
389 void days(time_t now, time_t then, char *out)
390 {
391 char s[81];
392
393 if (now - then > 86400) {
394 int days = (now - then) / 86400;
395
396 sprintf(out, "in %d day%s", days, (days == 1) ? "" : "s");
397 return;
398 }
399 strcpy(out, "at ");
400 strcpy(s, ctime(&now));
401 s[16] = 0;
402 strcpy(&out[3], &s[11]);
403 }
404
405 /* convert an interval (in seconds) to one of:
406 * "for 19 days", "for 1 day", "for 09:10" */
407 void daysdur(time_t now, time_t then, char *out)
408 {
409 char s[81];
410 int hrs, mins;
411
412 if (now - then > 86400) {
413 int days = (now - then) / 86400;
414
415 sprintf(out, "for %d day%s", days, (days == 1) ? "" : "s");
416 return;
417 }
418 strcpy(out, "for ");
419 now -= then;
420 hrs = (int) (now / 3600);
421 mins = (int) ((now - (hrs * 3600)) / 60);
422 sprintf(s, "%02d:%02d", hrs, mins);
423 strcat(out, s);
424 }
425
426 /***** LOGGING *****/
427
428 /* log something */
429 /* putlog(level,channel_name,format,...); */
430 void putlog EGG_VARARGS_DEF(int, arg1)
431 {
432 int i, type;
433 char *format, *chname, s[MAX_LOG_LINE + 1], s1[256], *out;
434 time_t tt;
435 char ct[81];
436 struct tm *T = localtime(&now);
437
438 va_list va;
439 type = EGG_VARARGS_START(int, arg1, va);
440 chname = va_arg(va, char *);
441 format = va_arg(va, char *);
442
443 /* format log entry at offset 8, then i can prepend the timestamp */
444 out = &s[8];
445 #ifdef HAVE_VSNPRINTF
446 /* no need to check if out should be null-terminated here,
447 * just do it! <cybah> */
448 vsnprintf(out, MAX_LOG_LINE - 8, format, va);
449 out[MAX_LOG_LINE - 8] = 0;
450 #else
451 vsprintf(out, format, va);
452 #endif
453 tt = now;
454 if (keep_all_logs) {
455 strcpy(ct, ctime(&tt));
456 ct[10] = 0;
457 strcpy(ct, &ct[8]);
458 ct[7] = 0;
459 strcpy(&ct[2], &ct[4]);
460 ct[24] = 0;
461 strcpy(&ct[5], &ct[20]);
462 if (ct[0] == ' ')
463 ct[0] = '0';
464 }
465 if ((out[0]) && (shtime)) {
466 strcpy(s1, ctime(&tt));
467 strcpy(s1, &s1[11]);
468 s1[5] = 0;
469 out = s;
470 s[0] = '[';
471 strncpy(&s[1], s1, 5);
472 s[6] = ']';
473 s[7] = ' ';
474 }
475 strcat(out, "\n");
476 if (!use_stderr) {
477 for (i = 0; i < max_logs; i++) {
478 if ((logs[i].filename != NULL) && (logs[i].mask & type) &&
479 ((chname[0] == '*') || (logs[i].chname[0] == '*') ||
480 (!rfc_casecmp(chname, logs[i].chname)))) {
481 if (logs[i].f == NULL) {
482 /* open this logfile */
483 if (keep_all_logs) {
484 sprintf(s1, "%s.%s", logs[i].filename, ct);
485 logs[i].f = fopen(s1, "a+");
486 } else
487 logs[i].f = fopen(logs[i].filename, "a+");
488 }
489 if (logs[i].f != NULL) {
490 /* Check if this is the same as the last line added to
491 * the log. <cybah> */
492 if (!strcasecmp(out + 8, logs[i].szLast)) {
493 /* It is a repeat, so increment Repeats */
494 logs[i].Repeats++;
495 } else {
496 /* Not a repeat, check if there were any repeat
497 * lines previously... */
498 if (logs[i].Repeats > 0) {
499 /* Yep.. so display 'last message repeated x times'
500 * then reset repeats. We want the current time here,
501 * so put that in the file first. */
502 if (T) {
503 fprintf(logs[i].f, "[%2.2d:%2.2d] ", T->tm_hour, T->tm_min);
504 fprintf(logs[i].f, MISC_LOGREPEAT, logs[i].Repeats);
505 } else {
506 fprintf(logs[i].f, "[??:??] ");
507 fprintf(logs[i].f, MISC_LOGREPEAT, logs[i].Repeats);
508 }
509 logs[i].Repeats = 0;
510 /* no need to reset logs[i].szLast here
511 * because we update it later on... */
512 }
513 fputs(out, logs[i].f);
514 strncpy(logs[i].szLast, out + 8, MAX_LOG_LINE);
515 logs[i].szLast[MAX_LOG_LINE] = 0;
516 }
517 }
518 }
519 }
520 }
521 for (i = 0; i < dcc_total; i++)
522 if ((dcc[i].type == &DCC_CHAT) && (dcc[i].u.chat->con_flags & type)) {
523 if ((chname[0] == '*') || (dcc[i].u.chat->con_chan[0] == '*') ||
524 (!rfc_casecmp(chname, dcc[i].u.chat->con_chan)))
525 dprintf(i, "%s", out);
526 }
527 if ((!backgrd) && (!con_chan) && (!term_z))
528 printf("%s", out);
529 else if ((type & LOG_MISC) && use_stderr) {
530 if (shtime)
531 out += 8;
532 dprintf(DP_STDERR, "%s", s);
533 }
534 va_end(va);
535 }
536
537 void check_logsize()
538 {
539 struct stat ss;
540 int i;
541
542 /* int x=1; */
543 char buf[1024]; /* should be plenty */
544
545 Context;
546 if ((keep_all_logs == 0) && (max_logsize != 0)) {
547 for (i = 0; i < max_logs; i++) {
548 if (logs[i].filename) {
549 if (stat(logs[i].filename, &ss) != 0) {
550 break;
551 }
552 if ((ss.st_size >> 10) > max_logsize) {
553 Context;
554 if (logs[i].f) {
555 /* write to the log before closing it huh.. */
556 putlog(LOG_MISC, "*", MISC_CLOGS, logs[i].filename, ss.st_size);
557 fflush(logs[i].f);
558 fclose(logs[i].f);
559 logs[i].f = NULL;
560 Context;
561 }
562 Context;
563
564 simple_sprintf(buf, "%s.yesterday", logs[i].filename);
565 buf[1023] = 0;
566 unlink(buf);
567 /* x++;
568 * This is an alternate method i was considering, i want to leave
569 * this in here and commented.. in case someone wants it like this
570 * it really depends on feedback from the users. - poptix
571 * feel free to ask me, if you have questions on this..
572 *
573 * while (x > 0) {
574 * x++;
575 * * only YOU can prevent buffer overflows! *
576 * simple_sprintf(buf,"%s.%d",logs[i].filename,x);
577 * buf[1023] = 0;
578 * if (stat(buf,&ss) == -1) {
579 * * file doesnt exist, lets use it *
580 */
581 movefile(logs[i].filename, buf);
582 /* x=0;
583 * }
584 * } */
585 }
586 }
587 }
588 }
589 Context;
590 }
591
592 /* flush the logfiles to disk */
593 void flushlogs()
594 {
595 int i;
596 struct tm *T = localtime(&now);
597
598 Context;
599 /* logs may not be initialised yet. (Fabian) */
600 if (!logs)
601 return;
602 /* Now also checks to see if there's a repeat message and
603 * displays the 'last message repeated...' stuff too <cybah> */
604 for (i = 0; i < max_logs; i++) {
605 if (logs[i].f != NULL) {
606 if ((logs[i].Repeats > 0) && quick_logs) {
607 /* Repeat.. if quicklogs used then display 'last message
608 * repeated x times' and reset Repeats. */
609 if (T) {
610 fprintf(logs[i].f, "[%2.2d:%2.2d] ", T->tm_hour, T->tm_min);
611 fprintf(logs[i].f, MISC_LOGREPEAT, logs[i].Repeats);
612 } else {
613 fprintf(logs[i].f, "[??:??] ");
614 fprintf(logs[i].f, MISC_LOGREPEAT, logs[i].Repeats);
615 }
616 /* Reset repeats */
617 logs[i].Repeats = 0;
618 }
619 fflush(logs[i].f);
620 }
621 }
622 Context;
623 }
624
625 /********** STRING SUBSTITUTION **********/
626
627 static int cols = 0;
628 static int colsofar = 0;
629 static int blind = 0;
630 static int subwidth = 70;
631 static char *colstr = NULL;
632
633 /* add string to colstr */
634 static void subst_addcol(char *s, char *newcol)
635 {
636 char *p, *q;
637 int i, colwidth;
638
639 if ((newcol[0]) && (newcol[0] != '\377'))
640 colsofar++;
641 colstr = nrealloc(colstr, strlen(colstr) + strlen(newcol) +
642 (colstr[0] ? 2 : 1));
643 if ((newcol[0]) && (newcol[0] != '\377')) {
644 if (colstr[0])
645 strcat(colstr, "\377");
646 strcat(colstr, newcol);
647 }
648 if ((colsofar == cols) || ((newcol[0] == '\377') && (colstr[0]))) {
649 colsofar = 0;
650 strcpy(s, " ");
651 colwidth = (subwidth - 5) / cols;
652 q = colstr;
653 p = strchr(colstr, '\377');
654 while (p != NULL) {
655 *p = 0;
656 strcat(s, q);
657 for (i = strlen(q); i < colwidth; i++)
658 strcat(s, " ");
659 q = p + 1;
660 p = strchr(q, '\377');
661 }
662 strcat(s, q);
663 nfree(colstr);
664 colstr = (char *) nmalloc(1);
665 colstr[0] = 0;
666 }
667 }
668
669 /* substitute %x codes in help files
670 * %B = bot nickname
671 * %V = version
672 * %C = list of channels i monitor
673 * %E = eggdrop banner
674 * %A = admin line
675 * %T = current time ("14:15")
676 * %N = user's nickname
677 * %U = display system name if possible
678 * %{+xy} require flags to read this section
679 * %{-} turn of required flag matching only
680 * %{center} center this line
681 * %{cols=N} start of columnated section (indented)
682 * %{help=TOPIC} start a section for a particular command
683 * %{end} end of section
684 */
685 #define HELP_BUF_LEN 256
686 #define HELP_BOLD 1
687 #define HELP_REV 2
688 #define HELP_UNDER 4
689 #define HELP_FLASH 8
690
691 void help_subst(char *s, char *nick, struct flag_record *flags,
692 int isdcc, char *topic)
693 {
694 char xx[HELP_BUF_LEN + 1], sub[161], *current, *q, chr, *writeidx,
695 *readidx, *towrite;
696 struct chanset_t *chan;
697 int i, j, center = 0;
698 static int help_flags;
699
700 #ifdef HAVE_UNAME
701 struct utsname uname_info;
702
703 #endif
704
705 if (s == NULL) {
706 /* used to reset substitutions */
707 blind = 0;
708 cols = 0;
709 subwidth = 70;
710 if (colstr != NULL) {
711 nfree(colstr);
712 colstr = NULL;
713 }
714 help_flags = isdcc;
715 return;
716 }
717 strncpy(xx, s, HELP_BUF_LEN);
718 xx[HELP_BUF_LEN] = 0;
719 readidx = xx;
720 writeidx = s;
721 current = strchr(readidx, '%');
722 while (current) {
723 /* are we about to copy a chuck to the end of the buffer?
724 * if so return */
725 if ((writeidx + (current - readidx)) >= (s + HELP_BUF_LEN)) {
726 strncpy(writeidx, readidx, (s + HELP_BUF_LEN) - writeidx);
727 s[HELP_BUF_LEN] = 0;
728 return;
729 }
730 chr = *(current + 1);
731 *current = 0;
732 if (!blind)
733 writeidx += my_strcpy(writeidx, readidx);
734 towrite = NULL;
735 switch (chr) {
736 case 'b':
737 if (glob_hilite(*flags)) {
738 if (help_flags & HELP_IRC) {
739 towrite = "\002";
740 } else if (help_flags & HELP_BOLD) {
741 help_flags &= ~HELP_BOLD;
742 towrite = "\033[0m";
743 } else {
744 help_flags |= HELP_BOLD;
745 towrite = "\033[1m";
746 }
747 }
748 break;
749 case 'v':
750 if (glob_hilite(*flags)) {
751 if (help_flags & HELP_IRC) {
752 towrite = "\026";
753 } else if (help_flags & HELP_REV) {
754 help_flags &= ~HELP_REV;
755 towrite = "\033[0m";
756 } else {
757 help_flags |= HELP_REV;
758 towrite = "\033[7m";
759 }
760 }
761 break;
762 case '_':
763 if (glob_hilite(*flags)) {
764 if (help_flags & HELP_IRC) {
765 towrite = "\037";
766 } else if (help_flags & HELP_UNDER) {
767 help_flags &= ~HELP_UNDER;
768 towrite = "\033[0m";
769 } else {
770 help_flags |= HELP_UNDER;
771 towrite = "\033[4m";
772 }
773 }
774 break;
775 case 'f':
776 if (glob_hilite(*flags)) {
777 if (help_flags & HELP_FLASH) {
778 if (help_flags & HELP_IRC) {
779 towrite = "\002\037";
780 } else {
781 towrite = "\033[0m";
782 }
783 help_flags &= ~HELP_FLASH;
784 } else {
785 help_flags |= HELP_FLASH;
786 if (help_flags & HELP_IRC) {
787 towrite = "\037\002";
788 } else {
789 towrite = "\033[5m";
790 }
791 }
792 }
793 break;
794 case 'U':
795 #ifdef HAVE_UNAME
796 if (!uname(&uname_info)) {
797 simple_sprintf(sub, "%s %s", uname_info.sysname,
798 uname_info.release);
799 towrite = sub;
800 } else
801 #endif
802 towrite = "*UNKNOWN*";
803 break;
804 case 'B':
805 towrite = (isdcc ? botnetnick : botname);
806 break;
807 case 'V':
808 towrite = ver;
809 break;
810 case 'E':
811 towrite = version;
812 break;
813 case 'A':
814 towrite = admin;
815 break;
816 case 'T':
817 strcpy(sub, ctime(&now));
818 sub[16] = 0;
819 towrite = sub + 11;
820 break;
821 case 'N':
822 towrite = strchr(nick, ':');
823 if (towrite)
824 towrite++;
825 else
826 towrite = nick;
827 break;
828 case 'C':
829 if (!blind)
830 for (chan = chanset; chan; chan = chan->next) {
831 if ((strlen(chan->name) + writeidx + 2) >=
832 (s + HELP_BUF_LEN)) {
833 strncpy(writeidx, chan->name, (s + HELP_BUF_LEN) - writeidx);
834 s[HELP_BUF_LEN] = 0;
835 return;
836 }
837 writeidx += my_strcpy(writeidx, chan->name);
838 if (chan->next) {
839 *writeidx++ = ',';
840 *writeidx++ = ' ';
841 }
842 }
843 break;
844 case '{':
845 q = current;
846 current++;
847 while ((*current != '}') && (*current))
848 current++;
849 if (*current) {
850 *current = 0;
851 current--;
852 q += 2;
853 /* now q is the string and p is where the rest of the fcn expects */
854 if (!strncmp(q, "help=", 5)) {
855 if (topic && strcasecmp(q + 5, topic))
856 blind |= 2;
857 else
858 blind &= ~2;
859 } else if (!(blind & 2)) {
860 if (q[0] == '+') {
861 struct flag_record fr =
862 {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
863
864 break_down_flags(q + 1, &fr, NULL);
865 if (!flagrec_ok(&fr, flags))
866 blind |= 1;
867 else
868 blind &= ~1;
869 } else if (q[0] == '-') {
870 blind &= ~1;
871 } else if (!strcasecmp(q, "end")) {
872 blind &= ~1;
873 subwidth = 70;
874 if (cols) {
875 sub[0] = 0;
876 subst_addcol(sub, "\377");
877 nfree(colstr);
878 colstr = NULL;
879 cols = 0;
880 towrite = sub;
881 }
882 } else if (!strcasecmp(q, "center"))
883 center = 1;
884 else if (!strncmp(q, "cols=", 5)) {
885 char *r;
886
887 cols = atoi(q + 5);
888 colsofar = 0;
889 colstr = (char *) nmalloc(1);
890 colstr[0] = 0;
891 r = strchr(q + 5, '/');
892 if (r != NULL)
893 subwidth = atoi(r + 1);
894 }
895 }
896 } else
897 current = q; /* no } so ignore */
898 break;
899 default:
900 if (!blind) {
901 *writeidx++ = chr;
902 if (writeidx >= (s + HELP_BUF_LEN)) {
903 *writeidx = 0;
904 return;
905 }
906 }
907 }
908 if (towrite && !blind) {
909 if ((writeidx + strlen(towrite)) >= (s + HELP_BUF_LEN)) {
910 strncpy(writeidx, towrite, (s + HELP_BUF_LEN) - writeidx);
911 s[HELP_BUF_LEN] = 0;
912 return;
913 }
914 writeidx += my_strcpy(writeidx, towrite);
915 }
916 if (chr) {
917 readidx = current + 2;
918 current = strchr(readidx, '%');
919 } else {
920 readidx = current + 1;
921 current = NULL;
922 }
923 }
924 if (!blind) {
925 i = strlen(readidx);
926 if (i && ((writeidx + i) >= (s + HELP_BUF_LEN))) {
927 strncpy(writeidx, readidx, (s + HELP_BUF_LEN) - writeidx);
928 s[HELP_BUF_LEN] = 0;
929 return;
930 }
931 strcpy(writeidx, readidx);
932 } else
933 *writeidx = 0;
934 if (center) {
935 strcpy(xx, s);
936 i = 35 - (strlen(xx) / 2);
937 if (i > 0) {
938 s[0] = 0;
939 for (j = 0; j < i; j++)
940 s[j] = ' ';
941 strcpy(s + i, xx);
942 }
943 }
944 if (cols) {
945 strcpy(xx, s);
946 s[0] = 0;
947 subst_addcol(s, xx);
948 }
949 }
950
951 static void scan_help_file(struct help_ref *current, char *filename, int type)
952 {
953 FILE *f;
954 char s[HELP_BUF_LEN + 1], *p, *q;
955 struct help_list_t *list;
956
957 if (is_file(filename) && (f = fopen(filename, "r"))) {
958 while (!feof(f)) {
959 fgets(s, HELP_BUF_LEN, f);
960 if (!feof(f)) {
961 p = s;
962 while ((q = strstr(p, "%{help="))) {
963 q += 7;
964 if ((p = strchr(q, '}'))) {
965 *p = 0;
966 list = nmalloc(sizeof(struct help_list_t));
967
968 list->name = nmalloc(p - q + 1);
969 strcpy(list->name, q);
970 list->next = current->first;
971 list->type = type;
972 current->first = list;
973 p++;
974 } else
975 p = "";
976 }
977 }
978 }
979 fclose(f);
980 }
981 }
982
983 void add_help_reference(char *file)
984 {
985 char s[1024];
986 struct help_ref *current;
987
988 for (current = help_list; current; current = current->next)
989 if (!strcmp(current->name, file))
990 return; /* already exists, can't re-add :P */
991 current = nmalloc(sizeof(struct help_ref));
992
993 current->name = nmalloc(strlen(file) + 1);
994 strcpy(current->name, file);
995 current->next = help_list;
996 current->first = NULL;
997 help_list = current;
998 simple_sprintf(s, "%smsg/%s", helpdir, file);
999 scan_help_file(current, s, 0);
1000 simple_sprintf(s, "%s%s", helpdir, file);
1001 scan_help_file(current, s, 1);
1002 simple_sprintf(s, "%sset/%s", helpdir, file);
1003 scan_help_file(current, s, 2);
1004 }
1005
1006 void rem_help_reference(char *file)
1007 {
1008 struct help_ref *current, *last = NULL;
1009 struct help_list_t *item;
1010
1011 for (current = help_list; current; last = current, current = current->next)
1012 if (!strcmp(current->name, file)) {
1013 while ((item = current->first)) {
1014 current->first = item->next;
1015 nfree(item->name);
1016 nfree(item);
1017 }
1018 nfree(current->name);
1019 if (last)
1020 last->next = current->next;
1021 else
1022 help_list = current->next;
1023 nfree(current);
1024 return;
1025 }
1026 }
1027
1028 void reload_help_data(void)
1029 {
1030 struct help_ref *current = help_list, *next;
1031 struct help_list_t *item;
1032
1033 help_list = NULL;
1034 while (current) {
1035 while ((item = current->first)) {
1036 current->first = item->next;
1037 nfree(item->name);
1038 nfree(item);
1039 }
1040 add_help_reference(current->name);
1041 nfree(current->name);
1042 next = current->next;
1043 nfree(current);
1044 current = next;
1045 }
1046 }
1047
1048 void debug_help(int idx)
1049 {
1050 struct help_ref *current;
1051 struct help_list_t *item;
1052
1053 for (current = help_list; current; current = current->next) {
1054 dprintf(idx, "HELP FILE(S): %s\n", current->name);
1055 for (item = current->first; item; item = item->next) {
1056 dprintf(idx, " %s (%s)\n", item->name, (item->type == 0) ? "msg/" :
1057 (item->type == 1) ? "" : "set/");
1058 }
1059 }
1060 }
1061
1062 FILE *resolve_help(int dcc, char *file)
1063 {
1064 char s[1024], *p;
1065 FILE *f;
1066 struct help_ref *current;
1067 struct help_list_t *item;
1068
1069 /* somewhere here goes the eventual substituation */
1070 if (!(dcc & HELP_TEXT))
1071 for (current = help_list; current; current = current->next)
1072 for (item = current->first; item; item = item->next)
1073 if (!strcmp(item->name, file)) {
1074 if (!item->type && !dcc) {
1075 simple_sprintf(s, "%smsg/%s", helpdir, current->name);
1076 if ((f = fopen(s, "r")))
1077 return f;
1078 } else if (dcc && item->type) {
1079 if (item->type == 1)
1080 simple_sprintf(s, "%s%s", helpdir, current->name);
1081 else
1082 simple_sprintf(s, "%sset/%s", helpdir, current->name);
1083 if ((f = fopen(s, "r")))
1084 return f;
1085 }
1086 }
1087 for (p = s + simple_sprintf(s, "%s%s", helpdir, dcc ? "" : "msg/");
1088 *file && (p < s + 1023); file++, p++) {
1089 switch (*file) {
1090 case ' ':
1091 case '.':
1092 *p = '/';
1093 break;
1094 case '-':
1095 *p = '-';
1096 break;
1097 case '+':
1098 *p = 'P';
1099 break;
1100 default:
1101 *p = *file;
1102 }
1103 }
1104 *p = 0;
1105 if (!is_file(s)) {
1106 strcat(s, "/");
1107 strcat(s, file);
1108 if (!is_file(s))
1109 return NULL;
1110 }
1111 return fopen(s, "r");
1112 }
1113
1114 void showhelp(char *who, char *file, struct flag_record *flags, int fl)
1115 {
1116 int lines = 0;
1117 char s[HELP_BUF_LEN + 1];
1118 FILE *f = resolve_help(fl, file);
1119
1120 if (f) {
1121 help_subst(NULL, NULL, 0, HELP_IRC, NULL); /* clear flags */
1122 while (!feof(f)) {
1123 fgets(s, HELP_BUF_LEN, f);
1124 if (!feof(f)) {
1125 if (s[strlen(s) - 1] == '\n')
1126 s[strlen(s) - 1] = 0;
1127 if (!s[0])
1128 strcpy(s, " ");
1129 help_subst(s, who, flags, 0, file);
1130 if ((s[0]) && (strlen(s) > 1)) {
1131 dprintf(DP_HELP, "NOTICE %s :%s\n", who, s);
1132 lines++;
1133 }
1134 }
1135 }
1136 fclose(f);
1137 }
1138 if (!lines && !(fl & HELP_TEXT))
1139 dprintf(DP_HELP, "NOTICE %s :%s\n", who, IRC_NOHELP2);
1140 }
1141
1142 static int display_tellhelp(int idx, char *file, FILE *f, struct flag_record *flags)
1143 {
1144 char s[HELP_BUF_LEN + 1];
1145 int lines = 0;
1146
1147 if (f) {
1148 help_subst(NULL, NULL, 0,
1149 (dcc[idx].status & STAT_TELNET) ? 0 : HELP_IRC, NULL);
1150 while (!feof(f)) {
1151 fgets(s, HELP_BUF_LEN, f);
1152 if (!feof(f)) {
1153 if (s[strlen(s) - 1] == '\n')
1154 s[strlen(s) - 1] = 0;
1155 if (!s[0])
1156 strcpy(s, " ");
1157 help_subst(s, dcc[idx].nick, flags, 1, file);
1158 if (s[0]) {
1159 dprintf(idx, "%s\n", s);
1160 lines++;
1161 }
1162 }
1163 }
1164 fclose(f);
1165 }
1166 return lines;
1167 }
1168
1169 void tellhelp(int idx, char *file, struct flag_record *flags, int fl)
1170 {
1171 int lines = 0;
1172 FILE *f = resolve_help(HELP_DCC | fl, file);
1173
1174 if (f)
1175 lines = display_tellhelp(idx, file, f, flags);
1176 if (!lines && !(fl & HELP_TEXT))
1177 dprintf(idx, "%s\n", IRC_NOHELP2);
1178 }
1179
1180 /* same as tellallhelp, just using wild_match instead of strcmp */
1181 void tellwildhelp(int idx, char *match, struct flag_record *flags)
1182 {
1183 struct help_ref *current;
1184 struct help_list_t *item;
1185 FILE *f;
1186 char s[1024];
1187
1188 s[0] = '\0';
1189 for (current = help_list; current; current = current->next)
1190 for (item = current->first; item; item = item->next)
1191 if (wild_match(match, item->name) && item->type) {
1192 if (item->type == 1)
1193 simple_sprintf(s, "%s%s", helpdir, current->name);
1194 else
1195 simple_sprintf(s, "%sset/%s", helpdir, current->name);
1196 if ((f = fopen(s, "r")))
1197 display_tellhelp(idx, item->name, f, flags);
1198 }
1199 if (!s[0])
1200 dprintf(idx, "%s\n", IRC_NOHELP2);
1201 }
1202
1203 /* same as tellwildhelp, just using strcmp instead of wild_match */
1204 void tellallhelp(int idx, char *match, struct flag_record *flags)
1205 {
1206 struct help_ref *current;
1207 struct help_list_t *item;
1208 FILE *f;
1209 char s[1024];
1210
1211 s[0] = '\0';
1212 for (current = help_list; current; current = current->next)
1213 for (item = current->first; item; item = item->next)
1214 if (!strcmp(match, item->name) && item->type) {
1215
1216 if (item->type == 1)
1217 simple_sprintf(s, "%s%s", helpdir, current->name);
1218 else
1219 simple_sprintf(s, "%sset/%s", helpdir, current->name);
1220 if ((f = fopen(s, "r")))
1221 display_tellhelp(idx, item->name, f, flags);
1222 }
1223 if (!s[0])
1224 dprintf(idx, "%s\n", IRC_NOHELP2);
1225 }
1226
1227 /* substitute vars in a lang text to dcc chatter */
1228 void sub_lang(int idx, char *text)
1229 {
1230 char s[1024];
1231 struct flag_record fr =
1232 {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
1233
1234 get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
1235 help_subst(NULL, NULL, 0,
1236 (dcc[idx].status & STAT_TELNET) ? 0 : HELP_IRC, NULL);
1237 strncpy(s, text, 1023);
1238 s[1023] = 0;
1239 if (s[strlen(s) - 1] == '\n')
1240 s[strlen(s) - 1] = 0;
1241 if (!s[0])
1242 strcpy(s, " ");
1243 help_subst(s, dcc[idx].nick, &fr, 1, botnetnick);
1244 if (s[0])
1245 dprintf(idx, "%s\n", s);
1246 }
1247
1248 /* show motd to dcc chatter */
1249 void show_motd(int idx)
1250 {
1251 FILE *vv;
1252 char s[1024];
1253 struct flag_record fr =
1254 {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
1255
1256 get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
1257 vv = fopen(motdfile, "r");
1258 if (vv != NULL) {
1259 if (!is_file(motdfile)) {
1260 fclose(vv);
1261 dprintf(idx, "### MOTD %s\n", IRC_NOTNORMFILE);
1262 return;
1263 }
1264 dprintf(idx, "\n");
1265 help_subst(NULL, NULL, 0,
1266 (dcc[idx].status & STAT_TELNET) ? 0 : HELP_IRC, NULL);
1267 while (!feof(vv)) {
1268 fgets(s, 120, vv);
1269 if (!feof(vv)) {
1270 if (s[strlen(s) - 1] == '\n')
1271 s[strlen(s) - 1] = 0;
1272 if (!s[0])
1273 strcpy(s, " ");
1274 help_subst(s, dcc[idx].nick, &fr, 1, botnetnick);
1275 if (s[0])
1276 dprintf(idx, "%s\n", s);
1277 }
1278 }
1279 fclose(vv);
1280 dprintf(idx, "\n");
1281 }
1282 }
1283
1284 /* remove :'s from ignores and bans */
1285 void remove_gunk(char *par)
1286 {
1287 char *q, *p, *WBUF = nmalloc(strlen(par) + 1);
1288
1289 for (p = par, q = WBUF; *p; p++, q++) {
1290 if (*p == ':')
1291 q--;
1292 else
1293 *q = *p;
1294 }
1295 *q = *p;
1296 strcpy(par, WBUF);
1297 nfree(WBUF);
1298 }
1299
1300 /* This will return a pointer to the first character after the @ in the
1301 * string given it. Possibly it's time to think about a regexp library
1302 * for eggdrop... */
1303 char *extracthostname(char *hostmask)
1304 {
1305 char *ptr = strrchr(hostmask, '@');
1306
1307 if (ptr) {
1308 ptr = ptr + 1;
1309 return ptr;
1310 }
1311 return "";
1312 }
1313
1314 /* show banner to telnet user, simialer to show_motd() - [seC] */
1315 void show_banner(int idx) {
1316 FILE *vv;
1317 char s[1024];
1318 struct flag_record fr = {FR_GLOBAL|FR_CHAN,0,0,0,0,0};
1319
1320 get_user_flagrec(dcc[idx].user,&fr,dcc[idx].u.chat->con_chan);
1321 vv = fopen(bannerfile, "r");
1322 if (!vv || !is_file(bannerfile))
1323 return;
1324 while(!feof(vv)) {
1325 fgets(s, 120, vv);
1326 if (!feof(vv)) {
1327 if (!s[0])
1328 strcpy(s, " \n");
1329 help_subst(s, dcc[idx].nick, &fr, 1, botnetnick);
1330 dprintf(idx, "%s", s);
1331 }
1332 }
1333 }
1334
1335 /* create a string with random letters and digits */
1336 void make_rand_str(char *s, int len)
1337 {
1338 int j;
1339
1340 for (j = 0; j < len; j++) {
1341 if (random() % 3 == 0)
1342 s[j] = '0' + (random() % 10);
1343 else
1344 s[j] = 'a' + (random() % 26);
1345 }
1346 s[len] = 0;
1347 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23