source: titan/titan/cam.h @ 41283

Last change on this file since 41283 was 41283, checked in by gost, 6 years ago

[titan] hd51 workaround for oscam

File size: 17.0 KB
Line 
1#ifndef CAM_H
2#define CAM_H
3
4void debugcaservice()
5{
6        int i = 0;
7
8        for(i = 0; i < MAXCASERVICE; i++)
9        {
10                if(caservice[i].service != NULL)
11                {
12                        printf("number: %d\n", i);
13                        printf("service: %p\n", caservice[i].service);
14                        if(caservice[i].channel != NULL)
15                                printf("channel: %s\n", caservice[i].channel->name);
16                        printf("camsockfd: %d\n", caservice[i].camsockfd);
17                        printf("caslot: %p\n", caservice[i].caslot);
18                        printf("count: %d\n", caservice[i].count);
19                }
20        }
21}
22
23int getcaservicebyslot(struct caslot* caslot, int flag)
24{
25        int i = 0;
26
27        for(i = 0; i < MAXCASERVICE; i++)
28        {
29                if(caslot == caservice[i].caslot)
30                {
31                        if(flag == 1)
32                        {
33                                if(caservice[i].service != NULL && (caservice[i].service->type == RECORDDIRECT || caservice[i].service->type == RECORDTIMER))
34                                        return i;
35                        }
36                        else
37                                return i;
38                }
39        }
40        return -1;
41}
42
43//flag 0 = from zap
44//flag 1 = from watchthread
45//flag 2 = from cathread / caservicedel
46//flag 3 = from recordthread
47int caserviceadd(struct service* snode, int flag)
48{
49        int i = 0, first = -1;
50
51        if(snode == NULL) return -1;
52
53        for(i = 0; i < MAXCASERVICE; i++)
54        {
55                if(caservice[i].service != NULL && caservice[i].channel == snode->channel)
56                {
57                        if((flag == 0 || flag == 3))
58                        {
59                                caservice[i].service = snode;
60                                caservice[i].count++;
61                                return -1;
62                        }
63                        return i;
64                }
65                if(caservice[i].service == NULL && first == -1)
66                        first = i;
67        }
68
69        if(first != -1)
70        {
71                caservice[first].service = snode;
72                caservice[first].channel = snode->channel;
73                caservice[first].count = 1;
74                caservice[first].camsockfd = -1;
75                if(caservice[first].caslot != NULL && caservice[first].camanager > -1 && caservice[first].caslot->casession[caservice[first].camanager].inuse > 0) caservice[first].caslot->casession[caservice[first].camanager].inuse = 1;
76                caservice[first].caslot = NULL;
77                caservice[first].camanager = -1;
78                free(caservice[first].capmt); caservice[first].capmt = NULL;
79                caservice[first].capmtlen = 0;
80                caservice[first].cmdpos = 0;
81                return first;
82        }
83
84        return -1;
85}
86
87void caservicedel(struct service* snode, struct caslot* caslot)
88{
89        int i = 0;
90
91        for(i = 0; i < MAXCASERVICE; i++)
92        {
93                if(snode != NULL && caservice[i].service != NULL && caservice[i].channel == snode->channel)
94                {
95                        caservice[i].count--;
96                        if(caservice[i].count < 1)
97                        {
98                                if(caservice[i].camsockfd > -1)
99                                        sockclose(&caservice[i].camsockfd);
100                                if(caservice[i].caslot != NULL)
101                                {
102                                        //sendcapmt(caservice[i].service, i + 1, 2);
103                                        if(caservice[i].caslot != NULL && caservice[i].camanager > -1 && caservice[i].caslot->casession[caservice[i].camanager].inuse > 0) caservice[i].caslot->casession[caservice[i].camanager].inuse = 1;
104                                        caservice[i].caslot = NULL;
105                                        caservice[i].camanager = -1;
106                                }
107                                free(caservice[i].capmt); caservice[i].capmt = NULL;
108                                caservice[i].count = 0;
109                                caservice[i].capmtlen = 0;
110                                caservice[i].cmdpos = 0;
111                                caservice[i].service = NULL;
112                                caservice[i].channel = NULL;
113                        }
114                        else
115                                caservice[i].service = getservicebyservice(snode, 1);
116                }
117                //remove cam from slot
118                if(caservice[i].service != NULL && caservice[i].caslot == caslot)
119                {
120                        if(caservice[i].caslot != NULL && caservice[i].camanager > -1 && caservice[i].caslot->casession[caservice[i].camanager].inuse > 0) caservice[i].caslot->casession[caservice[i].camanager].inuse = 1;
121                        caservice[i].caslot = NULL;
122                        caservice[i].camanager = -1;
123                }
124        }
125}
126
127void freecaservice()
128{
129        int i = 0;
130
131        for(i = 0; i < MAXCASERVICE; i++)
132        {
133                free(caservice[i].capmt);
134                caservice[i].capmt = NULL;
135
136                caservice[i].caslot = NULL;
137                caservice[i].camanager = -1;
138                caservice[i].capmtlen = 0;
139                caservice[i].cmdpos = 0;
140                caservice[i].service = NULL;
141                caservice[i].channel = NULL;
142
143                if(caservice[i].camsockfd > -1)
144                        sockclose(&caservice[i].camsockfd);
145        }
146}
147
148void dvbwritepmt(struct service* node, unsigned char* pmtbuf)
149{
150        int length;
151        FILE *fd;
152        char* filename = NULL, *tmpnr = NULL;
153
154        if(node == NULL || pmtbuf == NULL)
155        {
156                debug(1000, "NULL detect");
157                return;
158        }
159
160        if(node->fedev == NULL || (node->fedev != NULL && node->fedev->devnr == 0))
161        {
162                filename = ostrcat(filename, "/tmp/pmt.tmp", 0, 0);
163        }
164        else
165        {
166                tmpnr = oitoa(node->fedev->devnr);
167                filename = ostrcat(filename, "/tmp/pmt", 1, 0);
168                filename = ostrcat(filename, tmpnr, 1, 1);
169                filename = ostrcat(filename, ".tmp", 1, 0);
170        }
171
172        unlink(filename);
173        length =((pmtbuf[1] & 0xf) << 8) + ((pmtbuf[2] + 3) & 0xff);
174        if(filename != NULL)
175        {
176                fd=fopen(filename, "wbt");
177                if(fd != NULL)
178                {
179                        if((int) fwrite(pmtbuf, sizeof(unsigned char), length, fd) != length)
180                                unlink(filename);
181                        else
182                                debug(200, "write %s", filename);
183                        fclose(fd);
184                }
185        }
186        free(filename);
187}
188
189void sendcapmttosock(struct service* node, unsigned char* buf, int pos, int caservicenr)
190{
191        int ret = 0, i = 0;
192
193        if(caservice[caservicenr].camsockfd < 0 || socksend(&caservice[caservicenr].camsockfd, buf, pos, -1) != 0)
194        {
195                ret = sockopen(&caservice[caservicenr].camsockfd, "/tmp/camd.socket", 0, -1);
196                if(ret == 0)
197                        ret = socksend(&caservice[caservicenr].camsockfd, buf, pos, -1);
198        }
199
200        if(ret == 0 && debug_level == 620)
201        {
202                printf("CA-PMT: ");
203                for(i = 0; i < pos; i++)
204                        printf("%02x ", buf[i] & 0xff);
205                printf("\n");
206        }
207}
208
209//flag 0: cam capmt
210//flag 1: emu capmt
211//flag 2: clear capmt
212int createcapmt(struct dvbdev* dvbnode, struct service* node, unsigned char* buf, int* lenbytes, int flag)
213{
214        if(buf == NULL || node == NULL || node->channel == NULL) return -1;
215        if(node->fedev == NULL || node->channel->pmt == NULL) return -1;
216        if(node->channel->cadesc == NULL || node->channel->esinfo == NULL) return -1;
217
218        int pos = 10, i = 0;
219        struct cadesc* cadescnode = node->channel->cadesc;
220        struct esinfo* esinfonode = node->channel->esinfo;
221
222        memset(buf, 0, MINMALLOC);
223
224        buf[0] = 0x9F; // ca_pmt_tag
225        buf[1] = 0x80; // ca_pmt_tag
226        buf[2] = 0x32; // ca_pmt_tag
227
228        buf[pos++] = 0x03; //ca_pmt_lst_management: 0=more, 1=first, 2=last, 3=only, 4=add, 5=update
229        buf[pos++] = node->channel->pmt->programnumber >> 8;
230        buf[pos++] = node->channel->pmt->programnumber & 0xff;
231
232        buf[pos++] = (node->channel->pmt->versionnumber << 1) | node->channel->pmt->currentnextindicator;
233
234        buf[pos++] = 0x00; //len from here (programinfo len)
235        buf[pos++] = 0x00; //len from here (programinfo len)
236        buf[pos++] = 0x01; //ca_pmt_cmd_id: ok_descrambling=1
237
238        if(flag == 1)
239        {
240                buf[pos++] = 0x81; //id (fix)
241                buf[pos++] = 0x08; //len
242                buf[pos++] = 0x00; //namespace >> 24
243                buf[pos++] = 0x00; //(namespace >> 16) & 0xff
244                buf[pos++] = 0x00; //(namespace >> 8) & 0xff
245                buf[pos++] = 0x00; //namespace & 0xff
246                buf[pos++] = 0x00; //transportstreamid >> 8
247                buf[pos++] = 0x00; //transportstreamid & 0xff
248                buf[pos++] = 0x00; //original network id >> 8
249                buf[pos++] = 0x00; //original network id & 0xff
250
251                buf[pos++] = 0x82; //id (fix)
252                buf[pos++] = 0x02; //len
253
254/*
255                while(tmpnode != NULL)
256                {
257                        if(tmpnode->fedev != NULL)
258                        {
259                                //(demuxmask |= (1 << dmxdev->devnr)
260                                buf[pos] |= (1 << tmpnode->fedev->devnr);
261                        }
262                        tmpnode = tmpnode->next;
263                }
264                pos++;
265*/
266                buf[pos++] |= (1 << node->fedev->devnr); //cadev_nr
267                if(checkbox("HD51") == 1)
268                        buf[pos++] |= (1 << node->fedev->devnr); //demux_dev_nr / Workaround wenn 0 dann geht Oscam nicht, warum?????
269                else
270                        buf[pos++] = node->fedev->devnr; //demux_dev_nr
271
272                buf[pos++] = 0x84; //id (fix)
273                buf[pos++] = 0x02; //len
274                buf[pos++] = node->channel->pmtpid >> 8; //pmtpid >> 8
275                buf[pos++] = node->channel->pmtpid & 0xff; //pmtpid & 0xff
276        }
277
278        while(cadescnode != NULL && flag < 2)
279        {
280                //remove caids, cam can't
281                if(flag == 0 && status.casendallcaids == 0)
282                {
283                        char* tmpnr = NULL;
284
285                        if(dvbnode != NULL)
286                        {
287                                tmpnr = oitoa(cadescnode->systemid);
288                                if(ostrstr(dvbnode->caslot->caids, tmpnr) == NULL)
289                                {
290                                        free(tmpnr); tmpnr = NULL;
291                                        cadescnode = cadescnode->next;
292                                        continue;
293                                }
294                                free(tmpnr); tmpnr = NULL;
295                        }
296                }
297
298                if(cadescnode->len > 0 && cadescnode->pid == 0)
299                {
300                        int cadesclen = 0;
301
302                        buf[pos++] = 0x09; //ca desc tag
303                        if(flag == 0 && status.caskipprivat == 1) //workaround for to long capmt
304                        {
305                                buf[pos++] = 4;
306                                cadesclen = cadesclen;
307                        }
308                        else
309                        {
310                                cadesclen = cadescnode->len;
311                                buf[pos++] = cadesclen;
312                        }
313                        buf[pos++] = cadescnode->systemid >> 8;
314                        buf[pos++] = cadescnode->systemid & 0xff;
315                        buf[pos++] = (cadescnode->reserved << 5) | (cadescnode->capid >> 8);
316                        buf[pos++] = cadescnode->capid & 0xff;
317
318                        if(cadesclen > 4)
319                        {
320                                memcpy(&buf[pos], cadescnode->privat, cadesclen - 4);
321                                pos += cadesclen - 4;
322                        }
323                }
324                cadescnode = cadescnode->next;
325        }
326
327        int tmppos = pos;
328
329        while(esinfonode != NULL)
330        {
331                buf[pos++] = esinfonode->streamtype;
332                buf[pos++] = esinfonode->pid >> 8;
333                buf[pos++] = esinfonode->pid & 0xff;
334
335                int eslenpos = pos;
336                int eslen = 0;
337                pos += 2;
338
339                cadescnode = node->channel->cadesc;
340                while(cadescnode != NULL && flag < 2)
341                {
342                        if(cadescnode->len > 0 && cadescnode->pid == esinfonode->pid)
343                        {
344                                //remove caids, cam can't
345                                if(flag == 0 && status.casendallcaids == 0)
346                                {
347                                        char* tmpnr = NULL;
348
349                                        if(dvbnode != NULL)
350                                        {
351                                                tmpnr = oitoa(cadescnode->systemid);
352                                                if(ostrstr(dvbnode->caslot->caids, tmpnr) == NULL)
353                                                {
354                                                        free(tmpnr); tmpnr = NULL;
355                                                        cadescnode = cadescnode->next;
356                                                        continue;
357                                                }
358                                                free(tmpnr); tmpnr = NULL;
359                                        }
360                                }
361
362                                if(eslen == 0)
363                                {
364                                        eslen = 1;
365                                        buf[pos++] = 0x01; //ca_pmt_cmd_id: ok_descrambling=1
366                                }
367                                eslen = eslen + cadescnode->len + 2;
368                                buf[pos++] = 0x09; //ca desc tag
369                                buf[pos++] = cadescnode->len;
370                                buf[pos++] = cadescnode->systemid >> 8;
371                                buf[pos++] = cadescnode->systemid & 0xff;
372                                buf[pos++] = (cadescnode->reserved << 5) | (cadescnode->capid >> 8);
373                                buf[pos++] = cadescnode->capid & 0xff;
374                                if(cadescnode->len > 4)
375                                {
376                                        memcpy(&buf[pos], cadescnode->privat, cadescnode->len - 4);
377                                        pos += cadescnode->len - 4;
378                                }
379                        }
380                        cadescnode = cadescnode->next;
381                }
382
383                buf[eslenpos + 1] = eslen & 0xff;
384                buf[eslenpos] = (eslen >> 8) & 0x0f;
385
386                esinfonode = esinfonode->next;
387        }
388
389        *lenbytes = writelengthfield(&buf[3], pos - 10);
390        for(i = 0; i < pos + 10; i++)
391        {
392                buf[(*lenbytes) + 3 + i] = buf[10 + i];
393        }
394        pos = pos - 10 + (*lenbytes) + 3;
395        tmppos = tmppos - 10 + (*lenbytes) + 3;
396
397        //programinfo len
398        buf[8 + (*lenbytes)] = (tmppos - 9 - (*lenbytes)) & 0xff;
399        buf[7 + (*lenbytes)] = ((tmppos - 9 - (*lenbytes)) >> 8) & 0x0f;
400
401        return pos;
402}
403
404//flag 0 = from zap
405//flag 1 = from watchthread
406//flag 2 = from cathread / caservicedel
407//flag 3 = from recordthread
408void sendcapmt(struct service* node, int clear, int flag)
409{
410        int len = 0, i = 0, caservicenr = 0, lenbytes = 0;
411        unsigned char* buf = NULL;
412        struct dvbdev* dvbnode = dvbdev;
413
414        //check if service should decrypt
415        if(node == NULL)
416        {
417                debug(620, "service empty");
418                return;
419        }
420        if(node->channel == NULL)
421        {
422                debug(620, "channel empty");
423                return;
424        }
425        if(node->fedev == NULL)
426        {
427                debug(620, "no frontend");
428                return;
429        }
430       
431        if(node->channel->crypt == 0)
432        {
433                debug(620, "channel not crypt");
434
435                //check if we can change input sources
436                int doswitch = 1;
437                for(i = 0; i < MAXCASERVICE; i++)
438                {
439                        if(caservice[i].caslot != NULL && caservice[i].service != NULL && caservice[i].service->fedev != NULL)
440                        {
441                                if(caservice[i].service->fedev->devnr == node->fedev->devnr && (caservice[i].service->type == RECORDDIRECT || caservice[i].service->type == RECORDTIMER))
442                                {
443                                        debug(620, "can't change input sources");
444                                        doswitch = 0;
445                                }
446                        }
447                }
448
449                if(doswitch == 1)
450                {
451                        debug(200, "reset routing tuner %d", node->fedev->devnr);
452                        switch(node->fedev->devnr)
453                        {
454                                case 0: setcisource(node->fedev->devnr, "A"); break;
455                                case 1: setcisource(node->fedev->devnr, "B"); break;
456                                case 2: setcisource(node->fedev->devnr, "C"); break;
457                                case 3: setcisource(node->fedev->devnr, "D"); break;
458                        }
459                }
460               
461                return;
462        }
463       
464        if(node->channel->pmt == NULL)
465        {
466                debug(620, "pmt empty");
467                return;
468        }
469        if(node->channel->cadesc == NULL)
470        {
471                debug(620, "cadesc empty");
472                return;
473        }
474        if(node->channel->esinfo == NULL)
475        {
476                debug(620, "esinfo empty");
477                return;
478        }
479        if(node->fedev->type == FRONTENDDEVDUMMY)
480        {
481                debug(620, "dummy frontend not crypt");
482                return;
483        }
484        if(flag != 3 && node->type != CHANNEL && node->type != RECORDDIRECT && node->type != RECORDTIMER && node->type != RECORDTIMESHIFT && node->type != RECORDSTREAM)
485        {
486                debug(620, "service type should not decrypt");
487                return;
488        }
489
490        buf = malloc(MINMALLOC);
491        if(buf == NULL)
492        {
493                err("no mem");
494                return;
495        }
496
497        if(clear == 0)
498        {
499                caservicenr = caserviceadd(node, flag);
500                if(caservicenr < 0)
501                {
502                        debug(620, "service is decrypt");
503                        free(buf);
504                        return;
505                }
506
507                int foundcam = 0;
508
509                while(dvbnode != NULL)
510                {
511                        if(dvbnode->type == CIDEV && dvbnode->fd > -1 && dvbnode->caslot != NULL && dvbnode->caslot->status == 2 && dvbnode->caslot->caids != NULL)
512                        {
513                                if(caservice[caservicenr].caslot == NULL)
514                                {
515                                        lenbytes = 0;
516                                        len = createcapmt(dvbnode, node, buf, &lenbytes, 0);
517                                        if(len > -1)
518                                        {
519                                                if(sendcapmttocam(dvbnode, node, buf, len, caservicenr, lenbytes + 9, clear) == 0)
520                                                {
521                                                        foundcam = 1;
522                                                        break;
523                                                }
524                                        }
525                                }
526                        }
527                        dvbnode = dvbnode->next;
528                }
529
530                if(caservice[caservicenr].camsockfd < 0 && foundcam == 0)
531                {
532                        lenbytes = 0;
533                        len = createcapmt(NULL, node, buf, &lenbytes, 1);
534                        if(len > -1)
535                                sendcapmttosock(node, buf, len, caservicenr);
536                }
537        }
538
539        if(clear > 0)
540        {
541                while(dvbnode != NULL)
542                {
543                        if(dvbnode->type == CIDEV && dvbnode->fd > -1 && dvbnode->caslot != NULL && dvbnode->caslot->status == 2 && dvbnode->caslot->caids != NULL)
544                        {
545                                if(caservice[clear - 1].caslot == dvbnode->caslot)
546                                {
547                                        lenbytes = 0;
548                                        len = createcapmt(dvbnode, node, buf, &lenbytes, 2);
549                                        if(len > -1)
550                                                sendcapmttocam(dvbnode, node, buf, len, caservicenr, lenbytes + 9, clear);
551                                        break;
552                                }
553                        }
554                        dvbnode = dvbnode->next;
555                }
556        }
557
558        free(buf);
559}
560
561void checkcam()
562{
563        int i = 0;
564        if(status.pmtmode == 1) return;
565
566        //struct can change from another thread
567        m_lock(&status.servicemutex, 2);
568        for(i = 0; i < MAXCASERVICE; i++)
569        {
570                if(caservice[i].service != NULL)
571                {
572                        sockcheck(&caservice[i].camsockfd);
573                        if((caservice[i].camsockfd < 0 && caservice[i].camanager == -1) || caservice[i].caslot == NULL)
574                                sendcapmt(caservice[i].service, 0, 1);
575                }
576        }
577        m_unlock(&status.servicemutex, 2);
578}
579
580struct pmt* addpmt(struct channel* chnode, int programnumber, int versionnumber, int currentnextindicator)
581{
582        struct pmt *newnode = NULL;
583
584        if(chnode == NULL)
585        {
586                err("NULL detect");
587                return NULL;
588        }
589
590        newnode = (struct pmt*)malloc(sizeof(struct pmt));     
591        if(newnode == NULL)
592        {
593                err("no memory");
594                return NULL;
595        }
596
597        memset(newnode, 0, sizeof(struct pmt));
598
599        newnode->programnumber = programnumber;
600        newnode->versionnumber = versionnumber;
601        newnode->currentnextindicator = currentnextindicator;
602
603        chnode->pmt = newnode;
604
605        return newnode;
606}
607
608struct cadesc* addcadesc(struct channel* chnode, int pid, unsigned char* buf, struct cadesc* last)
609{
610        struct cadesc *newnode = NULL, *prev = NULL, *node = NULL;
611
612        if(chnode == NULL || buf == NULL)
613        {
614                err("NULL detect");
615                return NULL;
616        }
617
618        node = chnode->cadesc;
619
620        newnode = (struct cadesc*)malloc(sizeof(struct cadesc));       
621        if(newnode == NULL)
622        {
623                err("no memory");
624                return NULL;
625        }
626
627        memset(newnode, 0, sizeof(struct cadesc));
628
629        newnode->pid = pid;
630        newnode->len = buf[1];
631        newnode->systemid = (buf[2] << 8) | buf[3];
632        newnode->reserved = buf[4] >> 5;
633        newnode->capid = ((buf[4] & 0x1F) << 8) | buf[5];
634
635        if(newnode->len > 4)
636        {
637                newnode->privat = malloc(newnode->len - 4);
638                if(newnode->privat == NULL)
639                {
640                        err("no mem");
641                }
642                else
643                        memcpy(newnode->privat, &buf[6], newnode->len - 4);
644        }
645
646        if(last == NULL)
647        {
648                while(node != NULL)
649                {
650                        prev = node;
651                        node = node->next;
652                }
653        }
654        else
655        {
656                prev = last;
657                node = last->next;
658        }
659
660        if(prev == NULL)
661                chnode->cadesc = newnode;
662        else
663                prev->next = newnode;
664
665        newnode->next = node;
666
667        return newnode;
668}
669
670struct esinfo* addesinfo(struct channel* chnode, int streamtype, int pid, struct esinfo* last)
671{
672        struct esinfo *newnode = NULL, *prev = NULL, *node = NULL;
673
674        if(chnode == NULL)
675        {
676                err("NULL detect");
677                return NULL;
678        }
679
680        node = chnode->esinfo;
681
682        newnode = (struct esinfo*)malloc(sizeof(struct esinfo));       
683        if(newnode == NULL)
684        {
685                err("no memory");
686                return NULL;
687        }
688
689        memset(newnode, 0, sizeof(struct esinfo));
690
691        newnode->streamtype = streamtype;
692        newnode->pid = pid;
693
694        if(last == NULL)
695        {
696                while(node != NULL)
697                {
698                        prev = node;
699                        node = node->next;
700                }
701        }
702        else
703        {
704                prev = last;
705                node = last->next;
706        }
707
708        if(prev == NULL)
709                chnode->esinfo = newnode;
710        else
711                prev->next = newnode;
712
713        newnode->next = node;
714
715        return newnode;
716}
717
718void freepmt(struct channel* chnode)
719{
720        if(chnode == NULL || chnode->pmt == NULL) return;
721
722        free(chnode->pmt);
723        chnode->pmt = NULL;
724}
725
726void freecadesc(struct channel* chnode)
727{
728        struct cadesc *node = NULL, *prev = NULL;
729
730        if(chnode == NULL) return;
731
732        node = chnode->cadesc;
733        prev = chnode->cadesc;
734
735        while(node != NULL)
736        {
737                prev = node;
738                node = node->next;
739                chnode->cadesc = node;
740
741                free(prev->privat);
742                prev->privat = NULL;
743
744                free(prev);
745                prev = NULL;
746
747        }
748}
749
750void freeesinfo(struct channel* chnode)
751{
752        struct esinfo *node = NULL, *prev = NULL;
753
754        if(chnode == NULL) return;
755
756        node = chnode->esinfo;
757        prev = chnode->esinfo;
758
759        while(node != NULL)
760        {
761                prev = node;
762                node = node->next;
763                chnode->esinfo = node;
764
765                free(prev);
766                prev = NULL;
767
768        }
769}
770
771#endif
Note: See TracBrowser for help on using the repository browser.