source: trunk/oscam-config-reader.c @ 9531

Last change on this file since 9531 was 9531, checked in by Gorgone Impertinence, 6 years ago

remove version send on wish of blacky (programmer of this patch)

File size: 35.4 KB
Line 
1#include "globals.h"
2#include "module-gbox.h"
3#include "oscam-aes.h"
4#include "oscam-conf.h"
5#include "oscam-conf-chk.h"
6#include "oscam-conf-mk.h"
7#include "oscam-config.h"
8#include "oscam-garbage.h"
9#include "oscam-lock.h"
10#include "oscam-reader.h"
11#include "oscam-string.h"
12
13#define cs_srvr "oscam.server"
14
15extern struct s_cardreader cardreaders[CS_MAX_MOD];
16extern char *RDR_CD_TXT[];
17
18static void reader_label_fn(const char *token, char *value, void *setting, FILE *f)
19{
20    struct s_reader *rdr = setting;
21    if(value)
22    {
23        int i, found = 0;
24        if(!strlen(value))
25            { return; }
26        for(i = 0; i < (int)strlen(value); i++)
27        {
28            if(value[i] == ' ')
29            {
30                value[i] = '_';
31                found++;
32            }
33        }
34        if(found)
35            { fprintf(stderr, "Configuration reader: corrected label to %s\n", value); }
36        cs_strncpy(rdr->label, value, sizeof(rdr->label));
37        return;
38    }
39    fprintf_conf(f, token, "%s\n", rdr->label);
40}
41
42static void ecmwhitelist_fn(const char *token, char *value, void *setting, FILE *f)
43{
44    struct s_reader *rdr = setting;
45    if(value)
46    {
47        char *ptr, *ptr2, *ptr3, *saveptr1 = NULL;
48        struct s_ecmWhitelist *tmp, *last;
49        struct s_ecmWhitelistIdent *tmpIdent, *lastIdent;
50        struct s_ecmWhitelistLen *tmpLen, *lastLen;
51        for(tmp = rdr->ecmWhitelist; tmp; tmp = tmp->next)
52        {
53            for(tmpIdent = tmp->idents; tmpIdent; tmpIdent = tmpIdent->next)
54            {
55                for(tmpLen = tmpIdent->lengths; tmpLen; tmpLen = tmpLen->next)
56                {
57                    add_garbage(tmpLen);
58                }
59                add_garbage(tmpIdent);
60            }
61            add_garbage(tmp);
62        }
63        rdr->ecmWhitelist = NULL;
64        if(strlen(value) > 0)
65        {
66            saveptr1 = NULL;
67            char *saveptr2 = NULL;
68            for(ptr = strtok_r(value, ";", &saveptr1); ptr; ptr = strtok_r(NULL, ";", &saveptr1))
69            {
70                int16_t caid = 0, len;
71                uint32_t ident = 0;
72                ptr2 = strchr(ptr, ':');
73                if(ptr2 != NULL)
74                {
75                    ptr2[0] = '\0';
76                    ++ptr2;
77                    ptr3 = strchr(ptr, '@');
78                    if(ptr3 != NULL)
79                    {
80                        ptr3[0] = '\0';
81                        ++ptr3;
82                        ident = (uint32_t)a2i(ptr3, 6);
83                    }
84                    caid = (int16_t)dyn_word_atob(ptr);
85                }
86                else { ptr2 = ptr; }
87                for(ptr2 = strtok_r(ptr2, ",", &saveptr2); ptr2; ptr2 = strtok_r(NULL, ",", &saveptr2))
88                {
89                    len = (int16_t)dyn_word_atob(ptr2);
90                    last = NULL, tmpIdent = NULL, lastIdent = NULL, tmpLen = NULL, lastLen = NULL;
91                    for(tmp = rdr->ecmWhitelist; tmp; tmp = tmp->next)
92                    {
93                        last = tmp;
94                        if(tmp->caid == caid)
95                        {
96                            for(tmpIdent = tmp->idents; tmpIdent; tmpIdent = tmpIdent->next)
97                            {
98                                lastIdent = tmpIdent;
99                                if(tmpIdent->ident == ident)
100                                {
101                                    for(tmpLen = tmpIdent->lengths; tmpLen; tmpLen = tmpLen->next)
102                                    {
103                                        lastLen = tmpLen;
104                                        if(tmpLen->len == len) { break; }
105                                    }
106                                    break;
107                                }
108                            }
109                        }
110                    }
111                    if(tmp == NULL)
112                    {
113                        if(cs_malloc(&tmp, sizeof(struct s_ecmWhitelist)))
114                        {
115                            tmp->caid = caid;
116                            tmp->idents = NULL;
117                            tmp->next = NULL;
118                            if(last == NULL)
119                            {
120                                rdr->ecmWhitelist = tmp;
121                            }
122                            else
123                            {
124                                last->next = tmp;
125                            }
126                        }
127                    }
128                    if(tmp != NULL && tmpIdent == NULL)
129                    {
130                        if(cs_malloc(&tmpIdent, sizeof(struct s_ecmWhitelistIdent)))
131                        {
132                            tmpIdent->ident = ident;
133                            tmpIdent->lengths = NULL;
134                            tmpIdent->next = NULL;
135                            if(lastIdent == NULL)
136                            {
137                                tmp->idents = tmpIdent;
138                            }
139                            else
140                            {
141                                lastIdent->next = tmpIdent;
142                            }
143                        }
144                    }
145                    if(tmp != NULL && tmpIdent != NULL && tmpLen == NULL)
146                    {
147                        if(cs_malloc(&tmpLen, sizeof(struct s_ecmWhitelistLen)))
148                        {
149                            tmpLen->len = len;
150                            tmpLen->next = NULL;
151                            if(lastLen == NULL)
152                            {
153                                tmpIdent->lengths = tmpLen;
154                            }
155                            else
156                            {
157                                lastLen->next = tmpLen;
158                            }
159                        }
160                    }
161                }
162            }
163        }
164        return;
165    }
166
167    value = mk_t_ecmwhitelist(rdr->ecmWhitelist);
168    if(strlen(value) > 0 || cfg.http_full_cfg)
169        { fprintf_conf(f, token, "%s\n", value); }
170    free_mk_t(value);
171}
172
173static void ecmheaderwhitelist_fn(const char *token, char *value, void *setting, FILE *f)
174{
175    struct s_reader *rdr = setting;
176    if(value)
177    {
178        char *ptr, *ptr2, *ptr3;
179        struct s_ecmHeaderwhitelist *tmp, *last = NULL;
180
181        if(strlen(value) == 0)
182        {
183            for(tmp = rdr->ecmHeaderwhitelist; tmp; tmp = tmp->next)
184                { add_garbage(tmp); }
185            rdr->ecmHeaderwhitelist = NULL;
186        }
187        else
188        {
189            char *ptr4, *ptr5, *ptr6, *saveptr = NULL, *saveptr4 = NULL, *saveptr5 = NULL, *saveptr6 = NULL;
190            uint16_t caid = 0;
191            uint32_t provid = 0;
192            int16_t len = 0;
193            for(ptr = strtok_r(value, ";", &saveptr); ptr; ptr = strtok_r(NULL, ";", &saveptr))
194            {
195                caid = 0;
196                provid = 0;
197                ptr2 = strchr(ptr, '@');
198                ptr3 = strchr(ptr, ':');
199                if(ptr2 == NULL && ptr3 == NULL)    //no Caid no Provid
200                {
201                    for(ptr4 = strtok_r(ptr, ",", &saveptr4); ptr4; ptr4 = strtok_r(NULL, ",", &saveptr4))
202                    {
203                        if(cs_malloc(&tmp, sizeof(struct s_ecmHeaderwhitelist)))
204                        {
205                            ptr4 = trim(ptr4);
206                            len = strlen(ptr4);
207                            key_atob_l(ptr4, tmp->header, len);
208                            tmp->len = len;
209                            tmp->caid = 0;
210                            tmp->provid = 0;
211                            tmp->next = NULL;
212                            if(last == NULL)
213                            {
214                                rdr->ecmHeaderwhitelist = tmp;
215                            }
216                            else
217                            {
218                                last->next = tmp;
219                            }
220                            last = tmp;
221                        }
222                    }
223                }
224
225                if(ptr3 != NULL && ptr2 == NULL)    // only with Caid
226                {
227                    ptr3[0] = '\0';
228                    ++ptr3;
229                    caid = (int16_t)dyn_word_atob(ptr);
230                    for(ptr5 = strtok_r(ptr3, ",", &saveptr5); ptr5; ptr5 = strtok_r(NULL, ",", &saveptr5))
231                    {
232                        if(cs_malloc(&tmp, sizeof(struct s_ecmHeaderwhitelist)))
233                        {
234                            tmp->caid = caid;
235                            tmp->provid = 0;
236                            ptr5 = trim(ptr5);
237                            len = strlen(ptr5);
238                            key_atob_l(ptr5, tmp->header, len);
239                            tmp->len = len;
240                            tmp->next = NULL;
241                            if(last == NULL)
242                            {
243                                rdr->ecmHeaderwhitelist = tmp;
244                            }
245                            else
246                            {
247                                last->next = tmp;
248                            }
249                            last = tmp;
250                        }
251                    }
252                }
253
254                if(ptr3 != NULL && ptr2 != NULL)    // with Caid & Provid
255                {
256                    ptr2[0] = '\0';
257                    ++ptr2; // -> provid
258                    ptr3[0] = '\0';
259                    ++ptr3; // -> headers
260                    caid = (int16_t)dyn_word_atob(ptr);
261                    provid = (uint32_t)a2i(ptr2, 6);
262                    for(ptr6 = strtok_r(ptr3, ",", &saveptr6); ptr6; ptr6 = strtok_r(NULL, ",", &saveptr6))
263                    {
264                        if(cs_malloc(&tmp, sizeof(struct s_ecmHeaderwhitelist)))
265                        {
266                            tmp->caid = caid;
267                            tmp->provid = provid;
268                            ptr6 = trim(ptr6);
269                            len = strlen(ptr6);
270                            key_atob_l(ptr6, tmp->header, len);
271                            tmp->len = len;
272                            tmp->next = NULL;
273                            if(last == NULL)
274                            {
275                                rdr->ecmHeaderwhitelist = tmp;
276                            }
277                            else
278                            {
279                                last->next = tmp;
280                            }
281                            last = tmp;
282                        }
283                    }
284                }
285            }
286        }
287        /*  if (rdr->ecmHeaderwhitelist != NULL) { // debug
288                cs_log("**********Begin ECM Header List for Reader: %s **************", rdr->label);
289
290                struct s_ecmHeaderwhitelist *tmp;
291                for(tmp = rdr->ecmHeaderwhitelist; tmp; tmp=tmp->next){
292                    cs_log("Caid: %i Provid: %i Header: %02X Len: %i", tmp->caid, tmp->provid, tmp->header[0], tmp->len);
293                }
294                cs_log("***********End ECM Header List for Reader: %s ***************", rdr->label);
295            } */
296        return;
297    }
298
299    value = mk_t_ecmheaderwhitelist(rdr->ecmHeaderwhitelist);
300    if(strlen(value) > 0 || cfg.http_full_cfg)
301        { fprintf_conf(f, token, "%s\n", value); }
302    free_mk_t(value);
303}
304
305static void protocol_fn(const char *token, char *value, void *setting, FILE *f)
306{
307    struct s_reader *rdr = setting;
308    if(value)
309    {
310        if(strlen(value) == 0)
311            { return; }
312        struct protocol_map
313        {
314            char *name;
315            int typ;
316        } protocols[] =
317        {
318            { "serial",     R_SERIAL },
319            { "camd35",     R_CAMD35 },
320            { "cs378x",     R_CS378X },
321            { "cs357x",     R_CAMD35 },
322            { "camd33",     R_CAMD33 },
323            { "gbox",       R_GBOX },
324            { "cccam",      R_CCCAM },
325            { "cccam ext",  R_CCCAM },
326            { "constcw",    R_CONSTCW },
327            { "radegast",   R_RADEGAST },
328            { "ghttp",      R_GHTTP },
329            { "newcamd",    R_NEWCAMD },
330            { "newcamd525", R_NEWCAMD },
331            { "newcamd524", R_NEWCAMD },
332            { NULL        , 0 }
333        }, *p;
334        int i;
335        // Parse card readers
336        for(i = 0; i < CS_MAX_MOD; i++)
337        {
338            if(streq(value, cardreaders[i].desc))
339            {
340                rdr->crdr = cardreaders[i];
341                rdr->typ  = cardreaders[i].typ;
342                return;
343            }
344        }
345        // Parse protocols
346        for(i = 0, p = &protocols[0]; p->name; p = &protocols[++i])
347        {
348            if(streq(p->name, value))
349            {
350                rdr->typ = p->typ;
351                break;
352            }
353        }
354        if(rdr->typ == R_NEWCAMD)
355            { rdr->ncd_proto = streq(value, "newcamd524") ? NCD_524 : NCD_525; }
356        if(!rdr->typ)
357            { fprintf(stderr, "ERROR: '%s' is unsupported reader protocol!\n", value); }
358        return;
359    }
360    fprintf_conf(f, token, "%s\n", reader_get_type_desc(rdr, 0));
361}
362
363static void device_fn(const char *token, char *value, void *setting, FILE *f)
364{
365    struct s_reader *rdr = setting;
366    int32_t isphysical = !is_network_reader(rdr);
367    if(value)
368    {
369        int32_t i;
370        char *ptr, *saveptr1 = NULL;
371        for(i = 0, ptr = strtok_r(value, ",", &saveptr1); (i < 3) && (ptr); ptr = strtok_r(NULL, ",", &saveptr1), i++)
372        {
373            trim(ptr);
374            switch(i)
375            {
376            case 0:
377                cs_strncpy(rdr->device, ptr, sizeof(rdr->device));
378                break;
379            case 1:
380                rdr->r_port = atoi(ptr);
381                break;
382            case 2:
383                rdr->l_port = atoi(ptr);
384                break;
385            }
386        }
387        return;
388    }
389    fprintf_conf(f, token, "%s", rdr->device); // it should not have \n at the end
390    if((rdr->r_port || cfg.http_full_cfg) && !isphysical)
391        { fprintf(f, ",%d", rdr->r_port); }
392    if((rdr->l_port || cfg.http_full_cfg) && !isphysical && strncmp(reader_get_type_desc(rdr, 0), "cccam", 5))
393        { fprintf(f, ",%d", rdr->l_port); }
394    fprintf(f, "\n");
395}
396
397static void reader_services_fn(const char *token, char *value, void *setting, FILE *f)
398{
399    services_fn(token, value, setting, f);
400    if(value)
401    {
402        struct s_reader *rdr = container_of(setting, struct s_reader, sidtabs);
403        if(rdr)
404            { rdr->changes_since_shareupdate = 1; }
405    }
406}
407
408static void reader_lb_services_fn(const char *token, char *value, void *setting, FILE *f)
409{
410    services_fn(token, value, setting, f);
411    if(value)
412    {
413        struct s_reader *rdr = container_of(setting, struct s_reader, lb_sidtabs);
414        if(rdr)
415            { rdr->changes_since_shareupdate = 1; }
416    }
417}
418
419static void reader_caid_fn(const char *token, char *value, void *setting, FILE *f)
420{
421    check_caidtab_fn(token, value, setting, f);
422    if(value)
423    {
424        struct s_reader *rdr = container_of(setting, struct s_reader, ctab);
425        if(rdr)
426            { rdr->changes_since_shareupdate = 1; }
427    }
428}
429
430static void boxid_fn(const char *token, char *value, void *setting, FILE *f)
431{
432    struct s_reader *rdr = setting;
433    if(value)
434    {
435        rdr->boxid = strlen(value) ? a2i(value, 4) : 0;
436        return;
437    }
438    if(rdr->boxid)
439        { fprintf_conf(f, token, "%08X\n", rdr->boxid); }
440    else if(cfg.http_full_cfg)
441        { fprintf_conf(f, token, "\n"); }
442}
443
444static void rsakey_fn(const char *token, char *value, void *setting, FILE *f)
445{
446    struct s_reader *rdr = setting;
447    if(value)
448    {
449        int32_t len = strlen(value);
450        if(len != 128 && len != 240)
451        {
452            memset(rdr->rsa_mod, 0, 120);
453        }
454        else
455        {
456            if(key_atob_l(value, rdr->rsa_mod, len))
457            {
458                fprintf(stderr, "reader rsakey parse error, %s=%s\n", token, value);
459                memset(rdr->rsa_mod, 0, sizeof(rdr->rsa_mod));
460            }
461        }
462        return;
463    }
464    int32_t len = check_filled(rdr->rsa_mod, 120);
465    if(len > 0)
466    {
467        if(len > 64) { len = 120; }
468        else { len = 64; }
469        char tmp[len * 2 + 1];
470        fprintf_conf(f, "rsakey", "%s\n", cs_hexdump(0, rdr->rsa_mod, len, tmp, sizeof(tmp)));
471    }
472    else if(cfg.http_full_cfg)
473        { fprintf_conf(f, "rsakey", "\n"); }
474}
475
476static void flags_fn(const char *token, char *value, void *setting, long flag, FILE *f)
477{
478    uint32_t *var = setting;
479    if(value)
480    {
481        int i = atoi(value);
482        if(!i && (*var & flag))
483            { *var -= flag; }
484        if(i)
485            { *var |= flag; }
486        return;
487    }
488    if((*var & flag) || cfg.http_full_cfg)
489        { fprintf_conf(f, token, "%d\n", (*var & flag) ? 1 : 0); }
490}
491
492static void ins7E_fn(const char *token, char *value, void *setting, long var_size, FILE *f)
493{
494    uint8_t *var = setting;
495    var_size -= 1; // var_size contains sizeof(var) which is [X + 1]
496    if(value)
497    {
498        int32_t len = strlen(value);
499        if(len != var_size * 2 || key_atob_l(value, var, len))
500        {
501            if(len > 0)
502                { fprintf(stderr, "reader %s parse error, %s=%s\n", token, token, value); }
503            memset(var, 0, var_size + 1);
504        }
505        else
506        {
507            var[var_size] = 1; // found and correct
508        }
509        return;
510    }
511    if(var[var_size])
512    {
513        char tmp[var_size * 2 + 1];
514        fprintf_conf(f, token, "%s\n", cs_hexdump(0, var, var_size, tmp, sizeof(tmp)));
515    }
516    else if(cfg.http_full_cfg)
517        { fprintf_conf(f, token, "\n"); }
518}
519
520static void atr_fn(const char *token, char *value, void *setting, FILE *f)
521{
522    struct s_reader *rdr = setting;
523    if(value)
524    {
525        memset(rdr->atr, 0, sizeof(rdr->atr));
526        rdr->atrlen = strlen(value);
527        if(rdr->atrlen)
528        {
529            if(rdr->atrlen > (int32_t)sizeof(rdr->atr) * 2)
530                { rdr->atrlen = (int32_t)sizeof(rdr->atr) * 2; }
531            key_atob_l(value, rdr->atr, rdr->atrlen);
532        }
533        return;
534    }
535    if(rdr->atr[0] || cfg.http_full_cfg)
536    {
537        int j;
538        fprintf_conf(f, token, "%s", ""); // it should not have \n at the end
539        if(rdr->atr[0])
540        {
541            for(j = 0; j < rdr->atrlen / 2; j++)
542            {
543                fprintf(f, "%02X", rdr->atr[j]);
544            }
545        }
546        fprintf(f, "\n");
547    }
548}
549
550static void detect_fn(const char *token, char *value, void *setting, FILE *f)
551{
552    struct s_reader *rdr = setting;
553    if(value)
554    {
555        int i;
556        for(i = 0; RDR_CD_TXT[i]; i++)
557        {
558            if(!strcmp(value, RDR_CD_TXT[i]))
559            {
560                rdr->detect = i;
561            }
562            else
563            {
564                if(value[0] == '!' && streq(value + 1, RDR_CD_TXT[i]))
565                    { rdr->detect = i | 0x80; }
566            }
567        }
568        return;
569    }
570    fprintf_conf(f, token, "%s%s\n", rdr->detect & 0x80 ? "!" : "", RDR_CD_TXT[rdr->detect & 0x7f]);
571}
572
573void ftab_fn(const char *token, char *value, void *setting, long ftab_type, FILE *f)
574{
575    const char *zType = NULL, *zName = NULL, *zFiltNamef = NULL;
576    struct s_reader *rdr = NULL;
577    FTAB *ftab = setting;
578
579    if(ftab_type & FTAB_ACCOUNT)
580    {
581        struct s_auth *account = NULL;
582        zType = "account";
583        if(ftab_type & FTAB_PROVID) { account = container_of(setting, struct s_auth, ftab); }
584        if(ftab_type & FTAB_CHID)   { account = container_of(setting, struct s_auth, fchid); }
585        if(account) { zName = account->usr; }
586    }
587    if(ftab_type & FTAB_READER)
588    {
589        zType = "reader";
590        if(ftab_type & FTAB_PROVID)  { rdr = container_of(setting, struct s_reader, ftab); }
591        if(ftab_type & FTAB_CHID)    { rdr = container_of(setting, struct s_reader, fchid); }
592        if(ftab_type & FTAB_FBPCAID) { rdr = container_of(setting, struct s_reader, fallback_percaid); }
593        if(rdr) { zName = rdr->label; }
594    }
595    if(ftab_type & FTAB_PROVID) { zFiltNamef = "provid"; }
596    if(ftab_type & FTAB_CHID)   { zFiltNamef = "chid"; }
597    if(ftab_type & FTAB_FBPCAID) { zFiltNamef = "fallback_percaid"; }
598
599    if(value)
600    {
601        if(strlen(value))
602        {
603            strtolower(value);
604            chk_ftab(value, ftab, zType, zName, zFiltNamef);
605        }
606        else
607        {
608            clear_ftab(ftab);
609        }
610        if(rdr)
611            { rdr->changes_since_shareupdate = 1; }
612        return;
613    }
614    value = mk_t_ftab(ftab);
615    if(strlen(value) > 0 || cfg.http_full_cfg)
616        { fprintf_conf(f, token, "%s\n", value); }
617    free_mk_t(value);
618}
619
620static void aeskeys_fn(const char *token, char *value, void *setting, FILE *f)
621{
622    struct s_reader *rdr = setting;
623    if(value)
624    {
625        parse_aes_keys(rdr, value);
626        return;
627    }
628    value = mk_t_aeskeys(rdr);
629    if(strlen(value) > 0 || cfg.http_full_cfg)
630        { fprintf_conf(f, token, "%s\n", value); }
631    free_mk_t(value);
632}
633
634static void emmcache_fn(const char *token, char *value, void *setting, FILE *f)
635{
636    struct s_reader *rdr = setting;
637    if(value)
638    {
639        rdr->cachemm   = 0;
640        rdr->rewritemm = 0;
641        rdr->logemm    = 0;
642        if(strlen(value))
643        {
644            int i;
645            char *ptr, *saveptr1 = NULL;
646            for(i = 0, ptr = strtok_r(value, ",", &saveptr1); (i < 3) && (ptr); ptr = strtok_r(NULL, ",", &saveptr1), i++)
647            {
648                switch(i)
649                {
650                case 0:
651                    rdr->cachemm = atoi(ptr);
652                    break;
653                case 1:
654                    rdr->rewritemm = atoi(ptr);
655                    break;
656                case 2:
657                    rdr->logemm = atoi(ptr);
658                    break;
659                }
660            }
661            if(rdr->rewritemm <= 0)
662            {
663                fprintf(stderr, "Setting reader \"emmcache\" to %i,%d,%i instead of %i,%i,%i.",
664                        rdr->cachemm, 1, rdr->logemm,
665                        rdr->cachemm, rdr->rewritemm, rdr->logemm);
666                fprintf(stderr, "Zero or negative number of rewrites is silly\n");
667                rdr->rewritemm = 1;
668            }
669        }
670        return;
671    }
672    if(rdr->cachemm || cfg.http_full_cfg)
673        { fprintf_conf(f, token, "%d,%d,%d\n", rdr->cachemm, rdr->rewritemm, rdr->logemm); }
674}
675
676static void blockemm_bylen_fn(const char *token, char *value, void *setting, FILE *f)
677{
678    struct s_reader *rdr = setting;
679    if(value)
680    {
681        char *ptr, *saveptr1 = NULL, dash;
682        struct s_emmlen_range *blocklen;
683        uint32_t num;
684
685        if(!strlen(value))
686        {
687            if(rdr->blockemmbylen)
688            {
689                ll_destroy_data(rdr->blockemmbylen);
690                rdr->blockemmbylen = NULL;
691            }
692            return;
693        }
694
695        if(!rdr->blockemmbylen)
696            { rdr->blockemmbylen = ll_create("blockemmbylen"); }
697        else
698            { ll_clear_data(rdr->blockemmbylen); }
699
700        for(ptr = strtok_r(value, ",", &saveptr1); ptr;
701                ptr = strtok_r(NULL, ",", &saveptr1))
702        {
703            if(!cs_malloc(&blocklen, sizeof(*blocklen)))
704                { return; }
705            num = sscanf(ptr, "%hd%c%hd", &blocklen->min, &dash, &blocklen->max);
706            if(num <= 0)
707            {
708                NULLFREE(blocklen);
709                fprintf(stderr, "blockemm-bylen parse error: %s\n", value);
710                continue;
711            }
712            if(num == 1)  // single values: x1,x2,x3,...
713                { blocklen->max = blocklen->min; }
714            else if(num == 2)  // range values with open end: x1-
715                { blocklen->max = 0; }
716            ll_append(rdr->blockemmbylen, blocklen);
717        }
718        return;
719    }
720    value = mk_t_emmbylen(rdr);
721    if(strlen(value) > 0 || cfg.http_full_cfg)
722        { fprintf_conf(f, token, "%s\n", value); }
723    free_mk_t(value);
724}
725
726static void nano_fn(const char *token, char *value, void *setting, FILE *f)
727{
728    uint16_t *nano = setting;
729    if(value)
730    {
731        *nano = 0;
732        if(strlen(value) > 0)
733        {
734            if(streq(value, "all"))
735            {
736                *nano = 0xFFFF;
737            }
738            else
739            {
740                int32_t i;
741                char *ptr, *saveptr1 = NULL;
742                for(ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
743                {
744                    i = (byte_atob(ptr) % 0x80);
745                    if(i >= 0 && i <= 16)
746                        { *nano |= (1 << i); }
747                }
748            }
749        }
750        return;
751    }
752    value = mk_t_nano(*nano);
753    if(strlen(value) > 0 || cfg.http_full_cfg)
754        { fprintf_conf(f, token, "%s\n", value); }
755    free_mk_t(value);
756}
757
758static void auprovid_fn(const char *token, char *value, void *setting, FILE *f)
759{
760    struct s_reader *rdr = setting;
761    if(value)
762    {
763        rdr->auprovid = 0;
764        if(strlen(value))
765            { rdr->auprovid = a2i(value, 3); }
766        return;
767    }
768    if(rdr->auprovid)
769        { fprintf_conf(f, token, "%06X\n", rdr->auprovid); }
770    else if(cfg.http_full_cfg)
771        { fprintf_conf(f, token, "\n"); }
772}
773
774static void ratelimitecm_fn(const char *token, char *value, void *setting, FILE *f)
775{
776    struct s_reader *rdr = setting;
777    if(value)
778    {
779        rdr->ratelimitecm = 0;
780        if(strlen(value))
781        {
782            int i;
783            rdr->ratelimitecm = atoi(value);
784            for(i = 0; i < MAXECMRATELIMIT; i++)    // reset all slots
785            {
786                rdr->rlecmh[i].srvid = -1;
787                rdr->rlecmh[i].last.time = -1;
788            }
789        }
790        return;
791    }
792    if(rdr->ratelimitecm || cfg.http_full_cfg)
793        { fprintf_conf(f, token, "%d\n", rdr->ratelimitecm); }
794}
795
796static void ratelimittime_fn(const char *token, char *value, void *setting, FILE *f)
797{
798    struct s_reader *rdr = setting;
799    if(value)
800    {
801        if(strlen(value) == 0)
802        {
803            if(rdr->ratelimitecm > 0)
804            {
805                rdr->ratelimittime = 9000; // default 9 seconds
806                rdr->srvidholdtime = 2000; // default 2 seconds hold
807            }
808            else
809            {
810                rdr->ratelimitecm = 0; // in case someone set a negative value
811                rdr->ratelimittime = 0;
812                rdr->srvidholdtime = 0;
813            }
814        }
815        else
816        {
817            rdr->ratelimittime = atoi(value);
818            if (rdr->ratelimittime < 60) rdr->ratelimittime *=1000;
819        }
820        return;
821    }
822    if(rdr->ratelimitecm || cfg.http_full_cfg)
823        { fprintf_conf(f, token, "%d\n", rdr->ratelimittime); }
824}
825static void srvidholdtime_fn(const char *token, char *value, void *setting, FILE *f)
826{
827    struct s_reader *rdr = setting;
828    if(value)
829    {
830        if(strlen(value) == 0)
831        {
832            if(rdr->ratelimitecm > 0)
833            {
834                rdr->srvidholdtime = 2000; // default 2 seconds hold
835            }
836            else
837            {
838                rdr->ratelimitecm = 0; // in case someone set a negative value
839                rdr->srvidholdtime = 0;
840            }
841        }
842        else
843        {
844            rdr->srvidholdtime = atoi(value);
845            if (rdr->srvidholdtime < 60) rdr->srvidholdtime *=1000;
846        }
847        return;
848    }
849    if(rdr->ratelimitecm || cfg.http_full_cfg)
850        { fprintf_conf(f, token, "%d\n", rdr->srvidholdtime); }
851}
852
853static void cooldown_fn(const char *token, char *value, void *setting, FILE *f)
854{
855    struct s_reader *rdr = setting;
856    if(value)
857    {
858        if(strlen(value) == 0)
859        {
860            rdr->cooldown[0] = 0;
861            rdr->cooldown[1] = 0;
862        }
863        else
864        {
865            int32_t i;
866            char *ptr, *saveptr1 = NULL;
867            for(i = 0, ptr = strtok_r(value, ",", &saveptr1); (i < 2) && (ptr); ptr = strtok_r(NULL, ",", &saveptr1), i++)
868            {
869                rdr->cooldown[i] = atoi(ptr);
870            }
871            if(rdr->cooldown[0] <= 0 || rdr->cooldown[1] <= 0)
872            {
873                fprintf(stderr, "cooldown must have 2 positive values (x,y) set values %d,%d ! cooldown deactivated\n",
874                        rdr->cooldown[0], rdr->cooldown[1]);
875                rdr->cooldown[0] = 0;
876                rdr->cooldown[1] = 0;
877            }
878        }
879        return;
880    }
881    if(rdr->cooldown[0] || cfg.http_full_cfg)
882    {
883        fprintf_conf(f, token, "%d,%d\n", rdr->cooldown[0], rdr->cooldown[1]);
884    }
885}
886
887static void cooldowndelay_fn(const char *UNUSED(token), char *value, void *setting, FILE *UNUSED(f))
888{
889    struct s_reader *rdr = setting;
890    if(value)
891    {
892        rdr->cooldown[0] = strlen(value) ? atoi(value) : 0;
893    }
894    // This option is *not* written in the config file.
895    // It is only set by WebIf as convenience
896}
897
898static void cooldowntime_fn(const char *UNUSED(token), char *value, void *setting, FILE *UNUSED(f))
899{
900    struct s_reader *rdr = setting;
901    if(value)
902    {
903        if(strlen(value) == 0)
904        {
905            rdr->cooldown[0] = 0; // no cooling down time means no cooling set
906            rdr->cooldown[1] = 0;
907        }
908        else
909        {
910            rdr->cooldown[1] = atoi(value);
911        }
912        return;
913    }
914    // This option is *not* written in the config file.
915    // It is only set by WebIf as convenience
916}
917
918
919static void reader_fixups_fn(void *var)
920{
921    struct s_reader *rdr = var;
922#ifdef WITH_LB
923    if(rdr->lb_weight > 1000)
924        { rdr->lb_weight = 1000; }
925    else if(rdr->lb_weight <= 0)
926        { rdr->lb_weight = 100; }
927#endif
928
929    if(is_cascading_reader(rdr) && (rdr->typ == R_CAMD35 || rdr->typ == R_CS378X))
930    {
931#ifdef CS_CACHEEX
932        if(rdr && rdr->cacheex.mode>1)
933            { rdr->keepalive = 1; }   //with cacheex, it is required!
934#endif
935        if(rdr->keepalive)
936            { rdr->tcp_rto = 60; }    //we cannot check on rto before send keepalive (each 30s), so set rto > 30
937    }
938}
939
940
941#define OFS(X) offsetof(struct s_reader, X)
942#define SIZEOF(X) sizeof(((struct s_reader *)0)->X)
943
944static const struct config_list reader_opts[] =
945{
946    DEF_OPT_FIXUP_FUNC(reader_fixups_fn),
947    DEF_OPT_FUNC("label"                , 0,                            reader_label_fn),
948#ifdef WEBIF
949    DEF_OPT_STR("description"           , OFS(description),             NULL),
950#endif
951    DEF_OPT_INT8("enable"               , OFS(enable),                  1),
952    DEF_OPT_FUNC("protocol"             , 0,                            protocol_fn),
953    DEF_OPT_FUNC("device"               , 0,                            device_fn),
954    DEF_OPT_HEX("key"                   , OFS(ncd_key),                 SIZEOF(ncd_key)),
955    DEF_OPT_SSTR("user"                 , OFS(r_usr),                   "", SIZEOF(r_usr)),
956    DEF_OPT_SSTR("password"             , OFS(r_pwd),                   "", SIZEOF(r_pwd)),
957    DEF_OPT_SSTR("pincode"              , OFS(pincode),                 "none", SIZEOF(pincode)),
958#ifdef MODULE_GBOX
959    DEF_OPT_INT8("gbox_max_distance"    , OFS(gbox_maxdist),            DEFAULT_GBOX_MAX_DIST),
960    DEF_OPT_INT8("gbox_max_ecm_send"    , OFS(gbox_maxecmsend),         DEFAULT_GBOX_MAX_ECM_SEND),
961    DEF_OPT_INT8("gbox_reshare"         , OFS(gbox_reshare),            0),
962#endif
963    DEF_OPT_STR("readnano"              , OFS(emmfile),                 NULL),
964    DEF_OPT_FUNC("services"             , OFS(sidtabs),                 reader_services_fn),
965    DEF_OPT_FUNC("lb_whitelist_services"    , OFS(lb_sidtabs),              reader_lb_services_fn),
966    DEF_OPT_INT32("inactivitytimeout"   , OFS(tcp_ito),                 DEFAULT_INACTIVITYTIMEOUT),
967    DEF_OPT_INT32("reconnecttimeout"    , OFS(tcp_rto),                 DEFAULT_TCP_RECONNECT_TIMEOUT),
968    DEF_OPT_INT32("reconnectdelay"      , OFS(tcp_reconnect_delay),     60000),
969    DEF_OPT_INT32("resetcycle"          , OFS(resetcycle),              0),
970    DEF_OPT_INT8("disableserverfilter"  , OFS(ncd_disable_server_filt), 0),
971    DEF_OPT_INT8("connectoninit"        , OFS(ncd_connect_on_init),     0),
972    DEF_OPT_INT8("keepalive"            , OFS(keepalive),               0),
973    DEF_OPT_INT8("smargopatch"          , OFS(smargopatch),             0),
974    DEF_OPT_INT8("autospeed"            , OFS(autospeed),               1),
975    DEF_OPT_UINT8("sc8in1_dtrrts_patch" , OFS(sc8in1_dtrrts_patch),     0),
976    DEF_OPT_INT8("fallback"             , OFS(fallback),                0),
977    DEF_OPT_FUNC_X("fallback_percaid"   , OFS(fallback_percaid),        ftab_fn, FTAB_READER | FTAB_FBPCAID),
978#ifdef CS_CACHEEX
979    DEF_OPT_INT8("cacheex"              , OFS(cacheex.mode),            0),
980    DEF_OPT_INT8("cacheex_maxhop"       , OFS(cacheex.maxhop),          0),
981    DEF_OPT_FUNC("cacheex_ecm_filter"       , OFS(cacheex.filter_caidtab),  cacheex_hitvaluetab_fn),
982    DEF_OPT_UINT8("cacheex_allow_request"   , OFS(cacheex.allow_request),   0),
983    DEF_OPT_UINT8("cacheex_drop_csp"        , OFS(cacheex.drop_csp),        0),
984#endif
985    DEF_OPT_FUNC("caid"                 , OFS(ctab),                    reader_caid_fn),
986    DEF_OPT_FUNC("atr"                  , 0,                            atr_fn),
987    DEF_OPT_FUNC("boxid"                , 0,                            boxid_fn),
988    DEF_OPT_HEX("boxkey"                , OFS(boxkey),                  SIZEOF(boxkey)),
989    DEF_OPT_FUNC("rsakey"               , 0,                            rsakey_fn),
990    DEF_OPT_FUNC_X("ins7e"              , OFS(ins7E),                   ins7E_fn, SIZEOF(ins7E)),
991    DEF_OPT_FUNC_X("ins7e11"            , OFS(ins7E11),                 ins7E_fn, SIZEOF(ins7E11)),
992    DEF_OPT_INT8("fix9993"              , OFS(fix_9993),                0),
993    DEF_OPT_INT8("force_irdeto"         , OFS(force_irdeto),            0),
994    DEF_OPT_INT8("needsemmfirst"        , OFS(needsemmfirst),           0),
995    DEF_OPT_UINT32("ecmnotfoundlimit"   , OFS(ecmnotfoundlimit),        0),
996    DEF_OPT_FUNC("ecmwhitelist"         , 0,                            ecmwhitelist_fn),
997    DEF_OPT_FUNC("ecmheaderwhitelist"   , 0,                            ecmheaderwhitelist_fn),
998    DEF_OPT_FUNC("detect"               , 0,                            detect_fn),
999    DEF_OPT_INT8("nagra_read"           , OFS(nagra_read),              0),
1000    DEF_OPT_INT32("mhz"                 , OFS(mhz),                     357),
1001    DEF_OPT_INT32("cardmhz"             , OFS(cardmhz),                 357),
1002#ifdef WITH_AZBOX
1003    DEF_OPT_INT32("mode"                , OFS(azbox_mode),              -1),
1004#endif
1005    DEF_OPT_FUNC_X("ident"              , OFS(ftab),                    ftab_fn, FTAB_READER | FTAB_PROVID),
1006    DEF_OPT_FUNC_X("chid"               , OFS(fchid),                   ftab_fn, FTAB_READER | FTAB_CHID),
1007    DEF_OPT_FUNC("class"                , OFS(cltab),                   class_fn),
1008    DEF_OPT_FUNC("aeskeys"              , 0,                            aeskeys_fn),
1009    DEF_OPT_FUNC("group"                , OFS(grp),                     group_fn),
1010    DEF_OPT_FUNC("emmcache"             , 0,                            emmcache_fn),
1011    DEF_OPT_FUNC_X("blockemm-unknown"   , OFS(blockemm),                flags_fn, EMM_UNKNOWN),
1012    DEF_OPT_FUNC_X("blockemm-u"         , OFS(blockemm),                flags_fn, EMM_UNIQUE),
1013    DEF_OPT_FUNC_X("blockemm-s"         , OFS(blockemm),                flags_fn, EMM_SHARED),
1014    DEF_OPT_FUNC_X("blockemm-g"         , OFS(blockemm),                flags_fn, EMM_GLOBAL),
1015    DEF_OPT_FUNC_X("saveemm-unknown"    , OFS(saveemm),                 flags_fn, EMM_UNKNOWN),
1016    DEF_OPT_FUNC_X("saveemm-u"          , OFS(saveemm),                 flags_fn, EMM_UNIQUE),
1017    DEF_OPT_FUNC_X("saveemm-s"          , OFS(saveemm),                 flags_fn, EMM_SHARED),
1018    DEF_OPT_FUNC_X("saveemm-g"          , OFS(saveemm),                 flags_fn, EMM_GLOBAL),
1019    DEF_OPT_FUNC("blockemm-bylen"       , 0,                            blockemm_bylen_fn),
1020#ifdef WITH_LB
1021    DEF_OPT_INT32("lb_weight"           , OFS(lb_weight),               100),
1022#endif
1023    DEF_OPT_FUNC("savenano"             , OFS(s_nano),                  nano_fn),
1024    DEF_OPT_FUNC("blocknano"            , OFS(b_nano),                  nano_fn),
1025    DEF_OPT_INT8("dropbadcws"           , OFS(dropbadcws),              0),
1026    DEF_OPT_INT8("disablecrccws"        , OFS(disablecrccws),           0),
1027    DEF_OPT_INT32("use_gpio"            , OFS(use_gpio),                0),
1028#ifdef MODULE_PANDORA
1029    DEF_OPT_UINT8("pand_send_ecm"       , OFS(pand_send_ecm),           0),
1030#endif
1031#ifdef MODULE_CCCAM
1032    DEF_OPT_SSTR("cccversion"           , OFS(cc_version),              "", SIZEOF(cc_version)),
1033    DEF_OPT_INT8("cccmaxhops"           , OFS(cc_maxhops),              DEFAULT_CC_MAXHOPS),
1034    DEF_OPT_INT8("cccmindown"           , OFS(cc_mindown),              0),
1035    DEF_OPT_INT8("cccwantemu"           , OFS(cc_want_emu),             0),
1036    DEF_OPT_INT8("ccckeepalive"         , OFS(cc_keepalive),            DEFAULT_CC_KEEPALIVE),
1037    DEF_OPT_INT8("cccreshare"           , OFS(cc_reshare),              DEFAULT_CC_RESHARE),
1038    DEF_OPT_INT32("cccreconnect"        , OFS(cc_reconnect),            DEFAULT_CC_RECONNECT),
1039    DEF_OPT_INT8("ccchop"               , OFS(cc_hop),                  0),
1040#endif
1041#ifdef MODULE_GHTTP
1042    DEF_OPT_UINT8("use_ssl"             , OFS(ghttp_use_ssl),           0),
1043#endif
1044    DEF_OPT_INT8("deprecated"           , OFS(deprecated),              0),
1045    DEF_OPT_INT8("audisabled"           , OFS(audisabled),              0),
1046    DEF_OPT_FUNC("auprovid"             , 0,                            auprovid_fn),
1047    DEF_OPT_INT8("ndsversion"           , OFS(ndsversion),              0),
1048    DEF_OPT_FUNC("ratelimitecm"         , 0,                            ratelimitecm_fn),
1049    DEF_OPT_FUNC("ratelimittime"        , 0,                            ratelimittime_fn),
1050    DEF_OPT_INT8("ecmunique"            , OFS(ecmunique),               0),
1051    DEF_OPT_FUNC("srvidholdtime"        , 0,                            srvidholdtime_fn),
1052    DEF_OPT_FUNC("cooldown"             , 0,                            cooldown_fn),
1053    DEF_OPT_FUNC("cooldowndelay"        , 0,                            cooldowndelay_fn),
1054    DEF_OPT_FUNC("cooldowntime"         , 0,                            cooldowntime_fn),
1055    DEF_LAST_OPT
1056};
1057
1058static inline bool in_list(const char *token, const char *list[])
1059{
1060    int i;
1061    for(i = 0; list[i]; i++)
1062    {
1063        if(streq(token, list[i]))
1064            { return true; }
1065    }
1066    return false;
1067}
1068
1069static bool reader_check_setting(const struct config_list *UNUSED(clist), void *config_data, const char *setting)
1070{
1071    struct s_reader *reader = config_data;
1072    // These are written only when the reader is physical reader
1073    static const char *hw_only_settings[] =
1074    {
1075        "readnano", "resetcycle", "smargopatch", "autospeed", "sc8in1_dtrrts_patch", "boxid",
1076        "fix9993", "rsakey", "ins7e", "ins7e11", "force_irdeto", "needsemmfirst", "boxkey",
1077        "atr", "detect", "nagra_read", "mhz", "cardmhz",
1078#ifdef WITH_AZBOX
1079        "mode",
1080#endif
1081        "deprecated", "ndsversion",
1082        0
1083    };
1084    // These are written only when the reader is network reader
1085    static const char *network_only_settings[] =
1086    {
1087        "user", "inactivitytimeout", "reconnecttimeout",
1088        0
1089    };
1090    if(is_network_reader(reader))
1091    {
1092        if(in_list(setting, hw_only_settings))
1093            { return false; }
1094    }
1095    else
1096    {
1097        if(in_list(setting, network_only_settings))
1098            { return false; }
1099    }
1100
1101    // These are not written in the config file
1102    static const char *deprecated_settings[] =
1103    {
1104        "cooldowndelay", "cooldowntime", "mg-encrypted",
1105        0
1106    };
1107    if(in_list(setting, deprecated_settings))
1108        { return false; }
1109
1110    // Special settings for NEWCAMD
1111    static const char *newcamd_settings[] =
1112    {
1113        "disableserverfilter", "connectoninit",
1114        0
1115    };
1116    if(reader->typ != R_NEWCAMD && in_list(setting, newcamd_settings))
1117        { return false; }
1118
1119#ifdef MODULE_CCCAM
1120    // These are written only when the reader is CCCAM
1121    static const char *cccam_settings[] =
1122    {
1123        "cccversion", "cccmaxhops", "cccmindown", "cccwantemu", "ccckeepalive",
1124        "cccreconnect",
1125        0
1126    };
1127    // Special settings for CCCAM
1128    if(reader->typ != R_CCCAM)
1129    {
1130        if(in_list(setting, cccam_settings))
1131            { return false; }
1132    }
1133    else if(streq(setting, "ccchop"))
1134    {
1135        return false;
1136    }
1137#endif
1138
1139#ifdef MODULE_PANDORA
1140    // Special settings for PANDORA
1141    if(reader->typ != R_PANDORA && streq(setting, "pand_send_ecm"))
1142        { return false; }
1143#endif
1144
1145    return true; // Write the setting
1146}
1147
1148
1149void chk_reader(char *token, char *value, struct s_reader *rdr)
1150{
1151    if(config_list_parse(reader_opts, token, value, rdr))
1152        { return; }
1153    else if(token[0] != '#')
1154        { fprintf(stderr, "Warning: keyword '%s' in reader section not recognized\n", token); }
1155}
1156
1157void reader_set_defaults(struct s_reader *rdr)
1158{
1159    config_list_set_defaults(reader_opts, rdr);
1160}
1161
1162int32_t init_readerdb(void)
1163{
1164    configured_readers = ll_create("configured_readers");
1165
1166    FILE *fp = open_config_file(cs_srvr);
1167    if(!fp)
1168        { return 1; }
1169
1170    int32_t tag = 0;
1171    char *value, *token;
1172
1173    if(!cs_malloc(&token, MAXLINESIZE))
1174        { return 1; }
1175
1176    struct s_reader *rdr;
1177    if(!cs_malloc(&rdr, sizeof(struct s_reader)))
1178    {
1179        NULLFREE(token);
1180        return 1;
1181    }
1182
1183    ll_append(configured_readers, rdr);
1184    while(fgets(token, MAXLINESIZE, fp))
1185    {
1186        int32_t l;
1187        if((l = strlen(trim(token))) < 3)
1188            { continue; }
1189        if((token[0] == '[') && (token[l - 1] == ']'))
1190        {
1191            token[l - 1] = 0;
1192            tag = (!strcmp("reader", strtolower(token + 1)));
1193            if(rdr->label[0] && rdr->typ)
1194            {
1195                struct s_reader *newreader;
1196                if(cs_malloc(&newreader, sizeof(struct s_reader)))
1197                {
1198                    ll_append(configured_readers, newreader);
1199                    rdr = newreader;
1200                }
1201            }
1202            reader_set_defaults(rdr);
1203            continue;
1204        }
1205
1206        if(!tag)
1207            { continue; }
1208        if(!(value = strchr(token, '=')))
1209            { continue; }
1210        *value++ = '\0';
1211        chk_reader(trim(strtolower(token)), trim(value), rdr);
1212    }
1213    NULLFREE(token);
1214    LL_ITER itr = ll_iter_create(configured_readers);
1215    while((rdr = ll_iter_next(&itr)))   //build active readers list
1216    {
1217        reader_fixups_fn(rdr);
1218        module_reader_set(rdr);
1219    }
1220    fclose(fp);
1221    return (0);
1222}
1223
1224void free_reader(struct s_reader *rdr)
1225{
1226    NULLFREE(rdr->emmfile);
1227
1228    struct s_ecmWhitelist *tmp;
1229    struct s_ecmWhitelistIdent *tmpIdent;
1230    struct s_ecmWhitelistLen *tmpLen;
1231    for(tmp = rdr->ecmWhitelist; tmp; tmp = tmp->next)
1232    {
1233        for(tmpIdent = tmp->idents; tmpIdent; tmpIdent = tmpIdent->next)
1234        {
1235            for(tmpLen = tmpIdent->lengths; tmpLen; tmpLen = tmpLen->next)
1236            {
1237                add_garbage(tmpLen);
1238            }
1239            add_garbage(tmpIdent);
1240        }
1241        add_garbage(tmp);
1242    }
1243    rdr->ecmWhitelist = NULL;
1244
1245    struct s_ecmHeaderwhitelist *tmp1;
1246    for(tmp1 = rdr->ecmHeaderwhitelist; tmp1; tmp1 = tmp1->next)
1247    {
1248        add_garbage(tmp1);
1249    }
1250    rdr->ecmHeaderwhitelist = NULL;
1251
1252    clear_ftab(&rdr->ftab);
1253
1254#ifdef WITH_LB
1255    if(rdr->lb_stat)
1256    {
1257        cs_lock_destroy(&rdr->lb_stat_lock);
1258        ll_destroy_data(rdr->lb_stat);
1259        rdr->lb_stat = NULL;
1260    }
1261
1262#endif
1263    cs_clear_entitlement(rdr);
1264    if(rdr->ll_entitlements)
1265    {
1266        ll_destroy(rdr->ll_entitlements);
1267        rdr->ll_entitlements = NULL;
1268    }
1269    NULLFREE(rdr->csystem_data);
1270
1271    if(rdr->blockemmbylen)
1272    {
1273        ll_destroy_data(rdr->blockemmbylen);
1274        rdr->blockemmbylen = NULL;
1275    }
1276
1277    add_garbage(rdr);
1278}
1279
1280int32_t free_readerdb(void)
1281{
1282    int count = 0;
1283    struct s_reader *rdr;
1284    LL_ITER itr = ll_iter_create(configured_readers);
1285    while((rdr = ll_iter_next(&itr)))
1286    {
1287        free_reader(rdr);
1288        count++;
1289    }
1290    cs_log("readerdb %d readers freed", count);
1291    ll_destroy(configured_readers);
1292    return count;
1293}
1294
1295int32_t write_server(void)
1296{
1297    FILE *f = create_config_file(cs_srvr);
1298    if(!f)
1299        { return 1; }
1300    struct s_reader *rdr;
1301    LL_ITER itr = ll_iter_create(configured_readers);
1302    while((rdr = ll_iter_next(&itr)))
1303    {
1304        if(rdr->label[0])
1305        {
1306            fprintf(f, "[reader]\n");
1307            config_list_apply_fixups(reader_opts, rdr);
1308            config_list_save_ex(f, reader_opts, rdr, cfg.http_full_cfg, reader_check_setting);
1309            fprintf(f, "\n");
1310        }
1311    }
1312    return flush_config_file(f, cs_srvr);
1313}
Note: See TracBrowser for help on using the repository browser.