/[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.7 - (show annotations) (download) (as text)
Tue Aug 17 22:26:16 1999 UTC (20 years, 3 months ago) by poptix
Branch: MAIN
Changes since 1.6: +33 -3 lines
File MIME type: text/x-chdr
 Committing in .

 Modified Files: 	Makefile TODO doc/UPDATES1.3 src/cmds.c src/language.c
 	src/main.c src/mem.c src/misc.c src/modules.h src/patch.h
 	src/proto.h src/tclegg.h src/users.c
 	src/mod/channels.mod/userchan.c src/mod/filesys.mod/filesys.h

all of fabian's patches.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23