/[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.25 - (show annotations) (download) (as text)
Wed Jan 12 20:14:52 2000 UTC (19 years, 8 months ago) by per
Branch: MAIN
Changes since 1.24: +6 -2 lines
File MIME type: text/x-chdr
stricthost3 by drummer and dw

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23