/* * Creates a string ready to write as a token into config or WebIf for au readers. You must free the returned value through free_mk_t(). */ char *mk_t_aureader(struct s_auth *account) { int32_t pos = 0; char *dot = ""; char *value; if(ll_count(account->aureader_list) == 0 || !cs_malloc(&value, 256)) { return ""; } value[0] = '\0'; struct s_reader *rdr; LL_ITER itr = ll_iter_create(account->aureader_list); while((rdr = ll_iter_next(&itr))) { pos += snprintf(value + pos, 256 - pos, "%s%s", dot, rdr->label); dot = ","; } return value; }
static S_COOL_FILTER *find_filter_by_chanhandle(S_COOL_CHANHANDLE *chanhandle, int32_t filter_num) { // Find matching channel, if it exists. if(ll_count(ll_cool_filter) > 0) { LL_ITER itr = ll_iter_create(ll_cool_filter); S_COOL_FILTER *filter_item; while((filter_item = ll_iter_next(&itr))) { if(filter_item->chanhandle == chanhandle && filter_item->filter_num == filter_num) { return filter_item; } } } return NULL; }
static int32_t remove_filter(S_COOL_FILTER *filter_handle) { if(ll_count(ll_cool_filter) > 0) { LL_ITER itr = ll_iter_create(ll_cool_filter); S_COOL_FILTER *filter_item; while((filter_item = ll_iter_next(&itr))) { if(filter_item == filter_handle) { ll_iter_remove_data(&itr); return 0; } } } return -1; }
static S_COOL_CHANHANDLE *find_chanhandle(int32_t demux_index, int32_t pid) { // Find matching channel, if it exists. if(ll_count(ll_cool_chanhandle) > 0) { LL_ITER itr = ll_iter_create(ll_cool_chanhandle); S_COOL_CHANHANDLE *handle_item; while((handle_item = ll_iter_next(&itr))) { if(handle_item->demux_index == demux_index && handle_item->pid == pid) { return handle_item; } } } return NULL; }
int32_t cacheex_add_stats(struct s_client *cl, uint16_t caid, uint16_t srvid, uint32_t prid, uint8_t direction) { if(!cfg.cacheex_enable_stats) { return -1; } // create list if doesn't exist if(!cl->ll_cacheex_stats) { cl->ll_cacheex_stats = ll_create("ll_cacheex_stats"); } time_t now = time((time_t *)0); LL_ITER itr = ll_iter_create(cl->ll_cacheex_stats); S_CACHEEX_STAT_ENTRY *cacheex_stats_entry; // check for existing entry while((cacheex_stats_entry = ll_iter_next(&itr))) { if(cacheex_stats_entry->cache_srvid == srvid && cacheex_stats_entry->cache_caid == caid && cacheex_stats_entry->cache_prid == prid && cacheex_stats_entry->cache_direction == direction) { // we already have this entry - just add count and time cacheex_stats_entry->cache_count++; cacheex_stats_entry->cache_last = now; return cacheex_stats_entry->cache_count; } } // if we land here we have to add a new entry if(cs_malloc(&cacheex_stats_entry, sizeof(S_CACHEEX_STAT_ENTRY))) { cacheex_stats_entry->cache_caid = caid; cacheex_stats_entry->cache_srvid = srvid; cacheex_stats_entry->cache_prid = prid; cacheex_stats_entry->cache_count = 1; cacheex_stats_entry->cache_last = now; cacheex_stats_entry->cache_direction = direction; ll_iter_insert(&itr, cacheex_stats_entry); return 1; } return 0; }
static int32_t remove_chanhandle(S_COOL_CHANHANDLE *handle) { // Find matching channel, if it exists. if(ll_count(ll_cool_chanhandle) > 0) { LL_ITER itr = ll_iter_create(ll_cool_chanhandle); S_COOL_CHANHANDLE *handle_item; while((handle_item = ll_iter_next(&itr))) { if(handle_item == handle) { ll_iter_remove_data(&itr); return 0; } } } return -1; }
void gbox_remove_cards_without_goodsids(LLIST *card_list) { if(card_list) { LL_ITER it = ll_iter_create(card_list); struct gbox_card *card; while((card = ll_iter_next(&it))) { if(ll_count(card->goodsids) == 0) { ll_iter_remove(&it); gbox_free_card(card); } else { ll_destroy_data_NULL(card->badsids); } } } return; }
static void continue_build(build *current, char *filename, file_contents newest) { slice name_slice = new_slice(filename); slice *boxed_slice = new(boxed_slice); *boxed_slice = name_slice; hm_put(current->declarations, slice_hash(name_slice), boxed_slice, filename); linked_iter iterator = ll_iter_head(newest.imports); while(ll_iter_has_next(&iterator)) { import_declaration *dec = ll_iter_next(&iterator); char *filename = resolve_name(dec->name); slice filename_slice = new_slice(filename); slice *boxed_filename = new(boxed_filename); *boxed_filename = filename_slice; if(!hm_has(current->declarations, slice_hash(filename_slice), &(filename_slice))) { file_contents contents = get_contents(filename); ll_concat(current->composite.structs, contents.structs); ll_concat(current->composite.functions, contents.functions); hm_put(current->declarations, slice_hash(filename_slice), boxed_filename, filename); continue_build(current, filename, contents); } } }
void free_joblist(struct s_client *cl) { int32_t lock_status = pthread_mutex_trylock(&cl->thread_lock); LL_ITER it = ll_iter_create(cl->joblist); struct job_data *data; while((data = ll_iter_next(&it))) { free_job_data(data); } ll_destroy(&cl->joblist); cl->account = NULL; if(cl->work_job_data) // Free job_data that was not freed by work_thread { free_job_data(cl->work_job_data); } cl->work_job_data = NULL; if(lock_status == 0) { SAFE_MUTEX_UNLOCK(&cl->thread_lock); } pthread_mutex_destroy(&cl->thread_lock); }
void dvbapi_save_channel_cache(void) { char fname[256]; get_config_filename(fname, sizeof(fname), "oscam.ccache"); FILE *file = fopen(fname, "w"); if(!file) { cs_log("dvbapi channelcache can't write to file %s", fname); return; } LL_ITER it = ll_iter_create(channel_cache); struct s_channel_cache *c; while((c = ll_iter_next(&it))) { fprintf(file, "%04X,%06X,%04X,%04X,%06X\n", c->caid, c->prid, c->srvid, c->pid, c->chid); } fclose(file); cs_log("dvbapi channelcache saved to %s", fname); }
/* Print the created AST to stdout, mostly for debugging purposes */ void dump(file_contents contents) { { linked_iter iterator = ll_iter_head(contents.imports); while(ll_iter_has_next(&iterator)) { import_declaration *import = ll_iter_next(&iterator); printf("IMPORT: %s\n", evaluate(import->name)); } } { linked_iter iterator = ll_iter_head(contents.enums); while(ll_iter_has_next(&iterator)) { enum_declaration *dec = ll_iter_next(&iterator); printf("ENUM: %s\n", evaluate(dec->name)); linked_iter items = ll_iter_head(dec->options); while(ll_iter_has_next(&items)) { statement *option = ll_iter_next(&items); printf("\tOPTION: %s\n", evaluate(option->data)); } } } { linked_iter iterator = ll_iter_head(contents.structs); while(ll_iter_has_next(&iterator)) { struct_declaration *current = ll_iter_next(&iterator); printf("STRUCT: %s\n", evaluate(current->name)); linked_iter iterator = ll_iter_head(current->members); while(ll_iter_has_next(&iterator)) { struct_member *member = ll_iter_next(&iterator); printf("\tMEMBER: NAME: %s | TYPE: %s\n", evaluate(member->name), evaluate(member->type)); } } } { linked_iter iterator = ll_iter_head(contents.functions); while(ll_iter_has_next(&iterator)) { func_declaration *current = ll_iter_next(&iterator); printf("FUNC: %s | TYPE : %s\n", evaluate(current->name), evaluate(current->type)); printf("\tPARAMETERS:\n"); dump_node(current->parameters, 2); printf("\tBODY:\n"); dump_node(current->root->children, 2); } } }
struct s_channel_cache *dvbapi_find_channel_cache(int32_t demux_id, int32_t pidindex, int8_t caid_and_prid_only) { struct s_ecmpids *p = &demux[demux_id].ECMpids[pidindex]; struct s_channel_cache *c; LL_ITER it; if(!channel_cache) { channel_cache = ll_create("channel cache"); } it = ll_iter_create(channel_cache); while((c = ll_iter_next(&it))) { if(caid_and_prid_only) { if(p->CAID == c->caid && (p->PROVID == c->prid || p->PROVID == 0)) // PROVID ==0 some provider no provid in PMT table { return c; } } else { if(demux[demux_id].program_number == c->srvid && p->CAID == c->caid && p->ECM_PID == c->pid && (p->PROVID == c->prid || p->PROVID == 0)) // PROVID ==0 some provider no provid in PMT table { #ifdef WITH_DEBUG char buf[ECM_FMT_LEN]; ecmfmt(c->caid, 0, c->prid, c->chid, c->pid, c->srvid, 0, 0, 0, 0, buf, ECM_FMT_LEN, 0, 0); cs_debug_mask(D_DVBAPI, "[DVBAPI] found in channel cache: %s", buf); #endif return c; } } } return NULL; }
static void *arm_led_thread_main(void *UNUSED(thread_data)) { uint8_t running = 1; set_thread_name(__func__); while(running) { LL_ITER iter = ll_iter_create(arm_led_actions); struct s_arm_led *arm_led; while((arm_led = ll_iter_next(&iter))) { int32_t led, action; time_t now, start; led = arm_led->led; action = arm_led->action; now = time((time_t)0); start = arm_led->start_time; ll_iter_remove_data(&iter); if(action == LED_STOP_THREAD) { running = 0; break; } if(now - start < ARM_LED_TIMEOUT) { arm_switch_led_from_thread(led, action); } } if(running) { sleep(60); } } ll_clear_data(arm_led_actions); pthread_exit(NULL); return NULL; }
int32_t coolapi_set_filter (int32_t fd, int32_t num, int32_t pid, uchar * flt, uchar * mask, int32_t type) { dmx_t * dmx = find_demux(fd, 0); if(!dmx) { cs_debug_mask(D_DVBAPI, "dmx is NULL!"); return -1; } int32_t result, channel_found=0; void * channel = NULL; if (ll_count(ll_cool_chanhandle) > 0) { LL_ITER itr = ll_iter_create(ll_cool_chanhandle); S_COOL_CHANHANDLE *handle_item; while ((handle_item=ll_iter_next(&itr))) { if (handle_item->demux_index == dmx->demux_index && handle_item->pid == pid) { channel = handle_item->channel; channel_found=1; break; } } } if (!channel) { buffer_open_arg_t bufarg; int32_t uBufferSize = 8256; memset(&bufarg, 0, sizeof(bufarg)); bufarg.type = 3; bufarg.size = uBufferSize; bufarg.unknown3 = (uBufferSize * 7) / 8; result = cnxt_cbuf_open(&dmx->buffer1, &bufarg, NULL, NULL); coolapi_check_error("cnxt_cbuf_open", result); bufarg.type = 0; result = cnxt_cbuf_open(&dmx->buffer2, &bufarg, NULL, NULL); coolapi_check_error("cnxt_cbuf_open", result); channel_open_arg_t chanarg; memset(&chanarg, 0, sizeof(channel_open_arg_t)); chanarg.type = 4; result = cnxt_dmx_channel_open(dmx->device, &dmx->channel, &chanarg, dmx_callback, dmx); coolapi_check_error("cnxt_dmx_channel_open", result); result = cnxt_dmx_set_channel_buffer(dmx->channel, 0, dmx->buffer1); coolapi_check_error("cnxt_dmx_set_channel_buffer", result); result = cnxt_dmx_channel_attach(dmx->channel, 0xB, 0, dmx->buffer2); coolapi_check_error("cnxt_dmx_channel_attach", result); result = cnxt_cbuf_attach(dmx->buffer2, 2, dmx->channel); coolapi_check_error("cnxt_cbuf_attach", result); result = cnxt_dmx_set_channel_pid(dmx->channel, pid); coolapi_check_error("cnxt_dmx_set_channel_pid", result); result = cnxt_cbuf_flush (dmx->buffer1, 0); coolapi_check_error("cnxt_cbuf_flush", result); result = cnxt_cbuf_flush (dmx->buffer2, 0); coolapi_check_error("cnxt_cbuf_flush", result); S_COOL_CHANHANDLE *handle_item; if (cs_malloc(&handle_item,sizeof(S_COOL_CHANHANDLE))) { handle_item->pid = pid; handle_item->channel = dmx->channel; handle_item->buffer1 = dmx->buffer1; handle_item->buffer2 = dmx->buffer2; handle_item->demux_index = dmx->demux_index; ll_append(ll_cool_chanhandle, handle_item); } cs_debug_mask(D_DVBAPI, "opened new channel %x", (int32_t) dmx->channel); } else { channel_found=1; dmx->channel = channel; dmx->buffer1 = NULL; dmx->buffer2 = NULL; } cs_debug_mask(D_DVBAPI, "setting new filter fd=%08x demux=%d channel=%x num=%d pid=%04x flt=%x mask=%x", fd, dmx->demux_index, (int32_t) dmx->channel, num, pid, flt[0], mask[0]); pthread_mutex_lock(&dmx->mutex); filter_set_t filter; dmx->filter_num = num; dmx->pid = pid; dmx->type = type; memset(&filter, 0, sizeof(filter)); filter.length = 12; memcpy(filter.filter, flt, 16); memcpy(filter.mask, mask, 16); result = cnxt_dmx_open_filter(dmx->device, &dmx->filter); coolapi_check_error("cnxt_dmx_open_filter", result); result = cnxt_dmx_set_filter(dmx->filter, &filter, NULL); coolapi_check_error("cnxt_dmx_set_filter", result); result = cnxt_dmx_channel_attach_filter(dmx->channel, dmx->filter); coolapi_check_error("cnxt_dmx_channel_attach_filter", result); if (channel_found) { result = cnxt_dmx_channel_ctrl(dmx->channel, 0, 0); coolapi_check_error("cnxt_dmx_channel_ctrl", result); } result = cnxt_dmx_channel_ctrl(dmx->channel, 2, 0); coolapi_check_error("cnxt_dmx_channel_ctrl", result); pthread_mutex_unlock(&dmx->mutex); S_COOL_FILTER *filter_item; if (cs_malloc(&filter_item,sizeof(S_COOL_FILTER))) { // fill filter item filter_item->fd = fd; filter_item->pid = pid; filter_item->channel = (int32_t) dmx->channel; memcpy(filter_item->filter16, flt, 16); memcpy(filter_item->mask16, mask, 16); //add filter item ll_append(ll_cool_filter, filter_item); } return 0; }
int32_t coolapi_remove_filter (int32_t fd, int32_t num) { dmx_t * dmx = find_demux(fd, 0); if(!dmx) { cs_debug_mask(D_DVBAPI, "dmx is NULL!"); return -1; } if(dmx->pid <= 0) return -1; int32_t result, filter_on_channel=0; cs_debug_mask(D_DVBAPI, "removing filter fd=%08x num=%d pid=%04x on channel=%x", fd, num, dmx->pid, (int32_t) dmx->channel); pthread_mutex_lock(&dmx->mutex); if(dmx->filter) { result = cnxt_dmx_channel_detach_filter(dmx->channel, dmx->filter); coolapi_check_error("cnxt_dmx_channel_detach_filter", result); result = cnxt_dmx_close_filter(dmx->filter); coolapi_check_error("cnxt_dmx_close_filter", result); dmx->filter = NULL; result = cnxt_dmx_channel_ctrl(dmx->channel, 0, 0); coolapi_check_error("cnxt_dmx_channel_ctrl", result); } LL_ITER itr = ll_iter_create(ll_cool_filter); S_COOL_FILTER *filter_item; while ((filter_item=ll_iter_next(&itr))) { if (filter_item->channel == (int32_t) dmx->channel) filter_on_channel++; if (filter_item->fd == fd) { ll_iter_remove_data(&itr); filter_on_channel--; } } if (!filter_on_channel) { cs_debug_mask(D_DVBAPI, "closing channel %x", (int32_t) dmx->channel); itr = ll_iter_create(ll_cool_chanhandle); S_COOL_CHANHANDLE *handle_item; while ((handle_item=ll_iter_next(&itr))) { if (handle_item->demux_index == dmx->demux_index && handle_item->pid == dmx->pid) { dmx->buffer1=handle_item->buffer1; dmx->buffer2=handle_item->buffer2; ll_iter_remove_data(&itr); break; } } if (!dmx->buffer1 || !dmx->buffer2) cs_debug_mask(D_DVBAPI, "WARNING: buffer handle not found!"); result = cnxt_dmx_channel_ctrl(dmx->channel, 0, 0); coolapi_check_error("cnxt_dmx_channel_ctrl", result); result = cnxt_dmx_set_channel_pid(dmx->channel, 0x1FFF); coolapi_check_error("cnxt_dmx_set_channel_pid", result); result = cnxt_cbuf_flush (dmx->buffer1, 0); coolapi_check_error("cnxt_cbuf_flush", result); result = cnxt_cbuf_flush (dmx->buffer2, 0); coolapi_check_error("cnxt_cbuf_flush", result); result = cnxt_cbuf_detach(dmx->buffer2, 2, dmx->channel); coolapi_check_error("cnxt_cbuf_detach", result); result = cnxt_dmx_channel_detach(dmx->channel, 0xB, 0, dmx->buffer1); coolapi_check_error("cnxt_dmx_channel_detach", result); result = cnxt_dmx_channel_close(dmx->channel); coolapi_check_error("cnxt_dmx_channel_close", result); result = cnxt_cbuf_close(dmx->buffer2); coolapi_check_error("cnxt_cbuf_close", result); result = cnxt_cbuf_close(dmx->buffer1); coolapi_check_error("cnxt_cbuf_close", result); } if (filter_on_channel) { result = cnxt_dmx_channel_ctrl(dmx->channel, 2, 0); coolapi_check_error("cnxt_dmx_channel_ctrl", result); } pthread_mutex_unlock(&dmx->mutex); dmx->pid = -1; return 0; }
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t n) { char *data; char *hdrstr; uchar *content; int rcode, len, clen = 0; s_ghttp *context = (s_ghttp *)client->ghttp; ECM_REQUEST *er = NULL; if(n < 5) { return -1; } data = strstr((char *)buf, "HTTP/1.1 "); if(!data || ll_count(context->ecm_q) > 6) { cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response: %s", client->reader->label, buf); cs_ddump_mask(D_CLIENT, buf, n, "%s: ", client->reader->label); network_tcp_connection_close(client->reader, "receive error"); NULLFREE(context->session_id); ll_clear(context->ecm_q); return -1; } LL_ITER itr = ll_iter_create(context->ecm_q); er = (ECM_REQUEST *)ll_iter_next(&itr); rcode = _get_int_header(buf, "HTTP/1.1 "); clen = _get_int_header(buf, "Content-Length: "); content = (uchar *)(strstr(data, "\r\n\r\n") + 4); hdrstr = _get_header_substr(buf, "ETag: \"", "\"\r\n"); if(hdrstr) { NULLFREE(context->host_id); context->host_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: new name: %s", client->reader->label, context->host_id); len = b64decode(context->host_id); if(len == 0 || len >= 64) { NULLFREE(context->host_id); } else { cs_debug_mask(D_CLIENT, "%s: redirected...", client->reader->label); NULLFREE(context->session_id); ll_clear_data(ghttp_ignored_contexts); ll_clear(context->ecm_q); return -1; } } hdrstr = _get_header_substr(buf, "ETag: W/\"", "\"\r\n"); if(hdrstr) { NULLFREE(context->fallback_id); context->fallback_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: new fallback name: %s", client->reader->label, context->fallback_id); len = b64decode(context->fallback_id); if(len == 0 || len >= 64) { NULLFREE(context->fallback_id); } } hdrstr = _get_header(buf, "Set-Cookie: GSSID="); if(hdrstr) { NULLFREE(context->session_id); context->session_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id); } // buf[n] = '\0'; // cs_ddump_mask(D_TRACE, content, clen, "%s: reply\n%s", client->reader->label, buf); if(rcode < 200 || rcode > 204) { cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode); data = strstr((char *)buf, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect? if(data) // we have error info string in the post content { if(clen > 0) { content[clen] = '\0'; cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, content); } } if(rcode == 503) { if(er && _is_post_context(context->post_contexts, er, false)) { if(_swap_hosts(context)) { cs_debug_mask(D_CLIENT, "%s: switching to fallback", client->reader->label); } else { cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label); network_tcp_connection_close(client->reader, "reconnect"); ll_clear(context->ecm_q); } } else { // on 503 cache timeout, retry with POST immediately (and switch to POST for subsequent) if(er) { _set_pid_status(context->post_contexts, er->onid, er->tsid, er->srvid, 0); cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); } } } else if(rcode == 401) { NULLFREE(context->session_id); if(er) { cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); } } else if(rcode == 403) { client->reader->enable = 0; network_tcp_connection_close(client->reader, "login failure"); ll_clear(context->ecm_q); cs_log("%s: invalid username/password, disabling reader.", client->reader->label); } // not sure if this is needed on failure, copied from newcamd *rc = 0; memset(dcw, 0, 16); return -1; } // successful http reply (200 ok or 204 no content) hdrstr = _get_header(buf, "Pragma: context-ignore="); if(hdrstr) { if(clen > 1) { cs_ddump_mask(D_CLIENT, content, clen, "%s: pmt ignore reply - %s (%d pids)", client->reader->label, hdrstr, clen / 2); uint32_t onid = 0, tsid = 0, sid = 0; if(sscanf(hdrstr, "%4x-%4x-%4x", &onid, &tsid, &sid) == 3) { _set_pids_status(ghttp_ignored_contexts, onid, tsid, sid, content, clen); } NULLFREE(hdrstr); return -1; } NULLFREE(hdrstr); } data = strstr((char *)buf, "Pragma: context-ignore-clear"); if(data) { cs_debug_mask(D_CLIENT, "%s: clearing local ignore list (size %d)", client->reader->label, ll_count(ghttp_ignored_contexts)); ll_clear_data(ghttp_ignored_contexts); } // switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client if(!er || _is_post_context(context->post_contexts, er, false)) { data = strstr((char *)buf, "Pragma: cached"); if(data || (client->cwlastresptime > 0 && client->cwlastresptime < 640)) { cs_debug_mask(D_CLIENT, "%s: probably cached cw (%d ms), switching back to cache get for next req", client->reader->label, client->cwlastresptime); if(er) { _is_post_context(context->post_contexts, er, true); } } } if(clen == 16) // cw in content { memcpy(dcw, content, 16); *rc = 1; er = ll_remove_first(context->ecm_q); if(!er) { return -1; } cs_ddump_mask(D_TRACE, dcw, 16, "%s: cw recv chk for idx %d", client->reader->label, er->idx); return er->idx; } else { if(clen != 0) { cs_ddump_mask(D_CLIENT, content, clen, "%s: recv_chk fail, clen = %d", client->reader->label, clen); } } return -1; }
int32_t gbox_cmd_hello(struct s_client *cli, uchar *data, int32_t n) { struct gbox_peer *peer = cli->gbox; int32_t i; int32_t ncards_in_msg = 0; int32_t payload_len = n; //TODO: checkcode_len can be made void int32_t checkcode_len = 0; int32_t hostname_len = 0; int32_t footer_len = 0; uint8_t *ptr = 0; if(!(data[0] == 0x48 && data[1] == 0x49)) // if not MSG_HELLO1 { gbox_decompress(data, &payload_len); } cs_ddump_mask(D_READER, data, payload_len, "gbox: decompressed data (%d bytes):", payload_len); if((data[0x0B] == 0) | ((data[0x0A] == 1) && (data[0x0B] == 0x80))) { if(peer->gbox.cards) { gbox_remove_cards_without_goodsids(peer->gbox.cards); } else { peer->gbox.cards = ll_create("peer.cards"); } } if((data[0xB] & 0xF) == 0) { checkcode_len = 7; hostname_len = data[payload_len - 1]; footer_len = hostname_len + 2; } if(data[0] == 0x48 && data[1] == 0x49) // if MSG_HELLO1 { ptr = data + 11; } else { ptr = data + 12; } while(ptr < data + payload_len - footer_len - checkcode_len - 1) { uint16_t caid; uint32_t provid; uint32_t provid1; switch(ptr[0]) { //Viaccess case 0x05: caid = ptr[0] << 8; provid = ptr[1] << 16 | ptr[2] << 8 | ptr[3]; break; //Cryptoworks case 0x0D: caid = ptr[0] << 8 | ptr[1]; provid = ptr[2]; break; default: caid = ptr[0] << 8 | ptr[1]; provid = ptr[2] << 8 | ptr[3]; break; } //caid check if(chk_ctab(caid, &cli->reader->ctab)) { provid1 = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; uint8_t ncards = ptr[4]; ptr += 5; for(i = 0; i < ncards; i++) { // for all n cards and current caid/provid, // create card info from data and add card to peer.cards struct gbox_card *card; if(!cs_malloc(&card, sizeof(struct gbox_card))) { continue; } card->caid = caid; card->provid = provid; card->provid_1 = provid1; card->slot = ptr[0]; card->dist = ptr[1] & 0xf; card->lvl = ptr[1] >> 4; card->peer_id = ptr[2] << 8 | ptr[3]; ptr += 4; if((cli->reader->gbox_maxdist >= card->dist) && (card->peer_id != local_gbox.id)) { LL_ITER it = ll_iter_create(peer->gbox.cards); struct gbox_card *card_s; uint8_t v_card = 0; while((card_s = ll_iter_next(&it))) // don't add card if already in peer.cards list { if(card_s->peer_id == card->peer_id && card_s->provid_1 == card->provid_1) { gbox_free_card(card); card = NULL; v_card = 1; break; } } if(v_card != 1) // new card - not in list { card->badsids = ll_create("badsids"); card->goodsids = ll_create("goodsids"); ll_append(peer->gbox.cards, card); ncards_in_msg++; cs_debug_mask(D_READER, " card: caid=%04x, provid=%06x, slot=%d, level=%d, dist=%d, peer=%04x", card->caid, card->provid, card->slot, card->lvl, card->dist, card->peer_id); } } else // don't add card { gbox_free_card(card); card = NULL; } cli->reader->tcp_connected = 2; // we have card } // end for ncards } else {
static int32_t cs_check_v(IN_ADDR_T ip, int32_t port, int32_t add, char *info, int32_t acosc_penalty_duration) { int32_t result = 0; bool acosc_enabled = false; #ifdef CS_ANTICASC if(cfg.acosc_enabled) acosc_enabled = true; #endif if(!(cfg.failbantime || acosc_enabled)) { return 0; } if(!cfg.v_list) { cfg.v_list = ll_create("v_list"); } struct timeb (now); cs_ftime(&now); LL_ITER itr = ll_iter_create(cfg.v_list); V_BAN *v_ban_entry; int32_t ftime = cfg.failbantime * 60 * 1000; //run over all banned entries to do housekeeping: while((v_ban_entry = ll_iter_next(&itr))) { // housekeeping: int32_t gone = comp_timeb(&now, &v_ban_entry->v_time); if(((gone >= ftime) && !v_ban_entry->acosc_entry) || (v_ban_entry->acosc_entry && ((gone/1000) >= v_ban_entry->acosc_penalty_dur))) // entry out of time->remove { NULLFREE(v_ban_entry->info); ll_iter_remove_data(&itr); continue; } if(IP_EQUAL(ip, v_ban_entry->v_ip) && port == v_ban_entry->v_port) { result = 1; if(!info) { info = v_ban_entry->info; } else if(!v_ban_entry->info) { v_ban_entry->info = cs_strdup(info); } if(!add) { if(v_ban_entry->v_count >= cfg.failbancount) { if(!v_ban_entry->acosc_entry) { cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - %d seconds left%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, (ftime - gone)/1000, info ? ", info: " : "", info ? info : ""); } else { cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - %d seconds left%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, (v_ban_entry->acosc_penalty_dur - (gone/1000)), info?", info: ":"", info?info:""); } } else { cs_debug_mask(D_TRACE, "failban: ip %s:%d chance %d of %d%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, v_ban_entry->v_count, cfg.failbancount, info ? ", info: " : "", info ? info : ""); v_ban_entry->v_count++; } } else { cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - already exist in list%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, info ? ", info: " : "", info ? info : ""); } } } if(add && !result) { if(cs_malloc(&v_ban_entry, sizeof(V_BAN))) { cs_ftime(&v_ban_entry->v_time); v_ban_entry->v_ip = ip; v_ban_entry->v_port = port; v_ban_entry->v_count = 1; v_ban_entry->acosc_entry = false; v_ban_entry->acosc_penalty_dur = 0; if(acosc_penalty_duration > 0) { v_ban_entry->v_count = cfg.failbancount +1; // set it to a higher level v_ban_entry->acosc_entry = true; v_ban_entry->acosc_penalty_dur = acosc_penalty_duration; } if(info) { v_ban_entry->info = cs_strdup(info); } ll_iter_insert(&itr, v_ban_entry); cs_debug_mask(D_TRACE, "failban: ban ip %s:%d with timestamp %ld%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, v_ban_entry->v_time.time, info ? ", info: " : "", info ? info : ""); } } return result; }
int32_t ICC_Async_Device_Init (struct s_reader *reader) { reader->fdmc=-1; cs_debug_mask (D_IFD, "IFD: Opening device %s\n", reader->device); reader->written = 0; if (reader->crdr.active==1 && reader->crdr.reader_init) { return reader->crdr.reader_init(reader); } switch(reader->typ) { case R_SC8in1: cs_writelock(&sc8in1_lock); if (reader->handle != 0) {//this reader is already initialized cs_writeunlock(&sc8in1_lock); return OK; } //this reader is uninitialized, thus the first one, since the first one initializes all others //get physical device name int32_t pos = strlen(reader->device)-2; //this is where : should be located; is also valid length of physical device name if (reader->device[pos] != 0x3a) //0x3a = ":" cs_log("ERROR: '%c' detected instead of slot separator `:` at second to last position of device %s", reader->device[pos], reader->device); reader->slot=(int)reader->device[pos+1] - 0x30; reader->device[pos]= 0; //slot 1 reader now gets correct physicalname //open physical device reader->handle = open (reader->device, O_RDWR | O_NOCTTY| O_NONBLOCK); if (reader->handle < 0) { cs_log("ERROR opening device %s",reader->device); cs_writeunlock(&sc8in1_lock); return ERROR; } //copy physical device name and file handle to other slots struct s_reader *rdr; LL_ITER itr = ll_iter_create(configured_readers); while((rdr = ll_iter_next(&itr))) //copy handle to other slots if (rdr->typ == R_SC8in1 && rdr != reader) { //we have another sc8in1 reader unsigned char save = rdr->device[pos]; rdr->device[pos]=0; //set to 0 so we can compare device names if (!strcmp(reader->device, rdr->device)) {//we have a match to another slot with same device name rdr->handle = reader->handle; rdr->slot=(int)rdr->device[pos+1] - 0x30; } else rdr->device[pos] = save; //restore character } break; case R_MP35: case R_MOUSE: reader->handle = open (reader->device, O_RDWR | O_NOCTTY| O_NONBLOCK); if (reader->handle < 0) { cs_log("ERROR opening device %s",reader->device); return ERROR; } break; #if defined(TUXBOX) && defined(PPC) case R_DB2COM1: case R_DB2COM2: reader->handle = open (reader->device, O_RDWR | O_NOCTTY| O_SYNC); if (reader->handle < 0) { cs_log("ERROR opening device %s",reader->device); return ERROR; } if ((reader->fdmc = open(DEV_MULTICAM, O_RDWR)) < 0) { close(reader->handle); cs_log("ERROR opening device %s",DEV_MULTICAM); return ERROR; } break; #endif case R_SMART: #if defined(LIBUSB) call (SR_Init(reader)); break; #else cs_log("ERROR, you have specified 'protocol = smartreader' in oscam.server,"); cs_log("recompile with SmartReader support."); return ERROR; #endif case R_INTERNAL: #if defined(COOL) return Cool_Init(reader->device); #elif defined(AZBOX) return Azbox_Init(reader); #elif defined(SCI_DEV) #if defined(SH4) || defined(STB04SCI) reader->handle = open (reader->device, O_RDWR|O_NONBLOCK|O_NOCTTY); #else reader->handle = open (reader->device, O_RDWR); #endif if (reader->handle < 0) { cs_log("ERROR opening device %s",reader->device); return ERROR; } #elif defined(WITH_STAPI) return STReader_Open(reader->device, &reader->stsmart_handle); #else//SCI_DEV cs_log("ERROR, you have specified 'protocol = internal' in oscam.server,"); cs_log("recompile with internal reader support."); return ERROR; #endif//SCI_DEV break; #ifdef HAVE_PCSC case R_PCSC: return (pcsc_reader_init(reader, reader->device)); break; #endif default: cs_log("ERROR ICC_Device_Init: unknow reader type %i",reader->typ); return ERROR; } if (reader->typ == R_MP35) { if (MP35_Init(reader)) { cs_log("ERROR: MP35_Init returns error"); MP35_Close (reader); return ERROR; } } else if (reader->typ <= R_MOUSE) if (Phoenix_Init(reader)) { cs_log("ERROR: Phoenix_Init returns error"); Phoenix_Close (reader); return ERROR; } if (reader->typ == R_SC8in1) { call(Sc8in1_Init(reader)); cs_writeunlock(&sc8in1_lock); } cs_debug_mask (D_IFD, "IFD: Device %s succesfully opened\n", reader->device); return OK; }
static void camd35_request_emm(ECM_REQUEST *er) { int32_t i; time_t now; uchar mbuf[1024]; struct s_client *cl = cur_client(); struct s_reader *aureader = NULL, *rdr = NULL; if(er->selected_reader && !er->selected_reader->audisabled && ll_contains(cl->aureader_list, er->selected_reader)) { aureader = er->selected_reader; } if(!aureader && cl->aureader_list) { LL_ITER itr = ll_iter_create(cl->aureader_list); while((rdr = ll_iter_next(&itr))) { if(emm_reader_match(rdr, er->caid, er->prid)) { aureader = rdr; break; } } } if(!aureader) { return; } // TODO uint16_t au_caid = aureader->caid; if(!au_caid && caid_is_bulcrypt(er->caid)) // Bulcrypt has 2 caids and aureader->caid can't be used. Use ECM_REQUEST caid for AU. { au_caid = er->caid; } time(&now); if(!memcmp(cl->lastserial, aureader->hexserial, 8)) if(llabs(now - cl->last) < 180) { return; } memcpy(cl->lastserial, aureader->hexserial, 8); cl->last = now; if(au_caid) { cl->disable_counter = 0; cs_log("%s emm-request sent (reader=%s, caid=%04X, auprovid=%06X)", username(cur_client()), aureader->label, au_caid, aureader->auprovid ? aureader->auprovid : b2i(4, aureader->prid[0])); } else if(cl->disable_counter > 2) { return; } else { cl->disable_counter++; } memset(mbuf, 0, sizeof(mbuf)); mbuf[2] = mbuf[3] = 0xff; // must not be zero i2b_buf(2, er->srvid, mbuf + 8); //override request provid with auprovid if set in CMD05 if(aureader->auprovid) { if(aureader->auprovid != er->prid) { i2b_buf(4, aureader->auprovid, mbuf + 12); } else { i2b_buf(4, er->prid, mbuf + 12); } } else { i2b_buf(4, er->prid, mbuf + 12); } i2b_buf(2, er->pid, mbuf + 16); mbuf[0] = 5; mbuf[1] = 111; if(au_caid) { mbuf[39] = 1; // no. caids mbuf[20] = au_caid >> 8; // caid's (max 8) mbuf[21] = au_caid & 0xff; memcpy(mbuf + 40, aureader->hexserial, 6); // serial now 6 bytes mbuf[47] = aureader->nprov; for(i = 0; i < aureader->nprov; i++) { if((au_caid >= 0x1700 && au_caid <= 0x1799) || // Betacrypt (au_caid >= 0x0600 && au_caid <= 0x0699)) // Irdeto (don't know if this is correct, cause I don't own a IRDETO-Card) { mbuf[48 + (i * 5)] = aureader->prid[i][0]; memcpy(&mbuf[50 + (i * 5)], &aureader->prid[i][1], 3); } else { mbuf[48 + (i * 5)] = aureader->prid[i][2]; mbuf[49 + (i * 5)] = aureader->prid[i][3]; memcpy(&mbuf[50 + (i * 5)], &aureader->sa[i][0], 4); // for conax we need at least 4 Bytes } } //we think client/server protocols should deliver all information, and only readers should discard EMM mbuf[128] = (aureader->blockemm & EMM_GLOBAL && !(aureader->saveemm & EMM_GLOBAL)) ? 0 : 1; mbuf[129] = (aureader->blockemm & EMM_SHARED && !(aureader->saveemm & EMM_SHARED)) ? 0 : 1; mbuf[130] = (aureader->blockemm & EMM_UNIQUE && !(aureader->saveemm & EMM_UNIQUE)) ? 0 : 1; mbuf[127] = (aureader->blockemm & EMM_UNKNOWN && !(aureader->saveemm & EMM_UNKNOWN)) ? 0 : 1; } else // disable emm { mbuf[20] = mbuf[39] = mbuf[40] = mbuf[47] = mbuf[49] = 1; }
static void monitor_process_details_reader(struct s_client *cl) { char tbuffer1[64], tbuffer2[64], buf[256] = { 0 }, tmpbuf[256] = { 0 }, valid_to[32] = { 0 }; struct s_reader *rdr = cl->reader; if (!rdr) { monitor_send_details("Reader do not exist or it is not started.", cl->tid); return; } if (rdr->card_valid_to) { struct tm vto_t; localtime_r(&rdr->card_valid_to, &vto_t); strftime(valid_to, sizeof(valid_to) - 1, "%Y-%m-%d", &vto_t); } else { strncpy(valid_to, "n/a", 3); } snprintf(tmpbuf, sizeof(tmpbuf) - 1, "Cardsystem: %s Reader: %s ValidTo: %s HexSerial: %s ATR: %s", rdr->csystem.desc, rdr->label, valid_to, cs_hexdump(1, rdr->hexserial, 8, tbuffer2, sizeof(tbuffer2)), rdr->card_atr_length ? cs_hexdump(1, rdr->card_atr, rdr->card_atr_length, buf, sizeof(buf)) : "" ); monitor_send_details(tmpbuf, cl->tid); if (!rdr->ll_entitlements) { monitor_send_details("No entitlements for the reader.", cl->tid); return; } S_ENTITLEMENT *item; LL_ITER itr = ll_iter_create(rdr->ll_entitlements); time_t now = (time(NULL) / 84600) * 84600; while ((item = ll_iter_next(&itr))) { struct tm start_t, end_t; localtime_r(&item->start, &start_t); localtime_r(&item->end , &end_t); strftime(tbuffer1, sizeof(tbuffer1) - 1, "%Y-%m-%d %H:%M %z", &start_t); strftime(tbuffer2, sizeof(tbuffer2) - 1, "%Y-%m-%d %H:%M %z", &end_t); char *entresname = get_tiername(item->id & 0xFFFF, item->caid, buf); if (!entresname[0]) entresname = get_provider(item->caid, item->provid, buf, sizeof(buf)); snprintf(tmpbuf, sizeof(tmpbuf) - 1, "%s Type: %s CAID: %04X Provid: %06X ID: %08X%08X Class: %08X StartDate: %s ExpireDate: %s Name: %s", item->end > now ? "active " : "expired", entitlement_type[item->type], item->caid, item->provid, (uint32_t)(item->id >> 32), (uint32_t)(item->id), item->class, tbuffer1, tbuffer2, entresname ); monitor_send_details(tmpbuf, cl->tid); } }
void do_emm(struct s_client * client, EMM_PACKET *ep) { char *typtext[]={"unknown", "unique", "shared", "global"}; char tmp[17]; int32_t emmnok=0; struct s_reader *aureader = NULL; cs_ddump_mask(D_EMM, ep->emm, ep->emmlen, "emm:"); int8_t cl_dvbapi = 0, assemble = 0; #ifdef HAVE_DVBAPI cl_dvbapi = streq(cfg.dvbapi_usr, client->account->usr); #endif if (client->account->emm_reassembly > 1 || (client->account->emm_reassembly && cl_dvbapi)) assemble = 1; LL_ITER itr = ll_iter_create(client->aureader_list); while ((aureader = ll_iter_next(&itr))) { if (!aureader->enable) continue; uint16_t caid = b2i(2, ep->caid); uint32_t provid = b2i(4, ep->provid); if (aureader->audisabled) { rdr_debug_mask(aureader, D_EMM, "AU is disabled"); /* we have to write the log for blocked EMM here because this EMM never reach the reader module where the rest of EMM log is done. */ if (aureader->logemm & 0x10) { rdr_log(aureader, "%s emmtype=%s, len=%d, idx=0, cnt=1: audisabled (0 ms)", client->account->usr, typtext[ep->type], ep->emm[2]); } continue; } if (!(aureader->grp & client->grp)) { rdr_debug_mask(aureader, D_EMM, "skip emm, group mismatch"); continue; } //TODO: provider possibly not set yet, this is done in get_emm_type() if (!emm_reader_match(aureader, caid, provid)) continue; struct s_cardsystem *cs = NULL; if (is_cascading_reader(aureader)) { // network reader (R_CAMD35 R_NEWCAMD R_CS378X R_CCCAM) if (!aureader->ph.c_send_emm) // no emm support continue; cs = get_cardsystem_by_caid(caid); if (!cs) { rdr_debug_mask(aureader, D_EMM, "unable to find cardsystem for caid %04X", caid); continue; } } else { // local reader if (aureader->csystem.active) cs=&aureader->csystem; } if (cs && cs->get_emm_type) { if (!cs->get_emm_type(ep, aureader)) { rdr_debug_mask(aureader, D_EMM, "emm skipped, get_emm_type() returns error"); emmnok++; continue; } } if (cs && cs->get_emm_filter) { if (!do_simple_emm_filter(aureader, cs, ep)) { rdr_debug_mask(aureader, D_EMM, "emm skipped, emm_filter() returns invalid"); emmnok++; continue; } } if (cs && cs->do_emm_reassembly) { if (assemble) { if (!cs->do_emm_reassembly(client, ep)) return; } else { rdr_debug_mask(aureader, D_EMM, "processing raw emm"); } } rdr_debug_mask_sensitive(aureader, D_EMM, "emmtype %s. Reader serial {%s}.", typtext[ep->type], cs_hexdump(0, aureader->hexserial, 8, tmp, sizeof(tmp))); rdr_debug_mask_sensitive(aureader, D_EMM, "emm UA/SA: {%s}.", cs_hexdump(0, ep->hexserial, 8, tmp, sizeof(tmp))); client->last = time(NULL); saveemm(aureader, ep); int32_t is_blocked = 0; switch (ep->type) { case UNKNOWN: is_blocked = (aureader->blockemm & EMM_UNKNOWN) == EMM_UNKNOWN; break; case UNIQUE : is_blocked = (aureader->blockemm & EMM_UNIQUE ) == EMM_UNIQUE; break; case SHARED : is_blocked = (aureader->blockemm & EMM_SHARED ) == EMM_SHARED; break; case GLOBAL : is_blocked = (aureader->blockemm & EMM_GLOBAL ) == EMM_GLOBAL; break; } // if not already blocked we check for block by len if (!is_blocked) is_blocked = cs_emmlen_is_blocked( aureader, ep->emm[2] ) ; if (is_blocked != 0) { #ifdef WEBIF aureader->emmblocked[ep->type]++; is_blocked = aureader->emmblocked[ep->type]; #endif /* we have to write the log for blocked EMM here because this EMM never reach the reader module where the rest of EMM log is done. */ if (aureader->logemm & 0x08) { rdr_log(aureader, "%s emmtype=%s, len=%d, idx=0, cnt=%d: blocked (0 ms)", client->account->usr, typtext[ep->type], ep->emm[2], is_blocked); } continue; } client->lastemm = time((time_t*)0); client->emmok++; if (client->account) client->account->emmok++; first_client->emmok++; //Check emmcache early: int32_t i; unsigned char md5tmp[CS_EMMSTORESIZE]; struct s_client *au_cl = aureader->client; MD5(ep->emm, ep->emm[2], md5tmp); ep->client = client; for (i=0; i<CS_EMMCACHESIZE; i++) { if (!memcmp(au_cl->emmcache[i].emmd5, md5tmp, CS_EMMSTORESIZE)) { rdr_debug_mask(aureader, D_EMM, "emm found in cache: count %d rewrite %d", au_cl->emmcache[i].count, aureader->rewritemm); if (aureader->cachemm && (au_cl->emmcache[i].count > aureader->rewritemm)) { reader_log_emm(aureader, ep, i, 2, NULL); return; } break; } } EMM_PACKET *emm_pack; if (cs_malloc(&emm_pack, sizeof(EMM_PACKET))) { rdr_debug_mask(aureader, D_EMM, "emm is being sent to reader"); memcpy(emm_pack, ep, sizeof(EMM_PACKET)); add_job(aureader->client, ACTION_READER_EMM, emm_pack, sizeof(EMM_PACKET)); } } if (emmnok > 0 && emmnok == ll_count(client->aureader_list)) { client->emmnok++; if (client->account) client->account->emmnok++; first_client->emmnok++; } }
struct gbox_card *gbox_cards_iter_next(GBOX_CARDS_ITER *gci) { if (gci) { return ll_iter_next(&gci->it); } else { return NULL; } }
static statement *parse_simple_expression(linked_list *tokens) { while(equals_string(((parse_token*)ll_get_first(tokens))->data, "(") && equals_string(((parse_token*)ll_get_last(tokens))->data, ")")) { ll_remove_first(tokens); ll_remove_last(tokens); } int size = ll_size(tokens); switch(size) { case 0: return NULL; case 1: return parse_single_token(tokens); default: { if(size == 2) { parse_token *token = ll_get_first(tokens); bool isStack; if((isStack = equals_string(token->data, "new")) || equals_string(token->data, "newref")) { statement *expression = new(expression); expression->children = ll_new(); expression->type = isStack ? STACK_INIT : HEAP_INIT; linked_list *name = ll_duplicate(tokens); ll_remove_first(name); ll_add_first(expression->children, parse_simple_expression(name)); return expression; } } int paren_level = 1; linked_iter iterator = ll_iter_head(tokens); bool is_index = true, is_call = true; ll_iter_next(&iterator); parse_token *second = ll_iter_next(&iterator); if(equals_string(second->data, "(")) { is_index = false; } else if(equals_string(second->data, "[")) { is_call = false; } else { is_index = is_call = false; } while((is_index || is_call) && ll_iter_has_next(&iterator)) { parse_token *token = ll_iter_next(&iterator); if(equals_string(token->data, "(") || equals_string(token->data, "[")) { paren_level += 1; } else if(paren_level == 0) { is_index = false; is_call = false; } else if(equals_string(token->data, ")") || equals_string(token->data, "]")) { paren_level -= 1; } } if(is_index) { return parse_array_index(tokens); } else if(is_call) { return parse_func_call(tokens); } linked_list *operator = get_node(); linked_iter level = ll_iter_head(operator); while(ll_iter_has_next(&level)) { int paren_level = 0; linked_list *currentLevel = ll_iter_next(&level); linked_iter iterator = ll_iter_head(tokens); for(parse_token *current = ll_iter_next(&iterator); ll_iter_has_next(&iterator); current = ll_iter_next(&iterator)) { char currentChar = current->data.data[0]; if(currentChar == '(') { paren_level += 1; } else if(currentChar == ')') { paren_level -= 1; } if(paren_level != 0) continue; linked_iter innerMost = ll_iter_head(currentLevel); while(ll_iter_has_next(&innerMost)) { operator_node *currentOperator = ll_iter_next(&innerMost); if(equals_string(current->data, currentOperator->data)) { if(!is_unary_operator(new_slice(currentOperator->data))) { linked_list *op1 = ll_duplicate(tokens); while(ll_get_last(op1) != current) ll_remove_last(op1); ll_remove_last(op1); linked_list *op2 = tokens; while(ll_get_first(op2) != current) ll_remove_first(op2); ll_remove_first(op2); statement *expression = new(expression); expression->data = new_slice(""); expression->children = ll_new(); expression->type = currentOperator->operatorType; statement *op1_exp = parse_simple_expression(op1); statement *op2_exp = parse_simple_expression(op2); ll_add_last(expression->children, op1_exp); ll_add_last(expression->children, op2_exp); return expression; } else { statement *expression = new(expression); expression->data = new_slice(currentOperator->data); expression->type = currentOperator->operatorType; linked_list *rest = ll_duplicate(tokens); ll_remove_first(rest); expression->children = ll_new(); ll_add_first(expression->children, parse_simple_expression(rest)); return expression; } } } } } return NULL; } } }