/[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.18 - (show annotations) (download) (as text)
Mon Oct 18 19:59:50 1999 UTC (20 years, 1 month ago) by guppy
Branch: MAIN
Changes since 1.17: +5 -2 lines
File MIME type: text/x-chdr
dang coredumps

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23