/[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.23 - (show annotations) (download) (as text)
Thu Jan 6 21:03:45 2000 UTC (19 years, 8 months ago) by guppy
Branch: MAIN
Changes since 1.22: +16 -16 lines
File MIME type: text/x-chdr
patches queue, waiting for a new copyright.patch

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23