ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/csvlib.c
Revision: 741
Committed: Sun Jul 23 13:49:20 2006 UTC (19 years, 1 month ago) by adx
Content type: text/x-csrc
File size: 14310 byte(s)
Log Message:
+ removed s_conf.h and superseded parts of s_conf.c

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

Properties

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