/* * vtxqueue.c: Routines to search for pages (possibly in the background) and to manage the * page-queue & page-history * * $Id: vtxqueue.c,v 1.2 1997/10/21 00:23:38 mb Exp mb $ * * Copyright (c) 1994-97 Martin Buck * Read COPYING for more information * */ #include #include #include #include #include #include #include #include #include "safe_malloc.h" #include "misc.h" #include "config.h" #include "cct.h" #include "vtxdecode.h" #include "toptext.h" #include "fastext.h" #include "cache.h" #include "search.h" #include "hotlist.h" #include "dialog.h" #include "vtxtools.h" #include "spool.h" #include "xvtools.h" #include "selection.h" #include "xinit.h" #include "xevents.h" #include "vtxqueue.h" typedef struct top_queue_s { int page, minute, hour; struct top_queue_s *next; } top_queue_t; int vtx_dev_open, dau_status_changed = TRUE, clear_cache = TRUE; queue_entry_t *dau_status; static queue_entry_t *vtx_queue; static top_queue_t *top_queue; static int queue_maxlen, queue_end, top_queue_count; static char timeout_table[800]; static void write_pagenum(int page, int subpage, byte_t *buf); static int check_open_device(void); static int free_dau(int page, int priority); static int insert_queue(int priority, int page, int subpage, int insert_front); static int remove_queue(int page); static Server_image history_icon(int page, int default_img); /* This is one of the main functions in VideoteXt. It does all the things necessary to get a * page: open the device if it was closed, checking if the page is already in the cache, * updating the dau_status, history-list & pagenumber-display for PRI_FGROUND, handling page- * lookahead for PRI_FGROUND, throwing out lower priority pages for PRI_TOP or inserting the * page into the queue for other priorities. * If subpage == -1, search for the next subpage; if subpage == 0, search for all subpages; * if subpage > 0, search for given subpage * If hour != -1, search only for pages with equal hour-number (only used with PRI_TOP) */ int get_page(int priority, int page, int subpage, int hour, byte_t *buffer, vtxpgwin_t *vtxwin) { int bufloop, pri; if (config_get_spool_only() || keep_closed) { if (priority == PRI_FGROUND || priority == PRI_FGROUND_NH) { selection_hide(vtxwin); if (cache_query(page, (subpage ? subpage : -1), 40, buffer + 40, &vtxwin->page->info) || query_spool(page, (subpage ? subpage : -1), buffer, &vtxwin->page->info)) { buffer[0] = vtx_mkparity(2); write_pagenum(page, subpage, &buffer[1]); decode_page(buffer, vtxwin->page, 0, 23); vtxwin->update = SCR_UPDATE; vtxwin->pgnum = page; vtxwin->subpgnum = subpage; update_pagenumdisp(vtxwin->page->info.pagenum, vtxwin->page->info.minute, toptext_numsubpg(vtxwin->page->info.pagenum), cache_count_subpg(vtxwin->page->info.pagenum)); fastext_new_buttons(vtxwin->page->info.pagenum, vtxwin->page->info.minute); if (priority != PRI_FGROUND_NH) { history_insert(page, TRUE); } history_set_status(page, STAT_READ); } else { buffer[0] = vtx_mkparity(1); } } return 0; } else { if (check_open_device() < 0) return -1; } switch (priority) { case PRI_FGROUND: case PRI_FGROUND_NH: { int cache_found = FALSE, cont_search; selection_hide(vtxwin); /* (Re)move currently sought page & update history-status */ if (dau_status[0].page && (int)xv_get(cont_button, PANEL_VALUE)) { int pgbuf, tmppage; if ((pgbuf = free_dau(dau_status[0].page, PRI_HIGH))) { /* keep_running is unused if buffer != 0 */ CCTCHK(cct_searchpage(dau_status[0].page, 0, 0, PGMASK_PAGE, pgbuf), "cct_searchpage", return -1); CCTCHK(cct_reset_pgfound(pgbuf), "cct_reset_pgfound", return -1); dau_status[pgbuf] = dau_status[0]; dau_status[pgbuf].priority = PRI_HIGH; dau_status[pgbuf].timeout = time(NULL) + hotlist_get_timeout(); dau_status[pgbuf].page_found = FALSE; dau_status_changed = TRUE; tmppage = dau_status[0].page; dau_status[0].page = 0; history_set_status(tmppage, STAT_SEARCH); } else { tmppage = dau_status[0].page; dau_status[0].page = 0; insert_queue(PRI_HIGH, tmppage, dau_status[0].subpage, TRUE); history_set_status(tmppage, STAT_NEW); } } /* Check if page is already in cache */ vtxwin->update = HDR_UPDATE; if ((cache_found = cache_query(page, (subpage ? subpage : -1), 40, buffer + 40, &vtxwin->page->info)) || query_spool(page, (subpage ? subpage : -1), buffer, &vtxwin->page->info)) { decode_page(buffer, vtxwin->page, 1, 23); buffer[0] = vtx_mkparity(cache_found ? 6 : 3); vtxwin->update = SCR_UPDATE; update_pagenumdisp(vtxwin->page->info.pagenum, vtxwin->page->info.minute, toptext_numsubpg(vtxwin->page->info.pagenum), cache_count_subpg(vtxwin->page->info.pagenum)); fastext_new_buttons(vtxwin->page->info.pagenum, vtxwin->page->info.minute); if (priority != PRI_FGROUND_NH) { history_insert(page, TRUE); } history_set_status(page, STAT_READ); } else { buffer[0] = vtx_mkparity(1); } /* Search for page in DAU 0 */ CCTCHK(cct_searchpage(page, 0, 0, PGMASK_PAGE, 0), "cct_searchpage", return -1); CCTCHK(cct_reset_pgfound(0), "cct_reset_pgfound", return -1); dau_status[0].page = page; dau_status[0].subpage = subpage; dau_status[0].priority = priority; dau_status[0].timeout = time(NULL) + hotlist_get_timeout(); dau_status[0].page_found = FALSE; dau_status[0].keep_running = TRUE; dau_status[0].firstsubpg = dau_status[0].lastsubpg = 0; dau_status_changed = TRUE; /* Remeber to activate "Continue"-button as soon as the next page is found */ if (config_get_cont_search() && priority == PRI_FGROUND && page != hotlist_get_index_page()) { xv_set(cont_button, PANEL_CLIENT_DATA, TRUE, NULL); } /* Remove page from other DAUs */ cont_search = FALSE; for (bufloop = 1; bufloop < vtx_info.numpages; bufloop++) { if (dau_status[bufloop].page == page) { CCTCHK(cct_stop_dau(bufloop), "cct_stop_dau", return -1); dau_status[0].firstsubpg = dau_status[bufloop].firstsubpg; dau_status[0].lastsubpg = dau_status[bufloop].lastsubpg; if (((dau_status[bufloop].priority == PRI_MED || dau_status[bufloop].priority == PRI_HIGH) && config_get_cont_queue_search()) || dau_status[bufloop].priority == PRI_TOP) { cont_search = TRUE; } dau_status[bufloop].page = 0; } } pri = remove_queue(page); if (((pri == PRI_MED || pri == PRI_HIGH) && config_get_cont_queue_search()) || pri == PRI_TOP) { cont_search = TRUE; } /* Don't continue searching for page if all subpages are already in cache */ if (cache_query(page, -1, 0, NULL, NULL) == 2) { cont_search = FALSE; } xv_set(cont_button, PANEL_VALUE, cont_search, NULL); /* Update display (insert 'xxx.xx' in upper left corner), reset stop/reveal-buttons */ write_pagenum(page, subpage, &buffer[1]); decode_page(buffer, vtxwin->page, 0, 0); vtxwin->pgnum = page; vtxwin->subpgnum = subpage; xv_set(checkbox, PANEL_VALUE, 0, NULL); checkbox_proc(); if (priority != PRI_FGROUND_NH) { history_insert(page, TRUE); } history_set_status(page, STAT_SEARCH); /* Perform page-lookahead */ if (page != hotlist_get_index_page()) { int lookahead, tmp_page, nextpage = page; if (remove_priority(PRI_LOW) < 0) return -1; for (lookahead = hotlist_get_lookahead(); lookahead > 0; lookahead--) { tmp_page = 0; if (toptext_ok) { tmp_page = toptext_pginc(nextpage); } if (!tmp_page) { tmp_page = inc_vtxpage(nextpage); } nextpage = tmp_page; if (get_page(PRI_LOW, nextpage, -1, 0, NULL, NULL) < 0) { return -1; } } } pgdesc_update(page); } break; case PRI_TOP: { /* Search for TOP-Text-pages immediately */ int pgbuf; if (dau_status[0].page == page || vtx_info.numpages == 1) break; if ((pgbuf = free_dau(page, priority))) { /* Start searching for page */ remove_queue(page); if (hour != -1) { CCTCHK(cct_searchpage(page, hour, 0, PGMASK_PAGE | PGMASK_HOUR, pgbuf), "cct_searchpage", return -1); } else { CCTCHK(cct_searchpage(page, 0, 0, PGMASK_PAGE, pgbuf), "cct_searchpage", return -1); } CCTCHK(cct_reset_pgfound(pgbuf), "cct_reset_pgfound", return -1); /* keep_running is unused if buffer != 0 */ dau_status[pgbuf].page = page; dau_status[pgbuf].subpage = subpage; dau_status[pgbuf].priority = PRI_TOP; dau_status[pgbuf].timeout = time(NULL) + hotlist_get_timeout(); dau_status[pgbuf].page_found = FALSE; dau_status[pgbuf].firstsubpg = dau_status[pgbuf].lastsubpg = 0; dau_status_changed = TRUE; history_set_status(dau_status[pgbuf].page, STAT_SEARCH); } else { insert_queue(priority, page, 0, TRUE); /* FIXME: Also pass hour to insert_queue */ } } break; default: if (priority == PRI_LOW && timeout_check(page)) break; if (priority == PRI_HIGH || !cache_query(page, subpage, 0, NULL, NULL)) { if (!insert_queue(priority, page, subpage, FALSE) && !subpage && dau_status[0].page == page) { xv_set(cont_button, PANEL_VALUE, TRUE, NULL); } } if (priority == PRI_HIGH) { history_insert(page, FALSE); } break; } return 0; } static void write_pagenum(int page, int subpage, byte_t *buf) { const char hexchars[] = "0123456789ABCDEF"; buf[0] = vtx_mkparity(hexchars[page / 0x100]); buf[1] = vtx_mkparity(hexchars[(page / 0x10) & 0xf]); buf[2] = vtx_mkparity(hexchars[page & 0xf]); if (subpage > 0) { buf[3] = vtx_mkparity('.'); if (subpage >= 10) { buf[4] = vtx_mkparity(hexchars[(subpage / 0x10) & 0xf]); buf[5] = vtx_mkparity(hexchars[subpage & 0xf]); } else { buf[4] = vtx_mkparity(hexchars[subpage & 0xf]); buf[5] = vtx_mkparity(' '); } } else { buf[3] = buf[4] = buf[5] = vtx_mkparity(' '); } } static int check_open_device(void) { int err; #ifdef NEED_KERNELD_WORKAROUND sigset_t mask, oldmask; #endif /* All the sigprocmask-stuff is used to work around a bug in Linux's kerneld. * If signals are enabled, open() might receive a signal and return before the module * is actually loaded which causes ENODEV to be returned. The module gets loaded * nevertheless, but then it's too late :-( */ if (!vtx_dev_open) { #ifdef NEED_KERNELD_WORKAROUND sigemptyset(&mask); sigaddset(&mask, SIGIO); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &oldmask); #endif if ((err = cct_open(REQ_MAJOR, REQ_MINOR, &vtx_info)) < 0) { #ifdef NEED_KERNELD_WORKAROUND sigprocmask(SIG_SETMASK, &oldmask, NULL); #endif if (err == CCTEVERSION) { confirm_notice_v(frame, TRUE, "Can't open videotext-device ", cct_device, ":\nIncompatible driver version (need " STRINGIFY(REQ_MAJOR) "." STRINGIFY(REQ_MINOR) ").", (char *)0); return -1; } else { confirm_notice_v(frame, TRUE, "Can't open videotext-device ", cct_device, ":\n", strerror(errno), (char *)0); return -1; } } #ifdef NEED_KERNELD_WORKAROUND sigprocmask(SIG_SETMASK, &oldmask, NULL); #endif vtx_dev_open = TRUE; if (dau_status) { free(dau_status); } dau_status = scalloc(vtx_info.numpages, sizeof(queue_entry_t)); CCTCHK(cct_set_display(config_get_tv_disp() ? (config_get_display_mode() + config_get_interlace() * INTERLACE_OFFSET) : DISPOFF), "cct_set_display", return -1); CCTCHK(cct_set_virtual(!hotlist_get_fastdisable()), "cct_set_virtual", return -1); } if (clear_cache) { int buf; CCTCHK(cct_clear_cache(), "cct_clear_cache", return -1); for (buf = 0; buf < vtx_info.numpages; buf++) { CCTCHK(cct_clearpgbuf(buf), "cct_clearpgbuf", return -1); } clear_cache = FALSE; } return 0; } /* Find idle DAU, or, if none available, DAU searching for page with lowest priority which * started searching most recently. Prefer DAUs that haven't found subpages yet. Stop DAU, * remove currently sought page from DAU & re-insert it into queue. Return number of DAU * or 0 if no DAU was available. */ static int free_dau(int page, int priority) { int bufloop, tmppg, pgbuf = 1, found = FALSE; /* Check for free DAUs or if page is already being searched for */ for (bufloop = 1; bufloop < vtx_info.numpages; bufloop++) { if (!dau_status[bufloop].page || dau_status[bufloop].page == page) { return bufloop; } } for (bufloop = 1; bufloop < vtx_info.numpages; bufloop++) { if (!dau_status[bufloop].firstsubpg && priority > dau_status[bufloop].priority && (dau_status[bufloop].priority < dau_status[pgbuf].priority || (dau_status[bufloop].priority == dau_status[pgbuf].priority && (dau_status[bufloop].timeout > dau_status[pgbuf].timeout || !found)))) { pgbuf = bufloop; found = TRUE; } } if (!found && priority >= PRI_TOP) { for (bufloop = 1; bufloop < vtx_info.numpages; bufloop++) { if (priority > dau_status[bufloop].priority && (dau_status[bufloop].priority < dau_status[pgbuf].priority || (dau_status[bufloop].priority == dau_status[pgbuf].priority && (dau_status[bufloop].timeout > dau_status[pgbuf].timeout || !found)))) { pgbuf = bufloop; found = TRUE; } } } if (!found) { return 0; } /* Remove page from DAU-struct *before* calling history_set_status(), because otherwise * it would think we are currently searching for the page. */ tmppg = dau_status[pgbuf].page; dau_status[pgbuf].page = 0; history_set_status(tmppg, STAT_NEW); insert_queue(dau_status[pgbuf].priority, tmppg, dau_status[pgbuf].subpage, TRUE); return pgbuf; } void top_getpage(int page, int hour, int minute) { /* We can't call get_page immediately, because this function is called from within queue_itimer, * which modifies dau_status. So we just queue up the requests and flush them when we leave * queue_itimer. */ top_queue_count++; top_queue = srealloc(top_queue, sizeof(top_queue_t) * top_queue_count); top_queue[top_queue_count - 1].page = page; top_queue[top_queue_count - 1].minute = minute; top_queue[top_queue_count - 1].hour = hour; } int top_flush_getpage(void) { if (!top_queue_count || !top_queue) return 0; if (get_page(PRI_TOP, top_queue[top_queue_count - 1].page, top_queue[top_queue_count - 1].minute, top_queue[top_queue_count - 1].hour, NULL, NULL) < 0) return -1; top_queue_count--; /* Kluge to avoid getting a NULL-pointer when realloc'ing 0 bytes: */ top_queue = srealloc(top_queue, (sizeof(top_queue_t) * top_queue_count) + 1); return 0; } void stop_search(int page) { int entry; if (dau_status) { for (entry = 1; entry < vtx_info.numpages; entry++) { if (dau_status[entry].page == page) { if (vtx_dev_open) { CCTCHK(cct_stop_dau(entry), "cct_stop_dau", return); } history_set_status(dau_status[entry].page, STAT_NEW); dau_status[entry].page = 0; dau_status_changed = TRUE; } } } } static void exch_queue_entries(queue_entry_t *entry1, queue_entry_t *entry2) { queue_entry_t save; save = *entry1; *entry1 = *entry2; *entry2 = save; } static int insert_queue(int priority, int page, int subpage, int insert_front) { int bufloop, entry, new_pos; for (bufloop = 0; bufloop < vtx_info.numpages; bufloop++) { if (dau_status[bufloop].page == page) { int new_timeout = time(NULL) + hotlist_get_timeout(); dau_status[bufloop].timeout = MAX(new_timeout, dau_status[bufloop].timeout); return FALSE; } } for (entry = 0; entry < queue_end; entry++) { /* If new page already is in queue, set new priority & move it in front of all other * pages with same priority */ if (vtx_queue[entry].page == page && vtx_queue[entry].subpage == subpage) { if (priority >= vtx_queue[entry].priority) { vtx_queue[entry].priority = priority; new_pos = entry; for (; new_pos > 0 && priority >= vtx_queue[new_pos - 1].priority; new_pos--) { exch_queue_entries(&vtx_queue[new_pos], &vtx_queue[new_pos - 1]); } } return TRUE; } } if (queue_end >= queue_maxlen) { vtx_queue = srealloc(vtx_queue, (queue_maxlen += 10) * sizeof(queue_entry_t)); } for (entry = 0; entry < queue_end; entry++) { if (vtx_queue[entry].priority < priority + !!insert_front) break; } memmove(vtx_queue + entry + 1, vtx_queue + entry, (queue_end - entry) * sizeof(queue_entry_t)); queue_end++; /* Only page, subpage & priority are used in vtx_queue */ vtx_queue[entry].page = page; vtx_queue[entry].subpage = subpage; vtx_queue[entry].priority = priority; return TRUE; } /* Remove a page-request from queue. Return priority of removed page or 0 if page was * not in queue. */ static int remove_queue(int page) { int entry, pri; for (entry = 0; entry < queue_end; entry++) { if (vtx_queue[entry].page == page) { pri = vtx_queue[entry].priority; memmove(vtx_queue + entry, vtx_queue + entry + 1, (queue_end - entry - 1) * sizeof(queue_entry_t)); queue_end--; return pri; } } return 0; } static int queue_get_next(queue_entry_t *entry) { if (!queue_end) return FALSE; entry->page = vtx_queue[0].page; entry->subpage = vtx_queue[0].subpage; entry->priority = vtx_queue[0].priority; remove_queue(entry->page); return TRUE; } int remove_priority(int priority) { int entry, start; if (dau_status) { for (entry = (priority == PRI_ALL ? 0 : 1); entry < vtx_info.numpages; entry++) { if (dau_status[entry].page && (priority == PRI_ALL || dau_status[entry].priority == priority)) { if (vtx_dev_open) { CCTCHK(cct_stop_dau(entry), "cct_stop_dau", return -1); } history_set_status(dau_status[entry].page, STAT_NEW); dau_status[entry].page = 0; dau_status_changed = TRUE; } } } if (priority == PRI_ALL) { if (!queue_end) return 0; queue_maxlen = queue_end = 0; free(vtx_queue); vtx_queue = NULL; } else { start = -1; for (entry = 0; entry < queue_end; entry++) { if (vtx_queue[entry].priority == priority && start == -1) { start = entry; } if (vtx_queue[entry].priority > priority) { if (start != -1) { memmove(vtx_queue + start, vtx_queue + entry, (queue_end - entry) * sizeof(queue_entry_t)); queue_end -= entry - start; return 0; } } } } return 0; } int queue_itimer(void) { int pgnum, newpage = 0, currpage; static int lastpage = 100, bufloop = 1; queue_entry_t next_page; struct timeval t1, t2; if (!vtx_dev_open || vtx_info.numpages <= 1) return 0; gettimeofday(&t1, NULL); do { if (dau_status[bufloop].page) { do { if (newpage < 0 && report_cct_error(newpage, "cct_checkpage")) { cct_close(); hotlist_set_current(0); vtx_dev_open = FALSE; return -1; } } while ((newpage = cct_checkpage(bufloop)) < 0); if (!newpage) { if (dau_status[bufloop].page_found) { byte_t tmp_buffer[VTX_PAGESIZE]; vtx_pageinfo_t tmp_pageinfo; int toptext_last, curr_st; CCTCHK(cct_getpage(bufloop, 0, 0, 39, 23, tmp_buffer, &tmp_pageinfo), "cct_getpage", return -1); /* Restart DAU to keep header-line running (for station-change detection) */ CCTCHK(cct_searchpage(dau_status[bufloop].page, 0, 0, PGMASK_PAGE, bufloop), "cct_searchpage", return -1); CCTCHK(cct_reset_pgfound(bufloop), "cct_reset_pgfound", return -1); dau_status[bufloop].page_found = FALSE; /* Check if we received the right page (normally, the following test should never be * true, but you'll never know what these broken videotext-chips come up with next...) */ if (dau_status[bufloop].page != tmp_pageinfo.pagenum) { goto loopend; } /* Sanity check: Test if page-header matches recognized station before inserting * page into cache */ curr_st = hotlist_get_current(); if (hotlist_search(tmp_buffer + 8, curr_st) == curr_st) { cache_insert(tmp_buffer, &tmp_pageinfo); search_bg_newpage(tmp_buffer, &tmp_pageinfo, search_notify_cb); } currpage = dau_status[bufloop].page; if (!tmp_pageinfo.minute) { lastpage = currpage; } timeout_set(dau_status[bufloop].page, FALSE); toptext_last = toptext_ok; if (!hotlist_get_topdisable() && toptext_newpage(tmp_buffer + 40, &tmp_pageinfo, &top_getpage)) { CCTCHK(cct_stop_dau(bufloop), "cct_stop_dau", return -1); dau_status[bufloop].page = 0; dau_status_changed = TRUE; if (toptext_ok != toptext_last) { toptext_ok_notify(); } goto bufend; } if (!hotlist_get_fastdisable()) { int fastext_last = fastext_ok; byte_t packet24[40], packet27[4 * 40]; CCTCHK(cct_getpage(bufloop, 0, 44, 39, 44, packet24, NULL), "cct_getpage", return -1); CCTCHK(cct_getpage(bufloop, 0, 40, 39, 43, packet27, NULL), "cct_getpage", return -1); fastext_newpage(packet24, packet27, &tmp_pageinfo); if (fastext_ok != fastext_last) { fastext_ok_notify(); } } if (!tmp_pageinfo.minute) { cache_mark_complete(tmp_pageinfo.pagenum); } if (dau_status[bufloop].subpage < 0 || !tmp_pageinfo.minute) { /* We were only searching for the next subpage or there are no subpages -> stop * searching */ CCTCHK(cct_stop_dau(bufloop), "cct_stop_dau", return -1); dau_status[bufloop].page = 0; dau_status_changed = TRUE; goto bufend; } /* If we are searching for a certain subpage, check if the right one was found */ if (dau_status[bufloop].subpage && dau_status[bufloop].subpage == tmp_pageinfo.minute) { CCTCHK(cct_stop_dau(bufloop), "cct_stop_dau", return -1); dau_status[bufloop].page = 0; dau_status_changed = TRUE; goto bufend; } /* Check if all subpages for this page were received */ if (dau_status[bufloop].lastsubpg != tmp_pageinfo.minute) { dau_status[bufloop].timeout = time(NULL) + 2 * hotlist_get_timeout(); dau_status[bufloop].lastsubpg = tmp_pageinfo.minute; if (!dau_status[bufloop].firstsubpg) { dau_status[bufloop].firstsubpg = tmp_pageinfo.minute; } else if (tmp_pageinfo.minute == dau_status[bufloop].firstsubpg || tmp_pageinfo.minute == dau_status[bufloop].firstsubpg - 1) { /* All subpages received or subpage doesn't exist */ CCTCHK(cct_stop_dau(bufloop), "cct_stop_dau", return -1); cache_mark_complete(tmp_pageinfo.pagenum); dau_status[bufloop].page = 0; dau_status_changed = TRUE; } goto bufend; } bufend: /* If we're still searching for a page, set status to STAT_SEARCH again (icon will * probably change because now there's already a page in the cache) */ if (dau_status[bufloop].page) { history_set_status(dau_status[bufloop].page, STAT_SEARCH); } else { history_set_status(currpage, STAT_FOUND); } } else { dau_status[bufloop].page_found = TRUE; } } else if (time(NULL) > dau_status[bufloop].timeout) { history_set_status(dau_status[bufloop].page, STAT_TIMEOUT); timeout_set(dau_status[bufloop].page, TRUE); CCTCHK(cct_stop_dau(bufloop), "cct_stop_dau", return -1); dau_status[bufloop].page = 0; dau_status_changed = TRUE; } } /* Start searching for a new page if DAU is idle */ if (!dau_status[bufloop].page) { if (queue_get_next(&next_page)) { CCTCHK(cct_searchpage(next_page.page, 0, 0, PGMASK_PAGE, bufloop), "cct_searchpage", return -1); CCTCHK(cct_reset_pgfound(bufloop), "cct_reset_pgfound", return -1); /* keep_running is unused if buffer != 0 */ dau_status[bufloop].page = next_page.page; dau_status[bufloop].subpage = next_page.subpage; dau_status[bufloop].priority = next_page.priority; dau_status[bufloop].timeout = time(NULL) + hotlist_get_timeout(); dau_status[bufloop].page_found = FALSE; dau_status[bufloop].firstsubpg = dau_status[bufloop].lastsubpg = 0; dau_status_changed = TRUE; history_set_status(dau_status[bufloop].page, STAT_SEARCH); } else if (toptext_ok && !hotlist_get_topdisable() && hotlist_get_searchlevel() && (pgnum = toptext_getnext(lastpage, hotlist_get_interleave(), config_get_top_sorted(), TT_BLOCK, hotlist_get_searchlevel())) > 0) { int searchbuf; for (searchbuf = 0; searchbuf < vtx_info.numpages; searchbuf++) { if (dau_status[searchbuf].page == pgnum) pgnum = -1; } if (pgnum == -1) continue; CCTCHK(cct_searchpage(pgnum, 0, 0, PGMASK_PAGE, bufloop), "cct_searchpage", return -1); CCTCHK(cct_reset_pgfound(bufloop), "cct_reset_pgfound", return -1); dau_status[bufloop].page = pgnum; dau_status[bufloop].subpage = 0; dau_status[bufloop].priority = PRI_MED; dau_status[bufloop].timeout = time(NULL) + hotlist_get_timeout(); dau_status[bufloop].page_found = FALSE; dau_status[bufloop].firstsubpg = dau_status[bufloop].lastsubpg = 0; dau_status_changed = TRUE; } } loopend: if (++bufloop >= vtx_info.numpages) bufloop = 1; /* Exit if either all buffers were checked or at least .2 sec have passed */ gettimeofday(&t2, NULL); } while (bufloop != 1 && ((t2.tv_sec - t1.tv_sec) * 10 + (t2.tv_usec - t1.tv_usec) / 100000) < 2); return 0; } static int history_end = -1; void history_insert(int page, int do_select) { int pos; char tmpstr[4]; Server_image new_img; if (do_select && (pos = (int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_FIRST_SELECTED)) != -1) { xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_SELECT, pos, FALSE, NULL); } for (pos = 0; pos <= history_end; pos++) { if ((int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_CLIENT_DATA, pos) == page) { if (do_select) { xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_SELECT, pos, TRUE, NULL); } return; } } new_img = history_icon(page, STAT_NEW); history_end++; sprintf(tmpstr, "%3X", page); xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_INSERT, history_end, PANEL_LIST_STRING, history_end, tmpstr, PANEL_LIST_GLYPH, history_end, new_img, PANEL_LIST_MASK_GLYPH, history_end, new_img, PANEL_LIST_CLIENT_DATA, history_end, page, NULL); if (do_select) { xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_SELECT, history_end, TRUE, NULL); } } void history_reset(void) { xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_DELETE_ROWS, 0, history_end + 1, NULL); history_end = -1; } static Server_image history_icon(int page, int default_img) { int count; Server_image img; if ((count = cache_count_subpg(page))) { img = hist_image[count > 1 ? STAT_FOUND_MP : STAT_FOUND].image; } else { img = hist_image[default_img].image; } return img; } void history_set_status(int page, int status) { int pos; Server_image current, new; for (pos = 0; pos <= history_end; pos++) { if ((int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_CLIENT_DATA, pos) == page) { new = current = (Server_image)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_GLYPH, pos); if (current != hist_image[STAT_READ].image && current != hist_image[STAT_READ_MP].image) { switch (status) { case STAT_FOUND: case STAT_NEW: new = history_icon(page, STAT_NEW); break; case STAT_SEARCH: if (cache_query(page, -1, 0, NULL, NULL)) { new = hist_image[STAT_SEARCH_MP].image; } else { new = hist_image[STAT_SEARCH].image; } break; case STAT_TIMEOUT: new = history_icon(page, STAT_TIMEOUT); break; case STAT_READ: if (cache_count_subpg(page) > 1) { new = hist_image[STAT_READ_MP].image; } else { new = hist_image[STAT_READ].image; } break; } } else if (status == STAT_READ) { if (cache_count_subpg(page) > 1) { new = hist_image[STAT_READ_MP].image; } else { new = hist_image[STAT_READ].image; } } if (new != current) { xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_GLYPH, pos, new, PANEL_LIST_MASK_GLYPH, pos, new, NULL); } } } } int timeout_set(int page, int flag) { if (!vtx_chkpgnum(page, FALSE)) return -1; timeout_table[vtx_hex2dec(page) - 100] = !!flag; return 0; } int timeout_check(int page) { if (!vtx_chkpgnum(page, FALSE)) return -1; return timeout_table[vtx_hex2dec(page) - 100]; } void timeout_reset(void) { memset(timeout_table, 0, sizeof(timeout_table)); }