/[svn]/ircd-hybrid/src/csvlib.c
ViewVC logotype

Diff of /ircd-hybrid/src/csvlib.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 933 by adx, Sun Aug 27 22:43:34 2006 UTC revision 934 by db, Wed Apr 8 20:34:38 2009 UTC
# Line 13  Line 13 
13    
14  // refuses to compile on win32 (unknown types and such),  // refuses to compile on win32 (unknown types and such),
15  // wouldn't work anyway, to be restored later.  // 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    }

Legend:
Removed from v.933  
changed lines
  Added in v.934

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28