ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/csvlib.c
Revision: 30
Committed: Sun Oct 2 20:03:27 2005 UTC (19 years, 10 months ago) by adx
Content type: text/x-csrc
Original Path: ircd-hybrid/src/csvlib.c
File size: 17786 byte(s)
Log Message:
- imported sources
- can be moved later according to the directory/branching scheme,
  but we need the svn up

File Contents

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

Properties

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