/[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.1 - (show annotations) (download) (as text)
Wed Jun 23 19:51:30 1999 UTC (20 years, 3 months ago) by segfault
Branch: MAIN
Branch point for: eggdev
File MIME type: text/x-chdr
Initial revision

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23