/[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.10 - (show annotations) (download) (as text)
Thu Aug 26 08:15:16 1999 UTC (20 years ago) by guppy
Branch: MAIN
Changes since 1.9: +26 -0 lines
File MIME type: text/x-chdr
helpfix2.patch

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23