/[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.2 - (show annotations) (download) (as text)
Thu Jun 24 19:54:57 1999 UTC (20 years, 2 months ago) by segfault
Branch: MAIN
Changes since 1.1: +24 -0 lines
File MIME type: text/x-chdr
Patch by Fabian to allow a customizable (by file) telnet banner handled
similarly to motd

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23