ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/ircd-hybrid-newconf/src/csvlib.c
Revision: 1027
Committed: Sun Nov 8 13:01:13 2009 UTC (16 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 17510 byte(s)
Log Message:
- Move old 7.3 sources to branches/ircd-hybrid-newconf

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * csvlib.c - set of functions to deal with csv type of conf files
4 *
5 * Copyright (C) 2003 by Diane Bruce, Stuart Walsh
6 * Use it anywhere you like, if you like it buy us a beer.
7 * If it's broken, don't bother us with the lawyers.
8 *
9 * $Id$
10 */
11
12 #include "stdinc.h"
13
14 // refuses to compile on win32 (unknown types and such),
15 // wouldn't work anyway, to be restored later.
16 static void parse_csv_line(char *, ...);
17 static int write_csv_line(FBFILE *, const char *, ...);
18 static int flush_write(struct Client *, FBFILE *, FBFILE *,
19 const char *, const char *);
20 static char *getfield(char *);
21
22 /* parse_csv_file()
23 *
24 * inputs - FILE pointer
25 * - type of conf to parse
26 * output - none
27 * side effects -
28 */
29 void
30 parse_csv_file(FBFILE *file, ConfType conf_type)
31 {
32 struct ConfItem *conf;
33 struct AccessItem *aconf;
34 struct MatchItem *match_item;
35 char *name_field=NULL;
36 char *user_field=NULL;
37 char *reason_field=NULL;
38 char *oper_reason=NULL;
39 char *host_field=NULL;
40 char line[IRCD_BUFSIZE];
41 char *p;
42
43 while (fbgets(line, sizeof(line), file) != NULL)
44 {
45 if ((p = strchr(line, '\n')) != NULL)
46 *p = '\0';
47
48 if ((line[0] == '\0') || (line[0] == '#'))
49 continue;
50
51 switch(conf_type)
52 {
53 case KLINE_TYPE:
54 parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
55 conf = make_conf_item(KLINE_TYPE);
56 aconf = map_to_conf(conf);
57
58 if (host_field != NULL)
59 DupString(aconf->host, host_field);
60 if (reason_field != NULL)
61 DupString(aconf->reason, reason_field);
62 if (user_field != NULL)
63 DupString(aconf->user, user_field);
64 if (aconf->host != NULL)
65 add_conf_by_address(CONF_KILL, aconf);
66 break;
67
68 case RKLINE_TYPE:
69 {
70 const char *errptr = NULL;
71 pcre *exp_user = NULL, *exp_host = NULL;
72
73 parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
74
75 if (host_field == NULL || user_field == NULL)
76 break;
77
78 if (!(exp_user = ircd_pcre_compile(user_field, &errptr)) ||
79 !(exp_host = ircd_pcre_compile(host_field, &errptr)))
80 {
81 sendto_realops_flags(UMODE_ALL, L_ALL,
82 "Failed to add regular expression based K-Line: %s", errptr);
83 break;
84 }
85
86 aconf = map_to_conf(make_conf_item(RKLINE_TYPE));
87
88 aconf->regexuser = exp_user;
89 aconf->regexhost = exp_host;
90
91 DupString(aconf->user, user_field);
92 DupString(aconf->host, host_field);
93
94 if (reason_field != NULL)
95 DupString(aconf->reason, reason_field);
96 else
97 DupString(aconf->reason, "No reason");
98
99 }
100 break;
101
102 case DLINE_TYPE:
103 parse_csv_line(line, &host_field, &reason_field, NULL);
104 conf = make_conf_item(DLINE_TYPE);
105 aconf = (struct AccessItem *)map_to_conf(conf);
106 if (host_field != NULL)
107 DupString(aconf->host, host_field);
108 if (reason_field != NULL)
109 DupString(aconf->reason, reason_field);
110 conf_add_d_conf(aconf);
111 break;
112
113 case XLINE_TYPE:
114 parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
115 conf = make_conf_item(XLINE_TYPE);
116 match_item = (struct MatchItem *)map_to_conf(conf);
117 if (name_field != NULL)
118 DupString(conf->name, name_field);
119 if (reason_field != NULL)
120 DupString(match_item->reason, reason_field);
121 break;
122
123 case RXLINE_TYPE:
124 {
125 const char *errptr = NULL;
126 pcre *exp_p = NULL;
127
128 parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
129
130 if (name_field == NULL)
131 break;
132
133 if (!(exp_p = ircd_pcre_compile(name_field, &errptr)))
134 {
135 sendto_realops_flags(UMODE_ALL, L_ALL,
136 "Failed to add regular expression based X-Line: %s", errptr);
137 break;
138 }
139
140 conf = make_conf_item(RXLINE_TYPE);
141 conf->regexpname = exp_p;
142 match_item = map_to_conf(conf);
143 DupString(conf->name, name_field);
144
145 if (reason_field != NULL)
146 DupString(match_item->reason, reason_field);
147 else
148 DupString(match_item->reason, "No reason");
149 }
150 break;
151
152 case CRESV_TYPE:
153 parse_csv_line(line, &name_field, &reason_field, NULL);
154 (void)create_channel_resv(name_field, reason_field, 0);
155 break;
156
157 case NRESV_TYPE:
158 parse_csv_line(line, &name_field, &reason_field, NULL);
159 (void)create_nick_resv(name_field, reason_field, 0);
160 break;
161
162 case GLINE_TYPE:
163 case GDENY_TYPE:
164 case CONF_TYPE:
165 case OPER_TYPE:
166 case CLIENT_TYPE:
167 case SERVER_TYPE:
168 case CLUSTER_TYPE:
169 case HUB_TYPE:
170 case LEAF_TYPE:
171 case ULINE_TYPE:
172 case EXEMPTDLINE_TYPE:
173 case CLASS_TYPE:
174 break;
175 }
176 }
177 }
178
179 /*
180 * parse_csv_line()
181 *
182 * inputs - pointer to line to parse
183 * output -
184 * side effects -
185 */
186
187 static void
188 parse_csv_line(char *line, ...)
189 {
190 va_list args;
191 char **dest;
192 char *field = NULL;
193
194 va_start(args, line);
195
196 for (; ;)
197 {
198 dest = va_arg(args, char **);
199 if ((dest == NULL) || ((field = getfield(field ? NULL : line)) == NULL))
200 {
201 va_end(args);
202 return;
203 }
204 *dest = field;
205 }
206 }
207
208 /* write_conf_line()
209 *
210 * inputs - pointer to struct AccessItem
211 * - string current_date (small date)
212 * - time_t cur_time
213 * output - NONE
214 * side effects - This function takes care of
215 * finding right conf file, writing
216 * the right lines to this file,
217 * notifying the oper that their kline/dline etc. is in place
218 * notifying the opers on the server about the k/d etc. line
219 *
220 * - Dianora
221 */
222 void
223 write_conf_line(struct ConfItem *conf,
224 const char *current_date, time_t cur_time)
225 {
226 FBFILE *out;
227 const char *filename, *from, *to;
228 struct AccessItem *aconf;
229 struct MatchItem *xconf;
230 struct ResvChannel *cresv_p=NULL;
231 struct MatchItem *nresv_p=NULL;
232 ConfType type;
233
234 type = conf->type;
235 filename = get_conf_name(type);
236
237 if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
238 {
239 from = me.id;
240 to = source_p->id;
241 }
242 else
243 {
244 from = me.name;
245 to = source_p->name;
246 }
247
248 if ((out = fbopen(filename, "a")) == NULL)
249 {
250 sendto_realops_flags(UMODE_ALL, L_ALL,
251 "*** Problem opening %s ", filename);
252 return;
253 }
254
255 switch(type)
256 {
257 case KLINE_TYPE:
258 aconf = (struct AccessItem *)map_to_conf(conf);
259 sendto_realops_flags(UMODE_ALL, L_ALL,
260 "%s added K-Line for [%s@%s] [%s]",
261 get_oper_name(source_p),
262 aconf->user, aconf->host, aconf->reason);
263 sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]",
264 from, to, aconf->user, aconf->host);
265 ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
266 source_p->name, aconf->user, aconf->host, aconf->reason);
267 log_oper_action(LOG_KLINE_TYPE, source_p, "[%s@%s] [%s]\n",
268 aconf->user, aconf->host, aconf->reason);
269 write_csv_line(out, "%s%s%s%s%s%s%d",
270 aconf->user, aconf->host,
271 aconf->reason, aconf->oper_reason, current_date,
272 get_oper_name(source_p), cur_time);
273 break;
274
275 case RKLINE_TYPE:
276 aconf = map_to_conf(conf);
277 sendto_realops_flags(UMODE_ALL, L_ALL,
278 "%s added RK-Line for [%s@%s] [%s]",
279 get_oper_name(source_p),
280 aconf->user, aconf->host, aconf->reason);
281 sendto_one(source_p, ":%s NOTICE %s :Added RK-Line [%s@%s]",
282 from, to, aconf->user, aconf->host);
283 ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
284 source_p->name, aconf->user, aconf->host, aconf->reason);
285 log_oper_action(LOG_RKLINE_TYPE, source_p, "[%s@%s] [%s]\n",
286 aconf->user, aconf->host, aconf->reason);
287 write_csv_line(out, "%s%s%s%s%s%s%d",
288 aconf->user, aconf->host,
289 aconf->reason, aconf->oper_reason, current_date,
290 get_oper_name(source_p), cur_time);
291 break;
292
293 case DLINE_TYPE:
294 aconf = (struct AccessItem *)map_to_conf(conf);
295 sendto_realops_flags(UMODE_ALL, L_ALL,
296 "%s added D-Line for [%s] [%s]",
297 get_oper_name(source_p), aconf->host, aconf->reason);
298 sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s",
299 from, to, aconf->host, filename);
300 ilog(L_TRACE, "%s added D-Line for [%s] [%s]",
301 get_oper_name(source_p), aconf->host, aconf->reason);
302 log_oper_action(LOG_DLINE_TYPE, source_p, "[%s] [%s]\n",
303 aconf->host, aconf->reason);
304 write_csv_line(out, "%s%s%s%s%s%d",
305 aconf->host, aconf->reason, aconf->oper_reason,
306 current_date,
307 get_oper_name(source_p), cur_time);
308 break;
309
310 case XLINE_TYPE:
311 xconf = (struct MatchItem *)map_to_conf(conf);
312 sendto_realops_flags(UMODE_ALL, L_ALL,
313 "%s added X-Line for [%s] [%s]",
314 get_oper_name(source_p), conf->name,
315 xconf->reason);
316 sendto_one(source_p,
317 ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s",
318 from, to, conf->name,
319 xconf->action, xconf->reason, filename);
320 ilog(L_TRACE, "%s added X-Line for [%s] [%s]",
321 get_oper_name(source_p), conf->name, xconf->reason);
322 write_csv_line(out, "%s%s%s%s%s%d",
323 conf->name, xconf->reason, xconf->oper_reason,
324 current_date, get_oper_name(source_p), cur_time);
325 break;
326
327 case RXLINE_TYPE:
328 xconf = (struct MatchItem *)map_to_conf(conf);
329 sendto_realops_flags(UMODE_ALL, L_ALL,
330 "%s added RX-Line for [%s] [%s]",
331 get_oper_name(source_p), conf->name,
332 xconf->reason);
333 sendto_one(source_p,
334 ":%s NOTICE %s :Added RX-Line [%s] [%s] to %s",
335 from, to, conf->name,
336 xconf->reason, filename);
337 ilog(L_TRACE, "%s added X-Line for [%s] [%s]",
338 get_oper_name(source_p), conf->name, xconf->reason);
339 write_csv_line(out, "%s%s%s%s%s%d",
340 conf->name, xconf->reason, xconf->oper_reason,
341 current_date, get_oper_name(source_p), cur_time);
342 break;
343
344 case CRESV_TYPE:
345 cresv_p = (struct ResvChannel *)map_to_conf(conf);
346
347 write_csv_line(out, "%s%s",
348 cresv_p->name, cresv_p->reason);
349 break;
350
351 case NRESV_TYPE:
352 nresv_p = (struct MatchItem *)map_to_conf(conf);
353
354 write_csv_line(out, "%s%s",
355 conf->name, nresv_p->reason);
356 break;
357
358 default:
359 fbclose(out);
360 return;
361 }
362
363 fbclose(out);
364 }
365
366 /*
367 * write_csv_line()
368 *
369 * inputs - pointer to FBFILE *
370 * - formatted string
371 * output -
372 * side effects - single line is written to csv conf file
373 */
374 static int
375 write_csv_line(FBFILE *out, const char *format, ...)
376 {
377 char c;
378 size_t bytes = 0;
379 va_list args;
380 char tmp[1024];
381 char *str = tmp;
382 const char *null_string = "";
383
384 if (out == NULL)
385 return(0);
386
387 va_start(args, format);
388
389 while ((c = *format++))
390 {
391 if (c == '%')
392 {
393 c = *format++;
394 if (c == 's')
395 {
396 const char *p1 = va_arg(args, const char *);
397 if (p1 == NULL)
398 p1 = null_string;
399 *str++ = '\"';
400 ++bytes;
401 while (*p1 != '\0')
402 {
403 *str++ = *p1++;
404 ++bytes;
405 }
406 *str++ = '\"';
407 *str++ = ',';
408
409 bytes += 2;
410 continue;
411 }
412 if (c == 'c')
413 {
414 *str++ = '\"';
415 ++bytes;
416 *str++ = (char) va_arg(args, int);
417 ++bytes;
418 *str++ = '\"';
419 *str++ = ',';
420
421 bytes += 2;
422 continue;
423 }
424
425 if (c == 'd')
426 {
427 int v = va_arg(args, int);
428 char t[40];
429 char *p=t;
430
431 while (v > 10)
432 {
433 *p++ = (v % 10) + '0';
434 v = v/10;
435 }
436 *p++ = (v % 10) + '0';
437
438 *str++ = '\"';
439 ++bytes;
440 while (p != t)
441 {
442 *str++ = *--p;
443 ++bytes;
444 }
445
446 *str++ = '\"';
447 *str++ = ',';
448 bytes += 2;
449 continue;
450 }
451 if (c != '%')
452 {
453 int ret;
454
455 format -= 2;
456 ret = vsprintf(str, format, args);
457 str += ret;
458 bytes += ret;
459 *str++ = ',';
460
461 ++bytes;
462 break;
463 }
464 }
465 *str++ = c;
466 ++bytes;
467 }
468
469 if (*(str-1) == ',')
470 {
471 *(str-1) = '\n';
472 *str = '\0';
473 }
474 else
475 {
476 *str++ = '\n';
477 ++bytes;
478 *str = '\0';
479 }
480
481 va_end(args);
482 str = tmp;
483 fbputs(str, out, bytes);
484
485 return(bytes);
486 }
487
488 /*
489 * getfield
490 *
491 * inputs - input buffer
492 * output - next field
493 * side effects - field breakup for ircd.conf file.
494 */
495 static char *
496 getfield(char *newline)
497 {
498 static char *line = NULL;
499 char *end, *field;
500
501 if (newline != NULL)
502 line = newline;
503
504 if (line == NULL)
505 return(NULL);
506
507 field = line;
508
509 /* skip everything that's not a starting quote */
510 for(;;)
511 {
512 if (*field == '\0')
513 return(NULL);
514 else if (*field == '"')
515 break;
516 ++field;
517 }
518
519 /* skip over the beginning " */
520 end = ++field;
521
522 for (;;)
523 {
524 /* At end of string, mark it as end and return */
525 if ((*end == '\0') || (*end == '\n'))
526 {
527 line = NULL;
528 return(NULL);
529 }
530 else if (*end == '\\') /* found escape character ? */
531 {
532 end++;
533 }
534 else if (*end == '"') /* found terminating " */
535 {
536 *end++ = '\0';
537 line = end;
538 return(field);
539 }
540
541 end++;
542 }
543
544 return (NULL);
545 }
546
547 /* remove_conf_line()
548 *
549 * inputs - type of kline to remove
550 * - pointer to oper removing
551 * - pat1 pat2 patterns to match
552 * output - -1 if unsuccessful 0 if no change 1 if change
553 * side effects -
554 */
555 int
556 remove_conf_line(ConfType type, struct Client *source_p, const char *pat1, const char *pat2)
557 {
558 const char *filename;
559 FBFILE *in, *out;
560 int pairme=0;
561 char buf[IRCD_BUFSIZE], buff[IRCD_BUFSIZE], temppath[IRCD_BUFSIZE];
562 char *found1;
563 char *found2;
564 int oldumask;
565 int (*cmpfunc)(const char *, const char *) = irccmp;
566
567 if (type == RXLINE_TYPE || type == RKLINE_TYPE)
568 cmpfunc = strcmp;
569
570 filename = get_conf_name(type);
571
572 if ((in = fbopen(filename, "r")) == NULL)
573 {
574 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
575 source_p->name, filename);
576 return -1;
577 }
578
579 ircsprintf(temppath, "%s.tmp", filename);
580 oldumask = umask(0);
581
582 if ((out = fbopen(temppath, "w")) == NULL)
583 {
584 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
585 source_p->name, temppath);
586 fbclose(in);
587 umask(oldumask);
588 return -1;
589 }
590
591 umask(oldumask);
592 oldumask = umask(0);
593
594 while (fbgets(buf, sizeof(buf), in) != NULL)
595 {
596 if ((*buf == '\0') || (*buf == '#'))
597 {
598 if (flush_write(source_p, in, out, buf, temppath) < 0)
599 return -1;
600 }
601
602 /* Keep copy of original line, getfield trashes line as it goes */
603 strlcpy(buff, buf, sizeof(buff));
604
605 if ((found1 = getfield(buff)) == NULL)
606 {
607 if (flush_write(source_p, in, out, buf, temppath) < 0)
608 return -1;
609 continue;
610 }
611
612 if (pat2 != NULL)
613 {
614 if ((found2 = getfield(NULL)) == NULL)
615 {
616 if (flush_write(source_p, in, out, buf, temppath) < 0)
617 return -1;
618 continue;
619 }
620
621 if (!cmpfunc(pat1, found1) && !cmpfunc(pat2, found2))
622 {
623 pairme = 1;
624 continue;
625 }
626 else
627 {
628 if(flush_write(source_p, in, out, buf, temppath) < 0)
629 return -1;
630 continue;
631 }
632 }
633 else
634 {
635 if (!cmpfunc(pat1, found1))
636 {
637 pairme = 1;
638 continue;
639 }
640 else
641 {
642 if(flush_write(source_p, in, out, buf, temppath) < 0)
643 return -1;
644 continue;
645 }
646 }
647 }
648
649 fbclose(in);
650 fbclose(out);
651
652 /* The result of the rename should be checked too... oh well */
653 /* If there was an error on a write above, then its been reported
654 * and I am not going to trash the original kline /conf file
655 */
656
657 if (pairme == 0)
658 {
659 if(temppath != NULL)
660 (void)unlink(temppath);
661 return 0;
662 }
663 else
664 {
665 (void)rename(temppath, filename);
666
667 /* XXX
668 * This is a very inefficient way of removing a kline/xline etc.
669 * This next function call forces a complete re-read of all conf
670 * files, instead of a re-read of the kline/dline etc. files modified
671 * But, consider how often an /quote unkline etc. is done compared
672 * to how often a /quote kline is done. Its not a biggie in
673 * the grand scheme of things. If it does become a biggie,
674 * we will rewrite it - Dianora
675 */
676
677 rehash(0);
678 return 1;
679 }
680 }
681
682 /*
683 * flush_write()
684 *
685 * inputs - pointer to client structure of oper requesting unkline
686 * - in is the input file descriptor
687 * - out is the output file descriptor
688 * - buf is the buffer to write
689 * - ntowrite is the expected number of character to be written
690 * - temppath is the temporary file name to be written
691 * output - -1 for error on write
692 * - 0 for ok
693 * side effects - if successful, the buf is written to output file
694 * if a write failure happesn, and the file pointed to
695 * by temppath, if its non NULL, is removed.
696 *
697 * The idea here is, to be as robust as possible when writing to the
698 * kline file.
699 *
700 * -Dianora
701 */
702 static int
703 flush_write(struct Client *source_p, FBFILE *in, FBFILE* out,
704 const char *buf, const char *temppath)
705 {
706 int error_on_write = (fbputs(buf, out, strlen(buf)) < 0) ? (-1) : (0);
707
708 if (error_on_write)
709 {
710 sendto_one(source_p,":%s NOTICE %s :Unable to write to %s aborting",
711 me.name, source_p->name, temppath);
712 if(temppath != NULL)
713 (void)unlink(temppath);
714 fbclose(in);
715 fbclose(out);
716 }
717
718 return (error_on_write);
719 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision