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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23