/* * Preferences memory-deallocation * (Call this one at exit time) */ void a_Prefs_freeall(void) { g_free(prefs.http_proxyuser); g_free(prefs.no_proxy); if (prefs.no_proxy_vec) g_strfreev(prefs.no_proxy_vec); a_Url_free(prefs.http_proxy); g_free(prefs.fw_fontname); g_free(prefs.vw_fontname); a_Url_free(prefs.start_page); a_Url_free(prefs.home); g_free(prefs.search_url); }
/* * Deallocate memory used by http module * (Call this one at exit time) */ void a_Http_freeall(void) { Http_host_connection_remove_all(); a_Klist_free(&ValidSocks); a_Url_free(HTTP_Proxy); dFree(HTTP_Proxy_Auth_base64); dFree(HTTP_Language_hdr); }
/* * Save link from behind a timeout so that Cache_process_queue() can * get on with its work. */ static void Cache_savelink_cb(void *vdata) { Cache_savelink_t *data = (Cache_savelink_t*) vdata; a_UIcmd_save_link(data->bw, data->url); a_Url_free(data->url); dFree(data); }
/* * Deallocate a DilloWeb structure */ void a_Web_free(DilloWeb *web) { if (!web) return; if (web->url) a_Url_free(web->url); if (web->Image) a_Image_unref(web->Image); ValidWebs = g_slist_remove(ValidWebs, (gpointer)web); g_free(web); }
/* * Free the components of a CacheEntry_t struct. */ static void Cache_entry_free(CacheEntry_t *entry) { a_Url_free((DilloUrl *)entry->Url); dFree(entry->TypeDet); dFree(entry->TypeHdr); dFree(entry->TypeMeta); dFree(entry->TypeNorm); dStr_free(entry->Header, TRUE); a_Url_free((DilloUrl *)entry->Location); Cache_auth_free(entry->Auth); dStr_free(entry->Data, 1); dStr_free(entry->UTF8Data, 1); if (entry->CharsetDecoder) a_Decode_free(entry->CharsetDecoder); if (entry->TransferDecoder) a_Decode_free(entry->TransferDecoder); if (entry->ContentDecoder) a_Decode_free(entry->ContentDecoder); dFree(entry); }
/* * Ask for user/password and reload the page. */ static void Cache_auth_callback(void *vdata) { CacheAuthData_t *data = (CacheAuthData_t *)vdata; if (a_Auth_do_auth(data->auth, data->url)) a_Nav_reload(data->bw); Cache_auth_free(data->auth); a_Url_free(data->url); dFree(data); Cache_auth_entry(NULL, NULL); a_Timeout_remove(); }
/* * Initialize dicache data */ void a_Cache_init(void) { ClientQueue = dList_new(32); DelayedQueue = dList_new(32); CachedURLs = dList_new(256); /* inject the splash screen in the cache */ { DilloUrl *url = a_Url_new("about:splash", NULL); Dstr *ds = dStr_new(AboutSplash); Cache_entry_inject(url, ds); dStr_free(ds, 1); a_Url_free(url); } }
/* * Process redirections (HTTP 30x answers) * (This is a work in progress --not finished yet) */ static int Cache_redirect(CacheEntry_t *entry, int Flags, BrowserWindow *bw) { DilloUrl *NewUrl; _MSG(" Cache_redirect: redirect_level = %d\n", bw->redirect_level); /* Don't allow redirection for SpamSafe/local URLs */ if (URL_FLAGS(entry->Url) & URL_SpamSafe) { a_UIcmd_set_msg(bw, "WARNING: local URL with redirection. Aborting."); return 0; } /* if there's a redirect loop, stop now */ if (bw->redirect_level >= 5) entry->Flags |= CA_RedirectLoop; if (entry->Flags & CA_RedirectLoop) { a_UIcmd_set_msg(bw, "ERROR: redirect loop for: %s", URL_STR_(entry->Url)); bw->redirect_level = 0; return 0; } if ((entry->Flags & CA_Redirect && entry->Location) && (entry->Flags & CA_ForceRedirect || entry->Flags & CA_TempRedirect || !entry->Data->len || entry->Data->len < 1024)) { _MSG(">>>> Redirect from: %s\n to %s <<<<\n", URL_STR_(entry->Url), URL_STR_(entry->Location)); _MSG("%s", entry->Header->str); if (Flags & WEB_RootUrl) { /* Redirection of the main page */ NewUrl = a_Url_new(URL_STR_(entry->Location), URL_STR_(entry->Url)); if (entry->Flags & CA_TempRedirect) a_Url_set_flags(NewUrl, URL_FLAGS(NewUrl) | URL_E2EQuery); a_Nav_push(bw, NewUrl, entry->Url); a_Url_free(NewUrl); } else { /* Sub entity redirection (most probably an image) */ if (!entry->Data->len) { _MSG(">>>> Image redirection without entity-content <<<<\n"); } else { _MSG(">>>> Image redirection with entity-content <<<<\n"); } } } return 0; }
/* * Decrement the reference count (and remove from list when zero) */ static void Capi_conn_unref(capi_conn_t *conn) { _MSG(" Capi_conn_unref #%d %p\n", conn->Ref - 1, conn); /* We may validate conn here, but it doesn't *seem* necessary */ if (--conn->Ref == 0) { /* remove conn preserving the list order */ dList_remove(CapiConns, (void *)conn); /* free dynamic memory */ a_Url_free(conn->url); dFree(conn->server); dFree(conn->datastr); dFree(conn); } _MSG(" Capi_conn_unref CapiConns=%d\n", dList_length(CapiConns)); }
/* * Return: Nonzero if we got new credentials from the user and everything * seems fine. */ static int Auth_do_auth_dialog(const AuthParse_t *auth_parse, const DilloUrl *url) { int ret; char *title, *msg; AuthDialogData_t *data; const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic"; _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm); title = dStrconcat("Dillo: Password for ", auth_parse->realm, NULL); msg = dStrconcat("The server at ", URL_HOST(url), " requires a username" " and password for \"", auth_parse->realm, "\".\n\n" "Authentication scheme: ", typestr, NULL); data = dNew(AuthDialogData_t, 1); data->auth_parse = auth_parse; data->url = a_Url_dup(url); ret = a_Dialog_user_password(title, msg, Auth_do_auth_dialog_cb, data); dFree(title); dFree(msg); a_Url_free((void *)data->url); dFree(data); return ret; }
/* * Read tokens from dillorc and set values in the prefs structure. * (Although this function can be called several times, and not leak, * preferences aren't yet enabled for on-the-fly changes). */ static guint Prefs_parser(GScanner *scanner) { gint st; guint symbol; /* expect a valid symbol */ g_scanner_get_next_token(scanner); symbol = scanner->token; if (scanner->token == G_TOKEN_EQUAL_SIGN) { g_scanner_get_next_token (scanner); return G_TOKEN_NONE; } else if (symbol < DRC_TOKEN_FIRST || symbol > DRC_TOKEN_LAST ) return G_TOKEN_SYMBOL; /* expect '=' */ g_scanner_get_next_token(scanner); if (scanner->token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; /* expect a string */ g_scanner_get_next_token(scanner); if (scanner->token != G_TOKEN_STRING) return G_TOKEN_STRING; /* assign value and exit successfully */ switch (symbol) { case DRC_TOKEN_GEOMETRY: a_Misc_parse_geometry(scanner->value.v_string, &prefs.xpos, &prefs.ypos, &prefs.width, &prefs.height); break; case DRC_TOKEN_PROXY: a_Url_free(prefs.http_proxy); prefs.http_proxy = a_Url_new(scanner->value.v_string, NULL, 0, 0, 0); break; case DRC_TOKEN_PROXYUSER: g_free(prefs.http_proxyuser); prefs.http_proxyuser = g_strdup(scanner->value.v_string); break; case DRC_TOKEN_NOPROXY: g_free(prefs.no_proxy); prefs.no_proxy = g_strdup(scanner->value.v_string); prefs.no_proxy_vec = g_strsplit(prefs.no_proxy, " ", 0); break; case DRC_TOKEN_LINK_COLOR: prefs.link_color = a_Color_parse(scanner->value.v_string, prefs.link_color, &st); break; case DRC_TOKEN_VISITED_COLOR: prefs.visited_color = a_Color_parse(scanner->value.v_string, prefs.visited_color, &st); break; case DRC_TOKEN_TEXT_COLOR: prefs.text_color = a_Color_parse(scanner->value.v_string, prefs.text_color, &st); break; case DRC_TOKEN_BG_COLOR: prefs.bg_color = a_Color_parse(scanner->value.v_string, prefs.bg_color, &st); break; case DRC_TOKEN_ALLOW_WHITE_BG: prefs.allow_white_bg = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_FORCE_MY_COLORS: prefs.force_my_colors = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_CONTRAST_VISITED_COLOR: prefs.contrast_visited_color = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_USE_OBLIQUE: prefs.use_oblique = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_PANEL_SIZE: if (!g_strcasecmp(scanner->value.v_string, "tiny")) prefs.panel_size = 1; else if (!g_strcasecmp(scanner->value.v_string, "small")) prefs.panel_size = 2; else if (!g_strcasecmp(scanner->value.v_string, "medium")) prefs.panel_size = 3; else /* default to "large" */ prefs.panel_size = 4; break; case DRC_TOKEN_SMALL_ICONS: prefs.small_icons = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_START_PAGE: a_Url_free(prefs.start_page); prefs.start_page = a_Url_new(scanner->value.v_string, NULL, 0, 0, 0); break; case DRC_TOKEN_HOME: a_Url_free(prefs.home); prefs.home = a_Url_new(scanner->value.v_string, NULL, 0, 0, 0); break; case DRC_TOKEN_SHOW_TOOLTIP: prefs.show_tooltip = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_FONT_FACTOR: prefs.font_factor = strtod(scanner->value.v_string, NULL); break; case DRC_TOKEN_LIMIT_TEXT_WIDTH: prefs.limit_text_width = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_W3C_PLUS_HEURISTICS: prefs.w3c_plus_heuristics = (strcmp(scanner->value.v_string,"YES") == 0); break; case DRC_TOKEN_USE_DICACHE: prefs.use_dicache = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_BACK: prefs.show_back = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_FORW: prefs.show_forw = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_HOME: prefs.show_home = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_RELOAD: prefs.show_reload = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_SAVE: prefs.show_save = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_STOP: prefs.show_stop = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_BOOKMARKS: prefs.show_bookmarks = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_MENUBAR: prefs.show_menubar = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_CLEAR_URL: prefs.show_clear_url = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_URL: prefs.show_url = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_SEARCH: prefs.show_search = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_PROGRESS_BOX: prefs.show_progress_box = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_FULLWINDOW_START: prefs.fullwindow_start = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_TRANSIENT_DIALOGS: prefs.transient_dialogs = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_FW_FONT: g_free(prefs.fw_fontname); prefs.fw_fontname = g_strdup(scanner->value.v_string); break; case DRC_TOKEN_VW_FONT: g_free(prefs.vw_fontname); prefs.vw_fontname = g_strdup(scanner->value.v_string); break; case DRC_TOKEN_GENERATE_SUBMIT: prefs.generate_submit = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_ENTERPRESS_FORCES_SUBMIT: prefs.enterpress_forces_submit = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SEARCH_URL: g_free(prefs.search_url); prefs.search_url = g_strdup(scanner->value.v_string); break; case DRC_TOKEN_SHOW_MSG: prefs.show_msg = (strcmp(scanner->value.v_string, "YES") == 0); break; case DRC_TOKEN_SHOW_EXTRA_WARNINGS: prefs.show_extra_warnings = (strcmp(scanner->value.v_string, "YES") == 0); break; default: break; /* Not reached */ } return G_TOKEN_NONE; }
/* * Scan, allocate, and set things according to header info. * (This function needs the whole header to work) */ static void Cache_parse_header(CacheEntry_t *entry) { char *header = entry->Header->str; char *Length, *Type, *location_str, *encoding; #ifndef DISABLE_COOKIES Dlist *Cookies; #endif Dlist *warnings; void *data; int i; _MSG("Cache_parse_header\n"); if (entry->Header->len > 12) { if (header[9] == '1' && header[10] == '0' && header[11] == '0') { /* 100: Continue. The "real" header has not come yet. */ MSG("An actual 100 Continue header!\n"); entry->Flags &= ~CA_GotHeader; dStr_free(entry->Header, 1); entry->Header = dStr_new(""); return; } if (header[9] == '3' && header[10] == '0' && (location_str = Cache_parse_field(header, "Location"))) { /* 30x: URL redirection */ DilloUrl *location_url = a_Url_new(location_str,URL_STR_(entry->Url)); if (prefs.filter_auto_requests == PREFS_FILTER_SAME_DOMAIN && !a_Url_same_organization(entry->Url, location_url)) { /* don't redirect; just show body like usual (if any) */ MSG("Redirection not followed from %s to %s\n", URL_HOST(entry->Url), URL_STR(location_url)); a_Url_free(location_url); } else { entry->Flags |= CA_Redirect; if (header[11] == '1') entry->Flags |= CA_ForceRedirect; /* 301 Moved Permanently */ else if (header[11] == '2') entry->Flags |= CA_TempRedirect; /* 302 Temporary Redirect */ if (URL_FLAGS(location_url) & (URL_Post + URL_Get) && dStrAsciiCasecmp(URL_SCHEME(location_url), "dpi") == 0 && dStrAsciiCasecmp(URL_SCHEME(entry->Url), "dpi") != 0) { /* Forbid dpi GET and POST from non dpi-generated urls */ MSG("Redirection Denied! '%s' -> '%s'\n", URL_STR(entry->Url), URL_STR(location_url)); a_Url_free(location_url); } else { entry->Location = location_url; } } dFree(location_str); } else if (strncmp(header + 9, "401", 3) == 0) { entry->Auth = Cache_parse_multiple_fields(header, "WWW-Authenticate"); } else if (strncmp(header + 9, "404", 3) == 0) { entry->Flags |= CA_NotFound; } } if ((warnings = Cache_parse_multiple_fields(header, "Warning"))) { for (i = 0; (data = dList_nth_data(warnings, i)); ++i) { MSG_HTTP("%s\n", (char *)data); dFree(data); } dList_free(warnings); } /* * Get Transfer-Encoding and initialize decoder */ encoding = Cache_parse_field(header, "Transfer-Encoding"); entry->TransferDecoder = a_Decode_transfer_init(encoding); if ((Length = Cache_parse_field(header, "Content-Length")) != NULL) { if (encoding) { /* * If Transfer-Encoding is present, Content-Length must be ignored. * If the Transfer-Encoding is non-identity, it is an error. */ if (dStrAsciiCasecmp(encoding, "identity")) MSG_HTTP("Content-Length and non-identity Transfer-Encoding " "headers both present.\n"); } else { entry->Flags |= CA_GotLength; entry->ExpectedSize = MAX(strtol(Length, NULL, 10), 0); } dFree(Length); } dFree(encoding); /* free Transfer-Encoding */ #ifndef DISABLE_COOKIES if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) { CacheClient_t *client; for (i = 0; (client = dList_nth_data(ClientQueue, i)); ++i) { if (client->Url == entry->Url) { DilloWeb *web = client->Web; if (!web->requester || a_Url_same_organization(entry->Url, web->requester)) { char *server_date = Cache_parse_field(header, "Date"); a_Cookies_set(Cookies, entry->Url, server_date); dFree(server_date); break; } } } if (i >= dList_length(ClientQueue)) { MSG("Cache: cookies not accepted from '%s'\n", URL_STR(entry->Url)); } for (i = 0; (data = dList_nth_data(Cookies, i)); ++i) dFree(data); dList_free(Cookies); } #endif /* !DISABLE_COOKIES */ /* * Get Content-Encoding and initialize decoder */ encoding = Cache_parse_field(header, "Content-Encoding"); entry->ContentDecoder = a_Decode_content_init(encoding); dFree(encoding); if (entry->ExpectedSize > 0) { if (entry->ExpectedSize > HUGE_FILESIZE) { entry->Flags |= CA_HugeFile; } /* Avoid some reallocs. With MAX_INIT_BUF we avoid a SEGFAULT * with huge files (e.g. iso files). * Note: the buffer grows automatically. */ dStr_free(entry->Data, 1); entry->Data = dStr_sized_new(MIN(entry->ExpectedSize, MAX_INIT_BUF)); } /* Get Content-Type */ if ((Type = Cache_parse_field(header, "Content-Type"))) { /* This HTTP Content-Type is not trusted. It's checked against real data * in Cache_process_queue(); only then CA_GotContentType becomes true. */ a_Cache_set_content_type(entry->Url, Type, "http"); _MSG("TypeHdr {%s} {%s}\n", Type, URL_STR(entry->Url)); _MSG("TypeMeta {%s}\n", entry->TypeMeta); dFree(Type); } Cache_ref_data(entry); }
/* * Update cache clients for a single cache-entry * Tasks: * - Set the client function (if not already set) * - Look if new data is available and pass it to client functions * - Remove clients when done * - Call redirect handler * * Return: Cache entry, which may be NULL if it has been removed. * * TODO: Implement CA_Abort Op in client callback */ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry) { uint_t i; int st; const char *Type; Dstr *data; CacheClient_t *Client; DilloWeb *ClientWeb; BrowserWindow *Client_bw = NULL; static bool_t Busy = FALSE; bool_t AbortEntry = FALSE; bool_t OfferDownload = FALSE; bool_t TypeMismatch = FALSE; if (Busy) MSG_ERR("FATAL!: >>>> Cache_process_queue Caught busy!!! <<<<\n"); if (!(entry->Flags & CA_GotHeader)) return entry; if (!(entry->Flags & CA_GotContentType)) { st = a_Misc_get_content_type_from_data( entry->Data->str, entry->Data->len, &Type); _MSG("Cache: detected Content-Type '%s'\n", Type); if (st == 0 || entry->Flags & CA_GotData) { if (a_Misc_content_type_check(entry->TypeHdr, Type) < 0) { MSG_HTTP("Content-Type '%s' doesn't match the real data.\n", entry->TypeHdr); TypeMismatch = TRUE; } entry->TypeDet = dStrdup(Type); entry->Flags |= CA_GotContentType; } else return entry; /* i.e., wait for more data */ } Busy = TRUE; for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) { if (Client->Url == entry->Url) { ClientWeb = Client->Web; /* It was a (void*) */ Client_bw = ClientWeb->bw; /* 'bw' in a local var */ if (ClientWeb->flags & WEB_RootUrl) { if (!(entry->Flags & CA_MsgErased)) { /* clear the "expecting for reply..." message */ a_UIcmd_set_msg(Client_bw, ""); entry->Flags |= CA_MsgErased; } if (TypeMismatch) { a_UIcmd_set_msg(Client_bw,"HTTP warning: Content-Type '%s' " "doesn't match the real data.", entry->TypeHdr); OfferDownload = TRUE; } if (entry->Flags & CA_Redirect) { if (!Client->Callback) { Client->Callback = Cache_null_client; Client_bw->redirect_level++; } } else { Client_bw->redirect_level = 0; } if (entry->Flags & CA_HugeFile) { a_UIcmd_set_msg(Client_bw,"Huge file! (%dMB)", entry->ExpectedSize / (1024*1024)); AbortEntry = OfferDownload = TRUE; } } else { /* For non root URLs, ignore redirections and 404 answers */ if (entry->Flags & CA_Redirect || entry->Flags & CA_NotFound) Client->Callback = Cache_null_client; } /* Set the client function */ if (!Client->Callback) { Client->Callback = Cache_null_client; if (TypeMismatch) { AbortEntry = TRUE; } else { const char *curr_type = Cache_current_content_type(entry); st = a_Web_dispatch_by_type(curr_type, ClientWeb, &Client->Callback, &Client->CbData); if (st == -1) { /* MIME type is not viewable */ if (ClientWeb->flags & WEB_RootUrl) { MSG("Content-Type '%s' not viewable.\n", curr_type); /* prepare a download offer... */ AbortEntry = OfferDownload = TRUE; } else { /* TODO: Resource Type not handled. * Not aborted to avoid multiple connections on the same * resource. A better idea is to abort the connection and * to keep a failed-resource flag in the cache entry. */ } } } if (AbortEntry) { if (ClientWeb->flags & WEB_RootUrl) a_Nav_cancel_expect_if_eq(Client_bw, Client->Url); a_Bw_remove_client(Client_bw, Client->Key); Cache_client_dequeue(Client, NULLKey); --i; /* Keep the index value in the next iteration */ continue; } } /* Send data to our client */ if (ClientWeb->flags & WEB_Download) { /* for download, always provide original data, not translated */ data = entry->Data; } else { data = Cache_data(entry); } if ((Client->BufSize = data->len) > 0) { Client->Buf = data->str; (Client->Callback)(CA_Send, Client); if (ClientWeb->flags & WEB_RootUrl) { /* show size of page received */ a_UIcmd_set_page_prog(Client_bw, entry->Data->len, 1); } } /* Remove client when done */ if (entry->Flags & CA_GotData) { /* Copy flags to a local var */ int flags = ClientWeb->flags; /* We finished sending data, let the client know */ (Client->Callback)(CA_Close, Client); if (ClientWeb->flags & WEB_RootUrl) a_UIcmd_set_page_prog(Client_bw, 0, 0); Cache_client_dequeue(Client, NULLKey); --i; /* Keep the index value in the next iteration */ /* within CA_GotData, we assert just one redirect call */ if (entry->Flags & CA_Redirect) Cache_redirect(entry, flags, Client_bw); } } } /* for */ if (AbortEntry) { /* Abort the entry, remove it from cache, and maybe offer download. */ DilloUrl *url = a_Url_dup(entry->Url); a_Capi_conn_abort_by_url(url); entry = NULL; if (OfferDownload) { /* Remove entry when 'conn' is already done */ Cache_entry_remove(NULL, url); if (a_Cache_download_enabled(url)) { Cache_savelink_t *data = dNew(Cache_savelink_t, 1); data->bw = Client_bw; data->url = a_Url_dup(url); a_Timeout_add(0.0, Cache_savelink_cb, data); } } a_Url_free(url); } else if (entry->Auth && (entry->Flags & CA_GotData)) { Cache_auth_entry(entry, Client_bw); } /* Trigger cleanup when there are no cache clients */ if (dList_length(ClientQueue) == 0) { _MSG(" a_Dicache_cleanup()\n"); a_Dicache_cleanup(); } Busy = FALSE; _MSG("QueueSize ====> %d\n", dList_length(ClientQueue)); return entry; }