ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/csvlib.c
Revision: 69
Committed: Tue Oct 4 16:09:51 2005 UTC (20 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 17612 byte(s)
Log Message:
- splitted ircd/libio, all headers connected with libio sources have been
  moved for internal use only. To use libio interface, include "libio.h"
  (which is already done in "stdinc.h")


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

Properties

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