/[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.29 - (show annotations) (download) (as text)
Tue Apr 4 23:43:08 2000 UTC (19 years, 3 months ago) by guppy
Branch: MAIN
CVS Tags: eggdrop104030RC2, eggdrop10404, eggdrop10403, HEAD
Changes since 1.28: +6 -4 lines
File MIME type: text/x-chdr
time for rc2

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23